express_checkout_helper->is_product() ); ?>>
@@ -342,7 +341,7 @@ class="woopay-express-button"
data-type=""
data-theme=""
data-size=""
- style="height: px; border-radius: px"
+ style="height: px; border-radius: px"
disabled
>
diff --git a/includes/class-wc-payments-woopay-direct-checkout.php b/includes/class-wc-payments-woopay-direct-checkout.php
index 6c2d170f4fe..6705bdf2332 100644
--- a/includes/class-wc-payments-woopay-direct-checkout.php
+++ b/includes/class-wc-payments-woopay-direct-checkout.php
@@ -1,14 +1,11 @@
init();
}
}
@@ -1882,13 +1880,14 @@ public static function load_stripe_bnpl_site_messaging() {
$are_subscriptions_enabled = class_exists( 'WC_Subscriptions' ) || class_exists( 'WC_Subscriptions_Core_Plugin' );
if ( $are_subscriptions_enabled ) {
global $product;
- $is_subscription = $product && WC_Subscriptions_Product::is_subscription( $product );
+ $is_subscription = $product && WC_Subscriptions_Product::is_subscription( $product );
+ $cart_contains_subscription = is_cart() && WC_Subscriptions_Cart::cart_contains_subscription();
}
- if ( ! $is_subscription ) {
+ if ( ! $is_subscription && ! $cart_contains_subscription ) {
require_once __DIR__ . '/class-wc-payments-payment-method-messaging-element.php';
$stripe_site_messaging = new WC_Payments_Payment_Method_Messaging_Element( self::$account, self::$card_gateway );
- echo wp_kses( $stripe_site_messaging->init(), 'post' );
+ echo wp_kses( $stripe_site_messaging->init() ?? '', 'post' );
}
}
diff --git a/includes/class-woopay-tracker.php b/includes/class-woopay-tracker.php
index 78e7ea5c8da..538ec873dc8 100644
--- a/includes/class-woopay-tracker.php
+++ b/includes/class-woopay-tracker.php
@@ -294,6 +294,8 @@ public function tracks_record_event( $event_name, $properties = [], $is_admin_ev
return false;
}
+ $properties = apply_filters( 'wcpay_tracks_event_properties', $properties, $event_name );
+
if ( isset( $properties['record_event_data'] ) ) {
if ( isset( $properties['record_event_data']['is_admin_event'] ) ) {
$is_admin_event = $properties['record_event_data']['is_admin_event'];
diff --git a/includes/constants/class-payment-request-button-states.php b/includes/constants/class-express-checkout-element-states.php
similarity index 99%
rename from includes/constants/class-payment-request-button-states.php
rename to includes/constants/class-express-checkout-element-states.php
index 63160ce6b56..d2e02532e22 100644
--- a/includes/constants/class-payment-request-button-states.php
+++ b/includes/constants/class-express-checkout-element-states.php
@@ -1,6 +1,6 @@
cart->empty_cart();
+ if ( empty( $payment_data['payment_request_type'] ) ) {
+ return;
+ }
+
+ $payment_request_type = wc_clean( wp_unslash( $payment_data['payment_request_type'] ) );
+
+ $payment_method_titles = [
+ 'apple_pay' => 'Apple Pay',
+ 'google_pay' => 'Google Pay',
+ ];
+
+ $suffix = apply_filters( 'wcpay_payment_request_payment_method_title_suffix', 'WooPayments' );
+ if ( ! empty( $suffix ) ) {
+ $suffix = " ($suffix)";
+ }
+
+ $payment_method_title = isset( $payment_method_titles[ $payment_request_type ] ) ? $payment_method_titles[ $payment_request_type ] : 'Payment Request';
+ $order->set_payment_method_title( $payment_method_title . $suffix );
+ }
+
+ /**
+ * Google Pay/Apple Pay parameters for address data might need some massaging for some of the countries.
+ * Ensuring that the Store API doesn't throw a `rest_invalid_param` error message for some of those scenarios.
+ *
+ * @param mixed $response Response to replace the requested version with.
+ * @param \WP_REST_Server $server Server instance.
+ * @param \WP_REST_Request $request Request used to generate the response.
+ *
+ * @return mixed
+ */
+ public function tokenized_cart_store_api_address_normalization( $response, $server, $request ) {
+ if ( 'true' !== $request->get_header( 'X-WooPayments-Tokenized-Cart' ) ) {
+ return $response;
+ }
+
+ // header added as additional layer of security.
+ $nonce = $request->get_header( 'X-WooPayments-Tokenized-Cart-Nonce' );
+ if ( ! wp_verify_nonce( $nonce, 'woopayments_tokenized_cart_nonce' ) ) {
+ return $response;
+ }
+
+ // This route is used to get shipping rates.
+ // GooglePay/ApplePay might provide us with "trimmed" zip codes.
+ // If that's the case, let's temporarily allow to skip the zip code validation, in order to get some shipping rates.
+ $is_update_customer_route = $request->get_route() === '/wc/store/v1/cart/update-customer';
+ if ( $is_update_customer_route ) {
+ add_filter( 'woocommerce_validate_postcode', [ $this, 'maybe_skip_postcode_validation' ], 10, 3 );
+ }
+
+ $request_data = $request->get_json_params();
+ if ( isset( $request_data['shipping_address'] ) ) {
+ $request->set_param( 'shipping_address', $this->transform_ece_address_state_data( $request_data['shipping_address'] ) );
+ // on the "update customer" route, GooglePay/Apple pay might provide redacted postcode data.
+ // we need to modify the zip code to ensure that shipping zone identification still works.
+ if ( $is_update_customer_route ) {
+ $request->set_param( 'shipping_address', $this->transform_ece_address_postcode_data( $request_data['shipping_address'] ) );
+ }
+ }
+ if ( isset( $request_data['billing_address'] ) ) {
+ $request->set_param( 'billing_address', $this->transform_ece_address_state_data( $request_data['billing_address'] ) );
+ // on the "update customer" route, GooglePay/Apple pay might provide redacted postcode data.
+ // we need to modify the zip code to ensure that shipping zone identification still works.
+ if ( $is_update_customer_route ) {
+ $request->set_param( 'billing_address', $this->transform_ece_address_postcode_data( $request_data['billing_address'] ) );
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Allows certain "redacted" postcodes for some countries to bypass WC core validation.
+ *
+ * @param bool $valid Whether the postcode is valid.
+ * @param string $postcode The postcode in question.
+ * @param string $country The country for the postcode.
+ *
+ * @return bool
+ */
+ public function maybe_skip_postcode_validation( $valid, $postcode, $country ) {
+ if ( ! in_array( $country, [ Country_Code::UNITED_KINGDOM, Country_Code::CANADA ], true ) ) {
+ return $valid;
+ }
+
+ // We padded the string with `0` in the `get_normalized_postal_code` method.
+ // It's a flimsy check, but better than nothing.
+ // Plus, this check is only made for the scenarios outlined in the `tokenized_cart_store_api_address_normalization` method.
+ if ( substr( $postcode, - 1 ) === '0' ) {
+ return true;
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Transform a GooglePay/ApplePay state address data fields into values that are valid for WooCommerce.
+ *
+ * @param array $address The address to normalize from the GooglePay/ApplePay request.
+ *
+ * @return array
+ */
+ private function transform_ece_address_state_data( $address ) {
+ $country = $address['country'] ?? '';
+ if ( empty( $country ) ) {
+ return $address;
+ }
+
+ // States from Apple Pay or Google Pay are in long format, we need their short format..
+ $state = $address['state'] ?? '';
+ if ( ! empty( $state ) ) {
+ $address['state'] = $this->express_checkout_button_helper->get_normalized_state( $state, $country );
+ }
+
+ return $address;
+ }
+
+ /**
+ * Transform a GooglePay/ApplePay postcode address data fields into values that are valid for WooCommerce.
+ *
+ * @param array $address The address to normalize from the GooglePay/ApplePay request.
+ *
+ * @return array
+ */
+ private function transform_ece_address_postcode_data( $address ) {
+ $country = $address['country'] ?? '';
+ if ( empty( $country ) ) {
+ return $address;
+ }
- if ( $booking_id ) {
- // When a bookable product is added to the cart, a 'booking' is create with status 'in-cart'.
- // This status is used to prevent the booking from being booked by another customer
- // and should be removed when the cart is emptied for PRB purposes.
- do_action( 'wc-booking-remove-inactive-cart', $booking_id ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
+ // Normalizes postal code in case of redacted data from Apple Pay or Google Pay.
+ $postcode = $address['postcode'] ?? '';
+ if ( ! empty( $postcode ) ) {
+ $address['postcode'] = $this->express_checkout_button_helper->get_normalized_postal_code( $postcode, $country );
}
- wp_send_json( [ 'result' => 'success' ] );
+ return $address;
}
}
diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php b/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php
index 4a78920db88..1f9470bbf65 100644
--- a/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php
+++ b/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php
@@ -21,13 +21,6 @@ class WC_Payments_Express_Checkout_Button_Display_Handler {
*/
private $gateway;
- /**
- * Instance of WC_Payments_Payment_Request_Button_Handler, created in init function
- *
- * @var WC_Payments_Payment_Request_Button_Handler
- */
- private $payment_request_button_handler;
-
/**
* Instance of WC_Payments_WooPay_Button_Handler, created in init function
*
@@ -60,7 +53,6 @@ class WC_Payments_Express_Checkout_Button_Display_Handler {
* Initialize class actions.
*
* @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
- * @param WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler Payment request button handler.
* @param WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler Platform checkout button handler.
* @param WC_Payments_Express_Checkout_Button_Handler $express_checkout_button_handler Express Checkout Element button handler.
* @param WC_Payments_Express_Checkout_Ajax_Handler $express_checkout_ajax_handler Express checkout ajax handlers.
@@ -68,14 +60,12 @@ class WC_Payments_Express_Checkout_Button_Display_Handler {
*/
public function __construct(
WC_Payment_Gateway_WCPay $gateway,
- WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler,
WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler,
WC_Payments_Express_Checkout_Button_Handler $express_checkout_button_handler,
WC_Payments_Express_Checkout_Ajax_Handler $express_checkout_ajax_handler,
WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper
) {
$this->gateway = $gateway;
- $this->payment_request_button_handler = $payment_request_button_handler;
$this->platform_checkout_button_handler = $platform_checkout_button_handler;
$this->express_checkout_button_handler = $express_checkout_button_handler;
$this->express_checkout_ajax_handler = $express_checkout_ajax_handler;
@@ -89,7 +79,6 @@ public function __construct(
*/
public function init() {
$this->platform_checkout_button_handler->init();
- $this->payment_request_button_handler->init();
$this->express_checkout_button_handler->init();
$is_woopay_enabled = WC_Payments_Features::is_woopay_enabled();
@@ -97,7 +86,6 @@ public function init() {
if ( $is_woopay_enabled || $is_payment_request_enabled ) {
add_action( 'wc_ajax_wcpay_add_to_cart', [ $this->express_checkout_ajax_handler, 'ajax_add_to_cart' ] );
- add_action( 'wc_ajax_wcpay_empty_cart', [ $this->express_checkout_ajax_handler, 'ajax_empty_cart' ] );
add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'display_express_checkout_buttons' ], 1 );
add_action( 'woocommerce_proceed_to_checkout', [ $this, 'display_express_checkout_buttons' ], 21 );
@@ -105,6 +93,8 @@ public function init() {
add_action( 'woocommerce_pay_order_before_payment', [ $this, 'display_express_checkout_buttons' ], 1 );
}
+ add_filter( 'wcpay_tracks_event_properties', [ $this, 'record_all_ece_tracks_events' ], 10, 2 );
+
if ( $this->is_pay_for_order_flow_supported() ) {
add_action( 'wp_enqueue_scripts', [ $this, 'add_pay_for_order_params_to_js_config' ], 5 );
}
@@ -117,10 +107,9 @@ public function init() {
* @return void
*/
public function display_express_checkout_separator_if_necessary( $separator_starts_hidden = false ) {
- $html_id = WC_Payments_Features::is_stripe_ece_enabled() ? 'wcpay-express-checkout-button-separator' : 'wcpay-payment-request-button-separator';
if ( $this->express_checkout_helper->is_checkout() ) {
?>
-
+
express_checkout_helper->is_pay_for_order_page() || $this->is_pay_for_order_flow_supported() ) {
$this->platform_checkout_button_handler->display_woopay_button_html();
}
- if ( WC_Payments_Features::is_stripe_ece_enabled() ) {
- $this->express_checkout_button_handler->display_express_checkout_button_html();
- } else {
- $this->payment_request_button_handler->display_payment_request_button_html();
- }
+ $this->express_checkout_button_handler->display_express_checkout_button_html();
if ( is_cart() ) {
add_action( 'woocommerce_after_cart', [ $this, 'add_order_attribution_inputs' ], 1 );
@@ -236,4 +220,27 @@ function ( $js_config ) use ( $order ) {
}
// phpcs:enable WordPress.Security.NonceVerification
}
+
+ /**
+ * Record all ECE tracks events by adding the track_on_all_stores flag to the event.
+ *
+ * @param array $properties Event properties.
+ * @param string $event_name Event name.
+ * @return array
+ */
+ public function record_all_ece_tracks_events( $properties, $event_name ) {
+ $tracked_events_prefixes = [
+ 'wcpay_applepay',
+ 'wcpay_gpay',
+ ];
+
+ foreach ( $tracked_events_prefixes as $prefix ) {
+ if ( strpos( $event_name, $prefix ) === 0 ) {
+ $properties['record_event_data']['track_on_all_stores'] = true;
+ break;
+ }
+ }
+
+ return $properties;
+ }
}
diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
index 9deeab01ca3..03f0100cefa 100644
--- a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
+++ b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
@@ -76,10 +76,6 @@ public function init() {
return;
}
- if ( ! WC_Payments_Features::is_stripe_ece_enabled() ) {
- return;
- }
-
// Checks if Payment Request is enabled.
if ( 'yes' !== $this->gateway->get_option( 'payment_request' ) ) {
return;
@@ -113,15 +109,15 @@ public function init() {
* @return array
*/
public function get_button_settings() {
- $button_type = $this->gateway->get_option( 'payment_request_button_type' );
- $common_settings = $this->express_checkout_helper->get_common_button_settings();
- $payment_request_button_settings = [
+ $button_type = $this->gateway->get_option( 'payment_request_button_type' );
+ $common_settings = $this->express_checkout_helper->get_common_button_settings();
+ $express_checkout_button_settings = [
// Default format is en_US.
'locale' => apply_filters( 'wcpay_payment_request_button_locale', substr( get_locale(), 0, 2 ) ),
'branded_type' => 'default' === $button_type ? 'short' : 'long',
];
- return array_merge( $common_settings, $payment_request_button_settings );
+ return array_merge( $common_settings, $express_checkout_button_settings );
}
/**
@@ -226,7 +222,7 @@ public function scripts() {
return;
}
- $payment_request_params = [
+ $express_checkout_params = [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
'stripe' => [
@@ -235,18 +231,23 @@ public function scripts() {
'locale' => WC_Payments_Utils::convert_to_stripe_locale( get_locale() ),
],
'nonce' => [
- 'get_cart_details' => wp_create_nonce( 'wcpay-get-cart-details' ),
- 'shipping' => wp_create_nonce( 'wcpay-payment-request-shipping' ),
- 'update_shipping' => wp_create_nonce( 'wcpay-update-shipping-method' ),
- 'checkout' => wp_create_nonce( 'woocommerce-process_checkout' ),
- 'add_to_cart' => wp_create_nonce( 'wcpay-add-to-cart' ),
- 'empty_cart' => wp_create_nonce( 'wcpay-empty-cart' ),
- 'get_selected_product_data' => wp_create_nonce( 'wcpay-get-selected-product-data' ),
- 'platform_tracker' => wp_create_nonce( 'platform_tracks_nonce' ),
- 'pay_for_order' => wp_create_nonce( 'pay_for_order' ),
+ 'get_cart_details' => wp_create_nonce( 'wcpay-get-cart-details' ),
+ 'shipping' => wp_create_nonce( 'wcpay-payment-request-shipping' ),
+ 'update_shipping' => wp_create_nonce( 'wcpay-update-shipping-method' ),
+ 'checkout' => wp_create_nonce( 'woocommerce-process_checkout' ),
+ 'add_to_cart' => wp_create_nonce( 'wcpay-add-to-cart' ),
+ 'empty_cart' => wp_create_nonce( 'wcpay-empty-cart' ),
+ 'get_selected_product_data' => wp_create_nonce( 'wcpay-get-selected-product-data' ),
+ 'platform_tracker' => wp_create_nonce( 'platform_tracks_nonce' ),
+ 'pay_for_order' => wp_create_nonce( 'pay_for_order' ),
+ // needed to communicate via the Store API.
+ 'tokenized_cart_nonce' => wp_create_nonce( 'woopayments_tokenized_cart_nonce' ),
+ 'tokenized_cart_session_nonce' => wp_create_nonce( 'woopayments_tokenized_cart_session_nonce' ),
+ 'store_api_nonce' => wp_create_nonce( 'wc_store_api' ),
],
'checkout' => [
'currency_code' => strtolower( get_woocommerce_currency() ),
+ 'currency_decimals' => WC_Payments::get_localization_service()->get_currency_format( get_woocommerce_currency() )['num_decimals'],
'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
'needs_shipping' => WC()->cart->needs_shipping(),
// Defaults to 'required' to match how core initializes this option.
@@ -255,25 +256,47 @@ public function scripts() {
],
'button' => $this->get_button_settings(),
'login_confirmation' => $this->get_login_confirmation_settings(),
- 'is_product_page' => $this->express_checkout_helper->is_product(),
'button_context' => $this->express_checkout_helper->get_button_context(),
- 'is_pay_for_order' => $this->express_checkout_helper->is_pay_for_order_page(),
'has_block' => has_block( 'woocommerce/cart' ) || has_block( 'woocommerce/checkout' ),
'product' => $this->express_checkout_helper->get_product_data(),
'total_label' => $this->express_checkout_helper->get_total_label(),
- 'is_checkout_page' => $this->express_checkout_helper->is_checkout(),
];
- WC_Payments::register_script_with_dependencies( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'dist/express-checkout', [ 'jquery', 'stripe' ] );
+ if ( WC_Payments_Features::is_tokenized_cart_ece_enabled() ) {
+ WC_Payments::register_script_with_dependencies(
+ 'WCPAY_EXPRESS_CHECKOUT_ECE',
+ 'dist/tokenized-express-checkout',
+ [
+ 'jquery',
+ 'stripe',
+ ]
+ );
- WC_Payments_Utils::enqueue_style(
- 'WCPAY_EXPRESS_CHECKOUT_ECE',
- plugins_url( 'dist/payment-request.css', WCPAY_PLUGIN_FILE ),
- [],
- WC_Payments::get_file_version( 'dist/payment-request.css' )
- );
+ WC_Payments_Utils::enqueue_style(
+ 'WCPAY_EXPRESS_CHECKOUT_ECE',
+ plugins_url( 'dist/tokenized-express-checkout.css', WCPAY_PLUGIN_FILE ),
+ [],
+ WC_Payments::get_file_version( 'dist/tokenized-express-checkout.css' )
+ );
+ } else {
+ WC_Payments::register_script_with_dependencies(
+ 'WCPAY_EXPRESS_CHECKOUT_ECE',
+ 'dist/express-checkout',
+ [
+ 'jquery',
+ 'stripe',
+ ]
+ );
- wp_localize_script( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'wcpayExpressCheckoutParams', $payment_request_params );
+ WC_Payments_Utils::enqueue_style(
+ 'WCPAY_EXPRESS_CHECKOUT_ECE',
+ plugins_url( 'dist/express-checkout.css', WCPAY_PLUGIN_FILE ),
+ [],
+ WC_Payments::get_file_version( 'dist/express-checkout.css' )
+ );
+ }
+
+ wp_localize_script( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'wcpayExpressCheckoutParams', $express_checkout_params );
wp_set_script_translations( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'woocommerce-payments' );
@@ -466,10 +489,11 @@ private function register_ece_data_for_block_editor() {
return;
}
- $ece_data = [
- 'button' => $this->get_button_settings(),
- ];
-
- $data_registry->add( 'ece_data', $ece_data );
+ $data_registry->add(
+ 'ece_data',
+ [
+ 'button' => $this->get_button_settings(),
+ ]
+ );
}
}
diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php b/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
index 1a189749dff..561679882a7 100644
--- a/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
+++ b/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
@@ -251,17 +251,13 @@ public function is_available_at( $location, $option_name ) {
*/
public function get_common_button_settings() {
$button_type = $this->gateway->get_option( 'payment_request_button_type' );
- $settings = [
+
+ return [
'type' => $button_type,
'theme' => $this->gateway->get_option( 'payment_request_button_theme' ),
'height' => $this->get_button_height(),
+ 'radius' => $this->gateway->get_option( 'payment_request_button_border_radius' ),
];
-
- if ( WC_Payments_Features::is_stripe_ece_enabled() ) {
- $settings['radius'] = $this->gateway->get_option( 'payment_request_button_border_radius' );
- }
-
- return $settings;
}
/**
@@ -431,7 +427,7 @@ public function should_show_express_checkout_button() {
)
// ...and billing is calculated based on billing address.
- && 'billing' === get_option( 'woocommerce_tax_based_on' )
+ && wc_tax_enabled() && 'billing' === get_option( 'woocommerce_tax_based_on' )
) {
return false;
}
@@ -893,7 +889,7 @@ public function get_normalized_state( $state, $country ) {
}
// Try to match state from the Payment Request API list of states.
- $state = $this->get_normalized_state_from_pr_states( $state, $country );
+ $state = $this->get_normalized_state_from_ece_states( $state, $country );
// If it's normalized, return.
if ( $this->is_normalized_state( $state, $country ) ) {
@@ -980,10 +976,10 @@ public function is_normalized_state( $state, $country ) {
*
* @return string Normalized state or original state input value.
*/
- public function get_normalized_state_from_pr_states( $state, $country ) {
- // Include Payment Request API State list for compatibility with WC countries/states.
- include_once WCPAY_ABSPATH . 'includes/constants/class-payment-request-button-states.php';
- $pr_states = \WCPay\Constants\Payment_Request_Button_States::STATES;
+ public function get_normalized_state_from_ece_states( $state, $country ) {
+ // Include Express Checkout Element API State list for compatibility with WC countries/states.
+ include_once WCPAY_ABSPATH . 'includes/constants/class-express-checkout-element-states.php';
+ $pr_states = \WCPay\Constants\Express_Checkout_Element_States::STATES;
if ( ! isset( $pr_states[ $country ] ) ) {
return $state;
diff --git a/includes/payment-methods/class-affirm-payment-method.php b/includes/payment-methods/class-affirm-payment-method.php
index 24dba99b021..47b89f49951 100644
--- a/includes/payment-methods/class-affirm-payment-method.php
+++ b/includes/payment-methods/class-affirm-payment-method.php
@@ -20,7 +20,7 @@ class Affirm_Payment_Method extends UPE_Payment_Method {
const PAYMENT_METHOD_STRIPE_ID = 'affirm';
/**
- * Constructor for link payment method
+ * Constructor for Affirm payment method
*
* @param WC_Payments_Token_Service $token_service Token class instance.
*/
diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php
index a0a4acbbf30..4cc9b027e8c 100644
--- a/includes/payment-methods/class-afterpay-payment-method.php
+++ b/includes/payment-methods/class-afterpay-payment-method.php
@@ -20,7 +20,7 @@ class Afterpay_Payment_Method extends UPE_Payment_Method {
const PAYMENT_METHOD_STRIPE_ID = 'afterpay_clearpay';
/**
- * Constructor for link payment method
+ * Constructor for Afterpay payment method
*
* @param WC_Payments_Token_Service $token_service Token class instance.
*/
diff --git a/includes/payment-methods/class-klarna-payment-method.php b/includes/payment-methods/class-klarna-payment-method.php
index aaea0697423..31c71cb813a 100644
--- a/includes/payment-methods/class-klarna-payment-method.php
+++ b/includes/payment-methods/class-klarna-payment-method.php
@@ -20,7 +20,7 @@ class Klarna_Payment_Method extends UPE_Payment_Method {
const PAYMENT_METHOD_STRIPE_ID = 'klarna';
/**
- * Constructor for link payment method
+ * Constructor for Klarna payment method
*
* @param WC_Payments_Token_Service $token_service Token class instance.
*/
diff --git a/includes/reports/class-wc-rest-payments-reports-authorizations-controller.php b/includes/reports/class-wc-rest-payments-reports-authorizations-controller.php
index 0834d078eeb..3f1e60f7e8b 100644
--- a/includes/reports/class-wc-rest-payments-reports-authorizations-controller.php
+++ b/includes/reports/class-wc-rest-payments-reports-authorizations-controller.php
@@ -127,7 +127,7 @@ public function get_authorization( $request ) {
* @param array|mixed $item Item to prepare.
* @param WP_REST_Request $request Request instance.
*
- * @return WP_REST_Response|WP_Error|WP_REST_Response
+ * @return WP_REST_Response|WP_Error
*/
public function prepare_item_for_response( $item, $request ) {
diff --git a/includes/reports/class-wc-rest-payments-reports-transactions-controller.php b/includes/reports/class-wc-rest-payments-reports-transactions-controller.php
index 1e38d6cd746..a307c12c627 100644
--- a/includes/reports/class-wc-rest-payments-reports-transactions-controller.php
+++ b/includes/reports/class-wc-rest-payments-reports-transactions-controller.php
@@ -115,7 +115,7 @@ public function get_transaction( $request ) {
* @param array|mixed $item Item to prepare.
* @param WP_REST_Request $request Request instance.
*
- * @return WP_REST_Response|WP_Error|WP_REST_Response
+ * @return WP_REST_Response|WP_Error
*/
public function prepare_item_for_response( $item, $request ) {
diff --git a/includes/woopay/class-woopay-session.php b/includes/woopay/class-woopay-session.php
index f19549cd9fa..dce1878265e 100644
--- a/includes/woopay/class-woopay-session.php
+++ b/includes/woopay/class-woopay-session.php
@@ -45,6 +45,7 @@ public static function init() {
add_filter( 'woocommerce_session_handler', [ __CLASS__, 'add_woopay_store_api_session_handler' ], 20 );
add_action( 'woocommerce_order_payment_status_changed', [ __CLASS__, 'woopay_order_payment_status_changed' ] );
add_action( 'woopay_restore_order_customer_id', [ __CLASS__, 'restore_order_customer_id_from_requests_with_verified_email' ] );
+ add_filter( 'woocommerce_order_needs_payment', [ __CLASS__, 'woopay_trial_subscriptions_handler' ], 20, 3 );
register_deactivation_hook( WCPAY_PLUGIN_FILE, [ __CLASS__, 'run_and_remove_woopay_restore_order_customer_id_schedules' ] );
@@ -272,6 +273,33 @@ public static function automatewoo_refer_a_friend_referral_from_parameter( $advo
return $automatewoo_referral;
}
+ /**
+ * Process trial subscriptions for WooPay.
+ *
+ * @param bool $needs_payment If the order needs payment.
+ * @param \WC_Order $order The order.
+ * @param array $valid_order_statuses The valid order statuses.
+ */
+ public static function woopay_trial_subscriptions_handler( $needs_payment, $order, $valid_order_statuses ) {
+ if ( ! self::is_request_from_woopay() || ! \WC_Payments_Utils::is_store_api_request() ) {
+ return $needs_payment;
+ }
+
+ if ( ! self::is_woopay_enabled() ) {
+ return $needs_payment;
+ }
+
+ if ( ! class_exists( 'WC_Subscriptions_Cart' ) || $order->get_total() > 0 ) {
+ return $needs_payment;
+ }
+
+ if ( \WC_Subscriptions_Cart::cart_contains_subscription() ) {
+ return true;
+ }
+
+ return $needs_payment;
+ }
+
/**
* Returns the payload from a cart token.
*
diff --git a/package-lock.json b/package-lock.json
index 83cd7a25f41..4d8d73b8e87 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "woocommerce-payments",
- "version": "8.5.1",
+ "version": "8.6.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "woocommerce-payments",
- "version": "8.5.1",
+ "version": "8.6.0",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
diff --git a/package.json b/package.json
index c62ba8fd0ec..4fa803a245c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce-payments",
- "version": "8.5.1",
+ "version": "8.6.0",
"main": "webpack.config.js",
"author": "Automattic",
"license": "GPL-3.0-or-later",
@@ -62,6 +62,7 @@
"lint:css": "stylelint 'client/**/*.scss' 'client/**/*.css' 'assets/**/*.scss' 'assets/**/*.css'",
"lint:js": "tsc --noEmit && eslint . --ext=js,jsx,ts,tsx",
"lint:php": "./vendor/bin/phpcs --standard=phpcs.xml.dist $(git ls-files | grep .php$)",
+ "lint:php-compatibility": "./vendor/bin/phpcs --standard=phpcs-compat.xml.dist $(git ls-files | grep .php$)",
"lint:php-fix": "./vendor/bin/phpcbf --standard=phpcs.xml.dist $(git ls-files | grep .php$)",
"format": "npm run format:js && npm run format:css",
"format:js": "npm run format:provided '**/*.js' '**/*.ts' '**/*.tsx'",
diff --git a/phpcs-compat.xml.dist b/phpcs-compat.xml.dist
index 996f8374292..83faef2a44a 100644
--- a/phpcs-compat.xml.dist
+++ b/phpcs-compat.xml.dist
@@ -12,6 +12,7 @@
./docker/*
./node_modules/*
./vendor/*
+ ./vendor-dist/*
tests/
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index e997f0fa2fd..c3547cfc17b 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -19,7 +19,7 @@
-
+
diff --git a/readme.txt b/readme.txt
index 59e8fefc1cd..d67f01c3951 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.3
-Stable tag: 8.5.1
+Stable tag: 8.6.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -89,11 +89,44 @@ Please note that our support for the checkout block is still experimental and th
1. View Transactions
2. View Transaction Details
-3. Track Deposits
+3. Track Payouts
4. Manage Disputes
== Changelog ==
+= 8.6.0 - 2024-12-04 =
+* Add - Add Bank reference key column in Payout reports. This will help reconcile WooPayments Payouts with bank statements.
+* Add - Display credit card brand icons on order received page.
+* Fix - Add support to load stripe js asynchronously when it is not immediately available in the global scope.
+* Fix - Add the missing "Download" column heading label and toggle menu option to the Payments → Documents list view table.
+* Fix - Ensure ECE button load events are triggered for multiple buttons on the same page.
+* Fix - Ensure ECE is displayed correctly taking into account the tax settings.
+* Fix - Evidence submission is no longer available for Klarna inquiries as this is not supported by Stripe / Klarna.
+* Fix - fix: express checkout to use its own css files.
+* Fix - fix: missing ece is_product_page checks
+* Fix - Fix ECE Tracks events not triggering when WooPay is disabled.
+* Fix - Fix WooPay component spacing.
+* Fix - Fix WooPay trial subscriptions purchases.
+* Fix - Make sure the status of manual capture enablement is fetched from the right place.
+* Fix - Prevent express checkout from being used if cart total becomes zero after coupon usage.
+* Fix - Resolved issue with terminal payments in the payment intent failed webhook processing.
+* Fix - Set the support phone field as mandatory in the settings page.
+* Fix - Update Link logo alignment issue when WooPay is enabled and a specific version of Gutenberg is enabled.
+* Fix - Use paragraph selector instead of label for pmme appearance
+* Fix - Validate required billing fields using data from objects instead of checking the labels.
+* Update - Avoid getting the appearance for pay for order page with the wrong appearance key.
+* Update - chore: rename wrapper from payment-request to express-checkout
+* Update - feat: add `wcpay_checkout_use_plain_method_label` filter to allow themes or merchants to force the "plain" WooPayments label on shortcode checkout.
+* Update - refactor: express checkout initialization page location checks
+* Update - refactor: express checkout utility for button UI interactions
+* Dev - Allow redirect to the settings page from WCPay connect
+* Dev - chore: removed old PRB implementation for ApplePay/GooglePay in favor of the ECE implementation; cleaned up ECE feature flag;
+* Dev - Disable visual regression testing from Playwright until a more reliable approach is defined.
+* Dev - Ensure proper return types in the webhook processing service.
+* Dev - fix: E_DEPRECATED on BNPL empty PMME
+* Dev - Fix return types
+* Dev - Update snapshots for E2E Playwright screenshots
+
= 8.5.1 - 2024-11-25 =
* Fix - fix: remove "test mode" badge from shortcode checkout.
diff --git a/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png b/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png
index 302a722e0a6..7cfb7e2649d 100644
Binary files a/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png and b/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png differ
diff --git a/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png b/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png
index 17d9ff94c0e..fdfd9a99e2d 100644
Binary files a/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png and b/tests/e2e-pw/specs/merchant/__snapshots__/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png differ
diff --git a/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts b/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
index 6c2e6b41e72..96008887630 100644
--- a/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
+++ b/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
@@ -54,8 +54,9 @@ test.describe( 'Merchant deposits', () => {
await page.evaluate( () => {
window.scrollTo( 0, 0 );
} );
- await expect(
- page.locator( '.woocommerce-filters' ).last()
- ).toHaveScreenshot();
+ // TODO: This visual regression test is not flaky, but we should revisit the approach.
+ // await expect(
+ // page.locator( '.woocommerce-filters' ).last()
+ // ).toHaveScreenshot();
} );
} );
diff --git a/tests/e2e-pw/specs/merchant/merchant-disputes-view-details-via-order-notice.spec.ts b/tests/e2e-pw/specs/merchant/merchant-disputes-view-details-via-order-notice.spec.ts
index 1e55cafba1e..b7da795ce06 100644
--- a/tests/e2e-pw/specs/merchant/merchant-disputes-view-details-via-order-notice.spec.ts
+++ b/tests/e2e-pw/specs/merchant/merchant-disputes-view-details-via-order-notice.spec.ts
@@ -74,9 +74,10 @@ test.describe(
).toBeVisible();
// Visual regression test for the dispute notice.
- await expect(
- merchantPage.locator( '.dispute-notice' )
- ).toHaveScreenshot();
+ // TODO: This visual regression test is not flaky, but we should revisit the approach.
+ // await expect(
+ // merchantPage.locator( '.dispute-notice' )
+ // ).toHaveScreenshot();
} );
}
);
diff --git a/tests/e2e-pw/specs/merchant/multi-currency-on-boarding.spec.ts b/tests/e2e-pw/specs/merchant/multi-currency-on-boarding.spec.ts
index f987ae71d8e..ccf557c00a6 100644
--- a/tests/e2e-pw/specs/merchant/multi-currency-on-boarding.spec.ts
+++ b/tests/e2e-pw/specs/merchant/multi-currency-on-boarding.spec.ts
@@ -58,11 +58,12 @@ test.describe( 'Multi-currency on-boarding', () => {
test( 'should disable the submit button when no currencies are selected', async () => {
// To take a better screenshot of the component.
await page.setViewportSize( { width: 1280, height: 2000 } );
- await expect(
- page.locator(
- '.multi-currency-setup-wizard > div > .components-card-body'
- )
- ).toHaveScreenshot();
+ // TODO: fix flaky visual regression test.
+ // await expect(
+ // page.locator(
+ // '.multi-currency-setup-wizard > div > .components-card-body'
+ // )
+ // ).toHaveScreenshot();
// Set the viewport back to the default size.
await page.setViewportSize( { width: 1280, height: 720 } );
@@ -168,9 +169,10 @@ test.describe( 'Multi-currency on-boarding', () => {
// To take a better screenshot of the iframe preview.
await page.setViewportSize( { width: 1280, height: 1280 } );
await goToNextOnboardingStep( page );
- await expect(
- page.locator( '.wcpay-wizard-task.is-active' )
- ).toHaveScreenshot();
+ // TODO: fix flaky visual regression test.
+ // await expect(
+ // page.locator( '.wcpay-wizard-task.is-active' )
+ // ).toHaveScreenshot();
await page.getByTestId( 'enable_auto_currency' ).check();
await page.getByRole( 'button', { name: 'Preview' } ).click();
@@ -185,9 +187,10 @@ test.describe( 'Multi-currency on-boarding', () => {
await expect(
await previewPage.locator( '.woocommerce-store-notice' )
).toBeVisible();
- await expect(
- page.locator( '.multi-currency-store-settings-preview-iframe' )
- ).toHaveScreenshot();
+ // TODO: fix flaky visual regression test.
+ // await expect(
+ // page.locator( '.multi-currency-store-settings-preview-iframe' )
+ // ).toHaveScreenshot();
const noticeText = await previewPage
.locator( '.woocommerce-store-notice' )
diff --git a/tests/e2e-pw/specs/merchant/multi-currency.spec.ts b/tests/e2e-pw/specs/merchant/multi-currency.spec.ts
index 45b6bf0b89b..3786b4f17f9 100644
--- a/tests/e2e-pw/specs/merchant/multi-currency.spec.ts
+++ b/tests/e2e-pw/specs/merchant/multi-currency.spec.ts
@@ -41,9 +41,10 @@ test.describe( 'Multi-currency', () => {
page.getByRole( 'heading', { name: 'Enabled currencies' } )
).toBeVisible();
await expect( page.getByText( 'Default currency' ) ).toBeVisible();
- await expect(
- page.locator( '.multi-currency-settings' ).last()
- ).toHaveScreenshot();
+ // TODO: fix flaky visual regression test.
+ // await expect(
+ // page.locator( '.multi-currency-settings' ).last()
+ // ).toHaveScreenshot();
} );
test( 'add the currency switcher to the sidebar', async () => {
diff --git a/tests/e2e-pw/specs/merchant/woopay-setup.spec.ts b/tests/e2e-pw/specs/merchant/woopay-setup.spec.ts
new file mode 100644
index 00000000000..c36cdb135d0
--- /dev/null
+++ b/tests/e2e-pw/specs/merchant/woopay-setup.spec.ts
@@ -0,0 +1,33 @@
+/**
+ * External dependencies
+ */
+import { test, Page } from '@playwright/test';
+/**
+ * Internal dependencies
+ */
+import { getMerchant } from '../../utils/helpers';
+import { activateWooPay, deactivateWooPay } from '../../utils/merchant';
+
+test.describe( 'WooPay setup', () => {
+ let merchantPage: Page;
+ let wasWooPayEnabled: boolean;
+
+ test.beforeAll( async ( { browser } ) => {
+ merchantPage = ( await getMerchant( browser ) ).merchantPage;
+ wasWooPayEnabled = await activateWooPay( merchantPage );
+ } );
+
+ test.afterAll( async () => {
+ if ( ! wasWooPayEnabled ) {
+ await deactivateWooPay( merchantPage );
+ }
+ } );
+
+ test( 'can disable the WooPay feature', async () => {
+ await deactivateWooPay( merchantPage );
+ } );
+
+ test( 'can enable the WooPay feature', async () => {
+ await activateWooPay( merchantPage );
+ } );
+} );
diff --git a/tests/e2e-pw/utils/merchant.ts b/tests/e2e-pw/utils/merchant.ts
index 2cbefa58615..d5908956359 100644
--- a/tests/e2e-pw/utils/merchant.ts
+++ b/tests/e2e-pw/utils/merchant.ts
@@ -250,3 +250,31 @@ export const disablePaymentMethods = async (
await saveWooPaymentsSettings( page );
};
+
+export const isWooPayEnabled = async ( page: Page ) => {
+ await navigation.goToWooPaymentsSettings( page );
+
+ const checkboxTestId = 'woopay-toggle';
+ const isEnabled = await page.getByTestId( checkboxTestId ).isChecked();
+
+ return isEnabled;
+};
+
+export const activateWooPay = async ( page: Page ) => {
+ await navigation.goToWooPaymentsSettings( page );
+
+ const checkboxTestId = 'woopay-toggle';
+ const wasInitiallyEnabled = await isWooPayEnabled( page );
+
+ if ( ! wasInitiallyEnabled ) {
+ await page.getByTestId( checkboxTestId ).check();
+ await saveWooPaymentsSettings( page );
+ }
+ return wasInitiallyEnabled;
+};
+
+export const deactivateWooPay = async ( page: Page ) => {
+ await navigation.goToWooPaymentsSettings( page );
+ await page.getByTestId( 'woopay-toggle' ).uncheck();
+ await saveWooPaymentsSettings( page );
+};
diff --git a/tests/js/jest.config.js b/tests/js/jest.config.js
index 7a918a8d63c..b81f434b8c5 100644
--- a/tests/js/jest.config.js
+++ b/tests/js/jest.config.js
@@ -45,6 +45,8 @@ module.exports = {
'/.*/build-module/',
'/docker/',
'/tests/e2e',
+ // We'll delete the directory and its contents as part of https://github.com/Automattic/woocommerce-payments/issues/9722 .
+ '/client/tokenized-payment-request',
],
transform: {
...tsjPreset.transform,
diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php
index 89ef79bfb11..99f99b071c2 100755
--- a/tests/unit/bootstrap.php
+++ b/tests/unit/bootstrap.php
@@ -96,6 +96,8 @@ function () {
require_once $_plugin_dir . 'includes/admin/class-wc-rest-payments-customer-controller.php';
require_once $_plugin_dir . 'includes/admin/class-wc-rest-payments-refunds-controller.php';
+ require_once $_plugin_dir . 'includes/class-wc-payments-payment-request-button-handler.php';
+
// Load currency helper class early to ensure its implementation is used over the one resolved during further test initialization.
require_once __DIR__ . '/helpers/class-wc-helper-site-currency.php';
diff --git a/tests/unit/express-checkout/test-class-wc-payments-express-checkout-ajax-handler.php b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-ajax-handler.php
new file mode 100644
index 00000000000..de7d43f2bb3
--- /dev/null
+++ b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-ajax-handler.php
@@ -0,0 +1,190 @@
+getMockBuilder( WC_Payments_Express_Checkout_Button_Helper::class )
+ ->onlyMethods( [] )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ update_option( '_wcpay_feature_tokenized_cart_ece', '1' );
+ $this->ajax_handler = new WC_Payments_Express_Checkout_Ajax_Handler(
+ $express_checkout_button_helper_mock
+ );
+ $this->ajax_handler->init();
+ }
+
+ /**
+ * Clean up after each test.
+ *
+ * @return void
+ */
+ public function tear_down() {
+ delete_option( '_wcpay_feature_tokenized_cart_ece' );
+
+ parent::tear_down();
+ }
+
+ public function test_tokenized_cart_address_avoid_normalization_when_missing_header() {
+ $request = new WP_REST_Request();
+ $request->set_header( 'X-WooPayments-Tokenized-Cart', null );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_param(
+ 'shipping_address',
+ [
+ 'country' => 'US',
+ 'state' => 'California',
+ ]
+ );
+
+ $this->ajax_handler->tokenized_cart_store_api_address_normalization( null, null, $request );
+
+ $shipping_address = $request->get_param( 'shipping_address' );
+
+ $this->assertSame( 'California', $shipping_address['state'] );
+ }
+
+ public function test_tokenized_cart_address_avoid_normalization_when_wrong_nonce() {
+ $request = new WP_REST_Request();
+ $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', 'invalid-nonce' );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_param(
+ 'shipping_address',
+ [
+ 'country' => 'US',
+ 'state' => 'California',
+ ]
+ );
+
+ $this->ajax_handler->tokenized_cart_store_api_address_normalization( null, null, $request );
+
+ $shipping_address = $request->get_param( 'shipping_address' );
+
+ $this->assertSame( 'California', $shipping_address['state'] );
+ }
+
+ public function test_tokenized_cart_address_state_normalization() {
+ $request = new WP_REST_Request();
+ $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_param(
+ 'shipping_address',
+ [
+ 'country' => 'US',
+ 'state' => 'California',
+ ]
+ );
+ $request->set_param(
+ 'billing_address',
+ [
+ 'country' => 'CA',
+ 'state' => 'Colombie-Britannique',
+ ]
+ );
+
+ $this->ajax_handler->tokenized_cart_store_api_address_normalization( null, null, $request );
+
+ $shipping_address = $request->get_param( 'shipping_address' );
+ $billing_address = $request->get_param( 'billing_address' );
+
+ $this->assertSame( 'CA', $shipping_address['state'] );
+ $this->assertSame( 'BC', $billing_address['state'] );
+ }
+
+ public function test_tokenized_cart_address_postcode_normalization() {
+ $request = new WP_REST_Request();
+ $request->set_route( '/wc/store/v1/cart/update-customer' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_param(
+ 'shipping_address',
+ [
+ 'country' => 'CA',
+ 'postcode' => 'H3B',
+ ]
+ );
+ $request->set_param(
+ 'billing_address',
+ [
+ 'country' => 'US',
+ 'postcode' => '90210',
+ ]
+ );
+
+ $this->ajax_handler->tokenized_cart_store_api_address_normalization( null, null, $request );
+
+ $shipping_address = $request->get_param( 'shipping_address' );
+ $billing_address = $request->get_param( 'billing_address' );
+
+ // this should be modified.
+ $this->assertSame( 'H3B000', $shipping_address['postcode'] );
+ // this shouldn't be modified.
+ $this->assertSame( '90210', $billing_address['postcode'] );
+ }
+
+ public function test_tokenized_cart_avoid_address_postcode_normalization_if_route_incorrect() {
+ $request = new WP_REST_Request();
+ $request->set_route( '/wc/store/v1/checkout' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
+ $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_param(
+ 'shipping_address',
+ [
+ 'country' => 'CA',
+ 'postcode' => 'H3B',
+ 'state' => 'Colombie-Britannique',
+ ]
+ );
+ $request->set_param(
+ 'billing_address',
+ [
+ 'country' => 'CA',
+ 'postcode' => 'H3B',
+ 'state' => 'Colombie-Britannique',
+ ]
+ );
+
+ $this->ajax_handler->tokenized_cart_store_api_address_normalization( null, null, $request );
+
+ $shipping_address = $request->get_param( 'shipping_address' );
+ $billing_address = $request->get_param( 'billing_address' );
+
+ // this should be modified.
+ $this->assertSame( 'BC', $shipping_address['state'] );
+ $this->assertSame( 'BC', $billing_address['state'] );
+ // this shouldn't be modified.
+ $this->assertSame( 'H3B', $shipping_address['postcode'] );
+ $this->assertSame( 'H3B', $billing_address['postcode'] );
+ }
+}
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-display-handler.php
similarity index 79%
rename from tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
rename to tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-display-handler.php
index 0444375d01d..482faafe057 100644
--- a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
+++ b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-display-handler.php
@@ -13,7 +13,7 @@
use WCPay\WooPay\WooPay_Utilities;
/**
- * WC_Payments_WooPay_Button_Handler_Test class.
+ * WC_Payments_Express_Checkout_Button_Display_Handler_Test class.
*/
class WC_Payments_Express_Checkout_Button_Display_Handler_Test extends WCPAY_UnitTestCase {
/**
@@ -37,13 +37,6 @@ class WC_Payments_Express_Checkout_Button_Display_Handler_Test extends WCPAY_Uni
*/
private $mock_woopay_button_handler;
- /**
- * Payment Request Button Handler mock instance.
- *
- * @var WC_Payments_Payment_Request_Button_Handler|MockObject
- */
- private $mock_payment_request_button_handler;
-
/**
* WC_Payments_Account instance.
*
@@ -150,22 +143,6 @@ public function set_up() {
)
->getMock();
- $this->mock_payment_request_button_handler = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
- ->setConstructorArgs(
- [
- $this->mock_wcpay_account,
- $this->mock_wcpay_gateway,
- $this->mock_express_checkout_helper,
- ]
- )
- ->setMethods(
- [
- 'should_show_payment_request_button',
- 'is_checkout',
- ]
- )
- ->getMock();
-
$this->mock_express_checkout_ece_button_handler = $this->getMockBuilder( WC_Payments_Express_Checkout_Button_Handler::class )
->setConstructorArgs(
[
@@ -184,7 +161,6 @@ public function set_up() {
$this->express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler(
$this->mock_wcpay_gateway,
- $this->mock_payment_request_button_handler,
$this->mock_woopay_button_handler,
$this->mock_express_checkout_ece_button_handler,
$this->mock_express_checkout_ajax_handler,
@@ -258,7 +234,7 @@ public function test_display_express_checkout_buttons_all_enabled() {
$this->assertStringContainsString( 'wcpay-woopay-button', ob_get_contents() );
$this->assertStringContainsString( 'wcpay-express-checkout-element', ob_get_contents() );
- $this->assertStringNotContainsString( 'wcpay-payment-request-button-separator', ob_get_contents() );
+ $this->assertStringNotContainsString( 'wcpay-express-checkout-button-separator', ob_get_contents() );
ob_end_clean();
}
@@ -267,10 +243,6 @@ public function test_display_express_checkout_buttons_all_disabled() {
->method( 'should_show_woopay_button' )
->willReturn( false );
- $this->mock_payment_request_button_handler
- ->method( 'should_show_payment_request_button' )
- ->willReturn( false );
-
$this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
@@ -278,7 +250,7 @@ public function test_display_express_checkout_buttons_all_disabled() {
ob_start();
$this->express_checkout_button_display_handler->display_express_checkout_buttons();
- $this->assertStringNotContainsString( 'wcpay-payment-request-wrapper', ob_get_contents() );
+ $this->assertStringNotContainsString( 'wcpay-express-checkout-wrapper', ob_get_contents() );
ob_end_clean();
}
@@ -287,10 +259,6 @@ public function test_display_express_checkout_buttons_only_woopay() {
->method( 'should_show_woopay_button' )
->willReturn( true );
- $this->mock_payment_request_button_handler
- ->method( 'should_show_payment_request_button' )
- ->willReturn( false );
-
$this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
@@ -299,28 +267,7 @@ public function test_display_express_checkout_buttons_only_woopay() {
$this->express_checkout_button_display_handler->display_express_checkout_buttons();
$this->assertStringContainsString( 'wcpay-woopay-button', ob_get_contents() );
- $this->assertStringNotContainsString( 'wcpay-payment-request-button-separator', ob_get_contents() );
- ob_end_clean();
- }
-
- public function test_display_express_checkout_buttons_only_payment_request() {
- $this->mock_woopay_button_handler
- ->method( 'should_show_woopay_button' )
- ->willReturn( false );
-
- $this->mock_payment_request_button_handler
- ->method( 'should_show_payment_request_button' )
- ->willReturn( true );
-
- $this->mock_express_checkout_helper
- ->method( 'is_checkout' )
- ->willReturn( true );
-
- ob_start();
- $this->express_checkout_button_display_handler->display_express_checkout_buttons();
-
- $this->assertStringContainsString( 'wcpay-express-checkout-button-separator', ob_get_contents() );
- $this->assertStringContainsString( 'display:none;', ob_get_contents() );
+ $this->assertStringNotContainsString( 'wcpay-express-checkout-button-separator', ob_get_contents() );
ob_end_clean();
}
}
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-helper.php b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-helper.php
similarity index 99%
rename from tests/unit/test-class-wc-payments-express-checkout-button-helper.php
rename to tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-helper.php
index 00176f20d07..bcc4ca69601 100644
--- a/tests/unit/test-class-wc-payments-express-checkout-button-helper.php
+++ b/tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-helper.php
@@ -11,7 +11,7 @@
use WCPay\Session_Rate_Limiter;
/**
- * WC_Payments_Payment_Request_Button_Handler_Test class.
+ * WC_Payments_Express_Checkout_Button_Helper_Test class.
*/
class WC_Payments_Express_Checkout_Button_Helper_Test extends WCPAY_UnitTestCase {
/**
diff --git a/tests/unit/test-class-wc-payments-account.php b/tests/unit/test-class-wc-payments-account.php
index 54ae7dede7e..f0087e3e966 100644
--- a/tests/unit/test-class-wc-payments-account.php
+++ b/tests/unit/test-class-wc-payments-account.php
@@ -257,6 +257,7 @@ public function test_maybe_handle_onboarding_connect_from_known_from(
$has_working_jetpack_connection,
$is_stripe_connected,
$create_test_drive_account,
+ $redirect_to_settings_page,
$expected_next_step
) {
@@ -278,9 +279,10 @@ public function test_maybe_handle_onboarding_connect_from_known_from(
$_GET['page'] = 'wc-admin';
$_GET['path'] = '/payments/some-bogus-page';
- $_GET['from'] = $onboarding_from;
- $_GET['source'] = $onboarding_source;
- $_GET['test_drive'] = $create_test_drive_account ? 'true' : null;
+ $_GET['from'] = $onboarding_from;
+ $_GET['source'] = $onboarding_source;
+ $_GET['test_drive'] = $create_test_drive_account ? 'true' : null;
+ $_GET['redirect_to_settings_page'] = $redirect_to_settings_page ? 'true' : null;
$this->mock_jetpack_connection( $has_working_jetpack_connection );
@@ -398,6 +400,18 @@ public function test_maybe_handle_onboarding_connect_from_known_from(
)
);
break;
+ case 'settings_page':
+ $this->mock_api_client
+ ->expects( $this->never() )
+ ->method( 'start_server_connection' );
+ $mock_redirect_service
+ ->expects( $this->once() )
+ ->method( 'redirect_to' )
+ ->with(
+ // It should redirect to settings page URL.
+ $this->stringContains( 'page=wc-settings&tab=checkout' ),
+ );
+ break;
default:
$this->fail( 'Unexpected redirect type: ' . $expected_next_step );
break;
@@ -431,6 +445,7 @@ public function provider_onboarding_known_froms() {
false,
true,
false,
+ false,
'start_jetpack_connection',
],
'From Woo Payments task - Jetpack connection, Stripe not connected' => [
@@ -439,6 +454,7 @@ public function provider_onboarding_known_froms() {
true,
false,
false,
+ false,
'onboarding_wizard',
],
'From Woo Payments task - Jetpack connection, Stripe connected' => [
@@ -447,6 +463,7 @@ public function provider_onboarding_known_froms() {
true,
true,
false,
+ false,
'overview_page',
],
'From Connect page - no Jetpack connection, Stripe connected' => [
@@ -455,6 +472,7 @@ public function provider_onboarding_known_froms() {
false,
true,
false,
+ false,
'start_jetpack_connection',
],
'From Connect page - Jetpack connection, Stripe not connected' => [
@@ -463,6 +481,7 @@ public function provider_onboarding_known_froms() {
true,
false,
false,
+ false,
'onboarding_wizard',
],
'From Connect page - Jetpack connection, Stripe connected' => [
@@ -471,6 +490,7 @@ public function provider_onboarding_known_froms() {
true,
true,
false,
+ false,
'overview_page',
],
'From Connect page - no Jetpack connection, Stripe connected - test-drive' => [
@@ -479,6 +499,7 @@ public function provider_onboarding_known_froms() {
false,
true,
true,
+ false,
'start_jetpack_connection',
],
'From Connect page - Jetpack connection, Stripe not connected - test-drive' => [
@@ -487,6 +508,7 @@ public function provider_onboarding_known_froms() {
true,
false,
true,
+ false,
'init_stripe_onboarding',
],
'From Connect page - Jetpack connection, Stripe connected - test-drive' => [
@@ -495,14 +517,25 @@ public function provider_onboarding_known_froms() {
true,
true,
true,
+ false,
'overview_page',
],
+ 'From Connect page - Jetpack connection, Stripe connected - test-drive, redirect to settings' => [
+ WC_Payments_Onboarding_Service::FROM_CONNECT_PAGE,
+ WC_Payments_Onboarding_Service::SOURCE_WCADMIN_SETTINGS_PAGE, // Some other original source.
+ true,
+ true,
+ true,
+ true,
+ 'settings_page',
+ ],
'From Woo Payments Settings - no Jetpack connection, Stripe connected' => [
WC_Payments_Onboarding_Service::FROM_WCADMIN_PAYMENTS_SETTINGS,
WC_Payments_Onboarding_Service::SOURCE_WCADMIN_SETTINGS_PAGE,
false,
true,
false,
+ false,
'connect_page',
],
'From Woo Payments Settings - Jetpack connection, Stripe not connected' => [
@@ -511,6 +544,7 @@ public function provider_onboarding_known_froms() {
true,
false,
false,
+ false,
'connect_page',
],
'From Woo Payments Settings - Jetpack connection, Stripe connected' => [
@@ -519,6 +553,7 @@ public function provider_onboarding_known_froms() {
true,
true,
false,
+ false,
'overview_page',
],
'From Incentive page - no Jetpack connection, Stripe connected' => [
@@ -527,6 +562,7 @@ public function provider_onboarding_known_froms() {
false,
true,
false,
+ false,
'start_jetpack_connection',
],
'From Incentive page - Jetpack connection, Stripe not connected' => [
@@ -535,6 +571,7 @@ public function provider_onboarding_known_froms() {
true,
false,
false,
+ false,
'onboarding_wizard',
],
'From Incentive page - Jetpack connection, Stripe connected' => [
@@ -543,6 +580,7 @@ public function provider_onboarding_known_froms() {
true,
true,
false,
+ false,
'overview_page',
],
// This is a weird scenario that should not happen under normal circumstances.
@@ -552,6 +590,7 @@ public function provider_onboarding_known_froms() {
false,
false,
false,
+ false,
'connect_page',
],
'From Onboarding wizard - Jetpack connection, Stripe not connected' => [
@@ -560,6 +599,7 @@ public function provider_onboarding_known_froms() {
true,
false,
false,
+ false,
'init_stripe_onboarding',
],
'From Onboarding wizard - Jetpack connection, Stripe connected' => [
@@ -568,6 +608,7 @@ public function provider_onboarding_known_froms() {
true,
true,
false,
+ false,
'overview_page',
],
];
diff --git a/tests/unit/test-class-wc-payments-features.php b/tests/unit/test-class-wc-payments-features.php
index fac4d7b37bc..d30ba6bec2a 100644
--- a/tests/unit/test-class-wc-payments-features.php
+++ b/tests/unit/test-class-wc-payments-features.php
@@ -29,7 +29,6 @@ class WC_Payments_Features_Test extends WCPAY_UnitTestCase {
'_wcpay_feature_customer_multi_currency' => 'multiCurrency',
'_wcpay_feature_documents' => 'documents',
'_wcpay_feature_auth_and_capture' => 'isAuthAndCaptureEnabled',
- '_wcpay_feature_stripe_ece' => 'isStripeEceEnabled',
];
public function set_up() {
diff --git a/tests/unit/test-class-wc-payments-order-service.php b/tests/unit/test-class-wc-payments-order-service.php
index d02681e42d9..d7c6ca45c0d 100644
--- a/tests/unit/test-class-wc-payments-order-service.php
+++ b/tests/unit/test-class-wc-payments-order-service.php
@@ -856,7 +856,7 @@ public function test_mark_payment_dispute_created() {
$this->assertStringContainsString( $amount, $notes[0]->content );
$this->assertStringContainsString( 'Product not received', $notes[0]->content );
$this->assertStringContainsString( $deadline, $notes[0]->content );
- $this->assertStringContainsString( '/payments/transactions/details&id=ch_123" target="_blank" rel="noopener noreferrer">Response due by', $notes[0]->content );
+ $this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">Response due by', $notes[0]->content );
// Assert: Check that order status change note was added.
$this->assertStringContainsString( 'Pending payment to On hold', $notes[1]->content );
@@ -910,7 +910,7 @@ public function test_mark_payment_dispute_closed_with_status_won() {
$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertStringContainsString( 'Pending payment to Completed', $notes[1]->content );
$this->assertStringContainsString( 'Payment dispute has been closed with status won', $notes[0]->content );
- $this->assertStringContainsString( '/payments/transactions/details&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );
+ $this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );
// Assert: Applying the same data multiple times does not cause duplicate actions.
$this->order_service->mark_payment_dispute_closed( $this->order, $charge_id, $status );
@@ -938,7 +938,7 @@ public function test_mark_payment_dispute_closed_with_status_lost() {
$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertStringContainsString( 'On hold to Refunded', $notes[1]->content );
$this->assertStringContainsString( 'Payment dispute has been closed with status lost', $notes[0]->content );
- $this->assertStringContainsString( '/payments/transactions/details&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );
+ $this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );
// Assert: Check for created refund, and the amount is correct.
$refunds = $this->order->get_refunds();
diff --git a/tests/unit/test-class-wc-payments-order-success-page.php b/tests/unit/test-class-wc-payments-order-success-page.php
index df92e94a482..849bcd61565 100644
--- a/tests/unit/test-class-wc-payments-order-success-page.php
+++ b/tests/unit/test-class-wc-payments-order-success-page.php
@@ -22,6 +22,60 @@ public function set_up() {
$this->payments_order_success_page = new WC_Payments_Order_Success_Page();
}
+ public function test_show_card_payment_method_name_without_card_brand() {
+ $order = WC_Helper_Order::create_order();
+ $order->set_payment_method( 'woocommerce_payments' );
+ $order->save();
+
+ $payment_method = $this->getMockBuilder( '\WCPay\Payment_Methods\UPE_Payment_Method' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $payment_method->method( 'get_title' )->willReturn( 'Credit Card' );
+
+ $result = $this->payments_order_success_page->show_card_payment_method_name( $order, $payment_method );
+
+ $this->assertEquals( 'Credit Card', $result );
+ }
+
+ public function test_show_card_payment_method_name_with_brand_and_last4() {
+ $order = WC_Helper_Order::create_order();
+ $order->add_meta_data( '_card_brand', 'visa' );
+ $order->add_meta_data( 'last4', '4242' );
+ $order->set_payment_method( 'woocommerce_payments' );
+ $order->save();
+
+ $payment_method = $this->getMockBuilder( '\WCPay\Payment_Methods\UPE_Payment_Method' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $payment_method->method( 'get_title' )->willReturn( 'Credit Card' );
+
+ $result = $this->payments_order_success_page->show_card_payment_method_name( $order, $payment_method );
+
+ $this->assertStringContainsString( 'wc-payment-gateway-method-logo-wrapper wc-payment-card-logo', $result );
+ $this->assertStringContainsString( 'img alt="Credit Card"', $result );
+ $this->assertStringContainsString( 'visa.svg', $result );
+ $this->assertStringContainsString( '4242', $result );
+ }
+
+ public function test_show_card_payment_method_name_with_brand_only() {
+ $order = WC_Helper_Order::create_order();
+ $order->add_meta_data( '_card_brand', 'mastercard' );
+ $order->set_payment_method( 'woocommerce_payments' );
+ $order->save();
+
+ $payment_method = $this->getMockBuilder( '\WCPay\Payment_Methods\UPE_Payment_Method' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $payment_method->method( 'get_title' )->willReturn( 'Credit Card' );
+
+ $result = $this->payments_order_success_page->show_card_payment_method_name( $order, $payment_method );
+
+ $this->assertStringContainsString( 'wc-payment-gateway-method-logo-wrapper wc-payment-card-logo', $result );
+ $this->assertStringContainsString( 'img alt="Credit Card"', $result );
+ $this->assertStringContainsString( 'mastercard.svg', $result );
+ $this->assertStringNotContainsString( '•••', $result );
+ }
+
public function test_show_woopay_payment_method_name_empty_order() {
$method_name = 'Credit card';
$result = $this->payments_order_success_page->show_woocommerce_payments_payment_method_name( $method_name, null );
diff --git a/tests/unit/test-class-wc-payments-payment-request-button-handler.php b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
index 117f254f5ff..28bfdfb064e 100644
--- a/tests/unit/test-class-wc-payments-payment-request-button-handler.php
+++ b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
@@ -13,6 +13,7 @@
/**
* WC_Payments_Payment_Request_Button_Handler_Test class.
+ * @deprecated We'll delete this as part of https://github.com/Automattic/woocommerce-payments/issues/9722 .
*/
class WC_Payments_Payment_Request_Button_Handler_Test extends WCPAY_UnitTestCase {
const SHIPPING_ADDRESS = [
@@ -157,7 +158,6 @@ function () {
WC()->session->init();
WC()->cart->add_to_cart( $this->simple_product->get_id(), 1 );
- $this->pr->update_shipping_method( [ self::get_shipping_option_rate_id( $this->flat_rate_id ) ] );
WC()->cart->calculate_totals();
}
@@ -245,24 +245,6 @@ private static function set_shipping_method_cost( $instance_id, $cost ) {
update_option( $option_key, $options );
}
- /**
- * Composes shipping option object by shipping method instance id.
- *
- * @param string $instance_id Shipping method instance id.
- *
- * @return array Shipping option.
- */
- private static function get_shipping_option( $instance_id ) {
- $method = WC_Shipping_Zones::get_shipping_method( $instance_id );
-
- return [
- 'id' => $method->get_rate_id(),
- 'label' => $method->title,
- 'detail' => '',
- 'amount' => WC_Payments_Utils::prepare_amount( $method->get_instance_option( 'cost' ) ),
- ];
- }
-
/**
* Retrieves rate id by shipping method instance id.
*
@@ -276,185 +258,6 @@ private static function get_shipping_option_rate_id( $instance_id ) {
return $method->get_rate_id();
}
- public function test_tokenized_cart_address_avoid_normalization_when_missing_header() {
- $request = new WP_REST_Request();
- $request->set_header( 'X-WooPayments-Tokenized-Cart', null );
- $request->set_header( 'Content-Type', 'application/json' );
- $request->set_param(
- 'shipping_address',
- [
- 'country' => 'US',
- 'state' => 'California',
- ]
- );
-
- $this->pr->tokenized_cart_store_api_address_normalization( null, null, $request );
-
- $shipping_address = $request->get_param( 'shipping_address' );
-
- $this->assertSame( 'California', $shipping_address['state'] );
- }
-
- public function test_tokenized_cart_address_avoid_normalization_when_wrong_nonce() {
- $request = new WP_REST_Request();
- $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', 'invalid-nonce' );
- $request->set_header( 'Content-Type', 'application/json' );
- $request->set_param(
- 'shipping_address',
- [
- 'country' => 'US',
- 'state' => 'California',
- ]
- );
-
- $this->pr->tokenized_cart_store_api_address_normalization( null, null, $request );
-
- $shipping_address = $request->get_param( 'shipping_address' );
-
- $this->assertSame( 'California', $shipping_address['state'] );
- }
-
- public function test_tokenized_cart_address_state_normalization() {
- $request = new WP_REST_Request();
- $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
- $request->set_header( 'Content-Type', 'application/json' );
- $request->set_param(
- 'shipping_address',
- [
- 'country' => 'US',
- 'state' => 'California',
- ]
- );
- $request->set_param(
- 'billing_address',
- [
- 'country' => 'CA',
- 'state' => 'Colombie-Britannique',
- ]
- );
-
- $this->pr->tokenized_cart_store_api_address_normalization( null, null, $request );
-
- $shipping_address = $request->get_param( 'shipping_address' );
- $billing_address = $request->get_param( 'billing_address' );
-
- $this->assertSame( 'CA', $shipping_address['state'] );
- $this->assertSame( 'BC', $billing_address['state'] );
- }
-
- public function test_tokenized_cart_address_postcode_normalization() {
- $request = new WP_REST_Request();
- $request->set_route( '/wc/store/v1/cart/update-customer' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
- $request->set_header( 'Content-Type', 'application/json' );
- $request->set_param(
- 'shipping_address',
- [
- 'country' => 'CA',
- 'postcode' => 'H3B',
- ]
- );
- $request->set_param(
- 'billing_address',
- [
- 'country' => 'US',
- 'postcode' => '90210',
- ]
- );
-
- $this->pr->tokenized_cart_store_api_address_normalization( null, null, $request );
-
- $shipping_address = $request->get_param( 'shipping_address' );
- $billing_address = $request->get_param( 'billing_address' );
-
- // this should be modified.
- $this->assertSame( 'H3B000', $shipping_address['postcode'] );
- // this shouldn't be modified.
- $this->assertSame( '90210', $billing_address['postcode'] );
- }
-
- public function test_tokenized_cart_avoid_address_postcode_normalization_if_route_incorrect() {
- $request = new WP_REST_Request();
- $request->set_route( '/wc/store/v1/checkout' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart', 'true' );
- $request->set_header( 'X-WooPayments-Tokenized-Cart-Nonce', wp_create_nonce( 'woopayments_tokenized_cart_nonce' ) );
- $request->set_header( 'Content-Type', 'application/json' );
- $request->set_param(
- 'shipping_address',
- [
- 'country' => 'CA',
- 'postcode' => 'H3B',
- 'state' => 'Colombie-Britannique',
- ]
- );
- $request->set_param(
- 'billing_address',
- [
- 'country' => 'CA',
- 'postcode' => 'H3B',
- 'state' => 'Colombie-Britannique',
- ]
- );
-
- $this->pr->tokenized_cart_store_api_address_normalization( null, null, $request );
-
- $shipping_address = $request->get_param( 'shipping_address' );
- $billing_address = $request->get_param( 'billing_address' );
-
- // this should be modified.
- $this->assertSame( 'BC', $shipping_address['state'] );
- $this->assertSame( 'BC', $billing_address['state'] );
- // this shouldn't be modified.
- $this->assertSame( 'H3B', $shipping_address['postcode'] );
- $this->assertSame( 'H3B', $billing_address['postcode'] );
- }
-
- public function test_get_shipping_options_returns_shipping_options() {
- $data = $this->pr->get_shipping_options( self::SHIPPING_ADDRESS );
-
- $expected_shipping_options = array_map(
- 'self::get_shipping_option',
- [ $this->flat_rate_id, $this->local_pickup_id ]
- );
-
- $this->assertEquals( 'success', $data['result'] );
- $this->assertEquals( $expected_shipping_options, $data['shipping_options'], 'Shipping options mismatch' );
- }
-
- public function test_get_shipping_options_returns_chosen_option() {
- $data = $this->pr->get_shipping_options( self::SHIPPING_ADDRESS );
-
- $flat_rate = $this->get_shipping_option( $this->flat_rate_id );
- $expected_display_items = [
- [
- 'label' => 'Shipping',
- 'amount' => $flat_rate['amount'],
- 'key' => 'total_shipping',
- ],
- ];
-
- $this->assertEquals( 1500, $data['total']['amount'], 'Total amount mismatch' );
- $this->assertEquals( $expected_display_items, $data['displayItems'], 'Display items mismatch' );
- }
-
- public function test_get_shipping_options_keeps_chosen_option() {
- $method_id = self::get_shipping_option_rate_id( $this->local_pickup_id );
- $this->pr->update_shipping_method( [ $method_id ] );
-
- $data = $this->pr->get_shipping_options( self::SHIPPING_ADDRESS );
-
- $expected_shipping_options = array_map(
- 'self::get_shipping_option',
- [ $this->local_pickup_id, $this->flat_rate_id ]
- );
-
- $this->assertEquals( 'success', $data['result'] );
- $this->assertEquals( $expected_shipping_options, $data['shipping_options'], 'Shipping options mismatch' );
- }
-
public function test_multiple_packages_in_cart_not_allowed() {
// Add fake packages to the cart.
add_filter(
@@ -755,10 +558,6 @@ public function test_get_product_data_returns_the_same_as_build_display_items_wi
->method( 'get_product' )
->willReturn( $this->simple_product );
- $mock_pr = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
- ->setConstructorArgs( [ $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper ] )
- ->getMock();
-
$get_product_data_result = $this->pr->get_product_data();
foreach ( $get_product_data_result['displayItems'] as $key => $display_item ) {
diff --git a/tests/unit/test-class-wc-payments-redirect-service.php b/tests/unit/test-class-wc-payments-redirect-service.php
index 931d0e18102..2d2a8173d9a 100644
--- a/tests/unit/test-class-wc-payments-redirect-service.php
+++ b/tests/unit/test-class-wc-payments-redirect-service.php
@@ -268,4 +268,15 @@ public function test_redirect_to_connect_page_redirects_with_additional_params()
// Act.
$this->redirect_service->redirect_to_connect_page( null, null, [ 'source' => 'some-source' ] );
}
+
+ public function test_redirect_to_settings_page_redirects() {
+ // Assert.
+ $this->redirect_service
+ ->expects( $this->once() )
+ ->method( 'redirect_to' )
+ ->with( admin_url( 'admin.php?page=wc-settings&tab=checkout' ) );
+
+ // Act.
+ $this->redirect_service->redirect_to_settings_page();
+ }
}
diff --git a/tests/unit/test-class-wc-payments-webhook-processing-service.php b/tests/unit/test-class-wc-payments-webhook-processing-service.php
index bf58120532c..d376b1491fd 100644
--- a/tests/unit/test-class-wc-payments-webhook-processing-service.php
+++ b/tests/unit/test-class-wc-payments-webhook-processing-service.php
@@ -1733,4 +1733,59 @@ public function provider_mode_mismatch_detection() {
'No mode proceeds' => [ null, $this->once() ],
];
}
+
+ public function test_process_throws_exception_when_order_not_found_for_successful_intent_id() {
+ $this->event_body['type'] = 'payment_intent.succeeded';
+ $this->event_body['data']['object'] = [
+ 'id' => 'unresolvable_intent_id',
+ 'currency' => 'usd',
+ 'metadata' => [],
+ 'charges' => [
+ 'data' => [],
+ ],
+ ];
+
+ $this->mock_db_wrapper
+ ->expects( $this->once() )
+ ->method( 'order_from_intent_id' )
+ ->with( 'unresolvable_intent_id' )
+ ->willReturn( null );
+
+ $this->mock_order
+ ->expects( $this->never() )
+ ->method( 'save' );
+
+ $this->expectException( WCPay\Exceptions\Invalid_Payment_Method_Exception::class );
+ $this->expectExceptionMessage( 'Could not find order via intent ID: unresolvable_intent_id' );
+
+ $this->webhook_processing_service->process( $this->event_body );
+ }
+
+ public function test_process_throws_exception_when_refund_found_for_successful_intent_id() {
+ $mock_refund = $this->createMock( WC_Order_Refund::class );
+ $this->event_body['type'] = 'payment_intent.succeeded';
+ $this->event_body['data']['object'] = [
+ 'id' => 'intent_id',
+ 'currency' => 'usd',
+ 'metadata' => [],
+ 'charges' => [
+ 'data' => [],
+ ],
+ ];
+
+ $this->mock_db_wrapper
+ ->expects( $this->once() )
+ ->method( 'order_from_intent_id' )
+ ->with( 'intent_id' )
+ ->willReturn( $mock_refund );
+
+ $mock_refund
+ ->expects( $this->never() )
+ ->method( 'save' );
+
+ $this->expectException( WCPay\Exceptions\Invalid_Payment_Method_Exception::class );
+ $this->expectExceptionMessage( 'Could not find order via intent ID: intent_id' );
+
+ $this->webhook_processing_service->process( $this->event_body );
+ }
}
diff --git a/webpack/shared.js b/webpack/shared.js
index 7fe200a9f7a..2dce99ca3ec 100644
--- a/webpack/shared.js
+++ b/webpack/shared.js
@@ -20,9 +20,8 @@ module.exports = {
cart: './client/cart/index.js',
checkout: './client/checkout/classic/event-handlers.js',
'express-checkout': './client/express-checkout/index.js',
- 'payment-request': './client/payment-request/index.js',
- 'tokenized-payment-request':
- './client/tokenized-payment-request/index.js',
+ 'tokenized-express-checkout':
+ './client/tokenized-express-checkout/index.js',
'subscription-edit-page': './client/subscription-edit-page.js',
tos: './client/tos/index.js',
'payment-gateways': './client/payment-gateways/index.js',
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index f57ce075405..19012d26053 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -11,7 +11,7 @@
* WC tested up to: 9.4.0
* Requires at least: 6.0
* Requires PHP: 7.3
- * Version: 8.5.1
+ * Version: 8.6.0
* Requires Plugins: woocommerce
*
* @package WooCommerce\Payments
@@ -154,7 +154,7 @@ function wcpay_init() {
* Check https://github.com/Automattic/woocommerce-payments/issues/4759
*/
\WCPay\WooPay\WooPay_Session::init();
- if ( WC_Payments_Features::is_tokenized_cart_prb_enabled() ) {
+ if ( WC_Payments_Features::is_tokenized_cart_ece_enabled() ) {
( new WC_Payments_Payment_Request_Session() )->init();
}
}