diff --git a/VERSION.txt b/VERSION.txt index 3d325733355f..fcd2fd579853 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.7.28 \ No newline at end of file +5.7.29 \ No newline at end of file diff --git a/app/Console/Commands/CreateAccount.php b/app/Console/Commands/CreateAccount.php index 4bfa4c7a1326..d2ff960b2019 100644 --- a/app/Console/Commands/CreateAccount.php +++ b/app/Console/Commands/CreateAccount.php @@ -63,17 +63,25 @@ class CreateAccount extends Command private function createAccount() { + $settings = CompanySettings::defaults(); + + $settings->name = "Untitled Company"; + $settings->currency_id = '1'; + $settings->language_id = '1'; + $account = Account::factory()->create(); $company = Company::factory()->create([ 'account_id' => $account->id, 'portal_domain' => config('ninja.app_url'), 'portal_mode' => 'domain', + 'settings' => $settings, ]); $company->client_registration_fields = ClientRegistrationFields::generate(); $company->save(); $account->default_company_id = $company->id; + $account->set_react_as_default_ap = true; $account->save(); $email = $this->option('email') ?? 'admin@example.com'; diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index e4e8ff3085c5..bebf00b65d1f 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -841,6 +841,8 @@ class CompanySettings extends BaseSettings { $notification = new stdClass; $notification->email = []; + $notification->email = ['invoice_sent_all']; + // $notification->email = ['all_notifications']; return $notification; diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index 74625c98416c..b1f7fa9e6471 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -144,7 +144,7 @@ class InvoiceItemSum public function process(): self { - if (!$this->invoice->line_items || !is_array($this->invoice->line_items)) { + if (!$this->invoice->line_items || !is_iterable($this->invoice->line_items)) { $this->items = []; return $this; } diff --git a/app/Helpers/Invoice/InvoiceItemSumInclusive.php b/app/Helpers/Invoice/InvoiceItemSumInclusive.php index ad1a92600a08..7198abbfe8d1 100644 --- a/app/Helpers/Invoice/InvoiceItemSumInclusive.php +++ b/app/Helpers/Invoice/InvoiceItemSumInclusive.php @@ -131,8 +131,7 @@ class InvoiceItemSumInclusive public function process() { - if (! $this->invoice->line_items || ! is_array($this->invoice->line_items) || count($this->invoice->line_items) == 0) { - + if (!$this->invoice->line_items || ! is_iterable($this->invoice->line_items) || count($this->invoice->line_items) == 0) { return $this; } diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php index 3804ab890e94..bbed2ee5bbbf 100644 --- a/app/Http/Controllers/ClientPortal/InvoiceController.php +++ b/app/Http/Controllers/ClientPortal/InvoiceController.php @@ -195,7 +195,7 @@ class InvoiceController extends Controller //format data $invoices->map(function ($invoice) { - $invoice->service()->removeUnpaidGatewayFees(); + // $invoice->service()->removeUnpaidGatewayFees(); $invoice->balance = $invoice->balance > 0 ? Number::formatValue($invoice->balance, $invoice->client->currency()) : 0; $invoice->partial = $invoice->partial > 0 ? Number::formatValue($invoice->partial, $invoice->client->currency()) : 0; diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index c99a4a400fe8..0f94c8e9ac1a 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -290,10 +290,14 @@ class PreviewController extends BaseController return $maker->getCompiledHTML(); } } catch(\Exception $e) { - // nlog($e->getMessage()); + DB::connection(config('database.default'))->rollBack(); - return; + if (DB::connection(config('database.default'))->transactionLevel() > 0) { + DB::connection(config('database.default'))->rollBack(); + } + + return response()->json(['message' => 'Error generating preview. Please retry again shortly.'], 400); } //if phantom js...... inject here.. diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index 4fe0ccc36fbe..5eff1ff260cf 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -62,6 +62,7 @@ class Statement } $variables = $html->generateLabelsAndValues(); + $variables['values']['$show_paid_stamp'] = 'none'; //do not show paid stamp on statement $state = [ 'template' => $template->elements([ diff --git a/app/Services/Invoice/AddGatewayFee.php b/app/Services/Invoice/AddGatewayFee.php index 5729a13195ec..9716e558980f 100644 --- a/app/Services/Invoice/AddGatewayFee.php +++ b/app/Services/Invoice/AddGatewayFee.php @@ -29,7 +29,7 @@ class AddGatewayFee extends AbstractService { $gateway_fee = round($this->company_gateway->calcGatewayFee($this->amount, $this->gateway_type_id, $this->invoice->uses_inclusive_taxes), $this->invoice->client->currency()->precision); - if (! $gateway_fee) { + if (! $gateway_fee || $gateway_fee == 0) { return $this->invoice; } @@ -150,7 +150,7 @@ class AddGatewayFee extends AbstractService $this->invoice ->ledger() - ->updateInvoiceBalance($adjustment * -1, 'Adjustment for adding gateway fee'); + ->updateInvoiceBalance($adjustment * -1, 'Adjustment for adding gateway DISCOUNT'); } return $this->invoice; diff --git a/app/Services/Invoice/EInvoice/FacturaEInvoice.php b/app/Services/Invoice/EInvoice/FacturaEInvoice.php index a11c6cc03226..4ec4ca779e65 100644 --- a/app/Services/Invoice/EInvoice/FacturaEInvoice.php +++ b/app/Services/Invoice/EInvoice/FacturaEInvoice.php @@ -468,7 +468,7 @@ class FacturaEInvoice extends AbstractService { $company = $this->invoice->company; - if($company->getSetting('classification')) + if($company->getSetting('classification') == 'individual') return $this->setIndividualSeller(); $seller = new FacturaeParty([ @@ -512,7 +512,7 @@ class FacturaEInvoice extends AbstractService $seller = new FacturaeParty([ "isLegalEntity" => false, "taxNumber" => $company->settings->vat_number, - "name" => $company->getSetting('classification') === 'individual' ? substr($company->owner()->present()->name(), 0, 40) : substr($company->present()->name(), 0, 40), + // "name" => $company->getSetting('classification') === 'individual' ? substr($company->owner()->present()->name(), 0, 40) : substr($company->present()->name(), 0, 40), "address" => substr($company->settings->address1, 0, 80), "postCode" => substr($this->invoice->client->postal_code, 0, 5), "town" => substr($company->settings->city, 0, 50), @@ -529,7 +529,8 @@ class FacturaEInvoice extends AbstractService "fax" => "", "website" => substr($company->settings->website, 0, 50), // "contactPeople" => substr($company->owner()->present()->name(), 0, 40), - "firstSurname" => $company->owner()->present()->firstName(), + "name" => $company->owner()->present()->firstName(), + // "firstSurname" => $company->owner()->present()->firstName(), "lastSurname" => $company->owner()->present()->lastName(), ]); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 1122683a7735..c039078fc620 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -408,14 +408,15 @@ class InvoiceService $pre_count = count($this->invoice->line_items); - $this->invoice->line_items = collect($this->invoice->line_items) + $items = collect($this->invoice->line_items) ->reject(function ($item) { return $item->type_id == '3'; })->toArray(); + $this->invoice->line_items = array_values($items); + $this->invoice = $this->invoice->calc()->getInvoice(); - // $this->deletePdf(); - $this->deleteEInvoice(); + $this->deleteEInvoice(); //@deprecated /* 24-03-2022 */ $new_balance = $this->invoice->balance; diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 058f9ed36731..f96d37be5df8 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -12,21 +12,22 @@ namespace App\Utils; -use App\Helpers\Epc\EpcQrGenerator; -use App\Helpers\SwissQr\SwissQrGenerator; -use App\Models\Country; -use App\Models\CreditInvitation; -use App\Models\GatewayType; -use App\Models\InvoiceInvitation; -use App\Models\QuoteInvitation; -use App\Models\RecurringInvoiceInvitation; -use App\Utils\Traits\AppSetup; -use App\Utils\Traits\DesignCalculator; -use App\Utils\Traits\MakesDates; -use App\Utils\Traits\MakesHash; use Exception; +use App\Models\Account; +use App\Models\Country; +use App\Models\GatewayType; +use App\Utils\Traits\AppSetup; +use App\Models\QuoteInvitation; +use App\Utils\Traits\MakesHash; +use App\Models\CreditInvitation; +use App\Utils\Traits\MakesDates; +use App\Models\InvoiceInvitation; +use App\Helpers\Epc\EpcQrGenerator; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Cache; +use App\Utils\Traits\DesignCalculator; +use App\Helpers\SwissQr\SwissQrGenerator; +use App\Models\RecurringInvoiceInvitation; class HtmlEngine { @@ -1013,14 +1014,14 @@ html { */ protected function generateEntityImagesMarkup() { - if ($this->client->getSetting('embed_documents') === false) { - return ''; - } + // if (!$this->client->getSetting('embed_documents') && !$this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { + // return ''; + // } $dom = new \DOMDocument('1.0', 'UTF-8'); $container = $dom->createElement('div'); - $container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, 1fr);'); + $container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr);justify-items: center;'); foreach ($this->entity->documents as $document) { if (!$document->isImage()) { @@ -1029,8 +1030,8 @@ html { $image = $dom->createElement('img'); - $image->setAttribute('src', $document->generateUrl()); - $image->setAttribute('style', 'max-height: 100px; margin-top: 20px;'); + $image->setAttribute('src', "data:image/png;base64,".base64_encode($document->getFile())); + $image->setAttribute('style', 'max-width: 50%; margin-top: 20px;'); $container->appendChild($image); } @@ -1040,7 +1041,7 @@ html { $html = $dom->saveHTML(); $dom = null; - + return $html; } diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 35f065757b3d..153a9d65d21a 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -33,7 +33,7 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; - if ($invitation->company->is_disabled && + if ($company_user->company->is_disabled && is_array($notifications->email) || $company_user->trashed() || ! $company_user->user || @@ -43,7 +43,7 @@ trait UserNotifies //if a user owns this record or is assigned to it, they are attached the permission for notification. if ($invitation->{$entity_name}->user_id == $company_user->user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { - // $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); + } else { $required_permissions = $this->removeSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); } @@ -60,7 +60,7 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; - if ($entity->company->is_disabled || + if ($company_user->company->is_disabled || ! $notifications || $company_user->trashed() || ! $company_user->user || @@ -84,23 +84,6 @@ trait UserNotifies private function addSpecialUserPermissionForEntity($entity, array $required_permissions) :array { return array_merge($required_permissions, ['all_notifications', 'all_user_notifications']); - - // switch ($entity) { - // case $entity instanceof Payment || $entity instanceof Client: //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'payment_failure_user', 'payment_success_user']); - // case $entity instanceof Invoice: - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'invoice_created_user', 'invoice_sent_user', 'invoice_viewed_user', 'invoice_late_user']); - // case $entity instanceof Quote: - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'quote_created_user', 'quote_sent_user', 'quote_viewed_user', 'quote_approved_user', 'quote_expired_user']); - // case $entity instanceof Credit: - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'credit_created_user', 'credit_sent_user', 'credit_viewed_user']); - // case $entity instanceof PurchaseOrder: - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'purchase_order_created_user', 'purchase_order_sent_user', 'purchase_order_viewed_user']); - // case $entity instanceof Product: - // return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'inventory_user', 'inventory_all']); - // default: - // return []; - // } } private function removeSpecialUserPermissionForEntity($entity, $required_permissions) diff --git a/config/ninja.php b/config/ninja.php index b9c170a48bf9..5c38ee2e3562 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -15,8 +15,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION','5.7.28'), - 'app_tag' => env('APP_TAG','5.7.28'), + 'app_version' => env('APP_VERSION','5.7.29'), + 'app_tag' => env('APP_TAG','5.7.29'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), diff --git a/database/migrations/2023_10_10_083024_add_ariary_currency.php b/database/migrations/2023_10_10_083024_add_ariary_currency.php new file mode 100644 index 000000000000..51978dbab5c7 --- /dev/null +++ b/database/migrations/2023_10_10_083024_add_ariary_currency.php @@ -0,0 +1,39 @@ +id = 119; + $cur->code = 'MGA'; + $cur->name = 'Malagasy ariary'; + $cur->symbol = 'Ar'; + $cur->thousand_separator = ','; + $cur->decimal_separator = '.'; + $cur->precision = 0; + $cur->save(); + } + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/seeders/CurrenciesSeeder.php b/database/seeders/CurrenciesSeeder.php index 3005940fa1f9..b2c8b35af751 100644 --- a/database/seeders/CurrenciesSeeder.php +++ b/database/seeders/CurrenciesSeeder.php @@ -141,6 +141,7 @@ class CurrenciesSeeder extends Seeder ['id' => 116, 'name' => 'Silver Troy Ounce', 'code' => 'XAG', 'symbol' => 'XAG', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 117, 'name' => 'Gold Troy Ounce', 'code' => 'XAU', 'symbol' => 'XAU', 'precision' => '3', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 118, 'name' => 'Nicaraguan Córdoba', 'code' => 'NIO', 'symbol' => 'C$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['id' => 119, 'name' => 'Malagasy ariary', 'code' => 'MGA', 'symbol' => 'Ar', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], ]; foreach ($currencies as $currency) { diff --git a/database/seeders/RandomDataSeeder.php b/database/seeders/RandomDataSeeder.php index e508ba0daaee..027fad32815a 100644 --- a/database/seeders/RandomDataSeeder.php +++ b/database/seeders/RandomDataSeeder.php @@ -89,10 +89,16 @@ class RandomDataSeeder extends Seeder Model::unguard(); $faker = \Faker\Factory::create(); - + $settings= CompanySettings::defaults(); + + $settings->name = "Random Test Company"; + $settings->currency_id = '1'; + $settings->language_id = '1'; + $account = Account::factory()->create(); $company = Company::factory()->create([ 'account_id' => $account->id, + 'settings' => $settings, ]); $account->default_company_id = $company->id; diff --git a/resources/views/portal/ninja2020/gateways/gocardless/ach/pay.blade.php b/resources/views/portal/ninja2020/gateways/gocardless/ach/pay.blade.php index eb29b41515f5..aeb535ef3755 100644 --- a/resources/views/portal/ninja2020/gateways/gocardless/ach/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/gocardless/ach/pay.blade.php @@ -37,7 +37,9 @@ @endcomponent @endif - @include('portal.ninja2020.gateways.includes.pay_now') + @if (count($tokens) > 0) + @include('portal.ninja2020.gateways.includes.pay_now') + @endif @endsection @push('footer') diff --git a/resources/views/portal/ninja2020/gateways/gocardless/direct_debit/pay.blade.php b/resources/views/portal/ninja2020/gateways/gocardless/direct_debit/pay.blade.php index ac8071c3563b..75ff0ee4f077 100644 --- a/resources/views/portal/ninja2020/gateways/gocardless/direct_debit/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/gocardless/direct_debit/pay.blade.php @@ -38,7 +38,9 @@ @endcomponent @endif - @include('portal.ninja2020.gateways.includes.pay_now') + @if (count($tokens) > 0) + @include('portal.ninja2020.gateways.includes.pay_now') + @endif @endsection @push('footer') diff --git a/resources/views/portal/ninja2020/gateways/gocardless/sepa/pay.blade.php b/resources/views/portal/ninja2020/gateways/gocardless/sepa/pay.blade.php index 25b3c6a870fc..0732dcad478e 100644 --- a/resources/views/portal/ninja2020/gateways/gocardless/sepa/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/gocardless/sepa/pay.blade.php @@ -38,7 +38,9 @@ @endcomponent @endif - @include('portal.ninja2020.gateways.includes.pay_now') + @if (count($tokens) > 0) + @include('portal.ninja2020.gateways.includes.pay_now') + @endif @endsection @push('footer') diff --git a/tests/Unit/LateFeeTest.php b/tests/Unit/LateFeeTest.php index 383e9b2424dd..b89fa0ff13d5 100644 --- a/tests/Unit/LateFeeTest.php +++ b/tests/Unit/LateFeeTest.php @@ -22,6 +22,8 @@ use App\Jobs\Util\ReminderJob; use App\DataMapper\InvoiceItem; use App\DataMapper\FeesAndLimits; use App\DataMapper\CompanySettings; +use App\Factory\InvoiceItemFactory; +use App\Factory\ClientGatewayTokenFactory; use Illuminate\Foundation\Testing\DatabaseTransactions; /** @@ -93,6 +95,313 @@ class LateFeeTest extends TestCase return $client; } + public function testAddLateFeeAppropriately() + { + $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' => 'xyz']); + $invoice_item->quantity = 1; + $invoice_item->cost = 20; + + $invoice_items = $this->invoice->line_items; + $invoice_items[] = $invoice_item; + + $this->invoice->line_items = $invoice_items; + + $this->assertGreaterThan(1, count($this->invoice->line_items)); + + /**Refresh Invoice values*/ + $invoice = $this->invoice->calc()->getInvoice(); + + $this->assertGreaterThan(1, count($this->invoice->line_items)); + + } + + public function testModelBehaviourInsideMap() + { + $i = Invoice::factory()->count(5) + ->create([ + 'client_id' => $this->client->id, + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'tax_name1' => '', + 'tax_rate1' => 0, + 'tax_name2' => '', + 'tax_rate2' => 0, + 'tax_name3' => '', + 'tax_rate3' => 0, + 'discount' => 0, + ]); + + $i->each(function($invoice){ + $this->assertGreaterThan(1, count($invoice->line_items)); + }); + + $this->assertCount(5, $i); + + $invoices = $i->map(function ($invoice) { + $invoice->service()->removeUnpaidGatewayFees(); + return $invoice; + }); + + $invoices->each(function ($invoice) { + $this->assertGreaterThan(1, count($invoice->line_items)); + }); + + $ids = $invoices->pluck('id'); + + $invoices = $i->map(function ($invoice) { + + $line_items = $invoice->line_items; + + $item = new InvoiceItem; + $item->type_id = '3'; + $item->product_key = trans('texts.fee'); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = $item; + + $item = new InvoiceItem; + $item->type_id = '5'; + $item->product_key = trans('texts.fee'); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = $item; + $invoice->line_items = $line_items; + $invoice->saveQuietly(); + + return $invoice; + }); + + $invoices = Invoice::whereIn('id', $ids)->cursor()->map(function ($invoice){ + $this->assertGreaterThan(0, count($invoice->line_items)); + + $invoice->service()->removeUnpaidGatewayFees(); + $invoice = $invoice->fresh(); + $this->assertGreaterThan(0, count($invoice->line_items)); + + return $invoice; + }); + + $invoices->each(function ($invoice) { + $this->assertGreaterThan(0, count($invoice->line_items)); + }); + + } + + public function testCollectionPassesIsArray() + { + $line_items = collect($this->invoice->line_items); + $this->assertTrue(is_array($this->invoice->line_items)); + $this->assertTrue(is_iterable($line_items)); + $this->assertFalse(is_array($line_items)); + } + + public function testLineItemResiliency() + { + $line_count = count($this->invoice->line_items); + $this->assertGreaterThan(0, $line_count); + + $this->invoice->service()->removeUnpaidGatewayFees(); + + $this->invoice = $this->invoice->fresh(); + + $this->assertCount($line_count, $this->invoice->line_items); + } + + public function testCollectionAsLineItemArray() + { + + $i = Invoice::factory()->create([ + 'client_id' => $this->client->id, + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'tax_name1' => '', + 'tax_rate1' => 0, + 'tax_name2' => '', + 'tax_rate2' => 0, + 'tax_name3' => '', + 'tax_rate3' => 0, + 'discount' => 0, + ]); + + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + $item->type_id = '1'; + + $line_items[] = $item; + + $item = new InvoiceItem; + $item->type_id = '5'; + $item->product_key = trans('texts.fee'); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 1; + $item->type_id = '3'; + + $line_items[] = $item; + + $i->line_items = $line_items; + + $this->assertEquals(3, count($line_items)); + + $i = $i->calc()->getInvoice(); + + $this->assertEquals(3, count($i->line_items)); + $this->assertEquals(21, $i->amount); + + // $invoice_items = collect($invoice_items)->filter(function ($item) { + // return $item->type_id != '3'; + // }); + + // $this->invoice->line_items = $invoice_items; + + } + + public function testLateFeeRemovals() + { + + $data = []; + $data[1]['min_limit'] = -1; + $data[1]['max_limit'] = -1; + $data[1]['fee_amount'] = 0.00; + $data[1]['fee_percent'] = 1; + $data[1]['fee_tax_name1'] = ''; + $data[1]['fee_tax_rate1'] = 0; + $data[1]['fee_tax_name2'] = ''; + $data[1]['fee_tax_rate2'] = 0; + $data[1]['fee_tax_name3'] = ''; + $data[1]['fee_tax_rate3'] = 0; + $data[1]['adjust_fee_percent'] = false; + $data[1]['fee_cap'] = 0; + $data[1]['is_enabled'] = true; + + $cg = new \App\Models\CompanyGateway; + $cg->company_id = $this->company->id; + $cg->user_id = $this->user->id; + $cg->gateway_key = 'd14dd26a37cecc30fdd65700bfb55b23'; + $cg->require_cvv = true; + $cg->require_billing_address = true; + $cg->require_shipping_address = true; + $cg->update_details = true; + $cg->config = encrypt(config('ninja.testvars.stripe')); + $cg->fees_and_limits = $data; + $cg->save(); + + $cgt = ClientGatewayTokenFactory::create($this->company->id); + $cgt->client_id = $this->client->id; + $cgt->token = ''; + $cgt->gateway_customer_reference = ''; + $cgt->gateway_type_id = 1; + $cgt->company_gateway_id = $cg->id; + $cgt->save(); + + + $i = Invoice::factory()->create([ + 'client_id' => $this->client->id, + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'tax_name1' => '', + 'tax_rate1' => 0, + 'tax_name2' => '', + 'tax_rate2' => 0, + 'tax_name3' => '', + 'tax_rate3' => 0, + 'discount' => 0, + ]); + + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + $item->type_id = '1'; + + $line_items[] = $item; + + $item = new InvoiceItem; + $item->type_id = '5'; + $item->product_key = trans('texts.fee'); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 1; + $item->type_id = '3'; + + $line_items[] = $item; + + $i->line_items = $line_items; + + $i = $i->calc()->getInvoice(); + + $this->assertEquals(3, count($i->line_items)); + $this->assertEquals(21, $i->amount); + + $invoice_items = (array) $i->line_items; + + $invoice_items = collect($invoice_items)->filter(function ($item) { + return $item->type_id != '3'; + }); + + $i->line_items = $invoice_items; + + $i = $i->calc()->getInvoice(); + + $this->assertEquals(20, $i->amount); + + $i->line_items = collect($i->line_items) + ->reject(function ($item) { + return $item->type_id == '3'; + })->toArray(); + + $this->assertEquals(2, count($i->line_items)); + + $i->service()->autoBill(); + + $i = $i->fresh(); + + $this->assertCount(2, $i->line_items); + $this->assertEquals(20, $i->amount); + + $line_items = $i->line_items; + + $item = new InvoiceItem; + $item->type_id = '5'; + $item->product_key = trans('texts.fee'); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = $item; + + $i->line_items = $line_items; + + $i = $i->calc()->getInvoice(); + $this->assertEquals(30, $i->amount); + $this->assertCount(3, $i->line_items); + + $i->service()->autoBill(); + $i = $i->fresh(); + + $this->assertEquals(30, $i->amount); + $this->assertCount(3, $i->line_items); + + } + public function testLateFeeAdded() {