PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 All 51 releases
← All changes | app/Modules/PaymentMethods/StripeGateway/Stripe.php +60 -29 1.6.1 → 1.7.1 View file →
@@ -28,9 +28,9 @@
28 28 private $methodSlug = 'stripe';
29 29
30 30 public array $supportedFeatures = ['payment', 'refund', 'webhook', 'custom_payment', 'card_update', 'switch_payment_method' => [
31 31 'supported_gateways' => ['stripe', 'paypal'],
32 - ], 'dispute_handler', 'subscriptions', 'zero_recurring', 'system_subscription', 'manual_subscription'];
32 + ], 'dispute_handler', 'subscriptions', 'zero_recurring', 'system_subscription', 'manual_subscription', 'verify_vendor_ids'];
33 33
34 34 public BaseGatewaySettings $settings;
35 35
36 36 public function __construct()
@@ -55,9 +55,9 @@
55 55
56 56 public function meta(): array
57 57 {
58 58 return [
59 - 'title' => 'Card',
59 + 'title' => __('Card', 'fluent-cart'),
60 60 'route' => 'stripe',
61 61 'slug' => 'stripe',
62 62 'label' => 'Stripe',
63 63 'admin_title' => 'Stripe',
@@ -89,9 +89,11 @@
89 89 'amount' => $chargeAmount,
90 90 'currency' => strtolower($transactionCurrency),
91 91 'description' => $storeName . ' #' . $order->invoice_no, // @todo: We will replace with order summary with item names later
92 92 'customer_email' => $paymentInstance->order->email,
93 - 'success_url' => $this->getSuccessUrl($paymentInstance->transaction),
93 + 'success_url' => $paymentInstance->transaction->getSuccessUrl(),
94 + 'gateway_return_url' => Processor::getOnsiteGatewayReturnUrl($paymentInstance->transaction),
95 + 'trx_hash' => $paymentInstance->transaction->uuid,
94 96 'custom_payment_url' => PaymentHelper::getCustomPaymentLink($paymentInstance->order->uuid)
95 97 );
96 98
97 99 if ($paymentInstance->subscription) {
@@ -254,9 +256,9 @@
254 256
255 257 $attempt = max(1, (int) Arr::get($args, 'attempt', 1));
256 258
257 259 $intent = (new API())->createStripeObject('payment_intents', $intentData, $order->mode, [
258 - 'Idempotency-Key' => 'fct_system_charge_' . $order->id . '_' . $attempt,
260 + 'Idempotency-Key' => 'fct_system_charge_' . $order->uuid . '_' . $attempt,
259 261 ]);
260 262
261 263 if (is_wp_error($intent)) {
262 264 return $intent;
@@ -479,8 +481,11 @@
479 481 'redirecting for action' => __('redirecting for action', 'fluent-cart'),
480 482 'You will be redirected to Stripe to complete your payment securely.' => __('You will be redirected to Stripe to complete your payment securely.', 'fluent-cart'),
481 483 'Something went wrong' => __('Something went wrong', 'fluent-cart'),
482 484 'Payment confirmation failed' => __('Payment confirmation failed', 'fluent-cart'),
485 + 'Payment failed. Please try again.' => __('Payment failed. Please try again.', 'fluent-cart'),
486 + 'We could not record that failed attempt. Please reload the page before trying again.' => __('We could not record that failed attempt. Please reload the page before trying again.', 'fluent-cart'),
487 + 'We could not verify your payment status. Please do not pay again. Contact the store to check your order status.' => __('We could not verify your payment status. Please do not pay again. Contact the store to check your order status.', 'fluent-cart'),
483 488 ]
484 489 ]
485 490 ];
486 491 }
@@ -578,9 +583,9 @@
578 583 }
579 584
580 585 public function fields(): array
581 586 {
582 - $disabled = apply_filters_deprecated('fluent_cart_form_disable_stripe_connect', [false, []], '1.3.16', 'fluent_cart/form_disable_stripe_connect', 'Use fluent_cart/form_disable_stripe_connect instead of fluent_cart_form_disable_stripe_connect. It will be removed in v1.4.3.');
587 + $disabled = false;
583 588 $providerValue = apply_filters('fluent_cart/form_disable_stripe_connect', $disabled, []) ? 'api_keys' : 'connect';
584 589
585 590 return array(
586 591 'notice' => [
@@ -634,8 +639,23 @@
634 639 ],
635 640 'tooltip' => __('Choose between Embedded and Hosted checkout modes. Embedded mode is recommended for most use cases. For Bank transfers, use Hosted mode. (checkout.session.completed webhook event will be triggered only for hosted mode)', 'fluent-cart'),
636 641 'description' => __("Embedded checkout is recommended for most use cases. For Bank transfers , or if any payment methods are not showing up on embedded checkout, try Hosted checkout. ('checkout.session.completed' webhook event will be triggered only for hosted checkout)", 'fluent-cart')
637 642 ),
643 + 'submit_type' => array(
644 + 'value' => 'auto',
645 + 'label' => __('Submit Button Label', 'fluent-cart'),
646 + 'type' => 'select',
647 + 'filterable' => false,
648 + 'options' => [
649 + ['value' => 'auto', 'label' => __('Automatic (Pay / Subscribe)', 'fluent-cart')],
650 + ['value' => 'pay', 'label' => __('Pay', 'fluent-cart')],
651 + ['value' => 'book', 'label' => __('Book', 'fluent-cart')],
652 + ['value' => 'donate', 'label' => __('Donate', 'fluent-cart')],
653 + ['value' => 'subscribe', 'label' => __('Subscribe', 'fluent-cart')],
654 + ],
655 + 'tooltip' => __('Stripe customises the submit button and surrounding copy from this. Applies to Stripe Hosted Checkout only.', 'fluent-cart'),
656 + 'description' => __('Applies to Stripe Hosted Checkout only, and is ignored when a card is being saved without a charge. Automatic gives one-time orders the "Buy" button and subscriptions the "Subscribe" button.', 'fluent-cart')
657 + ),
638 658 'webhook_desc' => array(
639 659 'value' => Webhook::webhookInstruction(),
640 660 'label' => __('Webhook URL', 'fluent-cart'),
641 661 'type' => 'html_attr'
@@ -788,15 +808,11 @@
788 808 ], 422);
789 809 }
790 810
791 811 $paymentArgs['public_key'] = $publicKey;
812 + $appearance = $this->getElementsAppearance();
813 + $fonts = $this->getElementsFonts();
792 814
793 - // Allow filtering the appearance configuration for Stripe Elements
794 - $appearance = apply_filters_deprecated('fluent_cart_stripe_appearance', [
795 - ['theme' => 'stripe']
796 - ], '1.3.16', 'fluent_cart/stripe_appearance', 'Use fluent_cart/stripe_appearance instead of fluent_cart_stripe_appearance. It will be removed in v1.4.3.');
797 - $appearance = apply_filters('fluent_cart/stripe_appearance', $appearance);
798 -
799 815 $storeCurrency = CurrencySettings::get('currency');
800 816 $intentAmount = (int)$totalPrice;
801 817
802 818 if ($storeCurrency && CurrenciesHelper::isZeroDecimal($storeCurrency)) {
@@ -827,11 +843,13 @@
827 843 // mode — a zero-amount payment mode is invalid — and consent becomes a
828 844 // required checkbox: without a saved card the trial can never bill.
829 845 $payableNow = \FluentCart\App\Services\OrderService::getItemsAmountTotal($cart->cart_data ?? [], false, false);
830 846 if ($payableNow <= 0) {
847 + // Match the SetupIntent usage even when the optional save-card flag is set.
831 848 $intentData = [
832 - 'mode' => 'setup',
833 - 'currency' => strtolower($storeCurrency),
849 + 'mode' => 'setup',
850 + 'currency' => strtolower($storeCurrency),
851 + 'setup_future_usage' => 'off_session',
834 852 ];
835 853 $consentRequired = true;
836 854 }
837 855 }
@@ -842,22 +860,20 @@
842 860 } elseif (empty($intentData['setup_future_usage']) && Arr::get($data, 'save_payment_method') === 'yes') {
843 861 $intentData['setup_future_usage'] = 'on_session';
844 862 }
845 863
846 - // The browser cannot pass setup_future_usage per-request (this endpoint
847 - // receives no body), so extensions that vault cards (e.g. saved payment
848 - // methods) resolve it here, server-side. Must be matched on the actual
849 - // PaymentIntent at place-order (fluent_cart/payments/stripe_onetime_intent_args)
850 - // or Stripe rejects the confirmation for a setup_future_usage mismatch.
851 - $setupFutureUsage = apply_filters(
852 - 'fluent_cart/stripe/client_setup_future_usage',
853 - Arr::get($intentData, 'setup_future_usage'),
854 - ['data' => $data, 'has_subscription' => $hasSubscription]
855 - );
856 - if ($setupFutureUsage) {
857 - $intentData['setup_future_usage'] = $setupFutureUsage;
858 - } else {
859 - unset($intentData['setup_future_usage']);
864 + // a one-time payment may be changed here.
865 + if ($intentData['mode'] === 'payment') {
866 + $setupFutureUsage = apply_filters(
867 + 'fluent_cart/stripe/client_setup_future_usage',
868 + Arr::get($intentData, 'setup_future_usage'),
869 + ['data' => $data, 'has_subscription' => $hasSubscription]
870 + );
871 + if ($setupFutureUsage) {
872 + $intentData['setup_future_usage'] = $setupFutureUsage;
873 + } else {
874 + unset($intentData['setup_future_usage']);
875 + }
860 876 }
861 877
862 878 wp_send_json(
863 879 [
@@ -866,8 +882,9 @@
866 882 'data' => [],
867 883 'payment_args' => $paymentArgs,
868 884 'intent' => $intentData,
869 885 'appearance' => $appearance,
886 + 'fonts' => $fonts,
870 887 'system_consent' => $systemConsent,
871 888 'consent_required' => $consentRequired,
872 889 ],
873 890 200
@@ -873,8 +890,22 @@
873 890 200
874 891 );
875 892 }
876 893
894 + public function getElementsAppearance(): array
895 + {
896 + $appearance = ['theme' => 'stripe'];
897 +
898 + return (array) apply_filters('fluent_cart/stripe_appearance', $appearance);
899 + }
900 +
901 + public function getElementsFonts(): array
902 + {
903 + $fonts = (array) apply_filters('fluent_cart/stripe_elements_fonts', []);
904 +
905 + return array_values(array_filter($fonts, 'is_array'));
906 + }
907 +
877 908 public function getConnectInfo(): array
878 909 {
879 910 return ConnectConfig::getConnectConfig();
880 911 }
@@ -896,9 +927,9 @@
896 927 public function acceptRemoteDispute($transaction, $args = [])
897 928 {
898 929 $disputeId = Arr::get($transaction->meta, 'dispute_id');
899 930 if (!$disputeId) {
900 - $charge = (new API())->getStripeObject('payment_intents/' . $transaction->vendor_charge_id, ['expand' => ['latest_charge']]);
931 + $charge = (new API())->getStripeObject('payment_intents/' . $transaction->vendor_charge_id, ['expand' => ['latest_charge']], $transaction->payment_mode);
901 932
902 933 if (is_wp_error($charge) || empty($charge['dispute'])) {
903 934 new \WP_Error('No dispute ID found!', __('Please check stripe if the dispute is already accepted or not!', 'fluent-cart'));
904 935 }
@@ -905,9 +936,9 @@
905 936
906 937 $disputeId = Arr::get($charge, 'dispute', '');
907 938 }
908 939
909 - $closeDispute = (new API())->createStripeObject('disputes/' . $disputeId . '/close');
940 + $closeDispute = (new API())->createStripeObject('disputes/' . $disputeId . '/close', [], $transaction->payment_mode);
910 941
911 942 if (is_wp_error($closeDispute)) {
912 943 return $closeDispute;
913 944 }