From e9d9b8a1379f5c5dde54a0fd30432e6fa6f54ec8 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 10:19:31 +1100 Subject: [PATCH 01/18] Tests for apple pay --- .../ClientPortal/ApplePayDomainController.php | 105 ++++++++++++++++++ .../ClientPortal/CreditController.php | 9 ++ app/PaymentDrivers/StripePaymentDriver.php | 9 ++ app/Utils/Traits/Uploadable.php | 1 + routes/api.php | 1 + routes/web.php | 1 + .../Feature/ApplePayDomainMerchantUrlTest.php | 64 +++++++++++ 7 files changed, 190 insertions(+) create mode 100644 app/Http/Controllers/ClientPortal/ApplePayDomainController.php create mode 100644 tests/Feature/ApplePayDomainMerchantUrlTest.php diff --git a/app/Http/Controllers/ClientPortal/ApplePayDomainController.php b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php new file mode 100644 index 000000000000..8901102fec0c --- /dev/null +++ b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php @@ -0,0 +1,105 @@ +stripe_keys) + ->where('is_deleted', false) + ->get(); + + foreach($cgs as $cg) + { + + if($cg->getConfigField('appleMerchantId')){ + return response($cg->getConfigField('appleMerchantId'),200); + + } + + } + + return response('', 400); + } + + /* Hosted */ + + $domain_name = $request->getHost(); + + if (strpos($domain_name, 'invoicing.co') !== false) + { + $subdomain = explode('.', $domain_name)[0]; + + $query = [ + 'subdomain' => $subdomain, + 'portal_mode' => 'subdomain', + ]; + + if($company = MultiDB::findAndSetDbByDomain($query)){ + return $this->resolveAppleMerchantId($company); + } + } + + $query = [ + 'portal_domain' => $request->getSchemeAndHttpHost(), + 'portal_mode' => 'domain', + ]; + + if($company = MultiDB::findAndSetDbByDomain($query)){ + return $this->resolveAppleMerchantId($company); + } + + return response('', 400); + + } + + private function resolveAppleMerchantId($company) + { + + $cgs = $company->company_gateways() + ->whereIn('gateway_key', $this->stripe_keys) + ->where('is_deleted', false) + ->get(); + + foreach($cgs as $cg) + { + + if($cg->getConfigField('appleMerchantId')){ + return response($cg->getConfigField('appleMerchantId'),200); + } + + } + + return response('', 400); + + } + +} diff --git a/app/Http/Controllers/ClientPortal/CreditController.php b/app/Http/Controllers/ClientPortal/CreditController.php index 2d5cafaa012d..a72b8b70bd47 100644 --- a/app/Http/Controllers/ClientPortal/CreditController.php +++ b/app/Http/Controllers/ClientPortal/CreditController.php @@ -1,4 +1,13 @@ run(); } + public function setDomain() + { + // \Stripe\ApplePayDomain::create([ + // 'domain_name' => 'example.com', + // ],[ + // 'stripe_account' => '{{CONNECTED_ACCOUNT_ID}}', + // ]); + } + public function disconnect() { if(!$this->stripe_connect) diff --git a/app/Utils/Traits/Uploadable.php b/app/Utils/Traits/Uploadable.php index 604bab5f5b1b..911e11053c96 100644 --- a/app/Utils/Traits/Uploadable.php +++ b/app/Utils/Traits/Uploadable.php @@ -42,4 +42,5 @@ trait Uploadable } } + } diff --git a/routes/api.php b/routes/api.php index ac07a0c107fd..796b50cc43bf 100644 --- a/routes/api.php +++ b/routes/api.php @@ -208,6 +208,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::resource('subscriptions', 'SubscriptionController'); Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk'); Route::get('statics', 'StaticController'); + Route::post('apple_pay/upload_file','ApplyPayController@upload'); }); diff --git a/routes/web.php b/routes/web.php index b8180d7f1583..f29bf383ab55 100644 --- a/routes/web.php +++ b/routes/web.php @@ -44,3 +44,4 @@ Route::get('stripe/completed', 'StripeConnectController@completed')->name('strip Route::get('checkout/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Checkout3dsController@index')->name('checkout.3ds_redirect'); Route::get('mollie/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Mollie3dsController@index')->name('mollie.3ds_redirect'); Route::get('gocardless/ibp_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\GoCardlessController@ibpRedirect')->name('gocardless.ibp_redirect'); +Route::get('.well-known/apple-developer-merchantid-domain-association', 'ClientPortal\ApplePayDomainController@showAppleMerchantId'); diff --git a/tests/Feature/ApplePayDomainMerchantUrlTest.php b/tests/Feature/ApplePayDomainMerchantUrlTest.php new file mode 100644 index 000000000000..869652de1b5a --- /dev/null +++ b/tests/Feature/ApplePayDomainMerchantUrlTest.php @@ -0,0 +1,64 @@ +makeTestData(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + } + + public function testMerchantFieldGet() + { + $config = new \stdClass; + $config->publishableKey = "pk_test"; + $config->apiKey = "sk_test"; + $config->appleMerchantId = "merchant_id"; + + $cg = new 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(json_encode($config)); + $cg->fees_and_limits = ''; + $cg->save(); + + $response = $this->withHeaders([])->get('.well-known/apple-developer-merchantid-domain-association'); + + $arr = $response->getContent(); + $response->assertStatus(200); + $this->assertEquals("merchant_id", $arr); + } +} From a30941bdb8e49709376c2068cbf6a23efceeda7f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 11:19:29 +1100 Subject: [PATCH 02/18] Fixes for tests --- .../ClientPortal/ApplePayDomainController.php | 2 - .../Controllers/CompanyGatewayController.php | 6 ++ app/Jobs/Util/ApplePayDomain.php | 93 +++++++++++++++++++ app/PaymentDrivers/StripePaymentDriver.php | 14 +-- .../Feature/ApplePayDomainMerchantUrlTest.php | 28 ++++++ 5 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 app/Jobs/Util/ApplePayDomain.php diff --git a/app/Http/Controllers/ClientPortal/ApplePayDomainController.php b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php index 8901102fec0c..a62249313a69 100644 --- a/app/Http/Controllers/ClientPortal/ApplePayDomainController.php +++ b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php @@ -24,8 +24,6 @@ class ApplePayDomainController extends Controller private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23']; - private ?Company $company = null; - public function showAppleMerchantId(Request $request) { diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index f810c6e44ca0..4f254dff9562 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -20,6 +20,7 @@ use App\Http\Requests\CompanyGateway\EditCompanyGatewayRequest; use App\Http\Requests\CompanyGateway\ShowCompanyGatewayRequest; use App\Http\Requests\CompanyGateway\StoreCompanyGatewayRequest; use App\Http\Requests\CompanyGateway\UpdateCompanyGatewayRequest; +use App\Jobs\Util\ApplePayDomain; use App\Models\Client; use App\Models\CompanyGateway; use App\Repositories\CompanyRepository; @@ -45,6 +46,9 @@ class CompanyGatewayController extends BaseController public $forced_includes = []; + private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23']; + + /** * CompanyGatewayController constructor. * @param CompanyRepository $company_repo @@ -379,6 +383,8 @@ class CompanyGatewayController extends BaseController $company_gateway->save(); + ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db); + return $this->itemResponse($company_gateway); } diff --git a/app/Jobs/Util/ApplePayDomain.php b/app/Jobs/Util/ApplePayDomain.php new file mode 100644 index 000000000000..305abe8e554a --- /dev/null +++ b/app/Jobs/Util/ApplePayDomain.php @@ -0,0 +1,93 @@ +db = $db; + + $this->company_gateway = $company_gateway; + + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + MultiDB::setDB($this->db); + + if(in_array($this->company_gateway->gateway_key, $this->stripe_keys)) + { + $domain = $this->getDomain(); + + $this->company_gateway->driver()->setApplePayDomain($domain); + + } + + } + + private function getDomain() + { + + $domain = ''; + + if(Ninja::isHosted()) + { + + if($this->company->portal_mode == 'domain'){ + $domain = $this->company->portal_domain; + } + else{ + $domain = $this->company->subdomain . '.' . config('ninja.app_domain'); + } + + } + else { + + $domain = config('ninja.app_url'); + } + + $parsed_url = parse_url($domain); + + return $parsed_url['host']; + + } + +} diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 48db7ff7c40e..8e5b960b268c 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -725,13 +725,15 @@ class StripePaymentDriver extends BaseDriver return (new Verify($this))->run(); } - public function setDomain() + public function setApplePayDomain($domain) { - // \Stripe\ApplePayDomain::create([ - // 'domain_name' => 'example.com', - // ],[ - // 'stripe_account' => '{{CONNECTED_ACCOUNT_ID}}', - // ]); + + $this->init(); + + \Stripe\ApplePayDomain::create([ + 'domain_name' => $domain, + ],$this->stripe_connect_auth); + } public function disconnect() diff --git a/tests/Feature/ApplePayDomainMerchantUrlTest.php b/tests/Feature/ApplePayDomainMerchantUrlTest.php index 869652de1b5a..b670970db5bd 100644 --- a/tests/Feature/ApplePayDomainMerchantUrlTest.php +++ b/tests/Feature/ApplePayDomainMerchantUrlTest.php @@ -38,6 +38,11 @@ class ApplePayDomainMerchantUrlTest extends TestCase public function testMerchantFieldGet() { + + if (! config('ninja.testvars.stripe')) { + $this->markTestSkipped('Skip test no company gateways installed'); + } + $config = new \stdClass; $config->publishableKey = "pk_test"; $config->apiKey = "sk_test"; @@ -61,4 +66,27 @@ class ApplePayDomainMerchantUrlTest extends TestCase $response->assertStatus(200); $this->assertEquals("merchant_id", $arr); } + + public function testDomainParsing() + { + $domain = 'http://ninja.test:8000'; + + $parsed = parse_url($domain); + + $this->assertEquals('ninja.test', $parsed['host']); + + $domain = 'ninja.test:8000'; + + $parsed = parse_url($domain); + + $this->assertEquals('ninja.test', $parsed['host']); + + $domain = 'http://ninja.test:8000/afadf/dfdfdf/dfdfasf'; + + $parsed = parse_url($domain); + + $this->assertEquals('ninja.test', $parsed['host']); + + + } } From 2f34411b5fe66b16c384bbc39695cde4e26ebe70 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 11:30:45 +1100 Subject: [PATCH 03/18] Try/catch for apple pay domain --- app/Jobs/Util/ApplePayDomain.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Jobs/Util/ApplePayDomain.php b/app/Jobs/Util/ApplePayDomain.php index 305abe8e554a..add6041ba478 100644 --- a/app/Jobs/Util/ApplePayDomain.php +++ b/app/Jobs/Util/ApplePayDomain.php @@ -55,9 +55,15 @@ class ApplePayDomain implements ShouldQueue if(in_array($this->company_gateway->gateway_key, $this->stripe_keys)) { + $domain = $this->getDomain(); - $this->company_gateway->driver()->setApplePayDomain($domain); + try{ + $this->company_gateway->driver()->setApplePayDomain($domain); + } + catch(\Exception $e){ + nlog("failed to set Apple Domain with Stripe " . $e->getMessage()); + } } From 37a4c4810d4953b0fe25c0d4170d1e8167e1aa28 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 11:52:24 +1100 Subject: [PATCH 04/18] Stripe Apple Pay --- app/Http/Controllers/CompanyGatewayController.php | 2 ++ app/Jobs/Util/ApplePayDomain.php | 1 + app/Services/Invoice/InvoiceService.php | 5 +++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index 4f254dff9562..9c0a4f4eff4a 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -210,6 +210,8 @@ class CompanyGatewayController extends BaseController $company_gateway->save(); } + ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db); + return $this->itemResponse($company_gateway); } diff --git a/app/Jobs/Util/ApplePayDomain.php b/app/Jobs/Util/ApplePayDomain.php index add6041ba478..8dc6230b557f 100644 --- a/app/Jobs/Util/ApplePayDomain.php +++ b/app/Jobs/Util/ApplePayDomain.php @@ -51,6 +51,7 @@ class ApplePayDomain implements ShouldQueue */ public function handle() { + MultiDB::setDB($this->db); if(in_array($this->company_gateway->gateway_key, $this->stripe_keys)) diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index f551b8d1972a..23c50125c89d 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -333,9 +333,10 @@ class InvoiceService try{ - Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'); + if(Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf')) + Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'); - if(Ninja::isHosted()) { + if(Ninja::isHosted() && Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf')) { Storage::disk('public')->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'); } From 0634698c5b550575d2e0ee5e9cc7d93c51fe1092 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 13:08:19 +1100 Subject: [PATCH 05/18] Enfore payment_terms to '0' if none is set --- app/Jobs/Util/Import.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index 347ed8998dd7..773ef8326243 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -471,8 +471,9 @@ class Import implements ShouldQueue } - if ($key == 'payment_terms' && $key = '') { - $value = -1; + /* changes $key = '' to $value == '' and changed the return value from -1 to "0" 06/01/2022 */ + if ($key == 'payment_terms' && $value == '') { + $value = "0"; } $company_settings->{$key} = $value; From abbca58b4d9260b7a4991931376801d3cd5fdc03 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 13:31:44 +1100 Subject: [PATCH 06/18] Do not allow an invoice to be created for a deleted client --- .../Requests/Invoice/StoreInvoiceRequest.php | 2 +- .../ClientDeletedInvoiceCreationTest.php | 78 +++++++++++++++++++ tests/Feature/InvoiceTest.php | 15 ++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/ClientDeletedInvoiceCreationTest.php diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index b0fe7266fd8a..527c108cdbdd 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -47,7 +47,7 @@ class StoreInvoiceRequest extends Request $rules['documents'] = 'file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000'; } - $rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id; + $rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; // $rules['client_id'] = ['required', Rule::exists('clients')->where('company_id', auth()->user()->company()->id)]; $rules['invitations.*.client_contact_id'] = 'distinct'; diff --git a/tests/Feature/ClientDeletedInvoiceCreationTest.php b/tests/Feature/ClientDeletedInvoiceCreationTest.php new file mode 100644 index 000000000000..09429203658b --- /dev/null +++ b/tests/Feature/ClientDeletedInvoiceCreationTest.php @@ -0,0 +1,78 @@ +faker = \Faker\Factory::create(); + + Model::reguard(); + + $this->makeTestData(); + } + + public function testClientedDeletedAttemptingToCreateInvoice() + { + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/', $data) + ->assertStatus(200); + + $this->client->is_deleted = true; + $this->client->save(); + + + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude2', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/', $data) + ->assertStatus(302); + + + } + +} diff --git a/tests/Feature/InvoiceTest.php b/tests/Feature/InvoiceTest.php index 68341e10b631..87d37188f2f1 100644 --- a/tests/Feature/InvoiceTest.php +++ b/tests/Feature/InvoiceTest.php @@ -220,4 +220,19 @@ class InvoiceTest extends TestCase ])->put('/api/v1/invoices/'.$arr['data']['id'], $data) ->assertStatus(200); } + + public function testClientedDeletedAttemptingToCreateInvoice() + { + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/', $data) + ->assertStatus(200); + } } From b42ae9023b29d0cd5b8ffb9ddfac33868b233065 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 14:53:03 +1100 Subject: [PATCH 07/18] Minor fixes for tests --- tests/Feature/ClientDeletedInvoiceCreationTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/ClientDeletedInvoiceCreationTest.php b/tests/Feature/ClientDeletedInvoiceCreationTest.php index 09429203658b..3ec20cb30f10 100644 --- a/tests/Feature/ClientDeletedInvoiceCreationTest.php +++ b/tests/Feature/ClientDeletedInvoiceCreationTest.php @@ -51,7 +51,7 @@ class ClientDeletedInvoiceCreationTest extends TestCase 'number' => 'dude', ]; - $response = $this->withHeaders([ + $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token, ])->post('/api/v1/invoices/', $data) @@ -66,7 +66,7 @@ class ClientDeletedInvoiceCreationTest extends TestCase 'number' => 'dude2', ]; - $response = $this->withHeaders([ + $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token, ])->post('/api/v1/invoices/', $data) From 240df693a51d59a5de6e74e1a8e622c9163c8417 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 15:58:55 +1100 Subject: [PATCH 08/18] Fixes for FlySystem exceptions for corrupt paths --- app/Models/Invoice.php | 25 +++++++++++++++++-- .../Authorize/AuthorizePaymentMethod.php | 3 ++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 7d2257c6b19a..93ada7f481c5 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -409,7 +409,19 @@ class Invoice extends BaseModel $file_path = $this->client->invoice_filepath($invitation).$this->numberFormatter().'.pdf'; - if(Ninja::isHosted() && $portal && Storage::disk(config('filesystems.default'))->exists($file_path)){ + $file_exists = false; + + /* Flysystem throws an exception if the path is "corrupted" so lets wrap it in a try catch and return a bool 06/01/2022*/ + try{ + $file_exists = Storage::disk(config('filesystems.default'))->exists($file_path); + } + catch(\Exception $e){ + + nlog($e->getMessage()); + + } + + if(Ninja::isHosted() && $portal && $file_exists){ return Storage::disk(config('filesystems.default'))->{$type}($file_path); } elseif(Ninja::isHosted()){ @@ -417,7 +429,16 @@ class Invoice extends BaseModel return Storage::disk(config('filesystems.default'))->{$type}($file_path); } - if(Storage::disk('public')->exists($file_path)) + try{ + $file_exists = Storage::disk('public')->exists($file_path); + } + catch(\Exception $e){ + + nlog($e->getMessage()); + + } + + if($file_exists) return Storage::disk('public')->{$type}($file_path); $file_path = CreateEntityPdf::dispatchNow($invitation); diff --git a/app/PaymentDrivers/Authorize/AuthorizePaymentMethod.php b/app/PaymentDrivers/Authorize/AuthorizePaymentMethod.php index e2cb1e6613d1..ba359b259443 100644 --- a/app/PaymentDrivers/Authorize/AuthorizePaymentMethod.php +++ b/app/PaymentDrivers/Authorize/AuthorizePaymentMethod.php @@ -157,7 +157,8 @@ class AuthorizePaymentMethod $paymentOne->setOpaqueData($op); $contact = $this->authorize->client->primary_contact()->first(); - + $billto = false; + if ($contact) { // Create the Bill To info for new payment type $billto = new CustomerAddressType(); From 996b3f246bb9980136271115a355f326837c3da3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 17:21:11 +1100 Subject: [PATCH 09/18] Add Apple Domain Verification to Stripe Gateways --- ...31_add_app_domain_id_to_gateways_table.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php diff --git a/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php b/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php new file mode 100644 index 000000000000..23c8757e6bff --- /dev/null +++ b/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php @@ -0,0 +1,39 @@ +fields = '{"account_id":"", "appleDomainVerification":""}'; + $stripe_connect->save(); + + } + + $stripe_connect = Gateway::find(20); + $stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}'; + $stripe_connect->save(); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + +} From 057cf9cd4248bc10aee64a9a901754067deb8f00 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 17:30:43 +1100 Subject: [PATCH 10/18] Minor fixes for Additional Stripe Field --- .../2021_04_12_095424_stripe_connect_gateway.php | 2 +- ...061231_add_app_domain_id_to_gateways_table.php | 15 ++++++++++----- database/seeders/PaymentLibrariesSeeder.php | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/database/migrations/2021_04_12_095424_stripe_connect_gateway.php b/database/migrations/2021_04_12_095424_stripe_connect_gateway.php index 4a6959c13a30..ef85ec207b3d 100644 --- a/database/migrations/2021_04_12_095424_stripe_connect_gateway.php +++ b/database/migrations/2021_04_12_095424_stripe_connect_gateway.php @@ -24,7 +24,7 @@ class StripeConnectGateway extends Migration 'provider' => 'StripeConnect', 'sort_order' => 1, 'key' => 'd14dd26a47cecc30fdd65700bfb67b34', - 'fields' => '{"account_id":""}' + 'fields' => '{"account_id":"","appleDomainVerification":""}' ]; Gateway::create($gateway); diff --git a/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php b/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php index 23c8757e6bff..35193d605575 100644 --- a/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php +++ b/database/migrations/2022_01_06_061231_add_app_domain_id_to_gateways_table.php @@ -19,14 +19,19 @@ class AddAppDomainIdToGatewaysTable extends Migration if(Ninja::isHosted()){ $stripe_connect = Gateway::find(56); - $stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}'; - $stripe_connect->save(); - + + if($stripe_connect){ + $stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}'; + $stripe_connect->save(); + } } $stripe_connect = Gateway::find(20); - $stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}'; - $stripe_connect->save(); + + if($stripe_connect){ + $stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}'; + $stripe_connect->save(); + } } diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index c4d50c57d099..fac849bf7398 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -44,7 +44,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 17, 'name' => 'Pin', 'provider' => 'Pin', 'key' => '0749cb92a6b36c88bd9ff8aabd2efcab', 'fields' => '{"secretKey":"","testMode":false}'], ['id' => 18, 'name' => 'SagePay Direct', 'provider' => 'SagePay_Direct', 'key' => '4c8f4e5d0f353a122045eb9a60cc0f2d', 'fields' => '{"vendor":"","testMode":false,"referrerId":""}'], ['id' => 19, 'name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost', 'key' => '8036a5aadb2bdaafb23502da8790b6a2', 'fields' => '{"merchantId":"","transactionPassword":"","testMode":false,"enable_ach":"","enable_sofort":"","enable_apple_pay":"","enable_alipay":""}'], - ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":""}'], + ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":"","appleDomainVerification":""}'], ['id' => 21, 'name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking', 'key' => 'd14dd26a37cdcc30fdd65700bfb55b23', 'fields' => '{"subAccountId":""}'], ['id' => 22, 'name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal', 'key' => 'ea3b328bd72d381387281c3bd83bd97c', 'fields' => '{"subAccountId":""}'], ['id' => 23, 'name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash', 'key' => 'a0035fc0d87c4950fb82c73e2fcb825a', 'fields' => '{"subAccountId":""}'], From f5f2395d7eb34928d213239cae807c709f924997 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 20:03:30 +1100 Subject: [PATCH 11/18] Fixes for clean design --- .../Controllers/ClientPortal/ApplePayDomainController.php | 8 ++++---- resources/views/pdf-designs/clean.html | 7 ++++++- tests/Feature/ApplePayDomainMerchantUrlTest.php | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/ApplePayDomainController.php b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php index a62249313a69..ab89cc869035 100644 --- a/app/Http/Controllers/ClientPortal/ApplePayDomainController.php +++ b/app/Http/Controllers/ClientPortal/ApplePayDomainController.php @@ -38,8 +38,8 @@ class ApplePayDomainController extends Controller foreach($cgs as $cg) { - if($cg->getConfigField('appleMerchantId')){ - return response($cg->getConfigField('appleMerchantId'),200); + if($cg->getConfigField('appleDomainVerification')){ + return response($cg->getConfigField('appleDomainVerification'),200); } @@ -90,8 +90,8 @@ class ApplePayDomainController extends Controller foreach($cgs as $cg) { - if($cg->getConfigField('appleMerchantId')){ - return response($cg->getConfigField('appleMerchantId'),200); + if($cg->getConfigField('appleDomainVerification')){ + return response($cg->getConfigField('appleDomainVerification'),200); } } diff --git a/resources/views/pdf-designs/clean.html b/resources/views/pdf-designs/clean.html index e23a1a111b12..aac1b3969f96 100644 --- a/resources/views/pdf-designs/clean.html +++ b/resources/views/pdf-designs/clean.html @@ -117,17 +117,22 @@ [data-ref="table"] > tbody > tr > td { border-top: 1px solid #d8d8d8; border-bottom: 1px solid #d8d8d8; - padding: 1.5rem; + padding: 1.5rem 1rem; } [data-ref="table"] > tbody > tr > td:first-child { color: var(--primary-color); } + [data-ref="table"] > thead > tr > th:last-child, [data-ref="table"] > tbody > tr > td:last-child { text-align: right; } + [data-ref="table"] > thead > tr > th:last-child { + padding-right: 1rem; + } + [data-ref="table"] > tbody > tr:nth-child(odd) { background-color: #f5f5f5; } diff --git a/tests/Feature/ApplePayDomainMerchantUrlTest.php b/tests/Feature/ApplePayDomainMerchantUrlTest.php index b670970db5bd..a2387f5f3536 100644 --- a/tests/Feature/ApplePayDomainMerchantUrlTest.php +++ b/tests/Feature/ApplePayDomainMerchantUrlTest.php @@ -46,7 +46,7 @@ class ApplePayDomainMerchantUrlTest extends TestCase $config = new \stdClass; $config->publishableKey = "pk_test"; $config->apiKey = "sk_test"; - $config->appleMerchantId = "merchant_id"; + $config->appleDomainVerification = "merchant_id"; $cg = new CompanyGateway; $cg->company_id = $this->company->id; From 89ce2b443eb8b4d30319d7b873a8e93e5a4a9b20 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 6 Jan 2022 21:06:46 +1100 Subject: [PATCH 12/18] Fixes for mollie payment driver --- app/PaymentDrivers/BaseDriver.php | 4 ++-- app/Services/Invoice/TriggeredActions.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index c9031daaeae0..a85229956014 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -256,13 +256,13 @@ class BaseDriver extends AbstractPaymentDriver $this->payment_hash->payment_id = $payment->id; $this->payment_hash->save(); + $this->attachInvoices($payment, $this->payment_hash); + if($this->payment_hash->credits_total() > 0) $payment = $payment->service()->applyCredits($this->payment_hash)->save(); $payment->service()->updateInvoicePayment($this->payment_hash); - $this->attachInvoices($payment, $this->payment_hash); - event('eloquent.created: App\Models\Payment', $payment); if ($this->client->getSetting('client_online_payment_notification') && in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING])) diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index b2f2ee395b53..f9b19f4b1b5c 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -49,6 +49,7 @@ class TriggeredActions extends AbstractService } if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { + $this->invoice->service()->touchPdf()->save(); $this->sendEmail(); } From 3417b1ff0f5cc0aa2840e752f130243efda424af Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 7 Jan 2022 11:54:12 +1100 Subject: [PATCH 13/18] Fixes for send_email triggered action not generating PDFs in time. --- app/Services/Credit/TriggeredActions.php | 1 + app/Services/Invoice/TriggeredActions.php | 2 +- app/Services/Quote/TriggeredActions.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Services/Credit/TriggeredActions.php b/app/Services/Credit/TriggeredActions.php index 28134972af8d..cfc10e2d286a 100644 --- a/app/Services/Credit/TriggeredActions.php +++ b/app/Services/Credit/TriggeredActions.php @@ -38,6 +38,7 @@ class TriggeredActions extends AbstractService { if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { + $this->credit = $this->credit->service()->markSent()->save(); $this->sendEmail(); } diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index f9b19f4b1b5c..2636a5376f34 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -49,7 +49,7 @@ class TriggeredActions extends AbstractService } if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { - $this->invoice->service()->touchPdf()->save(); + $this->invoice->service()->markSent()->touchPdf()->save(); $this->sendEmail(); } diff --git a/app/Services/Quote/TriggeredActions.php b/app/Services/Quote/TriggeredActions.php index fa630d753fe6..ea38a696c509 100644 --- a/app/Services/Quote/TriggeredActions.php +++ b/app/Services/Quote/TriggeredActions.php @@ -38,6 +38,7 @@ class TriggeredActions extends AbstractService { if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { + $this->quote = $this->quote->service()->markSent()->save(); $this->sendEmail(); } From 8f9febe5f84a1a066af738b4d8852b5721548ac5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 7 Jan 2022 13:39:31 +1100 Subject: [PATCH 14/18] Force ZAR for PayFast --- app/PaymentDrivers/PayFastPaymentDriver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/PaymentDrivers/PayFastPaymentDriver.php b/app/PaymentDrivers/PayFastPaymentDriver.php index b67026eaf518..8d3ab1e6d062 100644 --- a/app/PaymentDrivers/PayFastPaymentDriver.php +++ b/app/PaymentDrivers/PayFastPaymentDriver.php @@ -49,7 +49,8 @@ class PayFastPaymentDriver extends BaseDriver { $types = []; - if($this->client->currency()->code == 'ZAR' || $this->client->currency()->code == 'USD') + // if($this->client->currency()->code == 'ZAR' || $this->client->currency()->code == 'USD') + if($this->client->currency()->code == 'ZAR') $types[] = GatewayType::CREDIT_CARD; return $types; From addc10ef4e7ea451cef160434b6462dcbff99aff Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 7 Jan 2022 13:56:02 +1100 Subject: [PATCH 15/18] Hide expired quotes from client portal --- app/Http/Livewire/QuotesTable.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Http/Livewire/QuotesTable.php b/app/Http/Livewire/QuotesTable.php index f52ee96fd945..e93d24ec6d06 100644 --- a/app/Http/Livewire/QuotesTable.php +++ b/app/Http/Livewire/QuotesTable.php @@ -49,6 +49,10 @@ class QuotesTable extends Component ->where('company_id', $this->company->id) ->where('client_id', auth('contact')->user()->client->id) ->where('status_id', '<>', Quote::STATUS_DRAFT) + ->where(function ($query){ + $query->whereDate('due_date', '>=', now()) + ->orWhereNull('due_date'); + }) ->where('is_deleted', 0) ->withTrashed() ->paginate($this->per_page); From 959d45f0818614ca46b6e950f6595e3b01f093cc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 7 Jan 2022 15:03:42 +1100 Subject: [PATCH 16/18] Fixes for client portal quote tables --- .../ClientPortal/QuoteController.php | 5 ++- app/Http/Livewire/QuotesTable.php | 38 ++++++++++++++++--- app/Models/Quote.php | 11 ++++++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/QuoteController.php b/app/Http/Controllers/ClientPortal/QuoteController.php index c646d41efee9..1b0fa8214428 100644 --- a/app/Http/Controllers/ClientPortal/QuoteController.php +++ b/app/Http/Controllers/ClientPortal/QuoteController.php @@ -31,6 +31,7 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse; use ZipStream\Option\Archive; use ZipStream\ZipStream; use Illuminate\Http\Request; +use Illuminate\Support\Carbon; class QuoteController extends Controller { @@ -54,7 +55,9 @@ class QuoteController extends Controller * @return Factory|View|BinaryFileResponse */ public function show(ShowQuoteRequest $request, Quote $quote) - { + { + /* If the quote is expired, convert the status here */ + $data = [ 'quote' => $quote, ]; diff --git a/app/Http/Livewire/QuotesTable.php b/app/Http/Livewire/QuotesTable.php index e93d24ec6d06..1aa996f089d9 100644 --- a/app/Http/Livewire/QuotesTable.php +++ b/app/Http/Livewire/QuotesTable.php @@ -42,17 +42,45 @@ class QuotesTable extends Component ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc'); if (count($this->status) > 0) { - $query = $query->whereIn('status_id', $this->status); + + /* Special filter for expired*/ + if(in_array("-1", $this->status)){ + // $query->whereDate('due_date', '<=', now()->startOfDay()); + + $query->where(function ($query){ + $query->whereDate('due_date', '<=', now()->startOfDay()) + ->whereNotNull('due_date') + ->where('status_id', '<>', Quote::STATUS_CONVERTED); + }); + + } + + if(in_array("2", $this->status)){ + + $query->where(function ($query){ + $query->whereDate('due_date', '>=', now()->startOfDay()) + ->orWhereNull('due_date'); + })->where('status_id', Quote::STATUS_SENT); + + } + + if(in_array("3", $this->status)){ + $query->whereIn('status_id', [Quote::STATUS_APPROVED, Quote::STATUS_CONVERTED]); + } + + } + + $query = $query ->where('company_id', $this->company->id) ->where('client_id', auth('contact')->user()->client->id) ->where('status_id', '<>', Quote::STATUS_DRAFT) - ->where(function ($query){ - $query->whereDate('due_date', '>=', now()) - ->orWhereNull('due_date'); - }) + // ->where(function ($query){ + // $query->whereDate('due_date', '>=', now()) + // ->orWhereNull('due_date'); + // }) ->where('is_deleted', 0) ->withTrashed() ->paginate($this->per_page); diff --git a/app/Models/Quote.php b/app/Models/Quote.php index b5d105313913..451c73f69d5a 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -87,6 +87,7 @@ class Quote extends BaseModel 'updated_at' => 'timestamp', 'created_at' => 'timestamp', 'deleted_at' => 'timestamp', + 'is_deleted' => 'boolean', ]; protected $dates = []; @@ -117,6 +118,16 @@ class Quote extends BaseModel return $this->dateMutator($value); } + public function getStatusIdAttribute($value) + { + if($this->due_date && !$this->is_deleted && $value == Quote::STATUS_SENT && Carbon::parse($this->due_date)->lte(now()->startOfDay())){ + return Quote::STATUS_EXPIRED; + } + + return $value; + + } + public function company() { return $this->belongsTo(Company::class); From e0204a19d5778eae03a0274d5d6256a10bfdb4ba Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 8 Jan 2022 12:28:41 +1100 Subject: [PATCH 17/18] touch pdf on sent --- app/Services/Invoice/MarkSent.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Services/Invoice/MarkSent.php b/app/Services/Invoice/MarkSent.php index 7527ab633b1f..40a851f6dd09 100644 --- a/app/Services/Invoice/MarkSent.php +++ b/app/Services/Invoice/MarkSent.php @@ -63,7 +63,8 @@ class MarkSent extends AbstractService ->service() ->applyNumber() ->setDueDate() - ->deletePdf() + // ->deletePdf() //08-01-2022 + ->touchPdf() //08-01-2022 ->setReminder() ->save(); From 92b490043c8fcf5b5153cddd4994f325bc2f3bad Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 8 Jan 2022 14:54:02 +1100 Subject: [PATCH 18/18] Handle 100% gateway fees --- VERSION.txt | 2 +- app/Models/CompanyGateway.php | 41 ++-------------- config/ninja.php | 4 +- tests/Feature/CompanyGatewayApiTest.php | 65 +++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 40 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 6ce7f3e4b421..93a75a086973 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.3.41 \ No newline at end of file +5.3.42 \ No newline at end of file diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index a31823a5541b..7c6451253f1e 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -343,7 +343,10 @@ class CompanyGateway extends BaseModel } if ($fees_and_limits->fee_percent) { - if ($fees_and_limits->adjust_fee_percent) { + if($fees_and_limits->fee_percent == 100){ //unusual edge case if the user wishes to charge a fee of 100% 09/01/2022 + $fee += $amount; + } + elseif ($fees_and_limits->adjust_fee_percent) { $fee += round(($amount / (1 - $fees_and_limits->fee_percent / 100) - $amount), 2); } else { $fee += round(($amount * $fees_and_limits->fee_percent / 100), 2); @@ -383,42 +386,6 @@ class CompanyGateway extends BaseModel return route('payment_webhook', ['company_key' => $this->company->company_key, 'company_gateway_id' => $this->hashed_id]); } - /** - * we need to average out the gateway fees across all the invoices - * so lets iterate. - * - * we MAY need to adjust the final fee to ensure our rounding makes sense! - * @param $amount - * @param $invoice_count - * @return stdClass - */ - // public function calcGatewayFeeObject($amount, $invoice_count) - // { - // $total_gateway_fee = $this->calcGatewayFee($amount); - - // $fee_object = new stdClass; - - // $fees_and_limits = $this->getFeesAndLimits(); - - // if (! $fees_and_limits) { - // return $fee_object; - // } - - // $fee_component_amount = $fees_and_limits->fee_amount ?: 0; - // $fee_component_percent = $fees_and_limits->fee_percent ? ($amount * $fees_and_limits->fee_percent / 100) : 0; - - // $combined_fee_component = $fee_component_amount + $fee_component_percent; - - // $fee_component_tax_name1 = $fees_and_limits->fee_tax_name1 ?: ''; - // $fee_component_tax_rate1 = $fees_and_limits->fee_tax_rate1 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate1 / 100) : 0; - - // $fee_component_tax_name2 = $fees_and_limits->fee_tax_name2 ?: ''; - // $fee_component_tax_rate2 = $fees_and_limits->fee_tax_rate2 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate2 / 100) : 0; - - // $fee_component_tax_name3 = $fees_and_limits->fee_tax_name3 ?: ''; - // $fee_component_tax_rate3 = $fees_and_limits->fee_tax_rate3 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate3 / 100) : 0; - // } - public function resolveRouteBinding($value, $field = null) { return $this diff --git a/config/ninja.php b/config/ninja.php index 10e0fa553f36..c3656dce7023 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.3.41', - 'app_tag' => '5.3.41', + 'app_version' => '5.3.42', + 'app_tag' => '5.3.42', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), diff --git a/tests/Feature/CompanyGatewayApiTest.php b/tests/Feature/CompanyGatewayApiTest.php index 373196c8e92b..f1b3e5fec774 100644 --- a/tests/Feature/CompanyGatewayApiTest.php +++ b/tests/Feature/CompanyGatewayApiTest.php @@ -319,6 +319,71 @@ class CompanyGatewayApiTest extends TestCase $this->assertEquals(10.2, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD)); } + + public function testFeesAndLimitsFeePercentAndAmountCalcuationOneHundredPercent() + { + //{"1":{"min_limit":1,"max_limit":1000000,"fee_amount":10,"fee_percent":2,"fee_tax_name1":"","fee_tax_name2":"","fee_tax_name3":"","fee_tax_rate1":0,"fee_tax_rate2":0,"fee_tax_rate3":0,"fee_cap":10,"adjust_fee_percent":true}} + $fee = new FeesAndLimits; + $fee->fee_amount = 0; + $fee->fee_percent = 100; + // $fee->fee_tax_name1 = 'GST'; + // $fee->fee_tax_rate1 = '10.0'; + + $fee_arr[1] = (array) $fee; + + $data = [ + 'config' => 'random config', + 'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb', + 'fees_and_limits' => $fee_arr, + ]; + + /* POST */ + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/company_gateways', $data); + + $response->assertStatus(200); + + $arr = $response->json(); + $id = $this->decodePrimaryKey($arr['data']['id']); + + $company_gateway = CompanyGateway::find($id); + + $this->assertEquals(10, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD)); + } + + public function testFeesAndLimitsFeePercentAndAmountCalcuationOneHundredPercentVariationOne() + { + $fee = new FeesAndLimits; + $fee->fee_amount = 0; + $fee->fee_percent = 10; + + $fee_arr[1] = (array) $fee; + + $data = [ + 'config' => 'random config', + 'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb', + 'fees_and_limits' => $fee_arr, + ]; + + /* POST */ + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/company_gateways', $data); + + $response->assertStatus(200); + + $arr = $response->json(); + $id = $this->decodePrimaryKey($arr['data']['id']); + + $company_gateway = CompanyGateway::find($id); + + $this->assertEquals(1, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD)); + } + + public function testFeesAndLimitsFeePercentAndAmountAndTaxCalcuation() { //{"1":{"min_limit":1,"max_limit":1000000,"fee_amount":10,"fee_percent":2,"fee_tax_name1":"","fee_tax_name2":"","fee_tax_name3":"","fee_tax_rate1":0,"fee_tax_rate2":0,"fee_tax_rate3":0,"fee_cap":10,"adjust_fee_percent":true}}