From 81a58d89f9b38e948c4fa11712be706037465529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 10:15:43 +0100 Subject: [PATCH 1/8] update label for checkout authorization --- resources/lang/en/texts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index bca47d23277e..ceb5eea43d96 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3233,7 +3233,7 @@ return [ 'test_pdf' => 'Test PDF', 'status_cancelled' => 'Cancelled', - 'checkout_authorize_label' => 'Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Save card" during payment process.', + 'checkout_authorize_label' => 'Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Store credit card details" during payment process.', 'node_status' => 'Node status', 'npm_status' => 'NPM status', From 4a4a974a8d28718d55d752adb3c132afabca05c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:48:58 +0100 Subject: [PATCH 2/8] update matching on payment_webhook route --- routes/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index 8291c7185c75..81d65c713f87 100644 --- a/routes/api.php +++ b/routes/api.php @@ -180,6 +180,6 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::post('support/messages/send', 'Support\Messages\SendingController'); }); -Route::match(['get', 'post'], 'payment_webhook/{company_key?}/{gateway_key?}', 'PaymentWebhookController'); +Route::match(['get', 'post'], 'payment_webhook/{gateway_key}/{company_key}', 'PaymentWebhookController')->name('payment_webhook'); Route::fallback('BaseController@notFound'); From 2609e0027a6452d964315c9607458f7d55a7394f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:49:11 +0100 Subject: [PATCH 3/8] allow paymentfailed exception for guest middleware --- app/Exceptions/PaymentFailed.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/Exceptions/PaymentFailed.php b/app/Exceptions/PaymentFailed.php index 06d3f9dda5cb..55762f03fd8a 100644 --- a/app/Exceptions/PaymentFailed.php +++ b/app/Exceptions/PaymentFailed.php @@ -13,7 +13,14 @@ class PaymentFailed extends Exception public function render($request) { - return render('gateways.unsuccessful', [ + if (auth()->user()) { + return render('gateways.unsuccessful', [ + 'message' => $this->getMessage(), + 'code' => $this->getCode(), + ]); + } + + return response([ 'message' => $this->getMessage(), 'code' => $this->getCode(), ]); From c548bc2e0ddfa9d5061339c7bdccb63be5b1baf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:49:30 +0100 Subject: [PATCH 4/8] refactor paymentwebhook suite with new methods --- .../Controllers/PaymentWebhookController.php | 36 ++-------- .../Payments/PaymentWebhookRequest.php | 70 ++++++++++++++----- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/app/Http/Controllers/PaymentWebhookController.php b/app/Http/Controllers/PaymentWebhookController.php index e1884e7af149..b32afa1d4c11 100644 --- a/app/Http/Controllers/PaymentWebhookController.php +++ b/app/Http/Controllers/PaymentWebhookController.php @@ -13,8 +13,6 @@ namespace App\Http\Controllers; use App\Http\Requests\Payments\PaymentWebhookRequest; -use App\Models\Payment; -use Illuminate\Support\Arr; class PaymentWebhookController extends Controller { @@ -23,36 +21,10 @@ class PaymentWebhookController extends Controller $this->middleware('guest'); } - public function __invoke(PaymentWebhookRequest $request, string $company_key = null, string $gateway_key = null) + public function __invoke(PaymentWebhookRequest $request, string $gateway_key, string $company_key) { - $transaction_reference = $this->getTransactionReference($request->all(), $request); - - $payment = Payment::where('transaction_reference', $transaction_reference)->first(); - - if (is_null($payment)) { - return response([ - 'message' => 'Sorry, we couldn\'t find requested payment.', - 'status_code' => 404, - ], 404); /* Record event, throw an exception.. */ - } - - return $request - ->companyGateway() - ->driver($payment->client) - ->setPaymentMethod($payment->gateway_type_id) - ->processWebhookRequest($request->all(), $request->company(), $request->companyGateway(), $payment); - } - - public function getTransactionReference(array $data, PaymentWebhookRequest $request) - { - $flatten = Arr::dot($data); - - if (isset($flatten['data.object.id'])) { - return $flatten['data.object.id']; // stripe.com - } - - if ($request->has('cko-session-id')) { - // checkout.com - } + return $request->getCompanyGateway() + ->driver($request->getClient()) + ->processWebhookRequest($request, $request->getPayment()); } } diff --git a/app/Http/Requests/Payments/PaymentWebhookRequest.php b/app/Http/Requests/Payments/PaymentWebhookRequest.php index 7dc483272a23..81b44bcfd1b0 100644 --- a/app/Http/Requests/Payments/PaymentWebhookRequest.php +++ b/app/Http/Requests/Payments/PaymentWebhookRequest.php @@ -1,4 +1,5 @@ company_key) { - return false; - } - - return Company::query() - ->where('company_key', $this->company_key) - ->firstOrFail(); + return CompanyGateway::where('gateway_key', $this->gateway_key)->firstOrFail(); } - public function companyGateway() + /** + * Resolve payment hash. + * + * @param string $hash + * @return null|\App\Http\Requests\Payments\PaymentHash + */ + public function getPaymentHash(): ?PaymentHash { - if (! $this->gateway_key || ! $this->company_key) { - return false; + if ($this->query('hash')) { + return PaymentHash::where('hash', $this->query('hash'))->firstOrFail(); } + } - $company = $this->company(); + /** + * Resolve possible payment in the request. + * + * @return null|\App\Models\Payment + */ + public function getPayment(): ?Payment + { + $hash = $this->getPaymentHash(); - return CompanyGateway::query() - ->where('gateway_key', $this->gateway_key) - ->where('company_id', $company->id) - ->firstOrFail(); + return $hash->payment; + } + + /** + * Resolve client from payment hash. + * + * @return null|\App\Models\Client + */ + public function getClient(): ?Client + { + $hash = $this->getPaymentHash(); + + return Client::find($hash->data->client_id)->firstOrFail(); + } + + /** + * Resolve company from company_key parameter. + * + * @return null|\App\Models\Company + */ + public function getCompany(): ?Company + { + return Company::where('company_key', $this->company_key)->firstOrFail(); } } From fdafc068bb597d8085f36a511a81da242d308f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:49:56 +0100 Subject: [PATCH 5/8] processWebhookRequest for checkoutpaymentdriver --- .../CheckoutComPaymentDriver.php | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index afe466d7b3a2..0a55c3703101 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -12,10 +12,15 @@ namespace App\PaymentDrivers; +use App\Http\Requests\Payments\PaymentWebhookRequest; +use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; +use App\Models\Company; +use App\Models\CompanyGateway; use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentHash; +use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\CheckoutCom\CreditCard; use App\PaymentDrivers\CheckoutCom\Utilities; @@ -23,6 +28,7 @@ use App\Utils\Traits\SystemLogTrait; use Checkout\CheckoutApi; use Checkout\Library\Exceptions\CheckoutHttpException; use Checkout\Models\Payments\Refund; +use Exception; class CheckoutComPaymentDriver extends BaseDriver { @@ -134,7 +140,7 @@ class CheckoutComPaymentDriver extends BaseDriver ->route('client.profile.edit', ['client_contact' => auth()->user()->hashed_id]) ->with('missing_required_fields', $this->required_fields); } - + return $this->payment_method->authorizeResponse($data); } @@ -209,5 +215,24 @@ class CheckoutComPaymentDriver extends BaseDriver public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) { + // .. + } + + public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null) + { + $this->init(); + $this->setPaymentHash($request->getPaymentHash()); + + try { + $payment = $this->gateway->payments()->details($request->query('cko-session-id')); + + if ($payment->approved) { + return $this->processSuccessfulPayment($payment); + } else { + return $this->processUnsuccessfulPayment($payment); + } + } catch (CheckoutHttpException | Exception $e) { + return $this->processInternallyFailedPayment($this, $e); + } } } From 7818afddf8593458c633f3d02f7e5d4bbd47b733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:50:30 +0100 Subject: [PATCH 6/8] getParent() ref to utilities --- app/PaymentDrivers/CheckoutCom/Utilities.php | 48 ++++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index 455bc838a895..14a5c66c603d 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -29,6 +29,11 @@ trait Utilities return $this->company_gateway->getConfigField('publicApiKey'); } + public function getParent() + { + return static::class == 'App\PaymentDrivers\CheckoutComPaymentDriver' ? $this : $this->checkout; + } + public function convertToCheckoutAmount($amount, $currency) { $cases = [ @@ -52,42 +57,42 @@ trait Utilities private function processSuccessfulPayment(Payment $_payment) { - if ($this->checkout->payment_hash->data->store_card) { + if ($this->getParent()->payment_hash->data->store_card) { $this->storePaymentMethod($_payment); } $data = [ 'payment_method' => $_payment->source['id'], 'payment_type' => PaymentType::parseCardType(strtolower($_payment->source['scheme'])), - 'amount' => $this->checkout->payment_hash->data->raw_value, + 'amount' => $this->getParent()->payment_hash->data->raw_value, 'transaction_reference' => $_payment->id, ]; - $payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + $payment = $this->getParent()->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); SystemLogger::dispatch( ['response' => $_payment, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_CHECKOUT, - $this->checkout->client + $this->getParent()->client ); - return redirect()->route('client.payments.show', ['payment' => $this->checkout->encodePrimaryKey($payment->id)]); + return redirect()->route('client.payments.show', ['payment' => $this->getParent()->encodePrimaryKey($payment->id)]); } public function processUnsuccessfulPayment(Payment $_payment) { PaymentFailureMailer::dispatch( - $this->checkout->client, + $this->getParent()->client, $_payment, - $this->checkout->client->company, - $this->checkout->payment_hash->data->value + $this->getParent()->client->company, + $this->getParent()->payment_hash->data->value ); $message = [ 'server_response' => $_payment, - 'data' => $this->checkout->payment_hash->data, + 'data' => $this->getParent()->payment_hash->data, ]; SystemLogger::dispatch( @@ -95,7 +100,7 @@ trait Utilities SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, - $this->checkout->client + $this->getParent()->client ); throw new PaymentFailed($_payment->status, $_payment->http_code); @@ -103,27 +108,10 @@ trait Utilities private function processPendingPayment(Payment $_payment) { - $data = [ - 'payment_method' => $_payment->source->id, - 'payment_type' => PaymentType::CREDIT_CARD_OTHER, - 'amount' => $this->checkout->payment_hash->data->value, - 'transaction_reference' => $_payment->id, - ]; - - $payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_PENDING); - - SystemLogger::dispatch( - ['response' => $_payment, 'data' => $data], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_SUCCESS, - SystemLog::TYPE_CHECKOUT, - $this->checkout->client - ); - try { return redirect($_payment->_links['redirect']['href']); } catch (Exception $e) { - return $this->processInternallyFailedPayment($this->checkout, $e); + return $this->processInternallyFailedPayment($this->getParent(), $e); } } @@ -140,10 +128,10 @@ trait Utilities $data = [ 'payment_meta' => $payment_meta, 'token' => $response->source['id'], - 'payment_method_id' => $this->checkout->payment_hash->data->payment_method_id, + 'payment_method_id' => $this->getParent()->payment_hash->data->payment_method_id, ]; - return $this->checkout->storePaymentMethod($data); + return $this->getParent()->storePaymentMethod($data); } catch (Exception $e) { session()->flash('message', ctrans('texts.payment_method_saving_failed')); } From 5c89fdab0288218b13e6ea2808e017b757f8d439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:50:43 +0100 Subject: [PATCH 7/8] pass client id in paymentResponse --- app/PaymentDrivers/CheckoutCom/CreditCard.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index aeffd153351c..d56acdc3c7ad 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -13,6 +13,7 @@ namespace App\PaymentDrivers\CheckoutCom; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; +use App\Models\GatewayType; use App\PaymentDrivers\CheckoutComPaymentDriver; use Checkout\Library\Exceptions\CheckoutHttpException; use Checkout\Models\Payments\IdSource; @@ -82,6 +83,7 @@ class CreditCard 'currency' => $request->currency, 'payment_hash' => $request->payment_hash, 'reference' => $request->payment_hash, + 'client_id' => $this->checkout->client->id, ]; $state = array_merge($state, $request->all()); @@ -121,8 +123,17 @@ class CreditCard $payment->amount = $this->checkout->payment_hash->data->value; $payment->reference = $this->checkout->payment_hash->data->reference; + $this->checkout->payment_hash->data = array_merge((array) $this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]); + $this->checkout->payment_hash->save(); + if ($this->checkout->client->currency()->code === 'EUR') { $payment->{'3ds'} = ['enabled' => true]; + + $payment->{'success_url'} = route('payment_webhook', [ + 'gateway_key' => $this->checkout->company_gateway->gateway_key, + 'company_key' => $this->checkout->client->company->company_key, + 'hash' => $this->checkout->payment_hash->hash, + ]); } try { From a92d38ae0672303d842da9f1c376efa8c1edc5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 7 Dec 2020 14:56:23 +0100 Subject: [PATCH 8/8] php-cs-fixer --- .php_cs | 1 + .../Payments/PaymentWebhookRequest.php | 24 +++++++++---------- app/PaymentDrivers/CheckoutCom/CreditCard.php | 1 - .../CheckoutComPaymentDriver.php | 3 --- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.php_cs b/.php_cs index 9dfc128f7605..33c6ee25511b 100644 --- a/.php_cs +++ b/.php_cs @@ -4,6 +4,7 @@ $finder = Symfony\Component\Finder\Finder::create() ->notPath('vendor') ->notPath('bootstrap') ->notPath('storage') + ->notPath('node_modules') ->in(__DIR__) ->name('*.php') ->notName('*.blade.php'); diff --git a/app/Http/Requests/Payments/PaymentWebhookRequest.php b/app/Http/Requests/Payments/PaymentWebhookRequest.php index 81b44bcfd1b0..f4704559aac8 100644 --- a/app/Http/Requests/Payments/PaymentWebhookRequest.php +++ b/app/Http/Requests/Payments/PaymentWebhookRequest.php @@ -35,9 +35,9 @@ class PaymentWebhookRequest extends Request /** * Resolve company gateway. - * - * @param mixed $id - * @return null|\App\Models\CompanyGateway + * + * @param mixed $id + * @return null|\App\Models\CompanyGateway */ public function getCompanyGateway(): ?CompanyGateway { @@ -46,9 +46,9 @@ class PaymentWebhookRequest extends Request /** * Resolve payment hash. - * - * @param string $hash - * @return null|\App\Http\Requests\Payments\PaymentHash + * + * @param string $hash + * @return null|\App\Http\Requests\Payments\PaymentHash */ public function getPaymentHash(): ?PaymentHash { @@ -59,8 +59,8 @@ class PaymentWebhookRequest extends Request /** * Resolve possible payment in the request. - * - * @return null|\App\Models\Payment + * + * @return null|\App\Models\Payment */ public function getPayment(): ?Payment { @@ -71,8 +71,8 @@ class PaymentWebhookRequest extends Request /** * Resolve client from payment hash. - * - * @return null|\App\Models\Client + * + * @return null|\App\Models\Client */ public function getClient(): ?Client { @@ -83,8 +83,8 @@ class PaymentWebhookRequest extends Request /** * Resolve company from company_key parameter. - * - * @return null|\App\Models\Company + * + * @return null|\App\Models\Company */ public function getCompany(): ?Company { diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index d56acdc3c7ad..f5b51eb52b09 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -13,7 +13,6 @@ namespace App\PaymentDrivers\CheckoutCom; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; -use App\Models\GatewayType; use App\PaymentDrivers\CheckoutComPaymentDriver; use Checkout\Library\Exceptions\CheckoutHttpException; use Checkout\Models\Payments\IdSource; diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 0a55c3703101..9c0ff224eb12 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -13,14 +13,11 @@ namespace App\PaymentDrivers; use App\Http\Requests\Payments\PaymentWebhookRequest; -use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; use App\Models\Company; -use App\Models\CompanyGateway; use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentHash; -use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\CheckoutCom\CreditCard; use App\PaymentDrivers\CheckoutCom\Utilities;