From cc5430060799b0464dee1676f854b137fb91a015 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Oct 2021 21:13:11 +1100 Subject: [PATCH 01/14] Tests for credit payments --- tests/Feature/Payments/CreditPaymentTest.php | 220 +++++++++++++++++++ tests/MockUnitData.php | 52 +++++ 2 files changed, 272 insertions(+) create mode 100644 tests/Feature/Payments/CreditPaymentTest.php diff --git a/tests/Feature/Payments/CreditPaymentTest.php b/tests/Feature/Payments/CreditPaymentTest.php new file mode 100644 index 000000000000..a325d5618d89 --- /dev/null +++ b/tests/Feature/Payments/CreditPaymentTest.php @@ -0,0 +1,220 @@ +faker = \Faker\Factory::create(); + + Model::reguard(); + + $this->makeTestData(); + $this->withoutExceptionHandling(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + } + + public function testCreditPayments() + { + + $invoice = Invoice::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); + + $invoice->line_items = $this->buildLineItems(); + $invoice->uses_inclusive_taxes = false; + + // $invoice->save(); + $invoice_calc = new InvoiceSum($invoice); + $invoice_calc->build(); + $invoice = $invoice_calc->getInvoice(); + $invoice->setRelation('client', $this->client); + $invoice->setRelation('company', $this->company); + $invoice->save(); + + $credit = Credit::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); + + $credit->line_items = $this->buildLineItems(); + $credit->uses_inclusive_taxes = false; + + // $invoice->save(); + $invoice_calc = new InvoiceSum($credit); + $invoice_calc->build(); + $credit = $invoice_calc->getCredit(); + $credit->setRelation('client', $this->client); + $credit->setRelation('company', $this->company); + $credit->save(); + + + $data = [ + 'amount' => 0, + 'client_id' => $this->client->hashed_id, + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 10, + ], + ], + 'credits' => [ + ], + 'date' => '2019/12/12', + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + \Log::error(print_r($e->validator->getMessageBag(), 1)); + } + + // $response->assertStatus(200); + + // $arr = $response->json(); + + // $payment_id = $arr['data']['id']; + + // $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + + // $this->assertEquals($payment->amount, 15); + // $this->assertEquals($payment->applied, 10); + + + + + } + + /* + + public function testDoublePaymentTestWithInvalidAmounts() + { + + $data = [ + 'amount' => 15.0, + 'client_id' => $this->encodePrimaryKey($client->id), + 'invoices' => [ + [ + 'invoice_id' => $this->encodePrimaryKey($this->invoice->id), + 'amount' => 10, + ], + ], + 'date' => '2019/12/12', + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + \Log::error(print_r($e->validator->getMessageBag(), 1)); + } + + $response->assertStatus(200); + + $arr = $response->json(); + + $payment_id = $arr['data']['id']; + + $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + + $this->assertEquals($payment->amount, 15); + $this->assertEquals($payment->applied, 10); + + $this->invoice = null; + $this->invoice = InvoiceFactory::create($this->company->id, $this->user->id); //stub the company and user_id + $this->invoice->client_id = $client->id; + + $this->invoice->line_items = $this->buildLineItems(); + $this->invoice->uses_inclusive_taxes = false; + + $this->invoice->save(); + + $this->invoice_calc = new InvoiceSum($this->invoice); + $this->invoice_calc->build(); + + $this->invoice = $this->invoice_calc->getInvoice(); + $this->invoice->save(); + $this->invoice->service()->markSent()->save(); + + $data = [ + 'amount' => 15.0, + 'client_id' => $this->encodePrimaryKey($client->id), + 'invoices' => [ + [ + 'invoice_id' => $this->encodePrimaryKey($this->invoice->id), + 'amount' => 10, + ], + ], + 'date' => '2019/12/12', + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/payments/'.$this->encodePrimaryKey($payment->id), $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + + $this->assertTrue(array_key_exists('invoices', $message)); + } + } + */ + +} + diff --git a/tests/MockUnitData.php b/tests/MockUnitData.php index c0baea083e25..cb00239f3c78 100644 --- a/tests/MockUnitData.php +++ b/tests/MockUnitData.php @@ -11,10 +11,14 @@ namespace Tests; +use App\DataMapper\CompanySettings; +use App\DataMapper\DefaultSettings; +use App\Factory\InvoiceItemFactory; use App\Models\Account; use App\Models\Client; use App\Models\ClientContact; use App\Models\Company; +use App\Models\CompanyToken; use App\Models\User; /** * Class MockUnitData. @@ -33,6 +37,8 @@ trait MockUnitData public $primary_contact; + public $token; + public function makeTestData() { @@ -49,6 +55,39 @@ trait MockUnitData 'account_id' => $this->account->id ]); + $userPermissions = collect([ + 'view_invoice', + 'view_client', + 'edit_client', + 'edit_invoice', + 'create_invoice', + 'create_client', + ]); + + $userSettings = DefaultSettings::userSettings(); + + $this->user->companies()->attach($this->company->id, [ + 'account_id' => $this->account->id, + 'is_owner' => 1, + 'is_admin' => 1, + 'notifications' => CompanySettings::notificationDefaults(), + 'permissions' => $userPermissions->toJson(), + 'settings' => json_encode($userSettings), + 'is_locked' => 0, + ]); + + + $this->token = \Illuminate\Support\Str::random(64); + + $company_token = new CompanyToken; + $company_token->user_id = $this->user->id; + $company_token->company_id = $this->company->id; + $company_token->account_id = $this->account->id; + $company_token->name = 'test token'; + $company_token->token = $this->token; + $company_token->is_system = true; + $company_token->save(); + $this->client = Client::factory()->create([ 'user_id' => $this->user->id, 'company_id' => $this->company->id @@ -68,4 +107,17 @@ trait MockUnitData ]); } + + + public function buildLineItems() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + $line_items[] = $item; + + return $line_items; + } } \ No newline at end of file From a91c6b9a2ff595ee71a9d0a726374d62ffbc6e9a Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 13:59:35 +1100 Subject: [PATCH 02/14] Tests for credit payments --- tests/Feature/Payments/CreditPaymentTest.php | 120 +++++++++++++++---- 1 file changed, 95 insertions(+), 25 deletions(-) diff --git a/tests/Feature/Payments/CreditPaymentTest.php b/tests/Feature/Payments/CreditPaymentTest.php index a325d5618d89..7414001a6fcb 100644 --- a/tests/Feature/Payments/CreditPaymentTest.php +++ b/tests/Feature/Payments/CreditPaymentTest.php @@ -61,34 +61,25 @@ class CreditPaymentTest extends TestCase ); } - public function testCreditPayments() + public function testRegularPayment() { $invoice = Invoice::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); $invoice->line_items = $this->buildLineItems(); $invoice->uses_inclusive_taxes = false; + $invoice->discount = 0; + $invoice->tax_rate1 = 0; + $invoice->tax_name1 = ''; + $invoice->tax_rate2 = 0; + $invoice->tax_name2 = ''; - // $invoice->save(); $invoice_calc = new InvoiceSum($invoice); $invoice_calc->build(); $invoice = $invoice_calc->getInvoice(); $invoice->setRelation('client', $this->client); $invoice->setRelation('company', $this->company); - $invoice->save(); - - $credit = Credit::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); - - $credit->line_items = $this->buildLineItems(); - $credit->uses_inclusive_taxes = false; - - // $invoice->save(); - $invoice_calc = new InvoiceSum($credit); - $invoice_calc->build(); - $credit = $invoice_calc->getCredit(); - $credit->setRelation('client', $this->client); - $credit->setRelation('company', $this->company); - $credit->save(); + $invoice->service()->markSent()->save(); $data = [ @@ -100,8 +91,6 @@ class CreditPaymentTest extends TestCase 'amount' => 10, ], ], - 'credits' => [ - ], 'date' => '2019/12/12', ]; @@ -114,22 +103,103 @@ class CreditPaymentTest extends TestCase ])->post('/api/v1/payments/', $data); } catch (ValidationException $e) { $message = json_decode($e->validator->getMessageBag(), 1); - \Log::error(print_r($e->validator->getMessageBag(), 1)); + nlog($e->validator->getMessageBag()); } - // $response->assertStatus(200); + $response->assertStatus(200); - // $arr = $response->json(); + $arr = $response->json(); - // $payment_id = $arr['data']['id']; + $payment_id = $arr['data']['id']; - // $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); - // $this->assertEquals($payment->amount, 15); - // $this->assertEquals($payment->applied, 10); + $this->assertEquals($payment->amount, 10); + $this->assertEquals($payment->applied, 10); + + } + public function testCreditPayments() + { + + $invoice = Invoice::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); + + $invoice->line_items = $this->buildLineItems(); + $invoice->uses_inclusive_taxes = false; + $invoice->discount = 0; + $invoice->tax_rate1 = 0; + $invoice->tax_name1 = ''; + $invoice->tax_rate2 = 0; + $invoice->tax_name2 = ''; + + $invoice_calc = new InvoiceSum($invoice); + $invoice_calc->build(); + $invoice = $invoice_calc->getInvoice(); + $invoice->setRelation('client', $this->client); + $invoice->setRelation('company', $this->company); + $invoice->service()->markSent()->save(); + + $credit = Credit::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); + + $credit->line_items = $this->buildLineItems(); + $credit->uses_inclusive_taxes = false; + $credit->discount = 0; + $credit->tax_rate1 = 0; + $credit->tax_name1 = ''; + $credit->tax_rate2 = 0; + $credit->tax_name2 = ''; + + // $invoice->save(); + $invoice_calc = new InvoiceSum($credit); + $invoice_calc->build(); + $credit = $invoice_calc->getCredit(); + $credit->setRelation('client', $this->client); + $credit->setRelation('company', $this->company); + $credit->service()->markSent()->save(); + + + $data = [ + 'amount' => 0, + 'client_id' => $this->client->hashed_id, + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 10, + ], + ], + 'credits' => [ + [ + 'credit_id' => $credit->hashed_id, + 'amount' => 5 + ] + ], + 'date' => '2019/12/12', + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + nlog($e->validator->getMessageBag()); + } + + $response->assertStatus(200); + + $arr = $response->json(); + + $payment_id = $arr['data']['id']; + + $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + + $this->assertEquals($payment->amount, 5); + $this->assertEquals($payment->applied, 5); } From 3b8ef9ccd90879d1d636d0dc52087019a6ba6f98 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 15:49:05 +1100 Subject: [PATCH 03/14] Minor fixes for credit - paid - to - dates --- app/Http/Requests/Payment/StorePaymentRequest.php | 2 -- app/Repositories/PaymentRepository.php | 13 ++++--------- tests/Feature/RecurringExpenseApiTest.php | 4 ++-- tests/Integration/PaymentDrivers/AuthorizeTest.php | 6 +++--- tests/Unit/InvoiceInclusiveTest.php | 4 +++- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php index 81f8380fb55b..e3c845d8176f 100644 --- a/app/Http/Requests/Payment/StorePaymentRequest.php +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -39,8 +39,6 @@ class StorePaymentRequest extends Request { $input = $this->all(); - // nlog(print_r($input,1)); - $invoices_total = 0; $credits_total = 0; diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index ebcb5add517b..c2fc9501288a 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -89,11 +89,11 @@ class PaymentRepository extends BaseRepository { if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) { $_credit_totals = array_sum(array_column($data['credits'], 'amount')); - if ($data['amount'] == $_credit_totals) { - $data['amount'] = 0; - } else { + // if ($data['amount'] == $_credit_totals) { + // $data['amount'] = 0; + // } else { $client->service()->updatePaidToDate($_credit_totals)->save(); - } + // } } } @@ -170,11 +170,6 @@ class PaymentRepository extends BaseRepository { event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null) ) ); } - // nlog("payment amount = {$payment->amount}"); - // nlog("payment applied = {$payment->applied}"); - // nlog("invoice totals = {$invoice_totals}"); - // nlog("credit totals = {$credit_totals}"); - $payment->applied += ($invoice_totals - $credit_totals); //wont work because - check tests // $payment->applied += $invoice_totals; //wont work because - check tests diff --git a/tests/Feature/RecurringExpenseApiTest.php b/tests/Feature/RecurringExpenseApiTest.php index 586db2373426..e983248dcc25 100644 --- a/tests/Feature/RecurringExpenseApiTest.php +++ b/tests/Feature/RecurringExpenseApiTest.php @@ -185,7 +185,7 @@ class RecurringExpenseApiTest extends TestCase ])->post('/api/v1/recurring_expenses/bulk?action=start', $data); $arr = $response->json(); -nlog($arr); + $this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data'][0]['status_id']); } @@ -207,7 +207,7 @@ nlog($arr); ])->post('/api/v1/recurring_expenses/bulk?action=stop', $data); $arr = $response->json(); -nlog($arr); + $this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data'][0]['status_id']); } diff --git a/tests/Integration/PaymentDrivers/AuthorizeTest.php b/tests/Integration/PaymentDrivers/AuthorizeTest.php index 33934756a289..ed1415196206 100644 --- a/tests/Integration/PaymentDrivers/AuthorizeTest.php +++ b/tests/Integration/PaymentDrivers/AuthorizeTest.php @@ -311,9 +311,9 @@ class AuthorizeTest extends TestCase $response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX); // nlog($response); - nlog($response->getTransactionResponse()->getMessages() !== null); - nlog($response->getTransactionResponse()->getMessages()); - nlog($response->getTransactionResponse()->getMessages()[0]); + // nlog($response->getTransactionResponse()->getMessages() !== null); + // nlog($response->getTransactionResponse()->getMessages()); + // nlog($response->getTransactionResponse()->getMessages()[0]); //nlog($response->getTransactionResponse()->getMessages()[0]->getCode()); $code = ''; diff --git a/tests/Unit/InvoiceInclusiveTest.php b/tests/Unit/InvoiceInclusiveTest.php index 08f5a24e0c04..01048d069b72 100644 --- a/tests/Unit/InvoiceInclusiveTest.php +++ b/tests/Unit/InvoiceInclusiveTest.php @@ -275,7 +275,9 @@ class InvoiceInclusiveTest extends TestCase $this->assertEquals($this->invoice_calc->getSubTotal(), 19); $this->assertEquals($this->invoice_calc->getTotalDiscount(), 0.95); $this->assertEquals($this->invoice_calc->getTotalTaxes(), 4.92); - nlog($this->invoice_calc->getTaxMap()); + + // nlog($this->invoice_calc->getTaxMap()); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); $this->assertEquals($this->invoice_calc->getTotal(), 18.05); $this->assertEquals($this->invoice_calc->getBalance(), 18.05); From e8f79e54f5902c998907786861149c7b41bd45e2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 18:41:36 +1100 Subject: [PATCH 04/14] Expose webhooks for all gateways in AP UI --- app/Mail/Engine/PaymentEmailEngine.php | 2 +- app/Models/Gateway.php | 48 +++++++++++++++++--------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index 7f4805e4185b..b0b7a43dabe2 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -46,7 +46,7 @@ class PaymentEmailEngine extends BaseEmailEngine $this->payment = $payment; $this->company = $payment->company; $this->client = $payment->client; - $this->contact = $contact ?: $this->client->primary_contact()->first(); + $this->contact = $contact ?: $this->client->contacts()->first(); $this->contact->load('client.company'); $this->settings = $this->client->getMergedSettings(); $this->template_data = $template_data; diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index c177347a367c..f1c55fbae701 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -61,7 +61,7 @@ class Gateway extends StaticModel $link = 'https://bitpay.com/dashboard/signup'; } elseif ($this->id == 18) { $link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99'; - } elseif ($this->id == 20) { + } elseif ($this->id == 20 || $this->id == 56) { $link = 'https://dashboard.stripe.com/account/apikeys'; } @@ -89,17 +89,20 @@ class Gateway extends StaticModel break; case 7: return [ - GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true], // Mollie - GatewayType::BANK_TRANSFER => ['refund' => false, 'token_billing' => true], - GatewayType::KBC => ['refund' => false, 'token_billing' => false], - GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false], - GatewayType::IDEAL => ['refund' => false, 'token_billing' => false], + GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']], // Mollie + GatewayType::BANK_TRANSFER => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']], + GatewayType::KBC => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']], + GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']], + GatewayType::IDEAL => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']], ]; case 15: - return [GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]]; //Paypal + return [ + GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false] + ]; //Paypal break; case 20: - return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], + return [ + GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']], GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false], @@ -109,30 +112,41 @@ class Gateway extends StaticModel GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], - GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; + GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + ]; case 39: - return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Checkout + return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']]]; //Checkout break; case 46: return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Paytrace case 49: - return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], - GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true]]; //WePay + return [ + GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], + GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']] + ]; //WePay break; case 50: return [ GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], //Braintree GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true], - GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true], + GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']], ]; break; case 56: - return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], + return [ + GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']], GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false], - GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; //Stripe + GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], //Stripe + GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + GatewayType::PRZELEWY24 => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], + ]; break; case 57: return [ @@ -141,12 +155,12 @@ class Gateway extends StaticModel break; case 52: return [ - GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true] // GoCardless + GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']] // GoCardless ]; break; case 58: return [ - GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false] // Razorpay + GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']] // Razorpay ]; break; default: From af8c56a1f10fa11db2b4ae5748c7d533b39550eb Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 19:10:43 +1100 Subject: [PATCH 05/14] Fixes for N+1 queries in Client Statements --- .../Statements/CreateStatementRequest.php | 2 +- app/Services/Client/Statement.php | 14 ++++---- app/Services/PdfMaker/Design.php | 32 +++++++++---------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/app/Http/Requests/Statements/CreateStatementRequest.php b/app/Http/Requests/Statements/CreateStatementRequest.php index d887edfdd9e6..b8677bf8b0f4 100644 --- a/app/Http/Requests/Statements/CreateStatementRequest.php +++ b/app/Http/Requests/Statements/CreateStatementRequest.php @@ -51,6 +51,6 @@ class CreateStatementRequest extends Request public function client(): ?Client { - return Client::where('id', $this->client_id)->first(); + return Client::with('company')->where('id', $this->client_id)->withTrashed()->first(); } } diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index 219171651fcf..ab36d8f879f0 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -73,7 +73,7 @@ class Statement $state = [ 'template' => $template->elements([ - 'client' => $this->entity->client, + 'client' => $this->client, 'entity' => $this->entity, 'pdf_variables' => (array)$this->entity->company->settings->pdf_variables, '$product' => $this->getDesign()->design->product, @@ -219,7 +219,7 @@ class Statement */ protected function getInvoices(): Collection { - return Invoice::where('company_id', $this->client->company->id) + return Invoice::where('company_id', $this->client->company_id) ->where('client_id', $this->client->id) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) @@ -234,7 +234,8 @@ class Statement */ protected function getPayments(): Collection { - return Payment::where('company_id', $this->client->company->id) + return Payment::with('client.country','invoices') + ->where('company_id', $this->client->company_id) ->where('client_id', $this->client->id) ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) @@ -285,10 +286,7 @@ class Statement $from = $ranges[0]; $to = $ranges[1]; - $client = Client::where('id', $this->client->id)->first(); - - $amount = Invoice::where('company_id', $this->client->company->id) - ->where('client_id', $client->id) + $amount = Invoice::where('client_id', $this->client->id) ->where('company_id', $this->client->company_id) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) ->where('balance', '>', 0) @@ -296,7 +294,7 @@ class Statement ->whereBetween('date', [$to, $from]) ->sum('balance'); - return Number::formatMoney($amount, $client); + return Number::formatMoney($amount, $this->client); } /** diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index bb9e3f809269..57f2766a43e8 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -195,15 +195,15 @@ class Design extends BaseDesign if ($this->type == self::DELIVERY_NOTE) { $elements = [ ['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']], - ['element' => 'p', 'content' => $this->entity->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']], - ['element' => 'p', 'content' => $this->entity->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']], - ['element' => 'p', 'content' => $this->entity->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']], + ['element' => 'p', 'content' => $this->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']], + ['element' => 'p', 'content' => $this->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']], + ['element' => 'p', 'content' => $this->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']], ['element' => 'p', 'show_empty' => false, 'elements' => [ - ['element' => 'span', 'content' => "{$this->entity->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']], - ['element' => 'span', 'content' => "{$this->entity->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']], - ['element' => 'span', 'content' => "{$this->entity->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']], + ['element' => 'span', 'content' => "{$this->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']], + ['element' => 'span', 'content' => "{$this->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']], + ['element' => 'span', 'content' => "{$this->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']], ]], - ['element' => 'p', 'content' => optional($this->entity->client->shipping_country)->name, 'show_empty' => false], + ['element' => 'p', 'content' => optional($this->client->shipping_country)->name, 'show_empty' => false], ]; if (!is_null($this->context['contact'])) { @@ -232,7 +232,7 @@ class Design extends BaseDesign ]], ['element' => 'tr', 'properties' => [], 'elements' => [ ['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'], - ['element' => 'th', 'properties' => [], 'content' => Number::formatMoney($this->invoices->sum('balance'), $this->entity->client)], + ['element' => 'th', 'properties' => [], 'content' => Number::formatMoney($this->invoices->sum('balance'), $this->client)], ]], ]; } @@ -363,10 +363,10 @@ class Design extends BaseDesign $element = ['element' => 'tr', 'elements' => []]; $element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; - $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) ?: ' ']; - $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()) ?: ' ']; - $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->amount, $invoice->client) ?: ' ']; - $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->balance, $invoice->client) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $this->client->date_format(), $this->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $this->client->date_format(), $this->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->amount, $this->client) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->balance, $this->client) ?: ' ']; $tbody[] = $element; } @@ -386,7 +386,7 @@ class Design extends BaseDesign $outstanding = $this->invoices->sum('balance'); return [ - ['element' => 'p', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->entity->client)], + ['element' => 'p', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->client)], ]; } @@ -412,9 +412,9 @@ class Design extends BaseDesign $element = ['element' => 'tr', 'elements' => []]; $element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; - $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $this->client->date_format(), $this->client->locale()) ?: ' ']; $element['elements'][] = ['element' => 'td', 'content' => $payment->type ? $payment->type->name : ctrans('texts.manual_entry')]; - $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $payment->client) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $this->client) ?: ' ']; $tbody[] = $element; } @@ -439,7 +439,7 @@ class Design extends BaseDesign $payment = $this->payments->first(); return [ - ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $payment->client))], + ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $this->client))], ]; } From ebca34503be3eb828bc52942e6eb5404026bca46 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 20:45:15 +1100 Subject: [PATCH 06/14] Fixes for N+1 --- app/Http/Controllers/PreviewController.php | 3 ++- app/Services/Invoice/InvoiceService.php | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index e5a55fb19c9f..5907397b7e4a 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -204,6 +204,7 @@ class PreviewController extends BaseController if($request->has('entity_id')){ $entity_obj = $class::on(config('database.default')) + ->with('client.contacts.company') ->where('id', $this->decodePrimaryKey($request->input('entity_id'))) ->where('company_id', $company->id) ->withTrashed() @@ -216,7 +217,7 @@ class PreviewController extends BaseController if(!$request->has('entity_id')) $entity_obj->service()->fillDefaults()->save(); - $entity_obj->load('client.contacts','company'); + // $entity_obj->load('client.contacts','client.company'); App::forgetInstance('translator'); $t = app('translator'); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 55754f834210..dd0977a55bc6 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -449,6 +449,8 @@ class InvoiceService public function fillDefaults() { + $this->invoice->load('client.company'); + $settings = $this->invoice->client->getMergedSettings(); if (! $this->invoice->design_id) From d65b689ec60b6b9251ab0a5a49c033bdf493b22e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 20:54:52 +1100 Subject: [PATCH 07/14] Minor fixes for subscriptions --- .../Subscription/SubscriptionService.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index eff83c90f644..8771b9034c8c 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -693,6 +693,8 @@ class SubscriptionService public function convertInvoiceToRecurring($client_id) :RecurringInvoice { + $client = Client::find($client_id); + $subscription_repo = new SubscriptionRepository(); $recurring_invoice = RecurringInvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id); @@ -702,10 +704,23 @@ class SubscriptionService $recurring_invoice->frequency_id = $this->subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY; $recurring_invoice->date = now(); $recurring_invoice->remaining_cycles = -1; - + $recurring_invoice->auto_bill = $client->getSetting('auto_bill'); + $recurring_invoice->auto_bill_enabled = $this->setAutoBillFlag($recurring_invoice->auto_bill); + $recurring_invoice->due_date_days = 'terms'; + return $recurring_invoice; } + private function setAutoBillFlag($auto_bill) + { + if ($auto_bill == 'always' || $auto_bill == 'optout') { + return true; + } + + return false; + + } + /** * Hit a 3rd party API if defined in the subscription * From d9b7ffe9f17eaa679bb1ff90a1d36fd9286d0cb6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 21:24:09 +1100 Subject: [PATCH 08/14] N+1 for preview controller --- app/Http/Controllers/PreviewController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index 5907397b7e4a..19489a4b7da5 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -204,7 +204,7 @@ class PreviewController extends BaseController if($request->has('entity_id')){ $entity_obj = $class::on(config('database.default')) - ->with('client.contacts.company') + ->with('client.company') ->where('id', $this->decodePrimaryKey($request->input('entity_id'))) ->where('company_id', $company->id) ->withTrashed() @@ -221,7 +221,7 @@ class PreviewController extends BaseController App::forgetInstance('translator'); $t = app('translator'); - App::setLocale($entity_obj->client->contacts()->first()->preferredLocale()); + App::setLocale($entity_obj->client->locale()); $t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings())); $html = new HtmlEngine($entity_obj->invitations()->first()); From c4f09c23bab810f4a08d2b7300d906665a25d3b2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 21:48:07 +1100 Subject: [PATCH 09/14] Set default payment type if none defined --- app/Services/Invoice/MarkPaid.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index f3c23ab5b07f..654facfbc4f8 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -58,11 +58,17 @@ class MarkPaid extends AbstractService $payment->transaction_reference = ctrans('texts.manual_entry'); $payment->currency_id = $this->invoice->client->getSetting('currency_id'); $payment->is_manual = true; - /* Create a payment relationship to the invoice entity */ + + $payment_type_id = $this->invoice->client->getSetting('payment_type_id'); + + if((int)$payment_type_id > 0) + $payment->type_id = (int)$payment_type_id; + $payment->save(); $this->setExchangeRate($payment); + /* Create a payment relationship to the invoice entity */ $payment->invoices()->attach($this->invoice->id, [ 'amount' => $payment->amount, ]); From feab95caa7a11b96f4defccd3e6ace2349b3e2a4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Oct 2021 23:21:17 +1100 Subject: [PATCH 10/14] Company import/expore recurring expenses --- app/Jobs/Company/CompanyExport.php | 8 ++++++++ app/Jobs/Company/CompanyImport.php | 30 +++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index 571913ee0438..c9ba2d875a61 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -336,6 +336,14 @@ class CompanyExport implements ShouldQueue })->all(); + $this->export_data['recurring_expenses'] = $this->company->recurring_expenses->map(function ($expense){ + + $expense = $this->transformBasicEntities($expense); + $expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'project_id']); + + return $expense->makeVisible(['id']); + + })->all(); $this->export_data['recurring_invoices'] = $this->company->recurring_invoices->makeVisible(['id'])->map(function ($ri){ diff --git a/app/Jobs/Company/CompanyImport.php b/app/Jobs/Company/CompanyImport.php index 234040ea9f32..40494b60d2d3 100644 --- a/app/Jobs/Company/CompanyImport.php +++ b/app/Jobs/Company/CompanyImport.php @@ -47,6 +47,7 @@ use App\Models\Product; use App\Models\Project; use App\Models\Quote; use App\Models\QuoteInvitation; +use App\Models\RecurringExpense; use App\Models\RecurringInvoice; use App\Models\RecurringInvoiceInvitation; use App\Models\Subscription; @@ -76,6 +77,8 @@ use ZipArchive; use ZipStream\Option\Archive; use ZipStream\ZipStream; +use function GuzzleHttp\json_encode; + class CompanyImport implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash, GeneratesCounter; @@ -135,6 +138,7 @@ class CompanyImport implements ShouldQueue 'quote_invitations', 'credits', 'credit_invitations', + 'recurring_expenses', 'expenses', 'tasks', 'payments', @@ -452,6 +456,26 @@ class CompanyImport implements ShouldQueue } + private function import_recurring_expenses() + { +//unset / transforms / object_property / match_key + $this->genericImport(RecurringExpense::class, + ['assigned_user_id', 'user_id', 'client_id', 'company_id', 'id', 'hashed_id', 'project_id', 'vendor_id'], + [ + ['users' => 'user_id'], + ['users' => 'assigned_user_id'], + ['clients' => 'client_id'], + ['projects' => 'project_id'], + ['vendors' => 'vendor_id'], + ['invoices' => 'invoice_id'], + ['expense_categories' => 'category_id'], + ], + 'expenses', + 'number'); + + return $this; + } + private function import_payment_terms() { @@ -795,6 +819,8 @@ class CompanyImport implements ShouldQueue ['projects' => 'project_id'], ['vendors' => 'vendor_id'], ['invoices' => 'invoice_id'], + ['recurring_expenses' => 'recurring_expense_id'], + ['expense_categories' => 'category_id'], ], 'expenses', 'number'); @@ -1248,6 +1274,7 @@ class CompanyImport implements ShouldQueue if($class == 'App\Models\Subscription'){ $obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']); $obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']); + $obj_array['webhook_configuration'] = json_encode($obj_array['webhook_configuration']); } $new_obj = $class::firstOrNew( @@ -1297,7 +1324,8 @@ class CompanyImport implements ShouldQueue if($class == 'App\Models\Subscription'){ //$obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']); //$obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']); - // + // $obj_array['webhook_configuration'] = json_encode($obj_array['webhook_configuration']); + $obj_array['webhook_configuration'] = ''; $obj_array['recurring_product_ids'] = ''; $obj_array['product_ids'] = ''; } From 48dbd143be96a45cad8c88c7f0506deda2acf5b4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 13 Oct 2021 08:43:38 +1100 Subject: [PATCH 11/14] Minor fixes for Statements --- app/Services/Client/Statement.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index ab36d8f879f0..53aa575fcec8 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -291,7 +291,7 @@ class Statement ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) ->where('balance', '>', 0) ->where('is_deleted', 0) - ->whereBetween('date', [$to, $from]) + ->whereBetween('due_date', [$to, $from]) ->sum('balance'); return Number::formatMoney($amount, $this->client); @@ -326,7 +326,7 @@ class Statement return $ranges; case '120+': $ranges[0] = now()->startOfDay()->subDays(120); - $ranges[1] = now()->startOfDay()->subYears(40); + $ranges[1] = now()->startOfDay()->subYears(20); return $ranges; default: $ranges[0] = now()->startOfDay()->subDays(0); From 62058e910d6f79e2f783887c0cec76fcfef4f467 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 13 Oct 2021 09:10:44 +1100 Subject: [PATCH 12/14] Return fresh model instance --- app/Http/Livewire/BillingPortalPurchase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Livewire/BillingPortalPurchase.php b/app/Http/Livewire/BillingPortalPurchase.php index 1b358125981f..9586ae7a9ee2 100644 --- a/app/Http/Livewire/BillingPortalPurchase.php +++ b/app/Http/Livewire/BillingPortalPurchase.php @@ -268,7 +268,7 @@ class BillingPortalPurchase extends Component $client = $client_repo->save($data, ClientFactory::create($company->id, $user->id)); - return $client->contacts->first(); + return $client->fresh()->contacts->first(); } /** From 7eaafe52c71cb12765a4c1f11be9b7bcaed8baaa Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 13 Oct 2021 12:52:44 +1100 Subject: [PATCH 13/14] Minor fixes for terms being displayed on PDF --- app/PaymentDrivers/Stripe/ImportCustomers.php | 2 +- app/Services/PdfMaker/Design.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Stripe/ImportCustomers.php b/app/PaymentDrivers/Stripe/ImportCustomers.php index 2349761eb706..bd06616dafd6 100644 --- a/app/PaymentDrivers/Stripe/ImportCustomers.php +++ b/app/PaymentDrivers/Stripe/ImportCustomers.php @@ -162,7 +162,7 @@ class ImportCustomers if(strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1) throw new StripeConnectFailure('Stripe Connect has not been configured'); - $customer = Customer::retrieve($customer_id, $this->stripe_connect_auth); + $customer = Customer::retrieve($customer_id, $this->stripe->stripe_connect_auth); if(!$customer) return; diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 57f2766a43e8..eb858b225248 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -626,7 +626,7 @@ class Design extends BaseDesign ['element' => 'p', 'content' => strtr($_variables['values']['$entity.public_notes'], $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']], ['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column;'], 'elements' => [ ['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']], - ['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']], + ['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']], ]], ['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']], ['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [ From 05a65448989e73901b565ad99643a46045676192 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 13 Oct 2021 14:04:14 +1100 Subject: [PATCH 14/14] Set default designs --- app/Http/Controllers/DesignController.php | 1 + app/PaymentDrivers/BaseDriver.php | 26 +++++++++++-------- app/PaymentDrivers/CheckoutCom/CreditCard.php | 4 +-- .../CheckoutComPaymentDriver.php | 9 ------- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/DesignController.php b/app/Http/Controllers/DesignController.php index c6f44abf250a..f2b440056b7d 100644 --- a/app/Http/Controllers/DesignController.php +++ b/app/Http/Controllers/DesignController.php @@ -496,6 +496,7 @@ class DesignController extends BaseController $company = auth()->user()->getCompany(); $design = Design::where('company_id', $company->id) + ->orWhereNull('company_id') ->where('id', $design_id) ->exists(); diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 6084b5164b5a..ecb74e416af5 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -403,10 +403,8 @@ class BaseDriver extends AbstractPaymentDriver }); - } - SystemLogger::dispatch( $gateway->payment_hash, SystemLog::CATEGORY_GATEWAY_RESPONSE, @@ -620,21 +618,27 @@ class BaseDriver extends AbstractPaymentDriver { $types = []; - // if($type == GatewayType::BANK_TRANSFER && $this->company_gateway->fees_and_limits->{GatewayType::BANK_TRANSFER}->is_enabled) - // { - // $types[] = $type; - // } - // elseif($type == GatewayType::CREDIT_CARD && $this->company_gateway->fees_and_limits->{GatewayType::CREDIT_CARD}->is_enabled) - // { - // $types[] = $type; - // } - $types[] = GatewayType::CREDIT_CARD; $types[] = GatewayType::BANK_TRANSFER; return $types; } + /** + * Generic description handler + */ + public function getDescription(bool $abbreviated = true) + { + if(!$this->payment_hash) + return ""; + + if($abbreviated) + return \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()); + + return sprintf('%s: %s', ctrans('texts.invoices'), \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray())); + + } + public function disconnect() { return true; diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index cb7e728bc742..0cdc3c643b88 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -88,7 +88,6 @@ class CreditCard 'raw_value' => $request->raw_value, 'currency' => $request->currency, 'payment_hash' => $request->payment_hash, - 'reference' => $request->payment_hash, 'client_id' => $this->checkout->client->id, ]; @@ -134,9 +133,10 @@ class CreditCard private function completePayment($method, PaymentResponseRequest $request) { + $payment = new Payment($method, $this->checkout->payment_hash->data->currency); $payment->amount = $this->checkout->payment_hash->data->value; - $payment->reference = $this->checkout->payment_hash->data->reference; + $payment->reference = $this->checkout->getDescription(); $this->checkout->payment_hash->data = array_merge((array)$this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]); $this->checkout->payment_hash->save(); diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index e820808316e3..7b4f2aea4a6f 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -243,27 +243,18 @@ class CheckoutComPaymentDriver extends BaseDriver $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); - if ($invoice) { - $description = "Invoice {$invoice->number} for {$amount} for client {$this->client->present()->name()}"; - } else { - $description = "Payment with no invoice for amount {$amount} for client {$this->client->present()->name()}"; - } - $this->init(); $method = new IdSource($cgt->token); $payment = new \Checkout\Models\Payments\Payment($method, $this->client->getCurrencyCode()); $payment->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode()); - //$payment->reference = $cgt->meta->last4 . '-' . now(); $payment->reference = $invoice->number . '-' . now(); $request = new PaymentResponseRequest(); $request->setMethod('POST'); $request->request->add(['payment_hash' => $payment_hash->hash]); - //$this->setPaymentHash($payment_hash); - try { $response = $this->gateway->payments()->request($payment);