diff --git a/app/Events/Account/AccountCreated.php b/app/Events/Account/AccountCreated.php index a01c0c68abdf..f2149b2a82d2 100644 --- a/app/Events/Account/AccountCreated.php +++ b/app/Events/Account/AccountCreated.php @@ -52,8 +52,9 @@ class AccountCreated // * // * @return Channel|array // */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + // return new PrivateChannel('channel-name'); + } } diff --git a/app/Events/Client/ClientWasArchived.php b/app/Events/Client/ClientWasArchived.php index 0b7022705e22..aca000b8e594 100644 --- a/app/Events/Client/ClientWasArchived.php +++ b/app/Events/Client/ClientWasArchived.php @@ -54,8 +54,8 @@ class ClientWasArchived // * // * @return Channel|array // */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Company/CompanyDocumentsDeleted.php b/app/Events/Company/CompanyDocumentsDeleted.php index 4cad317fa38b..2c8f11c4f27f 100644 --- a/app/Events/Company/CompanyDocumentsDeleted.php +++ b/app/Events/Company/CompanyDocumentsDeleted.php @@ -42,8 +42,8 @@ class CompanyDocumentsDeleted * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { +return []; + } } diff --git a/app/Events/Contact/ContactLoggedIn.php b/app/Events/Contact/ContactLoggedIn.php index 112358db608e..e2c76d5b62d4 100644 --- a/app/Events/Contact/ContactLoggedIn.php +++ b/app/Events/Contact/ContactLoggedIn.php @@ -53,8 +53,8 @@ class ContactLoggedIn * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { +return []; + } } diff --git a/app/Events/Design/DesignWasArchived.php b/app/Events/Design/DesignWasArchived.php index c4b4196323e2..1dd9105c7c63 100644 --- a/app/Events/Design/DesignWasArchived.php +++ b/app/Events/Design/DesignWasArchived.php @@ -35,8 +35,8 @@ class DesignWasArchived * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Design/DesignWasCreated.php b/app/Events/Design/DesignWasCreated.php index 26f4515b5cde..c919768ac511 100644 --- a/app/Events/Design/DesignWasCreated.php +++ b/app/Events/Design/DesignWasCreated.php @@ -32,8 +32,8 @@ class DesignWasCreated * * @return PrivateChannel */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Design/DesignWasDeleted.php b/app/Events/Design/DesignWasDeleted.php index c3d1fc4e4538..f2339cd59d1f 100644 --- a/app/Events/Design/DesignWasDeleted.php +++ b/app/Events/Design/DesignWasDeleted.php @@ -32,8 +32,8 @@ class DesignWasDeleted * * @return PrivateChannel */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Design/DesignWasRestored.php b/app/Events/Design/DesignWasRestored.php index 4e294c327ce5..789ff15a684b 100644 --- a/app/Events/Design/DesignWasRestored.php +++ b/app/Events/Design/DesignWasRestored.php @@ -32,8 +32,8 @@ class DesignWasRestored * * @return PrivateChannel */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Design/DesignWasUpdated.php b/app/Events/Design/DesignWasUpdated.php index 759aa2aa1b0a..30d49a85c4fb 100644 --- a/app/Events/Design/DesignWasUpdated.php +++ b/app/Events/Design/DesignWasUpdated.php @@ -32,8 +32,8 @@ class DesignWasUpdated * * @return PrivateChannel */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Document/DocumentWasArchived.php b/app/Events/Document/DocumentWasArchived.php index d504e94f6378..229e7d6c1673 100644 --- a/app/Events/Document/DocumentWasArchived.php +++ b/app/Events/Document/DocumentWasArchived.php @@ -56,6 +56,6 @@ class DocumentWasArchived */ public function broadcastOn() { - return new PrivateChannel('channel-name'); + return []; } } diff --git a/app/Events/Invoice/InvoiceWasCreated.php b/app/Events/Invoice/InvoiceWasCreated.php index a6c909439c3f..cf1da1c42521 100644 --- a/app/Events/Invoice/InvoiceWasCreated.php +++ b/app/Events/Invoice/InvoiceWasCreated.php @@ -54,10 +54,10 @@ class InvoiceWasCreated implements ShouldBroadcast * * @return PrivateChannel|array */ - // public function broadcastOn() - // { - // return ['simple-channel']; - // } + public function broadcastOn() + { + return []; + } // /** diff --git a/app/Events/Payment/Methods/MethodDeleted.php b/app/Events/Payment/Methods/MethodDeleted.php index dbbde3ec22ba..4b1d3d710397 100644 --- a/app/Events/Payment/Methods/MethodDeleted.php +++ b/app/Events/Payment/Methods/MethodDeleted.php @@ -51,8 +51,8 @@ class MethodDeleted * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/Subscription/SubscriptionWasCreated.php b/app/Events/Subscription/SubscriptionWasCreated.php index 9a56c40a05f1..9d1616defb28 100644 --- a/app/Events/Subscription/SubscriptionWasCreated.php +++ b/app/Events/Subscription/SubscriptionWasCreated.php @@ -45,8 +45,8 @@ class SubscriptionWasCreated * * @return \Illuminate\Broadcasting\Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserLoggedIn.php b/app/Events/User/UserLoggedIn.php index c778373fead9..f3b55c2a1c71 100644 --- a/app/Events/User/UserLoggedIn.php +++ b/app/Events/User/UserLoggedIn.php @@ -35,8 +35,8 @@ class UserLoggedIn * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserWasArchived.php b/app/Events/User/UserWasArchived.php index 267f0b446232..51657baffbfc 100644 --- a/app/Events/User/UserWasArchived.php +++ b/app/Events/User/UserWasArchived.php @@ -35,8 +35,8 @@ class UserWasArchived * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserWasCreated.php b/app/Events/User/UserWasCreated.php index c0e5e3b0352d..36268aa5d157 100644 --- a/app/Events/User/UserWasCreated.php +++ b/app/Events/User/UserWasCreated.php @@ -35,8 +35,8 @@ class UserWasCreated * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserWasDeleted.php b/app/Events/User/UserWasDeleted.php index 8c465ded4e60..04e6e68a2651 100644 --- a/app/Events/User/UserWasDeleted.php +++ b/app/Events/User/UserWasDeleted.php @@ -57,8 +57,8 @@ class UserWasDeleted * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserWasRestored.php b/app/Events/User/UserWasRestored.php index bfb3c9884a54..10870b0b09ed 100644 --- a/app/Events/User/UserWasRestored.php +++ b/app/Events/User/UserWasRestored.php @@ -57,8 +57,8 @@ class UserWasRestored * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Events/User/UserWasUpdated.php b/app/Events/User/UserWasUpdated.php index 24bddce0ca3c..79bf871eaa56 100644 --- a/app/Events/User/UserWasUpdated.php +++ b/app/Events/User/UserWasUpdated.php @@ -57,8 +57,8 @@ class UserWasUpdated * * @return Channel|array */ - // public function broadcastOn() - // { - // return new PrivateChannel('channel-name'); - // } + public function broadcastOn() + { + return []; + } } diff --git a/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php b/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php index c8bd816aa3e2..9d06a835d05f 100644 --- a/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php +++ b/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php @@ -54,7 +54,6 @@ class LockedInvoiceRule implements Rule switch ($lock_invoices) { case 'off': return true; - break; case 'when_sent': if ($this->invoice->status_id == Invoice::STATUS_SENT) { return false; @@ -62,17 +61,14 @@ class LockedInvoiceRule implements Rule return true; - break; case 'when_paid': if ($this->invoice->status_id == Invoice::STATUS_PAID) { return false; } return true; - break; default: return true; - break; } } } diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index df52f0084b15..746b2d366335 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -12,6 +12,7 @@ namespace App\Jobs\Util; use App\DataMapper\InvoiceItem; +use App\Factory\InvoiceFactory; use App\Jobs\Entity\EmailEntity; use App\Jobs\Ninja\TransactionLog; use App\Libraries\MultiDB; @@ -111,6 +112,11 @@ class ReminderJob implements ShouldQueue private function sendReminderForInvoice($invoice) { + App::forgetInstance('translator'); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($invoice->client->getMergedSettings())); + App::setLocale($invoice->client->locale()); + if ($invoice->isPayable()) { //Attempts to prevent duplicates from sending if ($invoice->reminder_last_sent && Carbon::parse($invoice->reminder_last_sent)->startOfDay()->eq(now()->startOfDay())) { @@ -121,7 +127,14 @@ class ReminderJob implements ShouldQueue $reminder_template = $invoice->calculateTemplate('invoice'); nlog("reminder template = {$reminder_template}"); $invoice->service()->touchReminder($reminder_template)->save(); - $invoice = $this->calcLateFee($invoice, $reminder_template); + $fees = $this->calcLateFee($invoice, $reminder_template); + + if(in_array($invoice->client->getSetting('lock_invoices'), ['when_sent','when_paid'])) { + return $this->addFeeToNewInvoice($invoice, $reminder_template, $fees); + } + else + $invoice = $this->setLateFee($invoice, $fees[0], $fees[1]); + //20-04-2022 fixes for endless reminders - generic template naming was wrong $enabled_reminder = 'enable_'.$reminder_template; @@ -148,14 +161,88 @@ class ReminderJob implements ShouldQueue } } + private function addFeeToNewInvoice(Invoice $over_due_invoice, string $reminder_template, array $fees): void + { + + $amount = $fees[0]; + $percent = $fees[1]; + + $temp_invoice_balance = $over_due_invoice->balance; + + if ($amount <= 0 && $percent <= 0) { + return; + } + + $fee = $amount; + + if ($over_due_invoice->partial > 0) { + $fee += round($over_due_invoice->partial * $percent / 100, 2); + } else { + $fee += round($over_due_invoice->balance * $percent / 100, 2); + } + + $invoice = InvoiceFactory::create($over_due_invoice->company_id, $over_due_invoice->user_id); + $invoice->client_id = $invoice->client_id; + $invoice->date = now()->format('Y-m-d'); + $invoice->due_date = now()->format('Y-m-d'); + + $invoice_item = new InvoiceItem(); + $invoice_item->type_id = '5'; + $invoice_item->product_key = trans('texts.fee'); + $invoice_item->notes = ctrans('texts.late_fee_added', ['date' => $this->translateDate(now()->startOfDay(), $over_due_invoice->client->date_format(), $over_due_invoice->client->locale())]); + $invoice_item->quantity = 1; + $invoice_item->cost = $fee; + + $invoice_items = []; + $invoice_items[] = $invoice_item; + + $invoice->line_items = $invoice_items; + + /**Refresh Invoice values*/ + $invoice = $invoice->calc()->getInvoice(); + $invoice->service() + ->createInvitations() + ->applyNumber() + ->markSent() + ->save(); + + nlog('adjusting client balance and invoice balance by #'.$invoice->number.' '.$invoice->balance); + $invoice->client->service()->updateBalance($invoice->balance); + $invoice->ledger()->updateInvoiceBalance($invoice->balance, "Late Fee Adjustment for invoice {$invoice->number}"); + + $invoice->service()->touchPdf(true); + + $enabled_reminder = 'enable_'.$reminder_template; + if ($reminder_template == 'endless_reminder') { + $enabled_reminder = 'enable_reminder_endless'; + } + + if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'endless_reminder']) && + $invoice->client->getSetting($enabled_reminder) && + $invoice->client->getSetting('send_reminders') && + (Ninja::isSelfHost() || $invoice->company->account->isPaidHostedClient())) { + $invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) { + if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) { + EmailEntity::dispatch($invitation, $invitation->company, $reminder_template); + nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); + $invoice->entityEmailEvent($invitation, $reminder_template); + } + }); + } + + $invoice->service()->setReminder()->save(); + + + } + /** * Calculates the late if - if any - and rebuilds the invoice * * @param Invoice $invoice * @param string $template - * @return Invoice + * @return array */ - private function calcLateFee($invoice, $template): Invoice + private function calcLateFee($invoice, $template): array { $late_fee_amount = 0; $late_fee_percent = 0; @@ -183,7 +270,8 @@ class ReminderJob implements ShouldQueue break; } - return $this->setLateFee($invoice, $late_fee_amount, $late_fee_percent); + return [$late_fee_amount, $late_fee_percent]; + // return $this->setLateFee($invoice, $late_fee_amount, $late_fee_percent); } /** @@ -197,10 +285,6 @@ class ReminderJob implements ShouldQueue */ private function setLateFee($invoice, $amount, $percent): Invoice { - App::forgetInstance('translator'); - $t = app('translator'); - $t->replace(Ninja::transformTranslations($invoice->client->getMergedSettings())); - App::setLocale($invoice->client->locale()); $temp_invoice_balance = $invoice->balance; @@ -236,16 +320,6 @@ class ReminderJob implements ShouldQueue $invoice->client->service()->updateBalance($invoice->balance - $temp_invoice_balance); $invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}"); - // $transaction = [ - // 'invoice' => $invoice->transaction_event(), - // 'payment' => [], - // 'client' => $invoice->client->transaction_event(), - // 'credit' => [], - // 'metadata' => ['setLateFee'], - // ]; - - // TransactionLog::dispatch(TransactionEvent::CLIENT_STATUS, $transaction, $invoice->company->db); - $invoice->service()->touchPdf(true); return $invoice; diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index ff8d3e7b38ab..52901ea8a215 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -11,7 +11,6 @@ namespace App\Models; -use App\DataMapper\ClientSettings; use App\Jobs\Util\WebhookHandler; use App\Models\Traits\Excludable; use App\Utils\Traits\MakesHash; @@ -39,6 +38,7 @@ use Illuminate\Support\Str; * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude(array $excludeable) * @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel scopeExclude() + * @method static \Illuminate\Database\Eloquent\Builder|BaseModel find() * @method \App\Models\Company company() * @method int companyId() * @method Builder|static exclude($columns) diff --git a/app/Models/Client.php b/app/Models/Client.php index 8bea25eb2a1e..37b5c76c2aa4 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -796,7 +796,7 @@ class Client extends BaseModel implements HasLocalePreference if ($pm['gateway_type_id'] == GatewayType::CREDIT_CARD) { $cg = CompanyGateway::find($pm['company_gateway_id']); - if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::CREDIT_CARD)) { + if ($cg && ! property_exists($cg->fees_and_limits, strval(GatewayType::CREDIT_CARD))) { $fees_and_limits = $cg->fees_and_limits; $fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits; $cg->fees_and_limits = $fees_and_limits; diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 788d4b17d683..b104cbccdada 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -92,6 +92,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @method static \Illuminate\Database\Eloquent\Builder|CompanyGateway whereUserId($value) * @method static \Illuminate\Database\Eloquent\Builder|CompanyGateway withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|CompanyGateway withoutTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|CompanyGateway find() * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens diff --git a/app/Models/Timezone.php b/app/Models/Timezone.php index daf773deb09b..3bc9c16a62c9 100644 --- a/app/Models/Timezone.php +++ b/app/Models/Timezone.php @@ -27,6 +27,7 @@ namespace App\Models; * @method static \Illuminate\Database\Eloquent\Builder|Timezone whereLocation($value) * @method static \Illuminate\Database\Eloquent\Builder|Timezone whereName($value) * @method static \Illuminate\Database\Eloquent\Builder|Timezone whereUtcOffset($value) + * @method static \Illuminate\Database\Eloquent\Builder|Timezone find() * @mixin \Eloquent */ class Timezone extends StaticModel diff --git a/tests/Unit/LateFeeTest.php b/tests/Unit/LateFeeTest.php index 66acfdbe742a..8c80584066c0 100644 --- a/tests/Unit/LateFeeTest.php +++ b/tests/Unit/LateFeeTest.php @@ -11,11 +11,18 @@ namespace Tests\Unit; -use App\DataMapper\InvoiceItem; -use App\Models\Invoice; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Tests\MockAccountData; use Tests\TestCase; +use App\Models\User; +use App\Models\Client; +use App\Models\Account; +use App\Models\Company; +use App\Models\Invoice; +use Tests\MockAccountData; +use App\Jobs\Util\ReminderJob; +use App\DataMapper\InvoiceItem; +use App\DataMapper\FeesAndLimits; +use App\DataMapper\CompanySettings; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -25,13 +32,164 @@ class LateFeeTest extends TestCase use DatabaseTransactions; use MockAccountData; + public $faker; + protected function setUp() :void { parent::setUp(); + $this->faker = \Faker\Factory::create(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + $this->makeTestData(); + + $this->withoutExceptionHandling(); + } + private function buildData($settings) + { + $this->account = Account::factory()->create([ + 'hosted_client_count' => 1000, + 'hosted_company_count' => 1000, + ]); + + $this->account->num_users = 3; + $this->account->save(); + + $this->user = User::factory()->create([ + 'account_id' => $this->account->id, + 'confirmation_code' => 'xyz123', + 'email' => $this->faker->unique()->safeEmail(), + ]); + + $this->company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + ]); + + $this->company->settings = $settings; + $this->company->save(); + + $settings = new \stdClass; + $settings->currency_id = '1'; + + $this->client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'is_deleted' => 0, + 'settings' => $settings, + ]); + } + + public function testLateFeeAdded() + { + + $settings = CompanySettings::defaults(); + $settings->client_online_payment_notification = false; + $settings->client_manual_payment_notification = false; + $settings->late_fee_amount1 = 10; + $settings->late_fee_percent1 = 0; + $settings->lock_invoices = 'off'; + $settings->enable_reminder1 = true; + $settings->num_days_reminder1 = 10; + $settings->schedule_reminder1 = 'after_due_date'; + + $this->buildData($settings); + + $i = Invoice::factory()->create([ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'amount' => 0, + 'balance' => 0, + 'status_id' => 2, + 'total_taxes' => 1, + 'date' => now()->format('Y-m-d'), + 'due_date' => now()->subDays(10)->format('Y-m-d'), + 'terms' => 'nada', + 'discount' => 0, + 'tax_rate1' => 0, + 'tax_rate2' => 0, + 'tax_rate3' => 0, + 'tax_name1' => '', + 'tax_name2' => '', + 'tax_name3' => '', + 'uses_inclusive_taxes' => false, + 'line_items' => $this->buildLineItems(), + ]); + + $i = $i->calc()->getInvoice(); + $i->service()->applyNumber()->createInvitations()->save(); + + $this->assertEquals(10, $i->amount); + + $reflectionMethod = new \ReflectionMethod(ReminderJob::class, 'sendReminderForInvoice'); + $reflectionMethod->setAccessible(true); + $reflectionMethod->invokeArgs(new ReminderJob(), [$i]); + + $i->fresh(); + + $this->assertEquals(20, $i->balance); + + } + + public function testLateFeeAddedToNewInvoiceWithLockedInvoiceConfi() + { + + $settings = CompanySettings::defaults(); + $settings->client_online_payment_notification = false; + $settings->client_manual_payment_notification = false; + $settings->late_fee_amount1 = 10; + $settings->late_fee_percent1 = 0; + $settings->lock_invoices = 'when_sent'; + $settings->enable_reminder1 = true; + $settings->num_days_reminder1 = 10; + $settings->schedule_reminder1 = 'after_due_date'; + + $this->buildData($settings); + + $i = Invoice::factory()->create([ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'amount' => 0, + 'balance' => 0, + 'status_id' => 2, + 'total_taxes' => 1, + 'date' => now()->format('Y-m-d'), + 'due_date' => now()->subDays(10)->format('Y-m-d'), + 'terms' => 'nada', + 'discount' => 0, + 'tax_rate1' => 0, + 'tax_rate2' => 0, + 'tax_rate3' => 0, + 'tax_name1' => '', + 'tax_name2' => '', + 'tax_name3' => '', + 'uses_inclusive_taxes' => false, + 'line_items' => $this->buildLineItems(), + ]); + + $i = $i->calc()->getInvoice(); + $i->service()->applyNumber()->createInvitations()->save(); + + $this->assertEquals(10, $i->amount); + + $reflectionMethod = new \ReflectionMethod(ReminderJob::class, 'sendReminderForInvoice'); + $reflectionMethod->setAccessible(true); + $reflectionMethod->invokeArgs(new ReminderJob(), [$i]); + + $i->fresh(); + + $this->assertEquals(10, $i->balance); + + } + + public function testLateFeeBalances() { $this->assertEquals(10, $this->client->balance);