diff --git a/app/Http/Controllers/Gateways/GoCardlessController.php b/app/Http/Controllers/Gateways/GoCardlessController.php new file mode 100644 index 000000000000..fce5d5eea7ee --- /dev/null +++ b/app/Http/Controllers/Gateways/GoCardlessController.php @@ -0,0 +1,29 @@ +getCompanyGateway() + ->driver($request->getClient()) + ->setPaymentMethod(GatewayType::INSTANT_BANK_PAY) + ->processPaymentResponse($request); + } +} diff --git a/app/Http/Requests/Gateways/GoCardless/IbpRequest.php b/app/Http/Requests/Gateways/GoCardless/IbpRequest.php new file mode 100644 index 000000000000..8caeaf64ca2b --- /dev/null +++ b/app/Http/Requests/Gateways/GoCardless/IbpRequest.php @@ -0,0 +1,67 @@ +company_key)->first(); + } + + public function getCompanyGateway(): ?CompanyGateway + { + return CompanyGateway::find($this->decodePrimaryKey($this->company_gateway_id)); + } + + public function getPaymentHash(): ?PaymentHash + { + return PaymentHash::where('hash', $this->hash)->firstOrFail(); + } + + public function getClient(): ?Client + { + return Client::find($this->getPaymentHash()->data->client_id); + } +} diff --git a/app/PaymentDrivers/GoCardless/InstantBankPay.php b/app/PaymentDrivers/GoCardless/InstantBankPay.php index 824121f5f58c..8ff808af91be 100644 --- a/app/PaymentDrivers/GoCardless/InstantBankPay.php +++ b/app/PaymentDrivers/GoCardless/InstantBankPay.php @@ -2,9 +2,16 @@ namespace App\PaymentDrivers\GoCardless; +use App\Exceptions\PaymentFailed; use Illuminate\Http\Request; use App\PaymentDrivers\Common\MethodInterface; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; +use App\Jobs\Mail\PaymentFailureMailer; +use App\Jobs\Util\SystemLogger; +use App\Models\GatewayType; +use App\Models\Payment; +use App\Models\PaymentType; +use App\Models\SystemLog; use App\PaymentDrivers\GoCardlessPaymentDriver; class InstantBankPay implements MethodInterface @@ -18,11 +25,141 @@ class InstantBankPay implements MethodInterface $this->go_cardless->init(); } - public function authorizeView(array $data) { } + public function authorizeView(array $data) + { + } - public function authorizeResponse(Request $request) { } + public function authorizeResponse(Request $request) + { + } - public function paymentView(array $data) { } + public function paymentView(array $data) + { + try { + $billing_request = $this->go_cardless->gateway->billingRequests()->create([ + 'params' => [ + 'payment_request' => [ + 'description' => ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number'), + 'amount' => (string) $data['amount_with_fee'] * 100, + 'currency' => $this->go_cardless->client->getCurrencyCode(), + ], + ] + ]); - public function paymentResponse(PaymentResponseRequest $request) { } + $billing_request_flow = $this->go_cardless->gateway->billingRequestFlows()->create([ + 'params' => [ + 'redirect_uri' => route('gocardless.ibp_redirect', [ + 'company_key' => $this->go_cardless->company_gateway->company->company_key, + 'company_gateway_id' => $this->go_cardless->company_gateway->hashed_id, + 'hash' => $this->go_cardless->payment_hash->hash, + ]), + 'links' => [ + 'billing_request' => $billing_request->id, + ] + ], + ]); + + $this->go_cardless->payment_hash + ->withData('client_id', $this->go_cardless->client->id) + ->withData('billing_request', $billing_request->id) + ->withData('billing_request_flow', $billing_request_flow->id); + + return redirect( + $billing_request_flow->authorisation_url + ); + } catch (\Exception $exception) { + throw $exception; + } + } + + public function paymentResponse($request) + { + $this->go_cardless->setPaymentHash( + $request->getPaymentHash() + ); + + try { + $billing_request = $this->go_cardless->gateway->billingRequests()->get( + $this->go_cardless->payment_hash->data->billing_request + ); + + $payment = $this->go_cardless->gateway->payments()->get( + $billing_request->payment_request->links->payment + ); + + if ($billing_request->status === 'fulfilled') { + return $this->processSuccessfulPayment($payment); + } + + return $this->processUnsuccessfulPayment($payment); + } catch (\Exception $exception) { + throw new PaymentFailed( + $exception->getMessage(), + $exception->getCode() + ); + } + } + + /** + * Handle pending payments for Instant Bank Transfer. + * + * @param ResourcesPayment $payment + * @param array $data + * @return RedirectResponse + */ + public function processSuccessfulPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) + { + $data = [ + 'payment_method' => $payment->links->mandate, + 'payment_type' => PaymentType::INSTANT_BANK_PAY, + 'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, + 'transaction_reference' => $payment->id, + 'gateway_type_id' => GatewayType::INSTANT_BANK_PAY, + ]; + + $payment = $this->go_cardless->createPayment($data, Payment::STATUS_COMPLETED); + + SystemLogger::dispatch( + ['response' => $payment, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_GOCARDLESS, + $this->go_cardless->client, + $this->go_cardless->client->company, + ); + + return redirect()->route('client.payments.show', ['payment' => $this->go_cardless->encodePrimaryKey($payment->id)]); + } + + /** + * Process unsuccessful payments for Direct Debit. + * + * @param ResourcesPayment $payment + * @return never + */ + public function processUnsuccessfulPayment(\GoCardlessPro\Resources\Payment $payment) + { + PaymentFailureMailer::dispatch($this->go_cardless->client, $payment->status, $this->go_cardless->client->company, $this->go_cardless->payment_hash->data->amount_with_fee); + + PaymentFailureMailer::dispatch( + $this->go_cardless->client, + $payment, + $this->go_cardless->client->company, + $payment->amount + ); + + $message = [ + 'server_response' => $payment, + 'data' => $this->go_cardless->payment_hash->data, + ]; + + SystemLogger::dispatch( + $message, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_GOCARDLESS, + $this->go_cardless->client, + $this->go_cardless->client->company, + ); + } } diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index 948df3c679e6..c7d890e637d0 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -78,7 +78,9 @@ class GoCardlessPaymentDriver extends BaseDriver $types[] = GatewayType::SEPA; } - $types[] = GatewayType::INSTANT_BANK_PAY; + if ($this->client->currency()->code === 'GBP') { + $types[] = GatewayType::INSTANT_BANK_PAY; + } return $types; } diff --git a/routes/web.php b/routes/web.php index 8c3a8e85d0d3..b8180d7f1583 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,3 +43,4 @@ Route::get('stripe/completed', 'StripeConnectController@completed')->name('strip Route::get('checkout/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Checkout3dsController@index')->name('checkout.3ds_redirect'); Route::get('mollie/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Mollie3dsController@index')->name('mollie.3ds_redirect'); +Route::get('gocardless/ibp_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\GoCardlessController@ibpRedirect')->name('gocardless.ibp_redirect');