Skip to content

Commit a931019

Browse files
wjrosaMayisha
andauthored
Moving OC card method logic to the new OC payment method class (#4579)
* Removing card requirement for OC * Backend changes * Backend changes * Changelog and readme entries * Fix tests * Fix tests * unit test * Fix tests * Fix shortcode checkout methods display * Moving OC card method logic to the new single method class * Removing unnecessary condition * Condition is actually necessary * Fix shortcode container label * Moving some methods * Additional fixes * Fix add payment method title * Adding specific frontend constant to avoid confusion * Renaming class to OC * Improving docs * Removing disabledButChecked prop and related code * Removing the required for OC pill and related files * Renaming Single to OC * Fix tests * Unit test * Changelog and readme entries * Hide OC container when there are no methods available * Fix merge * Fix tests * Fix express methods not available * Removing unnecessary import * Fix payment method unavailable * Fix payment method unavailable * Fix method ID * Removing unnecessary changes * Revert unnecessary changes * Simplifying logic * Simplifying logic * Fix payment method title * Revert unnecessary change * Flagging infinity loop line * Fix infinity loop * Removing unnecessary constant * Simplifying logic * Fix instructions * Improving readability * Improving readability * Improving readability * Update changelog.txt Co-authored-by: Mayisha <[email protected]> * Changelog and readme entries * Fix invalid intent log when intent data is missing * Fix selected payment method type * Revert order lock changes * Fix methods availability * Update includes/class-wc-stripe-helper.php Co-authored-by: Mayisha <[email protected]> * Removing unnecessary LPM_GATEWAY_CLASS constnat * Update doc blocks * Fix methods availability at the shortcode checkout * Fix ECE methods title * Fix payment intent amount comparison * Fix Link availability in the block checkout * UI update * Adding call to parent is_available method --------- Co-authored-by: Mayisha <[email protected]>
1 parent e29a8ac commit a931019

13 files changed

+301
-137
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*** Changelog ***
22

33
= 9.9.0 - xxxx-xx-xx =
4+
* Dev - Extracts Optimized Checkout logic from card payment method into new WC_Stripe_UPE_Payment_Method_OC class
45
* Fix - The availability of the Link payment method when the Optimized Checkout is enabled
56
* Dev - Update Javascript unit tests for compatibility with Node 20
67
* Dev - Replaces some payment method instantiation logic for the Optimized Checkout with calls to the `get_payment_method_instance` method

client/settings/payment-request-section/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ const PaymentRequestSection = () => {
104104
<li className="express-checkout">
105105
<div>
106106
{ __(
107-
'Credit card / debit card must be enabled as a payment method in order to use Google Pay and Apple Pay.',
107+
'Credit card / debit card must be enabled as a payment method in order to use Google Pay and Apple Pay (and Link in the classic checkout).',
108108
'woocommerce-gateway-stripe'
109109
) }
110110
</div>

includes/class-wc-stripe-helper.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,11 +1949,13 @@ public static function validate_intent_for_order( $order, $intent, ?string $sele
19491949
$order_currency = strtolower( $order->get_currency() );
19501950
$order_amount = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $order->get_currency() );
19511951
$order_intent_id = self::get_intent_id_from_order( $order );
1952+
$intent_currency = isset( $intent->currency ) ? strtolower( $intent->currency ) : null;
1953+
$intent_amount = isset( $intent->amount ) ? (int) $intent->amount : null;
19521954

19531955
if ( 'payment_intent' === $intent->object ) {
1954-
$is_valid = $order_currency === $intent->currency
1956+
$is_valid = $order_currency === $intent_currency
19551957
&& $is_valid_payment_type
1956-
&& $order_amount === $intent->amount
1958+
&& $order_amount === $intent_amount
19571959
&& ( ! $order_intent_id || $order_intent_id === $intent->id );
19581960
} else {
19591961
// Setup intents don't have an amount or currency.
@@ -1968,12 +1970,12 @@ public static function validate_intent_for_order( $order, $intent, ?string $sele
19681970

19691971
$permitted_payment_types = implode( '/', $intent->payment_method_types );
19701972
WC_Stripe_Logger::critical(
1971-
"Error: Invalid payment intent for order. Intent: {$intent->currency} {$intent->amount} via {$permitted_payment_types}, Order: {$order_currency} {$order_amount} {$selected_payment_type}",
1973+
"Error: Invalid payment intent for order. Intent: {$intent_currency} {$intent_amount} via {$permitted_payment_types}, Order: {$order_currency} {$order_amount} {$selected_payment_type}",
19721974
[
19731975
'order_id' => $order->get_id(),
19741976
'intent_id' => $intent->id,
1975-
'intent_currency' => $intent->currency,
1976-
'intent_amount' => $intent->amount,
1977+
'intent_currency' => $intent_currency,
1978+
'intent_amount' => $intent_amount,
19771979
'intent_payment_method_types' => $intent->payment_method_types,
19781980
'selected_payment_type' => $selected_payment_type,
19791981
'order_currency' => $order->get_currency(),

includes/class-wc-stripe.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ public function init() {
182182
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-wechat-pay.php';
183183
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-acss.php';
184184
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-amazon-pay.php';
185+
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-oc.php';
185186
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-bancontact.php';
186187
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-sofort.php';
187188
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-giropay.php';

includes/constants/class-wc-stripe-payment-methods.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class WC_Stripe_Payment_Methods {
3333
const SEPA_DEBIT = 'sepa_debit';
3434
const SOFORT = 'sofort';
3535
const WECHAT_PAY = 'wechat_pay';
36+
const OC = 'card'; // This is a special case for the Optimized Checkout
3637

3738
// Express method constants
3839
const AMAZON_PAY = 'amazon_pay';

includes/payment-methods/class-wc-stripe-upe-payment-gateway.php

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -614,19 +614,23 @@ private function get_enabled_payment_method_config() {
614614
$settings = [];
615615

616616
$enabled_payment_methods = $this->get_upe_enabled_at_checkout_payment_method_ids();
617+
$original_method_ids = $enabled_payment_methods; // For OC, keep the original methods to control availability
618+
$payment_methods = $this->payment_methods;
617619

618620
// If the Optimized Checkout is enabled, we need to return just the card payment method + express methods.
619621
// All payment methods are rendered inside the card container.
620622
if ( $this->oc_enabled ) {
623+
$oc_method_id = WC_Stripe_UPE_Payment_Method_OC::STRIPE_ID;
621624
$enabled_express_methods = array_intersect(
622625
$enabled_payment_methods,
623626
WC_Stripe_Payment_Methods::EXPRESS_PAYMENT_METHODS
624627
);
625-
$enabled_payment_methods = array_merge( [ WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID ], $enabled_express_methods );
628+
$enabled_payment_methods = array_merge( [ $oc_method_id ], $enabled_express_methods );
629+
$payment_methods[ $oc_method_id ] = new WC_Stripe_UPE_Payment_Method_OC();
626630
}
627631

628632
foreach ( $enabled_payment_methods as $payment_method_id ) {
629-
$payment_method = $this->payment_methods[ $payment_method_id ];
633+
$payment_method = $payment_methods[ $payment_method_id ];
630634

631635
$settings[ $payment_method_id ] = [
632636
'isReusable' => $payment_method->is_reusable(),
@@ -636,7 +640,7 @@ private function get_enabled_payment_method_config() {
636640
'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ),
637641
'supportsDeferredIntent' => $payment_method->supports_deferred_intent(),
638642
'countries' => $payment_method->get_available_billing_countries(),
639-
'enabledPaymentMethods' => $this->get_upe_enabled_payment_method_ids(), // For the Optimized Checkout.
643+
'enabledPaymentMethods' => $original_method_ids,
640644
];
641645
}
642646

@@ -2030,19 +2034,26 @@ public function is_oc_enabled() {
20302034
* @version 5.5.0
20312035
*/
20322036
public function set_payment_method_title_for_order( $order, $payment_method_type, $stripe_payment_method = false ) {
2033-
if ( ! isset( $this->payment_methods[ $payment_method_type ] ) ) {
2037+
$payment_methods = $this->payment_methods;
2038+
2039+
// Override the payment method type if the Optimized Checkout is enabled.
2040+
if ( $this->oc_enabled && WC_Stripe_Payment_Methods::OC === $payment_method_type ) {
2041+
$payment_methods[ WC_Stripe_Payment_Methods::OC ] = new WC_Stripe_UPE_Payment_Method_OC();
2042+
}
2043+
2044+
if ( ! isset( $payment_methods[ $payment_method_type ] ) ) {
20342045
return;
20352046
}
20362047

2037-
$payment_method = $this->payment_methods[ $payment_method_type ];
2048+
$payment_method = $payment_methods[ $payment_method_type ];
20382049
$payment_method_id = $payment_method instanceof WC_Stripe_UPE_Payment_Method_CC ? $this->id : $payment_method->id;
20392050
$is_stripe_link = WC_Stripe_Payment_Methods::LINK === $payment_method_type ||
20402051
( isset( $stripe_payment_method->type ) && WC_Stripe_Payment_Methods::LINK === $stripe_payment_method->type );
20412052

20422053
// Stripe Link uses the main gateway to process payments, however Link payments should use the title of the Link payment method.
2043-
if ( $is_stripe_link && isset( $this->payment_methods[ WC_Stripe_Payment_Methods::LINK ] ) ) {
2054+
if ( $is_stripe_link && isset( $payment_methods[ WC_Stripe_Payment_Methods::LINK ] ) ) {
20442055
$payment_method_id = $this->id;
2045-
$payment_method_title = $this->payment_methods[ WC_Stripe_Payment_Methods::LINK ]->get_title( $stripe_payment_method );
2056+
$payment_method_title = $payment_methods[ WC_Stripe_Payment_Methods::LINK ]->get_title( $stripe_payment_method );
20462057
} else {
20472058
$payment_method_title = $payment_method->get_title( $stripe_payment_method );
20482059
}
@@ -2485,12 +2496,17 @@ protected function prepare_payment_information_from_request( WC_Order $order ) {
24852496

24862497
$payment_method_details = ! empty( $payment_method_id ) ? WC_Stripe_API::get_payment_method( $payment_method_id ) : (object) [];
24872498

2488-
$payment_method_types = $this->get_payment_method_types_for_intent_creation(
2489-
$selected_payment_type,
2490-
$order->get_id(),
2491-
$this->get_express_payment_type_from_request(),
2492-
( $payment_method_details->type ?? null )
2493-
);
2499+
// Override the payment method type with the API value when OC is enabled
2500+
if ( $this->oc_enabled ) {
2501+
$selected_payment_type = $payment_method_details->type ?? null;
2502+
$payment_method_types = [ $selected_payment_type ];
2503+
} else {
2504+
$payment_method_types = $this->get_payment_method_types_for_intent_creation(
2505+
$selected_payment_type,
2506+
$order->get_id(),
2507+
$this->get_express_payment_type_from_request()
2508+
);
2509+
}
24942510

24952511
$payment_information = [
24962512
'amount' => $amount,
@@ -3085,14 +3101,8 @@ private function get_existing_compatible_payment_intent( $order, $payment_method
30853101
private function get_payment_method_types_for_intent_creation(
30863102
string $selected_payment_type,
30873103
int $order_id,
3088-
?string $express_payment_type = null,
3089-
?string $payment_method_type = null
3104+
?string $express_payment_type = null
30903105
): array {
3091-
// If Single Payment Element is enabled, return only the payment method type.
3092-
if ( $this->oc_enabled && ! empty( $payment_method_type ) ) {
3093-
return [ $payment_method_type ];
3094-
}
3095-
30963106
// If the shopper didn't select a payment type, return all the enabled ones.
30973107
if ( '' === $selected_payment_type ) {
30983108
return $this->get_upe_enabled_at_checkout_payment_method_ids( $order_id );

includes/payment-methods/class-wc-stripe-upe-payment-method-cc.php

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ public function get_title( $payment_details = false ) {
4747
return $this->get_card_wallet_type_title( $wallet_type );
4848
}
4949

50-
// Optimized checkout
51-
if ( $this->oc_enabled ) {
52-
return $this->get_optimized_checkout_title( $payment_details );
53-
}
54-
5550
// Default
5651
return parent::get_title();
5752
}
@@ -117,10 +112,6 @@ public function requires_automatic_capture() {
117112
* @return string
118113
*/
119114
public function get_testing_instructions( $show_optimized_checkout_instruction = false ) {
120-
if ( $this->oc_enabled && ! $show_optimized_checkout_instruction ) {
121-
return WC_Stripe_UPE_Payment_Gateway::get_testing_instructions_for_optimized_checkout();
122-
}
123-
124115
return sprintf(
125116
/* translators: 1) HTML strong open tag 2) HTML strong closing tag 3) HTML anchor open tag 2) HTML anchor closing tag */
126117
esc_html__( '%1$sTest mode:%2$s use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed %3$shere%4$s.', 'woocommerce-gateway-stripe' ),
@@ -130,45 +121,4 @@ public function get_testing_instructions( $show_optimized_checkout_instruction =
130121
'</a>'
131122
);
132123
}
133-
134-
/**
135-
* Returns the title for the card wallet type.
136-
* This is used to display the title for Apple Pay and Google Pay.
137-
*
138-
* @param $express_payment_type string The type of express payment method.
139-
*
140-
* @return string The title for the card wallet type.
141-
*/
142-
private function get_card_wallet_type_title( $express_payment_type ) {
143-
$express_payment_titles = WC_Stripe_Payment_Methods::EXPRESS_METHODS_LABELS;
144-
$payment_method_title = $express_payment_titles[ $express_payment_type ] ?? false;
145-
146-
if ( ! $payment_method_title ) {
147-
return parent::get_title();
148-
}
149-
150-
return $payment_method_title . WC_Stripe_Express_Checkout_Helper::get_payment_method_title_suffix();
151-
}
152-
153-
/**
154-
* Returns the title for the optimized checkout.
155-
*
156-
* @param stdClass|array|bool $payment_details Optional payment details from charge object.
157-
* @return string
158-
*/
159-
private function get_optimized_checkout_title( $payment_details = false ) {
160-
if ( $payment_details ) { // Setting title for the order details page / thank you page.
161-
$payment_method = WC_Stripe_UPE_Payment_Gateway::get_payment_method_instance( $payment_details->type );
162-
163-
// Avoid potential recursion by checking instance type. This fixes the title on pay for order confirmation page.
164-
return $payment_method instanceof self ? parent::get_title() : $payment_method->get_title();
165-
}
166-
167-
// Block checkout and pay for order (checkout) page.
168-
if ( ( has_block( 'woocommerce/checkout' ) || ! empty( $_GET['pay_for_order'] ) ) && ! is_wc_endpoint_url( 'order-received' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
169-
return 'Stripe';
170-
}
171-
172-
return parent::get_title();
173-
}
174124
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
if ( ! defined( 'ABSPATH' ) ) {
3+
exit;
4+
}
5+
6+
/**
7+
* Class WC_Stripe_UPE_Payment_Method_OC
8+
*
9+
* This class represents the Stripe UPE payment method for the Optimized Checkout (OC) flow.
10+
*/
11+
class WC_Stripe_UPE_Payment_Method_OC extends WC_Stripe_UPE_Payment_Method {
12+
13+
const STRIPE_ID = WC_Stripe_Payment_Methods::OC;
14+
15+
/**
16+
* Constructor for the Optimized Checkout payment method (which renders all methods).
17+
*/
18+
public function __construct() {
19+
parent::__construct();
20+
$main_settings = WC_Stripe_Helper::get_stripe_settings();
21+
$is_stripe_enabled = ! empty( $main_settings['enabled'] ) && 'yes' === $main_settings['enabled'];
22+
23+
$this->enabled = $is_stripe_enabled && $this->oc_enabled ? 'yes' : 'no';
24+
$this->id = WC_Gateway_Stripe::ID; // Force the ID to be the same as the main payment gateway.
25+
$this->stripe_id = self::STRIPE_ID;
26+
$this->title = 'Stripe';
27+
$this->is_reusable = true;
28+
$this->supports[] = 'subscriptions';
29+
$this->supports[] = 'tokenization';
30+
}
31+
32+
/**
33+
* Returns payment method title
34+
*
35+
* @param stdClass|array|bool $payment_details Optional payment details from charge object.
36+
*
37+
* @return string
38+
*/
39+
public function get_title( $payment_details = false ) {
40+
// Wallet type
41+
$wallet_type = $payment_details->card->wallet->type ?? null;
42+
if ( $wallet_type ) {
43+
return $this->get_card_wallet_type_title( $wallet_type );
44+
}
45+
46+
if ( $payment_details ) { // Setting title for the order details page / thank you page.
47+
$payment_method = WC_Stripe_UPE_Payment_Gateway::get_payment_method_instance( $payment_details->type );
48+
49+
// Avoid potential recursion by checking instance type. This fixes the title on pay for order confirmation page.
50+
return $payment_method instanceof self ? parent::get_title() : $payment_method->get_title();
51+
}
52+
53+
// Block checkout and pay for order (checkout) page.
54+
if ( ( has_block( 'woocommerce/checkout' ) || ! empty( $_GET['pay_for_order'] ) ) && ! is_wc_endpoint_url( 'order-received' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
55+
return 'Stripe';
56+
}
57+
58+
return parent::get_title();
59+
}
60+
61+
/**
62+
* Returns true if the UPE method is available.
63+
*
64+
* @inheritDoc
65+
*/
66+
public function is_available() {
67+
if ( ! parent::is_available() ) {
68+
return false;
69+
}
70+
71+
return true;
72+
}
73+
74+
/**
75+
* Returns string representing payment method type
76+
* to query to retrieve saved payment methods from Stripe.
77+
*
78+
* @inheritDoc
79+
*/
80+
public function get_retrievable_type() {
81+
return WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID;
82+
}
83+
84+
/**
85+
* Returns boolean dependent on whether capability
86+
* for site account is enabled for payment method.
87+
*
88+
* @inheritDoc
89+
*/
90+
public function is_capability_active() {
91+
return true;
92+
}
93+
94+
/**
95+
* The Optimized Checkout method allows automatic capture.
96+
*
97+
* @inheritDoc
98+
*/
99+
public function requires_automatic_capture() {
100+
return false;
101+
}
102+
103+
/**
104+
* Returns testing credentials to be printed at checkout in test mode.
105+
*
106+
* @param bool $show_optimized_checkout_instruction Whether this is being called through the Optimized Checkout instructions method. Used to avoid an infinite loop call.
107+
* @return string
108+
*/
109+
public function get_testing_instructions( $show_optimized_checkout_instruction = false ) {
110+
if ( ! $show_optimized_checkout_instruction ) {
111+
return WC_Stripe_UPE_Payment_Gateway::get_testing_instructions_for_optimized_checkout();
112+
}
113+
114+
return sprintf(
115+
/* translators: 1) HTML strong open tag 2) HTML strong closing tag 3) HTML anchor open tag 2) HTML anchor closing tag */
116+
esc_html__( '%1$sTest mode:%2$s use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed %3$shere%4$s.', 'woocommerce-gateway-stripe' ),
117+
'<strong>',
118+
'</strong>',
119+
'<a href="https://docs.stripe.com/testing" target="_blank">',
120+
'</a>'
121+
);
122+
}
123+
}

0 commit comments

Comments
 (0)