From e27424d5badd372c818238602b55e36aba3847f8 Mon Sep 17 00:00:00 2001 From: Philip Date: Sat, 27 Aug 2022 22:31:44 +0000 Subject: [PATCH 1/6] Stripe checkout support --- Extension.php | 5 + language/en/default.php | 29 +++ payments/Stripe.php | 2 +- payments/StripeCheckout.php | 222 ++++++++++++++++++ payments/stripecheckout/fields.php | 118 ++++++++++ payments/stripecheckout/info.blade.php | 11 + .../stripecheckout/payment_form.blade.php | 0 7 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 payments/StripeCheckout.php create mode 100644 payments/stripecheckout/fields.php create mode 100644 payments/stripecheckout/info.blade.php create mode 100644 payments/stripecheckout/payment_form.blade.php diff --git a/Extension.php b/Extension.php index a2d8578..2a81231 100644 --- a/Extension.php +++ b/Extension.php @@ -33,6 +33,11 @@ public function registerPaymentGateways() 'name' => 'lang:igniter.payregister::default.stripe.text_payment_title', 'description' => 'lang:igniter.payregister::default.stripe.text_payment_desc', ], + \Igniter\PayRegister\Payments\StripeCheckout::class => [ + 'code' => 'stripecheckout', + 'name' => 'lang:igniter.payregister::default.stripecheckout.text_payment_title', + 'description' => 'lang:igniter.payregister::default.stripecheckout.text_payment_desc', + ], \Igniter\PayRegister\Payments\Mollie::class => [ 'code' => 'mollie', 'name' => 'lang:igniter.payregister::default.mollie.text_payment_title', diff --git a/language/en/default.php b/language/en/default.php index ab8db32..6efa310 100644 --- a/language/en/default.php +++ b/language/en/default.php @@ -123,6 +123,35 @@ 'help_locale_code' => 'See Stripe.js supported locales [ + 'text_tab_general' => 'General', + 'text_payment_title' => 'Stripe Checkout', + 'text_payment_desc' => 'Accept credit card, Apple Pay, Google Pay using Stripe builtin Checkout page', + 'text_credit_or_debit' => 'Credit or debit card', + + 'text_auth_only' => 'Authorization Only', + 'text_auth_capture' => 'Authorization & Capture', + 'text_description' => 'Pay by Credit Card using Stripe', + 'text_live' => 'Live', + 'text_test' => 'Test', + 'text_stripe_charge_description' => '%s Charge for %s', + 'text_payment_status' => 'Payment %s (%s)', + + 'label_title' => 'Title', + 'label_description' => 'Description', + 'label_transaction_mode' => 'Transaction Mode', + 'label_transaction_type' => 'Transaction Type', + 'label_test_secret_key' => 'Test Secret Key', + 'label_test_publishable_key' => 'Test Publishable Key', + 'label_live_secret_key' => 'Live Secret Key', + 'label_live_publishable_key' => 'Live Publishable Key', + 'label_locale_code' => 'Locale Code', + 'label_priority' => 'Priority', + 'label_status' => 'Status', + + 'help_locale_code' => 'See Stripe.js supported locales [ 'text_payment_title' => 'Mollie Payment', 'text_payment_desc' => 'Accept credit card payments using Mollie API', diff --git a/payments/Stripe.php b/payments/Stripe.php index f7ddebb..048ee75 100644 --- a/payments/Stripe.php +++ b/payments/Stripe.php @@ -23,7 +23,7 @@ class Stripe extends BasePaymentGateway public function registerEntryPoints() { return [ - 'stripe_webhook' => 'processWebhookUrl', + // 'stripe_webhook' => 'processWebhookUrl', ]; } diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php new file mode 100644 index 0000000..c5bcc2e --- /dev/null +++ b/payments/StripeCheckout.php @@ -0,0 +1,222 @@ + 'processWebhookUrl', + 'stripe_checkout_return_url' => 'processSuccessUrl', + 'stripe_checkout_cancel_url' => 'processCancelUrl', + ]; + } + + public function isTestMode() + { + return $this->model->transaction_mode != 'live'; + } + + public function getPublishableKey() + { + return $this->isTestMode() ? $this->model->test_publishable_key : $this->model->live_publishable_key; + } + + public function getSecretKey() + { + return $this->isTestMode() ? $this->model->test_secret_key : $this->model->live_secret_key; + } + + public function shouldAuthorizePayment() + { + return $this->model->transaction_type == 'auth_only'; + } + + public function isApplicable($total, $host) + { + return $host->order_total <= $total; + } + + /** + * @param array $data + * @param \Admin\Models\Payments_model $host + * @param \Admin\Models\Orders_model $order + * + * @return mixed + */ + public function processPaymentForm($data, $host, $order) + { + $this->validatePaymentMethod($order, $host); + + $fields = $this->getPaymentFormFields($order, $data); + + try { + $gateway = $this->createGateway(); + $response = $gateway->checkout->sessions->create($fields); + + return Redirect::to($response->url); + } catch (Exception $ex) { + $order->logPaymentAttempt('Payment error -> '.$ex->getMessage(), 0, $fields, []); + throw new ApplicationException('Sorry, there was an error processing your payment. Please try again later.'); + } + } + + public function processSuccessUrl($params) + { + $hash = $params[0] ?? null; + $redirectPage = input('redirect'); + $cancelPage = input('cancel'); + + $order = $this->createOrderModel()->whereHash($hash)->first(); + + try { + if (!$hash || !$order instanceof Orders_model) + throw new ApplicationException('No order found'); + + if (!strlen($redirectPage)) + throw new ApplicationException('No redirect page found'); + + if (!strlen($cancelPage)) + throw new ApplicationException('No cancel page found'); + + $paymentMethod = $order->payment_method; + if (!$paymentMethod || $paymentMethod->getGatewayClass() != static::class) + throw new ApplicationException('No valid payment method found'); + + $order->logPaymentAttempt('Payment successful', 1, [], $paymentMethod, true); + $order->updateOrderStatus($paymentMethod->order_status, ['notify' => false]); + $order->markAsPaymentProcessed(); + + return Redirect::to(page_url($redirectPage, [ + 'id' => $order->getKey(), + 'hash' => $order->hash, + ])); + } catch (Exception $ex) { + $order->logPaymentAttempt('Payment error -> '.$ex->getMessage(), 0, [], []); + flash()->warning($ex->getMessage())->important(); + } + + return Redirect::to(page_url($cancelPage)); + } + + public function processCancelUrl($params) + { + $hash = $params[0] ?? null; + $order = $this->createOrderModel()->whereHash($hash)->first(); + if (!$hash || !$order instanceof Orders_model) + throw new ApplicationException('No order found'); + + if (!strlen($redirectPage = input('redirect'))) + throw new ApplicationException('No redirect page found'); + + $paymentMethod = $order->payment_method; + if (!$paymentMethod || $paymentMethod->getGatewayClass() != static::class) + throw new ApplicationException('No valid payment method found'); + + $order->logPaymentAttempt('Payment canceled by customer', 0, input()); + + return Redirect::to(page_url($redirectPage)); + } + + protected function createGateway() + { + \Stripe\Stripe::setAppInfo( + 'TastyIgniter Stripe', + '1.0.0', + 'https://tastyigniter.com/marketplace/item/igniter-payregister', + 'pp_partner_JZyCCGR3cOwj9S' // Used by Stripe to identify this integration + ); + + $stripeClient = new StripeClient([ + 'api_key' => $this->getSecretKey(), + ]); + + $this->fireSystemEvent('payregister.stripe.extendClient', [$stripeClient]); + + return $stripeClient; + } + + protected function getPaymentFormFields($order, $data = []) + { + $cancelUrl = $this->makeEntryPointUrl('stripe_checkout_cancel_url').'/'.$order->hash; + $successUrl = $this->makeEntryPointUrl('stripe_checkout_return_url').'/'.$order->hash; + $successUrl .= '?redirect='.array_get($data, 'successPage').'&cancel='.array_get($data, 'cancelPage'); + + $fields = [ + 'line_items' => [ + [ + 'price_data' => [ + 'currency' => currency()->getUserCurrency(), + // All amounts sent to Stripe must be in integers, representing the lowest currency unit (cents) + 'unit_amount_decimal' => number_format($order->order_total, 2, '.', '') * 100, + 'product_data' => [ + 'name' => 'Test', + ], + ], + 'quantity' => 1, + ], + ], + 'cancel_url' => $cancelUrl.'?redirect='.array_get($data, 'cancelPage'), + 'success_url' => $successUrl, + 'mode' => 'payment', + 'metadata' => [ + 'order_id' => $order->order_id, + ], + ]; + + $this->fireSystemEvent('payregister.stripecheckout.extendFields', [&$fields, $order, $data]); + + return $fields; + } + + public function processWebhookUrl() + { + if (strtolower(request()->method()) !== 'post') + return response('Request method must be POST', 400); + + $payload = json_decode(request()->getContent(), true); + if (!isset($payload['type']) || !strlen($eventType = $payload['type'])) + return response('Missing webhook event name', 400); + + $eventName = Str::studly(str_replace('.', '_', $eventType)); + $methodName = 'webhookHandle'.$eventName; + + if (method_exists($this, $methodName)) + $this->$methodName($payload); + + Event::fire('payregister.stripecheckout.webhook.handle'.$eventName, [$payload]); + + return response('Webhook Handled'); + } + + protected function webhookHandleCheckoutSessionCompleted($payload) + { + if ($order = Orders_model::find($payload['data']['object']['metadata']['order_id'])) { + if (!$order->isPaymentProcessed()) { + if ($payload['data']['object']['status'] === 'requires_capture') { + $order->logPaymentAttempt('Payment authorized', 1, [], $payload['data']['object']); + } else { + $order->logPaymentAttempt('Payment successful', 1, [], $payload['data']['object'], true); + } + + $order->updateOrderStatus($this->model->order_status, ['notify' => false]); + $order->markAsPaymentProcessed(); + } + } + } +} diff --git a/payments/stripecheckout/fields.php b/payments/stripecheckout/fields.php new file mode 100644 index 0000000..55d0fbf --- /dev/null +++ b/payments/stripecheckout/fields.php @@ -0,0 +1,118 @@ + [ + 'setup' => [ + 'type' => 'partial', + 'path' => '$/igniter/payregister/payments/stripecheckout/info', + ], + 'transaction_mode' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_transaction_mode', + 'type' => 'radiotoggle', + 'default' => 'test', + 'span' => 'left', + 'options' => [ + 'live' => 'lang:igniter.payregister::default.stripecheckout.text_live', + 'test' => 'lang:igniter.payregister::default.stripecheckout.text_test', + ], + ], + 'transaction_type' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_transaction_type', + 'type' => 'radiotoggle', + 'default' => 'auth_capture', + 'span' => 'right', + 'options' => [ + 'auth_capture' => 'lang:igniter.payregister::default.stripecheckout.text_auth_capture', + 'auth_only' => 'lang:igniter.payregister::default.stripecheckout.text_auth_only', + ], + ], + 'live_secret_key' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_live_secret_key', + 'type' => 'text', + 'span' => 'left', + 'trigger' => [ + 'action' => 'show', + 'field' => 'transaction_mode', + 'condition' => 'value[live]', + ], + ], + 'live_publishable_key' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_live_publishable_key', + 'type' => 'text', + 'span' => 'right', + 'trigger' => [ + 'action' => 'show', + 'field' => 'transaction_mode', + 'condition' => 'value[live]', + ], + ], + 'test_secret_key' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_test_secret_key', + 'type' => 'text', + 'span' => 'left', + 'trigger' => [ + 'action' => 'show', + 'field' => 'transaction_mode', + 'condition' => 'value[test]', + ], + ], + 'test_publishable_key' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_test_publishable_key', + 'type' => 'text', + 'span' => 'right', + 'trigger' => [ + 'action' => 'show', + 'field' => 'transaction_mode', + 'condition' => 'value[test]', + ], + ], + 'locale_code' => [ + 'label' => 'lang:igniter.payregister::default.stripecheckout.label_locale_code', + 'type' => 'text', + 'span' => 'left', + ], + 'order_fee_type' => [ + 'label' => 'lang:igniter.payregister::default.label_order_fee_type', + 'type' => 'radiotoggle', + 'span' => 'right', + 'cssClass' => 'flex-width', + 'default' => 1, + 'options' => [ + 1 => 'lang:admin::lang.menus.text_fixed_amount', + 2 => 'lang:admin::lang.menus.text_percentage', + ], + ], + 'order_fee' => [ + 'label' => 'lang:igniter.payregister::default.label_order_fee', + 'type' => 'currency', + 'span' => 'right', + 'cssClass' => 'flex-width', + 'default' => 0, + 'comment' => 'lang:igniter.payregister::default.help_order_fee', + ], + 'order_total' => [ + 'label' => 'lang:igniter.payregister::default.label_order_total', + 'type' => 'currency', + 'span' => 'left', + 'comment' => 'lang:igniter.payregister::default.help_order_total', + ], + 'order_status' => [ + 'label' => 'lang:igniter.payregister::default.label_order_status', + 'type' => 'select', + 'options' => [\Admin\Models\Statuses_model::class, 'getDropdownOptionsForOrder'], + 'span' => 'right', + 'comment' => 'lang:igniter.payregister::default.help_order_status', + ], + ], + 'rules' => [ + ['transaction_mode', 'lang:igniter.payregister::default.stripecheckout.label_transaction_mode', 'string'], + ['live_secret_key', 'lang:igniter.payregister::default.stripecheckout.label_live_secret_key', 'string'], + ['live_publishable_key', 'lang:igniter.payregister::default.stripecheckout.label_live_publishable_key', 'string'], + ['test_secret_key', 'lang:igniter.payregister::default.stripecheckout.label_test_secret_key', 'string'], + ['test_publishable_key', 'lang:igniter.payregister::default.stripecheckout.label_test_publishable_key', 'string'], + ['order_fee_type', 'lang:igniter.payregister::default.label_order_fee_type', 'integer'], + ['order_fee', 'lang:igniter.payregister::default.label_order_fee', 'numeric'], + ['order_total', 'lang:igniter.payregister::default.label_order_total', 'numeric'], + ['order_status', 'lang:igniter.payregister::default.label_order_status', 'integer'], + ], +]; diff --git a/payments/stripecheckout/info.blade.php b/payments/stripecheckout/info.blade.php new file mode 100644 index 0000000..467a858 --- /dev/null +++ b/payments/stripecheckout/info.blade.php @@ -0,0 +1,11 @@ +
+
Configure Webhook
+
+ You can configure the webhook url + + in your Stripe Dashboard > Developers > Webhooks +
+
diff --git a/payments/stripecheckout/payment_form.blade.php b/payments/stripecheckout/payment_form.blade.php new file mode 100644 index 0000000..e69de29 From b84d3c5e051457793ad7b1e1cbae0a1875022ac8 Mon Sep 17 00:00:00 2001 From: Philip Date: Wed, 7 Sep 2022 15:03:58 +0000 Subject: [PATCH 2/6] better workaround: stripe checkout different fixed webhook url --- payments/Stripe.php | 2 +- payments/StripeCheckout.php | 2 +- payments/stripecheckout/info.blade.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/payments/Stripe.php b/payments/Stripe.php index 048ee75..f7ddebb 100644 --- a/payments/Stripe.php +++ b/payments/Stripe.php @@ -23,7 +23,7 @@ class Stripe extends BasePaymentGateway public function registerEntryPoints() { return [ - // 'stripe_webhook' => 'processWebhookUrl', + 'stripe_webhook' => 'processWebhookUrl', ]; } diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php index c5bcc2e..f8d7137 100644 --- a/payments/StripeCheckout.php +++ b/payments/StripeCheckout.php @@ -21,7 +21,7 @@ class StripeCheckout extends BasePaymentGateway public function registerEntryPoints() { return [ - 'stripe_webhook' => 'processWebhookUrl', + 'stripe_checkout_webhook' => 'processWebhookUrl', 'stripe_checkout_return_url' => 'processSuccessUrl', 'stripe_checkout_cancel_url' => 'processCancelUrl', ]; diff --git a/payments/stripecheckout/info.blade.php b/payments/stripecheckout/info.blade.php index 467a858..57cf352 100644 --- a/payments/stripecheckout/info.blade.php +++ b/payments/stripecheckout/info.blade.php @@ -2,7 +2,7 @@
Configure Webhook
You can configure the webhook url - + in your Date: Wed, 7 Sep 2022 23:30:08 +0000 Subject: [PATCH 3/6] Change item title and add customer email to stripe checkout session --- payments/StripeCheckout.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php index f8d7137..04b1b1e 100644 --- a/payments/StripeCheckout.php +++ b/payments/StripeCheckout.php @@ -165,7 +165,7 @@ protected function getPaymentFormFields($order, $data = []) // All amounts sent to Stripe must be in integers, representing the lowest currency unit (cents) 'unit_amount_decimal' => number_format($order->order_total, 2, '.', '') * 100, 'product_data' => [ - 'name' => 'Test', + 'name' => 'Meals', ], ], 'quantity' => 1, @@ -177,6 +177,7 @@ protected function getPaymentFormFields($order, $data = []) 'metadata' => [ 'order_id' => $order->order_id, ], + 'customer_email' => array_get($data, 'email'), ]; $this->fireSystemEvent('payregister.stripecheckout.extendFields', [&$fields, $order, $data]); From 01b6e77ea0881501b2e20472c9a7654f0a48fde3 Mon Sep 17 00:00:00 2001 From: Philip Date: Thu, 15 Sep 2022 20:44:24 +0000 Subject: [PATCH 4/6] fix: cannot send stripe a valid email from existing customer --- payments/StripeCheckout.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php index 04b1b1e..3fa5321 100644 --- a/payments/StripeCheckout.php +++ b/payments/StripeCheckout.php @@ -177,9 +177,19 @@ protected function getPaymentFormFields($order, $data = []) 'metadata' => [ 'order_id' => $order->order_id, ], - 'customer_email' => array_get($data, 'email'), ]; + + // Share the email field in our form to Stripe checkout session, + // so customers don't need to enter twice + if (!is_null(array_get($data, 'email'))) { + // if is unregistered customer + $fields['customer_email'] = array_get($data, 'email'); + } elseif (!is_null($order->customer) && !is_null($order->customer->email)) { + // else if is registered, get email from customer profile + $fields['customer_email'] = $order->customer->email; + } + $this->fireSystemEvent('payregister.stripecheckout.extendFields', [&$fields, $order, $data]); return $fields; From da5d9c8465f2f99d8222ed42cd115459bc5e7d7e Mon Sep 17 00:00:00 2001 From: Philip Date: Fri, 16 Sep 2022 20:44:40 +0000 Subject: [PATCH 5/6] Enable stripecheckout refund --- payments/StripeCheckout.php | 73 +++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php index 3fa5321..6533353 100644 --- a/payments/StripeCheckout.php +++ b/payments/StripeCheckout.php @@ -98,7 +98,8 @@ public function processSuccessUrl($params) if (!$paymentMethod || $paymentMethod->getGatewayClass() != static::class) throw new ApplicationException('No valid payment method found'); - $order->logPaymentAttempt('Payment successful', 1, [], $paymentMethod, true); + // Don't have detailed payment info, not refundable. + $order->logPaymentAttempt('Payment successful (not final)', 1, [], $paymentMethod, true); $order->updateOrderStatus($paymentMethod->order_status, ['notify' => false]); $order->markAsPaymentProcessed(); @@ -151,6 +152,58 @@ protected function createGateway() return $stripeClient; } + protected function getPaymentRefundFields($order, $data) + { + $fields = []; + + $eventResult = $this->fireSystemEvent('payregister.stripe.extendRefundFields', [$fields, $order, $data], false); + if (is_array($eventResult)) + $fields = array_merge($fields, ...$eventResult); + + return $fields; + } + + public function processRefundForm($data, $order, $paymentLog) + { + if (!is_null($paymentLog->refunded_at) || !is_array($paymentLog->response)) + throw new ApplicationException('Nothing to refund'); + + if (!array_get($paymentLog->response, 'status') === 'succeeded' + || !array_get($paymentLog->response, 'object') === 'payment_intent' + ) throw new ApplicationException('No charge to refund'); + + $paymentIntentId = array_get($paymentLog->response, 'payment_intent'); + $refundAmount = array_get($data, 'refund_type') == 'full' + ? $order->order_total : array_get($data, 'refund_amount'); + + if ($refundAmount > $order->order_total) + throw new ApplicationException('Refund amount should be be less than total'); + + try { + $gateway = $this->createGateway(); + $fields = $this->getPaymentRefundFields($order, $data); + $response = $gateway->refunds->create(array_merge($fields, [ + 'payment_intent' => $paymentIntentId, + 'amount' => number_format($refundAmount, 2, '', ''), + ])); + + if ($response->status === 'failed') + throw new Exception('Refund failed'); + + $message = sprintf('Payment intent %s refunded successfully -> (%s: %s)', + $paymentIntentId, + currency_format($refundAmount), + array_get($response->toArray(), 'refunds.data.0.id') + ); + + $order->logPaymentAttempt($message, 1, $fields, $response->toArray()); + $paymentLog->markAsRefundProcessed(); + } + catch (Exception $e) { + $order->logPaymentAttempt('Refund failed -> '.$response->getMessage(), 0, $fields, $response->toArray()); + } + } + protected function getPaymentFormFields($order, $data = []) { $cancelUrl = $this->makeEntryPointUrl('stripe_checkout_cancel_url').'/'.$order->hash; @@ -179,7 +232,6 @@ protected function getPaymentFormFields($order, $data = []) ], ]; - // Share the email field in our form to Stripe checkout session, // so customers don't need to enter twice if (!is_null(array_get($data, 'email'))) { @@ -218,16 +270,15 @@ public function processWebhookUrl() protected function webhookHandleCheckoutSessionCompleted($payload) { if ($order = Orders_model::find($payload['data']['object']['metadata']['order_id'])) { - if (!$order->isPaymentProcessed()) { - if ($payload['data']['object']['status'] === 'requires_capture') { - $order->logPaymentAttempt('Payment authorized', 1, [], $payload['data']['object']); - } else { - $order->logPaymentAttempt('Payment successful', 1, [], $payload['data']['object'], true); - } - - $order->updateOrderStatus($this->model->order_status, ['notify' => false]); - $order->markAsPaymentProcessed(); + if ($payload['data']['object']['status'] === 'requires_capture') { + $order->logPaymentAttempt('Payment authorized', 1, [], $payload['data']['object']); + } else { + // Have detailed payment info, refundable. + $order->logPaymentAttempt('Payment confirmed (Finalized, Refundable)', 1, [], $payload['data']['object'], true); } + + $order->updateOrderStatus($this->model->order_status, ['notify' => false]); + $order->markAsPaymentProcessed(); } } } From 76130b8de974a036bd0db65eb6188603844e4632 Mon Sep 17 00:00:00 2001 From: Philip Date: Sun, 26 Feb 2023 20:52:38 +0000 Subject: [PATCH 6/6] Support auth only and capture --- payments/StripeCheckout.php | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/payments/StripeCheckout.php b/payments/StripeCheckout.php index 6533353..89e556b 100644 --- a/payments/StripeCheckout.php +++ b/payments/StripeCheckout.php @@ -51,6 +51,55 @@ public function isApplicable($total, $host) { return $host->order_total <= $total; } + + public function capturePaymentIntent($paymentIntentId, $order, $data = []) + { + if ($order->payment !== $this->model->code) + return; + + try { + $response = $this->createGateway()->paymentIntents->capture( + $paymentIntentId, + $data, + ); + + if ($response->status == 'succeeded') { + $order->logPaymentAttempt('Payment captured successfully', 1, $data, $response); + } + else { + $order->logPaymentAttempt('Payment captured failed', 0, $data, $response); + } + + return $response; + } + catch (Exception $ex) { + $order->logPaymentAttempt('Payment capture failed -> '.$ex->getMessage(), 0, $data, $response); + } + } + + public function cancelPaymentIntent($paymentIntentId, $order, $data = []) + { + if ($order->payment !== $this->model->code) + return; + + try { + $response = $this->createGateway()->paymentIntents->cancel( + $paymentIntentId, $data + ); + + if ($response->status == 'canceled') { + $order->logPaymentAttempt('Payment canceled successfully', 1, $data, $response); + } + else { + $order->logPaymentAttempt('Payment canceled failed', 0, $data, $response); + } + + return $response; + } + catch (Exception $ex) { + $order->logPaymentAttempt('Payment canceled failed -> '.$ex->getMessage(), 0, $data, $response); + } + } /** * @param array $data @@ -230,6 +279,9 @@ protected function getPaymentFormFields($order, $data = []) 'metadata' => [ 'order_id' => $order->order_id, ], + 'payment_intent_data' => [ + 'capture_method' => $this->shouldAuthorizePayment() ? 'manual' : 'automatic', + ], ]; // Share the email field in our form to Stripe checkout session,