From 60f7e868a0453fdfac55061476b01c837740405f Mon Sep 17 00:00:00 2001 From: Anurag Bhandari Date: Thu, 28 Dec 2023 17:38:29 +0530 Subject: [PATCH 1/8] Bump WC tested up to version to 8.4.0 (#7943) --- changelog/dev-bump-wc-version-8-4-0 | 4 ++++ woocommerce-payments.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelog/dev-bump-wc-version-8-4-0 diff --git a/changelog/dev-bump-wc-version-8-4-0 b/changelog/dev-bump-wc-version-8-4-0 new file mode 100644 index 00000000000..5c00289cc5b --- /dev/null +++ b/changelog/dev-bump-wc-version-8-4-0 @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Bump WC tested up to version to 8.4.0. \ No newline at end of file diff --git a/woocommerce-payments.php b/woocommerce-payments.php index df1a348ec90..df7afe47766 100644 --- a/woocommerce-payments.php +++ b/woocommerce-payments.php @@ -9,7 +9,7 @@ * Text Domain: woocommerce-payments * Domain Path: /languages * WC requires at least: 7.6 - * WC tested up to: 8.3.1 + * WC tested up to: 8.4.0 * Requires at least: 6.0 * Requires PHP: 7.3 * Version: 6.9.2 From 62c69cbe63b6987394f88363b5b97efefc09e206 Mon Sep 17 00:00:00 2001 From: Timur Karimov Date: Fri, 29 Dec 2023 11:06:30 +0100 Subject: [PATCH 2/8] Consolidate gateways implementation - step II (#7944) Co-authored-by: Timur Karimov Co-authored-by: Timur Karimov --- changelog/cleanup-upe-gateways-II | 4 + client/checkout/api/index.js | 33 - includes/class-wc-payment-gateway-wcpay.php | 815 +++++++++++- includes/class-wc-payments-checkout.php | 18 +- ...ments-payment-method-messaging-element.php | 8 +- includes/class-wc-payments.php | 99 +- .../class-upe-payment-gateway.php | 1138 ----------------- src/Internal/Payment/State/ProcessedState.php | 2 +- ...s-wc-rest-payments-settings-controller.php | 174 +-- ...-class-wc-rest-payments-tos-controller.php | 4 + .../test-class-upe-payment-gateway.php | 329 +---- .../test-class-upe-split-payment-gateway.php | 325 +---- .../Payment/State/ProcessedStateTest.php | 2 +- ...wc-payment-gateway-wcpay-payment-types.php | 7 +- ...-payment-gateway-wcpay-process-payment.php | 11 +- ...c-payment-gateway-wcpay-process-refund.php | 4 + ...ubscriptions-payment-method-order-note.php | 12 +- ...ay-wcpay-subscriptions-process-payment.php | 10 +- ...wc-payment-gateway-wcpay-subscriptions.php | 26 + .../test-class-wc-payment-gateway-wcpay.php | 11 +- .../unit/test-class-wc-payments-checkout.php | 13 +- ...xpress-checkout-button-display-handler.php | 4 + ...ayments-payment-request-button-handler.php | 4 + ...lass-wc-payments-woopay-button-handler.php | 4 + tests/unit/test-class-wc-payments.php | 5 +- 25 files changed, 1016 insertions(+), 2046 deletions(-) create mode 100644 changelog/cleanup-upe-gateways-II delete mode 100644 includes/payment-methods/class-upe-payment-gateway.php diff --git a/changelog/cleanup-upe-gateways-II b/changelog/cleanup-upe-gateways-II new file mode 100644 index 00000000000..16f3e3cd17f --- /dev/null +++ b/changelog/cleanup-upe-gateways-II @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Cleanup the deprecated payment gateway processing - part VI diff --git a/client/checkout/api/index.js b/client/checkout/api/index.js index 9ecdf245b62..9b05ea40a26 100644 --- a/client/checkout/api/index.js +++ b/client/checkout/api/index.js @@ -440,39 +440,6 @@ export default class WCPayAPI { } ); } - /** - * Process checkout and update payment intent via AJAX. - * - * @param {string} paymentIntentId ID of payment intent to be updated. - * @param {Object} fields Checkout fields. - * @param {string} fingerprint User fingerprint. - * @return {Promise} Promise containing redirect URL for UPE element. - */ - processCheckout( paymentIntentId, fields, fingerprint ) { - return this.request( - buildAjaxURL( getConfig( 'wcAjaxUrl' ), 'checkout', '' ), - { - ...fields, - wc_payment_intent_id: paymentIntentId, - 'wcpay-fingerprint': fingerprint, - } - ) - .then( ( response ) => { - if ( response.result === 'failure' ) { - throw new Error( response.messages ); - } - return response; - } ) - .catch( ( error ) => { - if ( error.message ) { - throw error; - } else { - // Covers the case of error on the Ajaxrequest. - throw new Error( error.statusText ); - } - } ); - } - /** * Submits shipping address to get available shipping options * from Payment Request button. diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 0348466cf19..32910b60cad 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -17,7 +17,7 @@ use WCPay\Constants\Intent_Status; use WCPay\Constants\Payment_Type; use WCPay\Constants\Payment_Method; -use WCPay\Exceptions\{ Add_Payment_Method_Exception, Amount_Too_Small_Exception, Process_Payment_Exception, Intent_Authentication_Exception, API_Exception }; +use WCPay\Exceptions\{ Add_Payment_Method_Exception, Amount_Too_Small_Exception, Process_Payment_Exception, Intent_Authentication_Exception, API_Exception, Invalid_Address_Exception}; use WCPay\Core\Server\Request\Cancel_Intention; use WCPay\Core\Server\Request\Capture_Intention; use WCPay\Core\Server\Request\Create_And_Confirm_Intention; @@ -36,7 +36,6 @@ use WCPay\Internal\Service\DuplicatePaymentPreventionService; use WCPay\Logger; use WCPay\Payment_Information; -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\Payment_Methods\Link_Payment_Method; use WCPay\WooPay\WooPay_Order_Status_Sync; use WCPay\WooPay\WooPay_Utilities; @@ -48,6 +47,19 @@ use WCPay\Internal\Payment\State\CompletedState; use WCPay\Internal\Service\Level3Service; use WCPay\Internal\Service\OrderService; +use WCPay\Payment_Methods\Affirm_Payment_Method; +use WCPay\Payment_Methods\Afterpay_Payment_Method; +use WCPay\Payment_Methods\Bancontact_Payment_Method; +use WCPay\Payment_Methods\Becs_Payment_Method; +use WCPay\Payment_Methods\CC_Payment_Method; +use WCPay\Payment_Methods\Eps_Payment_Method; +use WCPay\Payment_Methods\Giropay_Payment_Method; +use WCPay\Payment_Methods\Ideal_Payment_Method; +use WCPay\Payment_Methods\Klarna_Payment_Method; +use WCPay\Payment_Methods\P24_Payment_Method; +use WCPay\Payment_Methods\Sepa_Payment_Method; +use WCPay\Payment_Methods\Sofort_Payment_Method; +use WCPay\Payment_Methods\UPE_Payment_Method; /** * Gateway class for WooPayments @@ -101,6 +113,10 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC { const USER_FORMATTED_TOKENS_LIMIT = 100; + const PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE = 'upe_process_redirect_order_id_mismatched'; + const UPE_APPEARANCE_TRANSIENT = 'wcpay_upe_appearance'; + const WC_BLOCKS_UPE_APPEARANCE_TRANSIENT = 'wcpay_wc_blocks_upe_appearance'; + /** * Client for making requests to the WooCommerce Payments API * @@ -185,6 +201,27 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC { */ protected $fraud_service; + /** + * UPE Payment Method for gateway. + * + * @var UPE_Payment_Method + */ + protected $payment_method; + + /** + * Array mapping payment method string IDs to classes + * + * @var UPE_Payment_Method[] + */ + protected $payment_methods = []; + + /** + * Stripe payment method type ID. + * + * @var string + */ + protected $stripe_id; + /** * WC_Payment_Gateway_WCPay constructor. * @@ -193,6 +230,8 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC { * @param WC_Payments_Customer_Service $customer_service - Customer class instance. * @param WC_Payments_Token_Service $token_service - Token class instance. * @param WC_Payments_Action_Scheduler_Service $action_scheduler_service - Action Scheduler service instance. + * @param UPE_Payment_Method $payment_method - Specific UPE_Payment_Method instance for gateway. + * @param array $payment_methods - Array of UPE payment methods. * @param Session_Rate_Limiter|null $failed_transaction_rate_limiter - Rate Limiter for failed transactions. * @param WC_Payments_Order_Service $order_service - Order class instance. * @param Duplicate_Payment_Prevention_Service $duplicate_payment_prevention_service - Service for preventing duplicate payments. @@ -205,12 +244,18 @@ public function __construct( WC_Payments_Customer_Service $customer_service, WC_Payments_Token_Service $token_service, WC_Payments_Action_Scheduler_Service $action_scheduler_service, + UPE_Payment_Method $payment_method, + array $payment_methods, Session_Rate_Limiter $failed_transaction_rate_limiter = null, WC_Payments_Order_Service $order_service, Duplicate_Payment_Prevention_Service $duplicate_payment_prevention_service, WC_Payments_Localization_Service $localization_service, WC_Payments_Fraud_Service $fraud_service ) { + $this->payment_methods = $payment_methods; + $this->payment_method = $payment_method; + $this->stripe_id = $payment_method->get_id(); + $this->payments_api_client = $payments_api_client; $this->account = $account; $this->customer_service = $customer_service; @@ -223,18 +268,23 @@ public function __construct( $this->fraud_service = $fraud_service; $this->id = static::GATEWAY_ID; - $this->icon = plugins_url( 'assets/images/payment-methods/cc.svg', WCPAY_PLUGIN_FILE ); + $this->icon = $payment_method->get_icon(); $this->has_fields = true; $this->method_title = 'WooPayments'; - $this->method_description = $this->get_method_description(); + $this->method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' ); - $this->title = __( 'Credit card / debit card', 'woocommerce-payments' ); - $this->description = __( 'Enter your card details', 'woocommerce-payments' ); + $this->title = $payment_method->get_title(); + $this->description = ''; $this->supports = [ 'products', 'refunds', ]; + if ( 'card' !== $this->stripe_id ) { + $this->id = self::GATEWAY_ID . '_' . $this->stripe_id; + $this->method_title = "WooPayments ($this->title)"; + } + // Define setting fields. $this->form_fields = [ 'enabled' => [ @@ -475,6 +525,95 @@ public function init_hooks() { $this->maybe_init_subscriptions_hooks(); } + /** + * Displays HTML tags for WC payment gateway radio button content. + */ + public function display_gateway_html() { + ?> +
+ get_selected_stripe_payment_type_id() ); + do_action( 'wc_payments_add_upe_payment_fields' ); + } + + /** + * Adds a token to current user from a setup intent id. + * + * @param string $setup_intent_id ID of the setup intent. + * @param WP_User $user User to add token to. + * + * @return WC_Payment_Token_CC|WC_Payment_Token_WCPay_SEPA|null The added token. + */ + public function create_token_from_setup_intent( $setup_intent_id, $user ) { + try { + $setup_intent_request = Get_Setup_Intention::create( $setup_intent_id ); + /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort + $setup_intent = $setup_intent_request->send(); + + $payment_method_id = $setup_intent->get_payment_method_id(); + // TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type. + // Leaving 'card' as a hardcoded value for now to avoid the extra API call. + // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced. + $payment_method = $this->payment_method; + + return $payment_method->get_payment_token_for_user( $user, $payment_method_id ); + } catch ( Exception $e ) { + wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error', [ 'icon' => 'error' ] ); + Logger::log( 'Error when adding payment method: ' . $e->getMessage() ); + } + } + + /** + * Validate order_id received from the request vs value saved in the intent metadata. + * Throw an exception if they're not matched. + * + * @param WC_Order $order The received order to process. + * @param array $intent_metadata The metadata of attached intent to the order. + * + * @return void + * @throws Process_Payment_Exception + */ + private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $order, array $intent_metadata ): void { + $intent_meta_order_id_raw = $intent_metadata['order_id'] ?? ''; + $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0; + + if ( $order->get_id() !== $intent_meta_order_id ) { + Logger::error( + sprintf( + 'UPE Process Redirect Payment - Order ID mismatched. Received: %1$d. Intent Metadata Value: %2$d', + $order->get_id(), + $intent_meta_order_id + ) + ); + + throw new Process_Payment_Exception( + __( "We're not able to process this payment due to the order ID mismatch. Please try again later.", 'woocommerce-payments' ), + self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE + ); + } + } + + /** + * Gets payment method settings to pass to client scripts + * + * @deprecated 5.0.0 + * + * @return array + */ + private function get_enabled_payment_method_config() { + wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' ); + return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config(); + } + + /** * If we're in a WooPay preflight check, remove all the checkout order processed * actions to prevent reduce available resources quantity. @@ -575,6 +714,10 @@ public function needs_https_setup() { * @return bool Whether the gateway is enabled and ready to accept payments. */ public function is_available() { + $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ]; + if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) { + return false; + } // Disable the gateway if using live mode without HTTPS set up or the currency is not // available in the country of the account. if ( $this->needs_https_setup() || ! $this->is_available_for_current_currency() ) { @@ -683,6 +826,59 @@ public function output_payments_settings_screen() { endif; } + /** + * Log payment errors on Checkout. + * + * @throws Exception If nonce is not present or invalid or charge ID is empty or order not found. + */ + public function log_payment_error_ajax() { + try { + $is_nonce_valid = check_ajax_referer( 'wcpay_log_payment_error_nonce', false, false ); + if ( ! $is_nonce_valid ) { + throw new Exception( 'Invalid request.' ); + } + + $charge_id = isset( $_POST['charge_id'] ) ? wc_clean( wp_unslash( $_POST['charge_id'] ) ) : ''; + if ( empty( $charge_id ) ) { + throw new Exception( 'Charge ID cannot be empty.' ); + } + + // Get charge data from WCPay Server. + $request = Get_Charge::create( $charge_id ); + $request->set_hook_args( $charge_id ); + $charge_data = $request->send(); + $order_id = $charge_data['metadata']['order_id']; + + // Validate Order ID and proceed with logging errors and updating order status. + $order = wc_get_order( $order_id ); + if ( ! $order ) { + throw new Exception( 'Order not found. Unable to log error.' ); + } + + $intent_id = $charge_data['payment_intent'] ?? $order->get_meta( '_intent_id' ); + + $request = Get_Intention::create( $intent_id ); + $request->set_hook_args( $order ); + $intent = $request->send(); + + $intent_status = $intent->get_status(); + $error_message = esc_html( rtrim( $charge_data['failure_message'], '.' ) ); + + $this->order_service->mark_payment_failed( $order, $intent_id, $intent_status, $charge_id, $error_message ); + + wp_send_json_success(); + } catch ( Exception $e ) { + wp_send_json_error( + [ + 'error' => [ + 'message' => WC_Payments_Utils::get_filtered_error_message( $e ), + ], + ], + WC_Payments_Utils::get_filtered_error_status_code( $e ), + ); + } + } + /** * Displays the save to account checkbox. * @@ -709,6 +905,10 @@ public function save_payment_method_checkbox( $force_checked = false ) { * @return bool */ public function should_use_stripe_platform_on_checkout_page() { + if ( 'card' !== $this->stripe_id ) { + return false; + } + if ( WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->get_option( 'platform_checkout', 'no' ) && @@ -1527,15 +1727,228 @@ public function process_payment_for_order( $cart, $payment_information, $schedul ]; } + /** + * Check for a redirect payment method on order received page or setup intent on payment methods page. + */ + public function maybe_process_upe_redirect() { + if ( $this->is_payment_methods_page() ) { + // If a payment method was added using UPE, we need to clear the cache and notify the user. + if ( $this->is_setup_intent_success_creation_redirection() ) { + wc_add_notice( __( 'Payment method successfully added.', 'woocommerce-payments' ) ); + $user = wp_get_current_user(); + $this->customer_service->clear_cached_payment_methods_for_user( $user->ID ); + } + return; + } + + if ( ! is_order_received_page() ) { + return; + } + + $payment_method = isset( $_GET['wc_payment_method'] ) ? wc_clean( wp_unslash( $_GET['wc_payment_method'] ) ) : ''; + if ( self::GATEWAY_ID !== $payment_method ) { + return; + } + + $is_nonce_valid = check_admin_referer( 'wcpay_process_redirect_order_nonce' ); + if ( ! $is_nonce_valid || empty( $_GET['wc_payment_method'] ) ) { + return; + } + + if ( ! empty( $_GET['payment_intent_client_secret'] ) ) { + $intent_id_from_request = isset( $_GET['payment_intent'] ) ? wc_clean( wp_unslash( $_GET['payment_intent'] ) ) : ''; + } elseif ( ! empty( $_GET['setup_intent_client_secret'] ) ) { + $intent_id_from_request = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : ''; + } else { + return; + } + + $order_id = absint( get_query_var( 'order-received' ) ); + $order_key_from_request = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; + $save_payment_method = isset( $_GET['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_GET['save_payment_method'] ) ) : false; + + if ( empty( $intent_id_from_request ) || empty( $order_id ) || empty( $order_key_from_request ) ) { + return; + } + + $order = wc_get_order( $order_id ); + + if ( ! is_a( $order, 'WC_Order' ) ) { + // the ID of non-existing order was passed in. + return; + } + + if ( $order->get_order_key() !== $order_key_from_request ) { + // Valid return url should have matching order key. + return; + } + + // Perform additional checks for non-zero-amount. For zero-amount orders, we can't compare intents because they are not attached to the order at this stage. + // Once https://github.com/Automattic/woocommerce-payments/issues/6575 is closed, this check can be applied for zero-amount orders as well. + if ( $order->get_total() > 0 && ! $this->is_proper_intent_used_with_order( $order, $intent_id_from_request ) ) { + return; + } + + $this->process_redirect_payment( $order, $intent_id_from_request, $save_payment_method ); + } + /** - * The parent method which allows to modify the child class implementation, while supporting the current design where the parent process_payment method is called from the child class. - * Mandate must be shown and acknowledged under certain conditions for Stripe Link and SEPA. - * Since WC_Payment_Gateway_WCPay represents card payment, which does not require mandate, we return false. + * Processes redirect payments. + * + * @param WC_Order $order The order being processed. + * @param string $intent_id The Stripe setup/payment intent ID for the order payment. + * @param bool $save_payment_method Boolean representing whether payment method for order should be saved. * - * @return boolean False since card payment does not require mandate. + * @throws Process_Payment_Exception When the payment intent has an error. */ - protected function is_mandate_data_required() { - return false; + public function process_redirect_payment( $order, $intent_id, $save_payment_method ) { + try { + $order_id = $order->get_id(); + if ( $order->has_status( + [ + Order_Status::PROCESSING, + Order_Status::COMPLETED, + Order_Status::ON_HOLD, + ] + ) ) { + return; + } + + Logger::log( "Begin processing UPE redirect payment for order {$order_id} for the amount of {$order->get_total()}" ); + + // Get user/customer for order. + list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order ); + + $payment_needed = 0 < $order->get_total(); + + // Get payment intent to confirm status. + if ( $payment_needed ) { + $request = Get_Intention::create( $intent_id ); + $request->set_hook_args( $order ); + /** @var WC_Payments_API_Payment_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort + $intent = $request->send(); + $client_secret = $intent->get_client_secret(); + $status = $intent->get_status(); + $charge = $intent->get_charge(); + $charge_id = $charge ? $charge->get_id() : null; + $currency = $intent->get_currency(); + $payment_method_id = $intent->get_payment_method_id(); + $payment_method_details = $charge ? $charge->get_payment_method_details() : []; + $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details ); + $error = $intent->get_last_payment_error(); + + // This check applies to payment intents only due to two reasons: + // (1) metadata is missed for setup intents. See https://github.com/Automattic/woocommerce-payments/issues/6575. + // (2) most issues so far affect only payment intents. + $intent_metadata = is_array( $intent->get_metadata() ) ? $intent->get_metadata() : []; + $this->validate_order_id_received_vs_intent_meta_order_id( $order, $intent_metadata ); + } else { + $request = Get_Setup_Intention::create( $intent_id ); + /** @var WC_Payments_API_Setup_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort + $intent = $request->send(); + $client_secret = $intent->get_client_secret(); + $status = $intent->get_status(); + $charge_id = ''; + $charge = null; + $currency = $order->get_currency(); + $payment_method_id = $intent->get_payment_method_id(); + $payment_method_details = false; + $payment_method_type = $intent->get_payment_method_type(); + $error = $intent->get_last_setup_error(); + } + + if ( ! empty( $error ) ) { + Logger::log( 'Error when processing payment: ' . $error['message'] ); + throw new Process_Payment_Exception( + __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ), + 'upe_payment_intent_error' + ); + } else { + $payment_method = $this->get_selected_payment_method( $payment_method_type ); + if ( ! $payment_method ) { + return; + } + + if ( $save_payment_method && $payment_method->is_reusable() ) { + try { + $token = $payment_method->get_payment_token_for_user( $user, $payment_method_id ); + $this->add_token_to_order( $order, $token ); + } catch ( Exception $e ) { + // If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow. + Logger::log( 'Error when saving payment method: ' . $e->getMessage() ); + } + } + + $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method_id, $customer_id, $charge_id, $currency ); + $this->attach_exchange_info_to_order( $order, $charge_id ); + if ( Intent_Status::SUCCEEDED === $status ) { + $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() ); + } + $this->order_service->update_order_status_from_intent( $order, $intent ); + $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ); + $this->order_service->attach_transaction_fee_to_order( $order, $charge ); + + if ( Intent_Status::REQUIRES_ACTION === $status ) { + // I don't think this case should be possible, but just in case... + $next_action = $intent->get_next_action(); + if ( isset( $next_action['type'] ) && 'redirect_to_url' === $next_action['type'] && ! empty( $next_action['redirect_to_url']['url'] ) ) { + wp_safe_redirect( $next_action['redirect_to_url']['url'] ); + exit; + } else { + $redirect_url = sprintf( + '#wcpay-confirm-%s:%s:%s:%s', + $payment_needed ? 'pi' : 'si', + $order_id, + WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $client_secret ), + wp_create_nonce( 'wcpay_update_order_status_nonce' ) + ); + wp_safe_redirect( $redirect_url ); + exit; + } + } + } + } catch ( Exception $e ) { + Logger::log( 'Error: ' . $e->getMessage() ); + + $is_order_id_mismatched_exception = + is_a( $e, Process_Payment_Exception::class ) + && self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE === $e->get_error_code(); + + // If the order ID mismatched exception is thrown, do not mark the order as failed. + // Because the outcome of the payment intent is for another order, not for the order processed here. + if ( ! $is_order_id_mismatched_exception ) { + // Confirm our needed variables are set before using them due to there could be a server issue during the get_intent process. + $status = $status ?? null; + $charge_id = $charge_id ?? null; + + /* translators: localized exception message */ + $message = sprintf( __( 'UPE payment failed: %s', 'woocommerce-payments' ), $e->getMessage() ); + $this->order_service->mark_payment_failed( $order, $intent_id, $status, $charge_id, $message ); + } + + wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error' ); + + $redirect_url = wc_get_checkout_url(); + if ( $is_order_id_mismatched_exception ) { + $redirect_url = add_query_arg( self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE, 'yes', $redirect_url ); + } + wp_safe_redirect( $redirect_url ); + exit; + } + } + + /** + * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed. + * This applies to SEPA and Link payment methods. + * https://stripe.com/docs/payments/finalize-payments-on-the-server + * + * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise. + */ + public function is_mandate_data_required() { + $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true ); + $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id(); + + return $is_stripe_link_enabled || $is_sepa_debit_payment; } /** @@ -1621,15 +2034,26 @@ private function get_mandate_data() { } /** - * By default this function does not do anything. But it can be overriden by child classes. - * It is used to set a formatted readable payment method title for order, + * Set formatted readable payment method title for order, * using payment method details from accompanying charge. * - * @param WC_Order $order WC Order being processed. + * @param \WC_Order $order WC Order being processed. * @param string $payment_method_type Stripe payment method key. * @param array|bool $payment_method_details Array of payment method details from charge or false. */ public function set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ) { + $payment_method = $this->get_selected_payment_method( $payment_method_type ); + if ( ! $payment_method ) { + return; + } + + $payment_method_title = $payment_method->get_title( $payment_method_details ); + + $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type; + + $order->set_payment_method( $payment_gateway ); + $order->set_payment_method_title( $payment_method_title ); + $order->save(); } /** @@ -3434,25 +3858,71 @@ public function update_cached_account_data( $property, $data ) { /** * Returns the Stripe payment type of the selected payment method. * - * @return string[] + * @return string */ public function get_selected_stripe_payment_type_id() { - return [ - 'card', - ]; + return $this->stripe_id; } + /** * Returns the list of enabled payment method types that will function with the current checkout. * * @param string $order_id optional Order ID. * @param bool $force_currency_check optional Whether the currency check is required even if is_admin(). + * * @return string[] */ public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $force_currency_check = false ) { - return [ - 'card', - ]; + $automatic_capture = empty( $this->get_option( 'manual_capture' ) ) || $this->get_option( 'manual_capture' ) === 'no'; + if ( $automatic_capture ) { + $upe_enabled_payment_methods = $this->get_upe_enabled_payment_method_ids(); + } else { + $upe_enabled_payment_methods = array_intersect( $this->get_upe_enabled_payment_method_ids(), [ Payment_Method::CARD, Payment_Method::LINK ] ); + } + if ( is_wc_endpoint_url( 'order-pay' ) ) { + $force_currency_check = true; + } + + $enabled_payment_methods = []; + $active_payment_methods = $this->get_upe_enabled_payment_method_statuses(); + + foreach ( $upe_enabled_payment_methods as $payment_method_id ) { + $payment_method_capability_key = $this->payment_method_capability_key_map[ $payment_method_id ] ?? 'undefined_capability_key'; + if ( isset( $this->payment_methods[ $payment_method_id ] ) ) { + // When creating a payment intent, we need to ensure the currency is matching + // with the payment methods which are sent with the payment intent request, otherwise + // Stripe returns an error. + + // force_currency_check = 0 is_admin = 0 currency_is_checked = 1. + // force_currency_check = 0 is_admin = 1 currency_is_checked = 0. + // force_currency_check = 1 is_admin = 0 currency_is_checked = 1. + // force_currency_check = 1 is_admin = 1 currency_is_checked = 1. + + $skip_currency_check = ! $force_currency_check && is_admin(); + $processing_payment_method = $this->payment_methods[ $payment_method_id ]; + if ( $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) && ( $skip_currency_check || $processing_payment_method->is_currency_valid( $this->get_account_domestic_currency(), $order_id ) ) ) { + $status = $active_payment_methods[ $payment_method_capability_key ]['status'] ?? null; + if ( 'active' === $status ) { + $enabled_payment_methods[] = $payment_method_id; + } + } + } + } + + // if credit card payment method is not enabled, we don't use stripe link. + if ( + ! in_array( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) && + in_array( Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) ) { + $enabled_payment_methods = array_filter( + $enabled_payment_methods, + static function( $method ) { + return Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID !== $method; + } + ); + } + + return $enabled_payment_methods; } /** @@ -3463,7 +3933,10 @@ public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $f * @return string[] */ public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $order_id = null, $force_currency_check = false ) { - return $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check ); + $enabled_payment_methods = $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check ); + $methods_with_fees = array_keys( $this->account->get_fees() ); + + return array_values( array_intersect( $enabled_payment_methods, $methods_with_fees ) ); } /** @@ -3473,11 +3946,79 @@ public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $or * @return string[] */ public function get_upe_available_payment_methods() { - return [ - 'card', - ]; + $available_methods = [ 'card' ]; + + $available_methods[] = Becs_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Bancontact_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Eps_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Giropay_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Ideal_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Sofort_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Sepa_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = P24_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Affirm_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Afterpay_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + $available_methods[] = Klarna_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + + $available_methods = array_values( + apply_filters( + 'wcpay_upe_available_payment_methods', + $available_methods + ) + ); + + $methods_with_fees = array_keys( $this->account->get_fees() ); + + return array_values( array_intersect( $available_methods, $methods_with_fees ) ); + } + + /** + * Handle AJAX request for saving UPE appearance value to transient. + * + * @throws Exception - If nonce or setup intent is invalid. + */ + public function save_upe_appearance_ajax() { + try { + $is_nonce_valid = check_ajax_referer( 'wcpay_save_upe_appearance_nonce', false, false ); + if ( ! $is_nonce_valid ) { + throw new Exception( + __( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' ) + ); + } + + $is_blocks_checkout = isset( $_POST['is_blocks_checkout'] ) ? rest_sanitize_boolean( wc_clean( wp_unslash( $_POST['is_blocks_checkout'] ) ) ) : false; + $appearance = isset( $_POST['appearance'] ) ? json_decode( wc_clean( wp_unslash( $_POST['appearance'] ) ) ) : null; + + $appearance_transient = $is_blocks_checkout ? self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT : self::UPE_APPEARANCE_TRANSIENT; + + if ( null !== $appearance ) { + set_transient( $appearance_transient, $appearance, DAY_IN_SECONDS ); + } + + wp_send_json_success( $appearance, 200 ); + } catch ( Exception $e ) { + // Send back error so it can be displayed to the customer. + wp_send_json_error( + [ + 'error' => [ + 'message' => WC_Payments_Utils::get_filtered_error_message( $e ), + ], + ], + WC_Payments_Utils::get_filtered_error_status_code( $e ), + ); + } } + /** + * Clear the saved UPE appearance transient value. + */ + public function clear_upe_appearance_transient() { + delete_transient( self::UPE_APPEARANCE_TRANSIENT ); + delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); + } + + /** * Text provided to users during onboarding setup. * @@ -3513,6 +4054,81 @@ protected function should_bump_rate_limiter( string $error_code ): bool { return in_array( $error_code, [ 'card_declined', 'incorrect_number', 'incorrect_cvc' ], true ); } + /** + * Returns boolean for whether payment gateway supports saved payments. + * + * @return bool True, if gateway supports saved payments. False, otherwise. + */ + public function should_support_saved_payments() { + return $this->is_enabled_for_saved_payments( $this->stripe_id ); + } + + /** + * Returns true when viewing payment methods page. + * + * @return bool + */ + private function is_payment_methods_page() { + global $wp; + + $page_id = wc_get_page_id( 'myaccount' ); + + return ( $page_id && is_page( $page_id ) && ( isset( $wp->query_vars['payment-methods'] ) ) ); + } + + /** + * Verifies that the proper intent is used to process the order. + * + * @param WC_Order $order The order object based on the order_id received from the request. + * @param string $intent_id_from_request The intent ID received from the request. + * + * @return bool True if the proper intent is used to process the order, false otherwise. + */ + public function is_proper_intent_used_with_order( $order, $intent_id_from_request ) { + $intent_id_attached_to_order = $this->order_service->get_intent_id_for_order( $order ); + if ( ! hash_equals( $intent_id_attached_to_order, $intent_id_from_request ) ) { + Logger::error( + sprintf( + 'Intent ID mismatch. Received in request: %1$s. Attached to order: %2$s. Order ID: %3$d', + $intent_id_from_request, + $intent_id_attached_to_order, + $order->get_id() + ) + ); + return false; + } + return true; + } + + /** + * True if the request contains the values that indicates a redirection after a successful setup intent creation. + * + * @return bool + */ + public function is_setup_intent_success_creation_redirection() { + return ! empty( $_GET['setup_intent_client_secret'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended + ! empty( $_GET['setup_intent'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended + ! empty( $_GET['redirect_status'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended + 'succeeded' === $_GET['redirect_status']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + /** + * Function to be used with array_filter + * to filter UPE payment methods that support saved payments + * + * @param string $payment_method_id Stripe payment method. + * + * @return bool + */ + public function is_enabled_for_saved_payments( $payment_method_id ) { + $payment_method = $this->get_selected_payment_method( $payment_method_id ); + if ( ! $payment_method ) { + return false; + } + return $payment_method->is_reusable() + && ( is_admin() || $payment_method->is_currency_valid( $this->get_account_domestic_currency() ) ); + } + /** * Move the email field to the top of the Checkout page. * @@ -3557,6 +4173,44 @@ public function append_stripelink_button( $field, $key, $args, $value ) { return $field; } + /** + * Get selected UPE payment methods. + * + * @param string $selected_upe_payment_type Selected payment methods. + * @param array $enabled_payment_methods Enabled payment methods. + * + * @return array + */ + protected function get_selected_upe_payment_methods( string $selected_upe_payment_type, array $enabled_payment_methods ) { + $payment_methods = []; + if ( '' !== $selected_upe_payment_type ) { + // Only update the payment_method_types if we have a reference to the payment type the customer selected. + $payment_methods[] = $selected_upe_payment_type; + + if ( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID === $selected_upe_payment_type ) { + $is_link_enabled = in_array( + Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, + $enabled_payment_methods, + true + ); + if ( $is_link_enabled ) { + $payment_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID; + } + } + } + return $payment_methods; + } + + /** + * Gets UPE_Payment_Method instance from ID. + * + * @param string $payment_method_type Stripe payment method type ID. + * @return UPE_Payment_Method|false UPE payment method instance. + */ + public function get_selected_payment_method( $payment_method_type ) { + return WC_Payments::get_payment_method_by_id( $payment_method_type ); + } + /** * Returns the URL of the configuration screen for this gateway, for use in internal links. * @@ -3566,6 +4220,73 @@ public static function get_settings_url() { return WC_Payments_Admin_Settings::get_settings_url(); } + /** + * Return the payment method type from the payment method details. + * + * @param array $payment_method_details Payment method details. + * @return string|null Payment method type or nothing. + */ + private function get_payment_method_type_from_payment_details( $payment_method_details ) { + return $payment_method_details['type'] ?? null; + } + + + /** + * This function wraps WC_Payments::get_payment_method_map, useful for unit testing. + * + * @return array Array of UPE_Payment_Method instances. + */ + public function wc_payments_get_payment_method_map() { + return WC_Payments::get_payment_method_map(); + } + + /** + * Returns the payment methods for this gateway. + * + * @return array|UPE_Payment_Method[] + */ + public function get_payment_methods() { + return $this->payment_methods; + } + + /** + * Returns the UPE payment method for the gateway. + * + * @return UPE_Payment_Method + */ + public function get_payment_method() { + return $this->payment_method; + } + + /** + * Returns Stripe payment method type ID. + * + * @return string + */ + public function get_stripe_id() { + return $this->stripe_id; + } + + /** + * This function wraps WC_Payments::get_payment_gateway_by_id, useful for unit testing. + * + * @param string $payment_method_id Stripe payment method type ID. + * @return false|WC_Payment_Gateway_WCPay Matching UPE Payment Gateway instance. + */ + public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) { + return WC_Payments::get_payment_gateway_by_id( $payment_method_id ); + } + + /** + * This function wraps WC_Payments::get_payment_method_by_id, useful for unit testing. + * + * @param string $payment_method_id Stripe payment method type ID. + * @return false|UPE_Payment_Method Matching UPE Payment Method instance. + */ + public function wc_payments_get_payment_method_by_id( $payment_method_id ) { + return WC_Payments::get_payment_method_by_id( $payment_method_id ); + } + /** * Get the right method description if WooPay is eligible. * @@ -3714,10 +4435,44 @@ private function upe_needs_redirection( $payment_methods ) { return 1 === count( $payment_methods ) && 'card' !== $payment_methods[0]; } + /** + * Handles the shipping requirement for Afterpay payments. + * + * This method extracts the shipping and billing data from the order and sets the appropriate + * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid + * for shipping, an exception is thrown. + * + * @param WC_Order $order The order object containing shipping and billing information. + * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on. + * + * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments. + * @return void + */ + private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void { + $check_if_usable = function( array $address ): bool { + return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1']; + }; + + $shipping_data = $this->order_service->get_shipping_data_from_order( $order ); + if ( $check_if_usable( $shipping_data['address'] ) ) { + $request->set_shipping( $shipping_data ); + return; + } + + $billing_data = $this->order_service->get_billing_data_from_order( $order ); + if ( $check_if_usable( $billing_data['address'] ) ) { + $request->set_shipping( $billing_data ); + return; + } + + throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) ); + } + + /** * Modifies the create intent parameters when processing a payment. * - * Currently used by child UPE_Payment_Gateway to add required shipping information for Afterpay. + * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request. * * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention. * @param Payment_Information $payment_information The payment information object. @@ -3725,7 +4480,9 @@ private function upe_needs_redirection( $payment_methods ) { * * @return void */ - protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ) { - // Do nothing. + protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void { + if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) { + $this->handle_afterpay_shipping_requirement( $order, $request ); + } } } diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php index 89f8654f716..4826252e7ec 100644 --- a/includes/class-wc-payments-checkout.php +++ b/includes/class-wc-payments-checkout.php @@ -19,7 +19,7 @@ use WC_Payments_Features; use WCPay\Constants\Payment_Method; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; -use WCPay\Payment_Methods\UPE_Payment_Gateway; +use WC_Payment_Gateway_WCPay; use WCPay\WooPay\WooPay_Utilities; use WCPay\Payment_Methods\UPE_Payment_Method; @@ -32,7 +32,7 @@ class WC_Payments_Checkout { /** * WC Payments Gateway. * - * @var UPE_Payment_Gateway + * @var WC_Payment_Gateway_WCPay */ protected $gateway; @@ -67,14 +67,14 @@ class WC_Payments_Checkout { /** * Construct. * - * @param UPE_Payment_Gateway $gateway WC Payment Gateway. + * @param WC_Payment_Gateway_WCPay $gateway WC Payment Gateway. * @param WooPay_Utilities $woopay_util WooPay Utilities. * @param WC_Payments_Account $account WC Payments Account. * @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service. * @param WC_Payments_Fraud_Service $fraud_service Fraud service instance. */ public function __construct( - UPE_Payment_Gateway $gateway, + WC_Payment_Gateway_WCPay $gateway, WooPay_Utilities $woopay_util, WC_Payments_Account $account, WC_Payments_Customer_Service $customer_service, @@ -170,7 +170,7 @@ public function get_payment_fields_js_config() { WC_Checkout::instance(); // The registered card gateway is more reliable than $this->gateway, but if it isn't available for any reason, fall back to the gateway provided to this checkout class. - $gateway = WC_Payments::get_registered_card_gateway() ?? $this->gateway; + $gateway = WC_Payments::get_gateway() ?? $this->gateway; $js_config = [ 'publishableKey' => $this->account->get_publishable_key( WC_Payments::mode()->is_test() ), @@ -214,12 +214,12 @@ public function get_payment_fields_js_config() { $payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor(); $payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' ); - $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID; + $payment_fields['gatewayId'] = WC_Payment_Gateway_WCPay::GATEWAY_ID; $payment_fields['isCheckout'] = is_checkout(); $payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config(); $payment_fields['testMode'] = WC_Payments::mode()->is_test(); - $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT ); - $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); + $payment_fields['upeAppearance'] = get_transient( WC_Payment_Gateway_WCPay::UPE_APPEARANCE_TRANSIENT ); + $payment_fields['wcBlocksUPEAppearance'] = get_transient( WC_Payment_Gateway_WCPay::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); $payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart(); $payment_fields['currency'] = get_woocommerce_currency(); $cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 ); @@ -260,7 +260,7 @@ public function get_payment_fields_js_config() { $payment_fields['orderReturnURL'] = esc_url_raw( add_query_arg( [ - 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID, + 'wc_payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ), ], $this->gateway->get_return_url( $order ) diff --git a/includes/class-wc-payments-payment-method-messaging-element.php b/includes/class-wc-payments-payment-method-messaging-element.php index 6fe6006188f..3d951d13cc5 100644 --- a/includes/class-wc-payments-payment-method-messaging-element.php +++ b/includes/class-wc-payments-payment-method-messaging-element.php @@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -use WCPay\Payment_Methods\UPE_Payment_Gateway; +use WC_Payment_Gateway_WCPay; /** * WC_Payments_Payment_Method_Messaging_Element class. */ @@ -24,15 +24,15 @@ class WC_Payments_Payment_Method_Messaging_Element { /** * WC_Payments_Gateway instance to get information about the enabled payment methods. * - * @var UPE_Payment_Gateway + * @var WC_Payment_Gateway_WCPay */ private $gateway; /** * WC_Payments_Payment_Method_Messaging_Element constructor * - * @param WC_Payments_Account $account Account instance. - * @param UPE_Payment_Gateway $gateway Gateway instance. + * @param WC_Payments_Account $account Account instance. + * @param WC_Payment_Gateway_WCPay $gateway Gateway instance. * @return void */ public function __construct( WC_Payments_Account $account, $gateway ) { diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index f171f9b07d6..0677eaa5a1b 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -12,7 +12,6 @@ use WCPay\Core\Mode; use WCPay\Core\Server\Request; use WCPay\Migrations\Allowed_Payment_Request_Button_Types_Update; -use WCPay\Payment_Methods\CC_Payment_Gateway; use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Payment_Methods\Bancontact_Payment_Method; use WCPay\Payment_Methods\Becs_Payment_Method; @@ -21,7 +20,6 @@ use WCPay\Payment_Methods\P24_Payment_Method; use WCPay\Payment_Methods\Sepa_Payment_Method; use WCPay\Payment_Methods\Sofort_Payment_Method; -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\Payment_Methods\Ideal_Payment_Method; use WCPay\Payment_Methods\Eps_Payment_Method; use WCPay\Payment_Methods\UPE_Payment_Method; @@ -51,24 +49,9 @@ class WC_Payments { /** * Main payment gateway controller instance, created in init function. * - * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway - */ - private static $card_gateway; - - /** - * Instance of WC_Payment_Gateway_WCPay to register as payment gateway. - * * @var WC_Payment_Gateway_WCPay */ - private static $legacy_card_gateway; - - /** - * Copy of either $card_gateway or $legacy_card_gateway, - * depending on which gateway is registered as main CC gateway. - * - * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway - */ - private static $registered_card_gateway; + private static $card_gateway; /** * Instance of WC_Payments_API_Client, created in init function. @@ -211,25 +194,18 @@ class WC_Payments { private static $webhook_processing_service; /** - * Maps all availabled Stripe payment method IDs to UPE Payment Method instances. + * Maps all availabled Stripe payment method IDs to Payment Method instances. * * @var array */ - private static $upe_payment_method_map = []; + private static $payment_method_map = []; /** - * Maps all availabled Stripe payment method IDs to UPE Payment Gateway instances. + * Maps all availabled Stripe payment method IDs to Payment Gateway instances. * * @var array */ - private static $upe_payment_gateway_map = []; - - /** - * Map to store all the available split upe checkouts - * - * @var array - */ - private static $upe_checkout_map = []; + private static $payment_gateway_map = []; /** * Instance of WC_Payments_Webhook_Reliability_Service, created in init function @@ -405,7 +381,6 @@ public static function init() { include_once __DIR__ . '/class-wc-payment-gateway-wcpay.php'; include_once __DIR__ . '/class-wc-payments-checkout.php'; include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php'; - include_once __DIR__ . '/payment-methods/class-upe-payment-gateway.php'; include_once __DIR__ . '/payment-methods/class-upe-payment-method.php'; include_once __DIR__ . '/payment-methods/class-cc-payment-method.php'; include_once __DIR__ . '/payment-methods/class-bancontact-payment-method.php'; @@ -523,8 +498,6 @@ public static function init() { self::$incentives_service->init_hooks(); self::$compatibility_service->init_hooks(); - self::$legacy_card_gateway = new CC_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service ); - $payment_method_classes = [ CC_Payment_Method::class, Bancontact_Payment_Method::class, @@ -547,16 +520,16 @@ public static function init() { $payment_methods[ $payment_method->get_id() ] = $payment_method; } foreach ( $payment_methods as $payment_method ) { - self::$upe_payment_method_map[ $payment_method->get_id() ] = $payment_method; + self::$payment_method_map[ $payment_method->get_id() ] = $payment_method; - $split_gateway = new UPE_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service ); + $split_gateway = new WC_Payment_Gateway_WCPay( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service ); // Card gateway hooks are registered once below. if ( 'card' !== $payment_method->get_id() ) { $split_gateway->init_hooks(); } - self::$upe_payment_gateway_map[ $payment_method->get_id() ] = $split_gateway; + self::$payment_gateway_map[ $payment_method->get_id() ] = $split_gateway; } self::$card_gateway = self::get_payment_gateway_by_id( 'card' ); @@ -765,23 +738,21 @@ public static function register_gateway( $gateways ) { self::get_gateway()->update_option( 'upe_enabled_payment_method_ids', $payment_methods ); } - self::$registered_card_gateway = self::$card_gateway; - - $gateways[] = self::$registered_card_gateway; - $all_upe_gateways = []; + $gateways[] = self::$card_gateway; + $all_gateways = []; $reusable_methods = []; foreach ( $payment_methods as $payment_method_id ) { if ( 'card' === $payment_method_id || 'link' === $payment_method_id ) { continue; } - $upe_gateway = self::get_payment_gateway_by_id( $payment_method_id ); - $upe_payment_method = self::get_payment_method_by_id( $payment_method_id ); + $gateway = self::get_payment_gateway_by_id( $payment_method_id ); + $payment_method = self::get_payment_method_by_id( $payment_method_id ); - if ( $upe_payment_method->is_reusable() ) { - $reusable_methods[] = $upe_gateway; + if ( $payment_method->is_reusable() ) { + $reusable_methods[] = $gateway; } - $all_upe_gateways[] = $upe_gateway; + $all_gateways[] = $gateway; } @@ -789,25 +760,7 @@ public static function register_gateway( $gateways ) { return array_merge( $gateways, $reusable_methods ); } - return array_merge( $gateways, $all_upe_gateways ); - } - - /** - * Returns main CC gateway registered for WCPay. - * - * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway - */ - public static function get_registered_card_gateway() { - return self::$registered_card_gateway; - } - - /** - * Sets registered card gateway instance. - * - * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway $gateway Gateway instance. - */ - public static function set_registered_card_gateway( $gateway ) { - self::$registered_card_gateway = $gateway; + return array_merge( $gateways, $all_gateways ); } /** @@ -816,7 +769,7 @@ public static function set_registered_card_gateway( $gateway ) { * Remove all WCPay gateways except CC one. */ public static function hide_gateways_on_settings_page() { - $default_gateway = self::get_registered_card_gateway(); + $default_gateway = self::get_gateway(); foreach ( WC()->payment_gateways->payment_gateways as $index => $payment_gateway ) { if ( $payment_gateway instanceof WC_Payment_Gateway_WCPay && $payment_gateway !== $default_gateway ) { unset( WC()->payment_gateways->payment_gateways[ $index ] ); @@ -1153,26 +1106,26 @@ public static function register_script_with_dependencies( string $handler, strin * Returns payment method instance by Stripe ID. * * @param string $payment_method_id Stripe payment method type ID. - * @return false|UPE_Payment_Method Matching UPE Payment Method instance. + * @return false|UPE_Payment_Method Matching Payment Method instance. */ public static function get_payment_method_by_id( $payment_method_id ) { - if ( ! isset( self::$upe_payment_method_map[ $payment_method_id ] ) ) { + if ( ! isset( self::$payment_method_map[ $payment_method_id ] ) ) { return false; } - return self::$upe_payment_method_map[ $payment_method_id ]; + return self::$payment_method_map[ $payment_method_id ]; } /** * Returns payment gateway instance by Stripe ID. * * @param string $payment_method_id Stripe payment method type ID. - * @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance. + * @return false|WC_Payment_Gateway_WCPay Matching Payment Gateway instance. */ public static function get_payment_gateway_by_id( $payment_method_id ) { - if ( ! isset( self::$upe_payment_gateway_map[ $payment_method_id ] ) ) { + if ( ! isset( self::$payment_gateway_map[ $payment_method_id ] ) ) { return false; } - return self::$upe_payment_gateway_map[ $payment_method_id ]; + return self::$payment_gateway_map[ $payment_method_id ]; } /** @@ -1181,13 +1134,13 @@ public static function get_payment_gateway_by_id( $payment_method_id ) { * @return array */ public static function get_payment_method_map() { - return self::$upe_payment_method_map; + return self::$payment_method_map; } /** * Returns the WC_Payment_Gateway_WCPay instance * - * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway gateway instance + * @return WC_Payment_Gateway_WCPay gateway instance */ public static function get_gateway() { return self::$card_gateway; @@ -1223,7 +1176,7 @@ public static function set_database_cache( Database_Cache $database_cache ) { /** * Sets the card gateway instance. * - * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway $gateway The card gateway instance.. + * @param WC_Payment_Gateway_WCPay $gateway The card gateway instance.. */ public static function set_gateway( $gateway ) { self::$card_gateway = $gateway; diff --git a/includes/payment-methods/class-upe-payment-gateway.php b/includes/payment-methods/class-upe-payment-gateway.php deleted file mode 100644 index eff6d3ad1d8..00000000000 --- a/includes/payment-methods/class-upe-payment-gateway.php +++ /dev/null @@ -1,1138 +0,0 @@ -title = $payment_method->get_title(); - $this->method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' ); - $this->description = ''; - $this->checkout_title = __( 'Popular payment methods', 'woocommerce-payments' ); - $this->payment_methods = $payment_methods; - - $this->stripe_id = $payment_method->get_id(); - $this->payment_method = $payment_method; - $this->icon = $payment_method->get_icon(); - - if ( 'card' !== $this->stripe_id ) { - $this->id = self::GATEWAY_ID . '_' . $this->stripe_id; - $this->method_title = "WooPayments ($this->title)"; - } - } - - /** - * Displays HTML tags for WC payment gateway radio button content. - */ - public function display_gateway_html() { - ?> -
- get_selected_stripe_payment_type_id() ); - do_action( 'wc_payments_add_upe_payment_fields' ); - } - - /** - * Update payment intent for completed checkout and return redirect URL for Stripe to confirm payment. - * - * @param int $order_id Order ID to process the payment for. - * - * @return array|null An array with result of payment and redirect URL, or nothing. - * @throws Exception Error processing the payment. - * @throws Order_Not_Found_Exception - */ - public function process_payment( $order_id ) { - $order = wc_get_order( $order_id ); - - if ( 20 < strlen( $order->get_billing_phone() ) ) { - throw new Process_Payment_Exception( - __( 'Invalid phone number.', 'woocommerce-payments' ), - 'invalid_phone_number' - ); - } - $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing - $amount = $order->get_total(); - $currency = $order->get_currency(); - $converted_amount = WC_Payments_Utils::prepare_amount( $amount, $currency ); - $payment_needed = 0 < $converted_amount; - $payment_type = $this->is_payment_recurring( $order_id ) ? Payment_Type::RECURRING() : Payment_Type::SINGLE(); - $save_payment_method = $payment_type->equals( Payment_Type::RECURRING() ) || ! empty( $_POST[ 'wc-' . $this->id . '-new-payment-method' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Missing - - if ( $payment_intent_id ) { - list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order ); - - if ( $payment_needed ) { - // Check if session exists before instantiating Fraud_Prevention_Service. - if ( WC()->session ) { - $fraud_prevention_service = Fraud_Prevention_Service::get_instance(); - // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - if ( $fraud_prevention_service->is_enabled() && ! $fraud_prevention_service->verify_token( $_POST['wcpay-fraud-prevention-token'] ?? null ) ) { - throw new Process_Payment_Exception( - __( "We're not able to process this payment. Please refresh the page and try again.", 'woocommerce-payments' ), - 'fraud_prevention_enabled' - ); - } - } - - if ( $this->failed_transaction_rate_limiter->is_limited() ) { - // Throwing an exception instead of adding an error notice - // makes the error notice show up both in the regular and block checkout. - throw new Exception( __( 'Your payment was not processed.', 'woocommerce-payments' ) ); - } - - // Try catching the error without reaching the API. - $minimum_amount = WC_Payments_Utils::get_cached_minimum_amount( $currency ); - if ( $minimum_amount > $converted_amount ) { - $exception = new Amount_Too_Small_Exception( 'Amount too small', $minimum_amount, $currency, 400 ); - throw new Exception( WC_Payments_Utils::get_filtered_error_message( $exception ) ); - } - - $check_session_order = $this->duplicate_payment_prevention_service->check_against_session_processing_order( $order ); - if ( is_array( $check_session_order ) ) { - return $check_session_order; - } - $this->duplicate_payment_prevention_service->maybe_update_session_processing_order( $order_id ); - - $check_existing_intention = $this->duplicate_payment_prevention_service->check_payment_intent_attached_to_order_succeeded( $order ); - if ( is_array( $check_existing_intention ) ) { - return $check_existing_intention; - } - - // @toDo: This is now not used? - $additional_api_parameters = $this->get_mandate_params_for_order( $order ); - - try { - $payment_methods = $this->get_selected_upe_payment_methods( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout( null, true ) ?? [] ); - - $request = Update_Intention::create( $payment_intent_id ); - $request->set_currency_code( strtolower( $currency ) ); - $request->set_amount( WC_Payments_Utils::prepare_amount( $amount, $currency ) ); - $request->set_metadata( $this->get_metadata_from_order( $order, $payment_type ) ); - $request->set_level3( $this->get_level3_data_from_order( $order ) ); - $request->set_payment_method_types( $payment_methods ); - $request->set_hook_args( $order, $payment_intent_id ); - if ( $payment_country ) { - $request->set_payment_country( $payment_country ); - } - if ( true === $save_payment_method ) { - $request->setup_future_usage(); - } - if ( $customer_id ) { - $request->set_customer( $customer_id ); - } - $payment_method_options = $this->get_mandate_params_for_order( $order ); - if ( $payment_method_options ) { - $request->setup_future_usage(); - $request->set_payment_method_options( $payment_method_options ); - } - $updated_payment_intent = $request->send(); - } catch ( Amount_Too_Small_Exception $e ) { - // This code would only be reached if the cache has already expired. - throw new Exception( WC_Payments_Utils::get_filtered_error_message( $e ) ); - } catch ( API_Exception $e ) { - if ( 'wcpay_blocked_by_fraud_rule' === $e->get_error_code() ) { - $this->order_service->mark_order_blocked_for_fraud( $order, $payment_intent_id, Intent_Status::CANCELED ); - } - throw $e; - } - - $intent_id = $updated_payment_intent->get_id(); - $intent_status = $updated_payment_intent->get_status(); - $payment_method = $updated_payment_intent->get_payment_method_id(); - $charge = $updated_payment_intent->get_charge(); - $payment_method_details = $charge ? $charge->get_payment_method_details() : []; - $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details ); - $charge_id = $charge ? $charge->get_id() : null; - - /** - * Attach the intent and exchange info to the order before doing the redirect, just in case the redirect - * either does not complete properly, or the Stripe webhook which processes a successful order hits before - * the redirect completes. - */ - $this->order_service->attach_intent_info_to_order( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency ); - $this->attach_exchange_info_to_order( $order, $charge_id ); - $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ); - if ( Intent_Status::SUCCEEDED === $intent_status ) { - $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() ); - } - $this->order_service->update_order_status_from_intent( $order, $updated_payment_intent ); - - $last_payment_error_code = $updated_payment_intent->get_last_payment_error()['code'] ?? ''; - if ( $this->should_bump_rate_limiter( $last_payment_error_code ) ) { - // UPE method gives us the error of the previous payment attempt, so we use that for the Rate Limiter. - $this->failed_transaction_rate_limiter->bump(); - } - } - } else { - return $this->parent_process_payment( $order_id ); - } - - return [ // nosemgrep: audit.php.wp.security.xss.query-arg -- The output of add_query_arg is being escaped. - 'result' => 'success', - 'payment_needed' => $payment_needed, - 'redirect_url' => wp_sanitize_redirect( - esc_url_raw( - add_query_arg( - [ - 'wc_payment_method' => self::GATEWAY_ID, - '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ), - 'save_payment_method' => $save_payment_method ? 'yes' : 'no', - ], - $this->get_return_url( $order ) - ) - ) - ), - ]; - } - - /** - * Returns true when viewing payment methods page. - * - * @return bool - */ - private function is_payment_methods_page() { - global $wp; - - $page_id = wc_get_page_id( 'myaccount' ); - - return ( $page_id && is_page( $page_id ) && ( isset( $wp->query_vars['payment-methods'] ) ) ); - } - - /** - * Get selected UPE payment methods. - * - * @param string $selected_upe_payment_type Selected payment methods. - * @param array $enabled_payment_methods Enabled payment methods. - * - * @return array - */ - protected function get_selected_upe_payment_methods( string $selected_upe_payment_type, array $enabled_payment_methods ) { - $payment_methods = []; - if ( '' !== $selected_upe_payment_type ) { - // Only update the payment_method_types if we have a reference to the payment type the customer selected. - $payment_methods[] = $selected_upe_payment_type; - - if ( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID === $selected_upe_payment_type ) { - $is_link_enabled = in_array( - Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, - $enabled_payment_methods, - true - ); - if ( $is_link_enabled ) { - $payment_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - } - } - } - return $payment_methods; - } - /** - * Check for a redirect payment method on order received page or setup intent on payment methods page. - */ - public function maybe_process_upe_redirect() { - if ( $this->is_payment_methods_page() ) { - // If a payment method was added using UPE, we need to clear the cache and notify the user. - if ( $this->is_setup_intent_success_creation_redirection() ) { - wc_add_notice( __( 'Payment method successfully added.', 'woocommerce-payments' ) ); - $user = wp_get_current_user(); - $this->customer_service->clear_cached_payment_methods_for_user( $user->ID ); - } - return; - } - - if ( ! is_order_received_page() ) { - return; - } - - $payment_method = isset( $_GET['wc_payment_method'] ) ? wc_clean( wp_unslash( $_GET['wc_payment_method'] ) ) : ''; - if ( self::GATEWAY_ID !== $payment_method ) { - return; - } - - $is_nonce_valid = check_admin_referer( 'wcpay_process_redirect_order_nonce' ); - if ( ! $is_nonce_valid || empty( $_GET['wc_payment_method'] ) ) { - return; - } - - if ( ! empty( $_GET['payment_intent_client_secret'] ) ) { - $intent_id_from_request = isset( $_GET['payment_intent'] ) ? wc_clean( wp_unslash( $_GET['payment_intent'] ) ) : ''; - } elseif ( ! empty( $_GET['setup_intent_client_secret'] ) ) { - $intent_id_from_request = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : ''; - } else { - return; - } - - $order_id = absint( get_query_var( 'order-received' ) ); - $order_key_from_request = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; - $save_payment_method = isset( $_GET['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_GET['save_payment_method'] ) ) : false; - - if ( empty( $intent_id_from_request ) || empty( $order_id ) || empty( $order_key_from_request ) ) { - return; - } - - $order = wc_get_order( $order_id ); - - if ( ! is_a( $order, 'WC_Order' ) ) { - // the ID of non-existing order was passed in. - return; - } - - if ( $order->get_order_key() !== $order_key_from_request ) { - // Valid return url should have matching order key. - return; - } - - // Perform additional checks for non-zero-amount. For zero-amount orders, we can't compare intents because they are not attached to the order at this stage. - // Once https://github.com/Automattic/woocommerce-payments/issues/6575 is closed, this check can be applied for zero-amount orders as well. - if ( $order->get_total() > 0 && ! $this->is_proper_intent_used_with_order( $order, $intent_id_from_request ) ) { - return; - } - - $this->process_redirect_payment( $order, $intent_id_from_request, $save_payment_method ); - } - - /** - * Processes redirect payments. - * - * @param WC_Order $order The order being processed. - * @param string $intent_id The Stripe setup/payment intent ID for the order payment. - * @param bool $save_payment_method Boolean representing whether payment method for order should be saved. - * - * @throws Process_Payment_Exception When the payment intent has an error. - */ - public function process_redirect_payment( $order, $intent_id, $save_payment_method ) { - try { - $order_id = $order->get_id(); - if ( $order->has_status( - [ - Order_Status::PROCESSING, - Order_Status::COMPLETED, - Order_Status::ON_HOLD, - ] - ) ) { - return; - } - - Logger::log( "Begin processing UPE redirect payment for order {$order_id} for the amount of {$order->get_total()}" ); - - // Get user/customer for order. - list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order ); - - $payment_needed = 0 < $order->get_total(); - - // Get payment intent to confirm status. - if ( $payment_needed ) { - $request = Get_Intention::create( $intent_id ); - $request->set_hook_args( $order ); - /** @var WC_Payments_API_Payment_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort - $intent = $request->send(); - $client_secret = $intent->get_client_secret(); - $status = $intent->get_status(); - $charge = $intent->get_charge(); - $charge_id = $charge ? $charge->get_id() : null; - $currency = $intent->get_currency(); - $payment_method_id = $intent->get_payment_method_id(); - $payment_method_details = $charge ? $charge->get_payment_method_details() : []; - $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details ); - $error = $intent->get_last_payment_error(); - - // This check applies to payment intents only due to two reasons: - // (1) metadata is missed for setup intents. See https://github.com/Automattic/woocommerce-payments/issues/6575. - // (2) most issues so far affect only payment intents. - $intent_metadata = is_array( $intent->get_metadata() ) ? $intent->get_metadata() : []; - $this->validate_order_id_received_vs_intent_meta_order_id( $order, $intent_metadata ); - } else { - $request = Get_Setup_Intention::create( $intent_id ); - /** @var WC_Payments_API_Setup_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort - $intent = $request->send(); - $client_secret = $intent->get_client_secret(); - $status = $intent->get_status(); - $charge_id = ''; - $charge = null; - $currency = $order->get_currency(); - $payment_method_id = $intent->get_payment_method_id(); - $payment_method_details = false; - $payment_method_type = $intent->get_payment_method_type(); - $error = $intent->get_last_setup_error(); - } - - if ( ! empty( $error ) ) { - Logger::log( 'Error when processing payment: ' . $error['message'] ); - throw new Process_Payment_Exception( - __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ), - 'upe_payment_intent_error' - ); - } else { - $payment_method = $this->get_selected_payment_method( $payment_method_type ); - if ( ! $payment_method ) { - return; - } - - if ( $save_payment_method && $payment_method->is_reusable() ) { - try { - $token = $payment_method->get_payment_token_for_user( $user, $payment_method_id ); - $this->add_token_to_order( $order, $token ); - } catch ( Exception $e ) { - // If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow. - Logger::log( 'Error when saving payment method: ' . $e->getMessage() ); - } - } - - $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method_id, $customer_id, $charge_id, $currency ); - $this->attach_exchange_info_to_order( $order, $charge_id ); - if ( Intent_Status::SUCCEEDED === $status ) { - $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() ); - } - $this->order_service->update_order_status_from_intent( $order, $intent ); - $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ); - $this->order_service->attach_transaction_fee_to_order( $order, $charge ); - - if ( Intent_Status::REQUIRES_ACTION === $status ) { - // I don't think this case should be possible, but just in case... - $next_action = $intent->get_next_action(); - if ( isset( $next_action['type'] ) && 'redirect_to_url' === $next_action['type'] && ! empty( $next_action['redirect_to_url']['url'] ) ) { - wp_safe_redirect( $next_action['redirect_to_url']['url'] ); - exit; - } else { - $redirect_url = sprintf( - '#wcpay-confirm-%s:%s:%s:%s', - $payment_needed ? 'pi' : 'si', - $order_id, - WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $client_secret ), - wp_create_nonce( 'wcpay_update_order_status_nonce' ) - ); - wp_safe_redirect( $redirect_url ); - exit; - } - } - } - } catch ( Exception $e ) { - Logger::log( 'Error: ' . $e->getMessage() ); - - $is_order_id_mismatched_exception = - is_a( $e, Process_Payment_Exception::class ) - && self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE === $e->get_error_code(); - - // If the order ID mismatched exception is thrown, do not mark the order as failed. - // Because the outcome of the payment intent is for another order, not for the order processed here. - if ( ! $is_order_id_mismatched_exception ) { - // Confirm our needed variables are set before using them due to there could be a server issue during the get_intent process. - $status = $status ?? null; - $charge_id = $charge_id ?? null; - - /* translators: localized exception message */ - $message = sprintf( __( 'UPE payment failed: %s', 'woocommerce-payments' ), $e->getMessage() ); - $this->order_service->mark_payment_failed( $order, $intent_id, $status, $charge_id, $message ); - } - - wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error' ); - - $redirect_url = wc_get_checkout_url(); - if ( $is_order_id_mismatched_exception ) { - $redirect_url = add_query_arg( self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE, 'yes', $redirect_url ); - } - wp_safe_redirect( $redirect_url ); - exit; - } - } - - /** - * Verifies that the proper intent is used to process the order. - * - * @param WC_Order $order The order object based on the order_id received from the request. - * @param string $intent_id_from_request The intent ID received from the request. - * - * @return bool True if the proper intent is used to process the order, false otherwise. - */ - public function is_proper_intent_used_with_order( $order, $intent_id_from_request ) { - $intent_id_attached_to_order = $this->order_service->get_intent_id_for_order( $order ); - if ( ! hash_equals( $intent_id_attached_to_order, $intent_id_from_request ) ) { - Logger::error( - sprintf( - 'Intent ID mismatch. Received in request: %1$s. Attached to order: %2$s. Order ID: %3$d', - $intent_id_from_request, - $intent_id_attached_to_order, - $order->get_id() - ) - ); - return false; - } - return true; - } - - /** - * Generates the configuration values, needed for UPE payment fields. - * - * @deprecated 5.0.0 - * - * @return array - */ - public function get_payment_fields_js_config() { - wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_payment_fields_js_config' ); - return WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config(); - } - - /** - * True if the request contains the values that indicates a redirection after a successful setup intent creation. - * - * @return bool - */ - public function is_setup_intent_success_creation_redirection() { - return ! empty( $_GET['setup_intent_client_secret'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended - ! empty( $_GET['setup_intent'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended - ! empty( $_GET['redirect_status'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended - 'succeeded' === $_GET['redirect_status']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended - } - - /** - * Adds a token to current user from a setup intent id. - * - * @param string $setup_intent_id ID of the setup intent. - * @param WP_User $user User to add token to. - * - * @return WC_Payment_Token_CC|WC_Payment_Token_WCPay_SEPA|null The added token. - */ - public function create_token_from_setup_intent( $setup_intent_id, $user ) { - try { - $setup_intent_request = Get_Setup_Intention::create( $setup_intent_id ); - /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort - $setup_intent = $setup_intent_request->send(); - - $payment_method_id = $setup_intent->get_payment_method_id(); - // TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type. - // Leaving 'card' as a hardcoded value for now to avoid the extra API call. - // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced. - $payment_method = $this->payment_method; - - return $payment_method->get_payment_token_for_user( $user, $payment_method_id ); - } catch ( Exception $e ) { - wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error', [ 'icon' => 'error' ] ); - Logger::log( 'Error when adding payment method: ' . $e->getMessage() ); - } - } - - /** - * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed. - * This applies to SEPA and Link payment methods. - * https://stripe.com/docs/payments/finalize-payments-on-the-server - * - * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise. - */ - public function is_mandate_data_required() { - $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true ); - $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id(); - - return $is_stripe_link_enabled || $is_sepa_debit_payment; - } - - /** - * Returns the Stripe payment type of the selected payment method. - * - * @return string - */ - public function get_selected_stripe_payment_type_id() { - return $this->stripe_id; - } - - /** - * Set formatted readable payment method title for order, - * using payment method details from accompanying charge. - * - * @param \WC_Order $order WC Order being processed. - * @param string $payment_method_type Stripe payment method key. - * @param array|bool $payment_method_details Array of payment method details from charge or false. - */ - public function set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ) { - $payment_method = $this->get_selected_payment_method( $payment_method_type ); - if ( ! $payment_method ) { - return; - } - - $payment_method_title = $payment_method->get_title( $payment_method_details ); - - $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type; - - $order->set_payment_method( $payment_gateway ); - $order->set_payment_method_title( $payment_method_title ); - $order->save(); - } - - /** - * Returns the list of enabled payment method types that will function with the current checkout. - * - * @param string $order_id optional Order ID. - * @param bool $force_currency_check optional Whether the currency check is required even if is_admin(). - * - * @return string[] - */ - public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $force_currency_check = false ) { - $automatic_capture = empty( $this->get_option( 'manual_capture' ) ) || $this->get_option( 'manual_capture' ) === 'no'; - if ( $automatic_capture ) { - $upe_enabled_payment_methods = $this->get_upe_enabled_payment_method_ids(); - } else { - $upe_enabled_payment_methods = array_intersect( $this->get_upe_enabled_payment_method_ids(), [ Payment_Method::CARD, Payment_Method::LINK ] ); - } - if ( is_wc_endpoint_url( 'order-pay' ) ) { - $force_currency_check = true; - } - - $enabled_payment_methods = []; - $active_payment_methods = $this->get_upe_enabled_payment_method_statuses(); - - foreach ( $upe_enabled_payment_methods as $payment_method_id ) { - $payment_method_capability_key = $this->payment_method_capability_key_map[ $payment_method_id ] ?? 'undefined_capability_key'; - if ( isset( $this->payment_methods[ $payment_method_id ] ) ) { - // When creating a payment intent, we need to ensure the currency is matching - // with the payment methods which are sent with the payment intent request, otherwise - // Stripe returns an error. - - // force_currency_check = 0 is_admin = 0 currency_is_checked = 1. - // force_currency_check = 0 is_admin = 1 currency_is_checked = 0. - // force_currency_check = 1 is_admin = 0 currency_is_checked = 1. - // force_currency_check = 1 is_admin = 1 currency_is_checked = 1. - - $skip_currency_check = ! $force_currency_check && is_admin(); - $processing_payment_method = $this->payment_methods[ $payment_method_id ]; - if ( $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) && ( $skip_currency_check || $processing_payment_method->is_currency_valid( $this->get_account_domestic_currency(), $order_id ) ) ) { - $status = $active_payment_methods[ $payment_method_capability_key ]['status'] ?? null; - if ( 'active' === $status ) { - $enabled_payment_methods[] = $payment_method_id; - } - } - } - } - - // if credit card payment method is not enabled, we don't use stripe link. - if ( - ! in_array( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) && - in_array( Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) ) { - $enabled_payment_methods = array_filter( - $enabled_payment_methods, - static function( $method ) { - return Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID !== $method; - } - ); - } - - return $enabled_payment_methods; - } - - /** - * Returns the list of enabled payment method types that will function with the current checkout filtered by fees. - * - * @param string $order_id optional Order ID. - * @param bool $force_currency_check optional Whether the currency check is required even if is_admin(). - * - * @return string[] - */ - public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $order_id = null, $force_currency_check = false ) { - $enabled_payment_methods = $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check ); - $methods_with_fees = array_keys( $this->account->get_fees() ); - - return array_values( array_intersect( $enabled_payment_methods, $methods_with_fees ) ); - } - - /** - * Returns the list of available payment method types for UPE. - * Filtering out those without configured fees, this will prevent a payment method not supported by the Stripe account's country from being returned. - * Note that we are not taking into account capabilities, which are taken into account when managing payment methods in settings. - * See https://stripe.com/docs/stripe-js/payment-element#web-create-payment-intent for a complete list. - * - * @return string[] - */ - public function get_upe_available_payment_methods() { - $available_methods = parent::get_upe_available_payment_methods(); - - $available_methods[] = Becs_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Bancontact_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Eps_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Giropay_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Ideal_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Sofort_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Sepa_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = P24_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Affirm_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Afterpay_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - $available_methods[] = Klarna_Payment_Method::PAYMENT_METHOD_STRIPE_ID; - - $available_methods = array_values( - apply_filters( - 'wcpay_upe_available_payment_methods', - $available_methods - ) - ); - - $methods_with_fees = array_keys( $this->account->get_fees() ); - - return array_values( array_intersect( $available_methods, $methods_with_fees ) ); - } - - /** - * Handle AJAX request for saving UPE appearance value to transient. - * - * @throws Exception - If nonce or setup intent is invalid. - */ - public function save_upe_appearance_ajax() { - try { - $is_nonce_valid = check_ajax_referer( 'wcpay_save_upe_appearance_nonce', false, false ); - if ( ! $is_nonce_valid ) { - throw new Exception( - __( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' ) - ); - } - - $is_blocks_checkout = isset( $_POST['is_blocks_checkout'] ) ? rest_sanitize_boolean( wc_clean( wp_unslash( $_POST['is_blocks_checkout'] ) ) ) : false; - $appearance = isset( $_POST['appearance'] ) ? json_decode( wc_clean( wp_unslash( $_POST['appearance'] ) ) ) : null; - - $appearance_transient = $is_blocks_checkout ? self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT : self::UPE_APPEARANCE_TRANSIENT; - - if ( null !== $appearance ) { - set_transient( $appearance_transient, $appearance, DAY_IN_SECONDS ); - } - - wp_send_json_success( $appearance, 200 ); - } catch ( Exception $e ) { - // Send back error so it can be displayed to the customer. - wp_send_json_error( - [ - 'error' => [ - 'message' => WC_Payments_Utils::get_filtered_error_message( $e ), - ], - ], - WC_Payments_Utils::get_filtered_error_status_code( $e ), - ); - } - } - - /** - * Clear the saved UPE appearance transient value. - */ - public function clear_upe_appearance_transient() { - delete_transient( self::UPE_APPEARANCE_TRANSIENT ); - delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); - } - - /** - * Validate order_id received from the request vs value saved in the intent metadata. - * Throw an exception if they're not matched. - * - * @param WC_Order $order The received order to process. - * @param array $intent_metadata The metadata of attached intent to the order. - * - * @return void - * @throws Process_Payment_Exception - */ - private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $order, array $intent_metadata ): void { - $intent_meta_order_id_raw = $intent_metadata['order_id'] ?? ''; - $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0; - - if ( $order->get_id() !== $intent_meta_order_id ) { - Logger::error( - sprintf( - 'UPE Process Redirect Payment - Order ID mismatched. Received: %1$d. Intent Metadata Value: %2$d', - $order->get_id(), - $intent_meta_order_id - ) - ); - - throw new Process_Payment_Exception( - __( "We're not able to process this payment due to the order ID mismatch. Please try again later.", 'woocommerce-payments' ), - self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE - ); - } - } - - /** - * Gets payment method settings to pass to client scripts - * - * @deprecated 5.0.0 - * - * @return array - */ - private function get_enabled_payment_method_config() { - wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' ); - return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config(); - } - - /** - * Function to be used with array_filter - * to filter UPE payment methods that support saved payments - * - * @param string $payment_method_id Stripe payment method. - * - * @return bool - */ - public function is_enabled_for_saved_payments( $payment_method_id ) { - $payment_method = $this->get_selected_payment_method( $payment_method_id ); - if ( ! $payment_method ) { - return false; - } - return $payment_method->is_reusable() - && ( is_admin() || $payment_method->is_currency_valid( $this->get_account_domestic_currency() ) ); - } - - /** - * Returns boolean for whether payment gateway supports saved payments. - * - * @return bool True, if gateway supports saved payments. False, otherwise. - */ - public function should_support_saved_payments() { - return $this->is_enabled_for_saved_payments( $this->stripe_id ); - } - - /** - * Whether we should use the platform account to initialize Stripe on the checkout page. - * - * @return bool Result of the WCPay gateway checks if the card payment method is used, false otherwise. - */ - public function should_use_stripe_platform_on_checkout_page() { - if ( 'card' === $this->stripe_id ) { - return parent::should_use_stripe_platform_on_checkout_page(); - } - return false; - } - - /** - * This method is used by WooCommerce Core's WC_Payment_Gateways::get_available_payment_gateways() to filter out gateways. - * - * The availability decision includes an additional business rule that checks if the payment method is enabled at checkout - * via the is_enabled_at_checkout method. This method provides crucial information, among others, to determine if the gateway - * is reusable in case there's a subcription in the cart. - * - * @return bool Whether the gateway is enabled and ready to accept payments. - */ - public function is_available() { - $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ]; - if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) { - return false; - } - return parent::is_available(); - } - - /** - * Log UPE Payment Errors on Checkout. - * - * @throws Exception If nonce is not present or invalid or charge ID is empty or order not found. - */ - public function log_payment_error_ajax() { - try { - $is_nonce_valid = check_ajax_referer( 'wcpay_log_payment_error_nonce', false, false ); - if ( ! $is_nonce_valid ) { - throw new Exception( 'Invalid request.' ); - } - - $charge_id = isset( $_POST['charge_id'] ) ? wc_clean( wp_unslash( $_POST['charge_id'] ) ) : ''; - if ( empty( $charge_id ) ) { - throw new Exception( 'Charge ID cannot be empty.' ); - } - - // Get charge data from WCPay Server. - $request = Get_Charge::create( $charge_id ); - $request->set_hook_args( $charge_id ); - $charge_data = $request->send(); - $order_id = $charge_data['metadata']['order_id']; - - // Validate Order ID and proceed with logging errors and updating order status. - $order = wc_get_order( $order_id ); - if ( ! $order ) { - throw new Exception( 'Order not found. Unable to log error.' ); - } - - $intent_id = $charge_data['payment_intent'] ?? $order->get_meta( '_intent_id' ); - - $request = Get_Intention::create( $intent_id ); - $request->set_hook_args( $order ); - $intent = $request->send(); - - $intent_status = $intent->get_status(); - $error_message = esc_html( rtrim( $charge_data['failure_message'], '.' ) ); - - $this->order_service->mark_payment_failed( $order, $intent_id, $intent_status, $charge_id, $error_message ); - - wp_send_json_success(); - } catch ( Exception $e ) { - wp_send_json_error( - [ - 'error' => [ - 'message' => WC_Payments_Utils::get_filtered_error_message( $e ), - ], - ], - WC_Payments_Utils::get_filtered_error_status_code( $e ), - ); - } - } - - /** - * This function wraps WC_Payments::get_payment_method_map, useful for unit testing. - * - * @return array Array of UPE_Payment_Method instances. - */ - public function wc_payments_get_payment_method_map() { - return WC_Payments::get_payment_method_map(); - } - - /** - * Returns the checkout tile. - * - * @return string Checkout title. - */ - public function get_checkout_title() { - return $this->checkout_title; - } - - /** - * Returns the payment methods for this gateway. - * - * @return array|UPE_Payment_Method[] - */ - public function get_payment_methods() { - return $this->payment_methods; - } - - /** - * Returns the UPE payment method for the gateway. - * - * @return UPE_Payment_Method - */ - public function get_payment_method() { - return $this->payment_method; - } - - /** - * Returns Stripe payment method type ID. - * - * @return string - */ - public function get_stripe_id() { - return $this->stripe_id; - } - - /** - * Return the payment method type from the payment method details. - * - * @param array $payment_method_details Payment method details. - * @return string|null Payment method type or nothing. - */ - private function get_payment_method_type_from_payment_details( $payment_method_details ) { - return $payment_method_details['type'] ?? null; - } - - /** - * This function wraps WC_Payments::get_payment_gateway_by_id, useful for unit testing. - * - * @param string $payment_method_id Stripe payment method type ID. - * @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance. - */ - public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) { - return WC_Payments::get_payment_gateway_by_id( $payment_method_id ); - } - - /** - * This function wraps WC_Payments::get_payment_method_by_id, useful for unit testing. - * - * @param string $payment_method_id Stripe payment method type ID. - * @return false|UPE_Payment_Method Matching UPE Payment Method instance. - */ - public function wc_payments_get_payment_method_by_id( $payment_method_id ) { - return WC_Payments::get_payment_method_by_id( $payment_method_id ); - } - - /** - * Handles the shipping requirement for Afterpay payments. - * - * This method extracts the shipping and billing data from the order and sets the appropriate - * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid - * for shipping, an exception is thrown. - * - * @param WC_Order $order The order object containing shipping and billing information. - * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on. - * - * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments. - * @return void - */ - private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void { - $check_if_usable = function( array $address ): bool { - return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1']; - }; - - $shipping_data = $this->order_service->get_shipping_data_from_order( $order ); - if ( $check_if_usable( $shipping_data['address'] ) ) { - $request->set_shipping( $shipping_data ); - return; - } - - $billing_data = $this->order_service->get_billing_data_from_order( $order ); - if ( $check_if_usable( $billing_data['address'] ) ) { - $request->set_shipping( $billing_data ); - return; - } - - throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) ); - } - - - /** - * Modifies the create intent parameters when processing a payment. - * - * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request. - * - * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention. - * @param Payment_Information $payment_information The payment information object. - * @param WC_Order $order The order object. - * - * @return void - */ - protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void { - if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) { - $this->handle_afterpay_shipping_requirement( $order, $request ); - } - } -} diff --git a/src/Internal/Payment/State/ProcessedState.php b/src/Internal/Payment/State/ProcessedState.php index 7e8629121eb..5765f96ecbf 100644 --- a/src/Internal/Payment/State/ProcessedState.php +++ b/src/Internal/Payment/State/ProcessedState.php @@ -13,7 +13,7 @@ use WCPay\Internal\Service\OrderService; use WCPay\Vendor\League\Container\Exception\ContainerException; use WCPay\Internal\Proxy\LegacyProxy; -use WCPay\Payment_Methods\UPE_Payment_Gateway; +use WC_Payment_Gateway_WCPay; /** * This state is used when payment is completed on the server, and we need to update date on the plugin side. diff --git a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php index 72d9c1854e3..8c1628a9f91 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php @@ -12,7 +12,6 @@ use WCPay\Database_Cache; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Payment_Methods\Eps_Payment_Method; -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Payment_Methods\Bancontact_Payment_Method; use WCPay\Payment_Methods\Becs_Payment_Method; @@ -65,34 +64,6 @@ class WC_REST_Payments_Settings_Controller_Test extends WCPAY_UnitTestCase { */ private $mock_db_cache; - /** - * An array of mocked split UPE payment gateways mapped to payment method ID. - * - * @var UPE_Payment_Gateway - */ - private $mock_upe_payment_gateway; - - /** - * An array of mocked split UPE payment gateways mapped to payment method ID. - * - * @var UPE_Payment_Gateway - */ - private $mock_split_upe_payment_gateway; - - /** - * UPE system under test. - * - * @var WC_REST_Payments_Settings_Controller - */ - private $upe_controller; - - /** - * UPE system under test. - * - * @var WC_REST_Payments_Settings_Controller - */ - private $upe_split_controller; - /** * WC_Payments_Localization_Service instance. * @@ -144,20 +115,6 @@ public function set_up() { $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); - $this->gateway = new WC_Payment_Gateway_WCPay( - $this->mock_api_client, - $this->mock_wcpay_account, - $customer_service, - $token_service, - $action_scheduler_service, - $mock_rate_limiter, - $order_service, - $mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - $this->controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->gateway, $this->mock_wcpay_account ); - $mock_payment_methods = []; $payment_method_classes = [ Becs_Payment_Method::class, @@ -184,7 +141,7 @@ public function set_up() { $mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method; } - $this->mock_upe_payment_gateway = new UPE_Payment_Gateway( + $this->gateway = new WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $customer_service, @@ -198,25 +155,7 @@ public function set_up() { $this->mock_localization_service, $this->mock_fraud_service ); - - $this->upe_controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->mock_upe_payment_gateway, $this->mock_wcpay_account ); - - $this->mock_split_upe_payment_gateway = new UPE_Payment_Gateway( - $this->mock_api_client, - $this->mock_wcpay_account, - $customer_service, - $token_service, - $action_scheduler_service, - $mock_payment_methods['card'], - $mock_payment_methods, - $mock_rate_limiter, - $order_service, - $mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - - $this->upe_split_controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->mock_split_upe_payment_gateway, $this->mock_wcpay_account ); + $this->controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->gateway, $this->mock_wcpay_account ); $this->mock_api_client ->method( 'is_server_connected' ) @@ -267,39 +206,13 @@ public function test_get_settings_returns_enabled_payment_method_ids() { ); } - public function test_upe_get_settings_returns_available_payment_method_ids() { + public function test_get_settings_returns_available_payment_method_ids() { $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [ 'currency_code' => 'usd', ] ); - $response = $this->upe_controller->get_settings(); - $enabled_method_ids = $response->get_data()['available_payment_method_ids']; - - $this->assertEquals( - [ - Payment_Method::CARD, - Payment_Method::BECS, - Payment_Method::BANCONTACT, - Payment_Method::EPS, - Payment_Method::GIROPAY, - Payment_Method::IDEAL, - Payment_Method::SOFORT, - Payment_Method::SEPA, - Payment_Method::P24, - Payment_Method::LINK, - ], - $enabled_method_ids - ); - } - - public function test_split_upe_get_settings_returns_available_payment_method_ids() { - $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( - [ - 'currency_code' => 'usd', - ] - ); - $response = $this->upe_split_controller->get_settings(); + $response = $this->controller->get_settings(); $enabled_method_ids = $response->get_data()['available_payment_method_ids']; $this->assertEquals( @@ -436,26 +349,15 @@ public function test_update_settings_returns_error_on_non_bool_is_wcpay_enabled_ $this->assertEquals( 400, $response->get_status() ); } - public function test_upe_update_settings_saves_enabled_payment_methods() { - $this->mock_upe_payment_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] ); + public function test_update_settings_saves_enabled_payment_methods() { + $this->gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] ); $request = new WP_REST_Request(); $request->set_param( 'enabled_payment_method_ids', [ Payment_Method::CARD, Payment_Method::GIROPAY ] ); - $this->upe_controller->update_settings( $request ); + $this->controller->update_settings( $request ); - $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->mock_upe_payment_gateway->get_option( 'upe_enabled_payment_method_ids' ) ); - } - - public function test_upe_split_update_settings_saves_enabled_payment_methods() { - $this->mock_split_upe_payment_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] ); - - $request = new WP_REST_Request(); - $request->set_param( 'enabled_payment_method_ids', [ Payment_Method::CARD, Payment_Method::GIROPAY ] ); - - $this->upe_split_controller->update_settings( $request ); - - $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->mock_split_upe_payment_gateway->get_option( 'upe_enabled_payment_method_ids' ) ); + $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->gateway->get_option( 'upe_enabled_payment_method_ids' ) ); } public function test_update_settings_fails_if_user_cannot_manage_woocommerce() { @@ -769,7 +671,7 @@ public function deregister_wc_blocks_rest_api() { } } - public function test_upe_get_settings_card_eligible_flag(): void { + public function test_get_settings_card_eligible_flag(): void { // Enable Cash on Delivery gateway for the purpose of this test. $cod_gateway = WC()->payment_gateways()->payment_gateways()['cod']; $cod_gateway->enabled = 'yes'; @@ -780,26 +682,7 @@ public function test_upe_get_settings_card_eligible_flag(): void { ] ); - $response = $this->upe_controller->get_settings(); - - $this->assertArrayHasKey( 'is_card_present_eligible', $response->get_data() ); - $this->assertTrue( $response->get_data()['is_card_present_eligible'] ); - - // Disable Cash on Delivery gateway. - $cod_gateway->enabled = 'no'; - } - - public function test_upe_split_get_settings_card_eligible_flag(): void { - // Enable Cash on Delivery gateway for the purpose of this test. - $cod_gateway = WC()->payment_gateways()->payment_gateways()['cod']; - $cod_gateway->enabled = 'yes'; - - $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( - [ - 'currency_code' => 'usd', - ] - ); - $response = $this->upe_split_controller->get_settings(); + $response = $this->controller->get_settings(); $this->assertArrayHasKey( 'is_card_present_eligible', $response->get_data() ); $this->assertTrue( $response->get_data()['is_card_present_eligible'] ); @@ -808,7 +691,7 @@ public function test_upe_split_get_settings_card_eligible_flag(): void { $cod_gateway->enabled = 'no'; } - public function test_upe_get_settings_domestic_currency(): void { + public function test_get_settings_domestic_currency(): void { $mock_domestic_currency = 'usd'; $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [ @@ -819,49 +702,20 @@ public function test_upe_get_settings_domestic_currency(): void { ->expects( $this->never() ) ->method( 'get_account_default_currency' ); - $response = $this->upe_controller->get_settings(); - - $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() ); - $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] ); - } - - public function test_upe_get_settings_domestic_currency_fallbacks_to_default_currency(): void { - $mock_domestic_currency = 'usd'; - $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [] ); - $this->mock_wcpay_account - ->expects( $this->once() ) - ->method( 'get_account_default_currency' ) - ->willReturn( $mock_domestic_currency ); - $response = $this->upe_controller->get_settings(); - - $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() ); - $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] ); - } - - public function test_upe_split_get_settings_domestic_currency(): void { - $mock_domestic_currency = 'usd'; - $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( - [ - 'currency_code' => $mock_domestic_currency, - ] - ); - $this->mock_wcpay_account - ->expects( $this->never() ) - ->method( 'get_account_default_currency' ); - $response = $this->upe_split_controller->get_settings(); + $response = $this->controller->get_settings(); $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() ); $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] ); } - public function test_upe_split_get_settings_domestic_currency_fallbacks_to_default_currency(): void { + public function test_get_settings_domestic_currency_fallbacks_to_default_currency(): void { $mock_domestic_currency = 'usd'; $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [] ); $this->mock_wcpay_account ->expects( $this->once() ) ->method( 'get_account_default_currency' ) ->willReturn( $mock_domestic_currency ); - $response = $this->upe_split_controller->get_settings(); + $response = $this->controller->get_settings(); $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() ); $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] ); diff --git a/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php b/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php index a7f6ea1a1b9..9597390a9a0 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php @@ -9,6 +9,7 @@ use WCPay\Core\Server\Request\Add_Account_Tos_Agreement; use WCPay\Database_Cache; use WCPay\Duplicate_Payment_Prevention_Service; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; /** @@ -63,6 +64,7 @@ public function set_up() { $order_service = new WC_Payments_Order_Service( $this->createMock( WC_Payments_API_Client::class ) ); $action_scheduler_service = new WC_Payments_Action_Scheduler_Service( $mock_api_client, $order_service ); $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); $this->gateway = new WC_Payment_Gateway_WCPay( $mock_api_client, @@ -70,6 +72,8 @@ public function set_up() { $customer_service, $token_service, $action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $mock_rate_limiter, $order_service, $mock_dpps, diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php index cd41a804268..7c013e2b858 100644 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php @@ -1,6 +1,6 @@ mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' ) ->disableOriginalConstructor() - ->setMethods( + ->onlyMethods( [ 'get_payment_method', 'is_server_connected', @@ -224,7 +220,7 @@ public function set_up() { // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly. $this->mock_token_service = $this->getMockBuilder( 'WC_Payments_Token_Service' ) ->disableOriginalConstructor() - ->setMethods( [ 'add_payment_method_to_user' ] ) + ->onlyMethods( [ 'add_payment_method_to_user' ] ) ->getMock(); // Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly. @@ -257,7 +253,7 @@ public function set_up() { foreach ( $payment_method_classes as $payment_method_class ) { $mock_payment_method = $this->getMockBuilder( $payment_method_class ) ->setConstructorArgs( [ $this->mock_token_service ] ) - ->setMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] ) + ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] ) ->getMock(); $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method; } @@ -268,7 +264,7 @@ public function set_up() { $this->mock_api_client, ] ) - ->setMethods( + ->onlyMethods( [ 'get_payment_method_id_for_order', ] @@ -281,9 +277,9 @@ public function set_up() { ->getMock(); $this->mock_payment_methods[ $this->mock_payment_method->get_id() ] = $this->mock_payment_method; - // Arrange: Mock UPE_Payment_Gateway so that some of its methods can be + // Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be // mocked, and their return values can be used for testing. - $this->mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $this->mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -312,13 +308,13 @@ public function set_up() { ->getMock(); // Arrange: Set the return value of get_return_url() so it can be used in a test later. - $this->mock_upe_gateway + $this->mock_gateway ->expects( $this->any() ) ->method( 'get_return_url' ) ->will( $this->returnValue( $this->return_url ) ); - $this->mock_upe_gateway + $this->mock_gateway ->expects( $this->any() ) ->method( 'parent_process_payment' ) ->will( @@ -329,7 +325,7 @@ public function set_up() { // so that get_payment_method_from_request() does not throw error. $_POST = [ 'wcpay-payment-method' => 'pm_mock', - 'payment_method' => UPE_Payment_Gateway::GATEWAY_ID, + 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, ]; // Mock the level3 service to always return an empty array. @@ -358,207 +354,53 @@ public function tear_down() { wcpay_get_test_container()->reset_all_replacements(); } - public function test_process_payment_returns_correct_redirect_url() { - $order = WC_Helper_Order::create_order(); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ); - - $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); - - $this->set_cart_contains_subscription_items( false ); - - $result = $this->mock_upe_gateway->process_payment( $order->get_id() ); - - unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( true, $result['payment_needed'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=no/', $result['redirect_url'] ); - } - - public function test_process_subscription_payment_passes_save_payment_method() { - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ); - - $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); + public function test_process_payment_returns_correct_redirect_when_using_saved_payment() { + $order = WC_Helper_Order::create_order(); + $_POST = $this->setup_saved_payment_method(); + $intent = WC_Helper_Intention::create_intention(); - $this->mock_upe_gateway + $this->mock_gateway->expects( $this->once() ) + ->method( 'manage_customer_details_for_order' ) + ->will( + $this->returnValue( [ wp_get_current_user(), 'cus_123' ] ) + ); + $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() ) ->expects( $this->once() ) - ->method( 'is_payment_recurring' ) - ->willReturn( true ); - - $result = $this->mock_upe_gateway->process_payment( $order->get_id() ); - - unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( true, $result['payment_needed'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] ); - } - - public function test_process_payment_returns_correct_redirect_when_using_saved_payment() { - $order = WC_Helper_Order::create_order(); - $_POST = $this->setup_saved_payment_method(); + ->method( 'format_response' ) + ->willReturn( $intent ); $this->set_cart_contains_subscription_items( false ); - $this->mock_upe_gateway - ->expects( $this->never() ) - ->method( 'manage_customer_details_for_order' ); - - $result = $this->mock_upe_gateway->process_payment( $order->get_id() ); + $result = $this->mock_gateway->process_payment( $order->get_id() ); $this->assertEquals( 'success', $result['result'] ); - $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] ); + $this->assertEquals( $this->return_url, $result['redirect'] ); } public function test_process_payment_returns_correct_redirect_when_using_payment_request() { $order = WC_Helper_Order::create_order(); + $intent = WC_Helper_Intention::create_intention(); $_POST['payment_request_type'] = 'google_pay'; - $this->set_cart_contains_subscription_items( false ); - - $result = $this->mock_upe_gateway->process_payment( $order->get_id() ); - - $this->mock_upe_gateway - ->expects( $this->never() ) - ->method( 'manage_customer_details_for_order' ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] ); - } - - public function test_upe_process_payment_check_session_order_redirect_to_previous_order() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $response = [ - 'dummy_result' => 'xyz', - ]; - - // Arrange the order is being processed. - $current_order = WC_Helper_Order::create_order(); - $current_order_id = $current_order->get_id(); - - // Arrange the DPPS to return an order from the session. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_against_session_processing_order' ) - ->with( wc_get_order( $current_order ) ) - ->willReturn( $response ); - - // Assert: no call to the server to confirm the payment. - $this->mock_wcpay_request( Update_Intention::class, 0, 'pi_XXXXX' ); - - // Act: process the order but redirect to the previous/session paid order. - $result = $this->mock_upe_gateway->process_payment( $current_order_id ); - - // Assert: the result of check_against_session_processing_order. - $this->assertSame( $response, $result ); - } - - public function test_upe_process_payment_check_session_with_failed_intent_then_order_id_saved_to_session() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Arrange the order is being processed. - $current_order = WC_Helper_Order::create_order(); - $current_order_id = $current_order->get_id(); - - // Arrange a failed intention. - $intent = WC_Helper_Intention::create_intention( [ 'status' => 'failed' ] ); - - // Assert. - $update_request = $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() ); - $update_request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $intent ); - - // Arrange the DPPS not to return an order from the session. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_against_session_processing_order' ) - ->with( wc_get_order( $current_order ) ) - ->willReturn( null ); - - // Assert: maybe_update_session_processing_order takes action and its value is kept. - $this->mock_dpps->expects( $this->once() ) - ->method( 'maybe_update_session_processing_order' ) - ->with( $current_order_id ); - - // Act: process the order but redirect to the previous/session paid order. - $this->mock_upe_gateway->process_payment( $current_order_id ); - } - - public function test_upe_process_payment_check_session_and_continue_processing() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Arrange the order is being processed. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange a successful intention. - $intent = WC_Helper_Intention::create_intention(); - - // Arrange the DPPS not to return an order from the session. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_against_session_processing_order' ) - ->with( wc_get_order( $order ) ) - ->willReturn( null ); - - // Assert: Order is removed from the session. - $this->mock_dpps->expects( $this->once() ) - ->method( 'remove_session_processing_order' ) - ->with( $order_id ); - - // Assert: the payment process continues. - $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() ) + $this->mock_gateway->expects( $this->once() ) + ->method( 'manage_customer_details_for_order' ) + ->will( + $this->returnValue( [ wp_get_current_user(), 'cus_123' ] ) + ); + $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() ) ->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( $intent ); + $this->set_cart_contains_subscription_items( false ); - // Act. - $this->mock_upe_gateway->process_payment( $order_id ); - } - - public function test_upe_check_payment_intent_attached_to_order_succeeded_return_redirection() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $response = [ - 'dummy_result' => 'xyz', - ]; - - // Arrange order. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange the DPPS to return a prepared response. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_payment_intent_attached_to_order_succeeded' ) - ->with( wc_get_order( $order ) ) - ->willReturn( $response ); - - // Assert: no more call to the server to update the intention. - $this->mock_wcpay_request( Update_Intention::class, 0 ); - - // Act: process the order but redirect to the order. - $result = $this->mock_upe_gateway->process_payment( $order_id ); + $result = $this->mock_gateway->process_payment( $order->get_id() ); - // Assert: the result of check_intent_attached_to_order_succeeded. - $this->assertSame( $response, $result ); + $this->assertEquals( 'success', $result['result'] ); + $this->assertEquals( $this->return_url, $result['redirect'] ); } public function is_proper_intent_used_with_order_returns_false() { - $this->assertFalse( $this->mock_upe_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) ); + $this->assertFalse( $this->mock_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) ); } public function test_process_redirect_payment_intent_processing() { @@ -584,7 +426,7 @@ public function test_process_redirect_payment_intent_processing() { ] ); - $this->mock_upe_gateway->expects( $this->once() ) + $this->mock_gateway->expects( $this->once() ) ->method( 'manage_customer_details_for_order' ) ->will( $this->returnValue( [ $user, $customer_id ] ) @@ -598,7 +440,7 @@ public function test_process_redirect_payment_intent_processing() { $this->set_cart_contains_subscription_items( false ); - $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); $result_order = wc_get_order( $order_id ); $note = wc_get_order_notes( @@ -640,7 +482,7 @@ public function test_process_redirect_payment_intent_succeded() { ] ); - $this->mock_upe_gateway->expects( $this->once() ) + $this->mock_gateway->expects( $this->once() ) ->method( 'manage_customer_details_for_order' ) ->will( $this->returnValue( [ $user, $customer_id ] ) @@ -654,7 +496,7 @@ public function test_process_redirect_payment_intent_succeded() { $this->set_cart_contains_subscription_items( false ); - $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); $result_order = wc_get_order( $order_id ); @@ -674,7 +516,7 @@ public function test_validate_order_id_received_vs_intent_meta_order_id_throw_ex $this->expectExceptionMessage( "We're not able to process this payment due to the order ID mismatch. Please try again later." ); \PHPUnit_Utils::call_method( - $this->mock_upe_gateway, + $this->mock_gateway, 'validate_order_id_received_vs_intent_meta_order_id', [ $order, $intent_metadata ] ); @@ -685,7 +527,7 @@ public function test_validate_order_id_received_vs_intent_meta_order_id_returnin $intent_metadata = [ 'order_id' => (string) ( $order->get_id() ) ]; $res = \PHPUnit_Utils::call_method( - $this->mock_upe_gateway, + $this->mock_gateway, 'validate_order_id_received_vs_intent_meta_order_id', [ $order, $intent_metadata ] ); @@ -771,7 +613,7 @@ public function test_correct_payment_method_title_for_order() { ]; foreach ( $charge_payment_method_details as $i => $payment_method_details ) { - $this->mock_upe_gateway->set_payment_method_title_for_order( $order, $payment_method_details['type'], $payment_method_details ); + $this->mock_gateway->set_payment_method_title_for_order( $order, $payment_method_details['type'], $payment_method_details ); $this->assertEquals( $expected_payment_method_titles[ $i ], $order->get_payment_method_title() ); } } @@ -1069,24 +911,7 @@ public function test_create_token_from_setup_intent_adds_token() { $this->returnValue( $mock_token ) ); - $this->assertEquals( $mock_token, $this->mock_upe_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) ); - } - - public function test_process_payment_rejects_with_cached_minimum_acount() { - $order = WC_Helper_Order::create_order(); - $order->set_currency( 'USD' ); - $order->set_total( 0.45 ); - $order->save(); - - set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS ); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Make sure that the payment was not actually processed. - $price = wp_strip_all_tags( html_entity_decode( wc_price( 0.5, [ 'currency' => 'USD' ] ) ) ); - $message = 'The selected payment method requires a total amount of at least ' . $price . '.'; - $this->expectException( Exception::class ); - $this->expectExceptionMessage( $message ); - $this->mock_upe_gateway->process_payment( $order->get_id() ); + $this->assertEquals( $mock_token, $this->mock_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) ); } public function test_exception_will_be_thrown_if_phone_number_is_invalid() { @@ -1095,66 +920,20 @@ public function test_exception_will_be_thrown_if_phone_number_is_invalid() { $order->save(); $this->expectException( Exception::class ); $this->expectExceptionMessage( 'Invalid phone number.' ); - $this->mock_upe_gateway->process_payment( $order->get_id() ); - } - - public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() { - $amount = 0.45; - $customer = 'cus_12345'; - $payment_intent_id = 'pi_mock'; - - $order = WC_Helper_Order::create_order(); - $order->set_total( $amount ); - $order->save(); - - delete_transient( 'wcpay_minimum_amount_usd' ); - - $_POST['wc_payment_intent_id'] = $payment_intent_id; - - $request = $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent_id ); - - $request->expects( $this->once() ) - ->method( 'set_amount' ) - ->with( (int) ( $amount * 100 ) ); - - $request->expects( $this->once() ) - ->method( 'set_level3' ) - ->with( - $this->callback( - function( $argument ) { - return is_array( $argument ); - } - ) - ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->will( $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $60 usd', 6000, 'usd', 400 ) ) ); - - $price = wp_strip_all_tags( html_entity_decode( wc_price( 60, [ 'currency' => 'USD' ] ) ) ); - $message = 'The selected payment method requires a total amount of at least ' . $price . '.'; - $this->expectException( Exception::class ); - $this->expectExceptionMessage( $message ); - - try { - $this->mock_upe_gateway->process_payment( $order->get_id() ); - } catch ( Exception $e ) { - $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) ); - throw $e; - } + $this->mock_gateway->process_payment( $order->get_id() ); } public function test_remove_link_payment_method_if_card_disabled() { - $this->mock_upe_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; + $this->mock_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; - $this->mock_upe_gateway + $this->mock_gateway ->expects( $this->once() ) ->method( 'get_upe_enabled_payment_method_statuses' ) ->will( $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] ) ); - $this->assertSame( $this->mock_upe_gateway->get_payment_method_ids_enabled_at_checkout(), [] ); + $this->assertSame( $this->mock_gateway->get_payment_method_ids_enabled_at_checkout(), [] ); } /** @@ -1167,7 +946,7 @@ public function test_get_upe_available_payment_methods( $payment_methods, $expec ->method( 'get_fees' ) ->willReturn( $payment_methods ); - $gateway = new UPE_Payment_Gateway( + $gateway = new WC_Payment_Gateway_WCPay( $this->mock_api_client, $mock_wcpay_account, $this->mock_customer_service, @@ -1239,7 +1018,7 @@ private function set_get_upe_enabled_payment_method_statuses_return_value( $retu ], ]; } - $this->mock_upe_gateway + $this->mock_gateway ->expects( $this->any() ) ->method( 'get_upe_enabled_payment_method_statuses' ) ->will( $this->returnValue( $return_value ) ); diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php index 54ffd9669f0..e788e467a14 100644 --- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php @@ -1,6 +1,6 @@ 'pm_mock', - 'payment_method' => UPE_Payment_Gateway::GATEWAY_ID, + 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, ]; $get_payment_gateway_by_id_return_value_map = []; @@ -268,7 +266,7 @@ public function set_up() { ->getMock(); $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method; - $mock_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -412,141 +410,36 @@ public function test_non_reusable_payment_method_is_not_available_when_subscript $this->assertFalse( $payment_gateway->is_available() ); } - public function test_process_payment_returns_correct_redirect_url() { - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ); - - $this->set_cart_contains_subscription_items( false ); - - foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) { - $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); - - $result = $mock_payment_gateway->process_payment( $order->get_id() ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( true, $result['payment_needed'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=no/', $result['redirect_url'] ); - } - - unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - } - - public function test_process_payment_passes_save_payment_method_to_store() { - $mock_sepa_payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - - $order = WC_Helper_Order::create_order(); - $gateway_id = UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::SEPA; - $save_payment_param = "wc-$gateway_id-new-payment-method"; - $_POST[ $save_payment_param ] = 'yes'; - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ); - - $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( - $payment_intent - ); - - $this->set_cart_contains_subscription_items( false ); - - // Test saving with SEPA. - $result = $mock_sepa_payment_gateway->process_payment( $order->get_id() ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] ); - - unset( $_POST[ $save_payment_param ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - } - - public function test_process_subscription_payment_passes_save_payment_method() { + public function test_process_payment_returns_correct_redirect_when_using_saved_payment() { $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - $mock_sepa_payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - - $order = WC_Helper_Order::create_order(); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ); + $user = wp_get_current_user(); + $customer_id = 'cus_mock'; - // Test card. - $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( - $payment_intent + $order = WC_Helper_Order::create_order(); + $_POST = $this->setup_saved_payment_method(); + $mock_card_payment_gateway->expects( $this->once() ) + ->method( 'manage_customer_details_for_order' ) + ->will( + $this->returnValue( [ $user, $customer_id ] ) ); - - $mock_card_payment_gateway - ->expects( $this->once() ) - ->method( 'is_payment_recurring' ) - ->willReturn( true ); - $result = $mock_card_payment_gateway->process_payment( $order->get_id() ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( true, $result['payment_needed'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] ); - - // Test SEPA. - $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() ) + $mock_card_payment_gateway->expects( $this->any() ) + ->method( 'get_upe_enabled_payment_method_ids' ) + ->will( + $this->returnValue( [ Payment_Method::CARD ] ) + ); + $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 ) ->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( - $payment_intent + WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ) ); - $mock_sepa_payment_gateway - ->expects( $this->once() ) - ->method( 'is_payment_recurring' ) - ->willReturn( true ); - $result = $mock_sepa_payment_gateway->process_payment( $order->get_id() ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( true, $result['payment_needed'] ); - $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] ); - $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] ); - - unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing - } - - public function test_process_payment_returns_correct_redirect_when_using_saved_payment() { - $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - - $order = WC_Helper_Order::create_order(); - $_POST = $this->setup_saved_payment_method(); - $this->set_cart_contains_subscription_items( false ); $result = $mock_card_payment_gateway->process_payment( $order->get_id() ); - $mock_card_payment_gateway - ->expects( $this->never() ) - ->method( 'manage_customer_details_for_order' ); $this->assertEquals( 'success', $result['result'] ); - $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] ); - } - - public function test_process_payment_returns_correct_redirect_when_using_payment_request() { - $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - - $order = WC_Helper_Order::create_order(); - $_POST['payment_request_type'] = 'google_pay'; - - $this->set_cart_contains_subscription_items( false ); - - $result = $mock_card_payment_gateway->process_payment( $order->get_id() ); - - $mock_card_payment_gateway - ->expects( $this->never() ) - ->method( 'manage_customer_details_for_order' ); - $this->assertEquals( 'success', $result['result'] ); - $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] ); + $this->assertEquals( $this->return_url, $result['redirect'] ); } public function test_upe_process_payment_check_session_order_redirect_to_previous_order() { @@ -574,113 +467,6 @@ public function test_upe_process_payment_check_session_order_redirect_to_previou $this->assertSame( $response, $result ); } - public function test_upe_process_payment_check_session_with_failed_intent_then_order_id_saved_to_session() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Arrange the order is being processed. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange a failed intention. - $intent = WC_Helper_Intention::create_intention( [ 'status' => 'failed' ] ); - - // Assert. - $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $intent ); - - // Make sure the DPPS will store the order. - $this->mock_dpps->expects( $this->once() ) - ->method( 'maybe_update_session_processing_order' ) - ->with( $order_id ); - - // Act: process the order but redirect to the previous/session paid order. - $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id ); - } - - public function test_upe_process_payment_check_session_and_continue_processing() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - - // Arrange the order is being processed. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange a successful intention. - $intent = WC_Helper_Intention::create_intention(); - - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [] ); - - // Arrange the DPPs not to return anything. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_against_session_processing_order' ) - ->with( wc_get_order( $order ) ) - ->willReturn( null ); - - $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $intent ); - - // Act. - $mock_upe_gateway->process_payment( $order_id ); - } - - public function test_upe_check_payment_intent_attached_to_order_succeeded_with_invalid_intent_id_continue_process_payment() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Arrange order. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange the DPPS not to return a redirect. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_payment_intent_attached_to_order_succeeded' ) - ->with( wc_get_order( $order ) ) - ->willReturn( null ); - - // Assert: the payment process continues. - $intent = WC_Helper_Intention::create_intention(); - $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $intent ); - - // Act: process the order. - $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id ); - } - - public function test_upe_check_payment_intent_attached_to_order_succeeded_return_redirection() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $response = [ - 'dummy_result' => 'xyz', - ]; - - // Arrange order. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange the DPPS to return a redirect based on a redirect. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_payment_intent_attached_to_order_succeeded' ) - ->with( wc_get_order( $order ) ) - ->willReturn( $response ); - - // Assert: no more call to the server to update the intention. - $this->mock_wcpay_request( Update_Intention::class, 0 ); - - // Act: process the order but redirect to the order. - $result = $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id ); - - // Assert: the result of check_intent_attached_to_order_succeeded. - $this->assertSame( $response, $result ); - } - public function test_process_redirect_payment_intent_processing() { $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; @@ -1263,64 +1049,13 @@ public function test_create_token_from_setup_intent_adds_token() { } } - public function test_process_payment_rejects_with_cached_minimum_acount() { - - $order = WC_Helper_Order::create_order(); - $order->set_currency( 'USD' ); - $order->set_total( 0.45 ); - $order->save(); - - set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS ); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - // Make sure that the payment was not actually processed. - $price = wp_strip_all_tags( html_entity_decode( wc_price( 0.5, [ 'currency' => 'USD' ] ) ) ); - $message = 'The selected payment method requires a total amount of at least ' . $price . '.'; - - foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) { - $this->expectException( Exception::class ); - $this->expectExceptionMessage( $message ); - $mock_payment_gateway->process_payment( $order->get_id() ); - } - } - - public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() { - $order = WC_Helper_Order::create_order(); - $order->set_total( 0.45 ); - $order->save(); - - delete_transient( 'wcpay_minimum_amount_usd' ); - $_POST['wc_payment_intent_id'] = 'pi_mock'; - - $price = wp_strip_all_tags( html_entity_decode( wc_price( 60, [ 'currency' => 'USD' ] ) ) ); - $message = 'The selected payment method requires a total amount of at least ' . $price . '.'; - $this->expectException( Exception::class ); - $this->expectExceptionMessage( $message ); - - try { - foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) { - $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->will( $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $60 usd', 6000, 'usd', 400 ) ) ); - - $mock_payment_gateway->process_payment( $order->get_id() ); - - break; - } - } catch ( Exception $e ) { - $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) ); - throw $e; - } - } - /** * Test get_payment_method_types with regular checkout post request context. * * @return void */ public function test_get_payment_methods_with_request_context() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -1365,7 +1100,7 @@ public function test_get_payment_methods_with_request_context() { * @return void */ public function test_get_payment_methods_without_request_context() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -1409,7 +1144,7 @@ public function test_get_payment_methods_without_request_context() { * @return void */ public function test_get_payment_methods_without_request_context_or_token() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -1462,7 +1197,7 @@ public function test_get_payment_methods_without_request_context_or_token() { */ public function test_get_payment_methods_from_gateway_id_upe() { WC_Helper_Order::create_order(); - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -1496,7 +1231,7 @@ public function test_get_payment_methods_from_gateway_id_upe() { $this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] ) ); - $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::BANCONTACT ); + $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT ); $this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods ); $mock_upe_gateway->expects( $this->any() ) @@ -1508,10 +1243,10 @@ public function test_get_payment_methods_from_gateway_id_upe() { ) ); - $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID ); + $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID ); $this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods ); - $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID ); + $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID ); $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); WC_Payments::set_gateway( $gateway ); diff --git a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php index 94273521a05..aca6138622e 100644 --- a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php +++ b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php @@ -16,7 +16,7 @@ use WCPay\Internal\Service\DuplicatePaymentPreventionService; use WCPay\Internal\Service\OrderService; use WCPay\Internal\Proxy\LegacyProxy; -use WCPay\Payment_Methods\UPE_Payment_Gateway; +use WC_Payment_Gateway_WCPay; use WCPAY_UnitTestCase; /** diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php b/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php index e80c97b1834..8cd1668986d 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php @@ -11,7 +11,7 @@ use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Session_Rate_Limiter; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; -use WCPay\Internal\Service\OrderService; +use WCPay\Payment_Methods\CC_Payment_Method; /** * WC_Payment_Gateway_WCPay unit tests. @@ -133,7 +133,8 @@ public function set_up() { $this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); - $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); // Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be // mocked, and their return values can be used for testing. @@ -145,6 +146,8 @@ public function set_up() { $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_rate_limiter, $this->mock_order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php index da7ed2798db..1ce7132f420 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php @@ -6,19 +6,17 @@ */ use WCPay\Core\Server\Request\Create_And_Confirm_Intention; -use WCPay\Core\Server\Request\WooPay_Create_And_Confirm_Intention; use WCPay\Core\Server\Request\Create_And_Confirm_Setup_Intention; use WCPay\Core\Server\Request\Get_Charge; -use WCPay\Core\Server\Response; use WCPay\Constants\Order_Status; use WCPay\Constants\Intent_Status; -use WCPay\Core\Server\Request\Get_Intention; -use WCPay\Core\Server\Request\Update_Intention; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Exceptions\API_Exception; use WCPay\Exceptions\Connection_Exception; use WCPay\Session_Rate_Limiter; use WCPay\Constants\Payment_Method; +use WCPay\Payment_Methods\CC_Payment_Method; + // Need to use WC_Mock_Data_Store. require_once dirname( __FILE__ ) . '/helpers/class-wc-mock-wc-data-store.php'; @@ -149,7 +147,8 @@ public function set_up() { $this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); - $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); // Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be // mocked, and their return values can be used for testing. @@ -161,6 +160,8 @@ public function set_up() { $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_rate_limiter, $this->mock_order_service, $this->mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php b/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php index 79c11b5fe1b..7350621aedc 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php @@ -13,6 +13,7 @@ use WCPay\Core\Server\Response; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Exceptions\API_Exception; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; // Need to use WC_Mock_Data_Store. @@ -89,6 +90,7 @@ public function set_up() { $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); $this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); $this->wcpay_gateway = new WC_Payment_Gateway_WCPay( $this->mock_api_client, @@ -96,6 +98,8 @@ public function set_up() { $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_rate_limiter, $this->mock_order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php index 73be48c5cbc..9715d61a193 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php @@ -6,7 +6,7 @@ */ use WCPay\Duplicate_Payment_Prevention_Service; -use WCPay\Exceptions\API_Exception; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; /** @@ -96,6 +96,9 @@ public function set_up() { ->getMock(); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_wcpay_account + ->method( 'get_account_default_currency' ) + ->willReturn( 'USD' ); $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' ) ->disableOriginalConstructor() @@ -119,12 +122,19 @@ public function set_up() { $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'is_subscription_item_in_cart' ] ) + ->getMock(); + $this->wcpay_gateway = new \WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_session_rate_limiter, $this->mock_order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php index 0db2ec88933..168349f902d 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php @@ -7,10 +7,10 @@ use WCPay\Core\Server\Request\Create_And_Confirm_Intention; use WCPay\Core\Server\Request\Create_And_Confirm_Setup_Intention; -use WCPay\Core\Server\Response; use WCPay\Constants\Order_Status; use WCPay\Constants\Intent_Status; use WCPay\Duplicate_Payment_Prevention_Service; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; /** @@ -122,6 +122,9 @@ public function set_up() { ->getMock(); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_wcpay_account + ->method( 'get_account_default_currency' ) + ->willReturn( 'usd' ); $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' ) ->disableOriginalConstructor() @@ -139,7 +142,8 @@ public function set_up() { $this->order_service = new WC_Payments_Order_Service( $this->mock_api_client ); - $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); $this->mock_wcpay_gateway = $this->getMockBuilder( '\WC_Payment_Gateway_WCPay' ) ->setConstructorArgs( @@ -149,6 +153,8 @@ public function set_up() { $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_rate_limiter, $this->order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php index 9c27fda1b2d..a5b33c1581c 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php @@ -11,6 +11,7 @@ use WCPay\Exceptions\API_Exception; use WCPay\Internal\Service\Level3Service; use WCPay\Internal\Service\OrderService; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; /** @@ -111,6 +112,9 @@ public function set_up() { ->getMock(); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_wcpay_account + ->method( 'get_account_default_currency' ) + ->willReturn( 'usd' ); $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' ) ->disableOriginalConstructor() @@ -135,12 +139,19 @@ public function set_up() { $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); + $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'is_subscription_item_in_cart' ] ) + ->getMock(); + $this->wcpay_gateway = new \WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_session_rate_limiter, $this->order_service, $this->mock_dpps, @@ -148,6 +159,7 @@ public function set_up() { $this->mock_fraud_service ); $this->wcpay_gateway->init_hooks(); + WC_Payments::set_gateway( $this->wcpay_gateway ); // Mock the level3 service to always return an empty array. $mock_level3_service = $this->createMock( Level3Service::class ); @@ -801,12 +813,19 @@ public function test_adds_custom_payment_meta_input_fallback_until_subs_3_0_7() WC_Subscriptions::$version = '3.0.7'; + $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'is_subscription_item_in_cart' ] ) + ->getMock(); + $payment_gateway = new \WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_session_rate_limiter, $this->order_service, $this->mock_dpps, @@ -827,6 +846,11 @@ public function test_adds_custom_payment_meta_input_fallback_until_subs_3_0_7() public function test_does_not_add_custom_payment_meta_input_fallback_for_subs_3_0_8() { remove_all_actions( 'woocommerce_admin_order_data_after_billing_address' ); + $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'is_subscription_item_in_cart' ] ) + ->getMock(); + WC_Subscriptions::$version = '3.0.8'; new \WC_Payment_Gateway_WCPay( $this->mock_api_client, @@ -834,6 +858,8 @@ public function test_does_not_add_custom_payment_meta_input_fallback_for_subs_3_ $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $this->mock_session_rate_limiter, $this->order_service, $this->mock_dpps, diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php index 3eb69d5cfb5..02505f94d51 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php @@ -13,9 +13,7 @@ use WCPay\Core\Server\Request\Get_Charge; use WCPay\Core\Server\Request\Get_Intention; use WCPay\Core\Server\Request\Get_Setup_Intention; -use WCPay\Core\Server\Request\Update_Intention; use WCPay\Constants\Order_Status; -use WCPay\Constants\Payment_Type; use WCPay\Constants\Intent_Status; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Exceptions\Amount_Too_Small_Exception; @@ -30,7 +28,6 @@ use WCPay\Payment_Information; use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Payment_Methods\Sepa_Payment_Method; -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; @@ -48,7 +45,7 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { /** * System under test. * - * @var UPE_Payment_Gateway + * @var WC_Payment_Gateway_WCPay */ private $wcpay_gateway; @@ -214,7 +211,7 @@ public function set_up() { ->setMethods( [ 'is_subscription_item_in_cart' ] ) ->getMock(); - $this->wcpay_gateway = new UPE_Payment_Gateway( + $this->wcpay_gateway = new WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, @@ -2006,7 +2003,7 @@ public function test_is_in_test_mode() { * @return MockObject|WC_Payment_Gateway_WCPay */ private function get_partial_mock_for_gateway( array $methods = [] ) { - return $this->getMockBuilder( UPE_Payment_Gateway::class ) + return $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -2363,7 +2360,7 @@ private function create_charge_object() { } private function create_gateway_with( $payment_method ) { - return new UPE_Payment_Gateway( + return new WC_Payment_Gateway_WCPay( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php index b187c4f51ce..d6273a1fcd2 100644 --- a/tests/unit/test-class-wc-payments-checkout.php +++ b/tests/unit/test-class-wc-payments-checkout.php @@ -8,7 +8,6 @@ use WCPay\WC_Payments_Checkout; use PHPUnit\Framework\MockObject\MockObject; use WCPay\Constants\Payment_Method; -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\WooPay\WooPay_Utilities; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; use WCPay\Payment_Methods\Bancontact_Payment_Method; @@ -36,9 +35,9 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase { private $system_under_test; /** - * UPE_Payment_Gateway instance. + * WC_Payment_Gateway_WCPay instance. * - * @var UPE_Payment_Gateway|MockObject + * @var WC_Payment_Gateway_WCPay|MockObject */ private $mock_wcpay_gateway; @@ -81,7 +80,7 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase { /** * Default gateway. * - * @var UPE_Payment_Gateway + * @var WC_Payment_Gateway_WCPay */ private $default_gateway; @@ -89,7 +88,7 @@ public function set_up() { parent::set_up(); // Setup the gateway mock. - $this->mock_wcpay_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) + $this->mock_wcpay_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) ->onlyMethods( [ 'get_account_domestic_currency', 'get_payment_method_ids_enabled_at_checkout', 'should_use_stripe_platform_on_checkout_page', 'should_support_saved_payments', 'is_saved_cards_enabled', 'save_payment_method_checkbox', 'get_account_statement_descriptor', 'get_icon_url', 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees', 'is_subscription_item_in_cart', 'wc_payments_get_payment_method_by_id', 'display_gateway_html' ] ) ->disableOriginalConstructor() ->getMock(); @@ -119,8 +118,7 @@ public function set_up() { $this->mock_token_service = $this->createMock( WC_Payments_Token_Service::class ); // This is needed to ensure that only the mocked gateway is always used by the checkout class. - $this->default_gateway = WC_Payments::get_registered_card_gateway(); - WC_Payments::set_registered_card_gateway( $this->mock_wcpay_gateway ); + $this->default_gateway = WC_Payments::get_gateway(); WC_Payments::set_gateway( $this->mock_wcpay_gateway ); // Use a callback to suppresses the output buffering being printed to the CLI. @@ -135,7 +133,6 @@ function ( $output ) { public function tear_down() { parent::tear_down(); - WC_Payments::set_registered_card_gateway( $this->default_gateway ); WC_Payments::set_gateway( $this->default_gateway ); } diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php index dfb059ba7b4..899e530aa67 100644 --- a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php +++ b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\MockObject\MockObject; use WCPay\Duplicate_Payment_Prevention_Service; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; use WCPay\WooPay\WooPay_Utilities; @@ -148,6 +149,7 @@ private function make_wcpay_gateway() { $mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); $mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); return new WC_Payment_Gateway_WCPay( $this->mock_api_client, @@ -155,6 +157,8 @@ private function make_wcpay_gateway() { $mock_customer_service, $mock_token_service, $mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $mock_rate_limiter, $mock_order_service, $mock_dpps, 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 ce1283265b4..e4d7412bf15 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 @@ -6,6 +6,7 @@ */ use WCPay\Duplicate_Payment_Prevention_Service; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; /** @@ -198,6 +199,7 @@ private function make_wcpay_gateway() { $mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); $mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); return new WC_Payment_Gateway_WCPay( $this->mock_api_client, @@ -205,6 +207,8 @@ private function make_wcpay_gateway() { $mock_customer_service, $mock_token_service, $mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $mock_rate_limiter, $mock_order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payments-woopay-button-handler.php b/tests/unit/test-class-wc-payments-woopay-button-handler.php index 78f464cadf2..161c5796101 100644 --- a/tests/unit/test-class-wc-payments-woopay-button-handler.php +++ b/tests/unit/test-class-wc-payments-woopay-button-handler.php @@ -6,6 +6,7 @@ */ use WCPay\Duplicate_Payment_Prevention_Service; +use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; use WCPay\WooPay\WooPay_Utilities; @@ -127,6 +128,7 @@ private function make_wcpay_gateway() { $mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); $mock_order_service = $this->createMock( WC_Payments_Order_Service::class ); $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); + $mock_payment_method = $this->createMock( CC_Payment_Method::class ); return new WC_Payment_Gateway_WCPay( $this->mock_api_client, @@ -134,6 +136,8 @@ private function make_wcpay_gateway() { $mock_customer_service, $mock_token_service, $mock_action_scheduler_service, + $mock_payment_method, + [ 'card' => $mock_payment_method ], $mock_rate_limiter, $mock_order_service, $mock_dpps, diff --git a/tests/unit/test-class-wc-payments.php b/tests/unit/test-class-wc-payments.php index ce6aa216a1d..d5e7da12239 100644 --- a/tests/unit/test-class-wc-payments.php +++ b/tests/unit/test-class-wc-payments.php @@ -5,7 +5,6 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\WooPay\WooPay_Session; /** @@ -81,7 +80,7 @@ public function test_it_does_not_register_woopay_hooks_if_feature_flag_is_disabl public function test_it_skips_stripe_link_gateway_registration() { $this->mock_cache->method( 'get' )->willReturn( [ 'is_deferred_intent_creation_upe_enabled' => true ] ); - $card_gateway_mock = $this->createMock( UPE_Payment_Gateway::class ); + $card_gateway_mock = $this->createMock( WC_Payment_Gateway_WCPay::class ); $card_gateway_mock ->expects( $this->once() ) ->method( 'get_payment_method_ids_enabled_at_checkout' ) @@ -100,7 +99,7 @@ public function test_it_skips_stripe_link_gateway_registration() { $registered_gateways = WC_Payments::register_gateway( [] ); $this->assertCount( 1, $registered_gateways ); - $this->assertInstanceOf( UPE_Payment_Gateway::class, $registered_gateways[0] ); + $this->assertInstanceOf( WC_Payment_Gateway_WCPay::class, $registered_gateways[0] ); $this->assertEquals( $registered_gateways[0]->get_stripe_id(), 'card' ); } From 0af42f558c730ee97a461931c06360026241f657 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:07:35 +0000 Subject: [PATCH 3/8] Update version and add changelog entries for release 7.0.0 --- changelog.txt | 56 ++++++++++++++++++ changelog/7588-express-checkout-utilities | 4 -- .../add-334-test-mode-notice-order-details | 4 -- ...ancel-authorizations-if-order-is-cancelled | 4 -- ...-7248-refund-transaction-from-details-page | 4 -- changelog/add-7591-missing-columns-export-csv | 4 -- changelog/add-7846-test-mode-confirm-modal | 4 -- changelog/add-thank-you-page-tracks | 4 -- changelog/cleanup-devtools-flags | 4 -- changelog/cleanup-is-upe-enabled-logic | 4 -- changelog/cleanup-redundant-script-enqueueing | 4 -- changelog/cleanup-upe-checkout-class | 4 -- changelog/cleanup-upe-gateways-II | 4 -- changelog/cleanup-upe-gateways-part-1 | 4 -- changelog/deferred-intent | 4 -- .../dev-3468-allow-reset-account-management | 4 -- changelog/dev-bump-wc-version-8-4-0 | 4 -- changelog/dev-fix-e2e-tests-on-wc-7-7 | 5 -- changelog/dev-fix-multi-currency-e2e-tests | 5 -- changelog/dev-test-ci-without-3ds1 | 4 -- changelog/e2e-7349-currency-switcher-widget | 4 -- ...2e-7382-spec-merchant-multi-currency-setup | 4 -- changelog/fix-3693-qualitative-feedback-note | 4 -- ...700-remove-currency-sign-modification-code | 4 -- changelog/fix-6782-support-phone-dev-mode | 4 -- ...ror-while-trying-to-capture-partial-amount | 4 -- ...01-descriptive-error-message-on-invalid-pm | 4 -- .../fix-7588-woopay-subscription-variation | 5 -- .../fix-7592-update-transaction-order-id | 4 -- changelog/fix-7595-reports-customers | 4 -- ...748-capture-notification-styles-are-broken | 4 -- .../fix-7750-include-discount-in-tooltip | 4 -- changelog/fix-7834-zero-decimals-csv-export | 4 -- .../fix-7838-fraud-filters-html-encode-bug | 4 -- changelog/fix-7839-deposits-rest-api-docs | 4 -- ...3-woopay-automatewoo-referrals-integration | 4 -- ...ect-account-overview-account-type-nullable | 5 -- changelog/fix-account-currency-hook | 4 -- changelog/fix-apple-pay-including-tax | 4 -- changelog/fix-jstest-regression-pr-7851 | 5 -- .../fix-jsx-account-status-error-messages | 4 -- ...r-order-and-first-party-auth-compatibility | 4 -- ...erview-account-balances-on-instant-deposit | 4 -- changelog/fix-test-support-phone | 5 -- changelog/fix-update-payment-assets | 4 -- .../partially-ccleanup-legacy-upe-and-card | 4 -- changelog/remove-flag-usage | 4 -- .../revert-file-needed-for-plugin-update | 5 -- changelog/revert-prefetch-session-for-button | 4 -- changelog/subscriptions-6.6.0-1 | 4 -- changelog/subscriptions-6.6.0-2 | 4 -- changelog/subscriptions-core-6.6.0 | 4 -- changelog/subscriptions-core-6.6.0-3 | 4 -- changelog/subscriptions-core-6.6.0-4 | 4 -- changelog/subscriptions-core-6.6.0-5 | 4 -- changelog/subscriptions-core-6.6.0-6 | 4 -- changelog/subscriptions-core-6.6.0-7 | 4 -- changelog/subscriptions-core-6.6.0-8 | 4 -- changelog/update-4163-compatibility-service | 4 -- ...-card-behavior-if-affected-by-other-config | 4 -- ...date-6325-fraud-risk-link-text-in-settings | 4 -- ...-change-setup-refund-policy-note-into-task | 4 -- package-lock.json | 4 +- package.json | 2 +- readme.txt | 58 ++++++++++++++++++- woocommerce-payments.php | 2 +- 66 files changed, 117 insertions(+), 256 deletions(-) delete mode 100644 changelog/7588-express-checkout-utilities delete mode 100644 changelog/add-334-test-mode-notice-order-details delete mode 100644 changelog/add-5605-cancel-authorizations-if-order-is-cancelled delete mode 100644 changelog/add-7248-refund-transaction-from-details-page delete mode 100644 changelog/add-7591-missing-columns-export-csv delete mode 100644 changelog/add-7846-test-mode-confirm-modal delete mode 100644 changelog/add-thank-you-page-tracks delete mode 100644 changelog/cleanup-devtools-flags delete mode 100644 changelog/cleanup-is-upe-enabled-logic delete mode 100644 changelog/cleanup-redundant-script-enqueueing delete mode 100644 changelog/cleanup-upe-checkout-class delete mode 100644 changelog/cleanup-upe-gateways-II delete mode 100644 changelog/cleanup-upe-gateways-part-1 delete mode 100644 changelog/deferred-intent delete mode 100644 changelog/dev-3468-allow-reset-account-management delete mode 100644 changelog/dev-bump-wc-version-8-4-0 delete mode 100644 changelog/dev-fix-e2e-tests-on-wc-7-7 delete mode 100644 changelog/dev-fix-multi-currency-e2e-tests delete mode 100644 changelog/dev-test-ci-without-3ds1 delete mode 100644 changelog/e2e-7349-currency-switcher-widget delete mode 100644 changelog/e2e-7382-spec-merchant-multi-currency-setup delete mode 100644 changelog/fix-3693-qualitative-feedback-note delete mode 100644 changelog/fix-6700-remove-currency-sign-modification-code delete mode 100644 changelog/fix-6782-support-phone-dev-mode delete mode 100644 changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount delete mode 100644 changelog/fix-7301-descriptive-error-message-on-invalid-pm delete mode 100644 changelog/fix-7588-woopay-subscription-variation delete mode 100644 changelog/fix-7592-update-transaction-order-id delete mode 100644 changelog/fix-7595-reports-customers delete mode 100644 changelog/fix-7748-capture-notification-styles-are-broken delete mode 100644 changelog/fix-7750-include-discount-in-tooltip delete mode 100644 changelog/fix-7834-zero-decimals-csv-export delete mode 100644 changelog/fix-7838-fraud-filters-html-encode-bug delete mode 100644 changelog/fix-7839-deposits-rest-api-docs delete mode 100644 changelog/fix-7913-woopay-automatewoo-referrals-integration delete mode 100644 changelog/fix-7920-correct-account-overview-account-type-nullable delete mode 100644 changelog/fix-account-currency-hook delete mode 100644 changelog/fix-apple-pay-including-tax delete mode 100644 changelog/fix-jstest-regression-pr-7851 delete mode 100644 changelog/fix-jsx-account-status-error-messages delete mode 100644 changelog/fix-pay-for-order-and-first-party-auth-compatibility delete mode 100644 changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit delete mode 100644 changelog/fix-test-support-phone delete mode 100644 changelog/fix-update-payment-assets delete mode 100644 changelog/partially-ccleanup-legacy-upe-and-card delete mode 100644 changelog/remove-flag-usage delete mode 100644 changelog/revert-file-needed-for-plugin-update delete mode 100644 changelog/revert-prefetch-session-for-button delete mode 100644 changelog/subscriptions-6.6.0-1 delete mode 100644 changelog/subscriptions-6.6.0-2 delete mode 100644 changelog/subscriptions-core-6.6.0 delete mode 100644 changelog/subscriptions-core-6.6.0-3 delete mode 100644 changelog/subscriptions-core-6.6.0-4 delete mode 100644 changelog/subscriptions-core-6.6.0-5 delete mode 100644 changelog/subscriptions-core-6.6.0-6 delete mode 100644 changelog/subscriptions-core-6.6.0-7 delete mode 100644 changelog/subscriptions-core-6.6.0-8 delete mode 100644 changelog/update-4163-compatibility-service delete mode 100644 changelog/update-6320-rule-card-behavior-if-affected-by-other-config delete mode 100644 changelog/update-6325-fraud-risk-link-text-in-settings delete mode 100644 changelog/update-change-setup-refund-policy-note-into-task diff --git a/changelog.txt b/changelog.txt index 73e649d188e..68da1290131 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,61 @@ *** WooPayments Changelog *** += 7.0.0 - 2024-01-03 = +* Add - Add Account Management tools with reset account functionality for partially onboarded accounts. +* Add - Adding Compatibility Service to assist with flagging possible compatibility issues in the future. +* Add - Add refund controls to transaction details view +* Add - Add test mode notice in page order detail. +* Add - Display a Confirmaton Modal on enabling Test Mode +* Add - Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export +* Fix - Allow test phone number as Support Phone in Dev mode +* Fix - Avoid using the removed deferred UPE flag +* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on. +* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way. +* Fix - fix: account currency hook return value +* Fix - Fix account status error messages with links. +* Fix - Fix country names with accents not showing correctly on international country fraud filter +* Fix - Fix currency negative sign position on JS rendered amounts +* Fix - Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount. +* Fix - Fixed Apple Pay Double Tax Calculation Issue +* Fix - Fixed broken styles in authorization capture notifications +* Fix - Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export +* Fix - Fix missing customer data from transactions report +* Fix - Fix missing order number in transaction reports CSV +* Fix - Fix WooPay integration with AutomateWoo - Refer a Friend extension. +* Fix - Improved error message for invalid payment method +* Fix - Include discount fee in fees tooltip +* Fix - Introduce WC_Payments_Express_Checkout_Button_Utils class. +* Fix - Pass the pay-for-order params to get the pre-fetch session data +* Fix - Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists. +* Fix - Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode. +* Fix - Revemoved pre-fretch session for button to prevent draft order creation +* Fix - Update account balances on the Payments Overview screen when an instant deposit is requested +* Fix - Update Qualitative Feedback note to have more efficient sql query. +* Fix - When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table. +* Fix - When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used. +* Update - Actualized cards-related assets for settings and transactions pages. +* Update - Cleanup the deprecated payment gateway processing - part II +* Update - Cleanup the deprecated payment gateway processing - part III +* Update - Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed. +* Update - Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page. +* Update - Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option. +* Dev - Add e2e tests for the currency switcher widget. +* Dev - Added documentation for deposits REST API endpoints. +* Dev - Bump WC tested up to version to 8.4.0. +* Dev - Cleanup enqueueing of the scripts which were removed +* Dev - Cleanup the deprecated payment gateway processing - part IV +* Dev - Cleanup the deprecated payment gateway processing - part V +* Dev - Cleanup the deprecated payment gateway processing - part VI +* Dev - Comment: Fix declined 3DS card E2E test. +* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead. +* Dev - E2E test - Merchant facing: Multi-currency setup +* Dev - Improve E2E checkout tests +* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept. +* Dev - Remove "Set-up refund policy" Inbox note as superfluous. +* Dev - remove unused factor flag for deferred UPE +* Dev - Thank you page Tracks event +* Dev - Updated subscriptions-core to version 6.6.0 + = 6.9.2 - 2023-12-14 = * Add - Notice is added when merchant has funds that are not yet available for deposit. * Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected. diff --git a/changelog/7588-express-checkout-utilities b/changelog/7588-express-checkout-utilities deleted file mode 100644 index 143b670d60c..00000000000 --- a/changelog/7588-express-checkout-utilities +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Introduce WC_Payments_Express_Checkout_Button_Utils class. diff --git a/changelog/add-334-test-mode-notice-order-details b/changelog/add-334-test-mode-notice-order-details deleted file mode 100644 index de22a34c323..00000000000 --- a/changelog/add-334-test-mode-notice-order-details +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add test mode notice in page order detail. diff --git a/changelog/add-5605-cancel-authorizations-if-order-is-cancelled b/changelog/add-5605-cancel-authorizations-if-order-is-cancelled deleted file mode 100644 index 879ed83d30f..00000000000 --- a/changelog/add-5605-cancel-authorizations-if-order-is-cancelled +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed. diff --git a/changelog/add-7248-refund-transaction-from-details-page b/changelog/add-7248-refund-transaction-from-details-page deleted file mode 100644 index bfd753860e8..00000000000 --- a/changelog/add-7248-refund-transaction-from-details-page +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add refund controls to transaction details view diff --git a/changelog/add-7591-missing-columns-export-csv b/changelog/add-7591-missing-columns-export-csv deleted file mode 100644 index 668644d2cfc..00000000000 --- a/changelog/add-7591-missing-columns-export-csv +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export diff --git a/changelog/add-7846-test-mode-confirm-modal b/changelog/add-7846-test-mode-confirm-modal deleted file mode 100644 index 0725c55b1aa..00000000000 --- a/changelog/add-7846-test-mode-confirm-modal +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Display a Confirmaton Modal on enabling Test Mode diff --git a/changelog/add-thank-you-page-tracks b/changelog/add-thank-you-page-tracks deleted file mode 100644 index 31888d5d917..00000000000 --- a/changelog/add-thank-you-page-tracks +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Thank you page Tracks event diff --git a/changelog/cleanup-devtools-flags b/changelog/cleanup-devtools-flags deleted file mode 100644 index adbf7f71958..00000000000 --- a/changelog/cleanup-devtools-flags +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -remove unused factor flag for deferred UPE diff --git a/changelog/cleanup-is-upe-enabled-logic b/changelog/cleanup-is-upe-enabled-logic deleted file mode 100644 index 79bae6fa471..00000000000 --- a/changelog/cleanup-is-upe-enabled-logic +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Cleanup the deprecated payment gateway processing - part III diff --git a/changelog/cleanup-redundant-script-enqueueing b/changelog/cleanup-redundant-script-enqueueing deleted file mode 100644 index 20c952d459e..00000000000 --- a/changelog/cleanup-redundant-script-enqueueing +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Cleanup enqueueing of the scripts which were removed diff --git a/changelog/cleanup-upe-checkout-class b/changelog/cleanup-upe-checkout-class deleted file mode 100644 index 95cfa040bf5..00000000000 --- a/changelog/cleanup-upe-checkout-class +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Cleanup the deprecated payment gateway processing - part IV diff --git a/changelog/cleanup-upe-gateways-II b/changelog/cleanup-upe-gateways-II deleted file mode 100644 index 16f3e3cd17f..00000000000 --- a/changelog/cleanup-upe-gateways-II +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Cleanup the deprecated payment gateway processing - part VI diff --git a/changelog/cleanup-upe-gateways-part-1 b/changelog/cleanup-upe-gateways-part-1 deleted file mode 100644 index d449f2047df..00000000000 --- a/changelog/cleanup-upe-gateways-part-1 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Cleanup the deprecated payment gateway processing - part V diff --git a/changelog/deferred-intent b/changelog/deferred-intent deleted file mode 100644 index ef5442b5f17..00000000000 --- a/changelog/deferred-intent +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Improve E2E checkout tests diff --git a/changelog/dev-3468-allow-reset-account-management b/changelog/dev-3468-allow-reset-account-management deleted file mode 100644 index ed030674f95..00000000000 --- a/changelog/dev-3468-allow-reset-account-management +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add Account Management tools with reset account functionality for partially onboarded accounts. diff --git a/changelog/dev-bump-wc-version-8-4-0 b/changelog/dev-bump-wc-version-8-4-0 deleted file mode 100644 index 5c00289cc5b..00000000000 --- a/changelog/dev-bump-wc-version-8-4-0 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Bump WC tested up to version to 8.4.0. \ No newline at end of file diff --git a/changelog/dev-fix-e2e-tests-on-wc-7-7 b/changelog/dev-fix-e2e-tests-on-wc-7-7 deleted file mode 100644 index 15b4d3b72e9..00000000000 --- a/changelog/dev-fix-e2e-tests-on-wc-7-7 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: Fix e2e tests on WC 7.7. - - diff --git a/changelog/dev-fix-multi-currency-e2e-tests b/changelog/dev-fix-multi-currency-e2e-tests deleted file mode 100644 index 45ac7deccc1..00000000000 --- a/changelog/dev-fix-multi-currency-e2e-tests +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: Fix multi-currency e2e tests. - - diff --git a/changelog/dev-test-ci-without-3ds1 b/changelog/dev-test-ci-without-3ds1 deleted file mode 100644 index f2d4b778788..00000000000 --- a/changelog/dev-test-ci-without-3ds1 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: dev - -Comment: Fix declined 3DS card E2E test. diff --git a/changelog/e2e-7349-currency-switcher-widget b/changelog/e2e-7349-currency-switcher-widget deleted file mode 100644 index 1bf9af1d6c3..00000000000 --- a/changelog/e2e-7349-currency-switcher-widget +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: dev - -Add e2e tests for the currency switcher widget. diff --git a/changelog/e2e-7382-spec-merchant-multi-currency-setup b/changelog/e2e-7382-spec-merchant-multi-currency-setup deleted file mode 100644 index b079e3e6e8e..00000000000 --- a/changelog/e2e-7382-spec-merchant-multi-currency-setup +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: dev - -E2E test - Merchant facing: Multi-currency setup diff --git a/changelog/fix-3693-qualitative-feedback-note b/changelog/fix-3693-qualitative-feedback-note deleted file mode 100644 index 8862cc0c961..00000000000 --- a/changelog/fix-3693-qualitative-feedback-note +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Update Qualitative Feedback note to have more efficient sql query. diff --git a/changelog/fix-6700-remove-currency-sign-modification-code b/changelog/fix-6700-remove-currency-sign-modification-code deleted file mode 100644 index 74634338357..00000000000 --- a/changelog/fix-6700-remove-currency-sign-modification-code +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix currency negative sign position on JS rendered amounts diff --git a/changelog/fix-6782-support-phone-dev-mode b/changelog/fix-6782-support-phone-dev-mode deleted file mode 100644 index 42166e6419d..00000000000 --- a/changelog/fix-6782-support-phone-dev-mode +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Allow test phone number as Support Phone in Dev mode diff --git a/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount b/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount deleted file mode 100644 index 870c1de09f2..00000000000 --- a/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount. diff --git a/changelog/fix-7301-descriptive-error-message-on-invalid-pm b/changelog/fix-7301-descriptive-error-message-on-invalid-pm deleted file mode 100644 index 798235980af..00000000000 --- a/changelog/fix-7301-descriptive-error-message-on-invalid-pm +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Improved error message for invalid payment method diff --git a/changelog/fix-7588-woopay-subscription-variation b/changelog/fix-7588-woopay-subscription-variation deleted file mode 100644 index 06f44dc9845..00000000000 --- a/changelog/fix-7588-woopay-subscription-variation +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Edge case adding subscription_variation to WooPay button supported types - - diff --git a/changelog/fix-7592-update-transaction-order-id b/changelog/fix-7592-update-transaction-order-id deleted file mode 100644 index 0ef8cffd17f..00000000000 --- a/changelog/fix-7592-update-transaction-order-id +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix missing order number in transaction reports CSV diff --git a/changelog/fix-7595-reports-customers b/changelog/fix-7595-reports-customers deleted file mode 100644 index e4ab131cb21..00000000000 --- a/changelog/fix-7595-reports-customers +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix missing customer data from transactions report diff --git a/changelog/fix-7748-capture-notification-styles-are-broken b/changelog/fix-7748-capture-notification-styles-are-broken deleted file mode 100644 index 348106f98f8..00000000000 --- a/changelog/fix-7748-capture-notification-styles-are-broken +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fixed broken styles in authorization capture notifications diff --git a/changelog/fix-7750-include-discount-in-tooltip b/changelog/fix-7750-include-discount-in-tooltip deleted file mode 100644 index b600a611e92..00000000000 --- a/changelog/fix-7750-include-discount-in-tooltip +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Include discount fee in fees tooltip diff --git a/changelog/fix-7834-zero-decimals-csv-export b/changelog/fix-7834-zero-decimals-csv-export deleted file mode 100644 index 1e5b2a1cf87..00000000000 --- a/changelog/fix-7834-zero-decimals-csv-export +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export diff --git a/changelog/fix-7838-fraud-filters-html-encode-bug b/changelog/fix-7838-fraud-filters-html-encode-bug deleted file mode 100644 index 1b358176fe8..00000000000 --- a/changelog/fix-7838-fraud-filters-html-encode-bug +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix country names with accents not showing correctly on international country fraud filter diff --git a/changelog/fix-7839-deposits-rest-api-docs b/changelog/fix-7839-deposits-rest-api-docs deleted file mode 100644 index b50f1644a81..00000000000 --- a/changelog/fix-7839-deposits-rest-api-docs +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Added documentation for deposits REST API endpoints. diff --git a/changelog/fix-7913-woopay-automatewoo-referrals-integration b/changelog/fix-7913-woopay-automatewoo-referrals-integration deleted file mode 100644 index bace9a2cc9b..00000000000 --- a/changelog/fix-7913-woopay-automatewoo-referrals-integration +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix WooPay integration with AutomateWoo - Refer a Friend extension. diff --git a/changelog/fix-7920-correct-account-overview-account-type-nullable b/changelog/fix-7920-correct-account-overview-account-type-nullable deleted file mode 100644 index 5db6d1382f4..00000000000 --- a/changelog/fix-7920-correct-account-overview-account-type-nullable +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: No changelog entry required – minor TS interface fix with no user-facing changes - - diff --git a/changelog/fix-account-currency-hook b/changelog/fix-account-currency-hook deleted file mode 100644 index 23d9628b19f..00000000000 --- a/changelog/fix-account-currency-hook +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -fix: account currency hook return value diff --git a/changelog/fix-apple-pay-including-tax b/changelog/fix-apple-pay-including-tax deleted file mode 100644 index 59afc2bef4f..00000000000 --- a/changelog/fix-apple-pay-including-tax +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fixed Apple Pay Double Tax Calculation Issue diff --git a/changelog/fix-jstest-regression-pr-7851 b/changelog/fix-jstest-regression-pr-7851 deleted file mode 100644 index 4308b603c02..00000000000 --- a/changelog/fix-jstest-regression-pr-7851 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: Fix JS regression test in PR 7851 - - diff --git a/changelog/fix-jsx-account-status-error-messages b/changelog/fix-jsx-account-status-error-messages deleted file mode 100644 index a45adc8b5ab..00000000000 --- a/changelog/fix-jsx-account-status-error-messages +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix account status error messages with links. diff --git a/changelog/fix-pay-for-order-and-first-party-auth-compatibility b/changelog/fix-pay-for-order-and-first-party-auth-compatibility deleted file mode 100644 index 26182c064d4..00000000000 --- a/changelog/fix-pay-for-order-and-first-party-auth-compatibility +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Pass the pay-for-order params to get the pre-fetch session data diff --git a/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit b/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit deleted file mode 100644 index 59ba1fb0bdd..00000000000 --- a/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Update account balances on the Payments Overview screen when an instant deposit is requested diff --git a/changelog/fix-test-support-phone b/changelog/fix-test-support-phone deleted file mode 100644 index 97abae072f7..00000000000 --- a/changelog/fix-test-support-phone +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Modified the test phone numbers supported by Stripe. - - diff --git a/changelog/fix-update-payment-assets b/changelog/fix-update-payment-assets deleted file mode 100644 index 0b45545b774..00000000000 --- a/changelog/fix-update-payment-assets +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: update - -Actualized cards-related assets for settings and transactions pages. diff --git a/changelog/partially-ccleanup-legacy-upe-and-card b/changelog/partially-ccleanup-legacy-upe-and-card deleted file mode 100644 index 9e5386f594e..00000000000 --- a/changelog/partially-ccleanup-legacy-upe-and-card +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Cleanup the deprecated payment gateway processing - part II diff --git a/changelog/remove-flag-usage b/changelog/remove-flag-usage deleted file mode 100644 index cab11239829..00000000000 --- a/changelog/remove-flag-usage +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Avoid using the removed deferred UPE flag diff --git a/changelog/revert-file-needed-for-plugin-update b/changelog/revert-file-needed-for-plugin-update deleted file mode 100644 index f4e5d1e3224..00000000000 --- a/changelog/revert-file-needed-for-plugin-update +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: This is the file revert to avoid failures on plugin update. This is a temporary solution. Both removal & revert happen on develop meaning there is no change to the outside world. - - diff --git a/changelog/revert-prefetch-session-for-button b/changelog/revert-prefetch-session-for-button deleted file mode 100644 index bcb2e97e61e..00000000000 --- a/changelog/revert-prefetch-session-for-button +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Revemoved pre-fretch session for button to prevent draft order creation diff --git a/changelog/subscriptions-6.6.0-1 b/changelog/subscriptions-6.6.0-1 deleted file mode 100644 index 9c70ea3d4ce..00000000000 --- a/changelog/subscriptions-6.6.0-1 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead. diff --git a/changelog/subscriptions-6.6.0-2 b/changelog/subscriptions-6.6.0-2 deleted file mode 100644 index 98a24e2a8d8..00000000000 --- a/changelog/subscriptions-6.6.0-2 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept. diff --git a/changelog/subscriptions-core-6.6.0 b/changelog/subscriptions-core-6.6.0 deleted file mode 100644 index 192de7697f3..00000000000 --- a/changelog/subscriptions-core-6.6.0 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Updated subscriptions-core to version 6.6.0 diff --git a/changelog/subscriptions-core-6.6.0-3 b/changelog/subscriptions-core-6.6.0-3 deleted file mode 100644 index 39e3728713e..00000000000 --- a/changelog/subscriptions-core-6.6.0-3 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way. diff --git a/changelog/subscriptions-core-6.6.0-4 b/changelog/subscriptions-core-6.6.0-4 deleted file mode 100644 index adf5488ac54..00000000000 --- a/changelog/subscriptions-core-6.6.0-4 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on. diff --git a/changelog/subscriptions-core-6.6.0-5 b/changelog/subscriptions-core-6.6.0-5 deleted file mode 100644 index fc15acdb576..00000000000 --- a/changelog/subscriptions-core-6.6.0-5 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode. diff --git a/changelog/subscriptions-core-6.6.0-6 b/changelog/subscriptions-core-6.6.0-6 deleted file mode 100644 index df965094736..00000000000 --- a/changelog/subscriptions-core-6.6.0-6 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table. diff --git a/changelog/subscriptions-core-6.6.0-7 b/changelog/subscriptions-core-6.6.0-7 deleted file mode 100644 index 96c2cae1f2c..00000000000 --- a/changelog/subscriptions-core-6.6.0-7 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists. diff --git a/changelog/subscriptions-core-6.6.0-8 b/changelog/subscriptions-core-6.6.0-8 deleted file mode 100644 index a2ffa0feb0c..00000000000 --- a/changelog/subscriptions-core-6.6.0-8 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used. diff --git a/changelog/update-4163-compatibility-service b/changelog/update-4163-compatibility-service deleted file mode 100644 index 3a524da05ae..00000000000 --- a/changelog/update-4163-compatibility-service +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Adding Compatibility Service to assist with flagging possible compatibility issues in the future. diff --git a/changelog/update-6320-rule-card-behavior-if-affected-by-other-config b/changelog/update-6320-rule-card-behavior-if-affected-by-other-config deleted file mode 100644 index 3755be13f4f..00000000000 --- a/changelog/update-6320-rule-card-behavior-if-affected-by-other-config +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: update - -Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option. diff --git a/changelog/update-6325-fraud-risk-link-text-in-settings b/changelog/update-6325-fraud-risk-link-text-in-settings deleted file mode 100644 index 3f37d6371ca..00000000000 --- a/changelog/update-6325-fraud-risk-link-text-in-settings +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: update - -Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page. diff --git a/changelog/update-change-setup-refund-policy-note-into-task b/changelog/update-change-setup-refund-policy-note-into-task deleted file mode 100644 index 08cf0d142a9..00000000000 --- a/changelog/update-change-setup-refund-policy-note-into-task +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: dev - -Remove "Set-up refund policy" Inbox note as superfluous. diff --git a/package-lock.json b/package-lock.json index 7e7375967b4..056a7547a52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "woocommerce-payments", - "version": "6.9.2", + "version": "7.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "woocommerce-payments", - "version": "6.9.2", + "version": "7.0.0", "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index d80cfbe4bd0..32b6a95a35f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-payments", - "version": "6.9.2", + "version": "7.0.0", "main": "webpack.config.js", "author": "Automattic", "license": "GPL-3.0-or-later", diff --git a/readme.txt b/readme.txt index 8a57aead24b..0c4dc6d82e0 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.4 Requires PHP: 7.3 -Stable tag: 6.9.2 +Stable tag: 7.0.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -94,6 +94,62 @@ Please note that our support for the checkout block is still experimental and th == Changelog == += 7.0.0 - 2024-01-03 = +* Add - Add Account Management tools with reset account functionality for partially onboarded accounts. +* Add - Adding Compatibility Service to assist with flagging possible compatibility issues in the future. +* Add - Add refund controls to transaction details view +* Add - Add test mode notice in page order detail. +* Add - Display a Confirmaton Modal on enabling Test Mode +* Add - Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export +* Fix - Allow test phone number as Support Phone in Dev mode +* Fix - Avoid using the removed deferred UPE flag +* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on. +* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way. +* Fix - fix: account currency hook return value +* Fix - Fix account status error messages with links. +* Fix - Fix country names with accents not showing correctly on international country fraud filter +* Fix - Fix currency negative sign position on JS rendered amounts +* Fix - Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount. +* Fix - Fixed Apple Pay Double Tax Calculation Issue +* Fix - Fixed broken styles in authorization capture notifications +* Fix - Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export +* Fix - Fix missing customer data from transactions report +* Fix - Fix missing order number in transaction reports CSV +* Fix - Fix WooPay integration with AutomateWoo - Refer a Friend extension. +* Fix - Improved error message for invalid payment method +* Fix - Include discount fee in fees tooltip +* Fix - Introduce WC_Payments_Express_Checkout_Button_Utils class. +* Fix - Pass the pay-for-order params to get the pre-fetch session data +* Fix - Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists. +* Fix - Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode. +* Fix - Revemoved pre-fretch session for button to prevent draft order creation +* Fix - Update account balances on the Payments Overview screen when an instant deposit is requested +* Fix - Update Qualitative Feedback note to have more efficient sql query. +* Fix - When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table. +* Fix - When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used. +* Update - Actualized cards-related assets for settings and transactions pages. +* Update - Cleanup the deprecated payment gateway processing - part II +* Update - Cleanup the deprecated payment gateway processing - part III +* Update - Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed. +* Update - Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page. +* Update - Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option. +* Dev - Add e2e tests for the currency switcher widget. +* Dev - Added documentation for deposits REST API endpoints. +* Dev - Bump WC tested up to version to 8.4.0. +* Dev - Cleanup enqueueing of the scripts which were removed +* Dev - Cleanup the deprecated payment gateway processing - part IV +* Dev - Cleanup the deprecated payment gateway processing - part V +* Dev - Cleanup the deprecated payment gateway processing - part VI +* Dev - Comment: Fix declined 3DS card E2E test. +* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead. +* Dev - E2E test - Merchant facing: Multi-currency setup +* Dev - Improve E2E checkout tests +* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept. +* Dev - Remove "Set-up refund policy" Inbox note as superfluous. +* Dev - remove unused factor flag for deferred UPE +* Dev - Thank you page Tracks event +* Dev - Updated subscriptions-core to version 6.6.0 + = 6.9.2 - 2023-12-14 = * Add - Notice is added when merchant has funds that are not yet available for deposit. * Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected. diff --git a/woocommerce-payments.php b/woocommerce-payments.php index df7afe47766..7f453eb5c35 100644 --- a/woocommerce-payments.php +++ b/woocommerce-payments.php @@ -12,7 +12,7 @@ * WC tested up to: 8.4.0 * Requires at least: 6.0 * Requires PHP: 7.3 - * Version: 6.9.2 + * Version: 7.0.0 * * @package WooCommerce\Payments */ From c39d1afdf8a7147aca80e36004aacfdaad0880c3 Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:40:26 +1000 Subject: [PATCH 4/8] Fix broken dispute details UI (#7959) --- ...nsaction-details-dispute-details-broken-ui | 5 + .../test/__snapshots__/index.test.tsx.snap | 78 +- client/payment-details/summary/index.tsx | 535 ++++---- client/payment-details/summary/style.scss | 6 +- .../test/__snapshots__/index.test.tsx.snap | 1208 +++++++++-------- .../test/__snapshots__/index.test.tsx.snap | 224 +-- 6 files changed, 1074 insertions(+), 982 deletions(-) create mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui diff --git a/changelog/fix-7958-transaction-details-dispute-details-broken-ui b/changelog/fix-7958-transaction-details-dispute-details-broken-ui new file mode 100644 index 00000000000..b196bc9910c --- /dev/null +++ b/changelog/fix-7958-transaction-details-dispute-details-broken-ui @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Not user-facing: fixes styling bug introduced in develop branch + + diff --git a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap index f28176053a7..ea41fb13ccb 100644 --- a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap @@ -20,55 +20,61 @@ exports[`Order details page should match the snapshot - Charge without payment i data-wp-component="CardBody" >
-

- $15.00 - - USD - - - Pending - -

- -

- Fees: - -$0.00 -

- -

- Net: +

$15.00 + + USD + + + Pending +

+
+ +

+ Fees: + -$0.00 +

+ +

+ Net: + $15.00 +

+
-
-
- Payment ID: - 776 +
+ Payment ID: + 776 +
+
-

= ( { return ( -
-
-

- - { formattedAmount } - - { charge.currency || 'USD' } - - { charge.dispute ? ( - - ) : ( - - ) } - -

-
- { renderStorePrice ? ( -

- { formatExplicitCurrency( - balance.amount, - balance.currency - ) } -

- ) : null } - { balance.refunded ? ( -

- { `${ - disputeFee - ? __( - 'Deducted', - 'woocommerce-payments' - ) - : __( - 'Refunded', - 'woocommerce-payments' - ) - }: ` } - { formatExplicitCurrency( - -balance.refunded, - balance.currency - ) } -

- ) : ( - '' - ) } -

+ +

+
+

- { `${ __( - 'Fees', - 'woocommerce-payments' - ) }: ` } - { formatCurrency( - -balance.fee, - balance.currency - ) } - { disputeFee && ( - } - buttonLabel={ __( - 'Fee breakdown', - 'woocommerce-payments' - ) } - content={ - <> - - - - { formatCurrency( - transactionFee.fee, - transactionFee.currency - ) } - - - - - - { disputeFee } - - - - - - { formatCurrency( - balance.fee, - balance.currency - ) } - - - + { formattedAmount } + + { charge.currency || 'USD' } + + { charge.dispute ? ( + + ) : ( + ) }

- { charge.paydown ? ( +
+ { renderStorePrice ? ( +

+ { formatExplicitCurrency( + balance.amount, + balance.currency + ) } +

+ ) : null } + { balance.refunded ? ( +

+ { `${ + disputeFee + ? __( + 'Deducted', + 'woocommerce-payments' + ) + : __( + 'Refunded', + 'woocommerce-payments' + ) + }: ` } + { formatExplicitCurrency( + -balance.refunded, + balance.currency + ) } +

+ ) : ( + '' + ) }

- { `${ __( - 'Loan repayment', - 'woocommerce-payments' - ) }: ` } - { formatExplicitCurrency( - charge.paydown.amount, - balance.currency - ) } + + { `${ __( + 'Fees', + 'woocommerce-payments' + ) }: ` } + { formatCurrency( + -balance.fee, + balance.currency + ) } + { disputeFee && ( + + } + buttonLabel={ __( + 'Fee breakdown', + 'woocommerce-payments' + ) } + content={ + <> + + + + { formatCurrency( + transactionFee.fee, + transactionFee.currency + ) } + + + + + + { disputeFee } + + + + + + { formatCurrency( + balance.fee, + balance.currency + ) } + + + + } + /> + ) } + +

+ { charge.paydown ? ( +

+ { `${ __( + 'Loan repayment', + 'woocommerce-payments' + ) }: ` } + { formatExplicitCurrency( + charge.paydown.amount, + balance.currency + ) } +

+ ) : ( + '' + ) } +

+ + { `${ __( + 'Net', + 'woocommerce-payments' + ) }: ` } + { formatExplicitCurrency( + charge.paydown + ? balance.net - + Math.abs( + charge.paydown + .amount + ) + : balance.net, + balance.currency + ) } +

- ) : ( - '' +
+
+
+ { ! isLoading && isFraudOutcomeReview && ( +
+ { + wcpayTracks.recordEvent( + 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked', + { + payment_intent_id: + charge.payment_intent, + } + ); + wcpayTracks.recordEvent( + 'payments_transactions_details_cancel_charge_button_click', + { + payment_intent_id: + charge.payment_intent, + } + ); + } } + > + { __( 'Block transaction' ) } + + + { + wcpayTracks.recordEvent( + 'wcpay_fraud_protection_transaction_reviewed_merchant_approved', + { + payment_intent_id: + charge.payment_intent, + } + ); + wcpayTracks.recordEvent( + 'payments_transactions_details_capture_charge_button_click', + { + payment_intent_id: + charge.payment_intent, + } + ); + } } + > + { __( 'Approve Transaction' ) } + +
) } -

+

{ `${ __( - 'Net', + 'Payment ID', 'woocommerce-payments' ) }: ` } - { formatExplicitCurrency( - charge.paydown - ? balance.net - - Math.abs( - charge.paydown.amount - ) - : balance.net, - balance.currency - ) } + { charge.payment_intent + ? charge.payment_intent + : charge.id } -

+
-
- { ! isLoading && isFraudOutcomeReview && ( -
- { - wcpayTracks.recordEvent( - 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked', - { - payment_intent_id: - charge.payment_intent, - } - ); - wcpayTracks.recordEvent( - 'payments_transactions_details_cancel_charge_button_click', - { - payment_intent_id: - charge.payment_intent, - } - ); - } } - > - { __( 'Block transaction' ) } - - - { - wcpayTracks.recordEvent( - 'wcpay_fraud_protection_transaction_reviewed_merchant_approved', - { - payment_intent_id: - charge.payment_intent, - } - ); - wcpayTracks.recordEvent( - 'payments_transactions_details_capture_charge_button_click', - { - payment_intent_id: - charge.payment_intent, - } - ); - } } - > - { __( 'Approve Transaction' ) } - -
- ) } -
+
+ { ! charge?.refunded && charge?.captured && ( - { `${ __( - 'Payment ID', - 'woocommerce-payments' - ) }: ` } - { charge.payment_intent - ? charge.payment_intent - : charge.id } - -
-
-
-
- { ! charge?.refunded && charge?.captured && ( - - - { ( { onClose } ) => ( - - { - setIsRefundModalOpen( true ); - wcpayTracks.recordEvent( - 'payments_transactions_details_refund_modal_open', - { - payment_intent_id: - charge.payment_intent, - } - ); - onClose(); - } } - > - { __( - 'Refund in full', - 'woocommerce-payments' - ) } - - { charge.order && ( + + { ( { onClose } ) => ( + { + setIsRefundModalOpen( + true + ); wcpayTracks.recordEvent( - 'payments_transactions_details_partial_refund', + 'payments_transactions_details_refund_modal_open', { payment_intent_id: charge.payment_intent, - order_id: - charge.order - ?.number, } ); - window.location = - charge.order?.url; + onClose(); } } > { __( - 'Partial refund', + 'Refund in full', 'woocommerce-payments' ) } - ) } - - ) } - - - ) } -
+ { charge.order && ( + { + wcpayTracks.recordEvent( + 'payments_transactions_details_partial_refund', + { + payment_intent_id: + charge.payment_intent, + order_id: + charge.order + ?.number, + } + ); + window.location = + charge.order?.url; + } } + > + { __( + 'Partial refund', + 'woocommerce-payments' + ) } + + ) } + + ) } + + + ) } +
+ diff --git a/client/payment-details/summary/style.scss b/client/payment-details/summary/style.scss index 95df0d33edd..0ee051834fb 100755 --- a/client/payment-details/summary/style.scss +++ b/client/payment-details/summary/style.scss @@ -8,11 +8,6 @@ margin-bottom: 24px; } -.components-card__body:first-of-type { - display: flex; - flex-direction: row; -} - .payment-details-summary { display: flex; flex: 1; @@ -30,6 +25,7 @@ padding: 0; margin: 0; display: flex; + flex-wrap: wrap; align-items: center; .payment-details-summary__amount-currency { diff --git a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap index b719e25c342..4d582a000c7 100644 --- a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap @@ -16,55 +16,61 @@ exports[`PaymentDetailsSummary capture notification and fraud buttons renders ca data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Payment authorized - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Payment authorized +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
+
-

-

- $20.00 - - usd - - - Needs review - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Needs review +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- - + +
+
- Approve Transaction - -
-
- Payment ID: - ch_38jdHA39KKA + Payment ID: + ch_38jdHA39KKA +
+
-

-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -923,79 +941,85 @@ exports[`PaymentDetailsSummary order missing notice does not render notice if or data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1212,79 +1236,85 @@ exports[`PaymentDetailsSummary order missing notice renders notice if order miss data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1524,79 +1554,85 @@ exports[`PaymentDetailsSummary renders a charge with subscriptions 1`] = ` data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1840,58 +1876,64 @@ exports[`PaymentDetailsSummary renders fully refunded information for a charge 1 data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Refunded - -

-

- Refunded: - -$20.00 -

-

- Fees: - -$0.70 -

- -

- Net: - -$0.70 +

+ $20.00 + + usd + + + Refunded +

+
+

+ Refunded: + -$20.00 +

+

+ Fees: + -$0.70 +

+ +

+ Net: + -$0.70 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
+
-

-

- - - USD - - -

- -

- Fees: - $0.00 -

- -

- Net: - $0.00 +

+ + + USD + +

+
+ +

+ Fees: + $0.00 +

+ +

+ Net: + $0.00 +

+
-
-
- Payment ID: +
+ Payment ID: +
+
-

-

- $20.00 - - usd - - - Partial refund - -

-

- Refunded: - -$12.00 -

-

- Fees: - -$0.70 -

- -

- Net: - $7.30 +

+ $20.00 + + usd + + + Partial refund +

+
+

+ Refunded: + -$12.00 +

+

+ Fees: + -$0.70 +

+ +

+ Net: + $7.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -2634,79 +2688,85 @@ exports[`PaymentDetailsSummary renders the Tap to Pay channel from metadata 1`] data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -2923,79 +2983,85 @@ exports[`PaymentDetailsSummary renders the information of a dispute-reversal cha data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Disputed: Won - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Disputed: Won +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
diff --git a/client/payment-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/test/__snapshots__/index.test.tsx.snap index 7a3274751bf..ebe9d418a92 100644 --- a/client/payment-details/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/test/__snapshots__/index.test.tsx.snap @@ -20,78 +20,84 @@ exports[`Payment details page should match the snapshot - Charge query param 1`] data-wp-component="CardBody" >
-

- - Amount placeholder - -

- -

+

- Fee amount + Amount placeholder

- -

+

+ +

+ + Fee amount + +

+ +

+ + Net amount + +

+
+
+
+
- Net amount + Payment ID: pi_xxxxxxxxxxxxxxxxxxxxxxxx -

+
-
- -
+ + +
-
- - - -

-

- $1,500.00 - - usd - - - Paid - -

- -

- Fees: - -$74.00 -

- -

- Net: - $1,426.00 +

+ $1,500.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$74.00 +

+ +

+ Net: + $1,426.00 +

+
-
-
- Payment ID: - pi_mock +
+ Payment ID: + pi_mock +
-
-
- + + +
From 3c9c94d72056eabbe2e93906aed5d212dcb7741f Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:40:26 +1000 Subject: [PATCH 5/8] Fix broken dispute details UI (#7959) --- ...nsaction-details-dispute-details-broken-ui | 5 + .../test/__snapshots__/index.test.tsx.snap | 78 +- client/payment-details/summary/index.tsx | 535 ++++---- client/payment-details/summary/style.scss | 6 +- .../test/__snapshots__/index.test.tsx.snap | 1208 +++++++++-------- .../test/__snapshots__/index.test.tsx.snap | 224 +-- 6 files changed, 1074 insertions(+), 982 deletions(-) create mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui diff --git a/changelog/fix-7958-transaction-details-dispute-details-broken-ui b/changelog/fix-7958-transaction-details-dispute-details-broken-ui new file mode 100644 index 00000000000..b196bc9910c --- /dev/null +++ b/changelog/fix-7958-transaction-details-dispute-details-broken-ui @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Not user-facing: fixes styling bug introduced in develop branch + + diff --git a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap index f28176053a7..ea41fb13ccb 100644 --- a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap @@ -20,55 +20,61 @@ exports[`Order details page should match the snapshot - Charge without payment i data-wp-component="CardBody" >
-

- $15.00 - - USD - - - Pending - -

- -

- Fees: - -$0.00 -

- -

- Net: +

$15.00 + + USD + + + Pending +

+
+ +

+ Fees: + -$0.00 +

+ +

+ Net: + $15.00 +

+
-
-
- Payment ID: - 776 +
+ Payment ID: + 776 +
+
-

= ( { return ( -
-
-

- - { formattedAmount } - - { charge.currency || 'USD' } - - { charge.dispute ? ( - - ) : ( - - ) } - -

-
- { renderStorePrice ? ( -

- { formatExplicitCurrency( - balance.amount, - balance.currency - ) } -

- ) : null } - { balance.refunded ? ( -

- { `${ - disputeFee - ? __( - 'Deducted', - 'woocommerce-payments' - ) - : __( - 'Refunded', - 'woocommerce-payments' - ) - }: ` } - { formatExplicitCurrency( - -balance.refunded, - balance.currency - ) } -

- ) : ( - '' - ) } -

+ +

+
+

- { `${ __( - 'Fees', - 'woocommerce-payments' - ) }: ` } - { formatCurrency( - -balance.fee, - balance.currency - ) } - { disputeFee && ( - } - buttonLabel={ __( - 'Fee breakdown', - 'woocommerce-payments' - ) } - content={ - <> - - - - { formatCurrency( - transactionFee.fee, - transactionFee.currency - ) } - - - - - - { disputeFee } - - - - - - { formatCurrency( - balance.fee, - balance.currency - ) } - - - + { formattedAmount } + + { charge.currency || 'USD' } + + { charge.dispute ? ( + + ) : ( + ) }

- { charge.paydown ? ( +
+ { renderStorePrice ? ( +

+ { formatExplicitCurrency( + balance.amount, + balance.currency + ) } +

+ ) : null } + { balance.refunded ? ( +

+ { `${ + disputeFee + ? __( + 'Deducted', + 'woocommerce-payments' + ) + : __( + 'Refunded', + 'woocommerce-payments' + ) + }: ` } + { formatExplicitCurrency( + -balance.refunded, + balance.currency + ) } +

+ ) : ( + '' + ) }

- { `${ __( - 'Loan repayment', - 'woocommerce-payments' - ) }: ` } - { formatExplicitCurrency( - charge.paydown.amount, - balance.currency - ) } + + { `${ __( + 'Fees', + 'woocommerce-payments' + ) }: ` } + { formatCurrency( + -balance.fee, + balance.currency + ) } + { disputeFee && ( + + } + buttonLabel={ __( + 'Fee breakdown', + 'woocommerce-payments' + ) } + content={ + <> + + + + { formatCurrency( + transactionFee.fee, + transactionFee.currency + ) } + + + + + + { disputeFee } + + + + + + { formatCurrency( + balance.fee, + balance.currency + ) } + + + + } + /> + ) } + +

+ { charge.paydown ? ( +

+ { `${ __( + 'Loan repayment', + 'woocommerce-payments' + ) }: ` } + { formatExplicitCurrency( + charge.paydown.amount, + balance.currency + ) } +

+ ) : ( + '' + ) } +

+ + { `${ __( + 'Net', + 'woocommerce-payments' + ) }: ` } + { formatExplicitCurrency( + charge.paydown + ? balance.net - + Math.abs( + charge.paydown + .amount + ) + : balance.net, + balance.currency + ) } +

- ) : ( - '' +
+
+
+ { ! isLoading && isFraudOutcomeReview && ( +
+ { + wcpayTracks.recordEvent( + 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked', + { + payment_intent_id: + charge.payment_intent, + } + ); + wcpayTracks.recordEvent( + 'payments_transactions_details_cancel_charge_button_click', + { + payment_intent_id: + charge.payment_intent, + } + ); + } } + > + { __( 'Block transaction' ) } + + + { + wcpayTracks.recordEvent( + 'wcpay_fraud_protection_transaction_reviewed_merchant_approved', + { + payment_intent_id: + charge.payment_intent, + } + ); + wcpayTracks.recordEvent( + 'payments_transactions_details_capture_charge_button_click', + { + payment_intent_id: + charge.payment_intent, + } + ); + } } + > + { __( 'Approve Transaction' ) } + +
) } -

+

{ `${ __( - 'Net', + 'Payment ID', 'woocommerce-payments' ) }: ` } - { formatExplicitCurrency( - charge.paydown - ? balance.net - - Math.abs( - charge.paydown.amount - ) - : balance.net, - balance.currency - ) } + { charge.payment_intent + ? charge.payment_intent + : charge.id } -

+
-
- { ! isLoading && isFraudOutcomeReview && ( -
- { - wcpayTracks.recordEvent( - 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked', - { - payment_intent_id: - charge.payment_intent, - } - ); - wcpayTracks.recordEvent( - 'payments_transactions_details_cancel_charge_button_click', - { - payment_intent_id: - charge.payment_intent, - } - ); - } } - > - { __( 'Block transaction' ) } - - - { - wcpayTracks.recordEvent( - 'wcpay_fraud_protection_transaction_reviewed_merchant_approved', - { - payment_intent_id: - charge.payment_intent, - } - ); - wcpayTracks.recordEvent( - 'payments_transactions_details_capture_charge_button_click', - { - payment_intent_id: - charge.payment_intent, - } - ); - } } - > - { __( 'Approve Transaction' ) } - -
- ) } -
+
+ { ! charge?.refunded && charge?.captured && ( - { `${ __( - 'Payment ID', - 'woocommerce-payments' - ) }: ` } - { charge.payment_intent - ? charge.payment_intent - : charge.id } - -
-
-
-
- { ! charge?.refunded && charge?.captured && ( - - - { ( { onClose } ) => ( - - { - setIsRefundModalOpen( true ); - wcpayTracks.recordEvent( - 'payments_transactions_details_refund_modal_open', - { - payment_intent_id: - charge.payment_intent, - } - ); - onClose(); - } } - > - { __( - 'Refund in full', - 'woocommerce-payments' - ) } - - { charge.order && ( + + { ( { onClose } ) => ( + { + setIsRefundModalOpen( + true + ); wcpayTracks.recordEvent( - 'payments_transactions_details_partial_refund', + 'payments_transactions_details_refund_modal_open', { payment_intent_id: charge.payment_intent, - order_id: - charge.order - ?.number, } ); - window.location = - charge.order?.url; + onClose(); } } > { __( - 'Partial refund', + 'Refund in full', 'woocommerce-payments' ) } - ) } - - ) } - - - ) } -
+ { charge.order && ( + { + wcpayTracks.recordEvent( + 'payments_transactions_details_partial_refund', + { + payment_intent_id: + charge.payment_intent, + order_id: + charge.order + ?.number, + } + ); + window.location = + charge.order?.url; + } } + > + { __( + 'Partial refund', + 'woocommerce-payments' + ) } + + ) } + + ) } + + + ) } +
+ diff --git a/client/payment-details/summary/style.scss b/client/payment-details/summary/style.scss index 95df0d33edd..0ee051834fb 100755 --- a/client/payment-details/summary/style.scss +++ b/client/payment-details/summary/style.scss @@ -8,11 +8,6 @@ margin-bottom: 24px; } -.components-card__body:first-of-type { - display: flex; - flex-direction: row; -} - .payment-details-summary { display: flex; flex: 1; @@ -30,6 +25,7 @@ padding: 0; margin: 0; display: flex; + flex-wrap: wrap; align-items: center; .payment-details-summary__amount-currency { diff --git a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap index b719e25c342..4d582a000c7 100644 --- a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap @@ -16,55 +16,61 @@ exports[`PaymentDetailsSummary capture notification and fraud buttons renders ca data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Payment authorized - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Payment authorized +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
+
-

-

- $20.00 - - usd - - - Needs review - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Needs review +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- - + +
+
- Approve Transaction - -
-
- Payment ID: - ch_38jdHA39KKA + Payment ID: + ch_38jdHA39KKA +
+
-

-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -923,79 +941,85 @@ exports[`PaymentDetailsSummary order missing notice does not render notice if or data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1212,79 +1236,85 @@ exports[`PaymentDetailsSummary order missing notice renders notice if order miss data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1524,79 +1554,85 @@ exports[`PaymentDetailsSummary renders a charge with subscriptions 1`] = ` data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -1840,58 +1876,64 @@ exports[`PaymentDetailsSummary renders fully refunded information for a charge 1 data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Refunded - -

-

- Refunded: - -$20.00 -

-

- Fees: - -$0.70 -

- -

- Net: - -$0.70 +

+ $20.00 + + usd + + + Refunded +

+
+

+ Refunded: + -$20.00 +

+

+ Fees: + -$0.70 +

+ +

+ Net: + -$0.70 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
+
-

-

- - - USD - - -

- -

- Fees: - $0.00 -

- -

- Net: - $0.00 +

+ + + USD + +

+
+ +

+ Fees: + $0.00 +

+ +

+ Net: + $0.00 +

+
-
-
- Payment ID: +
+ Payment ID: +
+
-

-

- $20.00 - - usd - - - Partial refund - -

-

- Refunded: - -$12.00 -

-

- Fees: - -$0.70 -

- -

- Net: - $7.30 +

+ $20.00 + + usd + + + Partial refund +

+
+

+ Refunded: + -$12.00 +

+

+ Fees: + -$0.70 +

+ +

+ Net: + $7.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -2634,79 +2688,85 @@ exports[`PaymentDetailsSummary renders the Tap to Pay channel from metadata 1`] data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Paid - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
@@ -2923,79 +2983,85 @@ exports[`PaymentDetailsSummary renders the information of a dispute-reversal cha data-wp-component="CardBody" >
-

- $20.00 - - usd - - - Disputed: Won - -

- -

- Fees: - -$0.70 -

- -

- Net: - $19.30 +

+ $20.00 + + usd + + + Disputed: Won +

+
+ +

+ Fees: + -$0.70 +

+ +

+ Net: + $19.30 +

+
-
-
- Payment ID: - ch_38jdHA39KKA +
+ Payment ID: + ch_38jdHA39KKA +
-
-
- + + +
diff --git a/client/payment-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/test/__snapshots__/index.test.tsx.snap index 7a3274751bf..ebe9d418a92 100644 --- a/client/payment-details/test/__snapshots__/index.test.tsx.snap +++ b/client/payment-details/test/__snapshots__/index.test.tsx.snap @@ -20,78 +20,84 @@ exports[`Payment details page should match the snapshot - Charge query param 1`] data-wp-component="CardBody" >
-

- - Amount placeholder - -

- -

+

- Fee amount + Amount placeholder

- -

+

+ +

+ + Fee amount + +

+ +

+ + Net amount + +

+
+
+
+
- Net amount + Payment ID: pi_xxxxxxxxxxxxxxxxxxxxxxxx -

+
-
- -
+ + +
-
- - - -

-

- $1,500.00 - - usd - - - Paid - -

- -

- Fees: - -$74.00 -

- -

- Net: - $1,426.00 +

+ $1,500.00 + + usd + + + Paid +

+
+ +

+ Fees: + -$74.00 +

+ +

+ Net: + $1,426.00 +

+
-
-
- Payment ID: - pi_mock +
+ Payment ID: + pi_mock +
-
-
- + + +
From 5ee80a640b2360292e55e37e1331316b89f1d30e Mon Sep 17 00:00:00 2001 From: botwoo Date: Tue, 2 Jan 2024 08:44:39 +0000 Subject: [PATCH 6/8] Amend changelog entries for release 7.0.0 --- .../fix-7958-transaction-details-dispute-details-broken-ui | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui diff --git a/changelog/fix-7958-transaction-details-dispute-details-broken-ui b/changelog/fix-7958-transaction-details-dispute-details-broken-ui deleted file mode 100644 index b196bc9910c..00000000000 --- a/changelog/fix-7958-transaction-details-dispute-details-broken-ui +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Not user-facing: fixes styling bug introduced in develop branch - - From 8af9441403234dd72b8b7b110352ae6ca7b109c0 Mon Sep 17 00:00:00 2001 From: Malith Senaweera <6216000+malithsen@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:25:04 -0600 Subject: [PATCH 7/8] Remove URL params from woopay_source_url (#7924) --- changelog/fix-trim-woopay-source-url | 4 ++++ client/checkout/woopay/email-input-iframe.js | 5 ++++- .../components/woopay/save-user/checkout-page-save-user.js | 7 +++++-- tests/js/jest-test-file-setup.js | 5 +++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 changelog/fix-trim-woopay-source-url diff --git a/changelog/fix-trim-woopay-source-url b/changelog/fix-trim-woopay-source-url new file mode 100644 index 00000000000..d0542cc8201 --- /dev/null +++ b/changelog/fix-trim-woopay-source-url @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Checkout error when page URL is too long diff --git a/client/checkout/woopay/email-input-iframe.js b/client/checkout/woopay/email-input-iframe.js index f57c3b4e90f..4a2efe861e5 100644 --- a/client/checkout/woopay/email-input-iframe.js +++ b/client/checkout/woopay/email-input-iframe.js @@ -263,7 +263,10 @@ export const handleWooPayEmailInput = async ( ); urlParams.append( 'wcpayVersion', getConfig( 'wcpayVersionNumber' ) ); urlParams.append( 'is_blocks', isBlocksCheckout ? 'true' : 'false' ); - urlParams.append( 'source_url', window.location.href ); + urlParams.append( + 'source_url', + wcSettings?.storePages?.checkout?.permalink + ); urlParams.append( 'viewport', `${ viewportWidth }x${ viewportHeight }` diff --git a/client/components/woopay/save-user/checkout-page-save-user.js b/client/components/woopay/save-user/checkout-page-save-user.js index 8edd7c583d4..c38bcae2929 100644 --- a/client/components/woopay/save-user/checkout-page-save-user.js +++ b/client/components/woopay/save-user/checkout-page-save-user.js @@ -73,7 +73,8 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => { ? {} : { save_user_in_woopay: isSaveDetailsChecked, - woopay_source_url: window.location.href, + woopay_source_url: + wcSettings?.storePages?.checkout?.permalink, woopay_is_blocks: true, woopay_viewport: `${ viewportWidth }x${ viewportHeight }`, woopay_user_phone_field: { @@ -291,7 +292,9 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => { Date: Tue, 2 Jan 2024 11:30:15 -0600 Subject: [PATCH 8/8] Track payment request button load events (#7919) --- changelog/add-prb-load-tracks | 4 ++ .../blocks/payment-request-express.js | 38 ++++++++++++++++++- client/payment-request/index.js | 18 +++++++++ client/tracks/index.js | 2 + 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 changelog/add-prb-load-tracks diff --git a/changelog/add-prb-load-tracks b/changelog/add-prb-load-tracks new file mode 100644 index 00000000000..5109e5ce0ca --- /dev/null +++ b/changelog/add-prb-load-tracks @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Track payment-request-button loads diff --git a/client/payment-request/blocks/payment-request-express.js b/client/payment-request/blocks/payment-request-express.js index a44cc527b16..01e32444050 100644 --- a/client/payment-request/blocks/payment-request-express.js +++ b/client/payment-request/blocks/payment-request-express.js @@ -1,3 +1,5 @@ +/* global wcpayPaymentRequestParams */ + /** * External dependencies */ @@ -9,6 +11,7 @@ import { Elements, PaymentRequestButtonElement } from '@stripe/react-stripe-js'; import { useInitialization } from './use-initialization'; import { getPaymentRequestData } from '../utils'; import wcpayTracks from 'tracks'; +import { useEffect, useState } from 'react'; /** * PaymentRequestExpressComponent @@ -24,6 +27,7 @@ const PaymentRequestExpressComponent = ( { setExpressPaymentError, onClick, onClose, + onPaymentRequestAvailable, } ) => { // TODO: Don't display custom button when result.requestType // is `apple_pay` or `google_pay`. @@ -68,6 +72,7 @@ const PaymentRequestExpressComponent = ( { } else if ( result.googlePay ) { paymentRequestType = 'google_pay'; } + onPaymentRequestAvailable( paymentRequestType ); } ); const onPaymentRequestButtonClick = () => { @@ -80,7 +85,9 @@ const PaymentRequestExpressComponent = ( { if ( paymentRequestTypeEvents.hasOwnProperty( paymentRequestType ) ) { const event = paymentRequestTypeEvents[ paymentRequestType ]; - wcpayTracks.recordUserEvent( event, { source: 'checkout' } ); + wcpayTracks.recordUserEvent( event, { + source: wcpayPaymentRequestParams?.button_context, + } ); } }; @@ -104,9 +111,36 @@ const PaymentRequestExpressComponent = ( { */ export const PaymentRequestExpress = ( props ) => { const { stripe } = props; + const [ paymentRequestType, setPaymentRequestType ] = useState( false ); + + const handlePaymentRequestAvailability = ( paymentType ) => { + setPaymentRequestType( paymentType ); + }; + + useEffect( () => { + if ( paymentRequestType ) { + const paymentRequestTypeEvents = { + google_pay: wcpayTracks.events.GOOGLEPAY_BUTTON_LOAD, + apple_pay: wcpayTracks.events.APPLEPAY_BUTTON_LOAD, + }; + + if ( + paymentRequestTypeEvents.hasOwnProperty( paymentRequestType ) + ) { + const event = paymentRequestTypeEvents[ paymentRequestType ]; + wcpayTracks.recordUserEvent( event, { + source: wcpayPaymentRequestParams?.button_context, + } ); + } + } + }, [ paymentRequestType ] ); + return ( - + ); }; diff --git a/client/payment-request/index.js b/client/payment-request/index.js index 9578b42517c..fc4b6f6853a 100644 --- a/client/payment-request/index.js +++ b/client/payment-request/index.js @@ -4,6 +4,7 @@ */ import { __ } from '@wordpress/i18n'; import { doAction } from '@wordpress/hooks'; +import { debounce } from 'lodash'; /** * Internal dependencies */ @@ -65,6 +66,19 @@ jQuery( ( $ ) => { } }; + // Track the payment request button load event. + const trackPaymentRequestButtonLoad = debounce( ( source ) => { + const paymentRequestTypeEvents = { + google_pay: wcpayTracks.events.GOOGLEPAY_BUTTON_LOAD, + apple_pay: wcpayTracks.events.APPLEPAY_BUTTON_LOAD, + }; + + if ( paymentRequestTypeEvents.hasOwnProperty( paymentRequestType ) ) { + const event = paymentRequestTypeEvents[ paymentRequestType ]; + wcpayTracks.recordUserEvent( event, { source } ); + } + }, 1000 ); + /** * Object to handle Stripe payment forms. */ @@ -236,6 +250,10 @@ jQuery( ( $ ) => { paymentRequestType: paymentRequestType, } ); + trackPaymentRequestButtonLoad( + wcpayPaymentRequestParams.button_context + ); + wcpayPaymentRequest.attachPaymentRequestButtonEventListeners( prButton, paymentRequest diff --git a/client/tracks/index.js b/client/tracks/index.js index c862f189954..fa94e5d32bc 100644 --- a/client/tracks/index.js +++ b/client/tracks/index.js @@ -61,6 +61,7 @@ function recordUserEvent( eventName, eventProperties, isLegacy = false ) { const events = { APPLEPAY_BUTTON_CLICK: 'applepay_button_click', + APPLEPAY_BUTTON_LOAD: 'applepay_button_load', CONNECT_ACCOUNT_CLICKED: 'wcpay_connect_account_clicked', CONNECT_ACCOUNT_VIEW: 'page_view', CONNECT_ACCOUNT_LEARN_MORE: 'wcpay_welcome_learn_more', @@ -76,6 +77,7 @@ const events = { DISPUTE_INQUIRY_REFUND_MODAL_VIEW: 'wcpay_dispute_inquiry_refund_modal_view', GOOGLEPAY_BUTTON_CLICK: 'gpay_button_click', + GOOGLEPAY_BUTTON_LOAD: 'gpay_button_load', OVERVIEW_BALANCES_CURRENCY_CLICK: 'wcpay_overview_balances_currency_tab_click', OVERVIEW_DEPOSITS_VIEW_HISTORY_CLICK: