From 969a76003b1b59d9bd4cc8e09b576f093e26ceac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 26 Aug 2021 15:37:17 +0200 Subject: [PATCH 01/21] Add `BANK_TRANSFER` to `Gateway` model --- app/Models/Gateway.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 676112f979..dadb195e52 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -83,7 +83,7 @@ class Gateway extends StaticModel break; case 3: return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true]];//eWay - break; + break; case 11: return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false]];//Payfast break; @@ -106,11 +106,12 @@ class Gateway extends StaticModel case 49: return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true]]; //WePay - break; + break; case 50: return [ GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], //Braintree - GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true] + GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true], + GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true], ]; break; case 7: From 5a0c6b07342abda54bd53d197e5d82896a265e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 26 Aug 2021 15:37:37 +0200 Subject: [PATCH 02/21] Scaffold `MethodInterface` for child classes --- app/PaymentDrivers/Common/MethodInterface.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/PaymentDrivers/Common/MethodInterface.php diff --git a/app/PaymentDrivers/Common/MethodInterface.php b/app/PaymentDrivers/Common/MethodInterface.php new file mode 100644 index 0000000000..41ce99ac7f --- /dev/null +++ b/app/PaymentDrivers/Common/MethodInterface.php @@ -0,0 +1,31 @@ + Date: Thu, 26 Aug 2021 15:37:56 +0200 Subject: [PATCH 03/21] Braintree ACH class --- app/PaymentDrivers/Braintree/ACH.php | 79 ++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 app/PaymentDrivers/Braintree/ACH.php diff --git a/app/PaymentDrivers/Braintree/ACH.php b/app/PaymentDrivers/Braintree/ACH.php new file mode 100644 index 0000000000..98ab379c3b --- /dev/null +++ b/app/PaymentDrivers/Braintree/ACH.php @@ -0,0 +1,79 @@ +braintree = $braintree; + + $this->braintree->init(); + } + + public function authorizeView(array $data) + { + $data['gateway'] = $this->braintree; + $data['client_token'] = $this->braintree->gateway->clientToken()->generate(); + + return render('gateways.braintree.ach.authorize', $data); + } + + public function authorizeResponse(Request $request) + { + $request->validate([ + 'nonce' => ['required'], + 'gateway_type_id' => ['required'], + ]); + + $customer = $this->braintree->findOrCreateCustomer(); + + $result = $this->braintree->gateway->paymentMethod()->create([ + 'customerId' => $customer->id, + 'paymentMethodNonce' => $request->nonce, + 'options' => [ + 'usBankAccountVerificationMethod' => \Braintree\Result\UsBankAccountVerification::NETWORK_CHECK, + ], + ]); + + if ($result->success) { + $account = $result->paymentMethod; + + try { + $payment_meta = new \stdClass; + $payment_meta->brand = (string)$account->bankName; + $payment_meta->last4 = (string)$account->last4; + $payment_meta->type = GatewayType::BANK_TRANSFER; + $payment_meta->state = $account->verified ? 'authorized' : 'unauthorized'; + + $data = [ + 'payment_meta' => $payment_meta, + 'token' => $account->token, + 'payment_method_id' => $request->gateway_type_id, + ]; + + $this->braintree->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]); + + return redirect()->route('client.payment_methods.index'); + } catch (\Exception $e) { + // .. + } + } + } +} From 29d56f69d59650bee4f5f482d37bb8fbff58fcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 26 Aug 2021 15:38:28 +0200 Subject: [PATCH 04/21] Frontend for authorizing ACH --- app/PaymentDrivers/BraintreePaymentDriver.php | 15 +- .../braintree/ach/authorize.blade.php | 149 ++++++++++++++++++ 2 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php diff --git a/app/PaymentDrivers/BraintreePaymentDriver.php b/app/PaymentDrivers/BraintreePaymentDriver.php index 7c0cdd2786..ca22ca6f4f 100644 --- a/app/PaymentDrivers/BraintreePaymentDriver.php +++ b/app/PaymentDrivers/BraintreePaymentDriver.php @@ -23,6 +23,7 @@ use App\Models\Payment; use App\Models\PaymentHash; use App\Models\PaymentType; use App\Models\SystemLog; +use App\PaymentDrivers\Braintree\ACH; use App\PaymentDrivers\Braintree\CreditCard; use App\PaymentDrivers\Braintree\PayPal; use Braintree\Gateway; @@ -45,6 +46,7 @@ class BraintreePaymentDriver extends BaseDriver public static $methods = [ GatewayType::CREDIT_CARD => CreditCard::class, GatewayType::PAYPAL => PayPal::class, + GatewayType::BANK_TRANSFER => ACH::class, ]; const SYSTEM_LOG_TYPE = SystemLog::TYPE_BRAINTREE; @@ -72,9 +74,10 @@ class BraintreePaymentDriver extends BaseDriver { $types = [ GatewayType::PAYPAL, - GatewayType::CREDIT_CARD + GatewayType::CREDIT_CARD, + GatewayType::BANK_TRANSFER, ]; - + return $types; } @@ -125,9 +128,9 @@ class BraintreePaymentDriver extends BaseDriver $this->init(); try{ - + $response = $this->gateway->transaction()->refund($payment->transaction_reference, $amount); - + } catch (Exception $e) { $data = [ @@ -137,12 +140,12 @@ class BraintreePaymentDriver extends BaseDriver 'description' => $e->getMessage(), 'code' => $e->getCode(), ]; - + SystemLogger::dispatch(['server_response' => null, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_BRAINTREE, $this->client, $this->client->company); return $data; } - + if($response->success) { diff --git a/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php new file mode 100644 index 0000000000..ba2e9357ba --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php @@ -0,0 +1,149 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'ACH', 'card_title' => 'ACH']) + +@section('gateway_head') + +@endsection + +@section('gateway_content') + @if(session()->has('ach_error')) +
+

