Skip to content
22 changes: 16 additions & 6 deletions includes/class-wc-stripe-feature-flags.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
}

class WC_Stripe_Feature_Flags {
const UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME = 'upe_checkout_experience_enabled';
const AMAZON_PAY_FEATURE_FLAG_NAME = '_wcstripe_feature_amazon_pay';

const UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME = 'upe_checkout_experience_enabled';
const AMAZON_PAY_FEATURE_FLAG_NAME = '_wcstripe_feature_amazon_pay';
const SHARED_PAYMENT_TOKEN_FEATURE_FLAG_NAME = '_wcstripe_feature_shared_payment_token';
/**
* Feature flag for Stripe ECE (Express Checkout Element).
* This feature flag controls whether the new Express Checkout Element (ECE) or the legacy Payment Request Button (PRB) is used to render express checkout buttons.
Expand All @@ -33,9 +33,10 @@ class WC_Stripe_Feature_Flags {
* @var array
*/
protected static $feature_flags = [
'_wcstripe_feature_upe' => 'yes',
self::AMAZON_PAY_FEATURE_FLAG_NAME => 'no',
self::OC_FEATURE_FLAG_NAME => 'no',
'_wcstripe_feature_upe' => 'yes',
self::AMAZON_PAY_FEATURE_FLAG_NAME => 'no',
self::OC_FEATURE_FLAG_NAME => 'no',
self::SHARED_PAYMENT_TOKEN_FEATURE_FLAG_NAME => 'no',
];

/**
Expand Down Expand Up @@ -80,6 +81,15 @@ public static function is_stripe_ece_enabled() {
return true;
}

/**
* Checks whether Shared Payment Token feature flag is enabled.
*
* @return bool
*/
public static function is_shared_payment_token_available(): bool {
return 'yes' === self::get_option_with_default( self::SHARED_PAYMENT_TOKEN_FEATURE_FLAG_NAME );
}

/**
* Checks whether UPE "preview" feature flag is enabled.
* This allows the merchant to enable/disable UPE checkout.
Expand Down
33 changes: 23 additions & 10 deletions includes/class-wc-stripe-intent-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -818,8 +818,12 @@ public function create_and_confirm_payment_intent( $payment_information ) {

$non_empty_params = [];

// The payment method is not required if we're using the confirmation token flow.
if ( empty( $payment_information['confirmation_token'] ) ) {
if ( WC_Stripe_Payment_Methods::SHARED_PAYMENT_TOKEN === ( $payment_information['selected_payment_type'] ?? null ) ) {
$required_params[] = 'shared_payment_granted_token';

$non_empty_params[] = 'shared_payment_granted_token';
} elseif ( empty( $payment_information['confirmation_token'] ) ) {
// The payment method is not required if we're using the confirmation token flow.
$required_params[] = 'payment_method';
$required_params[] = 'capture_method';

Expand All @@ -832,7 +836,7 @@ public function create_and_confirm_payment_intent( $payment_information ) {

$order = $payment_information['order'];
$selected_payment_type = $payment_information['selected_payment_type'];
$payment_method_types = $payment_information['payment_method_types'];
$payment_method_types = $payment_information['payment_method_types'] ?? [];
$is_using_saved_token = $payment_information['is_using_saved_payment_method'] ?? false;

$request = $this->build_base_payment_intent_request_params( $payment_information );
Expand All @@ -847,10 +851,13 @@ public function create_and_confirm_payment_intent( $payment_information ) {
/* translators: 1) blog name 2) order number */
'description' => sprintf( __( '%1$s - Order %2$s', 'woocommerce-gateway-stripe' ), wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ), $order->get_order_number() ),
'metadata' => $payment_information['metadata'],
'payment_method_types' => $payment_method_types,
]
);

if ( [] !== $payment_method_types ) {
$request['payment_method_types'] = $payment_method_types;
}

if ( isset( $payment_information['statement_descriptor_suffix'] ) ) {
$request['statement_descriptor_suffix'] = $payment_information['statement_descriptor_suffix'];
}
Expand Down Expand Up @@ -884,8 +891,12 @@ public function create_and_confirm_payment_intent( $payment_information ) {
$order
);

