From f7dc57355139b8e96a84b9a1a45430248a289226 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 10 Sep 2020 15:20:13 +1000 Subject: [PATCH 1/5] Fixes for invoices --- app/Jobs/Invoice/CreateInvoicePdf.php | 3 +-- app/Services/Payment/UpdateInvoicePayment.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Jobs/Invoice/CreateInvoicePdf.php b/app/Jobs/Invoice/CreateInvoicePdf.php index acc644594a98..f7632d322c95 100644 --- a/app/Jobs/Invoice/CreateInvoicePdf.php +++ b/app/Jobs/Invoice/CreateInvoicePdf.php @@ -71,6 +71,7 @@ class CreateInvoicePdf implements ShouldQueue public function handle() { + if (config('ninja.phantomjs_key')) { return (new Phantom)->generate($this->invitation); } @@ -111,8 +112,6 @@ class CreateInvoicePdf implements ShouldQueue //todo - move this to the client creation stage so we don't keep hitting this unnecessarily Storage::makeDirectory($path, 0775); - //info($maker->getCompiledHTML(true)); - $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); $instance = Storage::disk($this->disk)->put($file_path, $pdf); diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index 60eaeb686c8c..41bfb41e3ee6 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -75,9 +75,8 @@ class UpdateInvoicePayment ->updateBalance($paid_amount * -1) ->save(); - info("firing invoice was updated event"); event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars())); - info("fired invoice was updated event"); + }); return $this->payment; From c55f660f7f915f3a6e6e1dfc3d620f7ce8911933 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Sep 2020 08:30:12 +1000 Subject: [PATCH 2/5] Generic handling page for unsuccessful payments --- app/Listeners/Invoice/InvoicePaidActivity.php | 2 ++ app/PaymentDrivers/BaseDriver.php | 18 ++++++++++++++++++ .../CheckoutComPaymentDriver.php | 19 ++++++++++++++++--- app/Services/Invoice/InvoiceService.php | 19 +++++++++++++++++++ app/Utils/HtmlEngine.php | 7 ++----- resources/lang/en/texts.php | 1 + .../ninja2020/gateways/unsuccessful.blade.php | 10 ++++++---- 7 files changed, 64 insertions(+), 12 deletions(-) diff --git a/app/Listeners/Invoice/InvoicePaidActivity.php b/app/Listeners/Invoice/InvoicePaidActivity.php index fd39151d86e7..c2d260d9658f 100644 --- a/app/Listeners/Invoice/InvoicePaidActivity.php +++ b/app/Listeners/Invoice/InvoicePaidActivity.php @@ -45,6 +45,8 @@ class InvoicePaidActivity implements ShouldQueue { MultiDB::setDb($event->company->db); + $event->invoice->service()->touchPdf(); + $fields = new \stdClass; $fields->invoice_id = $event->invoice->id; diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index a23002984172..d6089437a2e2 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -194,6 +194,24 @@ class BaseDriver extends AbstractPaymentDriver }); } + /** + * In case of a payment failure we should always + * return the invoice to its original state + * + * @param PaymentHash $payment_hash The payment hash containing the list of invoices + * @return void + */ + public function unWindGatewayFees(PaymentHash $payment_hash) + { + + $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->get(); + + $invoices->each(function ($invoice) { + $invoice->service()->removeUnpaidGatewayFees(); + }); + + } + /** * Return the contact if possible. * diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 45ecfd8bd3e0..0fa692d50fb6 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -253,7 +253,7 @@ class CheckoutComPaymentDriver extends BaseDriver $payment = $this->createPayment($data, Payment::STATUS_PENDING); - $this->attachInvoices($payment, $state['hashed_ids']); + $this->attachInvoices($payment, $state['payment_hash']); $payment->service()->updateInvoicePayment(); @@ -269,9 +269,16 @@ class CheckoutComPaymentDriver extends BaseDriver try { return redirect($state['payment_response']->_links['redirect']['href']); } catch (\Exception $e) { + SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client); - throw new \Exception('Failed to process the payment.', 1); + $this->unWindGatewayFees($state['payment_hash']); + + return render('gateways.unsuccessful', [ + 'code' => $state['payment_response']->response_code, + 'message' => ctrans('texts.payment_error'), + ]); + } } @@ -290,6 +297,7 @@ class CheckoutComPaymentDriver extends BaseDriver return render('gateways.unsuccessful', [ 'code' => $state['payment_response']->response_code, + 'message' => ctrans('texts.payment_error'), ]); } @@ -308,7 +316,12 @@ class CheckoutComPaymentDriver extends BaseDriver //todo push to a error page with the exception message. - throw new \Exception('Failed to process the payment.', 1); + //throw new \Exception('Failed to process the payment.', 1); + + return render('gateways.unsuccessful', [ + 'code' => '500', + 'message' => ctrans('texts.payment_error'), + ]); } public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index b646ffee4386..6dc73c1f7569 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -11,6 +11,7 @@ namespace App\Services\Invoice; +use App\Jobs\Invoice\CreateInvoicePdf; use App\Models\CompanyGateway; use App\Models\Invoice; use App\Models\Payment; @@ -211,6 +212,8 @@ class InvoiceService return $item; })->toArray(); + $this->invoice = $this->invoice->calc()->getInvoice(); + return $this; } @@ -221,6 +224,8 @@ class InvoiceService return $item->type_id == '3'; })->toArray(); + $this->invoice = $this->invoice->calc()->getInvoice(); + return $this; } @@ -241,6 +246,20 @@ class InvoiceService return $this; } + /** + * Sometimes we need to refresh the + * PDF when it is updated etc. + * @return void + */ + public function touchPdf() + { + $this->invoice->invitations->each(function ($invitation){ + CreateInvoicePdf::dispatch($invitation); + }); + + return $this; + } + /*When a reminder is sent we want to touch the dates they were sent*/ public function touchReminder(string $reminder_template) { diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index fc0d7160619b..893f3a31c3bd 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -141,8 +141,6 @@ class HtmlEngine } $data['$entity_number'] = &$data['$number']; - - //$data['$paid_to_date'] = ; $data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ctrans('texts.discount')]; $data['$discount'] = &$data['$invoice.discount']; $data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; @@ -236,9 +234,8 @@ class HtmlEngine $data['$client.country'] = &$data['$country']; $data['$client.email'] = &$data['$email']; - - $data['$client.balance'] = ['value' => $this->client->balance, 'label' => ctrans('texts.balance')]; - $data['$paid_to_date'] = ['value' => $this->client->paid_to_date, 'label' => ctrans('texts.paid_to_date')]; + $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; + $data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')]; $data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')]; $data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')]; diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index b9f14b54c991..4323653b70aa 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3268,4 +3268,5 @@ return [ 'no_items_selected' => 'No items selected.', 'payment_due' => 'Payment due', + 'account_balance' => 'Account balance', ]; diff --git a/resources/views/portal/ninja2020/gateways/unsuccessful.blade.php b/resources/views/portal/ninja2020/gateways/unsuccessful.blade.php index 94ae74289b3f..6b9b900dad2c 100644 --- a/resources/views/portal/ninja2020/gateways/unsuccessful.blade.php +++ b/resources/views/portal/ninja2020/gateways/unsuccessful.blade.php @@ -6,8 +6,10 @@ {{ ctrans('texts.payment_error_code', ['code' => isset($code) ? $code : '']) }} - {{ ctrans('texts.common_codes') }}: - + @if($message) + {{ ctrans('texts.message') }}: + + @endif @endsection From 0b56e8d4cb4e6fbe1fbd76d5a7505997d82b13ef Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Sep 2020 09:01:25 +1000 Subject: [PATCH 3/5] handle payments and gateway fee integration --- app/PaymentDrivers/Authorize/AuthorizeCreditCard.php | 3 +++ app/PaymentDrivers/CheckoutComPaymentDriver.php | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php index e154c5c01250..c531d6d82852 100644 --- a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php +++ b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php @@ -136,6 +136,9 @@ class AuthorizeCreditCard $response = $data['response']; if ($response != null && $response->getMessages()->getResultCode() == 'Ok') { + + $this->authorize->confirmGatewayFee($request); + return $this->processSuccessfulResponse($data, $request); } diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 0fa692d50fb6..7893318e545e 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -182,17 +182,26 @@ class CheckoutComPaymentDriver extends BaseDriver $state['payment_response'] = $response; if ($response->status === 'Authorized') { + $this->confirmGatewayFee($request); + return $this->processSuccessfulPayment($state); } if ($response->status === 'Pending') { + $this->confirmGatewayFee($request); + return $this->processPendingPayment($state); } if ($response->status === 'Declined') { + $this->unWindGatewayFees($request->payment_hash); + return $this->processUnsuccessfulPayment($state); } } catch (CheckoutHttpException $e) { + + $this->unWindGatewayFees($request->payment_hash); + return $this->processInternallyFailedPayment($e, $state); } } From 2f7e01c5a4aea10040b0e505ffa1438400a07858 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Sep 2020 10:10:53 +1000 Subject: [PATCH 4/5] Fixes for paid invoices via gateways --- app/Services/Invoice/InvoiceService.php | 8 ++++++++ app/Services/Payment/UpdateInvoicePayment.php | 1 + 2 files changed, 9 insertions(+) diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 6dc73c1f7569..9e027a98f381 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -201,6 +201,14 @@ class InvoiceService return $this; } + public function updateStatus() + { + if($this->invoice->balance == 0) + $this->setStatus(Invoice::STATUS_PAID); + + return $this; + } + public function toggleFeesPaid() { $this->invoice->line_items = collect($this->invoice->line_items) diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index 41bfb41e3ee6..e9d0fb1717b0 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -73,6 +73,7 @@ class UpdateInvoicePayment $invoice->service() //caution what if we amount paid was less than partial - we wipe it! ->clearPartial() ->updateBalance($paid_amount * -1) + ->updateStatus() ->save(); event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars())); From 9eaa136cc36f7fd556c2a5ecd972e49d92d72ffe Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Sep 2020 10:14:51 +1000 Subject: [PATCH 5/5] Clean up --- app/PaymentDrivers/CheckoutComPaymentDriver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 7893318e545e..0f1deac57357 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -182,12 +182,14 @@ class CheckoutComPaymentDriver extends BaseDriver $state['payment_response'] = $response; if ($response->status === 'Authorized') { + $this->confirmGatewayFee($request); return $this->processSuccessfulPayment($state); } if ($response->status === 'Pending') { + $this->confirmGatewayFee($request); return $this->processPendingPayment($state);