{{ session('ach_error') }}

+
+ @endif + +
+ @csrf + + + + + + +
+ + + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_type')]) + + + {{ __('texts.checking') }} + + + + {{ __('texts.savings') }} + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_type')]) + + + {{ __('texts.individual_account') }} + + + + {{ __('texts.company_account') }} + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_name')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_number')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.routing_number')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.address1')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.address2')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.locality')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.state')]) + + @endcomponent + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.postal_code')]) + + @endcomponent + + @component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'authorize-bank-account']) + {{ ctrans('texts.add_payment_method') }} + @endcomponent +@endsection + +@section('gateway_footer') + + + + +@endsection From 016e8033fb701757b79683e163ff435eac232461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 26 Aug 2021 15:46:17 +0200 Subject: [PATCH 05/21] Add `paymentView` to `MethodInterface` --- app/PaymentDrivers/Common/MethodInterface.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/PaymentDrivers/Common/MethodInterface.php b/app/PaymentDrivers/Common/MethodInterface.php index 41ce99ac7f..6e68b82dcf 100644 --- a/app/PaymentDrivers/Common/MethodInterface.php +++ b/app/PaymentDrivers/Common/MethodInterface.php @@ -28,4 +28,11 @@ interface MethodInterface * @param Request $request */ public function authorizeResponse(Request $request); + + /** + * Payment page for the gateway method. + * + * @param array $data + */ + public function paymentView(array $data); } From 760de008f84cca366dd75f731790620f82620080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 26 Aug 2021 15:46:31 +0200 Subject: [PATCH 06/21] Payments without token --- app/PaymentDrivers/Braintree/ACH.php | 7 +++ .../gateways/braintree/ach/pay.blade.php | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php diff --git a/app/PaymentDrivers/Braintree/ACH.php b/app/PaymentDrivers/Braintree/ACH.php index 98ab379c3b..00a3cc0371 100644 --- a/app/PaymentDrivers/Braintree/ACH.php +++ b/app/PaymentDrivers/Braintree/ACH.php @@ -76,4 +76,11 @@ class ACH implements MethodInterface } } } + + public function paymentView(array $data) + { + $data['gateway'] = $this->braintree; + + return render('gateways.braintree.ach.pay', $data); + } } diff --git a/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php b/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php new file mode 100644 index 0000000000..d6ccfb9851 --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php @@ -0,0 +1,58 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'ACH', 'card_title' => 'ACH']) + +@section('gateway_content') + @if(count($tokens) > 0) + + + @include('portal.ninja2020.gateways.includes.payment_details') + +
+ @csrf + + + + + + + +
+ + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) + @if(count($tokens) > 0) + @foreach($tokens as $token) + + @endforeach + @endisset + @endcomponent + + @include('portal.ninja2020.gateways.includes.pay_now') + + @else + @component('portal.ninja2020.components.general.card-element-single', ['title' => 'ACH', 'show_title' => false]) + {{ ctrans('texts.bank_account_not_linked') }} + {{ ctrans('texts.add_payment_method') }} + @endcomponent + @endif +@endsection + +@push('footer') + +@endpush From 38ceefc5369a2a558d513a214fc8b7472d39fe95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 16:19:10 +0200 Subject: [PATCH 07/21] Fixes for `processInternallyFailedPayment` --- app/PaymentDrivers/BaseDriver.php | 43 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 65705fc19c..b984b2b41e 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -360,16 +360,15 @@ class BaseDriver extends AbstractPaymentDriver public function processInternallyFailedPayment($gateway, $e) { - - $this->unWindGatewayFees($this->payment_hash); + if (!is_null($this->payment_hash)) { + $this->unWindGatewayFees($this->payment_hash); + } if ($e instanceof CheckoutHttpException) { $error = $e->getBody(); - } - else if ($e instanceof Exception) { + } else if ($e instanceof Exception) { $error = $e->getMessage(); - } - else + } else $error = $e->getMessage(); PaymentFailureMailer::dispatch( @@ -379,29 +378,29 @@ class BaseDriver extends AbstractPaymentDriver $this->payment_hash ); - $nmo = new NinjaMailerObject; - $nmo->mailable = new NinjaMailer( (new ClientPaymentFailureObject($gateway->client, $error, $gateway->client->company, $this->payment_hash))->build() ); - $nmo->company = $gateway->client->company; - $nmo->settings = $gateway->client->company->settings; + if (!is_null($this->payment_hash)) { - $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); + $nmo = new NinjaMailerObject; + $nmo->mailable = new NinjaMailer((new ClientPaymentFailureObject($gateway->client, $error, $gateway->client->company, $this->payment_hash))->build()); + $nmo->company = $gateway->client->company; + $nmo->settings = $gateway->client->company->settings; - $invoices->each(function ($invoice){ + $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); - $invoice->service()->deletePdf(); + $invoices->each(function ($invoice) { - }); + $invoice->service()->deletePdf(); + }); - $invoices->first()->invitations->each(function ($invitation) use ($nmo){ + $invoices->first()->invitations->each(function ($invitation) use ($nmo) { - if ($invitation->contact->send_email && $invitation->contact->email) { + if ($invitation->contact->send_email && $invitation->contact->email) { - $nmo->to_user = $invitation->contact; - NinjaMailerJob::dispatch($nmo); - - } - - }); + $nmo->to_user = $invitation->contact; + NinjaMailerJob::dispatch($nmo); + } + }); + } SystemLogger::dispatch( From a1875e2e32c01821a5860d9882a8b24213243637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 16:21:11 +0200 Subject: [PATCH 08/21] Handle failed authorization method --- app/PaymentDrivers/Braintree/ACH.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Braintree/ACH.php b/app/PaymentDrivers/Braintree/ACH.php index 00a3cc0371..e50778176b 100644 --- a/app/PaymentDrivers/Braintree/ACH.php +++ b/app/PaymentDrivers/Braintree/ACH.php @@ -72,7 +72,7 @@ class ACH implements MethodInterface return redirect()->route('client.payment_methods.index'); } catch (\Exception $e) { - // .. + return $this->braintree->processInternallyFailedPayment($this->braintree, $e); } } } From 2856f36a8677dd4fe937b304d7a3a5f362c789ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 17:00:32 +0200 Subject: [PATCH 09/21] Payment page with token --- app/PaymentDrivers/Braintree/ACH.php | 100 +++++++++++++++++- .../gateways/braintree/ach/pay.blade.php | 5 +- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/app/PaymentDrivers/Braintree/ACH.php b/app/PaymentDrivers/Braintree/ACH.php index e50778176b..1b400e61dd 100644 --- a/app/PaymentDrivers/Braintree/ACH.php +++ b/app/PaymentDrivers/Braintree/ACH.php @@ -11,13 +11,24 @@ namespace App\PaymentDrivers\Braintree; +use App\Exceptions\PaymentFailed; +use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Http\Requests\Request; +use App\Jobs\Mail\PaymentFailureMailer; +use App\Jobs\Util\SystemLogger; +use App\Models\ClientGatewayToken; use App\Models\GatewayType; +use App\Models\Payment; +use App\Models\PaymentType; +use App\Models\SystemLog; use App\PaymentDrivers\BraintreePaymentDriver; use App\PaymentDrivers\Common\MethodInterface; +use App\Utils\Traits\MakesHash; class ACH implements MethodInterface { + use MakesHash; + protected BraintreePaymentDriver $braintree; public function __construct(BraintreePaymentDriver $braintree) @@ -70,7 +81,7 @@ class ACH implements MethodInterface $this->braintree->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]); - return redirect()->route('client.payment_methods.index'); + return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); } catch (\Exception $e) { return $this->braintree->processInternallyFailedPayment($this->braintree, $e); } @@ -80,7 +91,94 @@ class ACH implements MethodInterface public function paymentView(array $data) { $data['gateway'] = $this->braintree; + $data['currency'] = $this->braintree->client->getCurrencyCode(); + $data['payment_method_id'] = GatewayType::BANK_TRANSFER; + $data['amount'] = $this->braintree->payment_hash->data->amount_with_fee; return render('gateways.braintree.ach.pay', $data); } + + public function paymentResponse(PaymentResponseRequest $request) + { + $request->validate([ + 'source' => ['required'], + 'payment_hash' => ['required'], + ]); + + $customer = $this->braintree->findOrCreateCustomer(); + + $token = ClientGatewayToken::query() + ->where('client_id', auth('contact')->user()->client->id) + ->where('id', $this->decodePrimaryKey($request->source)) + ->firstOrFail(); + + $result = $this->braintree->gateway->transaction()->sale([ + 'amount' => $this->braintree->payment_hash->data->amount_with_fee, + 'paymentMethodToken' => $token->token, + 'options' => [ + 'submitForSettlement' => true + ], + ]); + + if ($result->success) { + $this->braintree->logSuccessfulGatewayResponse(['response' => $request->server_response, 'data' => $this->braintree->payment_hash], SystemLog::TYPE_BRAINTREE); + + return $this->processSuccessfulPayment($result); + } + + return $this->processUnsuccessfulPayment($result); + } + + private function processSuccessfulPayment($response) + { + $state = $this->braintree->payment_hash->data; + + $data = [ + 'payment_type' => PaymentType::ACH, + 'amount' => $this->braintree->payment_hash->data->amount_with_fee, + 'transaction_reference' => $response->transaction->id, + 'gateway_type_id' => GatewayType::BANK_TRANSFER, + ]; + + $payment = $this->braintree->createPayment($data, Payment::STATUS_COMPLETED); + + SystemLogger::dispatch( + ['response' => $response, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_BRAINTREE, + $this->braintree->client, + $this->braintree->client->company, + ); + + return redirect()->route('client.payments.show', ['payment' => $this->braintree->encodePrimaryKey($payment->id)]); + } + + private function processUnsuccessfulPayment($response) + { + PaymentFailureMailer::dispatch($this->braintree->client, $response->transaction->additionalProcessorResponse, $this->braintree->client->company, $this->braintree->payment_hash->data->amount_with_fee); + + PaymentFailureMailer::dispatch( + $this->braintree->client, + $response, + $this->braintree->client->company, + $this->braintree->payment_hash->data->amount_with_fee, + ); + + $message = [ + 'server_response' => $response, + 'data' => $this->braintree->payment_hash->data, + ]; + + SystemLogger::dispatch( + $message, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_BRAINTREE, + $this->braintree->client, + $this->braintree->client->company, + ); + + throw new PaymentFailed($response->transaction->additionalProcessorResponse, $response->transaction->processorResponseCode); + } } diff --git a/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php b/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php index d6ccfb9851..50f87edcd4 100644 --- a/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/braintree/ach/pay.blade.php @@ -13,7 +13,6 @@ - @@ -51,7 +50,9 @@ document.querySelector('input[name=source]').value = element.target.dataset.token; })); - document.getElementById('pay-now').addEventListener('click', function () { + document.getElementById('pay-now').addEventListener('click', function (e) { + e.target.parentElement.disabled = true; + document.getElementById('server-response').submit(); }); From cd15861158339344945ba5cd051c0f4bbf24f811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 17:00:43 +0200 Subject: [PATCH 10/21] Add `paymentResponse` to MethodInterface.php --- app/PaymentDrivers/Common/MethodInterface.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/PaymentDrivers/Common/MethodInterface.php b/app/PaymentDrivers/Common/MethodInterface.php index 6e68b82dcf..0c839d602c 100644 --- a/app/PaymentDrivers/Common/MethodInterface.php +++ b/app/PaymentDrivers/Common/MethodInterface.php @@ -11,6 +11,7 @@ namespace App\PaymentDrivers\Common; +use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Http\Requests\Request; interface MethodInterface @@ -35,4 +36,11 @@ interface MethodInterface * @param array $data */ public function paymentView(array $data); + + /** + * Process the response from the payments page. + * + * @param PaymentResponseRequest $request + */ + public function paymentResponse(PaymentResponseRequest $request); } From fef4665c5aaa4ba2b488ac5de3d449e93a7670f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 17:32:20 +0200 Subject: [PATCH 11/21] Extract Javascript into separate file --- public/mix-manifest.json | 1 + .../clients/payment_methods/braintree-ach.js | 66 +++++++++++++++++++ .../braintree/ach/authorize.blade.php | 60 +---------------- webpack.mix.js | 4 ++ 4 files changed, 72 insertions(+), 59 deletions(-) create mode 100644 resources/js/clients/payment_methods/braintree-ach.js diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 9455fb18be..bf6470cd60 100755 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -5,6 +5,7 @@ "/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1", "/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7", "/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=f7f4ecfb1771951b91e7", + "/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=9fb7941baba1f9645ed9", "/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=8fea0be371d430064a89", "/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=7c2cbef525868592f42e", "/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=81957e7cb1cb49f23b90", diff --git a/resources/js/clients/payment_methods/braintree-ach.js b/resources/js/clients/payment_methods/braintree-ach.js new file mode 100644 index 0000000000..849145fa6a --- /dev/null +++ b/resources/js/clients/payment_methods/braintree-ach.js @@ -0,0 +1,66 @@ +/** + * Invoice Ninja (https://invoiceninja.com). + * + * @link https://github.com/invoiceninja/invoiceninja source repository + * + * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) + * + * @license https://www.elastic.co/licensing/elastic-license + */ + +window.braintree.client.create({ + authorization: document.querySelector('meta[name="client-token"]')?.content +}).then(function (clientInstance) { + return braintree.usBankAccount.create({ + client: clientInstance + }); +}).then(function (usBankAccountInstance) { + document + .getElementById('authorize-bank-account') + ?.addEventListener('click', (e) => { + e.target.parentElement.disabled = true; + + document.getElementById('errors').hidden = true; + document.getElementById('errors').textContent = ''; + + let bankDetails = { + accountNumber: document.getElementById('account-number').value, + routingNumber: document.getElementById('routing-number').value, + accountType: document.querySelector('input[name="account-type"]:checked').value, + ownershipType: document.querySelector('input[name="ownership-type"]:checked').value, + billingAddress: { + streetAddress: document.getElementById('billing-street-address').value, + extendedAddress: document.getElementById('billing-extended-address').value, + locality: document.getElementById('billing-locality').value, + region: document.getElementById('billing-region').value, + postalCode: document.getElementById('billing-postal-code').value + } + } + + if (bankDetails.ownershipType === 'personal') { + let name = document.getElementById('account-holder-name').value.split(' ', 2); + + bankDetails.firstName = name[0]; + bankDetails.lastName = name[1]; + } else { + bankDetails.businessName = document.getElementById('account-holder-name').value; + } + + usBankAccountInstance.tokenize({ + bankDetails, + mandateText: 'By clicking ["Checkout"], I authorize Braintree, a service of PayPal, on behalf of [your business name here] (i) to verify my bank account information using bank information and consumer reports and (ii) to debit my bank account.' + }).then(function (payload) { + document.querySelector('input[name=nonce]').value = payload.nonce; + document.getElementById('server_response').submit(); + }) + .catch(function (error) { + e.target.parentElement.disabled = false; + + document.getElementById('errors').textContent = `${error.details.originalError.message} ${error.details.originalError.details.originalError[0].message}`; + document.getElementById('errors').hidden = false; + }); + }); +}).catch(function (err) { + document.getElementById('errors').textContent = `${error.details.originalError.message} ${error.details.originalError.details.originalError[0].message}`; + document.getElementById('errors').hidden = false; +}); diff --git a/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php index ba2e9357ba..e5b48683b3 100644 --- a/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php @@ -87,63 +87,5 @@ @section('gateway_footer') - - + @endsection diff --git a/webpack.mix.js b/webpack.mix.js index faec00d75f..dfc018aa86 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -93,6 +93,10 @@ mix.js("resources/js/app.js", "public/js") .js( "resources/js/clients/payments/eway-credit-card.js", "public/js/clients/payments/eway-credit-card.js" + ) + .js( + "resources/js/clients/payment_methods/braintree-ach.js", + "public/js/clients/payment_methods/braintree-ach.js" ); mix.copyDirectory('node_modules/card-js/card-js.min.css', 'public/css/card-js.min.css'); From 0468363c8da87baa43507c5613601acdd30f0247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 17:32:28 +0200 Subject: [PATCH 12/21] Assets production build --- .../clients/payment_methods/braintree-ach.js | 2 ++ .../braintree-ach.js.LICENSE.txt | 9 ++++++++ .../Gateways/Braintree/ACHTest.php | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 public/js/clients/payment_methods/braintree-ach.js create mode 100644 public/js/clients/payment_methods/braintree-ach.js.LICENSE.txt create mode 100644 tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php diff --git a/public/js/clients/payment_methods/braintree-ach.js b/public/js/clients/payment_methods/braintree-ach.js new file mode 100644 index 0000000000..21a7acd168 --- /dev/null +++ b/public/js/clients/payment_methods/braintree-ach.js @@ -0,0 +1,2 @@ +/*! For license information please see braintree-ach.js.LICENSE.txt */ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=24)}({24:function(e,t,n){e.exports=n("cGea")},cGea:function(e,t){var n;window.braintree.client.create({authorization:null===(n=document.querySelector('meta[name="client-token"]'))||void 0===n?void 0:n.content}).then((function(e){return braintree.usBankAccount.create({client:e})})).then((function(e){var t;null===(t=document.getElementById("authorize-bank-account"))||void 0===t||t.addEventListener("click",(function(t){t.target.parentElement.disabled=!0,document.getElementById("errors").hidden=!0,document.getElementById("errors").textContent="";var n={accountNumber:document.getElementById("account-number").value,routingNumber:document.getElementById("routing-number").value,accountType:document.querySelector('input[name="account-type"]:checked').value,ownershipType:document.querySelector('input[name="ownership-type"]:checked').value,billingAddress:{streetAddress:document.getElementById("billing-street-address").value,extendedAddress:document.getElementById("billing-extended-address").value,locality:document.getElementById("billing-locality").value,region:document.getElementById("billing-region").value,postalCode:document.getElementById("billing-postal-code").value}};if("personal"===n.ownershipType){var r=document.getElementById("account-holder-name").value.split(" ",2);n.firstName=r[0],n.lastName=r[1]}else n.businessName=document.getElementById("account-holder-name").value;e.tokenize({bankDetails:n,mandateText:'By clicking ["Checkout"], I authorize Braintree, a service of PayPal, on behalf of [your business name here] (i) to verify my bank account information using bank information and consumer reports and (ii) to debit my bank account.'}).then((function(e){document.querySelector("input[name=nonce]").value=e.nonce,document.getElementById("server_response").submit()})).catch((function(e){t.target.parentElement.disabled=!1,document.getElementById("errors").textContent="".concat(e.details.originalError.message," ").concat(e.details.originalError.details.originalError[0].message),document.getElementById("errors").hidden=!1}))}))})).catch((function(e){document.getElementById("errors").textContent="".concat(error.details.originalError.message," ").concat(error.details.originalError.details.originalError[0].message),document.getElementById("errors").hidden=!1}))}}); \ No newline at end of file diff --git a/public/js/clients/payment_methods/braintree-ach.js.LICENSE.txt b/public/js/clients/payment_methods/braintree-ach.js.LICENSE.txt new file mode 100644 index 0000000000..6b30888ddb --- /dev/null +++ b/public/js/clients/payment_methods/braintree-ach.js.LICENSE.txt @@ -0,0 +1,9 @@ +/** + * Invoice Ninja (https://invoiceninja.com). + * + * @link https://github.com/invoiceninja/invoiceninja source repository + * + * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) + * + * @license https://www.elastic.co/licensing/elastic-license + */ diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php new file mode 100644 index 0000000000..025301e4e0 --- /dev/null +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -0,0 +1,23 @@ +browse(function (Browser $browser) { + $browser->visit('/') + ->assertSee('Laravel'); + }); + } +} From ab90db5295a11a161a2782f3cc1e69f6ba4f3bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 19:36:21 +0200 Subject: [PATCH 13/21] Scaffold ACHTest --- .../Gateways/Braintree/ACHTest.php | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php index 025301e4e0..0673dc6fc9 100644 --- a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -2,22 +2,48 @@ namespace Tests\Browser\ClientPortal\Gateways\Braintree; +use App\DataMapper\FeesAndLimits; +use App\Models\Company; +use App\Models\CompanyGateway; +use App\Models\GatewayType; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; +use Tests\Browser\Pages\ClientPortal\Login; use Tests\DuskTestCase; class ACHTest extends DuskTestCase { - /** - * A Dusk test example. - * - * @return void - */ - public function testExample() + protected function setUp(): void { + parent::setUp(); + + foreach (static::$browsers as $browser) { + $browser->driver->manage()->deleteAllCookies(); + } + $this->browse(function (Browser $browser) { - $browser->visit('/') - ->assertSee('Laravel'); + $browser + ->visit(new Login()) + ->auth(); }); + + $this->disableCompanyGateways(); + + CompanyGateway::where('gateway_key', 'f7ec488676d310683fb51802d076d713')->restore(); + + $cg = CompanyGateway::where('gateway_key', 'f7ec488676d310683fb51802d076d713')->firstOrFail(); + $fees_and_limits = $cg->fees_and_limits; + $fees_and_limits->{GatewayType::BANK_TRANSFER} = new FeesAndLimits(); + $cg->fees_and_limits = $fees_and_limits; + $cg->save(); + + $company = Company::first(); + $settings = $company->settings; + + $settings->client_portal_allow_under_payment = true; + $settings->client_portal_allow_over_payment = true; + + $company->settings = $settings; + $company->save(); } } From 3b22fc5e176403cada3eadb1c70b1beb5588821c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 19:45:45 +0200 Subject: [PATCH 14/21] Test adding bank account --- resources/lang/en/texts.php | 5 ++++- .../ClientPortal/Gateways/Braintree/ACHTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 18fd55344c..dc5ee29bd4 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4297,7 +4297,10 @@ $LANG = array( 'lang_Latvian' => 'Latvian', 'expiry_date' => 'Expiry date', 'cardholder_name' => 'Card holder name', - + 'account_type' => 'Account type', + 'locality' => 'Locality', + 'checking' => 'Checking', + 'savings' => 'Savings', ); return $LANG; diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php index 0673dc6fc9..9f0887dccc 100644 --- a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -46,4 +46,21 @@ class ACHTest extends DuskTestCase $company->settings = $settings; $company->save(); } + + public function testAddingBankAccount() + { + $this->browse(function (Browser $browser) { + $browser + ->visitRoute('client.payment_methods.index') + ->press('Add Payment Method') + ->clickLink('Bank Account') + ->type('#account-holder-name', 'John Doe') + ->type('#account-number', '1000000000') + ->type('#routing-number', '011000015') + ->type('#billing-region', 'AL') + ->type('#billing-postal-code', '12345') + ->press('Add Payment Method') + ->assertSee('Added payment method.'); + }); + } } From a89f5a8fc0eadef67e80d1af689746487cef34d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 19:45:59 +0200 Subject: [PATCH 15/21] Test paying with ACH --- .../ClientPortal/Gateways/Braintree/ACHTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php index 9f0887dccc..12d91dca9a 100644 --- a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -63,4 +63,18 @@ class ACHTest extends DuskTestCase ->assertSee('Added payment method.'); }); } + + public function testPayingWithExistingACH() + { + $this->browse(function (Browser $browser) { + $browser + ->visitRoute('client.invoices.index') + ->click('@pay-now') + ->press('Pay Now') + ->clickLink('Bank Transfer') + ->click('.toggle-payment-with-token') + ->press('Pay Now') + ->waitForText('Details of the payment', 60); + }); + } } From 8467c60a3bed93d46a7fdc16dd29406a01709238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 27 Aug 2021 19:46:20 +0200 Subject: [PATCH 16/21] Test removing ACH account --- .../ClientPortal/Gateways/Braintree/ACHTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php index 12d91dca9a..38caa94abb 100644 --- a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -77,4 +77,17 @@ class ACHTest extends DuskTestCase ->waitForText('Details of the payment', 60); }); } + + public function testRemoveACHAccount() + { + $this->browse(function (Browser $browser) { + $browser + ->visitRoute('client.payment_methods.index') + ->clickLink('View') + ->press('Remove Payment Method') + ->waitForText('Confirmation') + ->click('@confirm-payment-removal') + ->assertSee('Payment method has been successfully removed.'); + }); + } } From e67c668fd823d54c1097e0603c8026f3fe531797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 30 Aug 2021 12:18:57 +0200 Subject: [PATCH 17/21] Show message on unsuccessful verification --- app/PaymentDrivers/Braintree/ACH.php | 6 ++++-- resources/lang/en/texts.php | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Braintree/ACH.php b/app/PaymentDrivers/Braintree/ACH.php index 1b400e61dd..1a91473d5b 100644 --- a/app/PaymentDrivers/Braintree/ACH.php +++ b/app/PaymentDrivers/Braintree/ACH.php @@ -63,7 +63,7 @@ class ACH implements MethodInterface ], ]); - if ($result->success) { + if ($result->success && optional($result->paymentMethod)->verified) { $account = $result->paymentMethod; try { @@ -71,7 +71,7 @@ class ACH implements MethodInterface $payment_meta->brand = (string)$account->bankName; $payment_meta->last4 = (string)$account->last4; $payment_meta->type = GatewayType::BANK_TRANSFER; - $payment_meta->state = $account->verified ? 'authorized' : 'unauthorized'; + $payment_meta->state = 'authorized'; $data = [ 'payment_meta' => $payment_meta, @@ -86,6 +86,8 @@ class ACH implements MethodInterface return $this->braintree->processInternallyFailedPayment($this->braintree, $e); } } + + return back()->withMessage(ctrans('texts.unable_to_verify_payment_method')); } public function paymentView(array $data) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index dc5ee29bd4..7ed8c1b22e 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4301,6 +4301,7 @@ $LANG = array( 'locality' => 'Locality', 'checking' => 'Checking', 'savings' => 'Savings', + 'unable_to_verify_payment_method' => 'Unable to verify payment method.', ); return $LANG; From 7be6252233ade5b267145875d44f80a801b16cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 30 Aug 2021 12:28:23 +0200 Subject: [PATCH 18/21] Provide US states for Braintree ACH --- app/DataProviders/USStates.php | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 app/DataProviders/USStates.php diff --git a/app/DataProviders/USStates.php b/app/DataProviders/USStates.php new file mode 100644 index 0000000000..0551b5fbc3 --- /dev/null +++ b/app/DataProviders/USStates.php @@ -0,0 +1,75 @@ + 'Alabama', + 'AK' => 'Alaska', + 'AZ' => 'Arizona', + 'AR' => 'Arkansas', + 'CA' => 'California', + 'CO' => 'Colorado', + 'CT' => 'Connecticut', + 'DE' => 'Delaware', + 'DC' => 'District Of Columbia', + 'FL' => 'Florida', + 'GA' => 'Georgia', + 'HI' => 'Hawaii', + 'ID' => 'Idaho', + 'IL' => 'Illinois', + 'IN' => 'Indiana', + 'IA' => 'Iowa', + 'KS' => 'Kansas', + 'KY' => 'Kentucky', + 'LA' => 'Louisiana', + 'ME' => 'Maine', + 'MD' => 'Maryland', + 'MA' => 'Massachusetts', + 'MI' => 'Michigan', + 'MN' => 'Minnesota', + 'MS' => 'Mississippi', + 'MO' => 'Missouri', + 'MT' => 'Montana', + 'NE' => 'Nebraska', + 'NV' => 'Nevada', + 'NH' => 'New Hampshire', + 'NJ' => 'New Jersey', + 'NM' => 'New Mexico', + 'NY' => 'New York', + 'NC' => 'North Carolina', + 'ND' => 'North Dakota', + 'OH' => 'Ohio', + 'OK' => 'Oklahoma', + 'OR' => 'Oregon', + 'PA' => 'Pennsylvania', + 'RI' => 'Rhode Island', + 'SC' => 'South Carolina', + 'SD' => 'South Dakota', + 'TN' => 'Tennessee', + 'TX' => 'Texas', + 'UT' => 'Utah', + 'VT' => 'Vermont', + 'VA' => 'Virginia', + 'WA' => 'Washington', + 'WV' => 'West Virginia', + 'WI' => 'Wisconsin', + 'WY' => 'Wyoming', + ]; + + public static function get(): array + { + return self::$states; + } +} From 631814db2610a3872144d4e96c2a2e1d82d5d9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 30 Aug 2021 12:28:34 +0200 Subject: [PATCH 19/21] Update form field to use states --- .../ninja2020/gateways/braintree/ach/authorize.blade.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php index e5b48683b3..91e313fc27 100644 --- a/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/braintree/ach/authorize.blade.php @@ -72,7 +72,11 @@ @endcomponent @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.state')]) - + @endcomponent @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.postal_code')]) From 5b8347a18429b6dbff168f596b6037f9850aa5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 30 Aug 2021 12:34:45 +0200 Subject: [PATCH 20/21] Fixes for tests --- tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php index 38caa94abb..e884e63ed6 100644 --- a/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php +++ b/tests/Browser/ClientPortal/Gateways/Braintree/ACHTest.php @@ -57,10 +57,9 @@ class ACHTest extends DuskTestCase ->type('#account-holder-name', 'John Doe') ->type('#account-number', '1000000000') ->type('#routing-number', '011000015') - ->type('#billing-region', 'AL') ->type('#billing-postal-code', '12345') ->press('Add Payment Method') - ->assertSee('Added payment method.'); + ->waitForText('Added payment method.'); }); } From 236a0f225aae1bc00a375fdce302efe8a118c1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 30 Aug 2021 12:43:00 +0200 Subject: [PATCH 21/21] Fixes for auto billing --- app/PaymentDrivers/BraintreePaymentDriver.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/BraintreePaymentDriver.php b/app/PaymentDrivers/BraintreePaymentDriver.php index ca22ca6f4f..f1d0858284 100644 --- a/app/PaymentDrivers/BraintreePaymentDriver.php +++ b/app/PaymentDrivers/BraintreePaymentDriver.php @@ -221,7 +221,8 @@ class BraintreePaymentDriver extends BaseDriver SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_BRAINTREE, - $this->client + $this->client, + $this->client->company, ); return $payment; @@ -242,7 +243,8 @@ class BraintreePaymentDriver extends BaseDriver SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_BRAINTREE, - $this->client + $this->client, + $this->client->company ); return false;