// Only update the payment_type if we have a reference to the payment type the customer selected.
if ( '' !== $selected_payment_type ) {
// TODO: Verify this works as expected.
// If we're processing a shared payment token, we need to look at the intent that was actually created.
if ( WC_Stripe_Payment_Methods::SHARED_PAYMENT_TOKEN === $selected_payment_type ) {
$order->update_meta_data( '_stripe_upe_payment_type', $payment_intent->type );
} elseif ( '' !== $selected_payment_type ) {
// Only update the payment_type if we have a reference to the payment type the customer selected.
$order->update_meta_data( '_stripe_upe_payment_type', $selected_payment_type );
}

Expand Down Expand Up @@ -1053,18 +1064,20 @@ private function validate_payment_intent_required_params( $required_params, $non
*/
private function build_base_payment_intent_request_params( $payment_information ) {
$selected_payment_type = $payment_information['selected_payment_type'];
if ( $this->get_upe_gateway()->is_oc_enabled() && isset( $payment_information['payment_method_details']->type ) ) {
if ( WC_Stripe_Payment_Methods::SHARED_PAYMENT_TOKEN !== $selected_payment_type && $this->get_upe_gateway()->is_oc_enabled() && isset( $payment_information['payment_method_details']->type ) ) {
$selected_payment_type = $payment_information['payment_method_details']->type;
}

$payment_method_types = $payment_information['payment_method_types'];
$payment_method_types = $payment_information['payment_method_types'] ?? [];

$request = [
'shipping' => $payment_information['shipping'],
];

$is_using_confirmation_token = ! empty( $payment_information['confirmation_token'] );
if ( $is_using_confirmation_token ) {
if ( WC_Stripe_Payment_Methods::SHARED_PAYMENT_TOKEN === $selected_payment_type ) {
$request['shared_payment_granted_token'] = $payment_information['shared_payment_granted_token'];
} elseif ( $is_using_confirmation_token ) {
$request['confirmation_token'] = $payment_information['confirmation_token'];
} else {
$request['payment_method'] = $payment_information['payment_method'];
Expand All @@ -1089,7 +1102,7 @@ private function build_base_payment_intent_request_params( $payment_information
// For confirmations tokens, the setup_future_usage is set within the payment method.
$payment_method = WC_Stripe_UPE_Payment_Gateway::get_payment_method_instance( $selected_payment_type );
$has_auto_renewing_subscription = ! empty( $payment_information['has_subscription'] ) && ! $this->is_manual_renewal_required( $payment_method->is_reusable() );
if ( ! $is_using_confirmation_token && ( $payment_information['save_payment_method_to_store'] || $has_auto_renewing_subscription ) ) {
if ( ! $is_using_confirmation_token && WC_Stripe_Payment_Methods::SHARED_PAYMENT_TOKEN !== $selected_payment_type && ( $payment_information['save_payment_method_to_store'] || $has_auto_renewing_subscription ) ) {
$request['setup_future_usage'] = 'off_session';
}

Expand Down
1 change: 1 addition & 0 deletions includes/class-wc-stripe.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ public function init() {
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-acss.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-amazon-pay.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-oc.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-stripe-upe-payment-method-shared-payment-token.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-bancontact.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-sofort.php';
require_once WC_STRIPE_PLUGIN_PATH . '/includes/payment-methods/class-wc-gateway-stripe-giropay.php';
Expand Down
51 changes: 26 additions & 25 deletions includes/constants/class-wc-stripe-payment-methods.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,32 @@
*/
class WC_Stripe_Payment_Methods {
// Standard payment method constants
const ACH = 'us_bank_account';
const ACSS_DEBIT = 'acss_debit';
const AFFIRM = 'affirm';
const AFTERPAY_CLEARPAY = 'afterpay_clearpay';
const ALIPAY = 'alipay';
const BACS_DEBIT = 'bacs_debit';
const BECS_DEBIT = 'au_becs_debit';
const BANCONTACT = 'bancontact';
const BLIK = 'blik';
const BOLETO = 'boleto';
const CARD = 'card';
const CARD_PRESENT = 'card_present';
const CASHAPP_PAY = 'cashapp';
const EPS = 'eps';
const GIROPAY = 'giropay';
const IDEAL = 'ideal';
const KLARNA = 'klarna';
const MULTIBANCO = 'multibanco';
const OXXO = 'oxxo';
const P24 = 'p24';
const SEPA = 'sepa';
const SEPA_DEBIT = 'sepa_debit';
const SOFORT = 'sofort';
const WECHAT_PAY = 'wechat_pay';
const OC = 'card'; // This is a special case for the Optimized Checkout
const ACH = 'us_bank_account';
const ACSS_DEBIT = 'acss_debit';
const AFFIRM = 'affirm';
const AFTERPAY_CLEARPAY = 'afterpay_clearpay';
const ALIPAY = 'alipay';
const BACS_DEBIT = 'bacs_debit';
const BECS_DEBIT = 'au_becs_debit';
const BANCONTACT = 'bancontact';
const BLIK = 'blik';
const BOLETO = 'boleto';
const CARD = 'card';
const CARD_PRESENT = 'card_present';
const CASHAPP_PAY = 'cashapp';
const EPS = 'eps';
const GIROPAY = 'giropay';
const IDEAL = 'ideal';
const KLARNA = 'klarna';
const MULTIBANCO = 'multibanco';
const OXXO = 'oxxo';
const P24 = 'p24';
const SEPA = 'sepa';
const SEPA_DEBIT = 'sepa_debit';
const SOFORT = 'sofort';
const WECHAT_PAY = 'wechat_pay';
const OC = 'card'; // This is a special case for the Optimized Checkout
const SHARED_PAYMENT_TOKEN = 'shared_payment_token';

// Express method constants
const AMAZON_PAY = 'amazon_pay';
Expand Down
Loading
Loading