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 01/60] 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 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 02/60] 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 03/60] 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: From 08a145b8166949329701160eac83cbe66d6ca1d7 Mon Sep 17 00:00:00 2001 From: Malith Senaweera <6216000+malithsen@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:33:13 -0600 Subject: [PATCH 04/60] Add Tracks to Place Order button (#7854) --- changelog/add-place-order-tracks | 4 ++++ client/checkout/blocks/index.js | 20 ++++++++++++++++++++ client/checkout/classic/event-handlers.js | 13 +++++++++++++ client/tracks/index.js | 1 + 4 files changed, 38 insertions(+) create mode 100644 changelog/add-place-order-tracks diff --git a/changelog/add-place-order-tracks b/changelog/add-place-order-tracks new file mode 100644 index 00000000000..450859bad49 --- /dev/null +++ b/changelog/add-place-order-tracks @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Place order button Tracks diff --git a/client/checkout/blocks/index.js b/client/checkout/blocks/index.js index deed017c0d9..0ce235a0086 100644 --- a/client/checkout/blocks/index.js +++ b/client/checkout/blocks/index.js @@ -34,6 +34,7 @@ import { } from '../constants.js'; import { getDeferredIntentCreationUPEFields } from './payment-elements'; import { handleWooPayEmailInput } from '../woopay/email-input-iframe'; +import wcpayTracks from 'tracks'; import wooPayExpressCheckoutPaymentMethod from '../woopay/express-button/woopay-express-checkout-payment-method'; import { isPreviewing } from '../preview'; @@ -113,6 +114,24 @@ Object.entries( enabledPaymentMethodsConfig ) } ); } ); +const addCheckoutTracking = () => { + const placeOrderButton = document.getElementsByClassName( + 'wc-block-components-checkout-place-order-button' + ); + if ( placeOrderButton.length ) { + placeOrderButton[ 0 ].addEventListener( 'click', () => { + const blocksCheckbox = document.getElementById( + 'radio-control-wc-payment-method-options-woocommerce_payments' + ); + if ( ! blocksCheckbox?.checked ) { + return; + } + + wcpayTracks.recordUserEvent( wcpayTracks.events.PLACE_ORDER_CLICK ); + } ); + } +}; + // Call handleWooPayEmailInput if woopay is enabled and this is the checkout page. if ( getUPEConfig( 'isWooPayEnabled' ) ) { if ( @@ -131,4 +150,5 @@ if ( getUPEConfig( 'isWooPayEnabled' ) ) { registerExpressPaymentMethod( paymentRequestPaymentMethod( api ) ); window.addEventListener( 'load', () => { enqueueFraudScripts( getUPEConfig( 'fraudServices' ) ); + addCheckoutTracking(); } ); diff --git a/client/checkout/classic/event-handlers.js b/client/checkout/classic/event-handlers.js index 00a2581b8a9..584495518be 100644 --- a/client/checkout/classic/event-handlers.js +++ b/client/checkout/classic/event-handlers.js @@ -26,6 +26,7 @@ import WCPayAPI from 'wcpay/checkout/api'; import apiRequest from '../utils/request'; import { handleWooPayEmailInput } from 'wcpay/checkout/woopay/email-input-iframe'; import { isPreviewing } from 'wcpay/checkout/preview'; +import wcpayTracks from 'tracks'; jQuery( function ( $ ) { enqueueFraudScripts( getUPEConfig( 'fraudServices' ) ); @@ -58,6 +59,18 @@ jQuery( function ( $ ) { return processPaymentIfNotUsingSavedMethod( $( this ) ); } ); + $( 'form.checkout' ).on( 'click', '#place_order', function () { + const isWCPay = document.getElementById( + 'payment_method_woocommerce_payments' + ).checked; + + if ( ! isWCPay ) { + return; + } + + wcpayTracks.recordUserEvent( wcpayTracks.events.PLACE_ORDER_CLICK ); + } ); + window.addEventListener( 'hashchange', () => { if ( window.location.hash.startsWith( '#wcpay-confirm-' ) ) { showAuthenticationModalIfRequired( api ); diff --git a/client/tracks/index.js b/client/tracks/index.js index fa94e5d32bc..4690919650d 100644 --- a/client/tracks/index.js +++ b/client/tracks/index.js @@ -92,6 +92,7 @@ const events = { MULTI_CURRENCY_ENABLED_CURRENCIES_UPDATED: 'wcpay_multi_currency_enabled_currencies_updated', PAYMENT_REQUEST_SETTINGS_CHANGE: 'wcpay_payment_request_settings_change', + PLACE_ORDER_CLICK: 'checkout_place_order_button_click', // WCPay Subscriptions empty state - prompts to connect to WCPay or create product. SUBSCRIPTIONS_EMPTY_STATE_VIEW: 'wcpay_subscriptions_empty_state_view', SUBSCRIPTIONS_EMPTY_STATE_FINISH_SETUP: From cdbb1d1584a18d5fa1d038760032b492c3be2e7e Mon Sep 17 00:00:00 2001 From: Hsing-yu Flowers Date: Wed, 3 Jan 2024 15:44:41 -0500 Subject: [PATCH 05/60] Send metadata in the error message (#7951) --- changelog/send-metadata-in-error-message | 4 ++++ includes/class-wc-payment-gateway-wcpay.php | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelog/send-metadata-in-error-message diff --git a/changelog/send-metadata-in-error-message b/changelog/send-metadata-in-error-message new file mode 100644 index 00000000000..1d4c516ae8b --- /dev/null +++ b/changelog/send-metadata-in-error-message @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Send metadata in error message diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 32910b60cad..6331101bd25 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -1463,7 +1463,12 @@ public function process_payment_for_order( $cart, $payment_information, $schedul $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0; if ( $intent_meta_order_id !== $order_id ) { throw new Intent_Authentication_Exception( - __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ), + sprintf( + /* translators: %s: metadata. We do not need to translate WooPayMeta */ + esc_html( __( 'We\'re not able to process this payment. Please try again later. WooPayMeta: intent_meta_order_id: %1$s, order_id: %2$s', 'woocommerce-payments' ) ), + esc_attr( $intent_meta_order_id ), + esc_attr( $order_id ), + ), 'order_id_mismatch' ); } From 9e3012962c0a0e0193c83416a6c111f6a0d130ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Costa?= <10233985+cesarcosta99@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:18:27 -0500 Subject: [PATCH 06/60] Avoid WooPay duplicate charges when order cannot be completely processed (#7968) --- changelog/fix-2199-woopay-duplicate-payments | 5 +++++ .../class-duplicate-payment-prevention-service.php | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 changelog/fix-2199-woopay-duplicate-payments diff --git a/changelog/fix-2199-woopay-duplicate-payments b/changelog/fix-2199-woopay-duplicate-payments new file mode 100644 index 00000000000..19c6948d923 --- /dev/null +++ b/changelog/fix-2199-woopay-duplicate-payments @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Fix WooPay duplicate charges. + + diff --git a/includes/class-duplicate-payment-prevention-service.php b/includes/class-duplicate-payment-prevention-service.php index 99f093c5c09..71a0bfbcc10 100644 --- a/includes/class-duplicate-payment-prevention-service.php +++ b/includes/class-duplicate-payment-prevention-service.php @@ -102,9 +102,13 @@ public function check_payment_intent_attached_to_order_succeeded( WC_Order $orde return; } - $intent_meta_order_id_raw = $intent->get_metadata()['order_id'] ?? ''; - $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0; - if ( $intent_meta_order_id !== $order->get_id() ) { + $intent_meta_order_id_raw = $intent->get_metadata()['order_id'] ?? ''; + $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0; + $intent_meta_order_number_raw = $intent->get_metadata()['order_number'] ?? ''; + $intent_meta_order_number = is_numeric( $intent_meta_order_number_raw ) ? intval( $intent_meta_order_number_raw ) : 0; + $paid_on_woopay = filter_var( $intent->get_metadata()['paid_on_woopay'] ?? false, FILTER_VALIDATE_BOOLEAN ); + $is_woopay_order = $order->get_id() === $intent_meta_order_number; + if ( ! ( $paid_on_woopay && $is_woopay_order ) && $intent_meta_order_id !== $order->get_id() ) { return; } From 2a8613820b9e2f3ca3f54639c8d3cb3a97ba199e Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:08:12 +1000 Subject: [PATCH 07/60] Hide the transaction details refund menu for non-refundable disputes (#7962) --- ...-transaction-refund-eligible-disputes-only | 4 ++ client/disputes/utils.ts | 5 ++ client/payment-details/summary/index.tsx | 12 ++++- .../summary/test/index.test.tsx | 48 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 changelog/fix-7960-transaction-refund-eligible-disputes-only diff --git a/changelog/fix-7960-transaction-refund-eligible-disputes-only b/changelog/fix-7960-transaction-refund-eligible-disputes-only new file mode 100644 index 00000000000..e35c11107f7 --- /dev/null +++ b/changelog/fix-7960-transaction-refund-eligible-disputes-only @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Hide the transaction details refund menu for ineligble disputed transactions diff --git a/client/disputes/utils.ts b/client/disputes/utils.ts index 6e5acf2f437..d4cb2fc52d1 100644 --- a/client/disputes/utils.ts +++ b/client/disputes/utils.ts @@ -72,6 +72,11 @@ export const isInquiry = ( dispute: Pick< Dispute, 'status' > ): boolean => { return dispute.status.startsWith( 'warning' ); }; +export const isRefundable = ( status: DisputeStatus ): boolean => { + // Refundable dispute statuses are one of `warning_needs_response`, `warning_under_review`, `warning_closed` or `won`. + return isInquiry( { status } ) || 'won' === status; +}; + /** * Returns the dispute fee balance transaction for a dispute if it exists * and the deduction has not been reversed. diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx index 607bacb5f0a..58db34e8da3 100644 --- a/client/payment-details/summary/index.tsx +++ b/client/payment-details/summary/index.tsx @@ -48,6 +48,7 @@ import DisputeStatusChip from 'components/dispute-status-chip'; import { getDisputeFeeFormatted, isAwaitingResponse, + isRefundable, } from 'wcpay/disputes/utils'; import { useAuthorization } from 'wcpay/data'; import CaptureAuthorizationButton from 'wcpay/components/capture-authorization-button'; @@ -208,6 +209,15 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( { const disputeFee = charge.dispute && getDisputeFeeFormatted( charge.dispute ); + // If this transaction is disputed, check if it is refundable. + const isDisputeRefundable = charge.dispute + ? isRefundable( charge.dispute.status ) + : true; + + // Control menu only shows refund actions for now. In the future, it may show other actions. + const showControlMenu = + charge.captured && ! charge.refunded && isDisputeRefundable; + // Use the balance_transaction fee if available. If not (e.g. authorized but not captured), use the application_fee_amount. const transactionFee = charge.balance_transaction ? { @@ -484,7 +494,7 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
- { ! charge?.refunded && charge?.captured && ( + { showControlMenu && ( { screen.getByRole( 'button', { name: /Accept dispute/, } ); + + // Refund menu is not rendered + expect( + screen.queryByRole( 'button', { + name: /Translation actions/i, + } ) + ).toBeNull(); } ); test( 'renders the information of a disputed charge when the store/charge currency differ', () => { @@ -684,6 +691,11 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is rendered + screen.getByRole( 'button', { + name: /Translation actions/i, + } ); } ); test( 'correctly renders dispute details for "under_review" disputes', () => { @@ -712,6 +724,13 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is not rendered + expect( + screen.queryByRole( 'button', { + name: /Translation actions/i, + } ) + ).toBeNull(); } ); test( 'correctly renders dispute details for "accepted" disputes', () => { @@ -744,6 +763,13 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is not rendered + expect( + screen.queryByRole( 'button', { + name: /Translation actions/i, + } ) + ).toBeNull(); } ); test( 'correctly renders dispute details for "lost" disputes', () => { @@ -777,6 +803,13 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is not rendered + expect( + screen.queryByRole( 'button', { + name: /Translation actions/i, + } ) + ).toBeNull(); } ); test( 'correctly renders dispute details for "warning_needs_response" inquiry disputes', () => { @@ -807,6 +840,11 @@ describe( 'PaymentDetailsSummary', () => { screen.getByRole( 'button', { name: /Issue refund/i, } ); + + // Refund menu is rendered + screen.getByRole( 'button', { + name: /Translation actions/i, + } ); } ); test( 'correctly renders dispute details for "warning_under_review" inquiry disputes', () => { @@ -834,6 +872,11 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is rendered + screen.getByRole( 'button', { + name: /Translation actions/i, + } ); } ); test( 'correctly renders dispute details for "warning_closed" inquiry disputes', () => { @@ -862,6 +905,11 @@ describe( 'PaymentDetailsSummary', () => { name: /Accept/i, } ) ).toBeNull(); + + // Refund menu is rendered + screen.getByRole( 'button', { + name: /Translation actions/i, + } ); } ); describe( 'order missing notice', () => { From c56dbcf9de0a4eacb6a89cab94e8be55cc91d0dc Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Fri, 5 Jan 2024 15:58:06 +1000 Subject: [PATCH 08/60] Fix missing transaction error when viewing orders placed in mismatched test mode (#7972) --- ...-7967-disputed-order-notice-test-mode-check | 4 ++++ client/order/index.js | 7 +++++-- includes/admin/class-wc-payments-admin.php | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 changelog/fix-7967-disputed-order-notice-test-mode-check diff --git a/changelog/fix-7967-disputed-order-notice-test-mode-check b/changelog/fix-7967-disputed-order-notice-test-mode-check new file mode 100644 index 00000000000..43f8af2c81b --- /dev/null +++ b/changelog/fix-7967-disputed-order-notice-test-mode-check @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. diff --git a/client/order/index.js b/client/order/index.js index 1bfdfeee7ad..16ec2b60183 100644 --- a/client/order/index.js +++ b/client/order/index.js @@ -61,6 +61,9 @@ jQuery( function ( $ ) { const manualRefundsTip = getConfig( 'manualRefundsTip' ) ?? ''; const chargeId = getConfig( 'chargeId' ); const testMode = getConfig( 'testMode' ); + // Order and site are both in test mode, or both in live mode. + // '1' = true, '' = false, null = the order was created before the test mode meta was added, so we assume it matches. + const orderTestModeMatch = getConfig( 'orderTestModeMatch' ) !== ''; maybeShowOrderNotices(); @@ -175,7 +178,7 @@ jQuery( function ( $ ) { '#wcpay-order-payment-details-container' ); - // If the container doesn't exist (WC < 7.9), or the charge ID isn't present, don't render the notice. + // If the container doesn't exist (WC < 7.9) don't render notices. if ( ! container ) { return; } @@ -184,7 +187,7 @@ jQuery( function ( $ ) { <> { testMode && } - { chargeId && ( + { chargeId && orderTestModeMatch && ( get_payment_method() ) { $refund_amount = $order->get_remaining_refund_amount(); + + // Check if the order's test mode meta matches the site's current test mode state. + // E.g. order and site are both in test mode, or both in live mode. + $order_mode = $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY ); + if ( '' === $order_mode ) { + // If the order doesn't have a mode set, assume it was created before the order mode meta was added (< 6.9 PR#7651) and return null. + $order_test_mode_match = null; + } else { + $order_test_mode_match = ( + \WCPay\Constants\Order_Mode::PRODUCTION === $order_mode && + WC_Payments::mode()->is_live() + ) || ( + \WCPay\Constants\Order_Mode::TEST === $order_mode && + WC_Payments::mode()->is_test() + ); + } + wp_localize_script( 'WCPAY_ADMIN_ORDER_ACTIONS', 'wcpay_order_config', @@ -736,6 +753,7 @@ public function enqueue_payments_scripts() { 'chargeId' => $this->order_service->get_charge_id_for_order( $order ), 'hasOpenAuthorization' => $this->order_service->has_open_authorization( $order ), 'testMode' => \WCPay\Constants\Order_Mode::TEST === $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY ), + 'orderTestModeMatch' => $order_test_mode_match, ] ); wp_localize_script( From c02877a5e56d94afc6c280eea1ece9cc19372224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Janisels?= Date: Fri, 5 Jan 2024 11:34:12 +0200 Subject: [PATCH 09/60] Fix the typo for transaction controls label (#7979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kārlis Janisels --- changelog/fix-7964-typo-for-transaction-actions | 5 +++++ client/payment-details/summary/index.tsx | 2 +- .../test/__snapshots__/index.test.tsx.snap | 14 +++++++------- .../payment-details/summary/test/index.test.tsx | 16 ++++++++-------- .../test/__snapshots__/index.test.tsx.snap | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 changelog/fix-7964-typo-for-transaction-actions diff --git a/changelog/fix-7964-typo-for-transaction-actions b/changelog/fix-7964-typo-for-transaction-actions new file mode 100644 index 00000000000..603667aa9a7 --- /dev/null +++ b/changelog/fix-7964-typo-for-transaction-actions @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Fixed a typo + + diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx index 58db34e8da3..0d9ea81fa93 100644 --- a/client/payment-details/summary/index.tsx +++ b/client/payment-details/summary/index.tsx @@ -502,7 +502,7 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
diff --git a/client/payment-methods-icons.tsx b/client/payment-methods-icons.tsx index 1cad55b62f2..bc29d2518f7 100644 --- a/client/payment-methods-icons.tsx +++ b/client/payment-methods-icons.tsx @@ -18,6 +18,7 @@ import IdealAsset from 'assets/images/payment-methods/ideal.svg?asset'; import BankDebitAsset from 'assets/images/payment-methods/bank-debit.svg?asset'; import AffirmAsset from 'assets/images/payment-methods/affirm.svg?asset'; import AfterpayAsset from 'assets/images/payment-methods/afterpay.svg?asset'; +import ClearpayAsset from 'assets/images/payment-methods/clearpay.svg?asset'; import JCBAsset from 'assets/images/payment-methods/jcb.svg?asset'; import KlarnaAsset from 'assets/images/payment-methods/klarna.svg?asset'; import VisaAsset from 'assets/images/cards/visa.svg?asset'; @@ -57,6 +58,10 @@ export const AfterpayIcon = iconComponent( AfterpayAsset, __( 'Afterpay', 'woocommerce-payments' ) ); +export const ClearpayIcon = iconComponent( + ClearpayAsset, + __( 'Clearpay', 'woocommerce-payments' ) +); export const AmericanExpressIcon = iconComponent( AmexAsset, __( 'American Express', 'woocommerce-payments' ) diff --git a/client/payment-methods-map.tsx b/client/payment-methods-map.tsx index d0a17f282ea..be758dd10ad 100644 --- a/client/payment-methods-map.tsx +++ b/client/payment-methods-map.tsx @@ -10,6 +10,7 @@ import { __ } from '@wordpress/i18n'; import { AffirmIcon, AfterpayIcon, + ClearpayIcon, BancontactIcon, BankDebitIcon, CreditCardIcon, @@ -23,6 +24,18 @@ import { SofortIcon, } from 'wcpay/payment-methods-icons'; +declare global { + interface Window { + wcpaySettings: { + accountStatus: { + country: string; + }; + }; + } +} + +const accountCountry = window.wcpaySettings?.accountStatus?.country || 'US'; + export interface PaymentMethodMapEntry { id: string; label: string; @@ -208,16 +221,29 @@ const PaymentMethodInformationObject: Record< }, afterpay_clearpay: { id: 'afterpay_clearpay', - label: __( 'Afterpay', 'woocommerce-payments' ), + label: + 'GB' === accountCountry + ? __( 'Clearpay', 'woocommerce-payments' ) + : __( 'Afterpay', 'woocommerce-payments' ), brandTitles: { - afterpay_clearpay: __( 'Afterpay', 'woocommerce-payments' ), + afterpay_clearpay: + 'GB' === accountCountry + ? __( 'Clearpay', 'woocommerce-payments' ) + : __( 'Afterpay', 'woocommerce-payments' ), }, - description: __( - // translators: %s is the store currency. - 'Allow customers to pay over time with Afterpay. Available to all customers paying in %s.', - 'woocommerce-payments' - ), - icon: AfterpayIcon, + description: + 'GB' === accountCountry + ? __( + // translators: %s is the store currency. + 'Allow customers to pay over time with Clearpay. Available to all customers paying in %s.', + 'woocommerce-payments' + ) + : __( + // translators: %s is the store currency. + 'Allow customers to pay over time with Afterpay. Available to all customers paying in %s.', + 'woocommerce-payments' + ), + icon: 'GB' === accountCountry ? ClearpayIcon : AfterpayIcon, currencies: [ 'USD', 'AUD', 'CAD', 'NZD', 'GBP', 'EUR' ], stripe_key: 'afterpay_clearpay_payments', allows_manual_capture: false, diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 7e55bda63b3..5ec5ba7697b 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -267,13 +267,14 @@ public function __construct( $this->localization_service = $localization_service; $this->fraud_service = $fraud_service; + $account_country = $this->get_account_country(); $this->id = static::GATEWAY_ID; - $this->icon = $payment_method->get_icon(); + $this->icon = $payment_method->get_icon( $account_country ); $this->has_fields = true; $this->method_title = 'WooPayments'; $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 = $payment_method->get_title(); + $this->title = $payment_method->get_title( $account_country ); $this->description = ''; $this->supports = [ 'products', @@ -2052,7 +2053,7 @@ public function set_payment_method_title_for_order( $order, $payment_method_type return; } - $payment_method_title = $payment_method->get_title( $payment_method_details ); + $payment_method_title = $payment_method->get_title( $this->get_account_country(), $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; @@ -2871,7 +2872,7 @@ protected function get_deposit_delay_days( int $default_value = 7 ): int { * * @return string code of the country. */ - protected function get_account_country( string $default_value = 'US' ): string { + public function get_account_country( string $default_value = 'US' ): string { try { if ( $this->is_connected() ) { return $this->account->get_account_country() ?? $default_value; diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php index 98a647b5bff..5ba354b3810 100644 --- a/includes/class-wc-payments-checkout.php +++ b/includes/class-wc-payments-checkout.php @@ -295,10 +295,11 @@ public function get_enabled_payment_method_config() { } $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id ); + $account_country = $this->account->get_account_country(); $settings[ $payment_method_id ] = [ 'isReusable' => $payment_method->is_reusable(), - 'title' => $payment_method->get_title(), - 'icon' => $payment_method->get_icon(), + 'title' => $payment_method->get_title( $account_country ), + 'icon' => $payment_method->get_icon( $account_country ), 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ), 'countries' => $payment_method->get_countries(), ]; diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index cad21f86d9e..18bd6b4f77d 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -293,6 +293,8 @@ public static function init() { include_once __DIR__ . '/class-wc-payments-utils.php'; include_once __DIR__ . '/core/class-mode.php'; + self::$mode = new Mode(); + include_once __DIR__ . '/class-database-cache.php'; self::$database_cache = new Database_Cache(); self::$database_cache->init_hooks(); @@ -538,8 +540,6 @@ public static function init() { self::$card_gateway->init_hooks(); self::$wc_payments_checkout->init_hooks(); - self::$mode = new Mode(); - self::$webhook_processing_service = new WC_Payments_Webhook_Processing_Service( self::$api_client, self::$db_helper, self::$account, self::$remote_note_service, self::$order_service, self::$in_person_payments_receipts_service, self::get_gateway(), self::$customer_service, self::$database_cache ); self::$webhook_reliability_service = new WC_Payments_Webhook_Reliability_Service( self::$api_client, self::$action_scheduler_service, self::$webhook_processing_service ); diff --git a/includes/multi-currency/PaymentMethodsCompatibility.php b/includes/multi-currency/PaymentMethodsCompatibility.php index 8f4f0f88e8b..7f48df769d5 100644 --- a/includes/multi-currency/PaymentMethodsCompatibility.php +++ b/includes/multi-currency/PaymentMethodsCompatibility.php @@ -82,7 +82,7 @@ function ( $result, $method ) { $result[ $method ] = [ 'currencies' => $payment_method_instance->get_currencies(), - 'title' => $payment_method_instance->get_title(), + 'title' => $payment_method_instance->get_title( $this->gateway->get_account_country() ), ]; return $result; diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php index 628ca444075..9bf7a0c3359 100644 --- a/includes/payment-methods/class-afterpay-payment-method.php +++ b/includes/payment-methods/class-afterpay-payment-method.php @@ -64,6 +64,35 @@ public function __construct( $token_service ) { ]; } + /** + * Returns payment method title. + * + * @param string $account_country Country of merchants account. + * @param array|false $payment_details Optional payment details from charge object. + * @return string|null + */ + public function get_title( string $account_country, $payment_details = false ) { + if ( 'GB' === $account_country ) { + return __( 'Clearpay', 'woocommerce-payments' ); + } + + return __( 'Afterpay', 'woocommerce-payments' ); + } + + /** + * Returns payment method icon. + * + * @param string $account_country Country of merchants account. + * @return string|null + */ + public function get_icon( string $account_country ) { + if ( 'GB' === $account_country ) { + return plugins_url( 'assets/images/payment-methods/clearpay.svg', WCPAY_PLUGIN_FILE ); + } + + return plugins_url( 'assets/images/payment-methods/afterpay.svg', WCPAY_PLUGIN_FILE ); + } + /** * Returns testing credentials to be printed at checkout in test mode. * diff --git a/includes/payment-methods/class-cc-payment-method.php b/includes/payment-methods/class-cc-payment-method.php index dfd20c3eaf6..4edb7b535f8 100644 --- a/includes/payment-methods/class-cc-payment-method.php +++ b/includes/payment-methods/class-cc-payment-method.php @@ -33,11 +33,11 @@ public function __construct( $token_service ) { /** * Returns payment method title * - * @param array|bool $payment_details Optional payment details from charge object. - * + * @param string $account_country Account country. + * @param array|false $payment_details Payment details. * @return string */ - public function get_title( $payment_details = false ) { + public function get_title( string $account_country, $payment_details = false ) { if ( ! $payment_details ) { return $this->title; } diff --git a/includes/payment-methods/class-upe-payment-method.php b/includes/payment-methods/class-upe-payment-method.php index ddc954e719f..3672048b118 100644 --- a/includes/payment-methods/class-upe-payment-method.php +++ b/includes/payment-methods/class-upe-payment-method.php @@ -113,11 +113,12 @@ public function get_id() { /** * Returns payment method title * - * @param array|bool $payment_details Optional payment details from charge object. + * @param string $account_country Country of merchants account. + * @param array|false $payment_details Optional payment details from charge object. * * @return string */ - public function get_title( $payment_details = false ) { + public function get_title( string $account_country, $payment_details = false ) { return $this->title; } @@ -224,9 +225,10 @@ abstract public function get_testing_instructions(); /** * Returns the payment method icon URL or an empty string. * + * @param string $account_country Optional account country. * @return string */ - public function get_icon() { + public function get_icon( string $account_country ) { return isset( $this->icon_url ) ? $this->icon_url : ''; } diff --git a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php index 6a0f24eeba8..7a6e910db46 100644 --- a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php +++ b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php @@ -54,9 +54,11 @@ public function set_up() { ->setMethods( [ 'get_upe_enabled_payment_method_ids', + 'get_account_country', ] ) ->getMock(); + $this->gateway_mock->method( 'get_account_country' )->willReturn( 'US' ); $this->payment_methods_compatibility = new \WCPay\MultiCurrency\PaymentMethodsCompatibility( $this->multi_currency_mock, $this->gateway_mock ); $this->payment_methods_compatibility->init_hooks(); 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 7c013e2b858..8260f8707b5 100644 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php @@ -688,72 +688,75 @@ public function test_payment_methods_show_correct_default_outputs() { $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); + $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) ); + $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) ); + $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) ); $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); $this->assertTrue( $card_method->is_reusable() ); $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) ); $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $giropay_method->is_reusable() ); $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) ); $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $p24_method->is_reusable() ); $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) ); $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sofort_method->is_reusable() ); $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) ); $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $bancontact_method->is_reusable() ); $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title() ); - $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); + $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) ); + $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) ); $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $eps_method->is_reusable() ); $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) ); $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sepa_method->is_reusable() ); $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) ); $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $ideal_method->is_reusable() ); $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) ); $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $becs_method->is_reusable() ); $this->assertSame( 'affirm', $affirm_method->get_id() ); - $this->assertSame( 'Affirm', $affirm_method->get_title() ); - $this->assertSame( 'Affirm', $affirm_method->get_title( $mock_affirm_details ) ); + $this->assertSame( 'Affirm', $affirm_method->get_title( 'US' ) ); + $this->assertSame( 'Affirm', $affirm_method->get_title( 'US', $mock_affirm_details ) ); $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $affirm_method->is_reusable() ); $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title() ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title( $mock_afterpay_details ) ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US' ) ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US', $mock_afterpay_details ) ); $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $afterpay_method->is_reusable() ); + $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB' ) ); + $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB', $mock_afterpay_details ) ); + $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'GB' ) ); } public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { 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 e788e467a14..fc9446ff775 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 @@ -893,58 +893,58 @@ public function test_payment_methods_show_correct_default_outputs() { $becs_method = $this->mock_payment_methods['au_becs_debit']; $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); + $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) ); + $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) ); + $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) ); $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); $this->assertTrue( $card_method->is_reusable() ); $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) ); $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $giropay_method->is_reusable() ); $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) ); $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $p24_method->is_reusable() ); $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) ); $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sofort_method->is_reusable() ); $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) ); $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $bancontact_method->is_reusable() ); $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title() ); - $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); + $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) ); + $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) ); $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $eps_method->is_reusable() ); $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) ); $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sepa_method->is_reusable() ); $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) ); $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $ideal_method->is_reusable() ); $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) ); $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $becs_method->is_reusable() ); } diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php index d6273a1fcd2..72a7688187d 100644 --- a/tests/unit/test-class-wc-payments-checkout.php +++ b/tests/unit/test-class-wc-payments-checkout.php @@ -103,6 +103,9 @@ public function set_up() { ->disableOriginalConstructor() ->getMock(); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_wcpay_account + ->method( 'get_account_country' ) + ->willReturn( 'US' ); $this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class ); $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); From 983a4720b390575c6bbc4cf9999e34d9793ddad0 Mon Sep 17 00:00:00 2001 From: Alefe Souza Date: Mon, 15 Jan 2024 21:02:42 -0300 Subject: [PATCH 31/60] Fix WooPay Adapted Extensions initialization (#7986) --- changelog/fix-woopay-adapted-extensions | 5 +++++ includes/woopay/class-woopay-session.php | 1 + 2 files changed, 6 insertions(+) create mode 100644 changelog/fix-woopay-adapted-extensions diff --git a/changelog/fix-woopay-adapted-extensions b/changelog/fix-woopay-adapted-extensions new file mode 100644 index 00000000000..f1f70ad71f3 --- /dev/null +++ b/changelog/fix-woopay-adapted-extensions @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Fix WooPay adapted extensions initialization. + + diff --git a/includes/woopay/class-woopay-session.php b/includes/woopay/class-woopay-session.php index 398219468be..42a5ec09c67 100644 --- a/includes/woopay/class-woopay-session.php +++ b/includes/woopay/class-woopay-session.php @@ -462,6 +462,7 @@ private static function get_init_session_request( $order_id = null, $key = null, WC()->customer->set_billing_email( $email ); WC()->customer->save(); + $woopay_adapted_extensions->init(); $request['adapted_extensions'] = $woopay_adapted_extensions->get_adapted_extensions_data( $email ); if ( ! is_user_logged_in() && count( $request['adapted_extensions'] ) > 0 ) { From e157a1c76588df5cb5f813d5f887059f5a0d295f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Costa?= <10233985+cesarcosta99@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:19:56 -0500 Subject: [PATCH 32/60] Prevent possible fatal when using `get_edit_post_link` filter (#8023) --- changelog/fix-7881-strict-return-type | 4 ++++ includes/multi-currency/Helpers/OrderMetaHelper.php | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 changelog/fix-7881-strict-return-type diff --git a/changelog/fix-7881-strict-return-type b/changelog/fix-7881-strict-return-type new file mode 100644 index 00000000000..5c2b0cc42be --- /dev/null +++ b/changelog/fix-7881-strict-return-type @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Prevent possible fatal when using get_edit_post_link filter. diff --git a/includes/multi-currency/Helpers/OrderMetaHelper.php b/includes/multi-currency/Helpers/OrderMetaHelper.php index 64e53e3c80a..208fefc2c26 100644 --- a/includes/multi-currency/Helpers/OrderMetaHelper.php +++ b/includes/multi-currency/Helpers/OrderMetaHelper.php @@ -325,14 +325,19 @@ public function display_meta_box_content( $order ) { /** * Appends our parameter to the edit post link if needed. * - * @param string $url The current edit post link. + * @param string|null $url The current edit post link. * - * @return string + * @return string|null */ - public function maybe_update_edit_post_link( $url ): string { + public function maybe_update_edit_post_link( $url ): ?string { + if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) { + return null; + } + if ( $this->is_feature_enabled() ) { $url .= '&wcpay_mc_meta_helper=1'; } + return $url; } From f63d75f2c2a83e8dce804fa0b248e86eefbeeeac Mon Sep 17 00:00:00 2001 From: Valery Sukhomlinov <683297+dmvrtx@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:05:12 +0100 Subject: [PATCH 33/60] Allow issue of zero amount refunds (#8013) --- changelog/fix-7984-allow-zero-amount-refunds | 4 ++++ includes/class-wc-payment-gateway-wcpay.php | 8 +++++++- ...s-wc-payment-gateway-wcpay-process-refund.php | 16 +++++++++++++--- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 changelog/fix-7984-allow-zero-amount-refunds diff --git a/changelog/fix-7984-allow-zero-amount-refunds b/changelog/fix-7984-allow-zero-amount-refunds new file mode 100644 index 00000000000..9a3327f189b --- /dev/null +++ b/changelog/fix-7984-allow-zero-amount-refunds @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 5ec5ba7697b..c69ef8782e3 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -2184,8 +2184,14 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) { ); } + // Refund without an amount is a no-op, but required to succeed in + // case merchant needs it to re-stock order items. + if ( '0.00' === sprintf( '%0.2f', $amount ?? 0 ) ) { + return true; + } + // If the entered amount is not valid stop without making a request. - if ( $amount <= 0 || $amount > $order->get_total() ) { + if ( $amount < 0 || $amount > $order->get_total() ) { return new WP_Error( 'invalid-amount', __( 'The refund amount is not valid.', 'woocommerce-payments' ) 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 7350621aedc..f42ef677dbb 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 @@ -766,7 +766,7 @@ public function test_process_refund_on_uncaptured_payment() { $this->assertEquals( 'uncaptured-payment', $result->get_error_code() ); } - public function test_process_refund_on_invalid_amount() { + public function test_process_refund_on_zero_amount() { $intent_id = 'pi_xxxxxxxxxxxxx'; $charge_id = 'ch_yyyyyyyyyyyyy'; @@ -778,9 +778,19 @@ public function test_process_refund_on_invalid_amount() { $order_id = $order->get_id(); $result = $this->wcpay_gateway->process_refund( $order_id, 0 ); + $this->assertSame( true, $result ); + } - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertEquals( 'invalid-amount', $result->get_error_code() ); + public function test_process_refund_on_invalid_amount() { + $intent_id = 'pi_xxxxxxxxxxxxx'; + $charge_id = 'ch_yyyyyyyyyyyyy'; + + $order = WC_Helper_Order::create_order(); + $order->update_meta_data( '_intent_id', $intent_id ); + $order->update_meta_data( '_charge_id', $charge_id ); + $order->save(); + + $order_id = $order->get_id(); $result = $this->wcpay_gateway->process_refund( $order_id, - 5 ); From 1156673f12940beba190fbd9acd05cf199c77289 Mon Sep 17 00:00:00 2001 From: Francesco Date: Wed, 17 Jan 2024 22:14:01 +0100 Subject: [PATCH 34/60] fix: Stripe Link autofill on checkout (#8021) --- ...-6881-stripe-link-blocks-checkout-refactor | 4 + client/checkout/api/index.js | 1 + client/checkout/blocks/payment-processor.js | 96 ++--- client/checkout/classic/payment-processing.js | 147 +++++-- client/checkout/constants.js | 32 +- client/checkout/stripe-link/index.js | 154 ++----- .../checkout/stripe-link/test/index.test.js | 400 +----------------- client/checkout/utils/upe.js | 18 +- 8 files changed, 225 insertions(+), 627 deletions(-) create mode 100644 changelog/fix-6881-stripe-link-blocks-checkout-refactor diff --git a/changelog/fix-6881-stripe-link-blocks-checkout-refactor b/changelog/fix-6881-stripe-link-blocks-checkout-refactor new file mode 100644 index 00000000000..b50316fcdbc --- /dev/null +++ b/changelog/fix-6881-stripe-link-blocks-checkout-refactor @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix Stripe Link autofill on checkout. diff --git a/client/checkout/api/index.js b/client/checkout/api/index.js index 9b05ea40a26..1c42111e6e0 100644 --- a/client/checkout/api/index.js +++ b/client/checkout/api/index.js @@ -85,6 +85,7 @@ export default class WCPayAPI { if ( ! this.stripe ) { let betas = [ 'card_country_event_beta_1' ]; if ( isStripeLinkEnabled ) { + // https://stripe.com/docs/payments/link/autofill-modal betas = betas.concat( [ 'link_autofill_modal_beta_1' ] ); } diff --git a/client/checkout/blocks/payment-processor.js b/client/checkout/blocks/payment-processor.js index aff4137356f..a88c74fa7cd 100644 --- a/client/checkout/blocks/payment-processor.js +++ b/client/checkout/blocks/payment-processor.js @@ -27,10 +27,6 @@ import { import enableStripeLinkPaymentMethod from 'wcpay/checkout/stripe-link'; import { getUPEConfig } from 'wcpay/utils/checkout'; import { validateElements } from 'wcpay/checkout/classic/payment-processing'; -import { - BLOCKS_SHIPPING_ADDRESS_FIELDS, - BLOCKS_BILLING_ADDRESS_FIELDS, -} from '../constants'; const getBillingDetails = ( billingData ) => { return { @@ -74,8 +70,11 @@ const PaymentProcessor = ( { const paymentMethodsConfig = getUPEConfig( 'paymentMethodsConfig' ); const isTestMode = getUPEConfig( 'testMode' ); const gatewayConfig = getPaymentMethods()[ upeMethods[ paymentMethodId ] ]; - const customerData = useCustomerData(); - const billingData = customerData.billingAddress; + const { + billingAddress: billingData, + setShippingAddress, + setBillingAddress, + } = useCustomerData(); useEffect( () => { if ( isLinkEnabled( paymentMethodsConfig ) ) { @@ -83,57 +82,52 @@ const PaymentProcessor = ( { api: api, elements: elements, emailId: 'email', - fill_field_method: ( address, nodeId, key ) => { - const setAddress = - BLOCKS_SHIPPING_ADDRESS_FIELDS[ key ] === nodeId - ? customerData.setShippingAddress - : customerData.setBillingData || - customerData.setBillingAddress; - const customerAddress = - BLOCKS_SHIPPING_ADDRESS_FIELDS[ key ] === nodeId - ? customerData.shippingAddress - : customerData.billingData || - customerData.billingAddress; - - if ( key === 'line1' ) { - customerAddress.address_1 = address.address[ key ]; - } else if ( key === 'line2' ) { - customerAddress.address_2 = address.address[ key ]; - } else if ( key === 'postal_code' ) { - customerAddress.postcode = address.address[ key ]; - } else { - customerAddress[ key ] = address.address[ key ]; + onAutofill: ( billingAddress, shippingAddress ) => { + // in some cases (e.g.: customer doesn't select the payment method in the Link modal), the billing address is empty. + if ( billingAddress ) { + // setting the country first, in case the "state"/"county"/"province" + // select changes from a select to a text field (or vice-versa). + setBillingAddress( { + country: billingAddress.country, + } ); + // after the country, we can safely set the other fields + setBillingAddress( { + ...billingAddress, + } ); } - setAddress( customerAddress ); - - if ( customerData.billingData ) { - customerData.billingData.email = getBlocksEmailValue(); - customerData.setBillingData( customerData.billingData ); - } else { - customerData.billingAddress.email = getBlocksEmailValue(); - customerData.setBillingAddress( - customerData.billingAddress - ); + // in some cases (e.g.: customer doesn't select the shipping address method in the Link modal), + // the shipping address is empty. + if ( shippingAddress ) { + // setting the country first, in case the "state"/"county"/"province" + // select changes from a select to a text field (or vice-versa). + setShippingAddress( { + country: shippingAddress.country, + } ); + // after the country, we can safely set the other fields + setShippingAddress( { + ...shippingAddress, + } ); } + + // after all the above, we can now set the email field by getting its value from the DOM. + setBillingAddress( { + email: getBlocksEmailValue(), + } ); + setShippingAddress( { + email: getBlocksEmailValue(), + } ); }, - show_button: blocksShowLinkButtonHandler, - shipping_fields: BLOCKS_SHIPPING_ADDRESS_FIELDS, - billing_fields: BLOCKS_BILLING_ADDRESS_FIELDS, - complete_shipping: () => { - return ( - document.getElementById( 'shipping-address_1' ) !== null - ); - }, - complete_billing: () => { - return ( - document.getElementById( 'billing-address_1' ) !== null - ); - }, + onButtonShow: blocksShowLinkButtonHandler, } ); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ elements ] ); + }, [ + api, + elements, + paymentMethodsConfig, + setBillingAddress, + setShippingAddress, + ] ); useEffect( () => diff --git a/client/checkout/classic/payment-processing.js b/client/checkout/classic/payment-processing.js index 073436abd71..713faf5906f 100644 --- a/client/checkout/classic/payment-processing.js +++ b/client/checkout/classic/payment-processing.js @@ -135,26 +135,36 @@ function createStripePaymentMethod( ...params.billing_details, name: `${ - document.querySelector( '#billing_first_name' ) - ?.value || '' + document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.first_name }` + )?.value || '' } ${ - document.querySelector( '#billing_last_name' )?.value || - '' + document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.last_name }` + )?.value || '' }`.trim() || undefined, email: document.querySelector( '#billing_email' )?.value, phone: document.querySelector( '#billing_phone' )?.value, address: { ...params.billing_details?.address, - city: document.querySelector( '#billing_city' )?.value, - country: document.querySelector( '#billing_country' ) - ?.value, - line1: document.querySelector( '#billing_address_1' ) - ?.value, - line2: document.querySelector( '#billing_address_2' ) - ?.value, - postal_code: document.querySelector( '#billing_postcode' ) - ?.value, - state: document.querySelector( '#billing_state' )?.value, + city: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.city }` + )?.value, + country: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.country }` + )?.value, + line1: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.address_1 }` + )?.value, + line2: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.address_2 }` + )?.value, + postal_code: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.postcode }` + )?.value, + state: document.querySelector( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.state }` + )?.value, }, }, }; @@ -228,6 +238,28 @@ function appendSetupIntentToForm( form, confirmedIntent ) { form.append( input ); } +const ensureSameAsBillingIsUnchecked = () => { + const sameAsBillingCheckbox = document.getElementById( + 'ship-to-different-address-checkbox' + ); + + if ( ! sameAsBillingCheckbox ) { + return; + } + + if ( sameAsBillingCheckbox.checked === true ) { + return; + } + + sameAsBillingCheckbox.checked = true; + + if ( window.jQuery ) { + const $sameAsBillingCheckbox = window.jQuery( sameAsBillingCheckbox ); + + $sameAsBillingCheckbox.prop( 'checked', true ).change(); + } +}; + /** * If Link is enabled, add event listeners and handlers. * @@ -239,21 +271,84 @@ export function maybeEnableStripeLink( api ) { api: api, elements: gatewayUPEComponents.card.elements, emailId: 'billing_email', - complete_billing: () => { - return true; + onAutofill: ( billingAddress, shippingAddress ) => { + const fillAddress = ( addressValues, fieldsMap ) => { + // in some cases, the address might be empty. + if ( ! addressValues ) return; + + // setting the country first, in case the "state"/"county"/"province" + // select changes from a select to a text field (or vice-versa). + const countryElement = document.getElementById( + fieldsMap.country + ); + if ( countryElement ) { + countryElement.value = addressValues.country; + // manually dispatching the "change" event, since the element might not be a `select2` component. + countryElement.dispatchEvent( new Event( 'change' ) ); + } + + Object.entries( addressValues ).forEach( + ( [ piece, value ] ) => { + const element = document.getElementById( + fieldsMap[ piece ] + ); + if ( element ) { + element.value = value; + } + } + ); + }; + + // this is needed on shortcode checkout, but not on blocks checkout. + ensureSameAsBillingIsUnchecked(); + + fillAddress( billingAddress, SHORTCODE_BILLING_ADDRESS_FIELDS ); + fillAddress( + shippingAddress, + SHORTCODE_SHIPPING_ADDRESS_FIELDS + ); + + // manually dispatching the "change" event, since the element might be a `select2` component. + document + .querySelectorAll( + `#${ SHORTCODE_BILLING_ADDRESS_FIELDS.country }, #${ SHORTCODE_BILLING_ADDRESS_FIELDS.state }, ` + + `#${ SHORTCODE_SHIPPING_ADDRESS_FIELDS.country }, #${ SHORTCODE_SHIPPING_ADDRESS_FIELDS.state }` + ) + .forEach( ( element ) => { + if ( ! window.jQuery ) return; + + const $element = window.jQuery( element ); + if ( $element.data( 'select2' ) ) { + $element.trigger( 'change' ); + } + } ); }, - complete_shipping: () => { - return ( - document.getElementById( - 'ship-to-different-address-checkbox' - ) && - document.getElementById( - 'ship-to-different-address-checkbox' - ).checked + onButtonShow: ( linkAutofill ) => { + // Display StripeLink button if email field is prefilled. + const billingEmailInput = document.getElementById( + 'billing_email' + ); + if ( billingEmailInput.value !== '' ) { + const linkButtonTop = + billingEmailInput.offsetTop + + ( billingEmailInput.offsetHeight - 40 ) / 2; + const stripeLinkButton = document.querySelector( + '.wcpay-stripelink-modal-trigger' + ); + stripeLinkButton.style.display = 'block'; + stripeLinkButton.style.top = `${ linkButtonTop }px`; + } + + // Handle StripeLink button click. + const stripeLinkButton = document.querySelector( + '.wcpay-stripelink-modal-trigger' ); + stripeLinkButton.addEventListener( 'click', ( event ) => { + event.preventDefault(); + // Trigger modal. + linkAutofill.launch( { email: billingEmailInput.value } ); + } ); }, - shipping_fields: SHORTCODE_SHIPPING_ADDRESS_FIELDS, - billing_fields: SHORTCODE_BILLING_ADDRESS_FIELDS, } ); } } diff --git a/client/checkout/constants.js b/client/checkout/constants.js index 4f48eae96fd..e2e4c6dfe93 100644 --- a/client/checkout/constants.js +++ b/client/checkout/constants.js @@ -35,42 +35,22 @@ export function getPaymentMethodsConstants() { ]; } -export const BLOCKS_SHIPPING_ADDRESS_FIELDS = { - line1: 'shipping-address_1', - line2: 'shipping-address_2', - city: 'shipping-city', - state: 'components-form-token-input-1', - postal_code: 'shipping-postcode', - country: 'components-form-token-input-0', - first_name: 'shipping-first_name', - last_name: 'shipping-last_name', -}; -export const BLOCKS_BILLING_ADDRESS_FIELDS = { - line1: 'billing-address_1', - line2: 'billing-address_2', - city: 'billing-city', - state: 'components-form-token-input-3', - postal_code: 'billing-postcode', - country: 'components-form-token-input-2', - first_name: 'billing-first_name', - last_name: 'billing-last_name', -}; export const SHORTCODE_SHIPPING_ADDRESS_FIELDS = { - line1: 'shipping_address_1', - line2: 'shipping_address_2', + address_1: 'shipping_address_1', + address_2: 'shipping_address_2', city: 'shipping_city', state: 'shipping_state', - postal_code: 'shipping_postcode', + postcode: 'shipping_postcode', country: 'shipping_country', first_name: 'shipping_first_name', last_name: 'shipping_last_name', }; export const SHORTCODE_BILLING_ADDRESS_FIELDS = { - line1: 'billing_address_1', - line2: 'billing_address_2', + address_1: 'billing_address_1', + address_2: 'billing_address_2', city: 'billing_city', state: 'billing_state', - postal_code: 'billing_postcode', + postcode: 'billing_postcode', country: 'billing_country', first_name: 'billing_first_name', last_name: 'billing_last_name', diff --git a/client/checkout/stripe-link/index.js b/client/checkout/stripe-link/index.js index 08ba006f814..fa36d290c4a 100644 --- a/client/checkout/stripe-link/index.js +++ b/client/checkout/stripe-link/index.js @@ -1,133 +1,45 @@ -const showLinkButton = ( linkAutofill ) => { - // Display StripeLink button if email field is prefilled. - const billingEmailInput = document.getElementById( 'billing_email' ); - if ( billingEmailInput.value !== '' ) { - const linkButtonTop = - billingEmailInput.offsetTop + - ( billingEmailInput.offsetHeight - 40 ) / 2; - const stripeLinkButton = document.querySelector( - '.wcpay-stripelink-modal-trigger' - ); - stripeLinkButton.style.display = 'block'; - stripeLinkButton.style.top = `${ linkButtonTop }px`; - } - - // Handle StripeLink button click. - const stripeLinkButton = document.querySelector( - '.wcpay-stripelink-modal-trigger' - ); - stripeLinkButton.addEventListener( 'click', ( event ) => { - event.preventDefault(); - // Trigger modal. - linkAutofill.launch( { email: billingEmailInput.value } ); - } ); -}; - -export const autofill = ( event, options ) => { - const { billingAddress, shippingAddress } = event.value; - const fillWith = options.fill_field_method - ? options.fill_field_method - : ( address, nodeId, key ) => { - if ( document.getElementById( nodeId ) !== null ) { - document.getElementById( nodeId ).value = - address.address[ key ]; - } - }; - - if ( options.complete_shipping() ) { - const shippingNames = shippingAddress.name.split( / (.*)/s, 2 ); - shippingAddress.address.last_name = shippingNames[ 1 ]; - shippingAddress.address.first_name = shippingNames[ 0 ]; - - fillWith( shippingAddress, options.shipping_fields.line1, 'line1' ); - fillWith( shippingAddress, options.shipping_fields.line2, 'line2' ); - fillWith( shippingAddress, options.shipping_fields.city, 'city' ); - fillWith( shippingAddress, options.shipping_fields.country, 'country' ); - fillWith( - shippingAddress, - options.shipping_fields.first_name, - 'first_name' - ); - fillWith( - shippingAddress, - options.shipping_fields.last_name, - 'last_name' - ); - const billingCountryStateSelects = document.querySelectorAll( - '#billing_country, #billing_state, #shipping_country, #shipping_state' - ); - billingCountryStateSelects.forEach( ( select ) => - select.dispatchEvent( new Event( 'change' ) ) - ); - fillWith( shippingAddress, options.shipping_fields.state, 'state' ); - fillWith( - shippingAddress, - options.shipping_fields.postal_code, - 'postal_code' - ); - } - - if ( options.complete_billing() ) { - const billingNames = billingAddress.name.split( / (.*)/s, 2 ); - billingAddress.address.last_name = billingNames[ 1 ]; - billingAddress.address.first_name = billingNames[ 0 ]; - - fillWith( billingAddress, options.billing_fields.line1, 'line1' ); - fillWith( billingAddress, options.billing_fields.line2, 'line2' ); - fillWith( billingAddress, options.billing_fields.city, 'city' ); - fillWith( billingAddress, options.billing_fields.country, 'country' ); - fillWith( - billingAddress, - options.billing_fields.first_name, - 'first_name' - ); - fillWith( - billingAddress, - options.billing_fields.last_name, - 'last_name' - ); - - const billingCountryStateSelects = document.querySelectorAll( - '#billing_country, #billing_state, #shipping_country, #shipping_state' - ); - billingCountryStateSelects.forEach( ( select ) => - select.dispatchEvent( new Event( 'change' ) ) - ); - fillWith( billingAddress, options.billing_fields.state, 'state' ); - fillWith( - billingAddress, - options.billing_fields.postal_code, - 'postal_code' - ); - } - const billingCountryStateSelects = document.querySelectorAll( - '#billing_country, #billing_state, #shipping_country, #shipping_state' - ); - billingCountryStateSelects.forEach( ( select ) => - select.dispatchEvent( new Event( 'change' ) ) - ); +const transformStripeLinkAddress = ( address ) => { + // when clicking "use another address" or "use another payment method", the returned value for shipping/billing might be `null`. + if ( ! address ) return null; + + const [ firstName, lastName ] = address.name.split( / (.*)/s, 2 ); + return { + first_name: firstName || '', + last_name: lastName || '', + address_1: address.address.line1 || '', + address_2: address.address.line2 || '', + city: address.address.city || '', + country: address.address.country || '', + postcode: address.address.postal_code || '', + state: address.address.state || '', + // missing fields from Stripe autofill: phone, company + }; }; const enableStripeLinkPaymentMethod = ( options ) => { - if ( ! document.getElementById( options.emailId ) ) { + const emailField = document.getElementById( options.emailId ); + + if ( ! emailField ) { return; } - const api = options.api; - const linkAutofill = api.getStripe().linkAutofillModal( options.elements ); - document - .getElementById( options.emailId ) - .addEventListener( 'keyup', ( event ) => { - linkAutofill.launch( { email: event.target.value } ); - } ); + // https://stripe.com/docs/payments/link/autofill-modal + const linkAutofill = options.api + .getStripe() + .linkAutofillModal( options.elements ); - const showButton = options.show_button - ? options.show_button - : showLinkButton; - showButton( linkAutofill ); + emailField.addEventListener( 'keyup', ( event ) => { + linkAutofill.launch( { email: event.target.value } ); + } ); + + options.onButtonShow( linkAutofill ); linkAutofill.on( 'autofill', ( event ) => { - autofill( event, options ); + const { billingAddress, shippingAddress } = event.value; + options.onAutofill( + transformStripeLinkAddress( billingAddress ), + transformStripeLinkAddress( shippingAddress ) + ); } ); }; diff --git a/client/checkout/stripe-link/test/index.test.js b/client/checkout/stripe-link/test/index.test.js index 4440a4df7c2..28f2cc10669 100644 --- a/client/checkout/stripe-link/test/index.test.js +++ b/client/checkout/stripe-link/test/index.test.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import enableStripeLinkPaymentMethod, { autofill } from '..'; +import enableStripeLinkPaymentMethod from '..'; import WCPayAPI from 'wcpay/checkout/api'; jest.mock( 'wcpay/checkout/api', () => { @@ -45,6 +45,8 @@ describe( 'Stripe Link elements behavior', () => { enableStripeLinkPaymentMethod( { api: WCPayAPI(), emailId: 'billing_email', + onAutofill: () => null, + onButtonShow: () => null, } ); expect( WCPayAPI().getStripe().linkAutofillModal ).toHaveBeenCalled(); } ); @@ -60,6 +62,8 @@ describe( 'Stripe Link elements behavior', () => { enableStripeLinkPaymentMethod( { api: WCPayAPI(), emailId: 'billing_email', + onAutofill: () => null, + onButtonShow: () => null, } ); billingEmailInput.dispatchEvent( new Event( 'keyup' ) ); @@ -72,74 +76,17 @@ describe( 'Stripe Link elements behavior', () => { ).toHaveBeenCalledWith( { email: billingEmail } ); } ); - test( 'Stripe Link button should be visible and clickable', () => { + test( 'Stripe Link button should call onButtonShow configuration value', () => { createStripeLinkElements(); - const stripeLinkButton = document.getElementsByClassName( - 'wcpay-stripelink-modal-trigger' - )[ 0 ]; - const addEventListenerSpy = jest.spyOn( - stripeLinkButton, - 'addEventListener' - ); - + const handleButtonShow = jest.fn(); enableStripeLinkPaymentMethod( { api: WCPayAPI(), emailId: 'billing_email', + onAutofill: () => null, + onButtonShow: handleButtonShow, } ); - expect( stripeLinkButton.style.display ).toBe( 'block' ); - expect( stripeLinkButton.style.top ).not.toBe( '' ); - - stripeLinkButton.click(); - expect( addEventListenerSpy ).toHaveBeenCalledWith( - 'click', - expect.any( Function ) - ); - expect( - WCPayAPI().getStripe().linkAutofillModal().launch - ).toHaveBeenCalledWith( { email: billingEmail } ); - } ); - - test( 'Custom fill function should be called', () => { - const customFillFunction = jest.fn(); - autofill( - { - value: { - billingAddress: '123 Main St', - shippingAddress: { - name: 'First Last', - address: { - line1: '123 Main St', - line2: 'shipping', - state: 'AK', - country: 'US', - city: 'San Francisco', - postal_code: '94110', - }, - }, - }, - }, - { - fill_field_method: customFillFunction, - complete_shipping: () => { - return true; - }, - complete_billing: () => { - return false; - }, - shipping_fields: { - line1: 'shipping_address_1', - line2: 'shipping_address_2', - city: 'shipping_city', - state: 'shipping_state', - postal_code: 'shipping_postcode', - country: 'shipping_country', - first_name: 'shipping_first_name', - last_name: 'shipping_last_name', - }, - } - ); - expect( customFillFunction ).toHaveBeenCalled(); + expect( handleButtonShow ).toHaveBeenCalled(); } ); function createStripeLinkElements() { @@ -162,330 +109,3 @@ describe( 'Stripe Link elements behavior', () => { document.body.appendChild( stripeLinkButton ); } } ); - -describe( 'Autofilling billing fields', () => { - beforeEach( () => { - createEmptyBillingFields(); - } ); - - afterEach( () => { - resetBillingFields(); - } ); - - test( 'Should fill the billing fields when complete_billing is true', () => { - autofill( - { - value: { - billingAddress: { - name: 'First Last', - address: { - line1: '123 Main St', - line2: 'shipping', - state: 'AK', - country: 'US', - city: 'San Francisco', - postal_code: '94110', - }, - }, - }, - }, - { - complete_shipping: () => { - return false; - }, - complete_billing: () => { - return true; - }, - billing_fields: { - line1: 'billing_address_1', - line2: 'billing_address_2', - city: 'billing_city', - state: 'billing_state', - postal_code: 'billing_postcode', - country: 'billing_country', - first_name: 'billing_first_name', - last_name: 'billing_last_name', - }, - } - ); - - expect( document.getElementById( 'billing_first_name' ).value ).toBe( - 'First' - ); - expect( document.getElementById( 'billing_last_name' ).value ).toBe( - 'Last' - ); - expect( document.getElementById( 'billing_address_1' ).value ).toBe( - '123 Main St' - ); - expect( document.getElementById( 'billing_address_2' ).value ).toBe( - 'shipping' - ); - expect( document.getElementById( 'billing_city' ).value ).toBe( - 'San Francisco' - ); - expect( document.getElementById( 'billing_state' ).value ).toBe( 'AK' ); - expect( document.getElementById( 'billing_postcode' ).value ).toBe( - '94110' - ); - expect( document.getElementById( 'billing_country' ).value ).toBe( - 'US' - ); - } ); - - test( 'Should not fill the billing fields when complete_billing is false', () => { - autofill( - { - value: {}, - }, - { - complete_shipping: () => { - return false; - }, - complete_billing: () => { - return false; - }, - } - ); - - expect( document.getElementById( 'billing_first_name' ).value ).toBe( - '' - ); - expect( document.getElementById( 'billing_last_name' ).value ).toBe( - '' - ); - expect( document.getElementById( 'billing_address_1' ).value ).toBe( - '' - ); - expect( document.getElementById( 'billing_address_2' ).value ).toBe( - '' - ); - expect( document.getElementById( 'billing_city' ).value ).toBe( '' ); - expect( document.getElementById( 'billing_state' ).value ).toBe( '' ); - expect( document.getElementById( 'billing_postcode' ).value ).toBe( - '' - ); - expect( document.getElementById( 'billing_country' ).value ).toBe( '' ); - } ); - - function createEmptyBillingFields() { - const firstName = document.createElement( 'input' ); - firstName.setAttribute( 'id', 'billing_first_name' ); - - const lastName = document.createElement( 'input' ); - lastName.setAttribute( 'id', 'billing_last_name' ); - - const address1 = document.createElement( 'input' ); - address1.setAttribute( 'id', 'billing_address_1' ); - - const address2 = document.createElement( 'input' ); - address2.setAttribute( 'id', 'billing_address_2' ); - - const city = document.createElement( 'input' ); - city.setAttribute( 'id', 'billing_city' ); - - const state = document.createElement( 'input' ); - state.setAttribute( 'id', 'billing_state' ); - - const postcode = document.createElement( 'input' ); - postcode.setAttribute( 'id', 'billing_postcode' ); - - const country = document.createElement( 'input' ); - country.setAttribute( 'id', 'billing_country' ); - - document.body.appendChild( firstName ); - document.body.appendChild( lastName ); - document.body.appendChild( address1 ); - document.body.appendChild( address2 ); - document.body.appendChild( city ); - document.body.appendChild( state ); - document.body.appendChild( postcode ); - document.body.appendChild( country ); - } - - function resetBillingFields() { - const firstName = document.querySelector( '#billing_first_name' ); - const lastName = document.querySelector( '#billing_last_name' ); - const address1 = document.querySelector( '#billing_address_1' ); - const address2 = document.querySelector( '#billing_address_2' ); - const city = document.querySelector( '#billing_city' ); - const state = document.querySelector( '#billing_state' ); - const postcode = document.querySelector( '#billing_postcode' ); - const country = document.querySelector( '#billing_country' ); - - firstName.value = ''; - lastName.value = ''; - address1.value = ''; - address2.value = ''; - city.value = ''; - state.value = ''; - postcode.value = ''; - country.value = ''; - } -} ); - -describe( 'Autofilling shipping fields', () => { - beforeEach( () => { - createEmptyShippingFields(); - } ); - - afterEach( () => { - resetShippingFields(); - } ); - - test( 'Should fill the shipping fields when complete_shipping is true', () => { - autofill( - { - value: { - billingAddress: '123 Main St', - shippingAddress: { - name: 'First Last', - address: { - line1: '123 Main St', - line2: 'shipping', - state: 'AK', - country: 'US', - city: 'San Francisco', - postal_code: '94110', - }, - }, - }, - }, - { - complete_shipping: () => { - return true; - }, - complete_billing: () => { - return false; - }, - shipping_fields: { - line1: 'shipping_address_1', - line2: 'shipping_address_2', - city: 'shipping_city', - state: 'shipping_state', - postal_code: 'shipping_postcode', - country: 'shipping_country', - first_name: 'shipping_first_name', - last_name: 'shipping_last_name', - }, - } - ); - - expect( document.getElementById( 'shipping_first_name' ).value ).toBe( - 'First' - ); - expect( document.getElementById( 'shipping_last_name' ).value ).toBe( - 'Last' - ); - expect( document.getElementById( 'shipping_address_1' ).value ).toBe( - '123 Main St' - ); - expect( document.getElementById( 'shipping_address_2' ).value ).toBe( - 'shipping' - ); - expect( document.getElementById( 'shipping_city' ).value ).toBe( - 'San Francisco' - ); - expect( document.getElementById( 'shipping_state' ).value ).toBe( - 'AK' - ); - expect( document.getElementById( 'shipping_postcode' ).value ).toBe( - '94110' - ); - expect( document.getElementById( 'shipping_country' ).value ).toBe( - 'US' - ); - } ); - - test( 'Should not fill the shipping fields when complete_shipping is false', () => { - autofill( - { - value: {}, - }, - { - complete_shipping: () => { - return false; - }, - complete_billing: () => { - return false; - }, - } - ); - - expect( document.getElementById( 'shipping_first_name' ).value ).toBe( - '' - ); - expect( document.getElementById( 'shipping_last_name' ).value ).toBe( - '' - ); - expect( document.getElementById( 'shipping_address_1' ).value ).toBe( - '' - ); - expect( document.getElementById( 'shipping_address_2' ).value ).toBe( - '' - ); - expect( document.getElementById( 'shipping_city' ).value ).toBe( '' ); - expect( document.getElementById( 'shipping_state' ).value ).toBe( '' ); - expect( document.getElementById( 'shipping_postcode' ).value ).toBe( - '' - ); - expect( document.getElementById( 'shipping_country' ).value ).toBe( - '' - ); - } ); - - function createEmptyShippingFields() { - const firstName = document.createElement( 'input' ); - firstName.setAttribute( 'id', 'shipping_first_name' ); - - const lastName = document.createElement( 'input' ); - lastName.setAttribute( 'id', 'shipping_last_name' ); - - const address1 = document.createElement( 'input' ); - address1.setAttribute( 'id', 'shipping_address_1' ); - - const address2 = document.createElement( 'input' ); - address2.setAttribute( 'id', 'shipping_address_2' ); - - const city = document.createElement( 'input' ); - city.setAttribute( 'id', 'shipping_city' ); - - const state = document.createElement( 'input' ); - state.setAttribute( 'id', 'shipping_state' ); - - const postcode = document.createElement( 'input' ); - postcode.setAttribute( 'id', 'shipping_postcode' ); - - const country = document.createElement( 'input' ); - country.setAttribute( 'id', 'shipping_country' ); - - document.body.appendChild( firstName ); - document.body.appendChild( lastName ); - document.body.appendChild( address1 ); - document.body.appendChild( address2 ); - document.body.appendChild( city ); - document.body.appendChild( state ); - document.body.appendChild( postcode ); - document.body.appendChild( country ); - } - - function resetShippingFields() { - const firstName = document.querySelector( '#shipping_first_name' ); - const lastName = document.querySelector( '#shipping_last_name' ); - const address1 = document.querySelector( '#shipping_address_1' ); - const address2 = document.querySelector( '#shipping_address_2' ); - const city = document.querySelector( '#shipping_city' ); - const state = document.querySelector( '#shipping_state' ); - const postcode = document.querySelector( '#shipping_postcode' ); - const country = document.querySelector( '#shipping_country' ); - - firstName.value = ''; - lastName.value = ''; - address1.value = ''; - address2.value = ''; - city.value = ''; - state.value = ''; - postcode.value = ''; - country.value = ''; - } -} ); diff --git a/client/checkout/utils/upe.js b/client/checkout/utils/upe.js index 7e1029d76e9..98f4656e23c 100644 --- a/client/checkout/utils/upe.js +++ b/client/checkout/utils/upe.js @@ -200,13 +200,9 @@ export function isUsingSavedPaymentMethod( paymentMethodType ) { * @return {Object} An object containing customer data and functions for managing customer information. */ export const useCustomerData = () => { - const { customerData, isInitialized } = useSelect( ( select ) => { - const store = select( WC_STORE_CART ); - return { - customerData: store.getCustomerData(), - isInitialized: store.hasFinishedResolution( 'getCartData' ), - }; - } ); + const customerData = useSelect( ( select ) => + select( WC_STORE_CART ).getCustomerData() + ); const { setShippingAddress, setBillingData, @@ -214,14 +210,10 @@ export const useCustomerData = () => { } = useDispatch( WC_STORE_CART ); return { - isInitialized, - billingData: customerData.billingData, // Backward compatibility billingData/billingAddress - billingAddress: customerData.billingAddress, - shippingAddress: customerData.shippingAddress, - setBillingData, + billingAddress: customerData.billingAddress || customerData.billingData, // Backward compatibility setBillingData/setBillingAddress - setBillingAddress, + setBillingAddress: setBillingAddress || setBillingData, setShippingAddress, }; }; From 5c25d7fad2a83271c2922eaa58bc35918fc7b297 Mon Sep 17 00:00:00 2001 From: Jesse Pearson Date: Wed, 17 Jan 2024 17:21:46 -0400 Subject: [PATCH 35/60] Revert "Displaying Clearpay instead of Afterpay for UK based stores" (#8034) --- assets/images/payment-methods/afterpay.svg | 5 ++ assets/images/payment-methods/clearpay.svg | 4 -- changelog/afterpay-clearpay | 4 -- .../connect-account-page/payment-methods.tsx | 7 +-- client/payment-methods-icons.tsx | 5 -- client/payment-methods-map.tsx | 42 +++------------- includes/class-wc-payment-gateway-wcpay.php | 9 ++-- includes/class-wc-payments-checkout.php | 5 +- includes/class-wc-payments.php | 4 +- .../PaymentMethodsCompatibility.php | 2 +- .../class-afterpay-payment-method.php | 29 ----------- .../class-cc-payment-method.php | 6 +-- .../class-upe-payment-method.php | 8 ++- ...st-class-payment-methods-compatibility.php | 2 - .../test-class-upe-payment-gateway.php | 49 +++++++++---------- .../test-class-upe-split-payment-gateway.php | 38 +++++++------- .../unit/test-class-wc-payments-checkout.php | 3 -- 17 files changed, 71 insertions(+), 151 deletions(-) delete mode 100644 assets/images/payment-methods/clearpay.svg delete mode 100644 changelog/afterpay-clearpay diff --git a/assets/images/payment-methods/afterpay.svg b/assets/images/payment-methods/afterpay.svg index 3795553025f..a769af42cdd 100644 --- a/assets/images/payment-methods/afterpay.svg +++ b/assets/images/payment-methods/afterpay.svg @@ -1,5 +1,9 @@ + + + + @@ -8,4 +12,5 @@ + diff --git a/assets/images/payment-methods/clearpay.svg b/assets/images/payment-methods/clearpay.svg deleted file mode 100644 index bce4db33418..00000000000 --- a/assets/images/payment-methods/clearpay.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/changelog/afterpay-clearpay b/changelog/afterpay-clearpay deleted file mode 100644 index 23a06913442..00000000000 --- a/changelog/afterpay-clearpay +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Displaying Clearpay instead of Afterpay for UK based stores diff --git a/client/connect-account-page/payment-methods.tsx b/client/connect-account-page/payment-methods.tsx index 1930ed10616..9add778d558 100644 --- a/client/connect-account-page/payment-methods.tsx +++ b/client/connect-account-page/payment-methods.tsx @@ -12,7 +12,6 @@ import './style.scss'; import { AffirmIcon, AfterpayIcon, - ClearpayIcon, AmericanExpressIcon, ApplePayIcon, DinersClubIcon, @@ -39,11 +38,7 @@ const PaymentMethods: React.FC = () => { - { 'GB' === wcpaySettings?.connect?.country ? ( - - ) : ( - - ) } + & more. diff --git a/client/payment-methods-icons.tsx b/client/payment-methods-icons.tsx index bc29d2518f7..1cad55b62f2 100644 --- a/client/payment-methods-icons.tsx +++ b/client/payment-methods-icons.tsx @@ -18,7 +18,6 @@ import IdealAsset from 'assets/images/payment-methods/ideal.svg?asset'; import BankDebitAsset from 'assets/images/payment-methods/bank-debit.svg?asset'; import AffirmAsset from 'assets/images/payment-methods/affirm.svg?asset'; import AfterpayAsset from 'assets/images/payment-methods/afterpay.svg?asset'; -import ClearpayAsset from 'assets/images/payment-methods/clearpay.svg?asset'; import JCBAsset from 'assets/images/payment-methods/jcb.svg?asset'; import KlarnaAsset from 'assets/images/payment-methods/klarna.svg?asset'; import VisaAsset from 'assets/images/cards/visa.svg?asset'; @@ -58,10 +57,6 @@ export const AfterpayIcon = iconComponent( AfterpayAsset, __( 'Afterpay', 'woocommerce-payments' ) ); -export const ClearpayIcon = iconComponent( - ClearpayAsset, - __( 'Clearpay', 'woocommerce-payments' ) -); export const AmericanExpressIcon = iconComponent( AmexAsset, __( 'American Express', 'woocommerce-payments' ) diff --git a/client/payment-methods-map.tsx b/client/payment-methods-map.tsx index be758dd10ad..d0a17f282ea 100644 --- a/client/payment-methods-map.tsx +++ b/client/payment-methods-map.tsx @@ -10,7 +10,6 @@ import { __ } from '@wordpress/i18n'; import { AffirmIcon, AfterpayIcon, - ClearpayIcon, BancontactIcon, BankDebitIcon, CreditCardIcon, @@ -24,18 +23,6 @@ import { SofortIcon, } from 'wcpay/payment-methods-icons'; -declare global { - interface Window { - wcpaySettings: { - accountStatus: { - country: string; - }; - }; - } -} - -const accountCountry = window.wcpaySettings?.accountStatus?.country || 'US'; - export interface PaymentMethodMapEntry { id: string; label: string; @@ -221,29 +208,16 @@ const PaymentMethodInformationObject: Record< }, afterpay_clearpay: { id: 'afterpay_clearpay', - label: - 'GB' === accountCountry - ? __( 'Clearpay', 'woocommerce-payments' ) - : __( 'Afterpay', 'woocommerce-payments' ), + label: __( 'Afterpay', 'woocommerce-payments' ), brandTitles: { - afterpay_clearpay: - 'GB' === accountCountry - ? __( 'Clearpay', 'woocommerce-payments' ) - : __( 'Afterpay', 'woocommerce-payments' ), + afterpay_clearpay: __( 'Afterpay', 'woocommerce-payments' ), }, - description: - 'GB' === accountCountry - ? __( - // translators: %s is the store currency. - 'Allow customers to pay over time with Clearpay. Available to all customers paying in %s.', - 'woocommerce-payments' - ) - : __( - // translators: %s is the store currency. - 'Allow customers to pay over time with Afterpay. Available to all customers paying in %s.', - 'woocommerce-payments' - ), - icon: 'GB' === accountCountry ? ClearpayIcon : AfterpayIcon, + description: __( + // translators: %s is the store currency. + 'Allow customers to pay over time with Afterpay. Available to all customers paying in %s.', + 'woocommerce-payments' + ), + icon: AfterpayIcon, currencies: [ 'USD', 'AUD', 'CAD', 'NZD', 'GBP', 'EUR' ], stripe_key: 'afterpay_clearpay_payments', allows_manual_capture: false, diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index c69ef8782e3..d6594de86bd 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -267,14 +267,13 @@ public function __construct( $this->localization_service = $localization_service; $this->fraud_service = $fraud_service; - $account_country = $this->get_account_country(); $this->id = static::GATEWAY_ID; - $this->icon = $payment_method->get_icon( $account_country ); + $this->icon = $payment_method->get_icon(); $this->has_fields = true; $this->method_title = 'WooPayments'; $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 = $payment_method->get_title( $account_country ); + $this->title = $payment_method->get_title(); $this->description = ''; $this->supports = [ 'products', @@ -2053,7 +2052,7 @@ public function set_payment_method_title_for_order( $order, $payment_method_type return; } - $payment_method_title = $payment_method->get_title( $this->get_account_country(), $payment_method_details ); + $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; @@ -2878,7 +2877,7 @@ protected function get_deposit_delay_days( int $default_value = 7 ): int { * * @return string code of the country. */ - public function get_account_country( string $default_value = 'US' ): string { + protected function get_account_country( string $default_value = 'US' ): string { try { if ( $this->is_connected() ) { return $this->account->get_account_country() ?? $default_value; diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php index 5ba354b3810..98a647b5bff 100644 --- a/includes/class-wc-payments-checkout.php +++ b/includes/class-wc-payments-checkout.php @@ -295,11 +295,10 @@ public function get_enabled_payment_method_config() { } $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id ); - $account_country = $this->account->get_account_country(); $settings[ $payment_method_id ] = [ 'isReusable' => $payment_method->is_reusable(), - 'title' => $payment_method->get_title( $account_country ), - 'icon' => $payment_method->get_icon( $account_country ), + 'title' => $payment_method->get_title(), + 'icon' => $payment_method->get_icon(), 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ), 'countries' => $payment_method->get_countries(), ]; diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index 18bd6b4f77d..cad21f86d9e 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -293,8 +293,6 @@ public static function init() { include_once __DIR__ . '/class-wc-payments-utils.php'; include_once __DIR__ . '/core/class-mode.php'; - self::$mode = new Mode(); - include_once __DIR__ . '/class-database-cache.php'; self::$database_cache = new Database_Cache(); self::$database_cache->init_hooks(); @@ -540,6 +538,8 @@ public static function init() { self::$card_gateway->init_hooks(); self::$wc_payments_checkout->init_hooks(); + self::$mode = new Mode(); + self::$webhook_processing_service = new WC_Payments_Webhook_Processing_Service( self::$api_client, self::$db_helper, self::$account, self::$remote_note_service, self::$order_service, self::$in_person_payments_receipts_service, self::get_gateway(), self::$customer_service, self::$database_cache ); self::$webhook_reliability_service = new WC_Payments_Webhook_Reliability_Service( self::$api_client, self::$action_scheduler_service, self::$webhook_processing_service ); diff --git a/includes/multi-currency/PaymentMethodsCompatibility.php b/includes/multi-currency/PaymentMethodsCompatibility.php index 7f48df769d5..8f4f0f88e8b 100644 --- a/includes/multi-currency/PaymentMethodsCompatibility.php +++ b/includes/multi-currency/PaymentMethodsCompatibility.php @@ -82,7 +82,7 @@ function ( $result, $method ) { $result[ $method ] = [ 'currencies' => $payment_method_instance->get_currencies(), - 'title' => $payment_method_instance->get_title( $this->gateway->get_account_country() ), + 'title' => $payment_method_instance->get_title(), ]; return $result; diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php index 9bf7a0c3359..628ca444075 100644 --- a/includes/payment-methods/class-afterpay-payment-method.php +++ b/includes/payment-methods/class-afterpay-payment-method.php @@ -64,35 +64,6 @@ public function __construct( $token_service ) { ]; } - /** - * Returns payment method title. - * - * @param string $account_country Country of merchants account. - * @param array|false $payment_details Optional payment details from charge object. - * @return string|null - */ - public function get_title( string $account_country, $payment_details = false ) { - if ( 'GB' === $account_country ) { - return __( 'Clearpay', 'woocommerce-payments' ); - } - - return __( 'Afterpay', 'woocommerce-payments' ); - } - - /** - * Returns payment method icon. - * - * @param string $account_country Country of merchants account. - * @return string|null - */ - public function get_icon( string $account_country ) { - if ( 'GB' === $account_country ) { - return plugins_url( 'assets/images/payment-methods/clearpay.svg', WCPAY_PLUGIN_FILE ); - } - - return plugins_url( 'assets/images/payment-methods/afterpay.svg', WCPAY_PLUGIN_FILE ); - } - /** * Returns testing credentials to be printed at checkout in test mode. * diff --git a/includes/payment-methods/class-cc-payment-method.php b/includes/payment-methods/class-cc-payment-method.php index 4edb7b535f8..dfd20c3eaf6 100644 --- a/includes/payment-methods/class-cc-payment-method.php +++ b/includes/payment-methods/class-cc-payment-method.php @@ -33,11 +33,11 @@ public function __construct( $token_service ) { /** * Returns payment method title * - * @param string $account_country Account country. - * @param array|false $payment_details Payment details. + * @param array|bool $payment_details Optional payment details from charge object. + * * @return string */ - public function get_title( string $account_country, $payment_details = false ) { + public function get_title( $payment_details = false ) { if ( ! $payment_details ) { return $this->title; } diff --git a/includes/payment-methods/class-upe-payment-method.php b/includes/payment-methods/class-upe-payment-method.php index 3672048b118..ddc954e719f 100644 --- a/includes/payment-methods/class-upe-payment-method.php +++ b/includes/payment-methods/class-upe-payment-method.php @@ -113,12 +113,11 @@ public function get_id() { /** * Returns payment method title * - * @param string $account_country Country of merchants account. - * @param array|false $payment_details Optional payment details from charge object. + * @param array|bool $payment_details Optional payment details from charge object. * * @return string */ - public function get_title( string $account_country, $payment_details = false ) { + public function get_title( $payment_details = false ) { return $this->title; } @@ -225,10 +224,9 @@ abstract public function get_testing_instructions(); /** * Returns the payment method icon URL or an empty string. * - * @param string $account_country Optional account country. * @return string */ - public function get_icon( string $account_country ) { + public function get_icon() { return isset( $this->icon_url ) ? $this->icon_url : ''; } diff --git a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php index 7a6e910db46..6a0f24eeba8 100644 --- a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php +++ b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php @@ -54,11 +54,9 @@ public function set_up() { ->setMethods( [ 'get_upe_enabled_payment_method_ids', - 'get_account_country', ] ) ->getMock(); - $this->gateway_mock->method( 'get_account_country' )->willReturn( 'US' ); $this->payment_methods_compatibility = new \WCPay\MultiCurrency\PaymentMethodsCompatibility( $this->multi_currency_mock, $this->gateway_mock ); $this->payment_methods_compatibility->init_hooks(); 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 8260f8707b5..7c013e2b858 100644 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php @@ -688,75 +688,72 @@ public function test_payment_methods_show_correct_default_outputs() { $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) ); + $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); + $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); + $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); $this->assertTrue( $card_method->is_reusable() ); $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) ); - $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title() ); + $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $giropay_method->is_reusable() ); $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $p24_method->is_reusable() ); $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title() ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sofort_method->is_reusable() ); $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $bancontact_method->is_reusable() ); $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) ); - $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) ); + $this->assertEquals( 'EPS', $eps_method->get_title() ); + $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $eps_method->is_reusable() ); $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sepa_method->is_reusable() ); $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $ideal_method->is_reusable() ); $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $becs_method->is_reusable() ); $this->assertSame( 'affirm', $affirm_method->get_id() ); - $this->assertSame( 'Affirm', $affirm_method->get_title( 'US' ) ); - $this->assertSame( 'Affirm', $affirm_method->get_title( 'US', $mock_affirm_details ) ); + $this->assertSame( 'Affirm', $affirm_method->get_title() ); + $this->assertSame( 'Affirm', $affirm_method->get_title( $mock_affirm_details ) ); $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $affirm_method->is_reusable() ); $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US' ) ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US', $mock_afterpay_details ) ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title() ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title( $mock_afterpay_details ) ); $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $afterpay_method->is_reusable() ); - $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB' ) ); - $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB', $mock_afterpay_details ) ); - $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'GB' ) ); } public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { 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 fc9446ff775..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 @@ -893,58 +893,58 @@ public function test_payment_methods_show_correct_default_outputs() { $becs_method = $this->mock_payment_methods['au_becs_debit']; $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) ); + $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); + $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); + $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); $this->assertTrue( $card_method->is_reusable() ); $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) ); - $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) ); + $this->assertEquals( 'giropay', $giropay_method->get_title() ); + $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $giropay_method->is_reusable() ); $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $p24_method->is_reusable() ); $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) ); + $this->assertEquals( 'Sofort', $sofort_method->get_title() ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sofort_method->is_reusable() ); $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $bancontact_method->is_reusable() ); $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) ); - $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) ); + $this->assertEquals( 'EPS', $eps_method->get_title() ); + $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $eps_method->is_reusable() ); $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $sepa_method->is_reusable() ); $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $ideal_method->is_reusable() ); $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); $this->assertFalse( $becs_method->is_reusable() ); } diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php index 72a7688187d..d6273a1fcd2 100644 --- a/tests/unit/test-class-wc-payments-checkout.php +++ b/tests/unit/test-class-wc-payments-checkout.php @@ -103,9 +103,6 @@ public function set_up() { ->disableOriginalConstructor() ->getMock(); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_wcpay_account - ->method( 'get_account_country' ) - ->willReturn( 'US' ); $this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class ); $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); From f00749a677180fa17dab671559ac8ba71601d3b3 Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:50:23 +1000 Subject: [PATCH 36/60] =?UTF-8?q?Show=20Payments=20=E2=86=92=20Overview=20?= =?UTF-8?q?waiting=20period=20notice=20for=20new=20accounts=20that=20have?= =?UTF-8?q?=20completed=20one=20or=20more=20transactions=20(#8041)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...fix-8040-new-account-waiting-period-notice | 4 + client/components/deposits-overview/index.tsx | 104 ++++++++++-------- .../components/deposits-overview/style.scss | 6 +- .../deposits-overview/test/index.tsx | 18 ++- 4 files changed, 78 insertions(+), 54 deletions(-) create mode 100644 changelog/fix-8040-new-account-waiting-period-notice diff --git a/changelog/fix-8040-new-account-waiting-period-notice b/changelog/fix-8040-new-account-waiting-period-notice new file mode 100644 index 00000000000..254a87050c8 --- /dev/null +++ b/changelog/fix-8040-new-account-waiting-period-notice @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Reinstate first deposit waiting period notice in payments overview (fix bug) diff --git a/client/components/deposits-overview/index.tsx b/client/components/deposits-overview/index.tsx index 8ab797f4977..e954f7a7ded 100644 --- a/client/components/deposits-overview/index.tsx +++ b/client/components/deposits-overview/index.tsx @@ -57,9 +57,10 @@ const DepositsOverview: React.FC = () => { availableFunds === 0 && pendingFunds > 0; const hasCompletedWaitingPeriod = wcpaySettings.accountStatus.deposits?.completed_waiting_period; + const canChangeDepositSchedule = + ! account?.deposits_blocked && hasCompletedWaitingPeriod; // Only show the deposit history section if the page is finished loading and there are deposits. */ } - const showRecentDeposits = - ! isLoading && deposits?.length > 0 && !! account; + const hasRecentDeposits = ! isLoading && deposits?.length > 0 && !! account; // Show a loading state if the page is still loading. if ( isLoading ) { @@ -88,8 +89,13 @@ const DepositsOverview: React.FC = () => { ); } - // This card isn't shown if there are no deposits, so we can bail early. - if ( ! isLoading && deposits.length === 0 ) { + if ( + ! hasCompletedWaitingPeriod && + availableFunds === 0 && + pendingFunds === 0 + ) { + // If still in new account waiting period and account has no transactions, + // don't render deposits card (nothing to show). return null; } @@ -133,7 +139,7 @@ const DepositsOverview: React.FC = () => { ) } - { showRecentDeposits && ( + { hasRecentDeposits && ( <> @@ -144,50 +150,54 @@ const DepositsOverview: React.FC = () => { ) } - - ) } - - { ! account?.deposits_blocked && ( - - ) } - + { canChangeDepositSchedule && ( + + ) } + + ) } ); }; diff --git a/client/components/deposits-overview/style.scss b/client/components/deposits-overview/style.scss index bfecab9f98c..e3a7e4d16bf 100644 --- a/client/components/deposits-overview/style.scss +++ b/client/components/deposits-overview/style.scss @@ -30,8 +30,12 @@ // so table CardDivider is full width. .components-card__body.wcpay-deposits-overview__table__container, .components-card__body.wcpay-deposits-overview__notices__container { - padding-bottom: 0; padding-top: 0; + + // If the CardFooter is rendered, remove the bottom padding + &:not( :last-child ) { + padding-bottom: 0; + } } // Override display:block on the first FlexItem with the date and icon diff --git a/client/components/deposits-overview/test/index.tsx b/client/components/deposits-overview/test/index.tsx index a4266f813d7..e865a6b8314 100644 --- a/client/components/deposits-overview/test/index.tsx +++ b/client/components/deposits-overview/test/index.tsx @@ -268,7 +268,8 @@ describe( 'Deposits Overview information', () => { expect( container ).toMatchSnapshot(); } ); - test( `Component doesn't render for new account`, () => { + test( `Component doesn't render for new accounts with no pending funds`, () => { + global.wcpaySettings.accountStatus.deposits.completed_waiting_period = false; mockOverviews( [ createMockNewAccountOverview( 'eur' ) ] ); mockDepositOverviews( [ createMockNewAccountOverview( 'eur' ) ] ); mockUseDeposits.mockReturnValue( { @@ -284,7 +285,8 @@ describe( 'Deposits Overview information', () => { expect( container ).toBeEmptyDOMElement(); } ); - test( `Component doesn't render for new accounts with pending funds but no available funds`, () => { + test( `Component renders for new accounts with pending funds but no available funds`, () => { + global.wcpaySettings.accountStatus.deposits.completed_waiting_period = false; mockOverviews( [ createMockNewAccountOverview( 'eur', 5000, 0 ) ] ); mockDepositOverviews( [ createMockNewAccountOverview( 'eur', 5000, 0 ), @@ -298,8 +300,12 @@ describe( 'Deposits Overview information', () => { selectedCurrency: 'eur', setSelectedCurrency: mockSetSelectedCurrency, } ); - const { container } = render( ); - expect( container ).toBeEmptyDOMElement(); + const { getByText, queryByText } = render( ); + getByText( /Your first deposit is held for seven business days/, { + ignore: '.a11y-speak-region', + } ); + expect( queryByText( 'Change deposit schedule' ) ).toBeFalsy(); + expect( queryByText( 'View full deposits history' ) ).toBeFalsy(); } ); test( 'Confirm notice renders if deposits blocked', () => { @@ -402,7 +408,7 @@ describe( 'Deposits Overview information', () => { ).toBeFalsy(); } ); - test( 'Confirm new account waiting period notice does not show', () => { + test( 'Confirm new account waiting period notice does not show if outside waiting period', () => { global.wcpaySettings.accountStatus.deposits.completed_waiting_period = true; const accountOverview = createMockNewAccountOverview( 'eur', @@ -422,7 +428,7 @@ describe( 'Deposits Overview information', () => { ).toBeFalsy(); } ); - test( 'Confirm new account waiting period notice shows', () => { + test( 'Confirm new account waiting period notice shows if within waiting period', () => { global.wcpaySettings.accountStatus.deposits.completed_waiting_period = false; const accountOverview = createMockNewAccountOverview( 'eur', From 3877aef6ec7fcd50fdec4fbbe71562cff90659ad Mon Sep 17 00:00:00 2001 From: Timur Karimov Date: Thu, 18 Jan 2024 10:32:43 +0100 Subject: [PATCH 37/60] Switch to proper input element when using Stripe Link autofill (#8017) Co-authored-by: Timur Karimov Co-authored-by: Guilherme Pressutto --- changelog/align-stripe-link-behavior | 4 +++ client/checkout/blocks/saved-token-handler.js | 5 +++ client/checkout/classic/payment-processing.js | 5 ++- client/checkout/stripe-link/index.js | 25 +++++++++++++ client/checkout/utils/test/upe.test.js | 35 +++++++++++++++++++ client/checkout/utils/upe.js | 5 +++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 changelog/align-stripe-link-behavior diff --git a/changelog/align-stripe-link-behavior b/changelog/align-stripe-link-behavior new file mode 100644 index 00000000000..fbc36a1cb22 --- /dev/null +++ b/changelog/align-stripe-link-behavior @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Select the proper payment element when using saved Stripe Link tokens or choosing to use Stripe Link for new email. diff --git a/client/checkout/blocks/saved-token-handler.js b/client/checkout/blocks/saved-token-handler.js index 0f8d6e42d46..86becd43f88 100644 --- a/client/checkout/blocks/saved-token-handler.js +++ b/client/checkout/blocks/saved-token-handler.js @@ -4,6 +4,7 @@ import { useEffect } from 'react'; import { usePaymentCompleteHandler } from './hooks'; import { useSelect } from '@wordpress/data'; +import { removeLinkButton } from '../stripe-link'; export const SavedTokenHandler = ( { api, @@ -46,5 +47,9 @@ export const SavedTokenHandler = ( { false // No need to save a payment that has already been saved. ); + // Once saved token component is loaded, Stripe Link button should be removed, + // because payment elements are not used then and there's no element to attach the button to. + removeLinkButton(); + return <>; }; diff --git a/client/checkout/classic/payment-processing.js b/client/checkout/classic/payment-processing.js index 713faf5906f..e551d49f80e 100644 --- a/client/checkout/classic/payment-processing.js +++ b/client/checkout/classic/payment-processing.js @@ -16,7 +16,9 @@ import { getUpeSettings, isLinkEnabled, } from 'wcpay/checkout/utils/upe'; -import enableStripeLinkPaymentMethod from 'wcpay/checkout/stripe-link'; +import enableStripeLinkPaymentMethod, { + switchToNewPaymentTokenElement, +} from 'wcpay/checkout/stripe-link'; import { SHORTCODE_SHIPPING_ADDRESS_FIELDS, SHORTCODE_BILLING_ADDRESS_FIELDS, @@ -347,6 +349,7 @@ export function maybeEnableStripeLink( api ) { event.preventDefault(); // Trigger modal. linkAutofill.launch( { email: billingEmailInput.value } ); + switchToNewPaymentTokenElement(); } ); }, } ); diff --git a/client/checkout/stripe-link/index.js b/client/checkout/stripe-link/index.js index fa36d290c4a..9a9c63acf4a 100644 --- a/client/checkout/stripe-link/index.js +++ b/client/checkout/stripe-link/index.js @@ -1,3 +1,27 @@ +/** + * Internal dependencies + */ +import { dispatchChangeEventFor } from '../utils/upe'; + +export const switchToNewPaymentTokenElement = () => { + const newPaymentTokenElement = document.getElementById( + 'wc-woocommerce_payments-payment-token-new' + ); + if ( newPaymentTokenElement && ! newPaymentTokenElement.checked ) { + newPaymentTokenElement.checked = true; + dispatchChangeEventFor( newPaymentTokenElement ); + } +}; + +export const removeLinkButton = () => { + const stripeLinkButton = document.querySelector( + '.wcpay-stripelink-modal-trigger' + ); + if ( stripeLinkButton ) { + stripeLinkButton.remove(); + } +}; + const transformStripeLinkAddress = ( address ) => { // when clicking "use another address" or "use another payment method", the returned value for shipping/billing might be `null`. if ( ! address ) return null; @@ -40,6 +64,7 @@ const enableStripeLinkPaymentMethod = ( options ) => { transformStripeLinkAddress( billingAddress ), transformStripeLinkAddress( shippingAddress ) ); + switchToNewPaymentTokenElement(); } ); }; diff --git a/client/checkout/utils/test/upe.test.js b/client/checkout/utils/test/upe.test.js index c785baa427b..baf8702a83a 100644 --- a/client/checkout/utils/test/upe.test.js +++ b/client/checkout/utils/test/upe.test.js @@ -11,6 +11,7 @@ import { blocksShowLinkButtonHandler, getSelectedUPEGatewayPaymentMethod, isUsingSavedPaymentMethod, + dispatchChangeEventFor, } from '../upe'; import { getPaymentMethodsConstants } from '../../constants'; import { getUPEConfig } from 'wcpay/utils/checkout'; @@ -533,3 +534,37 @@ describe( 'isUsingSavedPaymentMethod', () => { expect( isUsingSavedPaymentMethod( paymentMethodType ) ).toBe( false ); } ); } ); + +describe( 'dispatching change event for element', () => { + it( 'should dispatch a change event with bubbling', () => { + const mockElement = document.createElement( 'input' ); + jest.spyOn( mockElement, 'dispatchEvent' ); + + dispatchChangeEventFor( mockElement ); + + expect( mockElement.dispatchEvent ).toHaveBeenCalledWith( + expect.objectContaining( { + type: 'change', + bubbles: true, + } ) + ); + } ); + + it( 'should throw an error when called with an invalid element', () => { + expect( () => { + dispatchChangeEventFor( null ); + } ).toThrow(); + + expect( () => { + dispatchChangeEventFor( undefined ); + } ).toThrow(); + + expect( () => { + dispatchChangeEventFor( {} ); + } ).toThrow(); + + expect( () => { + dispatchChangeEventFor( 'not-an-element' ); + } ).toThrow(); + } ); +} ); diff --git a/client/checkout/utils/upe.js b/client/checkout/utils/upe.js index 98f4656e23c..87ba0308330 100644 --- a/client/checkout/utils/upe.js +++ b/client/checkout/utils/upe.js @@ -192,6 +192,11 @@ export function isUsingSavedPaymentMethod( paymentMethodType ) { ); } +export function dispatchChangeEventFor( element ) { + const event = new Event( 'change', { bubbles: true } ); + element.dispatchEvent( event ); +} + /** * * Custom React hook that provides customer data and related functions for managing customer information. From 173b56d21e64005abf8695dc4814cd7d8b45c316 Mon Sep 17 00:00:00 2001 From: Anurag Bhandari Date: Thu, 18 Jan 2024 16:08:59 +0530 Subject: [PATCH 38/60] Store balance transaction ID in order metadata (#7945) Co-authored-by: Cvetan Cvetanov Co-authored-by: Naman Malhotra Co-authored-by: Dan Paun <82826872+dpaun1985@users.noreply.github.com> --- ...pdate-7856-add-charge-txn-id-to-order-meta | 4 ++ ...ass-wc-rest-payments-orders-controller.php | 14 +---- includes/class-wc-payment-gateway-wcpay.php | 6 +- includes/class-wc-payments-order-service.php | 57 ++++++++++++++++++- .../class-wc-payments-invoice-service.php | 10 +--- src/Internal/Service/OrderService.php | 18 +++--- ...ass-wc-rest-payments-orders-controller.php | 21 +------ .../helpers/class-wc-helper-intention.php | 10 +++- .../test-class-upe-split-payment-gateway.php | 2 +- .../src/Internal/Service/OrderServiceTest.php | 6 +- ...-payment-gateway-wcpay-process-payment.php | 8 +-- .../test-class-wc-payments-order-service.php | 36 +++++++++--- 12 files changed, 125 insertions(+), 67 deletions(-) create mode 100644 changelog/update-7856-add-charge-txn-id-to-order-meta diff --git a/changelog/update-7856-add-charge-txn-id-to-order-meta b/changelog/update-7856-add-charge-txn-id-to-order-meta new file mode 100644 index 00000000000..38037b5a6d1 --- /dev/null +++ b/changelog/update-7856-add-charge-txn-id-to-order-meta @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Store balance transaction ID in order metadata. diff --git a/includes/admin/class-wc-rest-payments-orders-controller.php b/includes/admin/class-wc-rest-payments-orders-controller.php index a833fc9092f..e23f1ebfcff 100644 --- a/includes/admin/class-wc-rest-payments-orders-controller.php +++ b/includes/admin/class-wc-rest-payments-orders-controller.php @@ -189,19 +189,7 @@ public function capture_terminal_payment( WP_REST_Request $request ) { // Update the order: set the payment method and attach intent attributes. $order->set_payment_method( WC_Payment_Gateway_WCPay::GATEWAY_ID ); $order->set_payment_method_title( __( 'WooCommerce In-Person Payments', 'woocommerce-payments' ) ); - $intent_id = $intent->get_id(); - $intent_status = $intent->get_status(); - $charge = $intent->get_charge(); - $charge_id = $charge ? $charge->get_id() : null; - $this->order_service->attach_intent_info_to_order( - $order, - $intent_id, - $intent_status, - $intent->get_payment_method_id(), - $intent->get_customer_id(), - $charge_id, - $intent->get_currency() - ); + $this->order_service->attach_intent_info_to_order( $order, $intent ); $this->order_service->update_order_status_from_intent( $order, $intent ); // Certain payments (eg. Interac) are captured on the client-side (mobile app). diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index d6594de86bd..db6ebb6bb45 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -1689,7 +1689,7 @@ public function process_payment_for_order( $cart, $payment_information, $schedul } } - $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method, $customer_id, $charge_id, $currency ); + $this->order_service->attach_intent_info_to_order( $order, $intent ); $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() ); @@ -1884,7 +1884,7 @@ public function process_redirect_payment( $order, $intent_id, $save_payment_meth } } - $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method_id, $customer_id, $charge_id, $currency ); + $this->order_service->attach_intent_info_to_order( $order, $intent ); $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() ); @@ -3425,7 +3425,7 @@ public function update_order_status() { $charge_id = ! empty( $charge ) ? $charge->get_id() : null; $this->attach_exchange_info_to_order( $order, $charge_id ); - $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $intent->get_payment_method_id(), $intent->get_customer_id(), $charge_id, $intent->get_currency() ); + $this->order_service->attach_intent_info_to_order( $order, $intent ); $this->order_service->attach_transaction_fee_to_order( $order, $charge ); } else { // For $0 orders, fetch the Setup Intent instead. diff --git a/includes/class-wc-payments-order-service.php b/includes/class-wc-payments-order-service.php index 04ea3f9cad7..21b549768a7 100644 --- a/includes/class-wc-payments-order-service.php +++ b/includes/class-wc-payments-order-service.php @@ -113,6 +113,13 @@ class WC_Payments_Order_Service { */ const WCPAY_MODE_META_KEY = '_wcpay_mode'; + /** + * Meta key used to store payment transaction Id. + * + * @const string + */ + const WCPAY_PAYMENT_TRANSACTION_ID_META_KEY = '_wcpay_payment_transaction_id'; + /** * Client for making requests to the WooCommerce Payments API * @@ -531,6 +538,23 @@ public function set_charge_id_for_order( $order, $charge_id ) { $order->save_meta_data(); } + /** + * Set the payment metadata for payment transaction id. + * + * @param mixed $order The order. + * @param string $payment_transaction_id The value to be set. + * + * @throws Order_Not_Found_Exception + */ + public function set_payment_transaction_id_for_order( $order, $payment_transaction_id ) { + if ( ! isset( $payment_transaction_id ) || null === $payment_transaction_id ) { + return; + } + $order = $this->get_order( $order ); + $order->update_meta_data( self::WCPAY_PAYMENT_TRANSACTION_ID_META_KEY, $payment_transaction_id ); + $order->save_meta_data(); + } + /** * Get the payment metadata for charge id. * @@ -773,6 +797,35 @@ public function get_fraud_meta_box_type_for_order( $order ) : string { /** * Given the payment intent data, adds it to the given order as metadata and parses any notes that need to be added * + * @param WC_Order $order The order. + * @param WC_Payments_API_Payment_Intention|WC_Payments_API_Setup_Intention $intent The payment or setup intention object. + * + * @throws Order_Not_Found_Exception + */ + public function attach_intent_info_to_order( WC_Order $order, $intent ) { + // We don't want to allow metadata for a successful payment to be disrupted. + if ( Intent_Status::SUCCEEDED === $this->get_intention_status_for_order( $order ) ) { + return; + } + // first, let's prepare all the metadata needed for refunds, required for status change etc. + $intent_id = $intent->get_id(); + $intent_status = $intent->get_status(); + $payment_method = $intent->get_payment_method_id(); + $customer_id = $intent->get_customer_id(); + $currency = $intent instanceof WC_Payments_API_Payment_Intention ? $intent->get_currency() : $order->get_currency(); + $charge = $intent instanceof WC_Payments_API_Payment_Intention ? $intent->get_charge() : null; + $charge_id = $charge ? $charge->get_id() : null; + $payment_transaction = $charge ? $charge->get_balance_transaction() : null; + $payment_transaction_id = $payment_transaction['id'] ?? ''; + // next, save it in order meta. + $this->attach_intent_info_to_order__legacy( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency, $payment_transaction_id ); + } + + /** + * Legacy version of the attach_intent_info_to_order method. + * + * TODO: This method should ultimately be merged with `attach_intent_info_to_order` and then removed. + * * @param WC_Order $order The order. * @param string $intent_id The intent ID. * @param string $intent_status Intent status. @@ -780,10 +833,11 @@ public function get_fraud_meta_box_type_for_order( $order ) : string { * @param string $customer_id Customer ID. * @param string $charge_id Charge ID. * @param string $currency Currency code. + * @param string $payment_transaction_id The transaction ID of the linked charge. * * @throws Order_Not_Found_Exception */ - public function attach_intent_info_to_order( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency ) { + public function attach_intent_info_to_order__legacy( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency, $payment_transaction_id = null ) { // first, let's save all the metadata that needed for refunds, required for status change etc. $order->set_transaction_id( $intent_id ); $this->set_intent_id_for_order( $order, $intent_id ); @@ -792,6 +846,7 @@ public function attach_intent_info_to_order( $order, $intent_id, $intent_status, $this->set_intention_status_for_order( $order, $intent_status ); $this->set_customer_id_for_order( $order, $customer_id ); $this->set_wcpay_intent_currency_for_order( $order, $currency ); + $this->set_payment_transaction_id_for_order( $order, $payment_transaction_id ); $order->save(); } diff --git a/includes/subscriptions/class-wc-payments-invoice-service.php b/includes/subscriptions/class-wc-payments-invoice-service.php index c4d0cd38fb5..2e2b23663d2 100644 --- a/includes/subscriptions/class-wc-payments-invoice-service.php +++ b/includes/subscriptions/class-wc-payments-invoice-service.php @@ -299,15 +299,7 @@ public function get_and_attach_intent_info_to_order( $order, $intent_id ) { $charge = $intent_object->get_charge(); - $this->order_service->attach_intent_info_to_order( - $order, - $intent_id, - $intent_object->get_status(), - $intent_object->get_payment_method_id(), - $intent_object->get_customer_id(), - $charge ? $charge->get_id() : null, - $intent_object->get_currency() - ); + $this->order_service->attach_intent_info_to_order( $order, $intent_object ); } /** diff --git a/src/Internal/Service/OrderService.php b/src/Internal/Service/OrderService.php index 25e962cdadd..57265fcecc9 100644 --- a/src/Internal/Service/OrderService.php +++ b/src/Internal/Service/OrderService.php @@ -186,21 +186,25 @@ public function update_order_from_successful_intent( ) { $order = $this->get_order( $order_id ); - $charge = null; - $charge_id = null; + $charge = null; + $charge_id = null; + $payment_transaction_id = null; if ( $intent instanceof WC_Payments_API_Payment_Intention ) { - $charge = $intent->get_charge(); - $charge_id = $intent->get_charge()->get_id(); + $charge = $intent->get_charge(); + $charge_id = $intent->get_charge()->get_id(); + $payment_transaction = $charge ? $charge->get_balance_transaction() : null; + $payment_transaction_id = $payment_transaction['id'] ?? ''; } - $this->legacy_service->attach_intent_info_to_order( + $this->legacy_service->attach_intent_info_to_order__legacy( $order, $intent->get_id(), $intent->get_status(), $context->get_payment_method()->get_id(), $context->get_customer_id(), $charge_id, - $context->get_currency() + $context->get_currency(), + $payment_transaction_id, ); $this->legacy_service->attach_transaction_fee_to_order( $order, $charge ); @@ -253,7 +257,7 @@ public function update_order_from_intent_that_requires_action( ) { $order = $this->get_order( $order_id ); - $this->legacy_service->attach_intent_info_to_order( + $this->legacy_service->attach_intent_info_to_order__legacy( $order, $intent->get_id(), $intent->get_status(), diff --git a/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php b/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php index 3a76bcba3ea..3d44fc9bfa5 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php @@ -114,12 +114,7 @@ public function test_capture_terminal_payment_success() { ->method( 'attach_intent_info_to_order' ) ->with( $this->isInstanceOf( WC_Order::class ), - $this->mock_intent_id, - Intent_Status::REQUIRES_CAPTURE, - 'pm_mock', - 'cus_mock', - $this->mock_charge_id, - 'USD' + $mock_intent, ); $request = new WP_REST_Request( 'POST' ); @@ -171,12 +166,7 @@ public function test_capture_terminal_payment_succeeded_intent() { ->method( 'attach_intent_info_to_order' ) ->with( $this->isInstanceOf( WC_Order::class ), - $this->mock_intent_id, - Intent_Status::SUCCEEDED, - 'pm_mock', - 'cus_mock', - $this->mock_charge_id, - 'USD' + $mock_intent, ); $this->mock_gateway @@ -236,12 +226,7 @@ public function test_capture_terminal_payment_completed_order() { ->method( 'attach_intent_info_to_order' ) ->with( $this->isInstanceOf( WC_Order::class ), - $this->mock_intent_id, - Intent_Status::SUCCEEDED, - 'pm_mock', - 'cus_mock', - $this->mock_charge_id, - 'USD' + $mock_intent, ); $this->mock_gateway diff --git a/tests/unit/helpers/class-wc-helper-intention.php b/tests/unit/helpers/class-wc-helper-intention.php index 06130bb3b7e..3879db1f32d 100644 --- a/tests/unit/helpers/class-wc-helper-intention.php +++ b/tests/unit/helpers/class-wc-helper-intention.php @@ -38,7 +38,15 @@ public static function create_charge( $data = [] ) { 'amount_captured' => 5000, 'amount_refunded' => 0, 'application_fee_amount' => 0, - 'balance_transaction' => 'txn_mock', + 'balance_transaction' => [ + 'id' => 'txn_mock', + 'amount' => 5000, + 'available_on' => 1703808000, + 'created' => new DateTime( '2022-05-20 19:05:38' ), + 'currency' => 'usd', + 'exchange_rate' => null, + 'fee' => 82, + ], 'billing_details' => [], 'currency' => 'usd', 'dispute' => [], 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 e788e467a14..8671ab35be0 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 @@ -621,7 +621,7 @@ public function test_process_redirect_setup_intent_succeded() { $setup_intent = WC_Helper_Intention::create_setup_intention( [ - 'id' => 'pi_mock', + 'id' => $intent_id, 'client_secret' => $client_secret, 'status' => $intent_status, 'payment_method' => $payment_method_id, diff --git a/tests/unit/src/Internal/Service/OrderServiceTest.php b/tests/unit/src/Internal/Service/OrderServiceTest.php index 63f40cf074f..3faae6b6ccd 100644 --- a/tests/unit/src/Internal/Service/OrderServiceTest.php +++ b/tests/unit/src/Internal/Service/OrderServiceTest.php @@ -332,7 +332,7 @@ public function test_update_order_from_successful_intent( $intent ) { ->willReturn( $mock_charge ); } - // Prepare all parameters for `attach_intent_info_to_order`. + // Prepare all parameters for `attach_intent_info_to_order__legacy`. $intent->expects( $this->once() ) ->method( 'get_id' ) ->willReturn( $intent_id ); @@ -355,7 +355,7 @@ public function test_update_order_from_successful_intent( $intent ) { ->willReturn( 'prod' ); $this->mock_legacy_service->expects( $this->once() ) - ->method( 'attach_intent_info_to_order' ) + ->method( 'attach_intent_info_to_order__legacy' ) ->with( $mock_order, $intent_id, @@ -412,7 +412,7 @@ public function test_update_order_from_intent_that_requires_action() { $mock_intent->expects( $this->once() )->method( 'get_status' )->willReturn( $intent_status ); $this->mock_legacy_service->expects( $this->once() ) - ->method( 'attach_intent_info_to_order' ) + ->method( 'attach_intent_info_to_order__legacy' ) ->with( $mock_order, $intent_id, 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 1ce7132f420..b064ef08f90 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 @@ -304,7 +304,7 @@ public function test_intent_status_success() { $this->mock_order_service ->expects( $this->once() ) ->method( 'attach_intent_info_to_order' ) - ->with( $mock_order, $intent_id, $status, 'pm_mock', $customer_id, $charge_id, 'USD' ); + ->with( $mock_order, $intent ); $this->mock_order_service ->expects( $this->once() ) @@ -471,7 +471,7 @@ public function test_intent_status_requires_capture() { $this->mock_order_service ->expects( $this->once() ) ->method( 'attach_intent_info_to_order' ) - ->with( $mock_order, $intent_id, $status, 'pm_mock', $customer_id, $charge_id, 'USD' ); + ->with( $mock_order, $intent ); // Assert: The Order_Service is called correctly. $this->mock_order_service @@ -919,7 +919,7 @@ public function test_intent_status_requires_action() { $this->mock_order_service ->expects( $this->once() ) ->method( 'attach_intent_info_to_order' ) - ->with( $mock_order, $intent_id, $status, 'pm_mock', $customer_id, $charge_id, 'USD' ); + ->with( $mock_order, $intent ); $this->mock_order_service ->expects( $this->once() ) @@ -1035,7 +1035,7 @@ public function test_setup_intent_status_requires_action() { $this->mock_order_service ->expects( $this->once() ) ->method( 'attach_intent_info_to_order' ) - ->with( $mock_order, $intent_id, $status, 'pm_mock', $customer_id, '', 'USD' ); + ->with( $mock_order, $intent ); // Assert: Order status was not updated. $mock_order diff --git a/tests/unit/test-class-wc-payments-order-service.php b/tests/unit/test-class-wc-payments-order-service.php index 83ea7139ed9..b1d1f030ff0 100644 --- a/tests/unit/test-class-wc-payments-order-service.php +++ b/tests/unit/test-class-wc-payments-order-service.php @@ -1211,18 +1211,40 @@ public function test_get_fraud_meta_box_type() { $this->assertEquals( $fraud_meta_box_type_from_service, $fraud_meta_box_type ); } + public function test_set_payment_transaction_id_for_order() { + $transaction_id = 'txn_mock'; + $this->order_service->set_payment_transaction_id_for_order( $this->order, $transaction_id ); + $this->assertSame( $this->order->get_meta( '_wcpay_payment_transaction_id', true ), $transaction_id ); + } + public function test_attach_intent_info_to_order() { - $intent_id = 'pi_mock'; - $intent_status = 'succeeded'; - $payment_method = 'woocommerce_payments'; - $customer_id = 'cus_12345'; - $charge_id = 'ch_mock'; - $currency = 'USD'; - $this->order_service->attach_intent_info_to_order( $this->order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency ); + $intent_id = 'pi_mock'; + $intent = WC_Helper_Intention::create_intention( [ 'id' => $intent_id ] ); + $this->order_service->attach_intent_info_to_order( $this->order, $intent ); $this->assertEquals( $intent_id, $this->order->get_meta( '_intent_id', true ) ); } + public function test_attach_intent_info_to_order_after_successful_payment() { + $intent = WC_Helper_Intention::create_intention( + [ + 'id' => 'pi_mock', + 'status' => Intent_Status::SUCCEEDED, + ] + ); + $this->order_service->attach_intent_info_to_order( $this->order, $intent ); + + $another_intent = WC_Helper_Intention::create_intention( + [ + 'id' => 'pi_mock_2', + 'status' => Intent_Status::CANCELED, + ] + ); + $this->order_service->attach_intent_info_to_order( $this->order, $another_intent ); + + $this->assertEquals( Intent_Status::SUCCEEDED, $this->order->get_meta( '_intention_status', true ) ); + } + /** * Several methods use the private method get_order to get the order being worked on. If an order is not found * then an exception is thrown. This test attempt to confirm that exception gets thrown. From 861cb062435304240fbe1f1d8b5f176581487c19 Mon Sep 17 00:00:00 2001 From: Guilherme Pressutto Date: Thu, 18 Jan 2024 09:56:31 -0300 Subject: [PATCH 39/60] Checking if wcpayPaymentRequestPayForOrderParams before using it (#8014) --- changelog/7996-wcpayPaymentRequestPayForOrderParams | 4 ++++ client/payment-request/index.js | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 changelog/7996-wcpayPaymentRequestPayForOrderParams diff --git a/changelog/7996-wcpayPaymentRequestPayForOrderParams b/changelog/7996-wcpayPaymentRequestPayForOrderParams new file mode 100644 index 00000000000..de2d1870de3 --- /dev/null +++ b/changelog/7996-wcpayPaymentRequestPayForOrderParams @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page diff --git a/client/payment-request/index.js b/client/payment-request/index.js index fc4b6f6853a..cb4d73ed2dc 100644 --- a/client/payment-request/index.js +++ b/client/payment-request/index.js @@ -561,6 +561,10 @@ jQuery( ( $ ) => { */ init: () => { if ( wcpayPaymentRequestParams.is_pay_for_order ) { + if ( ! window.wcpayPaymentRequestPayForOrderParams ) { + return; + } + const { total: { amount: total }, displayItems, From a0cbc737675cd615ff4d5db04f9ec686ec90c257 Mon Sep 17 00:00:00 2001 From: Guilherme Pressutto Date: Thu, 18 Jan 2024 14:20:00 -0300 Subject: [PATCH 40/60] Getting settings directly from the db in Logger (#8038) --- changelog/refactor-logger | 5 +++ .../GenericServiceProvider.php | 4 +- src/Internal/Logger.php | 28 +++++-------- tests/unit/src/Internal/LoggerTest.php | 39 ++++--------------- .../test-class-wc-payments-api-client.php | 3 +- 5 files changed, 25 insertions(+), 54 deletions(-) create mode 100644 changelog/refactor-logger diff --git a/changelog/refactor-logger b/changelog/refactor-logger new file mode 100644 index 00000000000..054cac4ec60 --- /dev/null +++ b/changelog/refactor-logger @@ -0,0 +1,5 @@ +Significance: patch +Type: dev +Comment: It just changes how we get the same data from the database + + diff --git a/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php b/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php index 544e8e5a1e3..2bb57a967d1 100644 --- a/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php +++ b/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php @@ -9,7 +9,6 @@ use WC_Payments_Account; use WC_Payments_Order_Service; -use WC_Payment_Gateway_WCPay; use WCPay\Core\Mode; use WCPay\Internal\DependencyManagement\AbstractServiceProvider; use WCPay\Internal\Logger; @@ -44,8 +43,7 @@ public function register(): void { $container->add( 'wc_get_logger', 'wc_get_logger' ); $container->addShared( Logger::class ) ->addArgument( 'wc_get_logger' ) - ->addArgument( Mode::class ) - ->addArgument( WC_Payment_Gateway_WCPay::class ); + ->addArgument( Mode::class ); $container->addShared( OrderService::class ) ->addArgument( WC_Payments_Order_Service::class ) diff --git a/src/Internal/Logger.php b/src/Internal/Logger.php index 517f9f2fd6d..c22f17c6cfa 100644 --- a/src/Internal/Logger.php +++ b/src/Internal/Logger.php @@ -34,33 +34,20 @@ class Logger { */ private $mode; - /** - * WC_Payment_Gateway_WCPay - * - * @var WC_Payment_Gateway_WCPay - */ - private $gateway; - /** * Logger constructor. * - * @param WC_Logger_Interface $wc_logger WC_Logger_Interface. - * @param Mode $mode Mode. - * @param WC_Payment_Gateway_WCPay $gateway WC_Payment_Gateway_WCPay. + * @param WC_Logger_Interface $wc_logger WC_Logger_Interface. + * @param Mode $mode Mode. */ - public function __construct( WC_Logger_Interface $wc_logger, Mode $mode, WC_Payment_Gateway_WCPay $gateway ) { + public function __construct( WC_Logger_Interface $wc_logger, Mode $mode ) { $this->wc_logger = $wc_logger; $this->mode = $mode; - $this->gateway = $gateway; } /** * Add a log entry. * - * Note that this depends on WC_Payments gateway property to be initialized as - * we need this to access the plugins debug setting to figure out if the setting - * is turned on. - * * @param string $message Log message. * @param string $level One of the following: * 'emergency': System is unusable. @@ -80,7 +67,7 @@ public function log( $message, $level = 'info' ) : void { } /** - * Checks if the gateway setting logging toggle is enabled. + * Checks if the setting logging toggle is enabled. * * @return bool Depending on the enable_logging setting. */ @@ -92,7 +79,12 @@ public function can_log() { } catch ( Exception $e ) { return false; } - return 'yes' === $this->gateway->get_option( 'enable_logging' ); + + // Getting the gateway settings directly from the database so the gateway doesn't need to be initialized. + $settings_option_name = 'woocommerce_' . WC_Payment_Gateway_WCPay::GATEWAY_ID . '_settings'; + $wcpay_settings = get_option( $settings_option_name ); + + return 'yes' === ( $wcpay_settings['enable_logging'] ?? false ); } /** diff --git a/tests/unit/src/Internal/LoggerTest.php b/tests/unit/src/Internal/LoggerTest.php index 849d9d5dd3f..97765d6a8ea 100644 --- a/tests/unit/src/Internal/LoggerTest.php +++ b/tests/unit/src/Internal/LoggerTest.php @@ -42,13 +42,6 @@ class LoggerTest extends WCPAY_UnitTestCase { */ private $mode; - /** - * WC_Payment_Gateway_WCPay - * - * @var WC_Payment_Gateway_WCPay|MockObject - */ - private $mock_gateway; - /** * Sets up the logger. */ @@ -57,13 +50,11 @@ protected function setUp(): void { $this->mock_wc_logger = $this->createMock( WC_Logger::class ); $this->mode = $this->createMock( Mode::class ); - $this->mock_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); $this->sut = $this->getMockBuilder( Logger::class ) ->setConstructorArgs( [ $this->mock_wc_logger, $this->mode, - $this->mock_gateway, ] ) ->onlyMethods( [ 'can_log' ] ) @@ -134,8 +125,7 @@ public function provider_log_levels() { public function test_can_log_dev_mode() { $this->sut = new Logger( $this->mock_wc_logger, - $this->mode, - $this->mock_gateway + $this->mode ); $this->mode->expects( $this->once() ) ->method( 'is_dev' ) @@ -149,8 +139,7 @@ public function test_can_log_dev_mode() { public function test_can_log_exception() { $this->sut = new Logger( $this->mock_wc_logger, - $this->mode, - $this->mock_gateway + $this->mode ); $this->mode->expects( $this->once() ) ->method( 'is_dev' ) @@ -164,16 +153,12 @@ public function test_can_log_exception() { public function test_can_log_no_option() { $this->sut = new Logger( $this->mock_wc_logger, - $this->mode, - $this->mock_gateway + $this->mode ); $this->mode->expects( $this->once() ) ->method( 'is_dev' ) ->willReturn( false ); - $this->mock_gateway->expects( $this->once() ) - ->method( 'get_option' ) - ->with( 'enable_logging' ) - ->willReturn( null ); + update_option( 'woocommerce_woocommerce_payments_settings', [] ); $this->assertFalse( $this->sut->can_log() ); } @@ -183,16 +168,12 @@ public function test_can_log_no_option() { public function test_can_log_disabled() { $this->sut = new Logger( $this->mock_wc_logger, - $this->mode, - $this->mock_gateway + $this->mode ); $this->mode->expects( $this->once() ) ->method( 'is_dev' ) ->willReturn( false ); - $this->mock_gateway->expects( $this->once() ) - ->method( 'get_option' ) - ->with( 'enable_logging' ) - ->willReturn( 'no' ); + update_option( 'woocommerce_woocommerce_payments_settings', [ 'enable_logging' => 'no' ] ); $this->assertFalse( $this->sut->can_log() ); } @@ -202,16 +183,12 @@ public function test_can_log_disabled() { public function test_can_log_enabled() { $this->sut = new Logger( $this->mock_wc_logger, - $this->mode, - $this->mock_gateway + $this->mode ); $this->mode->expects( $this->once() ) ->method( 'is_dev' ) ->willReturn( false ); - $this->mock_gateway->expects( $this->once() ) - ->method( 'get_option' ) - ->with( 'enable_logging' ) - ->willReturn( 'yes' ); + update_option( 'woocommerce_woocommerce_payments_settings', [ 'enable_logging' => 'yes' ] ); $this->assertTrue( $this->sut->can_log() ); } } diff --git a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php index d6320c14bd0..b7e9231f5ad 100644 --- a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php +++ b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php @@ -795,8 +795,7 @@ public function test_redacting_params( $request_arguments, $logger_num_calls, .. $mock_logger = $this->getMockBuilder( 'WC_Logger' ) ->setMethods( [ 'log' ] ) ->getMock(); - $mock_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); - $mock_internal_logger = new Logger( $mock_logger, WC_Payments::mode(), $mock_gateway ); + $mock_internal_logger = new Logger( $mock_logger, WC_Payments::mode() ); wcpay_get_test_container()->replace( Logger::class, $mock_internal_logger ); WC_Payments::mode()->dev(); From 1fc54748d86febf1ce6075251ad757584ee59a5f Mon Sep 17 00:00:00 2001 From: Mike Moore Date: Thu, 18 Jan 2024 15:00:48 -0500 Subject: [PATCH 41/60] Allow subscription purchase via Payment Request when no shipping methods are present (#8024) --- ...ix-2493-filter-subscriptions-payment-request | 4 ++++ ...-payments-payment-request-button-handler.php | 14 ++++++++++++++ ...-payments-payment-request-button-handler.php | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 changelog/fix-2493-filter-subscriptions-payment-request diff --git a/changelog/fix-2493-filter-subscriptions-payment-request b/changelog/fix-2493-filter-subscriptions-payment-request new file mode 100644 index 00000000000..c05650ebbc0 --- /dev/null +++ b/changelog/fix-2493-filter-subscriptions-payment-request @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Allow subscription purchase via Payment Request when no shipping methods are present. diff --git a/includes/class-wc-payments-payment-request-button-handler.php b/includes/class-wc-payments-payment-request-button-handler.php index 9d401183ba3..b764ad4d1bb 100644 --- a/includes/class-wc-payments-payment-request-button-handler.php +++ b/includes/class-wc-payments-payment-request-button-handler.php @@ -94,6 +94,7 @@ public function init() { add_action( 'woocommerce_checkout_order_processed', [ $this, 'add_order_meta' ], 10, 2 ); add_filter( 'woocommerce_login_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 ); add_filter( 'woocommerce_registration_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 ); + add_filter( 'woocommerce_cart_needs_shipping_address', [ $this, 'filter_cart_needs_shipping_address' ], 11, 1 ); // Add a filter for the value of `wcpay_is_apple_pay_enabled`. // This option does not get stored in the database at all, and this function @@ -871,6 +872,19 @@ private function is_product_supported() { return apply_filters( 'wcpay_payment_request_is_product_supported', $is_supported, $product ); } + /** + * Determine wether to filter the cart needs shipping address. + * + * @param boolean $needs_shipping_address Whether the cart needs a shipping address. + */ + public function filter_cart_needs_shipping_address( $needs_shipping_address ) { + if ( $this->has_subscription_product() && wc_get_shipping_method_count( true, true ) === 0 ) { + return false; + } + + return $needs_shipping_address; + } + /** * Get cart details. */ 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 e4d7412bf15..f4c05dd5a13 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 @@ -153,6 +153,7 @@ function() { public function tear_down() { parent::tear_down(); + WC_Subscriptions_Cart::set_cart_contains_subscription( false ); WC()->cart->empty_cart(); WC()->session->cleanup_sessions(); $this->zone->delete(); @@ -549,4 +550,20 @@ public function test_get_product_data_returns_the_same_as_build_display_items_wi 'Failed asserting total amount are the same for get_product_data and build_display_items' ); } + + public function test_filter_cart_needs_shipping_address_returns_false() { + sleep( 1 ); + $this->zone->delete_shipping_method( $this->flat_rate_id ); + $this->zone->delete_shipping_method( $this->local_pickup_id ); + + WC_Subscriptions_Cart::set_cart_contains_subscription( true ); + + $this->assertFalse( $this->pr->filter_cart_needs_shipping_address( true ) ); + } + + public function test_filter_cart_needs_shipping_address_returns_true() { + WC_Subscriptions_Cart::set_cart_contains_subscription( true ); + + $this->assertTrue( $this->pr->filter_cart_needs_shipping_address( true ) ); + } } From 627850e175df49bedd6ea15304a9dddc6115220a Mon Sep 17 00:00:00 2001 From: Rua Haszard Date: Fri, 19 Jan 2024 10:57:34 +1300 Subject: [PATCH 42/60] Improve disputed order notice so is more readable and actionable (and not all in bold) (#8010) Co-authored-by: Rua Haszard Co-authored-by: Shendy <73803630+shendy-a8c@users.noreply.github.com> --- changelog/fix-7568-tidy-disputed-order-notice | 4 + .../components/disputed-order-notice/index.js | 166 +++++++++++------- 2 files changed, 110 insertions(+), 60 deletions(-) create mode 100644 changelog/fix-7568-tidy-disputed-order-notice diff --git a/changelog/fix-7568-tidy-disputed-order-notice b/changelog/fix-7568-tidy-disputed-order-notice new file mode 100644 index 00000000000..39613195023 --- /dev/null +++ b/changelog/fix-7568-tidy-disputed-order-notice @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Improve clarity & readability of disputed order notice (not all text bold). diff --git a/client/components/disputed-order-notice/index.js b/client/components/disputed-order-notice/index.js index dce0fb2b77f..eb9d6beb4e4 100644 --- a/client/components/disputed-order-notice/index.js +++ b/client/components/disputed-order-notice/index.js @@ -108,6 +108,90 @@ const DisputedOrderNoticeHandler = ( { chargeId, onDisableOrderRefund } ) => { ); }; +const UrgentDisputeNoticeBody = ( { + isPreDisputeInquiry, + disputeReason, + formattedAmount, + dueBy, + countdownDays, +} ) => { + const formatString = isPreDisputeInquiry + ? __( + // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. + "Please resolve the inquiry on this order of %1$s labeled '%2$s' by %3$s.", + 'woocommerce-payments' + ) + : __( + // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. + "Please resolve the dispute on this order of %1$s labeled '%2$s' by %3$s.", + 'woocommerce-payments' + ); + + const message = sprintf( + formatString, + formattedAmount, + reasons[ disputeReason ].display, + dateI18n( 'M j, Y', dueBy.local().toISOString() ) + ); + + let suffix = sprintf( + // Translators: %s is the number of days left to respond to the dispute. + _n( + '(%s day left)', + '(%s days left)', + countdownDays, + 'woocommerce-payments' + ), + countdownDays + ); + if ( countdownDays < 1 ) { + suffix = __( '(Last day today)', 'woocommerce-payments' ); + } + + return ( + <> + { message } { suffix } + + ); +}; + +const RegularDisputeNoticeBody = ( { + isPreDisputeInquiry, + disputeReason, + formattedAmount, + dueBy, +} ) => { + const formatString = isPreDisputeInquiry + ? __( + // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason. + "Please resolve the inquiry on this order of %1$s with reason '%2$s'.", + 'woocommerce-payments' + ) + : __( + // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason. + "This order has a payment dispute for %1$s for the reason '%2$s'. ", + 'woocommerce-payments' + ); + + const boldMessage = sprintf( + formatString, + formattedAmount, + reasons[ disputeReason ].display + ); + + const suffix = sprintf( + // Translators: %1$s is the dispute due date. + __( 'Please respond before %1$s.', 'woocommerce-payments' ), + dateI18n( 'M j, Y', dueBy.local().toISOString() ) + ); + + return ( + <> + { boldMessage } { suffix } + + ); +}; + const DisputeNeedsResponseNotice = ( { disputeReason, formattedAmount, @@ -124,67 +208,29 @@ const DisputeNeedsResponseNotice = ( { } ); }, [ isPreDisputeInquiry, disputeReason, countdownDays ] ); - const titleStrings = { - // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. - dispute_default: __( - // eslint-disable-next-line max-len - 'This order has been disputed in the amount of %1$s. The customer provided the following reason: %2$s. Please respond to this dispute before %3$s.', - 'woocommerce-payments' - ), - // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. - inquiry_default: __( - // eslint-disable-next-line max-len - 'The card network involved in this order has opened an inquiry into the transaction with the following reason: %2$s. Please respond to this inquiry before %3$s, just like you would for a formal dispute.', - 'woocommerce-payments' - ), - // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. - dispute_urgent: __( - 'Please resolve the dispute on this order for %1$s labeled "%2$s" by %3$s.', - 'woocommerce-payments' - ), - // Translators: %1$s is the formatted dispute amount, %2$s is the dispute reason, %3$s is the due date. - inquiry_urgent: __( - 'Please resolve the inquiry on this order for %1$s labeled "%2$s" by %3$s.', - 'woocommerce-payments' - ), - }; - - let buttonLabel = __( 'Respond now', 'woocommerce-payments' ); - let suffix = ''; - - let titleText = isPreDisputeInquiry - ? titleStrings.inquiry_default - : titleStrings.dispute_default; - - // If the dispute is due within 7 days, adjust wording and highlight urgency. - if ( countdownDays < 7 ) { - titleText = isPreDisputeInquiry - ? titleStrings.inquiry_urgent - : titleStrings.dispute_urgent; - - suffix = sprintf( - // Translators: %s is the number of days left to respond to the dispute. - _n( - '(%s day left)', - '(%s days left)', - countdownDays, - 'woocommerce-payments' - ), - countdownDays - ); - } + const isUrgent = countdownDays < 7; - const title = sprintf( - titleText, - formattedAmount, - reasons[ disputeReason ].display, - dateI18n( 'M j, Y', dueBy.local().toISOString() ) - ); + const buttonLabel = + countdownDays < 1 + ? __( 'Respond today', 'woocommerce-payments' ) + : __( 'Respond now', 'woocommerce-payments' ); - if ( countdownDays < 1 ) { - buttonLabel = __( 'Respond today', 'woocommerce-payments' ); - suffix = __( '(Last day today)', 'woocommerce-payments' ); - } + const noticeBody = isUrgent ? ( + + ) : ( + + ); return ( - { { `${ title } ${ suffix }` } } + { noticeBody } ); }; From ca1d5a0e1bf9f5c01d34a29de82de63b272b8cd9 Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:37:59 +1000 Subject: [PATCH 43/60] Show the correct number of days in the new account waiting period notices (Payments Overview and Settings) (#8030) --- ...larify-calendar-days-waiting-period-notice | 4 ++++ .../deposits-overview/deposit-notices.tsx | 2 +- .../deposits-overview/test/index.tsx | 8 +++----- client/settings/deposits/index.js | 2 +- client/settings/deposits/test/index.test.js | 19 ++++++++++++++++++- 5 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 changelog/fix-7970-clarify-calendar-days-waiting-period-notice diff --git a/changelog/fix-7970-clarify-calendar-days-waiting-period-notice b/changelog/fix-7970-clarify-calendar-days-waiting-period-notice new file mode 100644 index 00000000000..5f1286350f5 --- /dev/null +++ b/changelog/fix-7970-clarify-calendar-days-waiting-period-notice @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Show the correct number of days in the new account waiting period notice. diff --git a/client/components/deposits-overview/deposit-notices.tsx b/client/components/deposits-overview/deposit-notices.tsx index 86f0de918a0..abf821275a5 100644 --- a/client/components/deposits-overview/deposit-notices.tsx +++ b/client/components/deposits-overview/deposit-notices.tsx @@ -83,7 +83,7 @@ export const NewAccountWaitingPeriodNotice: React.FC = () => ( > { interpolateComponents( { mixedString: __( - 'Your first deposit is held for seven business days. {{whyLink}}Why?{{/whyLink}}', + 'Your first deposit is held for 7-14 days. {{whyLink}}Why?{{/whyLink}}', 'woocommerce-payments' ), components: { diff --git a/client/components/deposits-overview/test/index.tsx b/client/components/deposits-overview/test/index.tsx index e865a6b8314..493f01223c5 100644 --- a/client/components/deposits-overview/test/index.tsx +++ b/client/components/deposits-overview/test/index.tsx @@ -301,7 +301,7 @@ describe( 'Deposits Overview information', () => { setSelectedCurrency: mockSetSelectedCurrency, } ); const { getByText, queryByText } = render( ); - getByText( /Your first deposit is held for seven business days/, { + getByText( /Your first deposit is held for/, { ignore: '.a11y-speak-region', } ); expect( queryByText( 'Change deposit schedule' ) ).toBeFalsy(); @@ -423,9 +423,7 @@ describe( 'Deposits Overview information', () => { } ); const { queryByText } = render( ); - expect( - queryByText( 'Your first deposit is held for seven business days' ) - ).toBeFalsy(); + expect( queryByText( /Your first deposit is held for/ ) ).toBeFalsy(); } ); test( 'Confirm new account waiting period notice shows if within waiting period', () => { @@ -443,7 +441,7 @@ describe( 'Deposits Overview information', () => { } ); const { getByText, getByRole } = render( ); - getByText( /Your first deposit is held for seven business days/, { + getByText( /Your first deposit is held for/, { ignore: '.a11y-speak-region', } ); expect( getByRole( 'link', { name: /Why\?/ } ) ).toHaveAttribute( diff --git a/client/settings/deposits/index.js b/client/settings/deposits/index.js index 637f0546fc9..fd9cc76be52 100644 --- a/client/settings/deposits/index.js +++ b/client/settings/deposits/index.js @@ -194,7 +194,7 @@ const DepositsSchedule = () => { > { __( - 'Your first deposit will be held for 7 days. Deposit scheduling will be available after this period.', + 'Your first deposit will be held for 7-14 days. Deposit scheduling will be available after this period.', 'woocommerce-payments' ) } diff --git a/client/settings/deposits/test/index.test.js b/client/settings/deposits/test/index.test.js index 6a81fd73018..9d0cee18be8 100644 --- a/client/settings/deposits/test/index.test.js +++ b/client/settings/deposits/test/index.test.js @@ -139,7 +139,7 @@ describe( 'Deposits', () => { ); const depositsMessage = screen.getByText( - /Your first deposit will be held for [0-9]+ days. Deposit scheduling will be available after this period./, + /Your first deposit will be held for/, { ignore: '.a11y-speak-region', } @@ -147,6 +147,23 @@ describe( 'Deposits', () => { expect( depositsMessage ).toBeInTheDocument(); } ); + it( `doesn't render the deposits within waiting period message for accounts not within waiting period`, () => { + useDepositStatus.mockReturnValue( 'enabled' ); + useCompletedWaitingPeriod.mockReturnValue( true ); + + render( + + + + ); + + expect( + screen.queryByText( /Your first deposit will be held for/, { + ignore: '.a11y-speak-region', + } ) + ).toBeFalsy(); + } ); + it( 'renders the frequency select', () => { useDepositScheduleInterval.mockReturnValue( [ 'daily', jest.fn() ] ); From 98f728bcbf80ab6308c04f04bfe85044593dbcf1 Mon Sep 17 00:00:00 2001 From: Eric Jinks <3147296+Jinksi@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:21:56 +1000 Subject: [PATCH 44/60] Use consistent inline notice style for deposit settings notices (#8042) --- ...fix-6424-update-settings-deposit-notice-ui | 4 + client/settings/deposits/index.js | 89 ++++++++----------- client/settings/deposits/style.scss | 21 ----- 3 files changed, 42 insertions(+), 72 deletions(-) create mode 100644 changelog/fix-6424-update-settings-deposit-notice-ui diff --git a/changelog/fix-6424-update-settings-deposit-notice-ui b/changelog/fix-6424-update-settings-deposit-notice-ui new file mode 100644 index 00000000000..3657670ba80 --- /dev/null +++ b/changelog/fix-6424-update-settings-deposit-notice-ui @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update style of notices within the deposits section of the settings screen. diff --git a/client/settings/deposits/index.js b/client/settings/deposits/index.js index fd9cc76be52..3975edddf6b 100644 --- a/client/settings/deposits/index.js +++ b/client/settings/deposits/index.js @@ -4,13 +4,8 @@ import React, { useContext } from 'react'; import { select } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { - Card, - SelectControl, - ExternalLink, - Notice, -} from '@wordpress/components'; -import HelpOutlineIcon from 'gridicons/dist/help-outline'; +import { Card, SelectControl, ExternalLink } from '@wordpress/components'; +import interpolateComponents from '@automattic/interpolate-components'; import { STORE_NAME } from 'wcpay/data/constants'; /** @@ -29,6 +24,7 @@ import { } from '../../data'; import './style.scss'; import wcpayTracks from 'wcpay/tracks'; +import InlineNotice from 'components/inline-notice'; const daysOfWeek = [ { label: __( 'Monday', 'woocommerce-payments' ), value: 'monday' }, @@ -160,56 +156,47 @@ const DepositsSchedule = () => { depositRestrictions === 'schedule_restricted' ) { return ( - - - { __( - 'Deposit scheduling is currently unavailable for your store.', - 'woocommerce-payments' - ) } - - + { interpolateComponents( { + mixedString: __( + 'Deposit scheduling is currently unavailable for your store. {{learnMoreLink}}Learn more{{/learnMoreLink}}', 'woocommerce-payments' - ) } - href="https://woo.com/document/woopayments/deposits/deposit-schedule/" - target="_blank" - rel="external noreferrer noopener" - > - - - + ), + components: { + learnMoreLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + }, + } ) } + ); } if ( completedWaitingPeriod !== true ) { return ( - - - { __( - 'Your first deposit will be held for 7-14 days. Deposit scheduling will be available after this period.', + + { interpolateComponents( { + mixedString: __( + 'Your first deposit will be held for 7-14 days. ' + + 'Deposit scheduling will be available after this period. {{learnMoreLink}}Learn more{{/learnMoreLink}}', 'woocommerce-payments' - ) } - - - - - + ), + components: { + learnMoreLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + }, + } ) } + ); } diff --git a/client/settings/deposits/style.scss b/client/settings/deposits/style.scss index 679fed55589..378b9cb1157 100644 --- a/client/settings/deposits/style.scss +++ b/client/settings/deposits/style.scss @@ -1,10 +1,4 @@ .deposits { - .components-notice { - margin-left: 0; - margin-right: 0; - margin-bottom: 1em; - } - &__bank-information-help { font-style: italic; color: #757575; @@ -23,19 +17,4 @@ margin-top: 0; margin-bottom: 1em; } - &__notice > div { - align-items: center; - display: flex; - gap: 15px; - justify-content: space-between; - margin: 4px 4px 4px 0; - - > a { - line-height: 0; - - svg { - fill: $studio-blue-50; - } - } - } } From a7904e5215b7be90203defa7e6b928c772aa0a43 Mon Sep 17 00:00:00 2001 From: Matt Allan Date: Fri, 19 Jan 2024 11:00:16 +1000 Subject: [PATCH 45/60] Updates the version of subscriptions-core bundled in WooPayments to 6.7.1 (#8043) --- changelog/subscriptions-core-6.7.1 | 4 ++++ changelog/subscriptions-core-6.7.1-2 | 4 ++++ changelog/subscriptions-core-6.7.1-3 | 4 ++++ changelog/subscriptions-core-6.7.1-4 | 4 ++++ composer.json | 2 +- composer.lock | 14 +++++++------- 6 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 changelog/subscriptions-core-6.7.1 create mode 100644 changelog/subscriptions-core-6.7.1-2 create mode 100644 changelog/subscriptions-core-6.7.1-3 create mode 100644 changelog/subscriptions-core-6.7.1-4 diff --git a/changelog/subscriptions-core-6.7.1 b/changelog/subscriptions-core-6.7.1 new file mode 100644 index 00000000000..28a911d14cb --- /dev/null +++ b/changelog/subscriptions-core-6.7.1 @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Update subscriptions-core to 6.7.1. diff --git a/changelog/subscriptions-core-6.7.1-2 b/changelog/subscriptions-core-6.7.1-2 new file mode 100644 index 00000000000..ef0ced053e7 --- /dev/null +++ b/changelog/subscriptions-core-6.7.1-2 @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled. diff --git a/changelog/subscriptions-core-6.7.1-3 b/changelog/subscriptions-core-6.7.1-3 new file mode 100644 index 00000000000..83da04c3910 --- /dev/null +++ b/changelog/subscriptions-core-6.7.1-3 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing. diff --git a/changelog/subscriptions-core-6.7.1-4 b/changelog/subscriptions-core-6.7.1-4 new file mode 100644 index 00000000000..96fb34cb28e --- /dev/null +++ b/changelog/subscriptions-core-6.7.1-4 @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Resolved an error that would occur with WC 8.5.0 when editing a subscription customer from the admin dashboard. diff --git a/composer.json b/composer.json index 6624cf68256..e13f38f87ff 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "automattic/jetpack-autoloader": "2.11.18", "automattic/jetpack-identity-crisis": "0.14.1", "automattic/jetpack-sync": "2.4.0", - "woocommerce/subscriptions-core": "6.6.0" + "woocommerce/subscriptions-core": "6.7.1" }, "require-dev": { "composer/installers": "1.10.0", diff --git a/composer.lock b/composer.lock index 8a48f6be36e..5ad3d0b6b89 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "51eea716f587985d4728f64657073489", + "content-hash": "5bebf06cbd0a606b022f672f94e82881", "packages": [ { "name": "automattic/jetpack-a8c-mc-stats", @@ -967,16 +967,16 @@ }, { "name": "woocommerce/subscriptions-core", - "version": "6.6.0", + "version": "6.7.1", "source": { "type": "git", "url": "https://github.com/Automattic/woocommerce-subscriptions-core.git", - "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac" + "reference": "81d809a476e87c260492d4cc0413818d85e123cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/5abcf9aac4e53ad9bdcf3752a34a04ae42261bac", - "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac", + "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/81d809a476e87c260492d4cc0413818d85e123cc", + "reference": "81d809a476e87c260492d4cc0413818d85e123cc", "shasum": "" }, "require": { @@ -1017,10 +1017,10 @@ "description": "Sell products and services with recurring payments in your WooCommerce Store.", "homepage": "https://github.com/Automattic/woocommerce-subscriptions-core", "support": { - "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.6.0", + "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.7.1", "issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues" }, - "time": "2023-12-20T07:19:09+00:00" + "time": "2024-01-17T01:56:28+00:00" } ], "packages-dev": [ From 06ccfd5a435f3f057204d9e01db3ea427825f543 Mon Sep 17 00:00:00 2001 From: Timur Karimov Date: Fri, 19 Jan 2024 08:48:12 +0100 Subject: [PATCH 46/60] Merge split UPE tests with main gateway tests (#7954) Co-authored-by: Timur Karimov --- .github/workflows/e2e-pull-request.yml | 7 +- .github/workflows/e2e-tests-atomic.yml | 6 +- changelog/merge-upe-non-upe-tests | 4 + tests/e2e/config/jest.config.js | 2 - .../shopper-upe-enabled-all-flows.spec.js | 117 -- .../shopper-upe-enabled-all-flows.spec.js | 112 -- .../shopper/shopper-bnpls-checkout.spec.js | 0 ...heckout-purchase-with-upe-methods.spec.js} | 79 +- ...er-checkout-save-card-and-purchase.spec.js | 11 + ...r-myaccount-save-card-and-checkout.spec.js | 3 + tests/e2e/utils/payments.js | 21 +- .../test-class-upe-payment-gateway.php | 1026 ------------- .../test-class-upe-split-payment-gateway.php | 1290 ---------------- .../test-class-wc-payment-gateway-wcpay.php | 1302 +++++++++++++++-- 14 files changed, 1211 insertions(+), 2769 deletions(-) create mode 100644 changelog/merge-upe-non-upe-tests delete mode 100644 tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js delete mode 100644 tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js rename tests/e2e/specs/{upe-split => wcpay}/shopper/shopper-bnpls-checkout.spec.js (100%) rename tests/e2e/specs/{upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js => wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js} (62%) delete mode 100644 tests/unit/payment-methods/test-class-upe-payment-gateway.php delete mode 100644 tests/unit/payment-methods/test-class-upe-split-payment-gateway.php diff --git a/.github/workflows/e2e-pull-request.yml b/.github/workflows/e2e-pull-request.yml index ab0cd702a86..020ce16c0bd 100644 --- a/.github/workflows/e2e-pull-request.yml +++ b/.github/workflows/e2e-pull-request.yml @@ -47,13 +47,8 @@ jobs: strategy: fail-fast: false matrix: - test_groups: [ 'wcpay', 'subscriptions', 'upe', 'upeSplit' ] # [TODO] Unskip blocks tests after investigating constant failures. + test_groups: [ 'wcpay', 'subscriptions' ] # [TODO] Unskip blocks tests after investigating constant failures. test_branches: [ 'merchant', 'shopper' ] - exclude: - - test_groups: 'upe' - test_branches: 'merchant' - - test_groups: 'upeSplit' - test_branches: 'merchant' name: WC - latest | ${{ matrix.test_groups }} - ${{ matrix.test_branches }} diff --git a/.github/workflows/e2e-tests-atomic.yml b/.github/workflows/e2e-tests-atomic.yml index bf31de432f0..55cbe67e04a 100644 --- a/.github/workflows/e2e-tests-atomic.yml +++ b/.github/workflows/e2e-tests-atomic.yml @@ -26,16 +26,12 @@ jobs: fail-fast: false max-parallel: 1 matrix: - test_groups: [ 'wcpay', 'subscriptions', 'upe', 'upeSplit' ] + test_groups: [ 'wcpay', 'subscriptions' ] test_branches: [ 'merchant', 'shopper' ] exclude: - test_groups: 'subscriptions' - test_groups: 'wcpay' test_branches: 'merchant' - - test_groups: 'upe' - test_branches: 'merchant' - - test_groups: 'upeSplit' - test_branches: 'merchant' env: E2E_GROUP: ${{ matrix.test_groups }} diff --git a/changelog/merge-upe-non-upe-tests b/changelog/merge-upe-non-upe-tests new file mode 100644 index 00000000000..2e6ed78762f --- /dev/null +++ b/changelog/merge-upe-non-upe-tests @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Merge UPE tests into the single and main gateway test file for unit and E2E tests. diff --git a/tests/e2e/config/jest.config.js b/tests/e2e/config/jest.config.js index 8e6c3a446f8..b150629cdf1 100644 --- a/tests/e2e/config/jest.config.js +++ b/tests/e2e/config/jest.config.js @@ -11,8 +11,6 @@ const e2ePaths = { wcpay: path.resolve( __dirname, '../specs/wcpay' ), subscriptions: path.resolve( __dirname, '../specs/subscriptions' ), blocks: path.resolve( __dirname, '../specs/blocks' ), - upe: path.resolve( __dirname, '../specs/upe' ), - upeSplit: path.resolve( __dirname, '../specs/upe-split' ), }; // Allow E2E tests to run specific tests - wcpay, subscriptions, blocks, all (default). diff --git a/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js b/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js deleted file mode 100644 index 78642474eb1..00000000000 --- a/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -/** - * Internal dependencies - */ -import { merchantWCP, shopperWCP } from '../../../utils/flows'; -import { fillCardDetails, setupProductCheckout } from '../../../utils/payments'; -const { shopper, merchant, uiUnblocked } = require( '@woocommerce/e2e-utils' ); - -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; -const UPE_METHOD_CHECKBOXES = [ - '#inspector-checkbox-control-3', // bancontact - '#inspector-checkbox-control-4', // eps - '#inspector-checkbox-control-5', // giropay - '#inspector-checkbox-control-6', // ideal - '#inspector-checkbox-control-7', // sofort -]; -const card = config.get( 'cards.basic' ); - -describe( 'Enabled Split UPE', () => { - beforeAll( async () => { - await merchant.login(); - await merchantWCP.enablePaymentMethod( UPE_METHOD_CHECKBOXES ); - await merchant.logout(); - await shopper.login(); - await shopperWCP.changeAccountCurrencyTo( 'EUR' ); - } ); - - afterAll( async () => { - await shopperWCP.changeAccountCurrencyTo( 'USD' ); - await shopperWCP.logout(); - await merchant.login(); - await merchantWCP.disablePaymentMethod( UPE_METHOD_CHECKBOXES ); - await merchant.logout(); - } ); - - describe( 'Shortcode checkout', () => { - it( 'should save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectNewPaymentMethod(); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopper.goToCheckout(); - await uiUnblocked(); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - } ); - - describe( 'My Account', () => { - let timeAdded; - it( 'should add the card as a new payment method', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic', card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatch( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatch( 'Payment method successfully added' ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should be able to delete the card', async () => { - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted.' ); - } ); - - afterAll( async () => { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - elapsedWaitTime - : 0; - - await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js b/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js deleted file mode 100644 index c5ba0caa81e..00000000000 --- a/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -/** - * Internal dependencies - */ -import { merchantWCP, shopperWCP } from '../../../utils/flows'; -import { fillCardDetails, setupProductCheckout } from '../../../utils/payments'; -const { shopper, merchant } = require( '@woocommerce/e2e-utils' ); - -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; - -const sepaPaymentMethod = '#inspector-checkbox-control-8'; -const card = config.get( 'cards.basic' ); - -describe( 'Enabled UPE', () => { - beforeAll( async () => { - await merchant.login(); - // enable SEPA - await merchantWCP.enablePaymentMethod( [ sepaPaymentMethod ] ); - await merchant.logout(); - await shopper.login(); - await shopperWCP.changeAccountCurrencyTo( 'EUR' ); - } ); - - afterAll( async () => { - await shopperWCP.changeAccountCurrencyTo( 'USD' ); - await shopperWCP.logout(); - await merchant.login(); - //disable SEPA - await merchantWCP.disablePaymentMethod( [ sepaPaymentMethod ] ); - await merchant.logout(); - } ); - - describe( 'Shortcode checkout', () => { - it( 'should save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectNewPaymentMethod(); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - } ); - - describe( 'My Account', () => { - let timeAdded; - it( 'should add the card as a new payment method', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic', card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatch( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatch( 'Payment method successfully added' ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should be able to delete the card', async () => { - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted.' ); - } ); - - afterAll( async () => { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - elapsedWaitTime - : 0; - - await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/upe-split/shopper/shopper-bnpls-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js similarity index 100% rename from tests/e2e/specs/upe-split/shopper/shopper-bnpls-checkout.spec.js rename to tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js diff --git a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js similarity index 62% rename from tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js index e1062f6d1ca..3f122226c13 100644 --- a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js @@ -8,17 +8,15 @@ import config from 'config'; */ import { merchantWCP, shopperWCP } from '../../../utils/flows'; import { - confirmCardAuthentication, - fillCardDetails, setupProductCheckout, - selectGiropayOnCheckout, - completeGiropayPayment, + selectOnCheckout, + completeRedirectedPayment, } from '../../../utils/payments'; -import { uiUnblocked } from '@woocommerce/e2e-utils/build/page-utils'; const { shopper, merchant } = require( '@woocommerce/e2e-utils' ); const UPE_METHOD_CHECKBOXES = [ - '#inspector-checkbox-control-7', // giropay + "//label[contains(text(), 'Bancontact')]/preceding-sibling::span/input[@type='checkbox']", + "//label[contains(text(), 'giropay')]/preceding-sibling::span/input[@type='checkbox']", ]; const card = config.get( 'cards.basic' ); const card2 = config.get( 'cards.basic2' ); @@ -30,6 +28,7 @@ describe( 'Enabled UPE with deferred intent creation', () => { await merchantWCP.enablePaymentMethod( UPE_METHOD_CHECKBOXES ); await merchant.logout(); await shopper.login(); + await shopperWCP.changeAccountCurrencyTo( 'EUR' ); } ); afterAll( async () => { @@ -41,88 +40,30 @@ describe( 'Enabled UPE with deferred intent creation', () => { describe( 'Enabled UPE with deferred intent creation', () => { it( 'should successfully place order with Giropay', async () => { - await shopperWCP.goToShopWithCurrency( 'EUR' ); await setupProductCheckout( config.get( 'addresses.customer.billing' ) ); - await selectGiropayOnCheckout( page ); + await selectOnCheckout( 'giropay', page ); await shopper.placeOrder(); - await completeGiropayPayment( page, 'success' ); + await completeRedirectedPayment( page, 'success' ); await page.waitForNavigation( { waitUntil: 'networkidle0', } ); await expect( page ).toMatch( 'Order received' ); } ); - it( 'should successfully place order with the default card', async () => { + it( 'should successfully place order with Bancontact', async () => { await setupProductCheckout( config.get( 'addresses.customer.billing' ) ); - await fillCardDetails( page, card ); + await selectOnCheckout( 'bancontact', page ); await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should process a payment with authentication for the 3DS card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await fillCardDetails( page, config.get( 'cards.3ds' ) ); - await shopper.placeOrder(); - await confirmCardAuthentication( page, '3DS' ); + await completeRedirectedPayment( page, 'success' ); await page.waitForNavigation( { waitUntil: 'networkidle0', } ); await expect( page ).toMatch( 'Order received' ); } ); - - it( 'should successfully save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopper.goToCheckout(); - await uiUnblocked(); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - - it( 'should not allow guest user to save the card', async () => { - await shopperWCP.logout(); - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - - await expect( page ).not.toMatchElement( - 'input#wc-woocommerce_payments-new-payment-method' - ); - await shopper.login(); - } ); } ); describe( 'My Account', () => { diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js index df04f592763..341b52cf516 100644 --- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js @@ -87,6 +87,17 @@ describe( 'Saved cards ', () => { await shopperWCP.deleteSavedPaymentMethod( card.label ); await expect( page ).toMatch( 'Payment method deleted' ); } ); + + it( 'should not allow guest user to save the card', async () => { + await shopperWCP.logout(); + await setupProductCheckout( + config.get( 'addresses.customer.billing' ) + ); + + await expect( page ).not.toMatchElement( + 'input#wc-woocommerce_payments-new-payment-method' + ); + } ); } ); } ); diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js index 9eaea6e86ac..8def9e54824 100644 --- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js @@ -37,6 +37,9 @@ describe( 'Saved cards ', () => { await expect( page ).toMatch( 'Payment method successfully added' ); + await expect( page ).toMatch( + `${ card.expires.month }/${ card.expires.year }` + ); } ); it( 'should process a payment with the saved card', async () => { diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js index 3c8084c0811..c98b70a7fa7 100644 --- a/tests/e2e/utils/payments.js +++ b/tests/e2e/utils/payments.js @@ -298,26 +298,31 @@ export async function setupCheckout( billingDetails ) { } /** - * Selects the Giropay payment method on the checkout page. + * Selects the payment method on the checkout page. * + * @param {*} paymentMethod The payment method to select. * @param {*} page The page reference object. */ -export async function selectGiropayOnCheckout( page ) { - await page.$( '#payment .payment_method_woocommerce_payments_giropay' ); - const giropayRadioLabel = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments_giropay label' +export async function selectOnCheckout( paymentMethod, page ) { + await page.$( + '#payment .payment_method_woocommerce_payments_' + paymentMethod ); - giropayRadioLabel.click(); + const radioLabel = await page.waitForSelector( + '#payment .payment_method_woocommerce_payments_' + + paymentMethod + + ' label' + ); + radioLabel.click(); await page.waitFor( 1000 ); } /** - * Authorizes or fails a Giropay payment. + * Authorizes or fails a redirected payment. * * @param {*} page The page reference object. * @param {string} action Either of 'success' or 'failure'. */ -export async function completeGiropayPayment( page, action ) { +export async function completeRedirectedPayment( page, action ) { await page.$( '.actions .common-ButtonGroup' ); const actionButton = await page.waitForSelector( `.actions .common-ButtonGroup a[name=${ action }]` diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php deleted file mode 100644 index 7c013e2b858..00000000000 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ /dev/null @@ -1,1026 +0,0 @@ - 'success', - 'payment_needed' => true, - 'redirect' => 'testURL/key=mock_order_key', - ]; - - /** - * WC_Payments_Localization_Service instance. - * - * @var WC_Payments_Localization_Service - */ - private $mock_localization_service; - - /** - * Mock Fraud Service. - * - * @var WC_Payments_Fraud_Service|MockObject; - */ - private $mock_fraud_service; - - /** - * Pre-test setup - */ - public function set_up() { - parent::set_up(); - - // Arrange: Mock WC_Payments_API_Client so we can configure the - // return value of create_and_confirm_intention(). - // Note that we cannot use createStub here since it's not defined in PHPUnit 6.5. - $this->mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' ) - ->disableOriginalConstructor() - ->onlyMethods( - [ - 'get_payment_method', - 'is_server_connected', - 'get_timeline', - ] - ) - ->getMock(); - - $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_wcpay_account->method( 'get_account_country' )->willReturn( 'US' ); - $this->mock_wcpay_account->method( 'get_account_default_currency' )->willReturn( 'USD' ); - - // Mock the main class's cache service. - $this->_cache = WC_Payments::get_database_cache(); - $this->mock_cache = $this->createMock( Database_Cache::class ); - WC_Payments::set_database_cache( $this->mock_cache ); - - $payment_methods = [ - 'link' => [ - 'base' => 0.1, - ], - ]; - - $this->mock_wcpay_account - ->expects( $this->any() ) - ->method( 'get_fees' ) - ->willReturn( $payment_methods ); - - $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class ); - - // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly. - $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' ) - ->disableOriginalConstructor() - ->getMock(); - - // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly. - $this->mock_token_service = $this->getMockBuilder( 'WC_Payments_Token_Service' ) - ->disableOriginalConstructor() - ->onlyMethods( [ 'add_payment_method_to_user' ] ) - ->getMock(); - - // Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly. - $this->mock_action_scheduler_service = $this->getMockBuilder( 'WC_Payments_Action_Scheduler_Service' ) - ->disableOriginalConstructor() - ->getMock(); - - $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); - - $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); - $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); - - $this->mock_payment_methods = []; - $payment_method_classes = [ - CC_Payment_Method::class, - Giropay_Payment_Method::class, - Sofort_Payment_Method::class, - Bancontact_Payment_Method::class, - EPS_Payment_Method::class, - P24_Payment_Method::class, - Ideal_Payment_Method::class, - Sepa_Payment_Method::class, - Becs_Payment_Method::class, - Link_Payment_Method::class, - Affirm_Payment_Method::class, - Afterpay_Payment_Method::class, - ]; - - $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); - foreach ( $payment_method_classes as $payment_method_class ) { - $mock_payment_method = $this->getMockBuilder( $payment_method_class ) - ->setConstructorArgs( [ $this->mock_token_service ] ) - ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] ) - ->getMock(); - $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method; - } - - $this->mock_order_service = $this->getMockBuilder( WC_Payments_Order_Service::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - ] - ) - ->onlyMethods( - [ - 'get_payment_method_id_for_order', - ] - ) - ->getMock(); - - $this->mock_payment_method = $this->getMockBuilder( $payment_method_class ) - ->setConstructorArgs( [ $this->mock_token_service ] ) - ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] ) - ->getMock(); - $this->mock_payment_methods[ $this->mock_payment_method->get_id() ] = $this->mock_payment_method; - - // 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_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_method, - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->mock_order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_return_url', - 'manage_customer_details_for_order', - 'parent_process_payment', - 'get_upe_enabled_payment_method_statuses', - 'is_payment_recurring', - ] - ) - ->getMock(); - - // Arrange: Set the return value of get_return_url() so it can be used in a test later. - $this->mock_gateway - ->expects( $this->any() ) - ->method( 'get_return_url' ) - ->will( - $this->returnValue( $this->return_url ) - ); - $this->mock_gateway - ->expects( $this->any() ) - ->method( 'parent_process_payment' ) - ->will( - $this->returnValue( $this->mock_payment_result ) - ); - - // Arrange: Define a $_POST array which includes the payment method, - // so that get_payment_method_from_request() does not throw error. - $_POST = [ - 'wcpay-payment-method' => 'pm_mock', - 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, - ]; - - // Mock the level3 service to always return an empty array. - $mock_level3_service = $this->createMock( Level3Service::class ); - $mock_level3_service->expects( $this->any() ) - ->method( 'get_data_from_order' ) - ->willReturn( [] ); - wcpay_get_test_container()->replace( Level3Service::class, $mock_level3_service ); - - // Mock the order service to always return an empty array for meta. - $mock_order_service = $this->createMock( OrderService::class ); - $mock_order_service->expects( $this->any() ) - ->method( 'get_payment_metadata' ) - ->willReturn( [] ); - wcpay_get_test_container()->replace( OrderService::class, $mock_order_service ); - } - - /** - * Cleanup after tests. - * - * @return void - */ - public function tear_down() { - parent::tear_down(); - WC_Payments::set_database_cache( $this->_cache ); - wcpay_get_test_container()->reset_all_replacements(); - } - - 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_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 ); - - $result = $this->mock_gateway->process_payment( $order->get_id() ); - - $this->assertEquals( 'success', $result['result'] ); - $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->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 ); - - $result = $this->mock_gateway->process_payment( $order->get_id() ); - - $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_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) ); - } - - public function test_process_redirect_payment_intent_processing() { - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $save_payment_method = false; - $user = wp_get_current_user(); - $intent_status = Intent_Status::PROCESSING; - $intent_metadata = [ 'order_id' => (string) $order_id ]; - $charge_id = 'ch_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'pi_mock'; - $payment_method_id = 'pm_mock'; - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $payment_intent = WC_Helper_Intention::create_intention( - [ - 'status' => $intent_status, - 'metadata' => $intent_metadata, - ] - ); - - $this->mock_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->will( $this->returnValue( $payment_intent ) ); - - $this->set_cart_contains_subscription_items( false ); - - $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - $note = wc_get_order_notes( - [ - 'order_id' => $order_id, - 'limit' => 1, - ] - )[0]; - - $this->assertStringContainsString( 'authorized', $note->content ); - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() ); - } - - public function test_process_redirect_payment_intent_succeded() { - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $save_payment_method = false; - $user = wp_get_current_user(); - $intent_status = Intent_Status::SUCCEEDED; - $intent_metadata = [ 'order_id' => (string) $order_id ]; - $charge_id = 'ch_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'pi_mock'; - $payment_method_id = 'pm_mock'; - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $payment_intent = WC_Helper_Intention::create_intention( - [ - 'status' => $intent_status, - 'metadata' => $intent_metadata, - ] - ); - - $this->mock_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->will( $this->returnValue( $payment_intent ) ); - - $this->set_cart_contains_subscription_items( false ); - - $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() ); - } - - public function test_validate_order_id_received_vs_intent_meta_order_id_throw_exception() { - $order = WC_Helper_Order::create_order(); - $intent_metadata = [ 'order_id' => (string) ( $order->get_id() + 100 ) ]; - - $this->expectException( Process_Payment_Exception::class ); - $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_gateway, - 'validate_order_id_received_vs_intent_meta_order_id', - [ $order, $intent_metadata ] - ); - } - - public function test_validate_order_id_received_vs_intent_meta_order_id_returning_void() { - $order = WC_Helper_Order::create_order(); - $intent_metadata = [ 'order_id' => (string) ( $order->get_id() ) ]; - - $res = \PHPUnit_Utils::call_method( - $this->mock_gateway, - 'validate_order_id_received_vs_intent_meta_order_id', - [ $order, $intent_metadata ] - ); - - $this->assertSame( null, $res ); - } - - public function test_correct_payment_method_title_for_order() { - $order = WC_Helper_Order::create_order(); - - $visa_credit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'credit', - ], - ]; - $visa_debit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'debit', - ], - ]; - $mastercard_credit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'mastercard', - 'funding' => 'credit', - ], - ]; - $eps_details = [ - 'type' => 'eps', - ]; - $giropay_details = [ - 'type' => 'giropay', - ]; - $p24_details = [ - 'type' => 'p24', - ]; - $sofort_details = [ - 'type' => 'sofort', - ]; - $bancontact_details = [ - 'type' => 'bancontact', - ]; - $sepa_details = [ - 'type' => 'sepa_debit', - ]; - $ideal_details = [ - 'type' => 'ideal', - ]; - $becs_details = [ - 'type' => 'au_becs_debit', - ]; - - $charge_payment_method_details = [ - $visa_credit_details, - $visa_debit_details, - $mastercard_credit_details, - $giropay_details, - $sofort_details, - $bancontact_details, - $eps_details, - $p24_details, - $ideal_details, - $sepa_details, - $becs_details, - ]; - - $expected_payment_method_titles = [ - 'Visa credit card', - 'Visa debit card', - 'Mastercard credit card', - 'giropay', - 'Sofort', - 'Bancontact', - 'EPS', - 'Przelewy24 (P24)', - 'iDEAL', - 'SEPA Direct Debit', - 'BECS Direct Debit', - ]; - - foreach ( $charge_payment_method_details as $i => $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() ); - } - } - - public function test_payment_methods_show_correct_default_outputs() { - $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); - $this->mock_token_service->expects( $this->any() ) - ->method( 'add_payment_method_to_user' ) - ->will( - $this->returnValue( $mock_token ) - ); - - $mock_user = 'mock_user'; - $mock_payment_method_id = 'pm_mock'; - - $mock_visa_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'debit', - ], - ]; - $mock_mastercard_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'mastercard', - 'funding' => 'credit', - ], - ]; - $mock_giropay_details = [ - 'type' => 'giropay', - ]; - $mock_p24_details = [ - 'type' => 'p24', - ]; - $mock_sofort_details = [ - 'type' => 'sofort', - ]; - $mock_bancontact_details = [ - 'type' => 'bancontact', - ]; - $mock_eps_details = [ - 'type' => 'eps', - ]; - $mock_sepa_details = [ - 'type' => 'sepa_debit', - ]; - $mock_ideal_details = [ - 'type' => 'ideal', - ]; - $mock_becs_details = [ - 'type' => 'au_becs_debit', - ]; - $mock_affirm_details = [ - 'type' => 'affirm', - ]; - $mock_afterpay_details = [ - 'type' => 'afterpay_clearpay', - ]; - - $this->set_cart_contains_subscription_items( false ); - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $p24_method = $this->mock_payment_methods['p24']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - $affirm_method = $this->mock_payment_methods['affirm']; - $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; - - $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); - $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); - $this->assertTrue( $card_method->is_reusable() ); - $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); - - $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); - $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $giropay_method->is_reusable() ); - - $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); - $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $p24_method->is_reusable() ); - - $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); - $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sofort_method->is_reusable() ); - - $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); - $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $bancontact_method->is_reusable() ); - - $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title() ); - $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); - $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $eps_method->is_reusable() ); - - $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); - $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sepa_method->is_reusable() ); - - $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); - $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $ideal_method->is_reusable() ); - - $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); - $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $becs_method->is_reusable() ); - - $this->assertSame( 'affirm', $affirm_method->get_id() ); - $this->assertSame( 'Affirm', $affirm_method->get_title() ); - $this->assertSame( 'Affirm', $affirm_method->get_title( $mock_affirm_details ) ); - $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $affirm_method->is_reusable() ); - - $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title() ); - $this->assertSame( 'Afterpay', $afterpay_method->get_title( $mock_afterpay_details ) ); - $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $afterpay_method->is_reusable() ); - } - - public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { - $this->set_cart_contains_subscription_items( true ); - - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $p24_method = $this->mock_payment_methods['p24']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - $affirm_method = $this->mock_payment_methods['affirm']; - $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; - - $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $giropay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sofort_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $bancontact_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $eps_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sepa_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $p24_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $ideal_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $becs_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $affirm_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $afterpay_method->is_enabled_at_checkout( 'US' ) ); - } - - public function test_only_valid_payment_methods_returned_for_currency() { - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $p24_method = $this->mock_payment_methods['p24']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - $affirm_method = $this->mock_payment_methods['affirm']; - $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; - - WC_Helper_Site_Currency::$mock_site_currency = 'EUR'; - - $account_domestic_currency = 'USD'; - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - // BNPLs can accept only domestic payments. - $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = 'USD'; - - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = 'AUD'; - $this->assertTrue( $becs_method->is_currency_valid( $account_domestic_currency ) ); - - // BNPLs can accept only domestic payments. - WC_Helper_Site_Currency::$mock_site_currency = 'USD'; - $account_domestic_currency = 'CAD'; - $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = ''; - } - - public function test_payment_method_compares_correct_currency() { - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $p24_method = $this->mock_payment_methods['p24']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - $affirm_method = $this->mock_payment_methods['affirm']; - $afterpay_method = $this->mock_payment_methods['afterpay_clearpay']; - - WC_Helper_Site_Currency::$mock_site_currency = 'EUR'; - $account_domestic_currency = 'USD'; - - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - - global $wp; - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $wp->query_vars = [ 'order-pay' => strval( $order_id ) ]; - $order->set_currency( 'USD' ); - - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); - - $wp->query_vars = []; - } - - public function test_create_token_from_setup_intent_adds_token() { - $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); - $mock_setup_intent_id = 'si_mock'; - $mock_user = wp_get_current_user(); - - $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $mock_setup_intent_id ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( - WC_Helper_Intention::create_setup_intention( - [ - 'id' => $mock_setup_intent_id, - 'payment_method' => 'pm_mock', - ] - ) - ); - - $this->mock_token_service->expects( $this->once() ) - ->method( 'add_payment_method_to_user' ) - ->with( 'pm_mock', $mock_user ) - ->will( - $this->returnValue( $mock_token ) - ); - - $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() { - $order = WC_Helper_Order::create_order(); - $order->set_billing_phone( '+1123456789123456789123' ); - $order->save(); - $this->expectException( Exception::class ); - $this->expectExceptionMessage( 'Invalid phone number.' ); - $this->mock_gateway->process_payment( $order->get_id() ); - } - - public function test_remove_link_payment_method_if_card_disabled() { - $this->mock_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; - - $this->mock_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_statuses' ) - ->will( - $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] ) - ); - - $this->assertSame( $this->mock_gateway->get_payment_method_ids_enabled_at_checkout(), [] ); - } - - /** - * @dataProvider available_payment_methods_provider - */ - public function test_get_upe_available_payment_methods( $payment_methods, $expected_result ) { - $mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $mock_wcpay_account - ->expects( $this->any() ) - ->method( 'get_fees' ) - ->willReturn( $payment_methods ); - - $gateway = new WC_Payment_Gateway_WCPay( - $this->mock_api_client, - $mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_method, - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->mock_order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - - $this->assertEquals( $expected_result, $gateway->get_upe_available_payment_methods() ); - } - - public function available_payment_methods_provider() { - return [ - 'card only' => [ - [ 'card' => [ 'base' => 0.1 ] ], - [ 'card' ], - ], - 'no match with fees' => [ - [ 'some_other_payment_method' => [ 'base' => 0.1 ] ], - [], - ], - 'multiple matches with fees' => [ - [ - 'card' => [ 'base' => 0.1 ], - 'bancontact' => [ 'base' => 0.2 ], - ], - [ 'card', 'bancontact' ], - ], - 'no fees no methods' => [ - [], - [], - ], - ]; - } - - /** - * Helper function to mock subscriptions for internal UPE payment methods. - */ - private function set_cart_contains_subscription_items( $cart_contains_subscriptions ) { - foreach ( $this->mock_payment_methods as $mock_payment_method ) { - $mock_payment_method->expects( $this->any() ) - ->method( 'is_subscription_item_in_cart' ) - ->will( - $this->returnValue( $cart_contains_subscriptions ) - ); - } - } - - private function setup_saved_payment_method() { - $token = WC_Helper_Token::create_token( 'pm_mock' ); - - return [ - 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, - 'wc-' . WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' => (string) $token->get_id(), - ]; - } - - private function set_get_upe_enabled_payment_method_statuses_return_value( $return_value = null ) { - if ( null === $return_value ) { - $return_value = [ - 'card_payments' => [ - 'status' => 'active', - ], - ]; - } - $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 deleted file mode 100644 index 8671ab35be0..00000000000 --- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php +++ /dev/null @@ -1,1290 +0,0 @@ - 'success', - 'payment_needed' => true, - 'redirect' => 'testURL/key=mock_order_key', - ]; - - /** - * WC_Payments_Localization_Service instance. - * - * @var WC_Payments_Localization_Service - */ - private $mock_localization_service; - - /** - * Mock Fraud Service. - * - * @var WC_Payments_Fraud_Service|MockObject - */ - private $mock_fraud_service; - - /** - * Mapping for payment ID to payment method. - * - * @var array - */ - private $payment_method_classes = [ - Payment_Method::CARD => CC_Payment_Method::class, - Payment_Method::GIROPAY => Giropay_Payment_Method::class, - Payment_Method::SOFORT => Sofort_Payment_Method::class, - Payment_Method::BANCONTACT => Bancontact_Payment_Method::class, - Payment_Method::EPS => EPS_Payment_Method::class, - Payment_Method::P24 => P24_Payment_Method::class, - Payment_Method::IDEAL => Ideal_Payment_Method::class, - Payment_Method::SEPA => Sepa_Payment_Method::class, - Payment_Method::BECS => Becs_Payment_Method::class, - Payment_Method::LINK => Link_Payment_Method::class, - ]; - - /** - * Pre-test setup - */ - public function set_up() { - parent::set_up(); - - $this->mock_payment_gateways = []; - $this->mock_payment_methods = []; - - // Mock the main class's cache service. - $this->_cache = WC_Payments::get_database_cache(); - $this->mock_cache = $this->createMock( Database_Cache::class ); - WC_Payments::set_database_cache( $this->mock_cache ); - - // Arrange: Mock WC_Payments_API_Client so we can configure the - // return value of create_and_confirm_intention(). - // Note that we cannot use createStub here since it's not defined in PHPUnit 6.5. - $this->mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' ) - ->disableOriginalConstructor() - ->setMethods( - [ - 'create_intention', - 'create_setup_intention', - 'update_intention', - 'get_intent', - 'get_payment_method', - 'is_server_connected', - 'get_charge', - 'get_timeline', - ] - ) - ->getMock(); - - $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_wcpay_account->method( 'get_account_country' )->willReturn( 'US' ); - $this->mock_wcpay_account->method( 'get_account_default_currency' )->willReturn( 'USD' ); - - $payment_methods = [ - 'link' => [ - 'base' => 0.1, - ], - ]; - - $this->mock_wcpay_account - ->expects( $this->any() ) - ->method( 'get_fees' ) - ->willReturn( $payment_methods ); - - $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class ); - - // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly. - $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' ) - ->disableOriginalConstructor() - ->getMock(); - - // 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' ] ) - ->getMock(); - - // Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly. - $this->mock_action_scheduler_service = $this->getMockBuilder( 'WC_Payments_Action_Scheduler_Service' ) - ->disableOriginalConstructor() - ->getMock(); - - $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); - $this->order_service = new WC_Payments_Order_Service( $this->mock_api_client ); - - $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); - - $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); - $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); - - // Arrange: Define a $_POST array which includes the payment method, - // so that get_payment_method_from_request() does not throw error. - $_POST = [ - 'wcpay-payment-method' => 'pm_mock', - 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, - ]; - - $get_payment_gateway_by_id_return_value_map = []; - - foreach ( $this->payment_method_classes as $payment_method_id => $payment_method_class ) { - $mock_payment_method = $this->getMockBuilder( $payment_method_class ) - ->setConstructorArgs( [ $this->mock_token_service ] ) - ->setMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] ) - ->getMock(); - $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method; - - $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $mock_payment_method, - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_return_url', - 'manage_customer_details_for_order', - 'parent_process_payment', - 'get_upe_enabled_payment_method_statuses', - 'is_payment_recurring', - 'get_payment_method_ids_enabled_at_checkout', - 'wc_payments_get_payment_gateway_by_id', - 'get_selected_payment_method', - 'get_upe_enabled_payment_method_ids', - ] - ) - ->getMock(); - - // Arrange: Set the return value of get_return_url() so it can be used in a test later. - $mock_gateway - ->expects( $this->any() ) - ->method( 'get_return_url' ) - ->will( - $this->returnValue( $this->return_url ) - ); - $mock_gateway - ->expects( $this->any() ) - ->method( 'parent_process_payment' ) - ->will( - $this->returnValue( $this->mock_payment_result ) - ); - - $this->mock_payment_gateways[ $payment_method_id ] = $mock_gateway; - - $get_payment_gateway_by_id_return_value_map[] = [ $payment_method_id, $mock_gateway ]; - - WC_Helper_Site_Currency::$mock_site_currency = ''; - } - - foreach ( $this->mock_payment_gateways as $id => $mock_gateway ) { - $mock_gateway->expects( $this->any() ) - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->will( - $this->returnValueMap( $get_payment_gateway_by_id_return_value_map ) - ); - } - - // Mock the level3 service to always return an empty array. - $mock_level3_service = $this->createMock( Level3Service::class ); - $mock_level3_service->expects( $this->any() ) - ->method( 'get_data_from_order' ) - ->willReturn( [] ); - wcpay_get_test_container()->replace( Level3Service::class, $mock_level3_service ); - - // Mock the order service to always return an empty array for meta. - $mock_order_service = $this->createMock( OrderService::class ); - $mock_order_service->expects( $this->any() ) - ->method( 'get_payment_metadata' ) - ->willReturn( [] ); - wcpay_get_test_container()->replace( OrderService::class, $mock_order_service ); - } - - /** - * Cleanup after tests. - * - * @return void - */ - public function tear_down() { - parent::tear_down(); - WC_Payments::set_database_cache( $this->_cache ); - wcpay_get_test_container()->reset_all_replacements(); - } - - /** - * Test the UI
container that will hold the payment method. - * - * @return void - */ - public function test_display_gateway_html_for_multiple_gateways() { - foreach ( $this->mock_payment_gateways as $payment_method_id => $mock_payment_gateway ) { - /** - * This tests each payment method output separately without concatenating the output - * into 1 single buffer. Each iteration has 1 assertion. - */ - ob_start(); - $mock_payment_gateway->display_gateway_html(); - $actual_output = ob_get_contents(); - ob_end_clean(); - - $this->assertStringContainsString( '
', $actual_output ); - } - } - - public function test_should_not_use_stripe_platform_on_checkout_page_for_upe() { - $payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - $this->assertFalse( $payment_gateway->should_use_stripe_platform_on_checkout_page() ); - } - - public function test_link_payment_method_requires_mandate_data() { - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ 'link' ] ) - ); - - $this->assertTrue( $mock_upe_gateway->is_mandate_data_required() ); - } - - public function test_sepa_debit_payment_method_requires_mandate_data() { - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - $this->assertTrue( $mock_upe_gateway->is_mandate_data_required() ); - } - - public function test_non_required_mandate_data() { - $mock_gateway_not_requiring_mandate_data = $this->mock_payment_gateways[ Payment_Method::GIROPAY ]; - $this->assertFalse( $mock_gateway_not_requiring_mandate_data->is_mandate_data_required() ); - } - - public function test_non_reusable_payment_method_is_not_available_when_subscription_is_in_cart() { - $non_reusable_payment_method = Payment_Method::BANCONTACT; - $payment_gateway = $this->mock_payment_gateways[ $non_reusable_payment_method ]; - - $this->set_cart_contains_subscription_items( true ); - - $this->assertFalse( $payment_gateway->is_available() ); - } - - public function test_process_payment_returns_correct_redirect_when_using_saved_payment() { - $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - $user = wp_get_current_user(); - $customer_id = 'cus_mock'; - - $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->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( - WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ) - ); - - $this->set_cart_contains_subscription_items( false ); - - $result = $mock_card_payment_gateway->process_payment( $order->get_id() ); - - $this->assertEquals( 'success', $result['result'] ); - $this->assertEquals( $this->return_url, $result['redirect'] ); - } - - public function test_upe_process_payment_check_session_order_redirect_to_previous_order() { - $_POST['wc_payment_intent_id'] = 'pi_mock'; - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ]; - - $response = [ - 'dummy_result' => 'xyz', - ]; - - // Arrange the order is being processed. - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - - // Arrange the DPPs to return a redirect. - $this->mock_dpps->expects( $this->once() ) - ->method( 'check_against_session_processing_order' ) - ->with( wc_get_order( $order ) ) - ->willReturn( $response ); - - // Act: process the order but redirect to the previous/session paid order. - $result = $mock_upe_gateway->process_payment( $order_id ); - - // Assert: the result of check_against_session_processing_order. - $this->assertSame( $response, $result ); - } - - public function test_process_redirect_payment_intent_processing() { - - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - $order = WC_Helper_Order::create_order(); - - $order_id = $order->get_id(); - $save_payment_method = false; - $user = wp_get_current_user(); - $intent_status = Intent_Status::PROCESSING; - $intent_metadata = [ 'order_id' => (string) $order_id ]; - $charge_id = 'ch_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'pi_mock'; - $payment_method_id = 'pm_mock'; - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $card_method = $this->mock_payment_methods['card']; - - $payment_intent = WC_Helper_Intention::create_intention( - [ - 'status' => $intent_status, - 'metadata' => $intent_metadata, - ] - ); - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_selected_payment_method' ) - ->willReturn( $card_method ); - - $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); - - $this->set_cart_contains_subscription_items( false ); - - $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - $note = wc_get_order_notes( - [ - 'order_id' => $order_id, - 'limit' => 1, - ] - )[0]; - - $this->assertStringContainsString( 'authorized', $note->content ); - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() ); - } - - public function test_process_redirect_payment_intent_succeded() { - - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - $order = WC_Helper_Order::create_order(); - - $order_id = $order->get_id(); - $save_payment_method = false; - $user = wp_get_current_user(); - $intent_status = Intent_Status::SUCCEEDED; - $intent_metadata = [ 'order_id' => (string) $order_id ]; - $charge_id = 'ch_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'pi_mock'; - $payment_method_id = 'pm_mock'; - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $card_method = $this->mock_payment_methods['card']; - - $payment_intent = WC_Helper_Intention::create_intention( - [ - 'status' => $intent_status, - 'metadata' => $intent_metadata, - ] - ); - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); - - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_selected_payment_method' ) - ->willReturn( $card_method ); - - $this->set_cart_contains_subscription_items( false ); - - $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() ); - } - - 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' ) ); - } - - public function test_process_redirect_setup_intent_succeded() { - - $order = WC_Helper_Order::create_order(); - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - - $order_id = $order->get_id(); - $save_payment_method = true; - $user = wp_get_current_user(); - $intent_status = Intent_Status::SUCCEEDED; - $client_secret = 'cs_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'si_mock'; - $payment_method_id = 'pm_mock'; - $token = WC_Helper_Token::create_token( $payment_method_id ); - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $card_method = $this->mock_payment_methods['card']; - - $order->set_shipping_total( 0 ); - $order->set_shipping_tax( 0 ); - $order->set_cart_tax( 0 ); - $order->set_total( 0 ); - $order->save(); - - $setup_intent = WC_Helper_Intention::create_setup_intention( - [ - 'id' => $intent_id, - 'client_secret' => $client_secret, - 'status' => $intent_status, - 'payment_method' => $payment_method_id, - 'payment_method_options' => [ - 'card' => [ - 'request_three_d_secure' => 'automatic', - ], - ], - 'last_setup_error' => [], - ] - ); - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $intent_id ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $setup_intent ); - - $this->mock_token_service->expects( $this->once() ) - ->method( 'add_payment_method_to_user' ) - ->will( - $this->returnValue( $token ) - ); - - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_selected_payment_method' ) - ->willReturn( $card_method ); - - $this->set_cart_contains_subscription_items( true ); - - $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() ); - $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) ); - } - - public function test_process_redirect_payment_save_payment_token() { - - $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ]; - - $order = WC_Helper_Order::create_order(); - $order_id = $order->get_id(); - $save_payment_method = true; - $user = wp_get_current_user(); - $intent_status = Intent_Status::PROCESSING; - $intent_metadata = [ 'order_id' => (string) $order_id ]; - $charge_id = 'ch_mock'; - $customer_id = 'cus_mock'; - $intent_id = 'pi_mock'; - $payment_method_id = 'pm_mock'; - $token = WC_Helper_Token::create_token( $payment_method_id ); - - // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. - $order->update_meta_data( '_intent_id', $intent_id ); - $order->save(); - - $card_method = $this->mock_payment_methods['card']; - - $payment_intent = WC_Helper_Intention::create_intention( - [ - 'status' => $intent_status, - 'metadata' => $intent_metadata, - ] - ); - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'manage_customer_details_for_order' ) - ->will( - $this->returnValue( [ $user, $customer_id ] ) - ); - - $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( $payment_intent ); - - $this->mock_token_service->expects( $this->once() ) - ->method( 'add_payment_method_to_user' ) - ->will( - $this->returnValue( $token ) - ); - - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_selected_payment_method' ) - ->willReturn( $card_method ); - - $this->set_cart_contains_subscription_items( false ); - - $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); - - $result_order = wc_get_order( $order_id ); - $note = wc_get_order_notes( - [ - 'order_id' => $order_id, - 'limit' => 1, - ] - )[0]; - - $this->assertStringContainsString( 'authorized', $note->content ); - $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); - $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); - $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); - $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); - $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); - $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() ); - $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) ); - } - - public function test_correct_payment_method_title_for_order() { - $order = WC_Helper_Order::create_order(); - - $visa_credit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'credit', - ], - ]; - $visa_debit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'debit', - ], - ]; - $mastercard_credit_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'mastercard', - 'funding' => 'credit', - ], - ]; - $eps_details = [ - 'type' => 'eps', - ]; - $giropay_details = [ - 'type' => 'giropay', - ]; - $p24_details = [ - 'type' => 'p24', - ]; - $sofort_details = [ - 'type' => 'sofort', - ]; - $bancontact_details = [ - 'type' => 'bancontact', - ]; - $sepa_details = [ - 'type' => 'sepa_debit', - ]; - $ideal_details = [ - 'type' => 'ideal', - ]; - $becs_details = [ - 'type' => 'au_becs_debit', - ]; - - $charge_payment_method_details = [ - $visa_credit_details, - $visa_debit_details, - $mastercard_credit_details, - $giropay_details, - $sofort_details, - $bancontact_details, - $eps_details, - $p24_details, - $ideal_details, - $sepa_details, - $becs_details, - ]; - - $expected_payment_method_titles = [ - 'Visa credit card', - 'Visa debit card', - 'Mastercard credit card', - 'giropay', - 'Sofort', - 'Bancontact', - 'EPS', - 'Przelewy24 (P24)', - 'iDEAL', - 'SEPA Direct Debit', - 'BECS Direct Debit', - ]; - - foreach ( $charge_payment_method_details as $i => $payment_method_details ) { - $payment_method_id = $payment_method_details['type']; - $mock_upe_gateway = $this->mock_payment_gateways[ $payment_method_id ]; - $payment_method = $this->mock_payment_methods[ $payment_method_id ]; - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_selected_payment_method' ) - ->willReturn( $payment_method ); - $mock_upe_gateway->set_payment_method_title_for_order( $order, $payment_method_id, $payment_method_details ); - $this->assertEquals( $expected_payment_method_titles[ $i ], $order->get_payment_method_title() ); - } - } - - public function test_payment_methods_show_correct_default_outputs() { - $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); - $this->mock_token_service->expects( $this->any() ) - ->method( 'add_payment_method_to_user' ) - ->will( - $this->returnValue( $mock_token ) - ); - - $mock_user = 'mock_user'; - $mock_payment_method_id = 'pm_mock'; - - $mock_visa_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'visa', - 'funding' => 'debit', - ], - ]; - $mock_mastercard_details = [ - 'type' => 'card', - 'card' => [ - 'network' => 'mastercard', - 'funding' => 'credit', - ], - ]; - $mock_giropay_details = [ - 'type' => 'giropay', - ]; - $mock_p24_details = [ - 'type' => 'p24', - ]; - $mock_sofort_details = [ - 'type' => 'sofort', - ]; - $mock_bancontact_details = [ - 'type' => 'bancontact', - ]; - $mock_eps_details = [ - 'type' => 'eps', - ]; - $mock_sepa_details = [ - 'type' => 'sepa_debit', - ]; - $mock_ideal_details = [ - 'type' => 'ideal', - ]; - $mock_becs_details = [ - 'type' => 'au_becs_debit', - ]; - - $this->set_cart_contains_subscription_items( false ); - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $p24_method = $this->mock_payment_methods['p24']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - - $this->assertEquals( 'card', $card_method->get_id() ); - $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); - $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); - $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); - $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); - $this->assertTrue( $card_method->is_reusable() ); - $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); - - $this->assertEquals( 'giropay', $giropay_method->get_id() ); - $this->assertEquals( 'giropay', $giropay_method->get_title() ); - $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); - $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $giropay_method->is_reusable() ); - - $this->assertEquals( 'p24', $p24_method->get_id() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); - $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); - $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $p24_method->is_reusable() ); - - $this->assertEquals( 'sofort', $sofort_method->get_id() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title() ); - $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); - $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sofort_method->is_reusable() ); - - $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); - $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); - $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $bancontact_method->is_reusable() ); - - $this->assertEquals( 'eps', $eps_method->get_id() ); - $this->assertEquals( 'EPS', $eps_method->get_title() ); - $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); - $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $eps_method->is_reusable() ); - - $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); - $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); - $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sepa_method->is_reusable() ); - - $this->assertEquals( 'ideal', $ideal_method->get_id() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); - $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); - $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $ideal_method->is_reusable() ); - - $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); - $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); - $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $becs_method->is_reusable() ); - } - - public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { - // Setup $this->mock_payment_methods. - - $this->set_cart_contains_subscription_items( true ); - - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $p24_method = $this->mock_payment_methods['p24']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - - $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $giropay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sofort_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $bancontact_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $eps_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $sepa_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $p24_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $ideal_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $becs_method->is_enabled_at_checkout( 'US' ) ); - } - - public function test_only_valid_payment_methods_returned_for_currency() { - // Setup $this->mock_payment_methods. - - $card_method = $this->mock_payment_methods['card']; - $giropay_method = $this->mock_payment_methods['giropay']; - $sofort_method = $this->mock_payment_methods['sofort']; - $bancontact_method = $this->mock_payment_methods['bancontact']; - $eps_method = $this->mock_payment_methods['eps']; - $sepa_method = $this->mock_payment_methods['sepa_debit']; - $p24_method = $this->mock_payment_methods['p24']; - $ideal_method = $this->mock_payment_methods['ideal']; - $becs_method = $this->mock_payment_methods['au_becs_debit']; - - WC_Helper_Site_Currency::$mock_site_currency = 'EUR'; - $account_domestic_currency = 'USD'; - - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = 'USD'; - - $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) ); - $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = 'AUD'; - $this->assertTrue( $becs_method->is_currency_valid( $account_domestic_currency ) ); - - WC_Helper_Site_Currency::$mock_site_currency = ''; - } - - public function test_create_token_from_setup_intent_adds_token() { - - $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); - $mock_setup_intent_id = 'si_mock'; - $mock_user = wp_get_current_user(); - - $this->mock_token_service - ->method( 'add_payment_method_to_user' ) - ->with( 'pm_mock', $mock_user ) - ->will( - $this->returnValue( $mock_token ) - ); - - foreach ( $this->mock_payment_gateways as $mock_upe_gateway ) { - $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $mock_setup_intent_id ); - - $request->expects( $this->once() ) - ->method( 'format_response' ) - ->willReturn( - WC_Helper_Intention::create_setup_intention( - [ - 'id' => $mock_setup_intent_id, - 'payment_method' => 'pm_mock', - ] - ) - ); - $this->assertEquals( $mock_token, $mock_upe_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) ); - } - } - - /** - * 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( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::CARD ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( [ 'get_payment_methods_from_gateway_id' ] ) - ->getMock(); - - $order = WC_Helper_Order::create_order(); - $payment_information = new Payment_Information( 'pm_mock', $order ); - - $_POST['payment_method'] = 'woocommerce_payments'; - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'get_payment_methods_from_gateway_id' ) - ->with( 'woocommerce_payments' ) - ->will( - $this->returnValue( [ Payment_Method::CARD ] ) - ); - - $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information ); - - $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); - - unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification - } - - /** - * Test get_payment_method_types without post request context. - * - * @return void - */ - public function test_get_payment_methods_without_request_context() { - $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::CARD ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( [ 'get_payment_methods_from_gateway_id' ] ) - ->getMock(); - - $token = WC_Helper_Token::create_token( 'pm_mock' ); - $order = WC_Helper_Order::create_order(); - $payment_information = new Payment_Information( 'pm_mock', $order, null, $token ); - - unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'get_payment_methods_from_gateway_id' ) - ->with( $token->get_gateway_id(), $order->get_id() ) - ->will( - $this->returnValue( [ Payment_Method::CARD ] ) - ); - - $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information ); - - $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); - } - - /** - * Test get_payment_method_types without post request context or saved token. - * - * @return void - */ - public function test_get_payment_methods_without_request_context_or_token() { - $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::CARD ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_payment_methods_from_gateway_id', - 'get_payment_method_ids_enabled_at_checkout', - ] - ) - ->getMock(); - - $payment_information = new Payment_Information( 'pm_mock' ); - - unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification - - $gateway = WC_Payments::get_gateway(); - WC_Payments::set_gateway( $mock_upe_gateway ); - - $mock_upe_gateway->expects( $this->never() ) - ->method( 'get_payment_methods_from_gateway_id' ); - - $mock_upe_gateway->expects( $this->once() ) - ->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [ Payment_Method::CARD ] ); - - $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information ); - - $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); - - WC_Payments::set_gateway( $gateway ); - } - - /** - * Test get_payment_methods_from_gateway_id function with UPE enabled. - * - * @return void - */ - public function test_get_payment_methods_from_gateway_id_upe() { - WC_Helper_Order::create_order(); - $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::CARD ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->onlyMethods( - [ - 'get_upe_enabled_payment_method_ids', - 'get_payment_method_ids_enabled_at_checkout', - ] - ) - ->getMock(); - - $gateway = WC_Payments::get_gateway(); - WC_Payments::set_gateway( $mock_upe_gateway ); - - $mock_upe_gateway->expects( $this->any() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] ) - ); - - $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() ) - ->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->will( - $this->onConsecutiveCalls( - [ Payment_Method::CARD, Payment_Method::LINK ], - [ Payment_Method::CARD ] - ) - ); - - $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( WC_Payment_Gateway_WCPay::GATEWAY_ID ); - $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); - - WC_Payments::set_gateway( $gateway ); - } - - /** - * Helper function to mock subscriptions for internal UPE payment methods. - */ - private function set_cart_contains_subscription_items( $cart_contains_subscriptions ) { - foreach ( $this->mock_payment_methods as $mock_payment_method ) { - $mock_payment_method->expects( $this->any() ) - ->method( 'is_subscription_item_in_cart' ) - ->will( - $this->returnValue( $cart_contains_subscriptions ) - ); - } - } - - private function setup_saved_payment_method() { - $token = WC_Helper_Token::create_token( 'pm_mock' ); - - return [ - 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID, - 'wc-' . WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' => (string) $token->get_id(), - ]; - } - - private function set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway, $return_value = null ) { - if ( null === $return_value ) { - $return_value = [ - 'card_payments' => [ - 'status' => 'active', - ], - ]; - } - $mock_payment_gateway - ->expects( $this->any() ) - ->method( 'get_upe_enabled_payment_method_statuses' ) - ->will( $this->returnValue( $return_value ) ); - } -} diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php index 02505f94d51..62dd5c2f83a 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php @@ -15,9 +15,11 @@ use WCPay\Core\Server\Request\Get_Setup_Intention; use WCPay\Constants\Order_Status; use WCPay\Constants\Intent_Status; +use WCPay\Constants\Payment_Method; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Exceptions\Amount_Too_Small_Exception; use WCPay\Exceptions\API_Exception; +use WCPay\Exceptions\Process_Payment_Exception; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; use WCPay\Internal\Payment\Factor; use WCPay\Internal\Payment\Router; @@ -26,8 +28,20 @@ use WCPay\Internal\Service\OrderService; use WCPay\Internal\Service\PaymentProcessingService; use WCPay\Payment_Information; +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\Link_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\WC_Helper_Site_Currency; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; @@ -45,9 +59,30 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { /** * System under test. * + * The card gateway is predominantly used for testing compared to other gateways, + * therefore it is assigned its own variable. + * * @var WC_Payment_Gateway_WCPay */ - private $wcpay_gateway; + private $card_gateway; + + /** + * Arrays of system under test. + * + * Useful when testing operations involving multiple gateways. + * + * @var WC_Payment_Gateway_WCPay[] + */ + private $gateways; + + /** + * Arrays of payment methods. + * + * Useful when testing operations involving multiple payment methods. + * + * @var WCPay\Payment_Methods\UPE_Payment_Method[] + */ + private $payment_methods; /** * Mock WC_Payments_API_Client. @@ -168,16 +203,6 @@ public function set_up() { $this->mock_api_client->expects( $this->any() )->method( 'get_blog_id' )->willReturn( 1234567 ); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_wcpay_account - ->expects( $this->any() ) - ->method( 'get_fees' ) - ->willReturn( - [ - 'card' => [ - 'base' => 0.1, - ], - ] - ); // Mock the main class's cache service. $this->_cache = WC_Payments::get_database_cache(); @@ -211,22 +236,11 @@ public function set_up() { ->setMethods( [ '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, - $this->mock_payment_method, - [ 'card' => $this->mock_payment_method ], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); + $this->init_gateways(); - WC_Payments::set_gateway( $this->wcpay_gateway ); + // Replace the main class's gateway for testing purposes. + $this->_gateway = WC_Payments::get_gateway(); + WC_Payments::set_gateway( $this->card_gateway ); $this->woopay_utilities = new WooPay_Utilities(); @@ -256,9 +270,12 @@ public function tear_down() { // Restore the cache service in the main class. WC_Payments::set_database_cache( $this->_cache ); + // Restore the gateway in the main class. + WC_Payments::set_gateway( $this->_gateway ); + // Fall back to an US store. update_option( 'woocommerce_store_postcode', '94110' ); - $this->wcpay_gateway->update_option( 'saved_cards', 'yes' ); + $this->card_gateway->update_option( 'saved_cards', 'yes' ); // Some tests simulate payment method parameters. $payment_method_keys = [ @@ -277,6 +294,890 @@ public function tear_down() { wcpay_get_test_container()->reset_all_replacements(); } + public function test_process_redirect_payment_intent_processing() { + $order = WC_Helper_Order::create_order(); + $order_id = $order->get_id(); + $save_payment_method = false; + $user = wp_get_current_user(); + $intent_status = Intent_Status::PROCESSING; + $intent_metadata = [ 'order_id' => (string) $order_id ]; + $charge_id = 'ch_mock'; + $customer_id = 'cus_mock'; + $intent_id = 'pi_mock'; + $payment_method_id = 'pm_mock'; + + // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. + $order->update_meta_data( '_intent_id', $intent_id ); + $order->save(); + + $payment_intent = WC_Helper_Intention::create_intention( + [ + 'status' => $intent_status, + 'metadata' => $intent_metadata, + ] + ); + + $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ); + + $request->expects( $this->once() ) + ->method( 'format_response' ) + ->will( $this->returnValue( $payment_intent ) ); + + $this->mock_customer_service + ->expects( $this->once() ) + ->method( 'get_customer_id_by_user_id' ) + ->will( $this->returnValue( $customer_id ) ); + + $this->card_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + + $result_order = wc_get_order( $order_id ); + $note = wc_get_order_notes( + [ + 'order_id' => $order_id, + 'limit' => 1, + ] + )[0]; + + $this->assertStringContainsString( 'authorized', $note->content ); + $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); + $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); + $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); + $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); + $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); + $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() ); + } + + public function test_process_redirect_payment_intent_succeded() { + $order = WC_Helper_Order::create_order(); + + $order_id = $order->get_id(); + $save_payment_method = false; + $user = wp_get_current_user(); + $intent_status = Intent_Status::SUCCEEDED; + $intent_metadata = [ 'order_id' => (string) $order_id ]; + $charge_id = 'ch_mock'; + $customer_id = 'cus_mock'; + $intent_id = 'pi_mock'; + $payment_method_id = 'pm_mock'; + + // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. + $order->update_meta_data( '_intent_id', $intent_id ); + $order->save(); + + $payment_intent = WC_Helper_Intention::create_intention( + [ + 'status' => $intent_status, + 'metadata' => $intent_metadata, + ] + ); + + $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ) + ->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $payment_intent ); + + $this->mock_customer_service + ->expects( $this->once() ) + ->method( 'get_customer_id_by_user_id' ) + ->will( $this->returnValue( $customer_id ) ); + + $this->card_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + + $result_order = wc_get_order( $order_id ); + + $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); + $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); + $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); + $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); + $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); + $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() ); + } + + public function test_validate_order_id_received_vs_intent_meta_order_id_throw_exception() { + $order = WC_Helper_Order::create_order(); + $intent_metadata = [ 'order_id' => (string) ( $order->get_id() + 100 ) ]; + + $this->expectException( Process_Payment_Exception::class ); + $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->card_gateway, + 'validate_order_id_received_vs_intent_meta_order_id', + [ $order, $intent_metadata ] + ); + } + + public function test_validate_order_id_received_vs_intent_meta_order_id_returning_void() { + $order = WC_Helper_Order::create_order(); + $intent_metadata = [ 'order_id' => (string) ( $order->get_id() ) ]; + + $res = \PHPUnit_Utils::call_method( + $this->card_gateway, + 'validate_order_id_received_vs_intent_meta_order_id', + [ $order, $intent_metadata ] + ); + + $this->assertSame( null, $res ); + } + + public function test_correct_payment_method_title_for_order() { + $order = WC_Helper_Order::create_order(); + + $visa_credit_details = [ + 'type' => 'card', + 'card' => [ + 'network' => 'visa', + 'funding' => 'credit', + ], + ]; + $visa_debit_details = [ + 'type' => 'card', + 'card' => [ + 'network' => 'visa', + 'funding' => 'debit', + ], + ]; + $mastercard_credit_details = [ + 'type' => 'card', + 'card' => [ + 'network' => 'mastercard', + 'funding' => 'credit', + ], + ]; + $eps_details = [ + 'type' => 'eps', + ]; + $giropay_details = [ + 'type' => 'giropay', + ]; + $p24_details = [ + 'type' => 'p24', + ]; + $sofort_details = [ + 'type' => 'sofort', + ]; + $bancontact_details = [ + 'type' => 'bancontact', + ]; + $sepa_details = [ + 'type' => 'sepa_debit', + ]; + $ideal_details = [ + 'type' => 'ideal', + ]; + $becs_details = [ + 'type' => 'au_becs_debit', + ]; + + $charge_payment_method_details = [ + $visa_credit_details, + $visa_debit_details, + $mastercard_credit_details, + $giropay_details, + $sofort_details, + $bancontact_details, + $eps_details, + $p24_details, + $ideal_details, + $sepa_details, + $becs_details, + ]; + + $expected_payment_method_titles = [ + 'Visa credit card', + 'Visa debit card', + 'Mastercard credit card', + 'giropay', + 'Sofort', + 'Bancontact', + 'EPS', + 'Przelewy24 (P24)', + 'iDEAL', + 'SEPA Direct Debit', + 'BECS Direct Debit', + ]; + + foreach ( $charge_payment_method_details as $i => $payment_method_details ) { + $this->card_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() ); + } + } + + public function test_payment_methods_show_correct_default_outputs() { + $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); + $this->mock_token_service->expects( $this->any() ) + ->method( 'add_payment_method_to_user' ) + ->will( + $this->returnValue( $mock_token ) + ); + + $mock_user = 'mock_user'; + $mock_payment_method_id = 'pm_mock'; + + $mock_visa_details = [ + 'type' => 'card', + 'card' => [ + 'network' => 'visa', + 'funding' => 'debit', + ], + ]; + $mock_mastercard_details = [ + 'type' => 'card', + 'card' => [ + 'network' => 'mastercard', + 'funding' => 'credit', + ], + ]; + $mock_giropay_details = [ + 'type' => 'giropay', + ]; + $mock_p24_details = [ + 'type' => 'p24', + ]; + $mock_sofort_details = [ + 'type' => 'sofort', + ]; + $mock_bancontact_details = [ + 'type' => 'bancontact', + ]; + $mock_eps_details = [ + 'type' => 'eps', + ]; + $mock_sepa_details = [ + 'type' => 'sepa_debit', + ]; + $mock_ideal_details = [ + 'type' => 'ideal', + ]; + $mock_becs_details = [ + 'type' => 'au_becs_debit', + ]; + $mock_affirm_details = [ + 'type' => 'affirm', + ]; + $mock_afterpay_details = [ + 'type' => 'afterpay_clearpay', + ]; + + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $p24_method = $this->payment_methods['p24']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->payment_methods['afterpay_clearpay']; + + $this->assertEquals( 'card', $card_method->get_id() ); + $this->assertEquals( 'Credit card / debit card', $card_method->get_title() ); + $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) ); + $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) ); + $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); + $this->assertTrue( $card_method->is_reusable() ); + $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) ); + + $this->assertEquals( 'giropay', $giropay_method->get_id() ); + $this->assertEquals( 'giropay', $giropay_method->get_title() ); + $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) ); + $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $giropay_method->is_reusable() ); + + $this->assertEquals( 'p24', $p24_method->get_id() ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() ); + $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) ); + $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $p24_method->is_reusable() ); + + $this->assertEquals( 'sofort', $sofort_method->get_id() ); + $this->assertEquals( 'Sofort', $sofort_method->get_title() ); + $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) ); + $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $sofort_method->is_reusable() ); + + $this->assertEquals( 'bancontact', $bancontact_method->get_id() ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title() ); + $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) ); + $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $bancontact_method->is_reusable() ); + + $this->assertEquals( 'eps', $eps_method->get_id() ); + $this->assertEquals( 'EPS', $eps_method->get_title() ); + $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) ); + $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $eps_method->is_reusable() ); + + $this->assertEquals( 'sepa_debit', $sepa_method->get_id() ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() ); + $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) ); + $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $sepa_method->is_reusable() ); + + $this->assertEquals( 'ideal', $ideal_method->get_id() ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title() ); + $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) ); + $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $ideal_method->is_reusable() ); + + $this->assertEquals( 'au_becs_debit', $becs_method->get_id() ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() ); + $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) ); + $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $becs_method->is_reusable() ); + + $this->assertSame( 'affirm', $affirm_method->get_id() ); + $this->assertSame( 'Affirm', $affirm_method->get_title() ); + $this->assertSame( 'Affirm', $affirm_method->get_title( $mock_affirm_details ) ); + $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $affirm_method->is_reusable() ); + + $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title() ); + $this->assertSame( 'Afterpay', $afterpay_method->get_title( $mock_afterpay_details ) ); + $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $afterpay_method->is_reusable() ); + } + + public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->payment_methods['afterpay_clearpay']; + + $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $giropay_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $sofort_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $bancontact_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $eps_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $sepa_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $p24_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $ideal_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $becs_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $affirm_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $afterpay_method->is_enabled_at_checkout( 'US' ) ); + } + + public function test_only_valid_payment_methods_returned_for_currency() { + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->payment_methods['afterpay_clearpay']; + + WC_Helper_Site_Currency::$mock_site_currency = 'EUR'; + + $account_domestic_currency = 'USD'; + $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); + // BNPLs can accept only domestic payments. + $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); + + WC_Helper_Site_Currency::$mock_site_currency = 'USD'; + + $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); + + WC_Helper_Site_Currency::$mock_site_currency = 'AUD'; + $this->assertTrue( $becs_method->is_currency_valid( $account_domestic_currency ) ); + + // BNPLs can accept only domestic payments. + WC_Helper_Site_Currency::$mock_site_currency = 'USD'; + $account_domestic_currency = 'CAD'; + $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); + + WC_Helper_Site_Currency::$mock_site_currency = ''; + } + + public function test_payment_method_compares_correct_currency() { + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->payment_methods['afterpay_clearpay']; + + WC_Helper_Site_Currency::$mock_site_currency = 'EUR'; + $account_domestic_currency = 'USD'; + + $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); + + global $wp; + $order = WC_Helper_Order::create_order(); + $order_id = $order->get_id(); + $wp->query_vars = [ 'order-pay' => strval( $order_id ) ]; + $order->set_currency( 'USD' ); + + $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) ); + $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) ); + + WC_Helper_Site_Currency::$mock_site_currency = 'USD'; + $wp->query_vars = []; + } + + public function test_create_token_from_setup_intent_adds_token() { + $mock_token = WC_Helper_Token::create_token( 'pm_mock' ); + $mock_setup_intent_id = 'si_mock'; + $mock_user = wp_get_current_user(); + + $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $mock_setup_intent_id ); + + $request->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( + WC_Helper_Intention::create_setup_intention( + [ + 'id' => $mock_setup_intent_id, + 'payment_method' => 'pm_mock', + ] + ) + ); + + $this->mock_token_service->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->with( 'pm_mock', $mock_user ) + ->will( + $this->returnValue( $mock_token ) + ); + + $this->assertEquals( $mock_token, $this->card_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) ); + } + + public function test_exception_will_be_thrown_if_phone_number_is_invalid() { + $order = WC_Helper_Order::create_order(); + $order->set_billing_phone( '+1123456789123456789123' ); + $order->save(); + $this->expectException( Exception::class ); + $this->expectExceptionMessage( 'Invalid phone number.' ); + $this->card_gateway->process_payment( $order->get_id() ); + } + + public function test_remove_link_payment_method_if_card_disabled() { + $link_gateway = $this->get_gateway( Payment_Method::LINK ); + $link_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; + + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_cached_account_data' ) + ->willReturn( + [ + 'capabilities' => [ + 'link_payments' => 'active', + ], + 'capability_requirements' => [ + 'link_payments' => [], + ], + ] + ); + + $this->assertSame( $link_gateway->get_payment_method_ids_enabled_at_checkout(), [] ); + } + + /** + * @dataProvider available_payment_methods_provider + */ + public function test_get_upe_available_payment_methods( $payment_methods, $expected_result ) { + $this->mock_wcpay_account + ->expects( $this->once() ) + ->method( 'get_fees' ) + ->willReturn( $payment_methods ); + + $this->assertEquals( $expected_result, $this->card_gateway->get_upe_available_payment_methods() ); + } + + public function available_payment_methods_provider() { + return [ + 'card only' => [ + [ 'card' => [ 'base' => 0.1 ] ], + [ 'card' ], + ], + 'no match with fees' => [ + [ 'some_other_payment_method' => [ 'base' => 0.1 ] ], + [], + ], + 'multiple matches with fees' => [ + [ + 'card' => [ 'base' => 0.1 ], + 'bancontact' => [ 'base' => 0.2 ], + ], + [ 'card', 'bancontact' ], + ], + 'no fees no methods' => [ + [], + [], + ], + ]; + } + + // This test uses a mock of the gateway class due to get_selected_payment_method()'s reliance on the static method WC_Payments::get_payment_method_map(), which can't be mocked. Refactoring the gateway class to avoid using this static method would allow mocking it in tests. + public function test_process_redirect_setup_intent_succeded() { + $order = WC_Helper_Order::create_order(); + + /** @var WC_Payment_Gateway_WCPay */ + $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) + ->setConstructorArgs( + [ + $this->mock_api_client, + $this->mock_wcpay_account, + $this->mock_customer_service, + $this->mock_token_service, + $this->mock_action_scheduler_service, + $this->payment_methods['card'], + [ $this->payment_methods ], + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service, + ] + ) + ->onlyMethods( + [ + 'manage_customer_details_for_order', + 'get_selected_payment_method', + ] + ) + ->getMock(); + + $order_id = $order->get_id(); + $save_payment_method = true; + $user = wp_get_current_user(); + $intent_status = Intent_Status::SUCCEEDED; + $client_secret = 'cs_mock'; + $customer_id = 'cus_mock'; + $intent_id = 'si_mock'; + $payment_method_id = 'pm_mock'; + $token = WC_Helper_Token::create_token( $payment_method_id ); + + // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. + $order->update_meta_data( '_intent_id', $intent_id ); + $order->save(); + + $card_method = $this->payment_methods['card']; + + $order->set_shipping_total( 0 ); + $order->set_shipping_tax( 0 ); + $order->set_cart_tax( 0 ); + $order->set_total( 0 ); + $order->save(); + + $setup_intent = WC_Helper_Intention::create_setup_intention( + [ + 'id' => $intent_id, + 'client_secret' => $client_secret, + 'status' => $intent_status, + 'payment_method' => $payment_method_id, + 'payment_method_options' => [ + 'card' => [ + 'request_three_d_secure' => 'automatic', + ], + ], + 'last_setup_error' => [], + ] + ); + + $mock_gateway->expects( $this->once() ) + ->method( 'manage_customer_details_for_order' ) + ->will( + $this->returnValue( [ $user, $customer_id ] ) + ); + + $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $intent_id ); + + $request->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $setup_intent ); + + $this->mock_token_service->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->will( + $this->returnValue( $token ) + ); + + $mock_gateway->expects( $this->any() ) + ->method( 'get_selected_payment_method' ) + ->willReturn( $card_method ); + + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + + $result_order = wc_get_order( $order_id ); + + $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); + $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); + $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); + $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); + $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() ); + $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) ); + } + + // This test uses a mock of the gateway class due to get_selected_payment_method()'s reliance on the static method WC_Payments::get_payment_method_map(), which can't be mocked. Refactoring the gateway class to avoid using this static method would allow mocking it in tests. + public function test_process_redirect_payment_save_payment_token() { + /** @var WC_Payment_Gateway_WCPay */ + $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) + ->setConstructorArgs( + [ + $this->mock_api_client, + $this->mock_wcpay_account, + $this->mock_customer_service, + $this->mock_token_service, + $this->mock_action_scheduler_service, + $this->payment_methods['card'], + [ $this->payment_methods ], + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service, + ] + ) + ->onlyMethods( + [ + 'manage_customer_details_for_order', + 'get_selected_payment_method', + ] + ) + ->getMock(); + + $order = WC_Helper_Order::create_order(); + $order_id = $order->get_id(); + $save_payment_method = true; + $user = wp_get_current_user(); + $intent_status = Intent_Status::PROCESSING; + $intent_metadata = [ 'order_id' => (string) $order_id ]; + $charge_id = 'ch_mock'; + $customer_id = 'cus_mock'; + $intent_id = 'pi_mock'; + $payment_method_id = 'pm_mock'; + $token = WC_Helper_Token::create_token( $payment_method_id ); + + // Supply the order with the intent id so that it can be retrieved during the redirect payment processing. + $order->update_meta_data( '_intent_id', $intent_id ); + $order->save(); + + $card_method = $this->payment_methods['card']; + + $payment_intent = WC_Helper_Intention::create_intention( + [ + 'status' => $intent_status, + 'metadata' => $intent_metadata, + ] + ); + + $mock_gateway->expects( $this->once() ) + ->method( 'manage_customer_details_for_order' ) + ->will( + $this->returnValue( [ $user, $customer_id ] ) + ); + + $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ) + ->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $payment_intent ); + + $this->mock_token_service->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->will( + $this->returnValue( $token ) + ); + + $mock_gateway->expects( $this->any() ) + ->method( 'get_selected_payment_method' ) + ->willReturn( $card_method ); + + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method ); + + $result_order = wc_get_order( $order_id ); + $note = wc_get_order_notes( + [ + 'order_id' => $order_id, + 'limit' => 1, + ] + )[0]; + + $this->assertStringContainsString( 'authorized', $note->content ); + $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) ); + $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) ); + $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) ); + $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) ); + $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) ); + $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() ); + $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) ); + } + + public function test_get_payment_methods_with_post_request_context() { + $order = WC_Helper_Order::create_order(); + $payment_information = new Payment_Information( 'pm_mock', $order ); + + $_POST['payment_method'] = 'woocommerce_payments'; + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + + unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification + } + + public function test_get_payment_methods_without_post_request_context() { + $token = WC_Helper_Token::create_token( 'pm_mock' ); + $order = WC_Helper_Order::create_order(); + $payment_information = new Payment_Information( 'pm_mock', $order, null, $token ); + + unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + } + + public function test_get_payment_methods_without_request_context_or_token() { + $payment_information = new Payment_Information( 'pm_mock' ); + + unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification + + $gateway = WC_Payments::get_gateway(); + WC_Payments::set_gateway( $this->card_gateway ); + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + + WC_Payments::set_gateway( $gateway ); + } + + public function test_get_payment_methods_from_gateway_id_upe() { + WC_Helper_Order::create_order(); + + $gateway = WC_Payments::get_gateway(); + + $payment_methods = $this->card_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT ); + $this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods ); + + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_cached_account_data' ) + ->willReturn( + [ + 'capabilities' => [ + 'link_payments' => 'active', + 'card_payments' => 'active', + ], + 'capability_requirements' => [ + 'link_payments' => [], + 'card_payments' => [], + ], + ] + ); + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ Payment_Method::LINK, Payment_Method::CARD ]; + WC_Payments::set_gateway( $this->card_gateway ); + $payment_methods = $this->card_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID ); + $this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods ); + + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ Payment_Method::CARD ]; + $payment_methods = $this->card_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 ); + } + + public function test_display_gateway_html() { + foreach ( $this->gateways as $gateway ) { + /** + * This tests each payment method output separately without concatenating the output + * into 1 single buffer. Each iteration has 1 assertion. + */ + ob_start(); + $gateway->display_gateway_html(); + $actual_output = ob_get_contents(); + ob_end_clean(); + + $this->assertStringContainsString( '
', $actual_output ); + } + } + + public function test_should_not_use_stripe_platform_on_checkout_page_for_non_card() { + foreach ( $this->get_gateways_excluding( [ Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->should_use_stripe_platform_on_checkout_page() ); + } + } + public function test_attach_exchange_info_to_order_with_no_conversion() { $charge_id = 'ch_mock'; @@ -290,7 +1191,7 @@ public function test_attach_exchange_info_to_order_with_no_conversion() { ->method( 'get_account_default_currency' ) ->willReturn( 'usd' ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); // The meta key should not be set. $this->assertEquals( '', $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); @@ -309,7 +1210,7 @@ public function test_attach_exchange_info_to_order_with_different_account_curren ->method( 'get_account_default_currency' ) ->willReturn( 'jpy' ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); // The meta key should not be set. $this->assertEquals( '', $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); @@ -345,7 +1246,7 @@ public function test_attach_exchange_info_to_order_with_zero_decimal_order_curre ] ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); $this->assertEquals( 0.009414, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); } @@ -378,7 +1279,7 @@ public function test_attach_exchange_info_to_order_with_different_order_currency ] ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); $this->assertEquals( 0.853, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); } @@ -394,7 +1295,7 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox(); + $this->card_gateway->save_payment_method_checkbox(); } public function test_save_payment_method_checkbox_not_displayed_when_force_checked() { @@ -408,13 +1309,13 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox( true ); + $this->card_gateway->save_payment_method_checkbox( true ); } public function test_save_payment_method_checkbox_not_displayed_when_stripe_platform_account_used() { // Setup the test so that should_use_stripe_platform_on_checkout_page returns true. $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); + $this->card_gateway->update_option( 'platform_checkout', 'yes' ); add_filter( 'woocommerce_is_checkout', '__return_true' ); WC()->session->init(); WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 1 ); @@ -430,7 +1331,7 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox( false ); + $this->card_gateway->save_payment_method_checkbox( false ); remove_filter( 'woocommerce_is_checkout', '__return_true' ); WC()->cart->empty_cart(); @@ -457,7 +1358,7 @@ public function test_capture_charge_success() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $notes = wc_get_order_notes( [ @@ -509,7 +1410,7 @@ public function test_capture_charge_success_non_usd() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'currency' => 'eur' ] ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $notes = wc_get_order_notes( [ @@ -558,7 +1459,7 @@ public function test_capture_charge_failure() { ->method( 'format_response' ) ->willReturn( $mock_intent ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -610,7 +1511,7 @@ public function test_capture_charge_failure_non_usd() { ->method( 'format_response' ) ->willReturn( $mock_intent ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -664,7 +1565,7 @@ public function test_capture_charge_api_failure() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -723,7 +1624,7 @@ public function test_capture_charge_api_failure_non_usd() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -778,7 +1679,7 @@ public function test_capture_charge_expired() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -833,7 +1734,7 @@ public function test_capture_charge_metadata() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); - $result = $this->wcpay_gateway->capture_charge( $order, true, [] ); + $result = $this->card_gateway->capture_charge( $order, true, [] ); $note = wc_get_order_notes( [ @@ -883,7 +1784,7 @@ public function test_capture_charge_without_level3() { ->expects( $this->never() ) ->method( 'get_account_country' ); // stand-in for get_level3_data_from_order. - $result = $this->wcpay_gateway->capture_charge( $order, false ); + $result = $this->card_gateway->capture_charge( $order, false ); $notes = wc_get_order_notes( [ @@ -1075,7 +1976,7 @@ public function test_cancel_authorization_handles_api_exception_when_canceling() ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::CANCELED ] ) ); - $this->wcpay_gateway->cancel_authorization( $order ); + $this->card_gateway->cancel_authorization( $order ); $note = wc_get_order_notes( [ @@ -1110,7 +2011,7 @@ public function test_cancel_authorization_handles_all_api_exceptions() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'ignore this', 'test', 123 ) ) ); - $this->wcpay_gateway->cancel_authorization( $order ); + $this->card_gateway->cancel_authorization( $order ); $note = wc_get_order_notes( [ @@ -1125,7 +2026,7 @@ public function test_cancel_authorization_handles_all_api_exceptions() { } public function test_add_payment_method_no_method() { - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1159,7 +2060,7 @@ public function test_create_and_confirm_setup_intent_existing_customer() { ) ); - $result = $this->wcpay_gateway->create_and_confirm_setup_intent(); + $result = $this->card_gateway->create_and_confirm_setup_intent(); $this->assertSame( 'seti_mock_123', $result->get_id() ); } @@ -1186,13 +2087,13 @@ public function test_create_and_confirm_setup_intent_no_customer() { ) ); - $result = $this->wcpay_gateway->create_and_confirm_setup_intent(); + $result = $this->card_gateway->create_and_confirm_setup_intent(); $this->assertSame( 'seti_mock_123', $result->get_id() ); } public function test_add_payment_method_no_intent() { - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1222,7 +2123,7 @@ public function test_add_payment_method_success() { ->method( 'add_payment_method_to_user' ) ->with( 'pm_mock', wp_get_current_user() ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'success', $result['result'] ); } @@ -1241,7 +2142,7 @@ public function test_add_payment_method_no_customer() { ->expects( $this->never() ) ->method( 'add_payment_method_to_user' ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1263,7 +2164,7 @@ public function test_add_payment_method_cancelled_intent() { ->expects( $this->never() ) ->method( 'add_payment_method_to_user' ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); wc_clear_notices(); @@ -1278,7 +2179,7 @@ public function test_schedule_order_tracking_with_wrong_payment_gateway() { ->expects( $this->never() ) ->method( 'schedule_job' ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_with_sift_disabled() { @@ -1297,7 +2198,7 @@ public function test_schedule_order_tracking_with_sift_disabled() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_with_no_payment_method_id() { @@ -1319,7 +2220,7 @@ public function test_schedule_order_tracking_with_no_payment_method_id() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking() { @@ -1343,7 +2244,7 @@ public function test_schedule_order_tracking() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_on_already_created_order() { @@ -1367,12 +2268,12 @@ public function test_schedule_order_tracking_on_already_created_order() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_outputs_payments_settings_screen() { ob_start(); - $this->wcpay_gateway->output_payments_settings_screen(); + $this->card_gateway->output_payments_settings_screen(); $output = ob_get_clean(); $this->assertStringMatchesFormat( '%aid="wcpay-account-settings-container"%a', $output ); } @@ -1380,7 +2281,7 @@ public function test_outputs_payments_settings_screen() { public function test_outputs_express_checkout_settings_screen() { $_GET['method'] = 'foo'; ob_start(); - $this->wcpay_gateway->output_payments_settings_screen(); + $this->card_gateway->output_payments_settings_screen(); $output = ob_get_clean(); $this->assertStringMatchesFormat( '%aid="wcpay-express-checkout-settings-container"%a', $output ); $this->assertStringMatchesFormat( '%adata-method-id="foo"%a', $output ); @@ -1394,11 +2295,11 @@ public function test_outputs_express_checkout_settings_screen() { public function test_validate_account_statement_descriptor_field( $is_valid, $value, $expected = null ) { $key = 'account_statement_descriptor'; if ( $is_valid ) { - $validated_value = $this->wcpay_gateway->validate_account_statement_descriptor_field( $key, $value ); + $validated_value = $this->card_gateway->validate_account_statement_descriptor_field( $key, $value ); $this->assertEquals( $expected ?? $value, $validated_value ); } else { $this->expectExceptionMessage( 'Customer bank statement is invalid.' ); - $this->wcpay_gateway->validate_account_statement_descriptor_field( $key, $value ); + $this->card_gateway->validate_account_statement_descriptor_field( $key, $value ); } } @@ -1435,14 +2336,14 @@ public function test_payment_request_form_field_defaults() { 'cart', 'checkout', ], - $this->wcpay_gateway->get_option( 'payment_request_button_locations' ) + $this->card_gateway->get_option( 'payment_request_button_locations' ) ); $this->assertEquals( 'medium', - $this->wcpay_gateway->get_option( 'payment_request_button_size' ) + $this->card_gateway->get_option( 'payment_request_button_size' ) ); - $form_fields = $this->wcpay_gateway->get_form_fields(); + $form_fields = $this->card_gateway->get_form_fields(); $this->assertEquals( [ @@ -1472,7 +2373,7 @@ public function test_payment_gateway_enabled_for_supported_currency() { ] ) ); - $this->assertTrue( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertTrue( $this->card_gateway->is_available_for_current_currency() ); } public function test_payment_gateway_enabled_for_empty_supported_currency_list() { @@ -1482,7 +2383,7 @@ public function test_payment_gateway_enabled_for_empty_supported_currency_list() [] ) ); - $this->assertTrue( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertTrue( $this->card_gateway->is_available_for_current_currency() ); } public function test_payment_gateway_disabled_for_unsupported_currency() { @@ -1493,7 +2394,7 @@ public function test_payment_gateway_disabled_for_unsupported_currency() { ] ) ); - $this->assertFalse( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertFalse( $this->card_gateway->is_available_for_current_currency() ); } public function test_process_payment_for_order_not_from_request() { @@ -1519,7 +2420,7 @@ public function test_process_payment_for_order_not_from_request() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_for_order_rejects_with_cached_minimum_amount() { @@ -1534,10 +2435,10 @@ public function test_process_payment_for_order_rejects_with_cached_minimum_amoun $this->expectException( Exception::class ); $this->expectExceptionMessage( 'The selected payment method requires a total amount of at least $0.50.' ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_not_added_to_payment_intent_if_not_required() { + public function test_set_mandate_data_to_payment_intent_if_not_required() { $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1555,13 +2456,13 @@ public function test_mandate_data_not_added_to_payment_intent_if_not_required() $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - // Mandate data is required for SEPA and Stripe Link only, $this->wcpay_gateway is created with card hence mandate data should not be added. - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + // Mandate data is required for SEPA and Stripe Link only, $this->card_gateway is created with card hence mandate data should not be added. + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_added_to_payment_intent_if_required() { + public function test_set_mandate_data_to_payment_intent_if_required() { // Mandate data is required for SEPA and Stripe Link, hence creating the gateway with a SEPA payment method should add mandate data. - $gateway = $this->create_gateway_with( new Sepa_Payment_Method( $this->mock_token_service ) ); + $gateway = $this->get_gateway( Payment_Method::SEPA ); $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1593,9 +2494,9 @@ function ( $data ) { $gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_not_added_to_setup_intent_request_when_link_is_disabled() { + public function test_set_mandate_data_with_setup_intent_request_when_link_is_disabled() { // Disabled link is reflected in upe_enabled_payment_method_ids: when link is disabled, the array contains only card. - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1631,11 +2532,11 @@ public function test_mandate_data_not_added_to_setup_intent_request_when_link_is $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_added_to_setup_intent_request_when_link_is_enabled() { - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; + public function test_set_mandate_data_with_setup_intent_request_when_link_is_enabled() { + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1681,8 +2582,38 @@ function ( $data ) { ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + } + + public function test_is_mandate_data_required_card_and_link() { + $this->card_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::LINK ] ); + $this->assertTrue( $this->card_gateway->is_mandate_data_required() ); + } + + public function test_is_mandate_data_required_sepa() { + $sepa = $this->get_gateway( Payment_Method::SEPA ); + $this->assertTrue( $sepa->is_mandate_data_required() ); + } + + public function test_is_mandate_data_required_returns_false() { + foreach ( $this->get_gateways_excluding( [ Payment_Method::SEPA, Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->is_mandate_data_required() ); + } + } + + public function test_non_reusable_gateways_not_available_when_changing_payment_method_for_card() { + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + foreach ( $this->get_gateways_excluding( [ Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->is_available() ); + } } public function test_process_payment_for_order_cc_payment_method() { @@ -1705,7 +2636,7 @@ public function test_process_payment_for_order_cc_payment_method() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_for_order_upe_payment_method() { @@ -1728,7 +2659,7 @@ public function test_process_payment_for_order_upe_payment_method() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() { @@ -1780,7 +2711,7 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up $this->expectExceptionMessage( $message ); try { - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } catch ( Exception $e ) { $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) ); throw $e; @@ -1799,7 +2730,7 @@ public function test_process_payment_rejects_if_missing_fraud_prevention_token() $this->expectException( Exception::class ); $this->expectExceptionMessage( "We're not able to process this payment. Please refresh the page and try again." ); - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } public function test_process_payment_rejects_if_invalid_fraud_prevention_token() { @@ -1822,7 +2753,7 @@ public function test_process_payment_rejects_if_invalid_fraud_prevention_token() $this->expectException( Exception::class ); $this->expectExceptionMessage( "We're not able to process this payment. Please refresh the page and try again." ); - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } public function test_process_payment_continues_if_valid_fraud_prevention_token() { @@ -1872,7 +2803,7 @@ public function test_get_upe_enabled_payment_method_statuses_with_empty_cache() 'requirements' => [], ], ], - $this->wcpay_gateway->get_upe_enabled_payment_method_statuses() + $this->card_gateway->get_upe_enabled_payment_method_statuses() ); } @@ -1906,7 +2837,7 @@ public function test_get_upe_enabled_payment_method_statuses_with_cache() { 'requirements' => [], ], ], - $this->wcpay_gateway->get_upe_enabled_payment_method_statuses() + $this->card_gateway->get_upe_enabled_payment_method_statuses() ); } @@ -1920,36 +2851,36 @@ public function test_woopay_form_field_defaults() { 'cart', 'checkout', ], - $this->wcpay_gateway->get_option( 'platform_checkout_button_locations' ) + $this->card_gateway->get_option( 'platform_checkout_button_locations' ) ); $this->assertEquals( 'By placing this order, you agree to our [terms] and understand our [privacy_policy].', - $this->wcpay_gateway->get_option( 'platform_checkout_custom_message' ) + $this->card_gateway->get_option( 'platform_checkout_custom_message' ) ); } public function test_is_woopay_enabled_returns_true() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); + $this->card_gateway->update_option( 'platform_checkout', 'yes' ); wp_set_current_user( 1 ); add_filter( 'woocommerce_is_checkout', '__return_true' ); - $this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->wcpay_gateway ) ); + $this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->card_gateway ) ); remove_filter( 'woocommerce_is_checkout', '__return_true' ); } public function test_should_use_stripe_platform_on_checkout_page_not_woopay_eligible() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => false ] ); - $this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() ); + $this->assertFalse( $this->card_gateway->should_use_stripe_platform_on_checkout_page() ); } public function test_should_use_stripe_platform_on_checkout_page_not_woopay() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'no' ); + $this->card_gateway->update_option( 'platform_checkout', 'no' ); - $this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() ); + $this->assertFalse( $this->card_gateway->should_use_stripe_platform_on_checkout_page() ); } public function is_woopay_falsy_value_provider() { @@ -1971,13 +2902,13 @@ public function test_is_in_dev_mode() { $mode = WC_Payments::mode(); $mode->dev(); - $this->assertTrue( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertTrue( $this->card_gateway->is_in_dev_mode() ); $mode->test(); - $this->assertFalse( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertFalse( $this->card_gateway->is_in_dev_mode() ); $mode->live(); - $this->assertFalse( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertFalse( $this->card_gateway->is_in_dev_mode() ); } /** @@ -1987,13 +2918,13 @@ public function test_is_in_test_mode() { $mode = WC_Payments::mode(); $mode->dev(); - $this->assertTrue( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertTrue( $this->card_gateway->is_in_test_mode() ); $mode->test(); - $this->assertTrue( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertTrue( $this->card_gateway->is_in_test_mode() ); $mode->live(); - $this->assertFalse( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertFalse( $this->card_gateway->is_in_test_mode() ); } /** @@ -2060,7 +2991,7 @@ public function test_should_use_new_process_requires_dev_mode() { $mock_router->expects( $this->never() ) ->method( 'should_use_new_payment_process' ); - $this->assertFalse( $this->wcpay_gateway->should_use_new_process( $order ) ); + $this->assertFalse( $this->card_gateway->should_use_new_process( $order ) ); } public function test_should_use_new_process_returns_false_if_feature_unavailable() { @@ -2078,7 +3009,7 @@ public function test_should_use_new_process_returns_false_if_feature_unavailable ->willReturn( false ); // Act: Call the method. - $result = $this->wcpay_gateway->should_use_new_process( $order ); + $result = $this->card_gateway->should_use_new_process( $order ); $this->assertFalse( $result ); } @@ -2099,7 +3030,7 @@ public function test_should_use_new_process_uses_the_new_process() { ->willReturn( true ); // Act: Call the method. - $result = $this->wcpay_gateway->should_use_new_process( $order ); + $result = $this->card_gateway->should_use_new_process( $order ); $this->assertTrue( $result ); } @@ -2110,7 +3041,7 @@ public function test_should_use_new_process_adds_base_factor() { $order = WC_Helper_Order::create_order( 1, 0 ); $this->expect_router_factor( Factor::NEW_PAYMENT_PROCESS(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_no_payment() { @@ -2120,7 +3051,7 @@ public function test_should_use_new_process_determines_positive_no_payment() { $order = WC_Helper_Order::create_order( 1, 0 ); $this->expect_router_factor( Factor::NO_PAYMENT(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_no_payment() { @@ -2132,7 +3063,7 @@ public function test_should_use_new_process_determines_negative_no_payment() { $order->save(); $this->expect_router_factor( Factor::NO_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_no_payment_when_saving_pm() { @@ -2145,7 +3076,7 @@ public function test_should_use_new_process_determines_negative_no_payment_when_ $_POST['wc-woocommerce_payments-new-payment-method'] = 'pm_XYZ'; $this->expect_router_factor( Factor::NO_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_use_saved_pm() { @@ -2160,7 +3091,7 @@ public function test_should_use_new_process_determines_positive_use_saved_pm() { $_POST['wc-woocommerce_payments-payment-token'] = $token->get_id(); $this->expect_router_factor( Factor::USE_SAVED_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_use_saved_pm() { @@ -2174,7 +3105,7 @@ public function test_should_use_new_process_determines_negative_use_saved_pm() { $_POST['wc-woocommerce_payments-payment-token'] = 'new'; $this->expect_router_factor( Factor::USE_SAVED_PM(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_save_pm() { @@ -2186,7 +3117,7 @@ public function test_should_use_new_process_determines_positive_save_pm() { $_POST['wc-woocommerce_payments-new-payment-method'] = '1'; $this->expect_router_factor( Factor::SAVE_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_save_pm_for_subscription() { @@ -2198,7 +3129,7 @@ public function test_should_use_new_process_determines_positive_save_pm_for_subs WC_Subscriptions::$wcs_order_contains_subscription = '__return_true'; $this->expect_router_factor( Factor::SAVE_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_save_pm() { @@ -2214,7 +3145,7 @@ public function test_should_use_new_process_determines_negative_save_pm() { $_POST['wc-woocommerce_payments-payment-token'] = $token->get_id(); $this->expect_router_factor( Factor::SAVE_PM(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_subscription_signup() { @@ -2226,7 +3157,7 @@ public function test_should_use_new_process_determines_positive_subscription_sig WC_Subscriptions::$wcs_order_contains_subscription = '__return_true'; $this->expect_router_factor( Factor::SUBSCRIPTION_SIGNUP(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_subscription_signup() { @@ -2238,7 +3169,7 @@ public function test_should_use_new_process_determines_negative_subscription_sig WC_Subscriptions::$wcs_order_contains_subscription = '__return_false'; $this->expect_router_factor( Factor::SUBSCRIPTION_SIGNUP(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_woopay_payment() { @@ -2250,7 +3181,7 @@ public function test_should_use_new_process_determines_positive_woopay_payment() $_POST['platform-checkout-intent'] = 'pi_ZYX'; $this->expect_router_factor( Factor::WOOPAY_PAYMENT(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_woopay_payment() { @@ -2263,7 +3194,7 @@ public function test_should_use_new_process_determines_negative_woopay_payment() unset( $_POST['platform-checkout-intent'] ); $this->expect_router_factor( Factor::WOOPAY_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } /** @@ -2281,7 +3212,7 @@ public function test_should_use_new_process_determines_negative_wcpay_subscripti add_filter( 'wcpay_is_wcpay_subscriptions_enabled', '__return_true' ); $this->expect_router_factor( Factor::WCPAY_SUBSCRIPTION_SIGNUP(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_new_process_payment() { @@ -2306,7 +3237,7 @@ public function test_new_process_payment() { ->with( $order->get_id() ) ->willReturn( $mock_state ); - $result = $this->wcpay_gateway->process_payment( $order->get_id() ); + $result = $this->card_gateway->process_payment( $order->get_id() ); $this->assertSame( [ 'result' => 'success', @@ -2316,6 +3247,55 @@ public function test_new_process_payment() { ); } + public function test_process_payment_returns_correct_redirect() { + $order = WC_Helper_Order::create_order(); + $_POST = [ 'wcpay-payment-method' => 'pm_mock' ]; + + $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 ) + ->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( + WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ) + ); + + $this->mock_token_service + ->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->willReturn( new WC_Payment_Token_CC() ); + + $result = $this->card_gateway->process_payment( $order->get_id() ); + + $this->assertEquals( 'success', $result['result'] ); + $this->assertEquals( $order->get_checkout_order_received_url(), $result['redirect'] ); + } + + public function test_process_payment_returns_correct_redirect_when_using_payment_request() { + $order = WC_Helper_Order::create_order(); + $_POST['payment_request_type'] = 'google_pay'; + $_POST = [ 'wcpay-payment-method' => 'pm_mock' ]; + + $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 ) + ->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( + WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] ) + ); + + $this->mock_token_service + ->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->willReturn( new WC_Payment_Token_CC() ); + + $result = $this->card_gateway->process_payment( $order->get_id() ); + + $this->assertEquals( 'success', $result['result'] ); + $this->assertEquals( $order->get_checkout_order_received_url(), $result['redirect'] ); + } + + public function is_proper_intent_used_with_order_returns_false() { + $this->assertFalse( $this->card_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) ); + } + /** * Sets up the expectation for a certain factor for the new payment * process to be either set or unset. @@ -2359,20 +3339,74 @@ private function create_charge_object() { return new WC_Payments_API_Charge( $this->mock_charge_id, 1500, $created ); } - private function create_gateway_with( $payment_method ) { - return 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, - $payment_method, - [ $payment_method ], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service + private function init_payment_methods() { + $payment_methods = []; + + $payment_method_classes = [ + CC_Payment_Method::class, + Bancontact_Payment_Method::class, + Sepa_Payment_Method::class, + Giropay_Payment_Method::class, + Sofort_Payment_Method::class, + P24_Payment_Method::class, + Ideal_Payment_Method::class, + Becs_Payment_Method::class, + Eps_Payment_Method::class, + Link_Payment_Method::class, + Affirm_Payment_Method::class, + Afterpay_Payment_Method::class, + Klarna_Payment_Method::class, + ]; + + foreach ( $payment_method_classes as $payment_method_class ) { + $payment_method = new $payment_method_class( $this->mock_token_service ); + $payment_methods[ $payment_method->get_id() ] = new $payment_method_class( $this->mock_token_service ); + } + $this->payment_methods = $payment_methods; + } + + private function init_gateways() { + $this->init_payment_methods(); + $gateways = []; + + foreach ( $this->payment_methods as $payment_method ) { + $gateways[] = 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, + $payment_method, + $this->payment_methods, + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service + ); + } + + $this->gateways = $gateways; + $this->card_gateway = $gateways[0]; + } + + private function get_gateways_excluding( $excluded_payment_method_ids ) { + return array_filter( + $this->gateways, + function( $gateway ) use ( $excluded_payment_method_ids ) { + return ! in_array( $gateway->get_payment_method()->get_id(), $excluded_payment_method_ids, true ); + } ); } + + private function get_gateway( $payment_method_id ) { + return ( array_values( + array_filter( + $this->gateways, + function( $gateway ) use ( $payment_method_id ) { + return $payment_method_id === $gateway->get_payment_method()->get_id(); + } + ) + ) )[0] ?? null; + } } From c576435b28cdcacf749608a64bc1d47c02af3622 Mon Sep 17 00:00:00 2001 From: Dan Paun <82826872+dpaun1985@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:22:38 +0200 Subject: [PATCH 47/60] Add events for interactions with transactions page (#8020) Co-authored-by: Dan Paun --- changelog/add-7961-track-transactions-search | 4 ++++ client/transactions/declarations.d.ts | 1 + client/transactions/filters/index.tsx | 9 +++++++++ 3 files changed, 14 insertions(+) create mode 100644 changelog/add-7961-track-transactions-search diff --git a/changelog/add-7961-track-transactions-search b/changelog/add-7961-track-transactions-search new file mode 100644 index 00000000000..6781c1b99f6 --- /dev/null +++ b/changelog/add-7961-track-transactions-search @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Track filtering interactions on the Transactions page. diff --git a/client/transactions/declarations.d.ts b/client/transactions/declarations.d.ts index 07b2db0955c..08ff94e4892 100644 --- a/client/transactions/declarations.d.ts +++ b/client/transactions/declarations.d.ts @@ -38,6 +38,7 @@ declare module '@woocommerce/components' { path?: string; query?: Query; showDatePicker: boolean; + onAdvancedFilterAction?: ( args: string ) => void; // some properties are omitted, as we are not currently using them } diff --git a/client/transactions/filters/index.tsx b/client/transactions/filters/index.tsx index da485ef54e1..c3733ffbd81 100644 --- a/client/transactions/filters/index.tsx +++ b/client/transactions/filters/index.tsx @@ -11,6 +11,7 @@ import { getQuery } from '@woocommerce/navigation'; import { getFilters, getAdvancedFilters } from './config'; import { formatCurrencyName } from '../../utils/currency'; import './style.scss'; +import wcpayTracks from 'tracks'; interface TransactionsFiltersProps { storeCurrencies: string[]; @@ -53,6 +54,14 @@ export const TransactionsFilters = ( { showDatePicker={ false } path="/payments/transactions" query={ getQuery() } + onAdvancedFilterAction={ ( event ) => { + if ( event === 'filter' ) { + wcpayTracks.recordEvent( 'page_view', { + path: 'payments_transactions', + filter: 'advanced', + } ); + } + } } />
); From 945c67296d56b3489e5dfe6b1bafbcd7150c23bb Mon Sep 17 00:00:00 2001 From: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:07:30 +0200 Subject: [PATCH 48/60] Fix incorrect test mode notice when left KYC early after going live from builder mode (#8049) Co-authored-by: oaratovskyi --- changelog/fix-7819-incorrect-test-mode-notice | 4 ++++ includes/class-wc-payments-account.php | 24 +++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 changelog/fix-7819-incorrect-test-mode-notice diff --git a/changelog/fix-7819-incorrect-test-mode-notice b/changelog/fix-7819-incorrect-test-mode-notice new file mode 100644 index 00000000000..166132e2a26 --- /dev/null +++ b/changelog/fix-7819-incorrect-test-mode-notice @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix incorrect test mode notice when left KYC early after going live from builder mode diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index fa4d3b45e45..690d186cfb6 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -1499,18 +1499,18 @@ private function finalize_connection( $state, $mode ) { $event_properties ); - wp_safe_redirect( - add_query_arg( - [ - 'wcpay-state' => false, - 'wcpay-account-id' => false, - 'wcpay-live-publishable-key' => false, - 'wcpay-test-publishable-key' => false, - 'wcpay-mode' => false, - 'wcpay-connection-success' => '1', - ] - ) - ); + $params = [ + 'wcpay-state' => false, + 'wcpay-account-id' => false, + 'wcpay-live-publishable-key' => false, + 'wcpay-test-publishable-key' => false, + 'wcpay-mode' => false, + ]; + if ( empty( $_GET['wcpay-connection-error'] ) ) { + $params['wcpay-connection-success'] = '1'; + } + + wp_safe_redirect( add_query_arg( $params ) ); exit; } From ef848659f1ee25f27ae2f78d65d2d695d395c6f4 Mon Sep 17 00:00:00 2001 From: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:21:53 +0200 Subject: [PATCH 49/60] Fix reverse WPCOM url in Safe Mode (#8033) Co-authored-by: oaratovskyi --- changelog/8025-fix-safe-mode-message-reverse-host | 4 ++++ woocommerce-payments.php | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 changelog/8025-fix-safe-mode-message-reverse-host diff --git a/changelog/8025-fix-safe-mode-message-reverse-host b/changelog/8025-fix-safe-mode-message-reverse-host new file mode 100644 index 00000000000..a4b72307417 --- /dev/null +++ b/changelog/8025-fix-safe-mode-message-reverse-host @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix Safe Mode message reversed host diff --git a/woocommerce-payments.php b/woocommerce-payments.php index 7f453eb5c35..ee3eedb1409 100644 --- a/woocommerce-payments.php +++ b/woocommerce-payments.php @@ -333,7 +333,16 @@ function wcpay_get_jetpack_idc_custom_content(): array { $urls = Automattic\Jetpack\Identity_Crisis::get_mismatched_urls(); if ( false !== $urls ) { $current_url = untrailingslashit( $urls['current_url'] ); - $wpcom_url = untrailingslashit( $urls['wpcom_url'] ); + /** + * Undo the reverse the Jetpack IDC library is doing since we want to display the URL. + * + * @see https://github.com/Automattic/jetpack-identity-crisis/blob/trunk/src/class-identity-crisis.php#L471 + */ + $idc_sync_error = Automattic\Jetpack\Identity_Crisis::check_identity_crisis(); + if ( is_array( $idc_sync_error ) && ! empty( $idc_sync_error['reversed_url'] ) ) { + $urls['wpcom_url'] = strrev( $urls['wpcom_url'] ); + } + $wpcom_url = untrailingslashit( $urls['wpcom_url'] ); $custom_content['migrateCardBodyText'] = sprintf( /* translators: %1$s: The current site domain name. %2$s: The original site domain name. Please keep hostname tags in your translation so that they can be formatted properly. %3$s: WooPayments. */ From e375e8b6356ede5bf9105b483bbdc98cec41b5ba Mon Sep 17 00:00:00 2001 From: Daniel Mallory Date: Fri, 19 Jan 2024 15:27:38 +0000 Subject: [PATCH 50/60] Update Dev/Sandbox Mode Choice Design (#8002) Co-authored-by: Vlad Olaru --- changelog/dev-7731-update-dev-mode-choice | 4 + client/components/radio-card/index.tsx | 75 --------------- client/components/radio-card/style.scss | 57 ------------ .../test/__snapshots__/index.tsx.snap | 58 ------------ client/components/radio-card/test/index.tsx | 55 ----------- client/onboarding/steps/mode-choice.tsx | 92 +++++++++---------- client/onboarding/steps/test/mode-choice.tsx | 15 ++- client/onboarding/strings.tsx | 87 ++++++++++++------ client/onboarding/style.scss | 44 +++++++++ 9 files changed, 159 insertions(+), 328 deletions(-) create mode 100644 changelog/dev-7731-update-dev-mode-choice delete mode 100644 client/components/radio-card/index.tsx delete mode 100644 client/components/radio-card/style.scss delete mode 100644 client/components/radio-card/test/__snapshots__/index.tsx.snap delete mode 100644 client/components/radio-card/test/index.tsx diff --git a/changelog/dev-7731-update-dev-mode-choice b/changelog/dev-7731-update-dev-mode-choice new file mode 100644 index 00000000000..2c2ac2efae9 --- /dev/null +++ b/changelog/dev-7731-update-dev-mode-choice @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Updates to the styling of the onboarding mode selection page. diff --git a/client/components/radio-card/index.tsx b/client/components/radio-card/index.tsx deleted file mode 100644 index f8a2f9f74de..00000000000 --- a/client/components/radio-card/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/** - * External dependencies - */ -import React from 'react'; -import classNames from 'classnames'; - -/** - * Internal dependencies - */ -import './style.scss'; - -interface Props { - name: string; - selected: string; - options: { - label: string; - value: string; - icon: React.ReactNode; - content: React.ReactNode; - }[]; - onChange: ( value: string ) => void; - className?: string; -} -const RadioCard: React.FC< Props > = ( { - name, - selected, - options, - onChange, - className, -} ) => { - return ( - <> - { options.map( ( { label, icon, value, content } ) => { - const id = `radio-card-${ name }-${ value }`; - const checked = value === selected; - const handleChange = () => onChange( value ); - - return ( -
{ - if ( event.key === 'Enter' ) handleChange(); - } } - className={ classNames( - 'wcpay-component-radio-card', - { checked }, - className - ) } - > -
- - - { icon } -
- { checked && content } -
- ); - } ) } - - ); -}; - -export default RadioCard; diff --git a/client/components/radio-card/style.scss b/client/components/radio-card/style.scss deleted file mode 100644 index f2e0f75766c..00000000000 --- a/client/components/radio-card/style.scss +++ /dev/null @@ -1,57 +0,0 @@ -.wcpay-component-radio-card { - cursor: pointer; - display: block; - padding: $gap-large; - background-color: #fff; - border-radius: 3px; - border: 1px solid $light-gray-500; - - &:not( :last-of-type ) { - margin-bottom: $gap-large; - } - - &:hover, - &.checked, - &:focus-visible { - box-shadow: 0 0 0 1.5px var( --wp-admin-theme-color ); - } - - &__label { - display: grid; - grid-template-columns: 24px 1fr 25px; - column-gap: $gap-small; - align-items: center; - font-weight: bold; - - &:not( :last-child ) { - margin-bottom: $gap; - } - - svg { - fill: #bbb; - } - - input[type='radio'] { - margin: 0; - justify-self: flex-end; - width: 20px; - height: 20px; - border-color: $gray-700; - - &:checked { - border-color: var( --wp-admin-theme-color ); - } - - &::before { - width: 12px; - height: 12px; - margin: 3px; - background: var( --wp-admin-theme-color ); - } - - &:focus { - box-shadow: none; - } - } - } -} diff --git a/client/components/radio-card/test/__snapshots__/index.tsx.snap b/client/components/radio-card/test/__snapshots__/index.tsx.snap deleted file mode 100644 index f4429bb7ffd..00000000000 --- a/client/components/radio-card/test/__snapshots__/index.tsx.snap +++ /dev/null @@ -1,58 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RadioCard Component renders RadioCard component with provided props 1`] = ` -
- - -
-`; diff --git a/client/components/radio-card/test/index.tsx b/client/components/radio-card/test/index.tsx deleted file mode 100644 index de4050684ca..00000000000 --- a/client/components/radio-card/test/index.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * External dependencies - */ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import user from '@testing-library/user-event'; - -/** - * Internal dependencies - */ -import RadioCard from '../'; - -const options = [ - { - label: 'Pineapple pizza', - value: 'pineapple', - icon: , - content:

Sweet pizza

, - }, - { - label: 'Pizza', - value: 'pizza', - icon: , - content:

The real pizza

, - }, -]; - -describe( 'RadioCard Component', () => { - it( 'renders RadioCard component with provided props', () => { - const { container } = render( - - ); - expect( container ).toMatchSnapshot(); - } ); - - it( 'changes the selected value when an option is clicked', () => { - const mockOnChange = jest.fn(); - render( - - ); - - user.click( screen.getByLabelText( /Pineapple/i ) ); - expect( mockOnChange ).toHaveBeenCalledWith( 'pineapple' ); - } ); -} ); diff --git a/client/onboarding/steps/mode-choice.tsx b/client/onboarding/steps/mode-choice.tsx index 00af3d247be..6fe5a312208 100644 --- a/client/onboarding/steps/mode-choice.tsx +++ b/client/onboarding/steps/mode-choice.tsx @@ -1,39 +1,38 @@ /** * External dependencies */ -import React, { useState } from 'react'; +import React from 'react'; import { Button } from '@wordpress/components'; -import { Icon, store, tool } from '@wordpress/icons'; +import { Icon, store } from '@wordpress/icons'; import { addQueryArgs } from '@wordpress/url'; /** * Internal dependencies */ -import RadioCard from 'components/radio-card'; import { useStepperContext } from 'components/stepper'; import { trackModeSelected } from '../tracking'; import strings from '../strings'; import InlineNotice from 'components/inline-notice'; -const DevModeNotice = () => ( +const SandboxModeNotice = () => ( - { strings.steps.mode.devModeNotice } + { strings.steps.mode.sandboxModeNotice } ); const ModeChoice: React.FC = () => { const { devMode } = wcpaySettings; - const liveStrings = strings.steps.mode.live; - const testStrings = strings.steps.mode.test; + const modeStrings = strings.steps.mode; - const [ selected, setSelected ] = useState< 'live' | 'test' >( 'live' ); const { nextStep } = useStepperContext(); - const handleContinue = () => { - trackModeSelected( selected ); + const handleContinue = ( mode: 'live' | 'test' ) => { + trackModeSelected( mode ); - if ( selected === 'live' ) return nextStep(); + // If live mode is selected, go to the next step of the flow. + if ( mode === 'live' ) return nextStep(); + // Else, redirect to the test mode Stripe flow. const { connectUrl } = wcpaySettings; const url = addQueryArgs( connectUrl, { test_mode: true, @@ -43,41 +42,42 @@ const ModeChoice: React.FC = () => { return ( <> - { devMode && } - void } - options={ [ - { - label: liveStrings.label, - value: 'live', - icon: , - content: ( -
- { liveStrings.note } -
- ), - }, - { - label: testStrings.label, - value: 'test', - icon: , - content: ( -
- { testStrings.note } -
- ), - }, - ] } - /> - + { devMode && } +
+
+ + { modeStrings.label } +
+
+
+ { modeStrings.note } +
+

{ modeStrings.tos }

+
+
+ +
+
+ +
+ +
); }; diff --git a/client/onboarding/steps/test/mode-choice.tsx b/client/onboarding/steps/test/mode-choice.tsx index 8c081182324..4ad0f2996e0 100644 --- a/client/onboarding/steps/test/mode-choice.tsx +++ b/client/onboarding/steps/test/mode-choice.tsx @@ -35,14 +35,11 @@ describe( 'ModeChoice', () => { render( ); expect( - screen.getByText( strings.steps.mode.live.label ) - ).toBeInTheDocument(); - expect( - screen.getByText( strings.steps.mode.test.label ) + screen.getByText( strings.steps.mode.label ) ).toBeInTheDocument(); expect( screen.getByText( - 'Dev mode is enabled, only test accounts will be created. If you want to process live transactions, please disable it.' + 'Sandbox mode is enabled, only test accounts will be created. If you want to process live transactions, please disable it.' ) ).toBeInTheDocument(); } ); @@ -51,8 +48,7 @@ describe( 'ModeChoice', () => { nextStep = jest.fn(); render( ); - user.click( screen.getByText( strings.steps.mode.live.label ) ); - user.click( screen.getByRole( 'button' ) ); + user.click( screen.getByTestId( 'live-mode-button' ) ); expect( nextStep ).toHaveBeenCalled(); } ); @@ -70,8 +66,9 @@ describe( 'ModeChoice', () => { render( ); - user.click( screen.getByText( strings.steps.mode.test.label ) ); - user.click( screen.getByRole( 'button' ) ); + user.click( + screen.getByRole( 'button', { name: /Continue in sandbox mode/i } ) + ); expect( window.location.href ).toBe( `https://wcpay.test/connect?test_mode=true` diff --git a/client/onboarding/strings.tsx b/client/onboarding/strings.tsx index 04d201af815..fdeba48f840 100644 --- a/client/onboarding/strings.tsx +++ b/client/onboarding/strings.tsx @@ -6,6 +6,14 @@ import { __, sprintf } from '@wordpress/i18n'; import interpolateComponents from '@automattic/interpolate-components'; import React from 'react'; +const documentationUrls = { + sandboxMode: + 'https://woo.com/document/woopayments/testing-and-troubleshooting/dev-mode/', + tos: 'https://wordpress.com/tos/', + merchantTerms: 'https://wordpress.com/tos/#more-woopay-specifically', + privacyPolicy: 'https://automattic.com/privacy/', +}; + export default { steps: { mode: { @@ -17,33 +25,21 @@ export default { 'Select the option that best fits your needs.', 'woocommerce-payments' ), - live: { - label: __( - 'I’d like to set up payments on my own store', - 'woocommerce-payments' - ), - note: __( - 'You’ll need to provide details to verify that you’re the owner of the account. If you’re setting up payments for someone else, choose the test payments option.', - 'woocommerce-payments' - ), - }, - test: { - label: __( - 'I’m building a store for someone else and would like to test payments', - 'woocommerce-payments' - ), - note: sprintf( - /* translators: %s: WooPayments */ - __( - 'This option will set up %s in development mode. You can use test data to set up, no personal information is required. When you’re ready to launch your store, switching to live payments is easy.', - 'woocommerce-payments' - ), - 'WooPayments' - ), + label: __( + 'I’d like to set up payments for my store', + 'woocommerce-payments' + ), + note: __( + 'You’ll need to provide details to verify that you’re the owner of the account. If you’re setting up payments for someone else, choose sandbox mode.', + 'woocommerce-payments' + ), + continue: { + live: __( 'Continue', 'woocommerce-payments' ), + test: __( 'Continue in sandbox mode', 'woocommerce-payments' ), }, - devModeNotice: interpolateComponents( { + sandboxModeNotice: interpolateComponents( { mixedString: __( - 'Dev mode is enabled, only test accounts will be created. If you want to process live transactions, please disable it. {{learnMoreLink}}Learn more{{/learnMoreLink}}', + 'Sandbox mode is enabled, only test accounts will be created. If you want to process live transactions, please disable it. {{learnMoreLink}}Learn more{{/learnMoreLink}}', 'woocommerce-payments' ), components: { @@ -51,15 +47,50 @@ export default { // Link content is in the format string above. Consider disabling jsx-a11y/anchor-has-content. // eslint-disable-next-line jsx-a11y/anchor-has-content
), }, } ), + tos: interpolateComponents( { + mixedString: sprintf( + __( + /* translators: %1$s: WooPayments, %2$s: WooPay */ + 'By using %1$s, you agree to the {{tosLink}}Terms of Service{{/tosLink}} (including %2$s {{merchantTermsLink}}merchant terms{{/merchantTermsLink}}) and acknowledge that you have read our {{privacyPolicyLink}}Privacy Policy{{/privacyPolicyLink}}.', + 'woocommerce-payments' + ), + 'WooPayments', + 'WooPay' + ), + components: { + tosLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + merchantTermsLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + privacyPolicyLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + }, + } ), }, personal: { heading: __( diff --git a/client/onboarding/style.scss b/client/onboarding/style.scss index 1c118b5bf3c..8dbbef819e4 100644 --- a/client/onboarding/style.scss +++ b/client/onboarding/style.scss @@ -106,6 +106,12 @@ body.wcpay-onboarding__body { padding: $gap-small $gap; } + .onboarding-mode__sandbox { + display: flex; + align-items: center; + justify-content: center; + } + .personal-details-notice { margin: 0; } @@ -124,4 +130,42 @@ body.wcpay-onboarding__body { margin: $gap 0; } } + + .wcpay-component-onboarding-card { + display: block; + padding: $gap-large; + background-color: #fff; + border-radius: 3px; + border: 1px solid $light-gray-500; + margin-bottom: $gap-large; + + &__label { + display: grid; + grid-template-columns: 24px 1fr 25px; + column-gap: $gap-small; + align-items: center; + font-weight: bold; + + &:not( :last-child ) { + margin-bottom: $gap; + } + + svg { + fill: #bbb; + } + } + + &__footer { + button { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + } + } + + p { + color: $gray-700; + } + } } From 5a1d4b9d44a2489d2470f43388c8f48754658069 Mon Sep 17 00:00:00 2001 From: Zvonimir Maglica Date: Fri, 19 Jan 2024 16:36:08 +0100 Subject: [PATCH 51/60] Add ENUM class for country codes (#7925) Co-authored-by: Naman Malhotra --- changelog/dev-7886-add-country-codes-enum | 4 + ...s-wc-rest-payments-settings-controller.php | 3 +- includes/class-wc-payment-gateway-wcpay.php | 3 +- includes/class-wc-payments-account.php | 5 +- includes/class-wc-payments-features.php | 4 +- ...ayments-payment-request-button-handler.php | 3 +- includes/class-wc-payments-utils.php | 77 +-- includes/class-wc-payments.php | 1 + includes/constants/class-country-code.php | 231 ++++++++ .../class-payment-request-button-states.php | 154 +++--- includes/multi-currency/CountryFlags.php | 504 +++++++++--------- includes/multi-currency/MultiCurrency.php | 5 +- .../class-affirm-payment-method.php | 7 +- .../class-afterpay-payment-method.php | 11 +- .../class-klarna-payment-method.php | 29 +- .../test-class-wc-payments-task-disputes.php | 21 +- ...s-wc-rest-payments-accounts-controller.php | 9 +- ...s-wc-rest-payments-customer-controller.php | 5 +- ...wc-rest-payments-onboarding-controller.php | 7 +- ...s-wc-rest-payments-settings-controller.php | 3 +- .../unit/contants/test-class-country-code.php | 67 +++ .../test-class-list-transactions-request.php | 9 +- ...class-wc-payments-customer-service-api.php | 5 +- ...est-class-buyer-fingerprinting-service.php | 3 +- .../test-class-fraud-risk-tools.php | 5 +- tests/unit/helpers/class-wc-helper-order.php | 3 +- ...-class-update-service-data-from-server.php | 5 +- .../test-class-country-flags.php | 3 +- .../test-class-frontend-prices.php | 6 +- .../multi-currency/test-class-geolocation.php | 18 +- .../test-class-multi-currency.php | 27 +- ...ents-reports-authorizations-controller.php | 13 +- ...yments-reports-transactions-controller.php | 9 +- .../Internal/Service/Level3ServiceTest.php | 21 +- ...est-class-wc-payments-customer-service.php | 13 +- ...t-class-wc-payments-incentives-service.php | 2 +- ...class-wc-payments-localization-service.php | 4 +- ...t-class-wc-payments-onboarding-service.php | 7 +- ...ayments-payment-request-button-handler.php | 3 +- .../test-class-wc-payments-api-charge.php | 4 +- .../test-class-wc-payments-api-client.php | 7 +- .../woopay/class-woopay-scheduler-test.php | 3 +- 42 files changed, 834 insertions(+), 489 deletions(-) create mode 100644 changelog/dev-7886-add-country-codes-enum create mode 100644 includes/constants/class-country-code.php create mode 100644 tests/unit/contants/test-class-country-code.php diff --git a/changelog/dev-7886-add-country-codes-enum b/changelog/dev-7886-add-country-codes-enum new file mode 100644 index 00000000000..e6e2b8aad22 --- /dev/null +++ b/changelog/dev-7886-add-country-codes-enum @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Added enum class for country codes diff --git a/includes/admin/class-wc-rest-payments-settings-controller.php b/includes/admin/class-wc-rest-payments-settings-controller.php index 057af86e3f5..aed37660980 100644 --- a/includes/admin/class-wc-rest-payments-settings-controller.php +++ b/includes/admin/class-wc-rest-payments-settings-controller.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Admin */ +use WCPay\Constants\Country_Code; use WCPay\Fraud_Prevention\Fraud_Risk_Tools; use WCPay\Constants\Track_Events; @@ -388,7 +389,7 @@ public function validate_business_support_phone( string $value, WP_REST_Request } // Japan accounts require Japanese phone numbers. - if ( 'JP' === $this->account->get_account_country() ) { + if ( Country_Code::JAPAN === $this->account->get_account_country() ) { if ( '+81' !== substr( $value, 0, 3 ) ) { return new WP_Error( 'rest_invalid_pattern', diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index db6ebb6bb45..4c6c3bc92d6 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -9,6 +9,7 @@ exit; // Exit if accessed directly. } +use WCPay\Constants\Country_Code; use WCPay\Constants\Fraud_Meta_Box_Type; use WCPay\Constants\Order_Mode; use WCPay\Constants\Order_Status; @@ -2877,7 +2878,7 @@ protected function get_deposit_delay_days( int $default_value = 7 ): int { * * @return string code of the country. */ - protected function get_account_country( string $default_value = 'US' ): string { + protected function get_account_country( string $default_value = Country_Code::UNITED_STATES ): string { try { if ( $this->is_connected() ) { return $this->account->get_account_country() ?? $default_value; diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index 690d186cfb6..6c590950da6 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -11,6 +11,7 @@ use Automattic\WooCommerce\Admin\Notes\DataStore; use Automattic\WooCommerce\Admin\Notes\Note; +use WCPay\Constants\Country_Code; use WCPay\Core\Server\Request\Get_Account; use WCPay\Core\Server\Request\Get_Account_Capital_Link; use WCPay\Core\Server\Request\Get_Account_Login_Data; @@ -277,7 +278,7 @@ public function get_account_status_data() { return [ 'email' => $account['email'] ?? '', - 'country' => $account['country'] ?? 'US', + 'country' => $account['country'] ?? Country_Code::UNITED_STATES, 'status' => $account['status'], 'created' => $account['created'] ?? '', 'paymentsEnabled' => $account['payments_enabled'], @@ -1795,7 +1796,7 @@ private function get_actioned_notes(): array { */ public function get_account_country() { $account = $this->get_cached_account_data(); - return $account['country'] ?? 'US'; + return $account['country'] ?? Country_Code::UNITED_STATES; } /** diff --git a/includes/class-wc-payments-features.php b/includes/class-wc-payments-features.php index 904164421e0..9038a5c4898 100644 --- a/includes/class-wc-payments-features.php +++ b/includes/class-wc-payments-features.php @@ -5,6 +5,8 @@ * @package WooCommerce\Payments */ +use WCPay\Constants\Country_Code; + if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } @@ -310,7 +312,7 @@ public static function is_stripe_billing_eligible() { } $store_base_location = wc_get_base_location(); - return ! empty( $store_base_location['country'] ) && 'US' === $store_base_location['country']; + return ! empty( $store_base_location['country'] ) && Country_Code::UNITED_STATES === $store_base_location['country']; } /** diff --git a/includes/class-wc-payments-payment-request-button-handler.php b/includes/class-wc-payments-payment-request-button-handler.php index b764ad4d1bb..135ea785bd4 100644 --- a/includes/class-wc-payments-payment-request-button-handler.php +++ b/includes/class-wc-payments-payment-request-button-handler.php @@ -13,6 +13,7 @@ exit; } +use WCPay\Constants\Country_Code; use WCPay\Exceptions\Invalid_Price_Exception; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; use WCPay\Logger; @@ -442,7 +443,7 @@ public function get_normalized_postal_code( $postcode, $country ) { * when passing it back from the shippingcontactselected object. This causes WC to invalidate * the postal code and not calculate shipping zones correctly. */ - if ( 'GB' === $country ) { + if ( Country_Code::UNITED_KINGDOM === $country ) { // Replaces a redacted string with something like LN10***. return str_pad( preg_replace( '/\s+/', '', $postcode ), 7, '*' ); } diff --git a/includes/class-wc-payments-utils.php b/includes/class-wc-payments-utils.php index e49e6c65359..136f36b8d83 100644 --- a/includes/class-wc-payments-utils.php +++ b/includes/class-wc-payments-utils.php @@ -10,6 +10,7 @@ } use WCPay\Exceptions\{ Amount_Too_Small_Exception, API_Exception, Connection_Exception }; +use WCPay\Constants\Country_Code; /** * WC Payments Utils class @@ -223,44 +224,44 @@ public static function zero_decimal_currencies(): array { */ public static function supported_countries(): array { return [ - 'AE' => __( 'United Arab Emirates', 'woocommerce-payments' ), - 'AT' => __( 'Austria', 'woocommerce-payments' ), - 'AU' => __( 'Australia', 'woocommerce-payments' ), - 'BE' => __( 'Belgium', 'woocommerce-payments' ), - 'BG' => __( 'Bulgaria', 'woocommerce-payments' ), - 'CA' => __( 'Canada', 'woocommerce-payments' ), - 'CH' => __( 'Switzerland', 'woocommerce-payments' ), - 'CY' => __( 'Cyprus', 'woocommerce-payments' ), - 'CZ' => __( 'Czech Republic', 'woocommerce-payments' ), - 'DE' => __( 'Germany', 'woocommerce-payments' ), - 'DK' => __( 'Denmark', 'woocommerce-payments' ), - 'EE' => __( 'Estonia', 'woocommerce-payments' ), - 'FI' => __( 'Finland', 'woocommerce-payments' ), - 'ES' => __( 'Spain', 'woocommerce-payments' ), - 'FR' => __( 'France', 'woocommerce-payments' ), - 'HR' => __( 'Croatia', 'woocommerce-payments' ), - 'JP' => __( 'Japan', 'woocommerce-payments' ), - 'LU' => __( 'Luxembourg', 'woocommerce-payments' ), - 'GB' => __( 'United Kingdom (UK)', 'woocommerce-payments' ), - 'GR' => __( 'Greece', 'woocommerce-payments' ), - 'HK' => __( 'Hong Kong', 'woocommerce-payments' ), - 'HU' => __( 'Hungary', 'woocommerce-payments' ), - 'IE' => __( 'Ireland', 'woocommerce-payments' ), - 'IT' => __( 'Italy', 'woocommerce-payments' ), - 'LT' => __( 'Lithuania', 'woocommerce-payments' ), - 'LV' => __( 'Latvia', 'woocommerce-payments' ), - 'MT' => __( 'Malta', 'woocommerce-payments' ), - 'NL' => __( 'Netherlands', 'woocommerce-payments' ), - 'NO' => __( 'Norway', 'woocommerce-payments' ), - 'NZ' => __( 'New Zealand', 'woocommerce-payments' ), - 'PL' => __( 'Poland', 'woocommerce-payments' ), - 'PT' => __( 'Portugal', 'woocommerce-payments' ), - 'RO' => __( 'Romania', 'woocommerce-payments' ), - 'SE' => __( 'Sweden', 'woocommerce-payments' ), - 'SI' => __( 'Slovenia', 'woocommerce-payments' ), - 'SK' => __( 'Slovakia', 'woocommerce-payments' ), - 'SG' => __( 'Singapore', 'woocommerce-payments' ), - 'US' => __( 'United States (US)', 'woocommerce-payments' ), + Country_Code::UNITED_ARAB_EMIRATES => __( 'United Arab Emirates', 'woocommerce-payments' ), + Country_Code::AUSTRIA => __( 'Austria', 'woocommerce-payments' ), + Country_Code::AUSTRALIA => __( 'Australia', 'woocommerce-payments' ), + Country_Code::BELGIUM => __( 'Belgium', 'woocommerce-payments' ), + Country_Code::BULGARIA => __( 'Bulgaria', 'woocommerce-payments' ), + Country_Code::CANADA => __( 'Canada', 'woocommerce-payments' ), + Country_Code::SWITZERLAND => __( 'Switzerland', 'woocommerce-payments' ), + Country_Code::CYPRUS => __( 'Cyprus', 'woocommerce-payments' ), + Country_Code::CZECHIA => __( 'Czech Republic', 'woocommerce-payments' ), + Country_Code::GERMANY => __( 'Germany', 'woocommerce-payments' ), + Country_Code::DENMARK => __( 'Denmark', 'woocommerce-payments' ), + Country_Code::ESTONIA => __( 'Estonia', 'woocommerce-payments' ), + Country_Code::FINLAND => __( 'Finland', 'woocommerce-payments' ), + Country_Code::SPAIN => __( 'Spain', 'woocommerce-payments' ), + Country_Code::FRANCE => __( 'France', 'woocommerce-payments' ), + Country_Code::CROATIA => __( 'Croatia', 'woocommerce-payments' ), + Country_Code::JAPAN => __( 'Japan', 'woocommerce-payments' ), + Country_Code::LUXEMBOURG => __( 'Luxembourg', 'woocommerce-payments' ), + Country_Code::UNITED_KINGDOM => __( 'United Kingdom (UK)', 'woocommerce-payments' ), + Country_Code::GREECE => __( 'Greece', 'woocommerce-payments' ), + Country_Code::HONG_KONG => __( 'Hong Kong', 'woocommerce-payments' ), + Country_Code::HUNGARY => __( 'Hungary', 'woocommerce-payments' ), + Country_Code::IRELAND => __( 'Ireland', 'woocommerce-payments' ), + Country_Code::ITALY => __( 'Italy', 'woocommerce-payments' ), + Country_Code::LITHUANIA => __( 'Lithuania', 'woocommerce-payments' ), + Country_Code::LATVIA => __( 'Latvia', 'woocommerce-payments' ), + Country_Code::MALTA => __( 'Malta', 'woocommerce-payments' ), + Country_Code::NETHERLANDS => __( 'Netherlands', 'woocommerce-payments' ), + Country_Code::NORWAY => __( 'Norway', 'woocommerce-payments' ), + Country_Code::NEW_ZEALAND => __( 'New Zealand', 'woocommerce-payments' ), + Country_Code::POLAND => __( 'Poland', 'woocommerce-payments' ), + Country_Code::PORTUGAL => __( 'Portugal', 'woocommerce-payments' ), + Country_Code::ROMANIA => __( 'Romania', 'woocommerce-payments' ), + Country_Code::SWEDEN => __( 'Sweden', 'woocommerce-payments' ), + Country_Code::SLOVENIA => __( 'Slovenia', 'woocommerce-payments' ), + Country_Code::SLOVAKIA => __( 'Slovakia', 'woocommerce-payments' ), + Country_Code::SINGAPORE => __( 'Singapore', 'woocommerce-payments' ), + Country_Code::UNITED_STATES => __( 'United States (US)', 'woocommerce-payments' ), ]; } diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index cad21f86d9e..f5046144bed 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -414,6 +414,7 @@ public static function init() { include_once __DIR__ . '/exceptions/class-fraud-ruleset-exception.php'; include_once __DIR__ . '/exceptions/class-order-not-found-exception.php'; include_once __DIR__ . '/constants/class-base-constant.php'; + include_once __DIR__ . '/constants/class-country-code.php'; include_once __DIR__ . '/constants/class-fraud-meta-box-type.php'; include_once __DIR__ . '/constants/class-order-mode.php'; include_once __DIR__ . '/constants/class-order-status.php'; diff --git a/includes/constants/class-country-code.php b/includes/constants/class-country-code.php new file mode 100644 index 00000000000..790059d65ef --- /dev/null +++ b/includes/constants/class-country-code.php @@ -0,0 +1,231 @@ + [], + Country_Code::AFGHANISTAN => [], // Angola. - 'AO' => [], + Country_Code::ANDORRA => [], // Argentina. - 'AR' => [ + Country_Code::ARGENTINA => [ 'C' => [ 'Ciudad Autónoma de Buenos Aires', 'Ciudad Autónoma de Buenos Aires', NULL ], 'B' => [ 'Buenos Aires', 'Buenos Aires', NULL ], 'K' => [ 'Catamarca', 'Catamarca', NULL ], @@ -78,9 +78,9 @@ class Payment_Request_Button_States { 'T' => [ 'Tucumán', 'Tucumán', NULL ], ], // Austria. - 'AT' => [], + Country_Code::AUSTRIA => [], // Australia. - 'AU' =>[ + Country_Code::AUSTRALIA =>[ 'ACT' => [ 'ACT', 'Australian Capital Territory', NULL ], 'NSW' => [ 'NSW', 'New South Wales', NULL ], 'NT' => [ 'NT', 'Northern Territory', NULL ], @@ -94,21 +94,21 @@ class Payment_Request_Button_States { // Aland Islands. 'AX' => [], // Bangladesh. - 'BD' => [], + Country_Code::BANGLADESH => [], // Belgium. - 'BE' => [], + Country_Code::BELGIUM => [], // Bulgaria. - 'BG' => [], + Country_Code::BULGARIA => [], // Bahrain. - 'BH' => [], + Country_Code::BAHRAIN => [], // Burundi. - 'BI' => [], + Country_Code::BURUNDI => [], // Benin. - 'BJ' => [], + Country_Code::BENIN => [], // Bolivia. - 'BO' => [], + Country_Code::BOLIVIA => [], // Brazil. - 'BR' => [ + Country_Code::BRAZIL => [ 'AC' => [ 'AC', 'Acre', NULL ], 'AL' => [ 'AL', 'Alagoas', NULL ], 'AP' => [ 'AP', 'Amapá', NULL ], @@ -138,7 +138,7 @@ class Payment_Request_Button_States { 'TO' => [ 'TO', 'Tocantins', NULL ], ], // Canada. - 'CA' => [ + Country_Code::CANADA => [ 'AB' => [ 'AB', 'Alberta', 'Alberta' ], 'BC' => [ 'BC', 'British Columbia', 'Colombie-Britannique' ], 'MB' => [ 'MB', 'Manitoba', 'Manitoba' ], @@ -154,9 +154,9 @@ class Payment_Request_Button_States { 'YT' => [ 'YT', 'Yukon', 'Yukon' ], ], // Switzerland. - 'CH' => [], + Country_Code::SWITZERLAND => [], // China. - 'CN' => [ + Country_Code::CHINA => [ 'CN1' => [ 'Yunnan Sheng', 'Yunnan Sheng', '云南省' ], 'CN2' => [ 'Beijing Shi', 'Beijing Shi', '北京市' ], 'CN3' => [ 'Tianjin Shi', 'Tianjin Shi', '天津市' ], @@ -193,19 +193,19 @@ class Payment_Request_Button_States { // [ 'Hong Kong', 'Hong Kong', '香港' ], ], // Czech Republic. - 'CZ' => [], + Country_Code::CZECHIA => [], // Germany. - 'DE' => [], + Country_Code::GERMANY => [], // Denmark. - 'DK' => [], + Country_Code::DENMARK => [], // Dominican Republic. - 'DO' => [], + Country_Code::DOMINICAN_REPUBLIC => [], // Algeria. - 'DZ' => [], + Country_Code::ALGERIA => [], // Estonia. - 'EE' => [], + Country_Code::ESTONIA => [], // Egypt. - 'EG' => [ + Country_Code::EGYPT => [ 'EGALX' => [ 'Alexandria Governorate', 'Alexandria Governorate', 'الإسكندرية' ], 'EGASN' => [ 'Aswan Governorate', 'Aswan Governorate', 'أسوان' ], 'EGAST' => [ 'Asyut Governorate', 'Asyut Governorate', 'أسيوط' ], @@ -235,7 +235,7 @@ class Payment_Request_Button_States { 'EGWAD' => [ 'New Valley Governorate', 'New Valley Governorate', 'الوادي الجديد' ], ], // Spain. - 'ES' => [ + Country_Code::SPAIN => [ 'C' => [ 'A Coruña', 'A Coruña', NULL ], 'VI' => [ 'Álava', 'Álava', NULL ], 'AB' => [ 'Albacete', 'Albacete', NULL ], @@ -290,19 +290,19 @@ class Payment_Request_Button_States { 'Z' => [ 'Zaragoza', 'Zaragoza', NULL ], ], // Finland. - 'FI' => [], + Country_Code::FINLAND => [], // France. - 'FR' => [], + Country_Code::FRANCE => [], // French Guiana. 'GF' => [], // Ghana. - 'GH' => [], + Country_Code::GHANA => [], // Guadeloupe. 'GP' => [], // Greece. - 'GR' => [], + Country_Code::GREECE => [], // Guatemala. - 'GT' => [], + Country_Code::GUATEMALA => [], // Hong Kong. 'HK' => [ 'HONG KONG' => [ 'Hong Kong Island', 'Hong Kong Island', '香港島' ], @@ -310,9 +310,9 @@ class Payment_Request_Button_States { 'NEW TERRITORIES' => [ 'New Territories', 'New Territories', '新界' ], ], // Hungary. - 'HU' => [], + Country_Code::HUNGARY => [], // Indonesia. - 'ID' => [ + Country_Code::INDONESIA => [ 'AC' => [ 'Aceh', 'Aceh', NULL ], 'SU' => [ 'Sumatera Utara', 'Sumatera Utara', NULL ], 'SB' => [ 'Sumatera Barat', 'Sumatera Barat', NULL ], @@ -351,7 +351,7 @@ class Payment_Request_Button_States { // [ 'Kalimantan Timur', 'Kalimantan Timur', NULL ], ], // Ireland. - 'IE' => [ + Country_Code::IRELAND => [ 'CW' => [ 'Co. Carlow', 'Co. Carlow', NULL ], 'CN' => [ 'Co. Cavan', 'Co. Cavan', NULL ], 'CE' => [ 'Co. Clare', 'Co. Clare', NULL ], @@ -380,11 +380,11 @@ class Payment_Request_Button_States { 'WW' => [ 'Co. Wicklow', 'Co. Wicklow', NULL ], ], // Israel. - 'IL' => [], + Country_Code::ISRAEL => [], // Isle of Man. 'IM' => [], // India. - 'IN' => [ + Country_Code::INDIA => [ 'AP' => [ 'Andhra Pradesh', 'Andhra Pradesh', NULL ], 'AR' => [ 'Arunachal Pradesh', 'Arunachal Pradesh', NULL ], 'AS' => [ 'Assam', 'Assam', NULL ], @@ -424,7 +424,7 @@ class Payment_Request_Button_States { 'PY' => [ 'Puducherry', 'Puducherry', NULL ], ], // Iran. - 'IR' => [ + Country_Code::IRAN => [ 'KHZ' => [ 'Khuzestan Province', 'Khuzestan Province', 'استان خوزستان' ], 'THR' => [ 'Tehran Province', 'Tehran Province', 'استان تهران' ], 'ILM' => [ 'Ilam Province', 'Ilam Province', 'استان ایلام' ], @@ -458,9 +458,9 @@ class Payment_Request_Button_States { 'SBN' => [ 'Sistan and Baluchestan Province', 'Sistan and Baluchestan Province', 'استان سیستان و بلوچستان' ], ], // Iceland. - 'IS' => [], + Country_Code::ICELAND => [], // Italy. - 'IT' => [ + Country_Code::ITALY => [ 'AG' => [ 'AG', 'Agrigento', NULL ], 'AL' => [ 'AL', 'Alessandria', NULL ], 'AN' => [ 'AN', 'Ancona', NULL ], @@ -570,7 +570,7 @@ class Payment_Request_Button_States { 'VT' => [ 'VT', 'Viterbo', NULL ], ], // Jamaica. - 'JM' => [ + Country_Code::JAMAICA => [ 'JM-01' => [ 'Kingston', 'Kingston', NULL ], 'JM-02' => [ 'St. Andrew', 'St. Andrew', NULL ], 'JM-03' => [ 'St. Thomas', 'St. Thomas', NULL ], @@ -587,7 +587,7 @@ class Payment_Request_Button_States { 'JM-14' => [ 'St. Catherine', 'St. Catherine', NULL ], ], // Japan. - 'JP' => [ + Country_Code::JAPAN => [ 'JP01' => [ 'Hokkaido', 'Hokkaido', '北海道' ], 'JP02' => [ 'Aomori', 'Aomori', '青森県' ], 'JP03' => [ 'Iwate', 'Iwate', '岩手県' ], @@ -637,29 +637,29 @@ class Payment_Request_Button_States { 'JP47' => [ 'Okinawa', 'Okinawa', '沖縄県' ], ], // Kenya. - 'KE' => [], + Country_Code::KENYA => [], // South Korea. - 'KR' => [], + Country_Code::SOUTH_KOREA => [], // Kuwait. - 'KW' => [], + Country_Code::KUWAIT => [], // Laos. - 'LA' => [], + Country_Code::LAOS => [], // Lebanon. - 'LB' => [], + Country_Code::LEBANON => [], // Sri Lanka. 'LK' => [], // Liberia. - 'LR' => [], + Country_Code::LIBERIA => [], // Luxembourg. - 'LU' => [], + Country_Code::LUXEMBOURG => [], // Moldova. - 'MD' => [], + Country_Code::MOLDOVA => [], // Martinique. 'MQ' => [], // Malta. - 'MT' => [], + Country_Code::MALTA => [], // Mexico. - 'MX' => [ + Country_Code::MEXICO => [ 'DF' => [ 'CDMX', 'Ciudad de México', NULL ], 'JA' => [ 'Jal.', 'Jalisco', NULL ], 'NL' => [ 'N.L.', 'Nuevo León', NULL ], @@ -694,7 +694,7 @@ class Payment_Request_Button_States { 'ZA' => [ 'Zac.', 'Zacatecas', NULL ], ], // Malaysia. - 'MY' => [ + Country_Code::MALAYSIA => [ 'JHR' => [ 'Johor', 'Johor', NULL ], 'KDH' => [ 'Kedah', 'Kedah', NULL ], 'KTN' => [ 'Kelantan', 'Kelantan', NULL ], @@ -713,7 +713,7 @@ class Payment_Request_Button_States { 'KUL' => [ 'Kuala Lumpur', 'Kuala Lumpur', NULL ], ], // Mozambique. - 'MZ' => [ + Country_Code::MOZAMBIQUE => [ 'MZP' => [ 'Cabo Delgado', 'Cabo Delgado', NULL ], 'MZG' => [ 'Gaza', 'Gaza', NULL ], 'MZI' => [ 'Inhambane', 'Inhambane', NULL ], @@ -727,9 +727,9 @@ class Payment_Request_Button_States { 'MZQ' => [ 'Zambezia', 'Zambezia', NULL ], ], // Namibia. - 'NA' => [], + Country_Code::NAMIBIA => [], // Nigeria. - 'NG' => [ + Country_Code::NIGERIA => [ 'AB' => [ 'Abia', 'Abia', NULL ], 'FC' => [ 'Federal Capital Territory', 'Federal Capital Territory', NULL ], 'AD' => [ 'Adamawa', 'Adamawa', NULL ], @@ -769,15 +769,15 @@ class Payment_Request_Button_States { 'ZA' => [ 'Zamfara', 'Zamfara', NULL ], ], // Netherlands. - 'NL' => [], + Country_Code::NETHERLANDS => [], // Norway. - 'NO' => [], + Country_Code::NORWAY => [], // Nepal. - 'NP' => [], + Country_Code::NEPAL => [], // New Zealand. - 'NZ' => [], + Country_Code::NEW_ZEALAND => [], // Peru. - 'PE' => [ + Country_Code::PERU => [ 'CAL' => [ 'Callao', 'Callao', NULL ], 'LMA' => [ 'Municipalidad Metropolitana de Lima', 'Municipalidad Metropolitana de Lima', NULL ], 'AMA' => [ 'Amazonas', 'Amazonas', NULL ], @@ -806,7 +806,7 @@ class Payment_Request_Button_States { 'UCA' => [ 'Ucayali', 'Ucayali', NULL ], ], // Philippines. - 'PH' => [ + Country_Code::PHILIPPINES => [ 'ABR' => [ 'Abra', 'Abra', NULL ], 'AGN' => [ 'Agusan del Norte', 'Agusan del Norte', NULL ], 'AGS' => [ 'Agusan del Sur', 'Agusan del Sur', NULL ], @@ -891,31 +891,31 @@ class Payment_Request_Button_States { '00' => [ 'Metro Manila', 'Metro Manila', NULL ], ], // Pakistan. - 'PK' => [], + Country_Code::PAKISTAN => [], // Poland. - 'PL' => [], + Country_Code::POLAND => [], // Puerto Rico. 'PR' => [], // Portugal. - 'PT' => [], + Country_Code::PORTUGAL => [], // Paraguay. - 'PY' => [], + Country_Code::PARAGUAY => [], // Reunion. 'RE' => [], // Romania. - 'RO' => [], + Country_Code::ROMANIA => [], // Serbia. - 'RS' => [], + Country_Code::SERBIA => [], // Sweden. - 'SE' => [], + Country_Code::SWEDEN => [], // Singapore. - 'SG' => [], + Country_Code::SINGAPORE => [], // Slovenia. - 'SI' => [], + Country_Code::SLOVENIA => [], // Slovakia. - 'SK' => [], + Country_Code::SLOVAKIA => [], // Thailand. - 'TH' => [ + Country_Code::THAILAND => [ 'TH-37' => [ 'Amnat Charoen', 'Amnat Charoen', 'อำนาจเจริญ' ], 'TH-15' => [ 'Ang Thong', 'Ang Thong', 'อ่างทอง' ], 'TH-14' => [ 'Phra Nakhon Si Ayutthaya', 'Phra Nakhon Si Ayutthaya', 'พระนครศรีอยุธยา' ], @@ -995,7 +995,7 @@ class Payment_Request_Button_States { 'TH-35' => [ 'Yasothon', 'Yasothon', 'ยโสธร' ], ], // Turkey. - 'TR' => [ + Country_Code::TURKEY => [ 'TR01' => [ 'Adana', 'Adana', NULL ], 'TR02' => [ 'Adıyaman', 'Adıyaman', NULL ], 'TR03' => [ 'Afyon', 'Afyon', NULL ], @@ -1079,13 +1079,13 @@ class Payment_Request_Button_States { 'TR81' => [ 'Düzce', 'Düzce', NULL ], ], // Tanzania. - 'TZ' => [], + Country_Code::TANZANIA => [], // Uganda. - 'UG' => [], + Country_Code::UGANDA => [], // United States Minor Outlying Islands. 'UM' => [], // United States. - 'US' => [ + Country_Code::UNITED_STATES => [ 'AL' => [ 'AL', 'Alabama', NULL ], 'AK' => [ 'AK', 'Alaska', NULL ], 'AZ' => [ 'AZ', 'Arizona', NULL ], @@ -1150,13 +1150,13 @@ class Payment_Request_Button_States { //[ 'VI', 'Virgin Islands', NULL ], ], // Vietnam. - 'VN' => [], + Country_Code::VIETNAM => [], // Mayotte. 'YT' => [], // South Africa. - 'ZA' => [], + Country_Code::SOUTH_AFRICA => [], // Zambia. - 'ZM' => [], + Country_Code::ZAMBIA => [], ]; // phpcs:enable } diff --git a/includes/multi-currency/CountryFlags.php b/includes/multi-currency/CountryFlags.php index 286e77dfbe2..5bc494b3dd4 100644 --- a/includes/multi-currency/CountryFlags.php +++ b/includes/multi-currency/CountryFlags.php @@ -7,6 +7,8 @@ namespace WCPay\MultiCurrency; +use WCPay\Constants\Country_Code; + defined( 'ABSPATH' ) || exit; /** @@ -15,257 +17,257 @@ class CountryFlags { const EMOJI_COUNTRIES_FLAGS = [ - 'AD' => '🇦🇩', - 'AE' => '🇦🇪', - 'AF' => '🇦🇫', - 'AG' => '🇦🇬', - 'AI' => '🇦🇮', - 'AL' => '🇦🇱', - 'AM' => '🇦🇲', - 'AO' => '🇦🇴', - 'AQ' => '🇦🇶', - 'AR' => '🇦🇷', - 'AS' => '🇦🇸', - 'AT' => '🇦🇹', - 'AU' => '🇦🇺', - 'AW' => '🇦🇼', - 'AX' => '🇦🇽', - 'AZ' => '🇦🇿', - 'BA' => '🇧🇦', - 'BB' => '🇧🇧', - 'BD' => '🇧🇩', - 'BE' => '🇧🇪', - 'BF' => '🇧🇫', - 'BG' => '🇧🇬', - 'BH' => '🇧🇭', - 'BI' => '🇧🇮', - 'BJ' => '🇧🇯', - 'BL' => '🇧🇱', - 'BM' => '🇧🇲', - 'BN' => '🇧🇳', - 'BO' => '🇧🇴', - 'BQ' => '🇧🇶', - 'BR' => '🇧🇷', - 'BS' => '🇧🇸', - 'BT' => '🇧🇹', - 'BV' => '🇧🇻', - 'BW' => '🇧🇼', - 'BY' => '🇧🇾', - 'BZ' => '🇧🇿', - 'CA' => '🇨🇦', - 'CC' => '🇨🇨', - 'CD' => '🇨🇩', - 'CF' => '🇨🇫', - 'CG' => '🇨🇬', - 'CH' => '🇨🇭', - 'CI' => '🇨🇮', - 'CK' => '🇨🇰', - 'CL' => '🇨🇱', - 'CM' => '🇨🇲', - 'CN' => '🇨🇳', - 'CO' => '🇨🇴', - 'CR' => '🇨🇷', - 'CU' => '🇨🇺', - 'CV' => '🇨🇻', - 'CW' => '🇨🇼', - 'CX' => '🇨🇽', - 'CY' => '🇨🇾', - 'CZ' => '🇨🇿', - 'DE' => '🇩🇪', - 'DJ' => '🇩🇯', - 'DK' => '🇩🇰', - 'DM' => '🇩🇲', - 'DO' => '🇩🇴', - 'DZ' => '🇩🇿', - 'EC' => '🇪🇨', - 'EE' => '🇪🇪', - 'EG' => '🇪🇬', - 'EH' => '🇪🇭', - 'ER' => '🇪🇷', - 'ES' => '🇪🇸', - 'ET' => '🇪🇹', - 'EU' => '🇪🇺', - 'FI' => '🇫🇮', - 'FJ' => '🇫🇯', - 'FK' => '🇫🇰', - 'FM' => '🇫🇲', - 'FO' => '🇫🇴', - 'FR' => '🇫🇷', - 'GA' => '🇬🇦', - 'GB' => '🇬🇧', - 'GD' => '🇬🇩', - 'GE' => '🇬🇪', - 'GF' => '🇬🇫', - 'GG' => '🇬🇬', - 'GH' => '🇬🇭', - 'GI' => '🇬🇮', - 'GL' => '🇬🇱', - 'GM' => '🇬🇲', - 'GN' => '🇬🇳', - 'GP' => '🇬🇵', - 'GQ' => '🇬🇶', - 'GR' => '🇬🇷', - 'GS' => '🇬🇸', - 'GT' => '🇬🇹', - 'GU' => '🇬🇺', - 'GW' => '🇬🇼', - 'GY' => '🇬🇾', - 'HK' => '🇭🇰', - 'HM' => '🇭🇲', - 'HN' => '🇭🇳', - 'HR' => '🇭🇷', - 'HT' => '🇭🇹', - 'HU' => '🇭🇺', - 'ID' => '🇮🇩', - 'IE' => '🇮🇪', - 'IL' => '🇮🇱', - 'IM' => '🇮🇲', - 'IN' => '🇮🇳', - 'IO' => '🇮🇴', - 'IQ' => '🇮🇶', - 'IR' => '🇮🇷', - 'IS' => '🇮🇸', - 'IT' => '🇮🇹', - 'JE' => '🇯🇪', - 'JM' => '🇯🇲', - 'JO' => '🇯🇴', - 'JP' => '🇯🇵', - 'KE' => '🇰🇪', - 'KG' => '🇰🇬', - 'KH' => '🇰🇭', - 'KI' => '🇰🇮', - 'KM' => '🇰🇲', - 'KN' => '🇰🇳', - 'KP' => '🇰🇵', - 'KR' => '🇰🇷', - 'KW' => '🇰🇼', - 'KY' => '🇰🇾', - 'KZ' => '🇰🇿', - 'LA' => '🇱🇦', - 'LB' => '🇱🇧', - 'LC' => '🇱🇨', - 'LI' => '🇱🇮', - 'LK' => '🇱🇰', - 'LR' => '🇱🇷', - 'LS' => '🇱🇸', - 'LT' => '🇱🇹', - 'LU' => '🇱🇺', - 'LV' => '🇱🇻', - 'LY' => '🇱🇾', - 'MA' => '🇲🇦', - 'MC' => '🇲🇨', - 'MD' => '🇲🇩', - 'ME' => '🇲🇪', - 'MF' => '🇲🇫', - 'MG' => '🇲🇬', - 'MH' => '🇲🇭', - 'MK' => '🇲🇰', - 'ML' => '🇲🇱', - 'MM' => '🇲🇲', - 'MN' => '🇲🇳', - 'MO' => '🇲🇴', - 'MP' => '🇲🇵', - 'MQ' => '🇲🇶', - 'MR' => '🇲🇷', - 'MS' => '🇲🇸', - 'MT' => '🇲🇹', - 'MU' => '🇲🇺', - 'MV' => '🇲🇻', - 'MW' => '🇲🇼', - 'MX' => '🇲🇽', - 'MY' => '🇲🇾', - 'MZ' => '🇲🇿', - 'NA' => '🇳🇦', - 'NC' => '🇳🇨', - 'NE' => '🇳🇪', - 'NF' => '🇳🇫', - 'NG' => '🇳🇬', - 'NI' => '🇳🇮', - 'NL' => '🇳🇱', - 'NO' => '🇳🇴', - 'NP' => '🇳🇵', - 'NR' => '🇳🇷', - 'NU' => '🇳🇺', - 'NZ' => '🇳🇿', - 'OM' => '🇴🇲', - 'PA' => '🇵🇦', - 'PE' => '🇵🇪', - 'PF' => '🇵🇫', - 'PG' => '🇵🇬', - 'PH' => '🇵🇭', - 'PK' => '🇵🇰', - 'PL' => '🇵🇱', - 'PM' => '🇵🇲', - 'PN' => '🇵🇳', - 'PR' => '🇵🇷', - 'PS' => '🇵🇸', - 'PT' => '🇵🇹', - 'PW' => '🇵🇼', - 'PY' => '🇵🇾', - 'QA' => '🇶🇦', - 'RE' => '🇷🇪', - 'RO' => '🇷🇴', - 'RS' => '🇷🇸', - 'RU' => '🇷🇺', - 'RW' => '🇷🇼', - 'SA' => '🇸🇦', - 'SB' => '🇸🇧', - 'SC' => '🇸🇨', - 'SD' => '🇸🇩', - 'SE' => '🇸🇪', - 'SG' => '🇸🇬', - 'SH' => '🇸🇭', - 'SI' => '🇸🇮', - 'SJ' => '🇸🇯', - 'SK' => '🇸🇰', - 'SL' => '🇸🇱', - 'SM' => '🇸🇲', - 'SN' => '🇸🇳', - 'SO' => '🇸🇴', - 'SR' => '🇸🇷', - 'SS' => '🇸🇸', - 'ST' => '🇸🇹', - 'SV' => '🇸🇻', - 'SX' => '🇸🇽', - 'SY' => '🇸🇾', - 'SZ' => '🇸🇿', - 'TC' => '🇹🇨', - 'TD' => '🇹🇩', - 'TF' => '🇹🇫', - 'TG' => '🇹🇬', - 'TH' => '🇹🇭', - 'TJ' => '🇹🇯', - 'TK' => '🇹🇰', - 'TL' => '🇹🇱', - 'TM' => '🇹🇲', - 'TN' => '🇹🇳', - 'TO' => '🇹🇴', - 'TR' => '🇹🇷', - 'TT' => '🇹🇹', - 'TV' => '🇹🇻', - 'TW' => '🇹🇼', - 'TZ' => '🇹🇿', - 'UA' => '🇺🇦', - 'UG' => '🇺🇬', - 'UM' => '🇺🇲', - 'US' => '🇺🇸', - 'UY' => '🇺🇾', - 'UZ' => '🇺🇿', - 'VA' => '🇻🇦', - 'VC' => '🇻🇨', - 'VE' => '🇻🇪', - 'VG' => '🇻🇬', - 'VI' => '🇻🇮', - 'VN' => '🇻🇳', - 'VU' => '🇻🇺', - 'WF' => '🇼🇫', - 'WS' => '🇼🇸', - 'XK' => '🇽🇰', - 'YE' => '🇾🇪', - 'YT' => '🇾🇹', - 'ZA' => '🇿🇦', - 'ZM' => '🇿🇲', - 'ZW' => '🇿🇼', + Country_Code::ANDORRA => '🇦🇩', + Country_Code::UNITED_ARAB_EMIRATES => '🇦🇪', + Country_Code::AFGHANISTAN => '🇦🇫', + Country_Code::ANTIGUA_AND_BARBUDA => '🇦🇬', + Country_Code::ANGUILLA => '🇦🇮', + Country_Code::ALBANIA => '🇦🇱', + Country_Code::ARMENIA => '🇦🇲', + Country_Code::ANGOLA => '🇦🇴', + Country_Code::ANTARCTICA => '🇦🇶', + Country_Code::ARGENTINA => '🇦🇷', + Country_Code::AMERICAN_SAMOA => '🇦🇸', + Country_Code::AUSTRIA => '🇦🇹', + Country_Code::AUSTRALIA => '🇦🇺', + Country_Code::ARUBA => '🇦🇼', + Country_Code::ALAND_ISLANDS => '🇦🇽', + Country_Code::AZERBAIJAN => '🇦🇿', + Country_Code::BOSNIA_AND_HERZEGOVINA => '🇧🇦', + Country_Code::BARBADOS => '🇧🇧', + Country_Code::BANGLADESH => '🇧🇩', + Country_Code::BELGIUM => '🇧🇪', + Country_Code::BURKINA_FASO => '🇧🇫', + Country_Code::BULGARIA => '🇧🇬', + Country_Code::BAHRAIN => '🇧🇭', + Country_Code::BURUNDI => '🇧🇮', + Country_Code::BENIN => '🇧🇯', + Country_Code::SAINT_BARTHELEMY => '🇧🇱', + Country_Code::BERMUDA => '🇧🇲', + Country_Code::BRUNEI => '🇧🇳', + Country_Code::BOLIVIA => '🇧🇴', + Country_Code::CARIBBEAN_NETHERLANDS => '🇧🇶', + Country_Code::BRAZIL => '🇧🇷', + Country_Code::BAHAMAS => '🇧🇸', + Country_Code::BHUTAN => '🇧🇹', + Country_Code::BOUVET_ISLAND => '🇧🇻', + Country_Code::BOTSWANA => '🇧🇼', + Country_Code::BELARUS => '🇧🇾', + Country_Code::BELIZE => '🇧🇿', + Country_Code::CANADA => '🇨🇦', + Country_Code::COCOS_KEELING_ISLANDS => '🇨🇨', + Country_Code::DEMOCRATIC_REPUBLIC_OF_THE_CONGO => '🇨🇩', + Country_Code::CENTRAL_AFRICAN_REPUBLIC => '🇨🇫', + Country_Code::CONGO => '🇨🇬', + Country_Code::SWITZERLAND => '🇨🇭', + Country_Code::IVORY_COAST => '🇨🇮', + Country_Code::COOK_ISLANDS => '🇨🇰', + Country_Code::CHILE => '🇨🇱', + Country_Code::CAMEROON => '🇨🇲', + Country_Code::CHINA => '🇨🇳', + Country_Code::COLOMBIA => '🇨🇴', + Country_Code::COSTA_RICA => '🇨🇷', + Country_Code::CUBA => '🇨🇺', + Country_Code::CABO_VERDE => '🇨🇻', + 'CW' => '🇨🇼', + 'CX' => '🇨🇽', + Country_Code::CYPRUS => '🇨🇾', + Country_Code::CZECHIA => '🇨🇿', + Country_Code::GERMANY => '🇩🇪', + Country_Code::DJIBOUTI => '🇩🇯', + Country_Code::DENMARK => '🇩🇰', + Country_Code::DOMINICA => '🇩🇲', + Country_Code::DOMINICAN_REPUBLIC => '🇩🇴', + Country_Code::ALGERIA => '🇩🇿', + Country_Code::ECUADOR => '🇪🇨', + Country_Code::ESTONIA => '🇪🇪', + Country_Code::EGYPT => '🇪🇬', + 'EH' => '🇪🇭', + Country_Code::ERITREA => '🇪🇷', + Country_Code::SPAIN => '🇪🇸', + Country_Code::ETHIOPIA => '🇪🇹', + 'EU' => '🇪🇺', + Country_Code::FINLAND => '🇫🇮', + Country_Code::FIJI => '🇫🇯', + 'FK' => '🇫🇰', + Country_Code::MICRONESIA => '🇫🇲', + 'FO' => '🇫🇴', + Country_Code::FRANCE => '🇫🇷', + Country_Code::GABON => '🇬🇦', + Country_Code::UNITED_KINGDOM => '🇬🇧', + Country_Code::GRENADA => '🇬🇩', + Country_Code::GEORGIA => '🇬🇪', + 'GF' => '🇬🇫', + 'GG' => '🇬🇬', + Country_Code::GHANA => '🇬🇭', + Country_Code::GIBRALTAR => '🇬🇮', + 'GL' => '🇬🇱', + Country_Code::GAMBIA => '🇬🇲', + Country_Code::GUINEA => '🇬🇳', + 'GP' => '🇬🇵', + Country_Code::EQUATORIAL_GUINEA => '🇬🇶', + Country_Code::GREECE => '🇬🇷', + 'GS' => '🇬🇸', + Country_Code::GUATEMALA => '🇬🇹', + 'GU' => '🇬🇺', + Country_Code::GUINEA_BISSAU => '🇬🇼', + Country_Code::GUYANA => '🇬🇾', + Country_Code::HONG_KONG => '🇭🇰', + 'HM' => '🇭🇲', + Country_Code::HONDURAS => '🇭🇳', + Country_Code::CROATIA => '🇭🇷', + Country_Code::HAITI => '🇭🇹', + Country_Code::HUNGARY => '🇭🇺', + Country_Code::INDONESIA => '🇮🇩', + Country_Code::IRELAND => '🇮🇪', + Country_Code::ISRAEL => '🇮🇱', + 'IM' => '🇮🇲', + Country_Code::INDIA => '🇮🇳', + Country_Code::BRITISH_INDIAN_OCEAN_TERRITORY => '🇮🇴', + Country_Code::IRAQ => '🇮🇶', + Country_Code::IRAN => '🇮🇷', + Country_Code::ICELAND => '🇮🇸', + Country_Code::ITALY => '🇮🇹', + 'JE' => '🇯🇪', + Country_Code::JAMAICA => '🇯🇲', + Country_Code::JORDAN => '🇯🇴', + Country_Code::JAPAN => '🇯🇵', + Country_Code::KENYA => '🇰🇪', + Country_Code::KYRGYZSTAN => '🇰🇬', + Country_Code::CAMBODIA => '🇰🇭', + Country_Code::KIRIBATI => '🇰🇮', + Country_Code::COMOROS => '🇰🇲', + Country_Code::SAINT_KITTS_AND_NEVIS => '🇰🇳', + Country_Code::NORTH_KOREA => '🇰🇵', + Country_Code::SOUTH_KOREA => '🇰🇷', + Country_Code::KUWAIT => '🇰🇼', + 'KY' => '🇰🇾', + Country_Code::KAZAKHSTAN => '🇰🇿', + Country_Code::LAOS => '🇱🇦', + Country_Code::LEBANON => '🇱🇧', + Country_Code::SAINT_LUCIA => '🇱🇨', + Country_Code::LIECHTENSTEIN => '🇱🇮', + Country_Code::SRI_LANKA => '🇱🇰', + Country_Code::LIBERIA => '🇱🇷', + Country_Code::LESOTHO => '🇱🇸', + Country_Code::LITHUANIA => '🇱🇹', + Country_Code::LUXEMBOURG => '🇱🇺', + Country_Code::LATVIA => '🇱🇻', + Country_Code::LIBYA => '🇱🇾', + Country_Code::MOROCCO => '🇲🇦', + Country_Code::MONACO => '🇲🇨', + Country_Code::MOLDOVA => '🇲🇩', + Country_Code::MONTENEGRO => '🇲🇪', + 'MF' => '🇲🇫', + Country_Code::MADAGASCAR => '🇲🇬', + Country_Code::MARSHALL_ISLANDS => '🇲🇭', + Country_Code::NORTH_MACEDONIA => '🇲🇰', + Country_Code::MALI => '🇲🇱', + Country_Code::MYANMAR => '🇲🇲', + Country_Code::MONGOLIA => '🇲🇳', + 'MO' => '🇲🇴', + 'MP' => '🇲🇵', + 'MQ' => '🇲🇶', + Country_Code::MAURITANIA => '🇲🇷', + 'MS' => '🇲🇸', + Country_Code::MALTA => '🇲🇹', + Country_Code::MAURITIUS => '🇲🇺', + Country_Code::MALDIVES => '🇲🇻', + Country_Code::MALAWI => '🇲🇼', + Country_Code::MEXICO => '🇲🇽', + Country_Code::MALAYSIA => '🇲🇾', + Country_Code::MOZAMBIQUE => '🇲🇿', + Country_Code::NAMIBIA => '🇳🇦', + 'NC' => '🇳🇨', + Country_Code::NIGER => '🇳🇪', + 'NF' => '🇳🇫', + Country_Code::NIGERIA => '🇳🇬', + Country_Code::NICARAGUA => '🇳🇮', + Country_Code::NETHERLANDS => '🇳🇱', + Country_Code::NORWAY => '🇳🇴', + Country_Code::NEPAL => '🇳🇵', + Country_Code::NAURU => '🇳🇷', + 'NU' => '🇳🇺', + Country_Code::NEW_ZEALAND => '🇳🇿', + Country_Code::OMAN => '🇴🇲', + Country_Code::PANAMA => '🇵🇦', + Country_Code::PERU => '🇵🇪', + 'PF' => '🇵🇫', + Country_Code::PAPUA_NEW_GUINEA => '🇵🇬', + Country_Code::PHILIPPINES => '🇵🇭', + Country_Code::PAKISTAN => '🇵🇰', + Country_Code::POLAND => '🇵🇱', + 'PM' => '🇵🇲', + 'PN' => '🇵🇳', + 'PR' => '🇵🇷', + Country_Code::PALESTINE => '🇵🇸', + Country_Code::PORTUGAL => '🇵🇹', + Country_Code::PALAU => '🇵🇼', + Country_Code::PARAGUAY => '🇵🇾', + Country_Code::QATAR => '🇶🇦', + 'RE' => '🇷🇪', + Country_Code::ROMANIA => '🇷🇴', + Country_Code::SERBIA => '🇷🇸', + Country_Code::RUSSIA => '🇷🇺', + Country_Code::RWANDA => '🇷🇼', + Country_Code::SAUDI_ARABIA => '🇸🇦', + Country_Code::SOLOMON_ISLANDS => '🇸🇧', + Country_Code::SEYCHELLES => '🇸🇨', + Country_Code::SUDAN => '🇸🇩', + Country_Code::SWEDEN => '🇸🇪', + Country_Code::SINGAPORE => '🇸🇬', + 'SH' => '🇸🇭', + Country_Code::SLOVENIA => '🇸🇮', + 'SJ' => '🇸🇯', + Country_Code::SLOVAKIA => '🇸🇰', + Country_Code::SIERRA_LEONE => '🇸🇱', + Country_Code::SAN_MARINO => '🇸🇲', + Country_Code::SENEGAL => '🇸🇳', + Country_Code::SOMALIA => '🇸🇴', + Country_Code::SURINAME => '🇸🇷', + Country_Code::SOUTH_SUDAN => '🇸🇸', + Country_Code::SAO_TOME_AND_PRINCIPE => '🇸🇹', + Country_Code::EL_SALVADOR => '🇸🇻', + 'SX' => '🇸🇽', + Country_Code::SYRIA => '🇸🇾', + Country_Code::ESWATINI => '🇸🇿', + 'TC' => '🇹🇨', + Country_Code::CHAD => '🇹🇩', + 'TF' => '🇹🇫', + Country_Code::TOGO => '🇹🇬', + Country_Code::THAILAND => '🇹🇭', + Country_Code::TAJIKISTAN => '🇹🇯', + 'TK' => '🇹🇰', + Country_Code::EAST_TIMOR => '🇹🇱', + Country_Code::TURKMENISTAN => '🇹🇲', + Country_Code::TUNISIA => '🇹🇳', + Country_Code::TONGA => '🇹🇴', + Country_Code::TURKEY => '🇹🇷', + Country_Code::TRINIDAD_AND_TOBAGO => '🇹🇹', + Country_Code::TUVALU => '🇹🇻', + Country_Code::TAIWAN => '🇹🇼', + Country_Code::TANZANIA => '🇹🇿', + Country_Code::UKRAINE => '🇺🇦', + Country_Code::UGANDA => '🇺🇬', + 'UM' => '🇺🇲', + Country_Code::UNITED_STATES => '🇺🇸', + Country_Code::URUGUAY => '🇺🇾', + Country_Code::UZBEKISTAN => '🇺🇿', + Country_Code::VATICAN_CITY => '🇻🇦', + Country_Code::SAINT_VINCENT_AND_THE_GRENADINES => '🇻🇨', + Country_Code::VENEZUELA => '🇻🇪', + 'VG' => '🇻🇬', + 'VI' => '🇻🇮', + Country_Code::VIETNAM => '🇻🇳', + Country_Code::VANUATU => '🇻🇺', + 'WF' => '🇼🇫', + Country_Code::SAMOA => '🇼🇸', + Country_Code::KOSOVO => '🇽🇰', + Country_Code::YEMEN => '🇾🇪', + 'YT' => '🇾🇹', + Country_Code::SOUTH_AFRICA => '🇿🇦', + Country_Code::ZAMBIA => '🇿🇲', + Country_Code::ZIMBABWE => '🇿🇼', ]; /** diff --git a/includes/multi-currency/MultiCurrency.php b/includes/multi-currency/MultiCurrency.php index c862cc9f131..f1c890a656e 100644 --- a/includes/multi-currency/MultiCurrency.php +++ b/includes/multi-currency/MultiCurrency.php @@ -12,6 +12,7 @@ use WC_Payments_Utils; use WC_Payments_API_Client; use WC_Payments_Localization_Service; +use WCPay\Constants\Country_Code; use WCPay\Exceptions\API_Exception; use WCPay\Database_Cache; use WCPay\Logger; @@ -1392,8 +1393,8 @@ private function simulate_client_currency() { $countries = WC_Payments_Utils::supported_countries(); $predefined_simulation_currencies = [ - 'USD' => $countries['US'], - 'GBP' => $countries['GB'], + 'USD' => $countries[ Country_Code::UNITED_STATES ], + 'GBP' => $countries[ Country_Code::UNITED_KINGDOM ], ]; $simulation_currency = 'USD' === get_option( 'woocommerce_currency', 'USD' ) ? 'GBP' : 'USD'; diff --git a/includes/payment-methods/class-affirm-payment-method.php b/includes/payment-methods/class-affirm-payment-method.php index 68c4f785ddd..4be64bf653d 100644 --- a/includes/payment-methods/class-affirm-payment-method.php +++ b/includes/payment-methods/class-affirm-payment-method.php @@ -9,6 +9,7 @@ use WC_Payments_Token_Service; use WC_Payments_Utils; +use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\MultiCurrency; /** @@ -33,19 +34,19 @@ public function __construct( $token_service ) { $this->accept_only_domestic_payment = true; $this->limits_per_currency = [ 'CAD' => [ - 'CA' => [ + Country_Code::CANADA => [ 'min' => 5000, 'max' => 3000000, ], // Represents CAD 50 - 30,000 CAD. ], 'USD' => [ - 'US' => [ + Country_Code::UNITED_STATES => [ 'min' => 5000, 'max' => 3000000, ], // Represents USD 50 - 30,000 USD. ], ]; - $this->countries = [ 'US', 'CA' ]; + $this->countries = [ Country_Code::UNITED_STATES, Country_Code::CANADA ]; } /** diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php index 628ca444075..9984ae212b7 100644 --- a/includes/payment-methods/class-afterpay-payment-method.php +++ b/includes/payment-methods/class-afterpay-payment-method.php @@ -9,6 +9,7 @@ use WC_Payments_Token_Service; use WC_Payments_Utils; +use WCPay\Constants\Country_Code; /** * Afterpay Payment Method class extending UPE base class @@ -32,31 +33,31 @@ public function __construct( $token_service ) { $this->accept_only_domestic_payment = true; $this->limits_per_currency = [ 'AUD' => [ - 'AU' => [ + Country_Code::AUSTRALIA => [ 'min' => 100, 'max' => 200000, ], // Represents AUD 1 - 2,000 AUD. ], 'CAD' => [ - 'CA' => [ + Country_Code::CANADA => [ 'min' => 100, 'max' => 200000, ], // Represents CAD 1 - 2,000 CAD. ], 'NZD' => [ - 'NZ' => [ + Country_Code::NEW_ZEALAND => [ 'min' => 100, 'max' => 200000, ], // Represents NZD 1 - 2,000 NZD. ], 'GBP' => [ - 'GB' => [ + Country_Code::UNITED_KINGDOM => [ 'min' => 100, 'max' => 120000, ], // Represents GBP 1 - 1,200 GBP. ], 'USD' => [ - 'US' => [ + Country_Code::UNITED_STATES => [ 'min' => 100, 'max' => 400000, ], // Represents USD 1 - 4,000 USD. diff --git a/includes/payment-methods/class-klarna-payment-method.php b/includes/payment-methods/class-klarna-payment-method.php index 0300a2dfd74..9127cd16d48 100644 --- a/includes/payment-methods/class-klarna-payment-method.php +++ b/includes/payment-methods/class-klarna-payment-method.php @@ -9,6 +9,7 @@ use WC_Payments_Token_Service; use WC_Payments_Utils; +use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\MultiCurrency; /** @@ -31,68 +32,68 @@ public function __construct( $token_service ) { $this->icon_url = plugins_url( 'assets/images/payment-methods/klarna.svg', WCPAY_PLUGIN_FILE ); $this->currencies = [ 'USD', 'GBP', 'EUR', 'DKK', 'NOK', 'SEK' ]; $this->accept_only_domestic_payment = true; - $this->countries = [ 'US', 'GB', 'AT', 'DE', 'NL', 'BE', 'ES', 'IT', 'IE', 'DK', 'FI', 'NO', 'SE' ]; + $this->countries = [ Country_Code::UNITED_STATES, Country_Code::UNITED_KINGDOM, Country_Code::AUSTRIA, Country_Code::GERMANY, Country_Code::NETHERLANDS, Country_Code::BELGIUM, Country_Code::SPAIN, Country_Code::ITALY, Country_Code::IRELAND, Country_Code::DENMARK, Country_Code::FINLAND, Country_Code::NORWAY, Country_Code::SWEDEN ]; $this->limits_per_currency = [ 'USD' => [ - 'US' => [ + Country_Code::UNITED_STATES => [ 'min' => 0, 'max' => 1000000, ], ], 'GBP' => [ - 'GB' => [ + Country_Code::UNITED_KINGDOM => [ 'min' => 0, 'max' => 1150000, ], ], 'EUR' => [ - 'AT' => [ + Country_Code::AUSTRIA => [ 'min' => 1, 'max' => 1000000, ], - 'BE' => [ + Country_Code::BELGIUM => [ 'min' => 1, 'max' => 1000000, ], - 'DE' => [ + Country_Code::GERMANY => [ 'min' => 1, 'max' => 1000000, ], - 'NL' => [ + Country_Code::NETHERLANDS => [ 'min' => 1, 'max' => 1500000, ], - 'FI' => [ + Country_Code::FINLAND => [ 'min' => 0, 'max' => 1000000, ], - 'ES' => [ + Country_Code::SPAIN => [ 'min' => 0, 'max' => 1000000, ], - 'IE' => [ + Country_Code::IRELAND => [ 'min' => 0, 'max' => 400000, ], - 'IT' => [ + Country_Code::ITALY => [ 'min' => 0, 'max' => 1000000, ], ], 'DKK' => [ - 'DK' => [ + Country_Code::DENMARK => [ 'min' => 100, 'max' => 100000000, ], ], 'NOK' => [ - 'NO' => [ + Country_Code::NORWAY => [ 'min' => 0, 'max' => 100000000, ], ], 'SEK' => [ - 'SE' => [ + Country_Code::SWEDEN => [ 'min' => 0, 'max' => 15000000, ], diff --git a/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php b/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php index ff5971fdc49..2774d3e1b04 100644 --- a/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php +++ b/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WooCommerce\Payments\Tasks\WC_Payments_Task_Disputes; /** @@ -45,7 +46,7 @@ public function test_disputes_task_with_single_dispute_outside_7days() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+9 days' ) ), @@ -72,7 +73,7 @@ public function test_disputes_task_with_single_dispute_within_7days() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+6 days' ) ), @@ -104,7 +105,7 @@ public function test_disputes_task_with_single_dispute_within_24h() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+23 hours' ) ), @@ -136,7 +137,7 @@ public function test_disputes_task_with_multiple_disputes_within_7days() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+6 days' ) ), @@ -153,7 +154,7 @@ public function test_disputes_task_with_multiple_disputes_within_7days() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'warning_needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+3 days' ) ), @@ -183,7 +184,7 @@ public function test_disputes_task_with_multiple_disputes_within_24h() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+23 hours' ) ), @@ -200,7 +201,7 @@ public function test_disputes_task_with_multiple_disputes_within_24h() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'warning_needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+23 hours' ) ), @@ -217,7 +218,7 @@ public function test_disputes_task_with_multiple_disputes_within_24h() { 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'warning_needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+9 days' ) ), @@ -247,7 +248,7 @@ public function test_disputes_task_with_multiple_disputes_within_7days_multicurr 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+6 days' ) ), @@ -264,7 +265,7 @@ public function test_disputes_task_with_multiple_disputes_within_7days_multicurr 'order_number' => 14, 'customer_name' => 'customer', 'customer_email' => 'email@email.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'status' => 'warning_needs_response', 'created' => gmdate( 'Y-m-d H:i:s', strtotime( '-14 days' ) ), 'due_by' => gmdate( 'Y-m-d H:i:s', strtotime( '+3 days' ) ), diff --git a/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php b/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php index 7b5886e6eed..42560d5da90 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Core\Server\Request\Get_Account; use WCPay\Core\Server\Response; use WCPay\Exceptions\API_Exception; @@ -76,7 +77,7 @@ public function test_get_account_data_with_connected_account() { new Response( [ 'is_live' => true, - 'country' => 'DE', + 'country' => Country_Code::GERMANY, 'status' => 'complete', 'store_currencies' => [ 'default' => 'EUR' ], ] @@ -89,7 +90,7 @@ public function test_get_account_data_with_connected_account() { $this->assertSame( 200, $response->status ); $this->assertTrue( $response_data['test_mode'] ); $this->assertSame( 'complete', $response_data['status'] ); - $this->assertSame( 'DE', $response_data['country'] ); + $this->assertSame( Country_Code::GERMANY, $response_data['country'] ); $this->assertSame( 'EUR', $response_data['store_currencies']['default'] ); } @@ -114,7 +115,7 @@ public function test_get_account_data_without_connected_account_and_enabled_onbo $this->assertTrue( $response_data['test_mode'] ); $this->assertSame( 'NOACCOUNT', $response_data['status'] ); // The default country and currency have changed in WC 5.3, hence multiple options in assertions. - $this->assertContains( $response_data['country'], [ 'US', 'GB' ] ); + $this->assertContains( $response_data['country'], [ Country_Code::UNITED_STATES, Country_Code::UNITED_KINGDOM ] ); $this->assertContains( $response_data['store_currencies']['default'], [ 'USD', 'GBP' ] ); } @@ -138,7 +139,7 @@ public function test_get_account_data_without_connected_account_and_disabled_onb $this->assertTrue( $response_data['test_mode'] ); $this->assertSame( 'ONBOARDING_DISABLED', $response_data['status'] ); // The default country and currency have changed in WC 5.3, hence multiple options in assertions. - $this->assertContains( $response_data['country'], [ 'US', 'GB' ] ); + $this->assertContains( $response_data['country'], [ Country_Code::UNITED_STATES, Country_Code::UNITED_KINGDOM ] ); $this->assertContains( $response_data['store_currencies']['default'], [ 'USD', 'GBP' ] ); } diff --git a/tests/unit/admin/test-class-wc-rest-payments-customer-controller.php b/tests/unit/admin/test-class-wc-rest-payments-customer-controller.php index 11b9eb84669..0ab08a25597 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-customer-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-customer-controller.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; /** * WC_REST_Payments_Customer_Controller_Test unit tests. @@ -55,7 +56,7 @@ public function test_get_customer_payment_methods_endpoint_will_return_correct_r 'address_postal_code_check' => 'unchecked', 'cvc_check' => 'pass', ], - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'exp_month' => 11, 'exp_year' => 2030, 'fingerprint' => 'RSTUvWXZa1b2c3Y4', @@ -105,7 +106,7 @@ private function get_base_payment_method_data() { 'billing_details' => [ 'address' => [ 'city' => 'Los Angeles', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'line1' => '123 Sunset Blvd', 'line2' => 'Apt 456', 'postal_code' => '90028', diff --git a/tests/unit/admin/test-class-wc-rest-payments-onboarding-controller.php b/tests/unit/admin/test-class-wc-rest-payments-onboarding-controller.php index 7fd44cfa063..ee220f5b43c 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-onboarding-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-onboarding-controller.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; /** * WC_REST_Payments_Onboarding_Controller unit tests. @@ -105,7 +106,7 @@ public function test_get_required_verification_information() { $request = new WP_REST_Request( 'GET' ); $request->set_url_params( [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'type' => 'company', 'structure' => 'sole_proprietor', ] @@ -131,7 +132,7 @@ public function test_get_progressive_onboarding_eligible() { $request->set_body_params( [ 'business' => [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'type' => 'company', 'mcc' => 'most_popular__software_services', ], @@ -170,7 +171,7 @@ public function test_get_progressive_onboarding_not_eligible() { [ 'business' => [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'type' => 'company', 'mcc' => 'most_popular__software_services', ], 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 8c1628a9f91..0f8714c6b6b 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 @@ -8,6 +8,7 @@ use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\RestApi; use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Constants\Payment_Method; use WCPay\Database_Cache; use WCPay\Duplicate_Payment_Prevention_Service; @@ -741,7 +742,7 @@ public function account_business_support_address_validation_provider() { [ [ 'city' => 'test city', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], $request, 'account_business_support_address', diff --git a/tests/unit/contants/test-class-country-code.php b/tests/unit/contants/test-class-country-code.php new file mode 100644 index 00000000000..bf3f67a2ecf --- /dev/null +++ b/tests/unit/contants/test-class-country-code.php @@ -0,0 +1,67 @@ +assertEquals( 'AU', Country_Code::AUSTRALIA ); + $this->assertEquals( 'AT', Country_Code::AUSTRIA ); + $this->assertEquals( 'BE', Country_Code::BELGIUM ); + $this->assertEquals( 'BR', Country_Code::BRAZIL ); + $this->assertEquals( 'BG', Country_Code::BULGARIA ); + $this->assertEquals( 'CA', Country_Code::CANADA ); + $this->assertEquals( 'HR', Country_Code::CROATIA ); + $this->assertEquals( 'CY', Country_Code::CYPRUS ); + $this->assertEquals( 'CZ', Country_Code::CZECHIA ); + $this->assertEquals( 'DK', Country_Code::DENMARK ); + $this->assertEquals( 'EE', Country_Code::ESTONIA ); + $this->assertEquals( 'FI', Country_Code::FINLAND ); + $this->assertEquals( 'FR', Country_Code::FRANCE ); + $this->assertEquals( 'DE', Country_Code::GERMANY ); + $this->assertEquals( 'GH', Country_Code::GHANA ); + $this->assertEquals( 'GI', Country_Code::GIBRALTAR ); + $this->assertEquals( 'GR', Country_Code::GREECE ); + $this->assertEquals( 'HK', Country_Code::HONG_KONG ); + $this->assertEquals( 'HU', Country_Code::HUNGARY ); + $this->assertEquals( 'IN', Country_Code::INDIA ); + $this->assertEquals( 'ID', Country_Code::INDONESIA ); + $this->assertEquals( 'IE', Country_Code::IRELAND ); + $this->assertEquals( 'IT', Country_Code::ITALY ); + $this->assertEquals( 'JP', Country_Code::JAPAN ); + $this->assertEquals( 'KE', Country_Code::KENYA ); + $this->assertEquals( 'LV', Country_Code::LATVIA ); + $this->assertEquals( 'LI', Country_Code::LIECHTENSTEIN ); + $this->assertEquals( 'LT', Country_Code::LITHUANIA ); + $this->assertEquals( 'LU', Country_Code::LUXEMBOURG ); + $this->assertEquals( 'MY', Country_Code::MALAYSIA ); + $this->assertEquals( 'MT', Country_Code::MALTA ); + $this->assertEquals( 'MX', Country_Code::MEXICO ); + $this->assertEquals( 'NL', Country_Code::NETHERLANDS ); + $this->assertEquals( 'NZ', Country_Code::NEW_ZEALAND ); + $this->assertEquals( 'NG', Country_Code::NIGERIA ); + $this->assertEquals( 'NO', Country_Code::NORWAY ); + $this->assertEquals( 'PL', Country_Code::POLAND ); + $this->assertEquals( 'PT', Country_Code::PORTUGAL ); + $this->assertEquals( 'RO', Country_Code::ROMANIA ); + $this->assertEquals( 'SG', Country_Code::SINGAPORE ); + $this->assertEquals( 'SK', Country_Code::SLOVAKIA ); + $this->assertEquals( 'SI', Country_Code::SLOVENIA ); + $this->assertEquals( 'ZA', Country_Code::SOUTH_AFRICA ); + $this->assertEquals( 'ES', Country_Code::SPAIN ); + $this->assertEquals( 'SE', Country_Code::SWEDEN ); + $this->assertEquals( 'CH', Country_Code::SWITZERLAND ); + $this->assertEquals( 'TH', Country_Code::THAILAND ); + $this->assertEquals( 'AE', Country_Code::UNITED_ARAB_EMIRATES ); + $this->assertEquals( 'GB', Country_Code::UNITED_KINGDOM ); + $this->assertEquals( 'US', Country_Code::UNITED_STATES ); + } +} diff --git a/tests/unit/core/server/request/test-class-list-transactions-request.php b/tests/unit/core/server/request/test-class-list-transactions-request.php index 0d932deafcf..899e87ea4df 100644 --- a/tests/unit/core/server/request/test-class-list-transactions-request.php +++ b/tests/unit/core/server/request/test-class-list-transactions-request.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Core\Exceptions\Server\Request\Invalid_Request_Parameter_Exception; use WCPay\Core\Server\Request\List_Transactions; @@ -70,8 +71,8 @@ public function test_list_transactions_request_will_be_date() { $device_is_not = 'android'; $channel = 'online'; $channel_is_not = 'in_person'; - $country = 'US'; - $country_is_not = 'CA'; + $country = Country_Code::UNITED_STATES; + $country_is_not = Country_Code::CANADA; $risk_level = '0'; $risk_level_is_not = '1'; $search = [ 'search' ]; @@ -151,8 +152,8 @@ public function test_list_transactions_request_will_be_date_using_from_rest_requ $device_is_not = 'android'; $channel = 'online'; $channel_is_not = 'in_person'; - $country = 'US'; - $country_is_not = 'CA'; + $country = Country_Code::UNITED_STATES; + $country_is_not = Country_Code::CANADA; $risk_level = '0'; $risk_level_is_not = '1'; $search = [ 'search' ]; diff --git a/tests/unit/core/service/test-class-wc-payments-customer-service-api.php b/tests/unit/core/service/test-class-wc-payments-customer-service-api.php index a1b8847a41e..298549c6873 100644 --- a/tests/unit/core/service/test-class-wc-payments-customer-service-api.php +++ b/tests/unit/core/service/test-class-wc-payments-customer-service-api.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Database_Cache; use WCPay\Exceptions\API_Exception; use WCPay\Core\WC_Payments_Customer_Service_API; @@ -474,7 +475,7 @@ private function get_mock_customer_data() { 'postal_code' => '09876', 'city' => 'City', 'state' => 'State', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'shipping' => [ 'name' => 'Shipping Ship', @@ -484,7 +485,7 @@ private function get_mock_customer_data() { 'postal_code' => '76543', 'city' => 'City2', 'state' => 'State2', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], ], ]; diff --git a/tests/unit/fraud-prevention/test-class-buyer-fingerprinting-service.php b/tests/unit/fraud-prevention/test-class-buyer-fingerprinting-service.php index 271acc2bb9a..327187167e4 100644 --- a/tests/unit/fraud-prevention/test-class-buyer-fingerprinting-service.php +++ b/tests/unit/fraud-prevention/test-class-buyer-fingerprinting-service.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\Fraud_Prevention\Buyer_Fingerprinting_Service; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; @@ -45,7 +46,7 @@ public function test_it_hashes_using_sha512() { public function test_it_hashes_order_info() { $fingerprint = 'abc123'; - $ip_country = 'GB'; + $ip_country = Country_Code::UNITED_KINGDOM; add_filter( 'woocommerce_geolocate_ip', function() use ( $ip_country ) { diff --git a/tests/unit/fraud-prevention/test-class-fraud-risk-tools.php b/tests/unit/fraud-prevention/test-class-fraud-risk-tools.php index 7af9c4b76a1..249e56badd2 100644 --- a/tests/unit/fraud-prevention/test-class-fraud-risk-tools.php +++ b/tests/unit/fraud-prevention/test-class-fraud-risk-tools.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\Fraud_Prevention\Fraud_Risk_Tools; /** @@ -331,7 +332,7 @@ public function test_it_gets_high_protection_empty_allowed_countries_settings() public function test_it_gets_the_correct_for_specific_allowed_selling_locations_type() { update_option( 'woocommerce_allowed_countries', 'specific' ); - update_option( 'woocommerce_specific_allowed_countries', [ 'US', 'CA' ] ); + update_option( 'woocommerce_specific_allowed_countries', [ Country_Code::UNITED_STATES, Country_Code::CANADA ] ); $settings = $this->fraud_risk_tools->get_standard_protection_settings(); @@ -340,7 +341,7 @@ public function test_it_gets_the_correct_for_specific_allowed_selling_locations_ public function test_it_gets_the_correct_for_all_except_selling_locations_type() { update_option( 'woocommerce_allowed_countries', 'all_except' ); - update_option( 'woocommerce_all_except_countries', [ 'US', 'CA' ] ); + update_option( 'woocommerce_all_except_countries', [ Country_Code::UNITED_STATES, Country_Code::CANADA ] ); $settings = $this->fraud_risk_tools->get_standard_protection_settings(); diff --git a/tests/unit/helpers/class-wc-helper-order.php b/tests/unit/helpers/class-wc-helper-order.php index 93499fb901f..f7f02e23d74 100644 --- a/tests/unit/helpers/class-wc-helper-order.php +++ b/tests/unit/helpers/class-wc-helper-order.php @@ -5,6 +5,7 @@ * @package WooCommerce/Tests */ +use WCPay\Constants\Country_Code; use WCPay\Constants\Order_Status; /** @@ -96,7 +97,7 @@ public static function create_order( $customer_id = 1, $total = 50, $product = n $order->set_billing_city( 'WooCity' ); $order->set_billing_state( 'NY' ); $order->set_billing_postcode( '12345' ); - $order->set_billing_country( 'US' ); + $order->set_billing_country( Country_Code::UNITED_STATES ); $order->set_billing_email( 'admin@example.org' ); $order->set_billing_phone( '555-32123' ); diff --git a/tests/unit/migrations/test-class-update-service-data-from-server.php b/tests/unit/migrations/test-class-update-service-data-from-server.php index 998fcb39dc3..b7a7ca0c7f4 100644 --- a/tests/unit/migrations/test-class-update-service-data-from-server.php +++ b/tests/unit/migrations/test-class-update-service-data-from-server.php @@ -8,6 +8,7 @@ namespace WCPay\Migrations; use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPAY_UnitTestCase; /** @@ -74,7 +75,7 @@ public function test_does_nothing_if_account_data_contains_giropay_fees() { 'discount' => [], ], ], - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ] ) ); @@ -106,7 +107,7 @@ public function test_updates_service_data_if_account_data_does_not_contain_girop 'discount' => [], ], ], - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ] ) ); diff --git a/tests/unit/multi-currency/test-class-country-flags.php b/tests/unit/multi-currency/test-class-country-flags.php index cd3adff8feb..0ebe63fb8ef 100644 --- a/tests/unit/multi-currency/test-class-country-flags.php +++ b/tests/unit/multi-currency/test-class-country-flags.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\CountryFlags; /** @@ -12,7 +13,7 @@ */ class Country_Flags_Test extends WCPAY_UnitTestCase { public function test_get_by_country_returns_emoji_flag() { - $this->assertEquals( CountryFlags::get_by_country( 'US' ), '🇺🇸' ); + $this->assertEquals( CountryFlags::get_by_country( Country_Code::UNITED_STATES ), '🇺🇸' ); } public function test_get_by_country_returns_empty_string() { diff --git a/tests/unit/multi-currency/test-class-frontend-prices.php b/tests/unit/multi-currency/test-class-frontend-prices.php index db34cc1b40d..8c76d8a8ec4 100644 --- a/tests/unit/multi-currency/test-class-frontend-prices.php +++ b/tests/unit/multi-currency/test-class-frontend-prices.php @@ -5,6 +5,8 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; + /** * WCPay\MultiCurrency\FrontendPrices unit tests. */ @@ -206,7 +208,7 @@ function() { ); WC()->session->init(); - WC()->customer->set_location( 'US', 'CA' ); + WC()->customer->set_location( Country_Code::UNITED_STATES, 'CA' ); $shipping_method = new \WC_Shipping_Flat_Rate(); $shipping_method->tax_status = 'taxable'; @@ -250,7 +252,7 @@ function() { ); WC()->session->init(); - WC()->customer->set_location( 'US', 'CA' ); + WC()->customer->set_location( Country_Code::UNITED_STATES, 'CA' ); $shipping_method = new \WC_Shipping_Flat_Rate(); $shipping_method->tax_status = 'taxable'; diff --git a/tests/unit/multi-currency/test-class-geolocation.php b/tests/unit/multi-currency/test-class-geolocation.php index 0c663f17fcf..386787f6a3c 100644 --- a/tests/unit/multi-currency/test-class-geolocation.php +++ b/tests/unit/multi-currency/test-class-geolocation.php @@ -5,6 +5,8 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; + /** * WCPay\MultiCurrency\Geolocation unit tests. */ @@ -37,10 +39,10 @@ public function test_get_country_by_customer_location_returns_geolocation_countr add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); - $this->assertSame( 'CA', $this->geolocation->get_country_by_customer_location() ); + $this->assertSame( Country_Code::CANADA, $this->geolocation->get_country_by_customer_location() ); } public function test_get_country_by_customer_location_returns_default_country_when_no_geolocation() { @@ -54,20 +56,20 @@ function() { add_filter( 'woocommerce_customer_default_location', function() { - return 'BR'; + return Country_Code::BRAZIL; } ); - $this->assertSame( 'BR', $this->geolocation->get_country_by_customer_location() ); + $this->assertSame( Country_Code::BRAZIL, $this->geolocation->get_country_by_customer_location() ); } public function test_get_currency_by_customer_location_returns_geolocation_currency_code() { - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); @@ -75,7 +77,7 @@ function() { } public function test_get_currency_by_customer_location_returns_default_currency_code() { - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'BR' )->willReturn( [ 'currency_code' => 'BRL' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::BRAZIL )->willReturn( [ 'currency_code' => 'BRL' ] ); add_filter( 'woocommerce_geolocate_ip', @@ -86,7 +88,7 @@ function() { add_filter( 'woocommerce_customer_default_location', function() { - return 'BR'; + return Country_Code::BRAZIL; } ); diff --git a/tests/unit/multi-currency/test-class-multi-currency.php b/tests/unit/multi-currency/test-class-multi-currency.php index e5a360e2f5a..a6964e951ad 100644 --- a/tests/unit/multi-currency/test-class-multi-currency.php +++ b/tests/unit/multi-currency/test-class-multi-currency.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\Utils; use WCPay\Database_Cache; use WCPay\MultiCurrency\Exceptions\InvalidCurrencyException; @@ -451,11 +452,11 @@ function() { public function test_update_selected_currency_by_geolocation_does_not_set_session_cookie() { update_option( 'wcpay_multi_currency_enable_auto_currency', 'yes' ); - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); @@ -472,11 +473,11 @@ public function test_update_selected_currency_by_geolocation_updates_session_whe add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); $this->multi_currency->update_selected_currency_by_geolocation(); @@ -489,11 +490,11 @@ public function test_update_selected_currency_by_geolocation_displays_notice() { add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); $this->multi_currency->update_selected_currency_by_geolocation(); @@ -512,14 +513,14 @@ public function test_update_selected_currency_by_geolocation_does_not_update_if_ add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); // Arrange: Set the expected calls and retruns for our mock classes. $this->mock_localization_service ->method( 'get_country_locale_data' ) - ->with( 'CA' ) + ->with( Country_Code::CANADA ) ->willReturn( [ 'currency_code' => 'CAD' ] ); $this->mock_utils @@ -542,11 +543,11 @@ public function test_display_geolocation_currency_update_notice() { add_filter( 'woocommerce_geolocate_ip', function() { - return 'CA'; + return Country_Code::CANADA; } ); - $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); $this->multi_currency->display_geolocation_currency_update_notice(); @@ -554,11 +555,11 @@ function() { } public function test_display_geolocation_currency_update_notice_does_not_display_if_using_default_currency() { - WC()->session->set( WCPay\MultiCurrency\MultiCurrency::CURRENCY_SESSION_KEY, 'US' ); + WC()->session->set( WCPay\MultiCurrency\MultiCurrency::CURRENCY_SESSION_KEY, Country_Code::UNITED_STATES ); add_filter( 'woocommerce_geolocate_ip', function() { - return 'US'; + return Country_Code::UNITED_STATES; } ); @@ -572,7 +573,7 @@ public function test_display_geolocation_currency_update_notice_does_not_display add_filter( 'woocommerce_geolocate_ip', function() { - return 'US'; + return Country_Code::UNITED_STATES; } ); diff --git a/tests/unit/reports/test-class-wc-rest-payments-reports-authorizations-controller.php b/tests/unit/reports/test-class-wc-rest-payments-reports-authorizations-controller.php index 58f7bc1acaf..302ec1efadd 100644 --- a/tests/unit/reports/test-class-wc-rest-payments-reports-authorizations-controller.php +++ b/tests/unit/reports/test-class-wc-rest-payments-reports-authorizations-controller.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Exceptions\Connection_Exception; use WCPay\Core\Server\Request\List_Authorizations; @@ -196,7 +197,7 @@ private function get_authorizations_list_from_server() { 'source_identifier' => '4242', 'customer_name' => 'Test One', 'customer_email' => 'test1@woo.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'fees' => 312, 'currency' => 'eur', 'risk_level' => 0, @@ -221,7 +222,7 @@ private function get_authorizations_list_from_server() { 'source_identifier' => '4242', 'customer_name' => 'Test Two', 'customer_email' => 'test2@woo.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'fees' => 98, 'currency' => 'eur', 'risk_level' => 0, @@ -246,7 +247,7 @@ private function get_authorizations_list_from_server() { 'source_identifier' => '4242', 'customer_name' => 'Test One', 'customer_email' => 'test1@woo.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'fees' => 312, 'currency' => 'eur', 'risk_level' => 0, @@ -277,7 +278,7 @@ private function get_authorizations_list() { 'customer' => [ 'name' => 'Test One', 'email' => 'test1@woo.com', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'net_amount' => 6988, 'order_id' => 123, @@ -298,7 +299,7 @@ private function get_authorizations_list() { 'customer' => [ 'name' => 'Test Two', 'email' => 'test2@woo.com', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'net_amount' => 1702, 'order_id' => 456, @@ -319,7 +320,7 @@ private function get_authorizations_list() { 'customer' => [ 'name' => 'Test One', 'email' => 'test1@woo.com', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'net_amount' => 6988, 'order_id' => 789, diff --git a/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php b/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php index aefee308132..46c2b21452c 100644 --- a/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php +++ b/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Exceptions\Connection_Exception; use WCPay\Core\Server\Request\List_Transactions; @@ -200,7 +201,7 @@ private function get_transactions_list_from_server() { 'source_identifier' => '3184', 'customer_name' => 'Test Customer1', 'customer_email' => 'test1@woo.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'amount' => 2583, 'net' => 2426, 'fees' => 157, @@ -233,7 +234,7 @@ private function get_transactions_list_from_server() { 'source_identifier' => '3184', 'customer_name' => 'Test Customer2', 'customer_email' => 'test2@woo.com', - 'customer_country' => 'US', + 'customer_country' => Country_Code::UNITED_STATES, 'amount' => 2583, 'net' => 2452, 'fees' => 131, @@ -282,7 +283,7 @@ private function get_transactions_list() { 'customer' => [ 'name' => 'Test Customer1', 'email' => 'test1@woo.com', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'net_amount' => 2426, 'order_id' => 123, @@ -308,7 +309,7 @@ private function get_transactions_list() { 'customer' => [ 'name' => 'Test Customer2', 'email' => 'test2@woo.com', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'net_amount' => 2452, 'order_id' => 275, diff --git a/tests/unit/src/Internal/Service/Level3ServiceTest.php b/tests/unit/src/Internal/Service/Level3ServiceTest.php index 553c54f862c..5911201c99b 100644 --- a/tests/unit/src/Internal/Service/Level3ServiceTest.php +++ b/tests/unit/src/Internal/Service/Level3ServiceTest.php @@ -12,6 +12,7 @@ use WC_Order; use WC_Order_Item_Product; use WC_Order_Item_Fee; +use WCPay\Constants\Country_Code; use WCPAY_UnitTestCase; use WC_Payments_Account; use WCPay\Internal\Service\Level3Service; @@ -235,7 +236,7 @@ public function test_full_level3_data() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', false, false, 1, 1, 30, true ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -266,7 +267,7 @@ public function test_full_level3_data_with_product_id_longer_than_12_characters( ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', false, false, 1, 1, 123456789123456 ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -305,7 +306,7 @@ public function test_full_level3_data_with_fee() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', true ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -344,7 +345,7 @@ public function test_full_level3_data_with_negative_price_product() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', false, true, 1, 1 ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -353,7 +354,7 @@ public function test_full_level3_data_with_negative_price_product() { public function test_us_store_level_3_data() { // Use a non-us customer postcode to ensure it's not included in the level3 data. - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '9000' ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -384,7 +385,7 @@ public function test_us_customer_level_3_data() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '9000' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012' ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -394,7 +395,7 @@ public function test_us_customer_level_3_data() { public function test_non_us_customer_level_3_data() { $expected_data = []; - $this->mock_account->method( 'get_account_country' )->willReturn( 'CA' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::CANADA ); $this->mock_level_3_order( 'K0A' ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -425,7 +426,7 @@ public function test_full_level3_data_with_float_quantity() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', false, false, 3.7 ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -456,7 +457,7 @@ public function test_full_level3_data_with_float_quantity_zero() { ->with( 'get_option', 'woocommerce_store_postcode' ) ->willReturn( '94110' ); - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', false, false, 0.4 ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); @@ -505,7 +506,7 @@ public function test_level3_data_bundle() { } public function test_level3_data_bundle_for_orders_with_more_than_200_items() { - $this->mock_account->method( 'get_account_country' )->willReturn( 'US' ); + $this->mock_account->method( 'get_account_country' )->willReturn( Country_Code::UNITED_STATES ); $this->mock_level_3_order( '98012', true, false, 1, 500 ); $level_3_data = $this->sut->get_data_from_order( $this->order_id ); diff --git a/tests/unit/test-class-wc-payments-customer-service.php b/tests/unit/test-class-wc-payments-customer-service.php index 4260bf25d40..5d7c14fc34b 100644 --- a/tests/unit/test-class-wc-payments-customer-service.php +++ b/tests/unit/test-class-wc-payments-customer-service.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Database_Cache; use WCPay\Exceptions\API_Exception; @@ -485,7 +486,7 @@ public function test_update_payment_method_with_billing_details_from_order() { 'billing_details' => [ 'address' => [ 'city' => 'WooCity', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'line1' => 'WooAddress', 'postal_code' => '12345', 'state' => 'NY', @@ -589,7 +590,7 @@ private function get_mock_wc_object_for_customer_data( $object_class, $mock_retu 'get_billing_postcode' => '09876', 'get_billing_city' => 'City', 'get_billing_state' => 'State', - 'get_billing_country' => 'US', + 'get_billing_country' => Country_Code::UNITED_STATES, 'get_shipping_first_name' => 'Shipping', 'get_shipping_last_name' => 'Ship', 'get_shipping_address_1' => '2 Street St', @@ -597,7 +598,7 @@ private function get_mock_wc_object_for_customer_data( $object_class, $mock_retu 'get_shipping_postcode' => '76543', 'get_shipping_city' => 'City2', 'get_shipping_state' => 'State2', - 'get_shipping_country' => 'US', + 'get_shipping_country' => Country_Code::UNITED_STATES, ], $mock_return_overrides ); @@ -622,7 +623,7 @@ private function get_mock_customer_data( $overrides = [] ) { 'postal_code' => '09876', 'city' => 'City', 'state' => 'State', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], 'shipping' => [ 'name' => 'Shipping Ship', @@ -632,7 +633,7 @@ private function get_mock_customer_data( $overrides = [] ) { 'postal_code' => '76543', 'city' => 'City2', 'state' => 'State2', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], ], ], @@ -670,7 +671,7 @@ public function test_get_customer_id_for_order() { 'postal_code' => '12345', 'city' => 'WooCity', 'state' => 'NY', - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ], ]; diff --git a/tests/unit/test-class-wc-payments-incentives-service.php b/tests/unit/test-class-wc-payments-incentives-service.php index 0cbaa3b4ae8..4884198caaa 100644 --- a/tests/unit/test-class-wc-payments-incentives-service.php +++ b/tests/unit/test-class-wc-payments-incentives-service.php @@ -261,7 +261,7 @@ function() use ( $response ) { 'tc_url' => 'incentive_tc_url', ], // This is the hash of the test store context: - // 'country' => 'US', + // 'country' => Country_Code::UNITED_STATES, // 'locale' => 'en_US', // 'has_orders' => false, // 'has_payments' => false, diff --git a/tests/unit/test-class-wc-payments-localization-service.php b/tests/unit/test-class-wc-payments-localization-service.php index c002d6cc8a4..32be4fc17fd 100644 --- a/tests/unit/test-class-wc-payments-localization-service.php +++ b/tests/unit/test-class-wc-payments-localization-service.php @@ -5,6 +5,8 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; + /** * WC_Payments_Localization_Service_Test unit tests. */ @@ -156,7 +158,7 @@ public function test_get_country_locale_data() { ], ], ], - $this->localization_service->get_country_locale_data( 'BR' ) + $this->localization_service->get_country_locale_data( Country_Code::BRAZIL ) ); } diff --git a/tests/unit/test-class-wc-payments-onboarding-service.php b/tests/unit/test-class-wc-payments-onboarding-service.php index 8cb3f11ac99..982a363cb92 100644 --- a/tests/unit/test-class-wc-payments-onboarding-service.php +++ b/tests/unit/test-class-wc-payments-onboarding-service.php @@ -6,6 +6,7 @@ */ use PHPUnit\Framework\MockObject\MockObject; +use WCPay\Constants\Country_Code; use WCPay\Database_Cache; /** @@ -40,7 +41,7 @@ class WC_Payments_Onboarding_Service_Test extends WCPAY_UnitTestCase { */ private $mock_business_types = [ [ - 'key' => 'US', + 'key' => Country_Code::UNITED_STATES, 'name' => 'United States (US)', 'types' => [ [ @@ -146,12 +147,12 @@ public function test_get_required_verification_information() { $this->mock_api_client ->expects( $this->once() ) ->method( 'get_onboarding_required_verification_information' ) - ->with( 'US', 'company', 'sole_propietorship' ) + ->with( Country_Code::UNITED_STATES, 'company', 'sole_propietorship' ) ->willReturn( $mock_requirements ); $this->assertEquals( $mock_requirements, - $this->onboarding_service->get_required_verification_information( 'US', 'company', 'sole_propietorship' ) + $this->onboarding_service->get_required_verification_information( Country_Code::UNITED_STATES, 'company', 'sole_propietorship' ) ); } 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 f4c05dd5a13..c774cf5573f 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 @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Payment_Methods\CC_Payment_Method; use WCPay\Session_Rate_Limiter; @@ -14,7 +15,7 @@ */ class WC_Payments_Payment_Request_Button_Handler_Test extends WCPAY_UnitTestCase { const SHIPPING_ADDRESS = [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'state' => 'CA', 'postcode' => '94110', 'city' => 'San Francisco', diff --git a/tests/unit/wc-payment-api/models/test-class-wc-payments-api-charge.php b/tests/unit/wc-payment-api/models/test-class-wc-payments-api-charge.php index 5471fbfc5b8..1f06e1dd7bb 100644 --- a/tests/unit/wc-payment-api/models/test-class-wc-payments-api-charge.php +++ b/tests/unit/wc-payment-api/models/test-class-wc-payments-api-charge.php @@ -5,6 +5,8 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; + /** * WC_Payments_API_Charge unit tests. */ @@ -24,7 +26,7 @@ public function test_payments_api_charge_model_serializes_correctly() { 'address_postal_code_check' => null, 'cvc_check' => null, ], - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'exp_month' => 1, 'exp_year' => 2022, 'fingerprint' => 'mock', diff --git a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php index b7e9231f5ad..b9b8e5b79ee 100644 --- a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php +++ b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\Constants\Intent_Status; use WCPay\Exceptions\API_Exception; use WCPay\Internal\Logger; @@ -518,7 +519,7 @@ public function test_create_terminal_location_validation_values() { $this->payments_api_client->create_terminal_location( 'Example', [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, ] ); } @@ -527,7 +528,7 @@ public function test_create_terminal_location_success() { $location = [ 'display_name' => 'Example', 'address' => [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'line1' => 'Some Str. 2', ], 'metadata' => [], @@ -917,7 +918,7 @@ public function test_get_onboarding_po_eligible() { $po_eligible = $this->payments_api_client->get_onboarding_po_eligible( [ - 'country' => 'US', + 'country' => Country_Code::UNITED_STATES, 'type' => 'company', 'mcc' => 'most_popular__software_services', ], diff --git a/tests/unit/woopay/class-woopay-scheduler-test.php b/tests/unit/woopay/class-woopay-scheduler-test.php index 05d689527e3..0fa6db45784 100644 --- a/tests/unit/woopay/class-woopay-scheduler-test.php +++ b/tests/unit/woopay/class-woopay-scheduler-test.php @@ -5,6 +5,7 @@ * @package WooCommerce\Payments\Tests */ +use WCPay\Constants\Country_Code; use WCPay\WooPay\WooPay_Scheduler; use WCPay\WooPay\WooPay_Utilities; @@ -198,7 +199,7 @@ public function test_update_adapted_extensions_and_available_countries_list() { 'test-extension', 'test-extension-2', ]; - $available_countries = [ 'US', 'BR' ]; + $available_countries = [ Country_Code::UNITED_STATES, Country_Code::BRAZIL ]; $this->mock_api_response( [], $adapted_extensions, $available_countries ); From f1af5a8de52fb84f0cd7cc5fd88ffc965f97e1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Mart=C3=ADn=20Alabarce?= Date: Fri, 19 Jan 2024 17:16:59 +0100 Subject: [PATCH 52/60] Update PO success modal (#8005) Co-authored-by: Vlad Olaru --- .../images/illustrations/po-eligibility.svg | 1 - changelog/update-7579-po-success-modal | 5 ++ .../components/confetti-animation/index.tsx | 63 ++++++++++++++++ .../index.tsx | 28 +++----- .../style.scss | 71 +++++++++++-------- .../test/index.test.tsx | 10 ++- client/overview/test/index.js | 9 +-- package-lock.json | 28 ++++++++ package.json | 2 + 9 files changed, 156 insertions(+), 61 deletions(-) delete mode 100644 assets/images/illustrations/po-eligibility.svg create mode 100644 changelog/update-7579-po-success-modal create mode 100644 client/components/confetti-animation/index.tsx diff --git a/assets/images/illustrations/po-eligibility.svg b/assets/images/illustrations/po-eligibility.svg deleted file mode 100644 index 27f0885b30a..00000000000 --- a/assets/images/illustrations/po-eligibility.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/changelog/update-7579-po-success-modal b/changelog/update-7579-po-success-modal new file mode 100644 index 00000000000..f02eae18ba7 --- /dev/null +++ b/changelog/update-7579-po-success-modal @@ -0,0 +1,5 @@ +Significance: patch +Type: update +Comment: PO success modal design update. + + diff --git a/client/components/confetti-animation/index.tsx b/client/components/confetti-animation/index.tsx new file mode 100644 index 00000000000..32c2d971112 --- /dev/null +++ b/client/components/confetti-animation/index.tsx @@ -0,0 +1,63 @@ +/** + * External dependencies + */ +import React, { useEffect } from 'react'; +import confetti from 'canvas-confetti'; + +const defaultColors = [ '#889BF2', '#C3CDF9', '#6079ED' ]; + +const fireConfetti = ( colors: string[] ) => { + const defaults = { + origin: { y: 0.3 }, + spread: 360, + zIndex: 1000000, + colors, + }; + + const rectangle = confetti.shapeFromPath( { + path: 'M0,0 L2,0 L2,1 L0,1 Z', + } ); + + confetti( { + ...defaults, + particleCount: 20, + shapes: [ rectangle ], + scalar: 4, + startVelocity: 60, + } ); + confetti( { + ...defaults, + particleCount: 20, + shapes: [ rectangle ], + scalar: 2, + startVelocity: 40, + } ); + confetti( { + ...defaults, + particleCount: 40, + shapes: [ 'circle' ], + startVelocity: 20, + } ); +}; + +interface Props { + trigger?: boolean; + delay?: number; + colors?: string[]; +} + +const ConfettiAnimation: React.FC< Props > = ( { + trigger = true, + delay = 250, + colors = defaultColors, +} ) => { + useEffect( () => { + if ( trigger ) { + setTimeout( () => fireConfetti( colors ), delay ); + } + }, [ trigger, delay, colors ] ); + + return null; +}; + +export default ConfettiAnimation; diff --git a/client/overview/modal/progressive-onboarding-eligibility/index.tsx b/client/overview/modal/progressive-onboarding-eligibility/index.tsx index 6e16ac57a1f..b6c2b85054f 100644 --- a/client/overview/modal/progressive-onboarding-eligibility/index.tsx +++ b/client/overview/modal/progressive-onboarding-eligibility/index.tsx @@ -12,7 +12,7 @@ import { useDispatch } from '@wordpress/data'; * Internal dependencies */ import { trackEligibilityModalClosed } from 'onboarding/tracking'; -import HeaderImg from 'assets/images/illustrations/po-eligibility.svg'; +import ConfettiAnimation from 'components/confetti-animation'; import './style.scss'; const ProgressiveOnboardingEligibilityModal: React.FC = () => { @@ -70,18 +70,13 @@ const ProgressiveOnboardingEligibilityModal: React.FC = () => { className="wcpay-progressive-onboarding-eligibility-modal" onRequestClose={ handleDismiss } > -
- Header -
+

- { __( - 'You’re eligible to start selling now and fast-track the setup process.', - 'woocommerce-payments' - ) } + { __( 'You’re ready to sell.', 'woocommerce-payments' ) }

{ __( - 'Start selling now with these benefits or continue the process to set up deposits.', + 'Start selling now and fast track the setup process, or continue the process to set up deposits with WooPayments.', 'woocommerce-payments' ) }

@@ -97,7 +92,7 @@ const ProgressiveOnboardingEligibilityModal: React.FC = () => { { sprintf( /* translators: %s: WooPayments */ __( - '%s enables you to start processing payments right away.', + '%s enables you to start processing credit card payments right away.', 'woocommerce-payments' ), 'WooPayments' @@ -109,7 +104,7 @@ const ProgressiveOnboardingEligibilityModal: React.FC = () => { { __( 'Quick and easy setup', 'woocommerce-payments' ) } { __( - 'The setup process is super simple and ensures your store is ready to accept payments.', + 'The setup process is super simple and ensures your store is ready to accept card payments.', 'woocommerce-payments' ) } @@ -125,14 +120,11 @@ const ProgressiveOnboardingEligibilityModal: React.FC = () => {
- -
diff --git a/client/overview/modal/progressive-onboarding-eligibility/style.scss b/client/overview/modal/progressive-onboarding-eligibility/style.scss index 27d336e0743..1863d804d91 100644 --- a/client/overview/modal/progressive-onboarding-eligibility/style.scss +++ b/client/overview/modal/progressive-onboarding-eligibility/style.scss @@ -1,13 +1,17 @@ .wcpay-progressive-onboarding-eligibility-modal { - // fix for the modal being too short on smaller screens - @media ( max-height: 880px ) { - max-height: 100% !important; + &.components-modal__frame { + border-radius: 2px !important; + overflow: visible; } + .components-modal__content { box-sizing: border-box; max-width: 700px; - margin: 0 auto; + margin: 0; padding: $gap-larger; + display: flex; + flex-direction: column; + align-items: center; } .components-modal__header { @@ -18,26 +22,19 @@ left: initial; top: $gap-smaller; right: $gap-smaller; - } - } - - &__image { - margin: -$gap-larger; - margin-bottom: $gap-larger; - background-color: $studio-gray-0; - img { - display: block; - max-width: 100%; - max-height: 200px; - margin: 0 auto; + svg { + width: 32px; + height: 32px; + } } } &__heading { - @include wp-title-large; - text-align: center; - margin-bottom: 0; + font-size: 40px; + font-weight: 400; + line-height: 60px; + margin-bottom: $gap-smallest; } &__subheading { @@ -45,22 +42,28 @@ text-align: center; font-weight: normal; color: $gray-60; - margin-bottom: $gap-largest; + max-width: 480px; + margin: 0 0 $gap-large 0; } &__benefits { display: grid; grid-template-columns: repeat( 3, 1fr ); column-gap: $gap-largest; - text-align: center; + padding: 0 $gap; fill: $studio-woocommerce-purple-50; - @include wp-label; - color: $gray-700; + font-size: 14px; + line-height: 20px; + color: $gray-60; + + svg { + display: block; + margin: $gap-smaller auto; + } &__subtitle { @include wp-subtitle; - text-align: center; - margin-bottom: $gap-smaller; + margin: $gap-large 0 $gap-smallest; } @media screen and ( max-width: $break-small ) { @@ -71,15 +74,25 @@ &__footer { text-align: center; - margin-top: $gap-large; + margin: $gap-large 0; & :first-child { - margin-right: $gap-smaller; + margin-right: $gap; } button { - margin-top: $gap; - padding: $gap-smaller $gap; + margin-top: $gap-large; + padding: $gap-small $gap-large; + font-size: 14px; + line-height: 20px; + height: 40px; } } + + &__confetti { + position: absolute; + top: -28px; + left: -8px; + pointer-events: none; + } } diff --git a/client/overview/modal/progressive-onboarding-eligibility/test/index.test.tsx b/client/overview/modal/progressive-onboarding-eligibility/test/index.test.tsx index 3837b95f9c4..99e164f3b8f 100644 --- a/client/overview/modal/progressive-onboarding-eligibility/test/index.test.tsx +++ b/client/overview/modal/progressive-onboarding-eligibility/test/index.test.tsx @@ -36,8 +36,7 @@ describe( 'Progressive Onboarding Eligibility Modal', () => { const queryHeading = () => screen.queryByRole( 'heading', { - name: - 'You’re eligible to start selling now and fast-track the setup process.', + name: 'You’re ready to sell.', } ); expect( queryHeading() ).toBeInTheDocument(); @@ -55,14 +54,13 @@ describe( 'Progressive Onboarding Eligibility Modal', () => { user.click( screen.getByRole( 'button', { - name: 'Enable payments only', + name: 'Start selling', } ) ); expect( screen.queryByRole( 'heading', { - name: - 'You’re eligible to start selling now and fast-track the setup process.', + name: 'You’re ready to sell.', } ) ).not.toBeInTheDocument(); } ); @@ -85,7 +83,7 @@ describe( 'Progressive Onboarding Eligibility Modal', () => { user.click( screen.getByRole( 'button', { - name: 'Set up payments and deposits', + name: 'Start receiving deposits', } ) ); diff --git a/client/overview/test/index.js b/client/overview/test/index.js index 2c677e27e31..1318b654b14 100644 --- a/client/overview/test/index.js +++ b/client/overview/test/index.js @@ -303,17 +303,12 @@ describe( 'Overview page', () => { render( ); expect( - screen.getByText( - 'You’re eligible to start selling now and fast-track the setup process.' - ) + screen.getByText( 'You’re ready to sell.' ) ).toBeInTheDocument(); } ); it( 'does not displays ProgressiveOnboardingEligibilityModal if showProgressiveOnboardingEligibilityModal is false', () => { - const query = () => - screen.queryByText( - 'You’re eligible to start selling now and fast-track the setup process.' - ); + const query = () => screen.queryByText( 'You’re ready to sell.' ); render( ); diff --git a/package-lock.json b/package-lock.json index 056a7547a52..281f044e9ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@stripe/stripe-js": "1.15.1", "@woocommerce/explat": "2.3.0", "@woocommerce/number": "2.4.0", + "canvas-confetti": "1.9.2", "crypto-js": "4.1.1", "debug": "4.1.1", "intl-tel-input": "17.0.15", @@ -29,6 +30,7 @@ "@testing-library/react": "11.2.5", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "10.4.1", + "@types/canvas-confetti": "1.6.4", "@types/intl-tel-input": "17.0.4", "@types/lodash": "4.14.170", "@types/react": "17.0.2", @@ -8435,6 +8437,12 @@ "@types/node": "*" } }, + "node_modules/@types/canvas-confetti": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.6.4.tgz", + "integrity": "sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==", + "dev": true + }, "node_modules/@types/cheerio": { "version": "0.22.31", "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz", @@ -19327,6 +19335,15 @@ } ] }, + "node_modules/canvas-confetti": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.2.tgz", + "integrity": "sha512-6Xi7aHHzKwxZsem4mCKoqP6YwUG3HamaHHAlz1hTNQPCqXhARFpSXnkC9TWlahHY5CG6hSL5XexNjxK8irVErg==", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, "node_modules/capital-case": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", @@ -50103,6 +50120,12 @@ "@types/node": "*" } }, + "@types/canvas-confetti": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.6.4.tgz", + "integrity": "sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==", + "dev": true + }, "@types/cheerio": { "version": "0.22.31", "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz", @@ -58895,6 +58918,11 @@ "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", "dev": true }, + "canvas-confetti": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.2.tgz", + "integrity": "sha512-6Xi7aHHzKwxZsem4mCKoqP6YwUG3HamaHHAlz1hTNQPCqXhARFpSXnkC9TWlahHY5CG6hSL5XexNjxK8irVErg==" + }, "capital-case": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", diff --git a/package.json b/package.json index 32b6a95a35f..490bab8f986 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "@stripe/stripe-js": "1.15.1", "@woocommerce/explat": "2.3.0", "@woocommerce/number": "2.4.0", + "canvas-confetti": "1.9.2", "crypto-js": "4.1.1", "debug": "4.1.1", "intl-tel-input": "17.0.15", @@ -88,6 +89,7 @@ "@testing-library/react": "11.2.5", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "10.4.1", + "@types/canvas-confetti": "1.6.4", "@types/intl-tel-input": "17.0.4", "@types/lodash": "4.14.170", "@types/react": "17.0.2", From fd41bccee8ec0f9657ce4ceae2185badce269c98 Mon Sep 17 00:00:00 2001 From: Timur Karimov Date: Fri, 19 Jan 2024 20:27:56 +0100 Subject: [PATCH 53/60] Fix failing E2E pipelines (#8048) Co-authored-by: Timur Karimov --- changelog/fix-e2e-tests | 4 ++ ...opper-myaccount-renew-subscription.spec.js | 13 +++-- ...pper-subscriptions-manage-payments.spec.js | 20 +++++--- .../shopper/shopper-checkout-failures.spec.js | 49 ++++++------------- ...myaccount-payment-methods-add-fail.spec.js | 8 ++- .../shopper/shopper-pay-for-order.spec.js | 9 ++-- tests/e2e/utils/flows.js | 49 +++++++++++++++++-- tests/e2e/utils/payments.js | 30 ------------ 8 files changed, 94 insertions(+), 88 deletions(-) create mode 100644 changelog/fix-e2e-tests diff --git a/changelog/fix-e2e-tests b/changelog/fix-e2e-tests new file mode 100644 index 00000000000..6be373a93e5 --- /dev/null +++ b/changelog/fix-e2e-tests @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Allow test pipelines to pass by slightly adjusting HTML selectors diff --git a/tests/e2e/specs/subscriptions/shopper/shopper-myaccount-renew-subscription.spec.js b/tests/e2e/specs/subscriptions/shopper/shopper-myaccount-renew-subscription.spec.js index 41b4f569c80..5ce9187b684 100644 --- a/tests/e2e/specs/subscriptions/shopper/shopper-myaccount-renew-subscription.spec.js +++ b/tests/e2e/specs/subscriptions/shopper/shopper-myaccount-renew-subscription.spec.js @@ -19,7 +19,9 @@ let subscriptionId; const testSelectors = { subscriptionIdField: '.woocommerce-orders-table__cell-subscription-id > a', subscriptionRenewButton: 'a.button.subscription_renewal_early', - wcNotice: '.woocommerce .woocommerce-notices-wrapper .woocommerce-message', + wcNotice: 'div.wc-block-components-notice-banner', + wcOldNotice: + '.woocommerce .woocommerce-notices-wrapper .woocommerce-message', }; describeif( RUN_SUBSCRIPTIONS_TESTS )( @@ -65,10 +67,11 @@ describeif( RUN_SUBSCRIPTIONS_TESTS )( ); // Place an order to renew a subscription - await page.waitForSelector( testSelectors.wcNotice ); - await expect( page ).toMatchElement( testSelectors.wcNotice, { - text: 'Complete checkout to renew now.', - } ); + await shopperWCP.waitForSubscriptionsErrorBanner( + 'Complete checkout to renew now.', + testSelectors.wcNotice, + testSelectors.wcOldNotice + ); await page.waitForNavigation( { waitUntil: 'networkidle0' } ); await shopper.placeOrder(); diff --git a/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.js b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.js index 3b1dc31781f..236c792e8bb 100644 --- a/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.js +++ b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.js @@ -24,7 +24,8 @@ const testSelectors = { subscriptionIdField: '.woocommerce-orders-table__cell-subscription-id > a', subscriptionChangePaymentButton: '.subscription_details a.button.change_payment_method', - wcNotice: '.woocommerce .woocommerce-message', + wcNotice: 'div.wc-block-components-notice-banner', + wcOldNotice: '.woocommerce .woocommerce-message', pageTitle: 'h1.entry-title', newPaymentMethodCheckbox: 'input#wc-woocommerce_payments-payment-token-new', subscriptionPaymentMethod: '.subscription-payment-method', @@ -93,10 +94,11 @@ describeif( RUN_SUBSCRIPTIONS_TESTS )( await fillCardDetails( page, newCard ); await shopper.placeOrder(); - await page.waitForSelector( testSelectors.wcNotice, { - text: 'Payment method updated.', - } ); - + await shopperWCP.waitForSubscriptionsErrorBanner( + 'Payment method updated.', + testSelectors.wcNotice, + testSelectors.wcOldNotice + ); // Verify the new payment method has been set await page.waitForSelector( testSelectors.subscriptionPaymentMethod, @@ -133,9 +135,11 @@ describeif( RUN_SUBSCRIPTIONS_TESTS )( ); await checkboxes[ 0 ].click(); await shopper.placeOrder(); - await page.waitForSelector( testSelectors.wcNotice, { - text: 'Payment method updated.', - } ); + await shopperWCP.waitForSubscriptionsErrorBanner( + 'Payment method updated.', + testSelectors.wcNotice, + testSelectors.wcOldNotice + ); // Verify the new payment method has been set await page.waitForSelector( diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js index 715732b40f9..e1e959effd4 100644 --- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js @@ -2,18 +2,21 @@ * External dependencies */ import config from 'config'; -/** - * Internal dependencies - */ -import { shopperWCP } from '../../../utils'; import { clearCardDetails, fillCardDetails, setupProductCheckout, } from '../../../utils/payments'; +import { shopperWCP } from '../../../utils'; const { uiUnblocked } = require( '@woocommerce/e2e-utils' ); +const notice = 'div.wc-block-components-notice-banner'; +const oldNotice = 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li'; + +const waitForBanner = async ( errorText ) => { + return shopperWCP.waitForErrorBanner( errorText, notice, oldNotice ); +}; describe( 'Shopper > Checkout > Failures with various cards', () => { beforeAll( async () => { @@ -32,12 +35,7 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { await fillCardDetails( page, declinedCard ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( - page - ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { text: 'Error: Your card was declined.' } - ); + await waitForBanner( 'Error: Your card was declined.' ); await clearCardDetails(); } ); @@ -74,12 +72,7 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { await fillCardDetails( page, cardInsufficientFunds ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( - page - ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { text: 'Error: Your card has insufficient funds.' } - ); + await waitForBanner( 'Error: Your card has insufficient funds.' ); await clearCardDetails(); } ); @@ -88,12 +81,7 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { await fillCardDetails( page, cardExpired ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( - page - ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { text: 'Error: Your card has expired.' } - ); + await waitForBanner( 'Error: Your card has expired.' ); await clearCardDetails(); } ); @@ -102,12 +90,7 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { await fillCardDetails( page, cardIncorrectCVC ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( - page - ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { text: "Error: Your card's security code is incorrect." } - ); + await waitForBanner( "Error: Your card's security code is incorrect." ); await clearCardDetails(); } ); @@ -116,12 +99,8 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { await fillCardDetails( page, cardProcessingError ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( page ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { - text: - 'Error: An error occurred while processing your card. Try again in a little bit.', - } + await waitForBanner( + 'Error: An error occurred while processing your card. Try again in a little bit.' ); await clearCardDetails(); } ); @@ -151,7 +130,7 @@ describe( 'Shopper > Checkout > Failures with various cards', () => { ); await expect( page ).toMatch( declined3dsCardError, - 'Error: Your card was declined.' + 'Your card has been declined.' ); } ); } ); diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js index 3db157447e7..f3e3762f48d 100644 --- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js @@ -9,7 +9,10 @@ const { shopper } = require( '@woocommerce/e2e-utils' ); * Internal dependencies */ import { shopperWCP } from '../../../utils/flows'; -const { fillCardDetails } = require( '../../../utils/payments' ); +const { + fillCardDetails, + confirmCardAuthentication, +} = require( '../../../utils/payments' ); const cards = Object.entries( config.get( 'cards' ) ); const invalidCards = cards.filter( ( [ cardType ] ) => @@ -46,6 +49,9 @@ describe( 'Payment Methods', () => { await expect( page ).toClick( 'button', { text: 'Add payment method', } ); + if ( cardType === 'declined-3ds' ) { + await confirmCardAuthentication( page, '3DS2' ); + } await expect( page ).toMatchElement( '.woocommerce-error', { timeout: 30000, } ); diff --git a/tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.js index d9b421ad602..af9491a7885 100644 --- a/tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.js @@ -26,11 +26,10 @@ describe( 'Shopper > Pay for Order', () => { await fillCardDetails( page, declinedCard ); await expect( page ).toClick( '#place_order' ); await uiUnblocked(); - await expect( - page - ).toMatchElement( - 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li', - { text: 'Error: Your card was declined.' } + await shopperWCP.waitForErrorBanner( + 'Error: Your card was declined.', + 'div.wc-block-components-notice-banner', + 'div.woocommerce-NoticeGroup > ul.woocommerce-error > li' ); // after the card has been declined, go to the order page and pay with a basic card diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js index 4eeededd5fb..3399d5b9ffe 100644 --- a/tests/e2e/utils/flows.js +++ b/tests/e2e/utils/flows.js @@ -281,10 +281,11 @@ export const shopperWCP = { await uiUnblocked(); } - await page.waitForSelector( '.cart-empty.woocommerce-info' ); - await expect( page ).toMatchElement( '.cart-empty.woocommerce-info', { - text: 'Your cart is currently empty.', - } ); + await shopperWCP.waitForErrorBanner( + 'Your cart is currently empty.', + 'div.wc-block-components-notice-banner', + '.cart-empty.woocommerce-info' + ); }, goToProductPageBySlug: async ( productSlug ) => { @@ -297,6 +298,46 @@ export const shopperWCP = { await shopperWCP.goToProductPageBySlug( productSlug ); await shopper.addToCart(); }, + + waitForErrorBanner: async ( + errorText, + noticeSelector, + oldNoticeSelector + ) => { + const errorBannerToCheck = ( async () => { + await expect( page ).toMatchElement( noticeSelector, { + text: errorText, + } ); + } )(); + + const oldErrorBannerToCheck = ( async () => { + await expect( page ).toMatchElement( oldNoticeSelector, { + text: errorText, + } ); + } )(); + + await Promise.race( [ errorBannerToCheck, oldErrorBannerToCheck ] ); + }, + + waitForSubscriptionsErrorBanner: async ( + errorText, + errorSelector, + oldErrorSelector + ) => { + const errorBannerToCheck = ( async () => { + return page.waitForSelector( errorSelector, { + text: errorText, + } ); + } )(); + + const oldErrorBannerToCheck = ( async () => { + return page.waitForSelector( oldErrorSelector, { + text: errorText, + } ); + } )(); + + await Promise.race( [ errorBannerToCheck, oldErrorBannerToCheck ] ); + }, }; // The generic flows will be moved to their own package soon (more details in p7bje6-2gV-p2), so we're diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js index c98b70a7fa7..dc09c6d11f0 100644 --- a/tests/e2e/utils/payments.js +++ b/tests/e2e/utils/payments.js @@ -44,36 +44,6 @@ export async function fillCardDetails( page, card ) { if ( zip !== null ) { await zip.type( '90210', { delay: 20 } ); } - } else { - await page.waitForSelector( '.__PrivateStripeElement' ); - const frameHandle = await page.waitForSelector( - '#payment #wcpay-card-element iframe[name^="__privateStripeFrame"]' - ); - const stripeFrame = await frameHandle.contentFrame(); - - const cardNumberInput = await stripeFrame.waitForSelector( - '[name="cardnumber"]', - { timeout: 30000 } - ); - await cardNumberInput.type( card.number, { delay: 20 } ); - await page.waitFor( 1000 ); - - const cardDateInput = await stripeFrame.waitForSelector( - '[name="exp-date"]', - { timeout: 30000 } - ); - - await cardDateInput.type( card.expires.month + card.expires.year, { - delay: 20, - } ); - await page.waitFor( 1000 ); - - const cardCvcInput = await stripeFrame.waitForSelector( - '[name="cvc"]', - { timeout: 30000 } - ); - await cardCvcInput.type( card.cvc, { delay: 20 } ); - await page.waitFor( 1000 ); } } From 21a024b7e1bce749f8088abc53725e6f82c8d4dd Mon Sep 17 00:00:00 2001 From: Daniel Mallory Date: Fri, 19 Jan 2024 21:00:45 +0000 Subject: [PATCH 54/60] Updates to use centralised account status function (#8028) Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com> Co-authored-by: Vlad Olaru --- changelog/dev-centralize-account-status-logic | 4 + includes/admin/class-wc-payments-admin.php | 3 +- includes/class-wc-payment-gateway-wcpay.php | 2 +- includes/class-wc-payments-account.php | 56 ++++++-------- .../admin/test-class-wc-payments-admin.php | 35 +++------ tests/unit/test-class-wc-payments-account.php | 74 ++++++++----------- 6 files changed, 69 insertions(+), 105 deletions(-) create mode 100644 changelog/dev-centralize-account-status-logic diff --git a/changelog/dev-centralize-account-status-logic b/changelog/dev-centralize-account-status-logic new file mode 100644 index 00000000000..5b3d6d32d86 --- /dev/null +++ b/changelog/dev-centralize-account-status-logic @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Updates to account status logic to streamline it. diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php index e6f74194d25..ff01ef19764 100644 --- a/includes/admin/class-wc-payments-admin.php +++ b/includes/admin/class-wc-payments-admin.php @@ -351,7 +351,7 @@ public function add_payments_menu() { } try { // Render full payments menu with sub-items only if the merchant completed the KYC (details_submitted = true). - $should_render_full_menu = $this->account->is_account_fully_onboarded(); + $should_render_full_menu = $this->account->is_stripe_connected() && $this->account->is_details_submitted(); } catch ( Exception $e ) { // There is an issue with connection, don't render full menu, user will get redirected to the connect page. $should_render_full_menu = false; @@ -799,6 +799,7 @@ private function get_js_settings(): array { } $locale_info = include $path; + // Get symbols for those currencies without a short one. $symbols = get_woocommerce_currency_symbols(); $currency_data = []; diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 4c6c3bc92d6..3c4fc105483 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -679,7 +679,7 @@ public function is_connected() { * @return bool */ public function is_account_partially_onboarded(): bool { - return $this->account->is_account_partially_onboarded(); + return $this->account->is_stripe_connected() && ! $this->account->is_details_submitted(); } /** diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index 6c590950da6..3043b06d8a0 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -200,6 +200,7 @@ public function is_stripe_account_valid(): bool { if ( ! $this->is_stripe_connected() ) { return false; } + $account = $this->get_cached_account_data(); if ( ! isset( $account['capabilities']['card_payments'] ) ) { @@ -225,33 +226,18 @@ public function is_account_rejected(): bool { } /** - * Checks if the account has not completed onboarding due to users abandoning the process half way. - * Returns true if the onboarding is started but did not finish. + * Checks if the account "details_submitted" flag is true. + * This is a proxy for telling if an account has completed onboarding. + * If the "details_submitted" flag is false, it means that the account has not + * yet finished the initial KYC. * - * @return bool True if the account is connected and details are not submitted, false otherwise. + * @return boolean True if the account is connected and details are not submitted, false otherwise. */ - public function is_account_partially_onboarded(): bool { - if ( ! $this->is_stripe_connected() ) { - return false; - } - + public function is_details_submitted(): bool { $account = $this->get_cached_account_data(); - return false === $account['details_submitted']; - } - - /** - * Checks if the account has completed onboarding/KYC. - * Returns true if the onboarding/KYC is completed. - * - * @return bool True if the account is connected and details are submitted, false otherwise. - */ - public function is_account_fully_onboarded(): bool { - if ( ! $this->is_stripe_connected() ) { - return false; - } - $account = $this->get_cached_account_data(); - return true === $account['details_submitted']; + $details_submitted = $account['details_submitted'] ?? false; + return true === $details_submitted; } /** @@ -259,7 +245,7 @@ public function is_account_fully_onboarded(): bool { * * @return array An array containing the status data, or [ 'error' => true ] on error or no connected account. */ - public function get_account_status_data() { + public function get_account_status_data(): array { $account = $this->get_cached_account_data(); if ( empty( $account ) ) { @@ -859,31 +845,33 @@ public function maybe_redirect_settings_to_connect_or_overview(): bool { return false; } - // Account fully onboarded, don't redirect. - if ( $this->is_account_fully_onboarded() ) { - return false; - } - - // Account partially onboarded, redirect to overview. - if ( $this->is_account_partially_onboarded() ) { + // Not able to establish Stripe connection, redirect to the Connect page. + if ( ! $this->is_stripe_connected() ) { $this->redirect_to( admin_url( add_query_arg( [ 'page' => 'wc-admin', - 'path' => '/payments/overview', + 'path' => '/payments/connect', ], 'admin.php' ) ) ); + return true; + } + + if ( $this->is_details_submitted() ) { + // Account fully onboarded, don't redirect. + return false; } else { + // Account not yet fully onboarded so redirect to overview page. $this->redirect_to( admin_url( add_query_arg( [ 'page' => 'wc-admin', - 'path' => '/payments/connect', + 'path' => '/payments/overview', ], 'admin.php' ) @@ -967,7 +955,7 @@ public function maybe_handle_onboarding() { if ( isset( $_GET['wcpay-login'] ) && check_admin_referer( 'wcpay-login' ) ) { try { - if ( $this->is_account_partially_onboarded() ) { + if ( $this->is_stripe_connected() && ! $this->is_details_submitted() ) { $args = $_GET; $args['type'] = 'complete_kyc_link'; diff --git a/tests/unit/admin/test-class-wc-payments-admin.php b/tests/unit/admin/test-class-wc-payments-admin.php index 65b75d854fe..1f828d877b8 100644 --- a/tests/unit/admin/test-class-wc-payments-admin.php +++ b/tests/unit/admin/test-class-wc-payments-admin.php @@ -134,19 +134,13 @@ public function tear_down() { parent::tear_down(); } - /** - * @dataProvider feature_flag_combinations_not_causing_settings_badge_render_provider - * - * @param bool $is_upe_settings_preview_enabled - * @param bool $is_upe_enabled - */ - public function test_it_does_not_render_settings_badge( $is_upe_settings_preview_enabled, $is_upe_enabled ) { + public function test_it_does_not_render_settings_badge(): void { global $submenu; $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); @@ -161,7 +155,7 @@ public function test_it_does_not_render_payments_badge_if_stripe_is_connected() $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); @@ -180,7 +174,7 @@ public function test_it_refreshes_the_cache_if_get_param_exists() { ]; // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->mock_account->expects( $this->once() )->method( 'refresh_account_data' ); $this->payments_admin->add_payments_menu(); @@ -195,7 +189,7 @@ public function test_it_renders_payments_badge_if_activation_date_is_older_than_ $this->mock_current_user_is_admin(); // Make sure we render the menu without submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( false ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( false ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( false ); update_option( 'wcpay_activation_timestamp', time() - ( 3 * DAY_IN_SECONDS ) ); $this->payments_admin->add_payments_menu(); @@ -210,7 +204,7 @@ public function test_it_does_not_render_payments_badge_if_activation_date_is_les $this->mock_current_user_is_admin(); // Make sure we render the menu without submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( false ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( false ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( false ); update_option( 'wcpay_menu_badge_hidden', 'no' ); update_option( 'wcpay_activation_timestamp', time() - ( DAY_IN_SECONDS * 2 ) ); @@ -221,15 +215,6 @@ public function test_it_does_not_render_payments_badge_if_activation_date_is_les $this->assertArrayNotHasKey( 'wc-admin&path=/payments/overview', $item_names_by_urls ); } - public function feature_flag_combinations_not_causing_settings_badge_render_provider() { - return [ - [ false, false ], - [ false, true ], - [ true, false ], - [ true, true ], - ]; - } - private function mock_current_user_is_admin() { $admin_user = self::factory()->user->create( [ 'role' => 'administrator' ] ); wp_set_current_user( $admin_user ); @@ -514,7 +499,7 @@ public function test_disputes_notification_badge_display() { $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); @@ -556,7 +541,7 @@ public function test_disputes_notification_badge_no_display() { $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); @@ -600,7 +585,7 @@ public function test_transactions_notification_badge_display() { $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); @@ -646,7 +631,7 @@ public function test_transactions_notification_badge_no_display() { $this->mock_current_user_is_admin(); // Make sure we render the menu with submenu items. - $this->mock_account->method( 'is_account_fully_onboarded' )->willReturn( true ); + $this->mock_account->method( 'is_details_submitted' )->willReturn( true ); $this->mock_account->method( 'is_stripe_connected' )->willReturn( true ); $this->payments_admin->add_payments_menu(); diff --git a/tests/unit/test-class-wc-payments-account.php b/tests/unit/test-class-wc-payments-account.php index 35a94949c56..a872511ba2d 100644 --- a/tests/unit/test-class-wc-payments-account.php +++ b/tests/unit/test-class-wc-payments-account.php @@ -931,53 +931,39 @@ public function test_is_account_rejected_returns_false_on_error() { $this->assertFalse( $this->wcpay_account->is_account_rejected() ); } - public function test_is_account_partially_onboarded_returns_true() { - $this->mock_database_cache->expects( $this->exactly( 2 ) )->method( 'get_or_add' )->willReturn( - [ - 'account_id' => 'acc_test', - 'live_publishable_key' => 'pk_test_', - 'test_publishable_key' => 'pk_live_', - 'has_pending_requirements' => true, - 'current_deadline' => 12345, - 'is_live' => true, - 'status' => 'restricted', - 'details_submitted' => false, - ] - ); - - $this->assertTrue( $this->wcpay_account->is_account_partially_onboarded() ); - - } - - public function test_is_account_partially_onboarded_returns_false() { - $this->mock_database_cache->expects( $this->exactly( 2 ) )->method( 'get_or_add' )->willReturn( - [ - 'account_id' => 'acc_test', - 'live_publishable_key' => 'pk_test_', - 'test_publishable_key' => 'pk_live_', - 'has_pending_requirements' => true, - 'current_deadline' => 12345, - 'is_live' => true, - 'status' => 'restricted', - 'details_submitted' => true, - ] - ); - - $this->assertFalse( $this->wcpay_account->is_account_partially_onboarded() ); + /** + * Test the is_details_submitted method. + * + * @param bool $details_submitted Whether details_submitted is true for the account. + * + * @return void + * + * @dataProvider is_details_submitted_provider + */ + public function test_is_details_submitted( bool $details_submitted ): void { + $this->mock_database_cache->expects( $this->once() ) + ->method( 'get_or_add' ) + ->willReturn( + [ + 'account_id' => 'acc_test', + 'live_publishable_key' => 'pk_test_', + 'test_publishable_key' => 'pk_live_', + 'has_pending_requirements' => true, + 'current_deadline' => 12345, + 'is_live' => true, + 'status' => 'restricted', + 'details_submitted' => $details_submitted, + ] + ); + $this->assertEquals( $details_submitted, $this->wcpay_account->is_details_submitted() ); } - public function test_is_account_partially_onboarded_returns_false_when_stripe_not_connected() { - $this->mock_empty_cache(); - - $this->mock_wcpay_request( Get_Account::class ) - ->expects( $this->once() ) - ->method( 'format_response' ) - ->willThrowException( - new API_Exception( 'test', 'wcpay_account_not_found', 401 ) - ); - - $this->assertFalse( $this->wcpay_account->is_account_partially_onboarded() ); + public function is_details_submitted_provider(): array { + return [ + [ true ], + [ false ], + ]; } public function test_is_account_partially_onboarded_returns_false_if_account_not_connected() { From 8f6b267928fb12bee30cb0ba6d1773e9c24b4ff2 Mon Sep 17 00:00:00 2001 From: Daniel Mallory Date: Sat, 20 Jan 2024 20:47:12 +0000 Subject: [PATCH 55/60] Update dev mode to Sandbox mode throughout the plugin (#8004) Co-authored-by: Vlad Olaru --- README.md | 2 +- changelog/update-dev-mode-labels | 4 ++++ .../account-status/account-tools/test/index.test.tsx | 2 +- client/components/test-mode-notice/index.tsx | 4 ++-- .../test-mode-notice/test/__snapshots__/index.tsx.snap | 2 +- client/onboarding/steps/test/mode-choice.tsx | 2 +- client/onboarding/strings.tsx | 2 +- client/overview/index.js | 2 +- client/overview/strings.tsx | 2 +- client/settings/advanced-settings/debug-mode.js | 2 +- client/settings/advanced-settings/test/debug-mode.test.js | 6 +++--- client/settings/general-settings/index.js | 4 ++-- .../general-settings/test/test-mode-confirm-modal.test.js | 4 ++-- client/settings/support-phone-input/index.js | 2 +- .../support-phone-input/test/support-phone-input.test.js | 2 +- client/utils/index.js | 6 +++--- includes/admin/class-wc-payments-admin.php | 2 +- .../admin/class-wc-rest-payments-settings-controller.php | 4 ++-- includes/class-wc-payment-gateway-wcpay.php | 4 ++-- includes/class-wc-payments-account.php | 2 +- includes/core/README.md | 6 +++--- includes/core/class-mode.php | 6 +++--- .../core/server/request/class-get-account-login-data.md | 2 +- includes/core/server/request/class-get-account.md | 2 +- 24 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 changelog/update-dev-mode-labels diff --git a/README.md b/README.md index 72508e1b51a..f43b580b083 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ We currently support the following variables: ## Test account setup -For setting up a test account follow [these instructions](https://woo.com/document/woopayments/testing-and-troubleshooting/dev-mode/). +For setting up a test account follow [these instructions](https://woo.com/document/woopayments/testing-and-troubleshooting/sandbox-mode/). You will need a externally accessible URL to set up the plugin. You can use ngrok for this. diff --git a/changelog/update-dev-mode-labels b/changelog/update-dev-mode-labels new file mode 100644 index 00000000000..df9ff952e45 --- /dev/null +++ b/changelog/update-dev-mode-labels @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Update references to dev mode to use sandbox mode terminology. diff --git a/client/components/account-status/account-tools/test/index.test.tsx b/client/components/account-status/account-tools/test/index.test.tsx index 7c5827b115a..295970da639 100644 --- a/client/components/account-status/account-tools/test/index.test.tsx +++ b/client/components/account-status/account-tools/test/index.test.tsx @@ -31,7 +31,7 @@ describe( 'AccountTools', () => { expect( container ).toMatchSnapshot(); } ); - it( 'should not render in dev mode', () => { + it( 'should not render in sandbox mode', () => { global.wcpaySettings = { devMode: true, }; diff --git a/client/components/test-mode-notice/index.tsx b/client/components/test-mode-notice/index.tsx index 80310707a46..f77dcaff4a7 100644 --- a/client/components/test-mode-notice/index.tsx +++ b/client/components/test-mode-notice/index.tsx @@ -59,7 +59,7 @@ const getNoticeContent = ( mixedString: sprintf( /* translators: %1$s: WooPayments */ __( - '{{strong}}%1$s is in dev mode.{{/strong}} You need to set up a live %1$s account before you can accept real transactions.', + '{{strong}}%1$s is in sandbox mode.{{/strong}} You need to set up a live %1$s account before you can accept real transactions.', 'woocommerce-payments' ), 'WooPayments' @@ -87,7 +87,7 @@ const getNoticeContent = ( // eslint-disable-next-line jsx-a11y/anchor-has-content diff --git a/client/onboarding/steps/test/mode-choice.tsx b/client/onboarding/steps/test/mode-choice.tsx index 4ad0f2996e0..d6400d98936 100644 --- a/client/onboarding/steps/test/mode-choice.tsx +++ b/client/onboarding/steps/test/mode-choice.tsx @@ -27,7 +27,7 @@ declare const global: { }; describe( 'ModeChoice', () => { - it( 'displays test and live radio cards, notice for dev mode', () => { + it( 'displays test and live radio cards, notice for sandbox mode', () => { global.wcpaySettings = { connectUrl: 'https://wcpay.test/connect', devMode: true, diff --git a/client/onboarding/strings.tsx b/client/onboarding/strings.tsx index fdeba48f840..a1578aacb61 100644 --- a/client/onboarding/strings.tsx +++ b/client/onboarding/strings.tsx @@ -8,7 +8,7 @@ import React from 'react'; const documentationUrls = { sandboxMode: - 'https://woo.com/document/woopayments/testing-and-troubleshooting/dev-mode/', + 'https://woo.com/document/woopayments/testing-and-troubleshooting/sandbox-mode/', tos: 'https://wordpress.com/tos/', merchantTerms: 'https://wordpress.com/tos/#more-woopay-specifically', privacyPolicy: 'https://automattic.com/privacy/', diff --git a/client/overview/index.js b/client/overview/index.js index 124805902bc..fca15a172ad 100644 --- a/client/overview/index.js +++ b/client/overview/index.js @@ -152,7 +152,7 @@ const OverviewPage = () => { { label: strings.notice.actions.learnMore, url: - 'https://woo.com/document/woopayments/testing-and-troubleshooting/dev-mode/', + 'https://woo.com/document/woopayments/testing-and-troubleshooting/sandbox-mode/', urlTarget: '_blank', }, ] diff --git a/client/overview/strings.tsx b/client/overview/strings.tsx index 43ab5d47bb5..39ceda5d1e2 100644 --- a/client/overview/strings.tsx +++ b/client/overview/strings.tsx @@ -26,7 +26,7 @@ export default { mixedString: sprintf( /* translators: %1$s: WooPayments */ __( - '{{bold}}%1s is in dev mode.{{bold /}}. You need to set up a live %1s account before you can accept real transactions.', + '{{bold}}%1s is in sandbox mode.{{bold /}}. You need to set up a live %1s account before you can accept real transactions.', 'woocommerce-payments' ), 'WooPayments' diff --git a/client/settings/advanced-settings/debug-mode.js b/client/settings/advanced-settings/debug-mode.js index f1b5a09c7a3..97fcae3e63b 100644 --- a/client/settings/advanced-settings/debug-mode.js +++ b/client/settings/advanced-settings/debug-mode.js @@ -22,7 +22,7 @@ const DebugMode = () => { label={ isDevModeEnabled ? __( - 'Dev mode is active so logging is on by default.', + 'Sandbox mode is active so logging is on by default.', 'woocommerce-payments' ) : __( 'Log error messages', 'woocommerce-payments' ) diff --git a/client/settings/advanced-settings/test/debug-mode.test.js b/client/settings/advanced-settings/test/debug-mode.test.js index 54877787745..749fdaf6c73 100644 --- a/client/settings/advanced-settings/test/debug-mode.test.js +++ b/client/settings/advanced-settings/test/debug-mode.test.js @@ -34,7 +34,7 @@ describe( 'DebugMode', () => { expect( screen.queryByText( - 'Dev mode is active so logging is on by default.' + 'Sandbox mode is active so logging is on by default.' ) ).not.toBeInTheDocument(); expect( loggingCheckbox ).not.toBeChecked(); @@ -45,13 +45,13 @@ describe( 'DebugMode', () => { expect( setDebugLogMock ).toHaveBeenCalledWith( true ); } ); - it( 'prevents toggling the logging checkbox when dev mode is active', () => { + it( 'prevents toggling the logging checkbox when sandbox mode is active', () => { useDevMode.mockReturnValue( true ); render( ); const loggingCheckbox = screen.queryByRole( 'checkbox', { - name: 'Dev mode is active so logging is on by default.', + name: 'Sandbox mode is active so logging is on by default.', } ); expect( diff --git a/client/settings/general-settings/index.js b/client/settings/general-settings/index.js index b85e9e07632..cdfbd054211 100644 --- a/client/settings/general-settings/index.js +++ b/client/settings/general-settings/index.js @@ -115,7 +115,7 @@ const GeneralSettings = () => { mixedString: sprintf( /* translators: %s: WooPayments */ __( - '{{b}}%1$s is in dev mode.{{/b}} You need to set up a live %1$s account before ' + + '{{b}}%1$s is in sandbox mode.{{/b}} You need to set up a live %1$s account before ' + 'you can accept real transactions. {{learnMoreLink}}Learn more{{/learnMoreLink}}', 'woocommerce-payments' ), @@ -128,7 +128,7 @@ const GeneralSettings = () => {
), }, diff --git a/client/settings/general-settings/test/test-mode-confirm-modal.test.js b/client/settings/general-settings/test/test-mode-confirm-modal.test.js index df247142d81..a3a019a5e17 100644 --- a/client/settings/general-settings/test/test-mode-confirm-modal.test.js +++ b/client/settings/general-settings/test/test-mode-confirm-modal.test.js @@ -15,7 +15,7 @@ import TestModeConfirmationModal from '../test-mode-confirm-modal'; const mockOnClose = jest.fn(); const mockOnConfirm = jest.fn(); -describe( 'Dev Mode Confirmation Modal', () => { +describe( 'Sandbox Mode Confirmation Modal', () => { const renderTestModeConfirmationModal = () => { return render( { ); }; - it( 'Dev mode confirmation modal asks confirmation', () => { + it( 'Sandbox mode confirmation modal asks confirmation', () => { renderTestModeConfirmationModal(); expect( screen.queryByText( 'Are you sure you want to enable test mode?' ) diff --git a/client/settings/support-phone-input/index.js b/client/settings/support-phone-input/index.js index 4a9259b62d4..f4741f4ddaf 100644 --- a/client/settings/support-phone-input/index.js +++ b/client/settings/support-phone-input/index.js @@ -51,7 +51,7 @@ const SupportPhoneInput = ( { setInputVallid } ) => { let labelText = __( 'Support phone number', 'woocommerce-payments' ); if ( isDevModeEnabled ) { labelText += __( - ' (+1 0000000000 can be used in dev mode)', + ' (+1 0000000000 can be used in sandbox mode)', 'woocommerce-payments' ); } diff --git a/client/settings/support-phone-input/test/support-phone-input.test.js b/client/settings/support-phone-input/test/support-phone-input.test.js index 37262b03796..a86c66ae12e 100644 --- a/client/settings/support-phone-input/test/support-phone-input.test.js +++ b/client/settings/support-phone-input/test/support-phone-input.test.js @@ -98,7 +98,7 @@ describe( 'SupportPhoneInput', () => { ).toEqual( 'Please enter a valid phone number.' ); } ); - it( 'in dev mode, allow all 0s number', async () => { + it( 'in sandbox mode, allow all 0s number', async () => { useAccountBusinessSupportPhone.mockReturnValue( [ '+10000000000', // test phone number. jest.fn(), diff --git a/client/utils/index.js b/client/utils/index.js index d6e7a1c971d..f10cb308251 100644 --- a/client/utils/index.js +++ b/client/utils/index.js @@ -23,11 +23,11 @@ export const isInTestMode = ( fallback = false ) => { }; /** - * Returns true if WooPayments is in dev mode, false otherwise. + * Returns true if WooPayments is in dev/sandbox mode, false otherwise. * - * @param {boolean} fallback Fallback in case dev mode value can't be found (for example if the wcpaySettings are undefined). + * @param {boolean} fallback Fallback in case dev/sandbox mode value can't be found (for example if the wcpaySettings are undefined). * - * @return {boolean} True if in dev mode, false otherwise. Fallback value if test/dev mode value can't be found. + * @return {boolean} True if in dev/sandbox mode, false otherwise. Fallback value if dev/sandbox mode value can't be found. */ export const isInDevMode = ( fallback = false ) => { if ( typeof wcpaySettings === 'undefined' ) { diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php index ff01ef19764..179c1b2ddc6 100644 --- a/includes/admin/class-wc-payments-admin.php +++ b/includes/admin/class-wc-payments-admin.php @@ -829,7 +829,7 @@ private function get_js_settings(): array { try { $dev_mode = WC_Payments::mode()->is_dev(); } catch ( Exception $e ) { - Logger::log( sprintf( 'WooPayments JS settings: Could not determine if WCPay should be in dev mode! Message: %s', $e->getMessage() ), 'warning' ); + Logger::log( sprintf( 'WooPayments JS settings: Could not determine if WCPay should be in sandbox mode! Message: %s', $e->getMessage() ), 'warning' ); } $connect_url = WC_Payments_Account::get_connect_url(); diff --git a/includes/admin/class-wc-rest-payments-settings-controller.php b/includes/admin/class-wc-rest-payments-settings-controller.php index aed37660980..97c5087e46d 100644 --- a/includes/admin/class-wc-rest-payments-settings-controller.php +++ b/includes/admin/class-wc-rest-payments-settings-controller.php @@ -677,7 +677,7 @@ private function update_is_manual_capture_enabled( WP_REST_Request $request ) { * @param WP_REST_Request $request Request object. */ private function update_is_test_mode_enabled( WP_REST_Request $request ) { - // avoiding updating test mode when dev mode is enabled. + // Avoid updating test mode when dev mode is enabled. if ( WC_Payments::mode()->is_dev() ) { return; } @@ -697,7 +697,7 @@ private function update_is_test_mode_enabled( WP_REST_Request $request ) { * @param WP_REST_Request $request Request object. */ private function update_is_debug_log_enabled( WP_REST_Request $request ) { - // avoiding updating test mode when dev mode is enabled. + // Avoid updating test mode when dev mode is enabled. if ( WC_Payments::mode()->is_dev() ) { return; } diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 3c4fc105483..7d165269b4c 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -2357,12 +2357,12 @@ public function generate_checkbox_html( $key, $data ) { if ( 'test_mode' === $key && $in_dev_mode ) { $data['custom_attributes']['disabled'] = 'disabled'; - $data['label'] = __( 'Dev mode is active so all transactions will be in test mode. This setting is only available to live accounts.', 'woocommerce-payments' ); + $data['label'] = __( 'Sandbox mode is active so all transactions will be in test mode. This setting is only available to live accounts.', 'woocommerce-payments' ); } if ( 'enable_logging' === $key && $in_dev_mode ) { $data['custom_attributes']['disabled'] = 'disabled'; - $data['label'] = __( 'Dev mode is active so logging is on by default.', 'woocommerce-payments' ); + $data['label'] = __( 'Sandbox mode is active so logging is on by default.', 'woocommerce-payments' ); } return parent::generate_checkbox_html( $key, $data ); diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index 3043b06d8a0..db60f3df5d3 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -907,7 +907,7 @@ public function maybe_redirect_onboarding_flow_to_overview(): bool { // We check it here after refreshing the cache, because merchant might have clicked back in browser (after Stripe KYC). // That will mean that no redirect from Stripe happened and user might be able to go through onboarding again if no webhook processed yet. - // That might cause issues if user selects dev onboarding after live one. + // That might cause issues if user selects sandbox onboarding after live one. // Shouldn't be called with force disconnected option enabled, otherwise we'll get current account data. if ( ! WC_Payments_Utils::force_disconnected_enabled() ) { $this->refresh_account_data(); diff --git a/includes/core/README.md b/includes/core/README.md index 45fd0a68c42..59465c1b73e 100644 --- a/includes/core/README.md +++ b/includes/core/README.md @@ -59,13 +59,13 @@ This is a singular `WCPay\Core\Mode` object, accessible through `WC_Payments::mo During initialization, the following logic is used: -1. Dev mode would be entered if: +1. Sandbox mode would be entered if: - Either [WordPress's environment type](https://developer.wordpress.org/reference/functions/wp_get_environment_type/#description) is either `development` or `staging`. - or `WCPAY_DEV_MODE` is defined and set to boolean true. 2. Test mode is entered if: - - Either Dev mode is already enabled. + - Either Sandbox mode is already enabled. - or the gateway's test mode setting is on. -3. If the gateway is neither in dev or test mode, live mode is entered. +3. If the gateway is neither in sandbox or test mode, live mode is entered. To alter this behavior, you can use the `wcpay_dev_mode` and `wcpay_test_mode` filters, for example: diff --git a/includes/core/class-mode.php b/includes/core/class-mode.php index f80fc72d2d5..721b8ea689d 100644 --- a/includes/core/class-mode.php +++ b/includes/core/class-mode.php @@ -66,9 +66,9 @@ private function maybe_init() { ); /** - * Allows WooCommerce to enter dev mode. + * Allows WooPayments to enter dev (aka sandbox) mode. * - * @see https://woo.com/document/woopayments/testing-and-troubleshooting/dev-mode/ + * @see https://woo.com/document/woopayments/testing-and-troubleshooting/sandbox-mode/ * @param bool $dev_mode The pre-determined dev mode. */ $this->dev_mode = (bool) apply_filters( 'wcpay_dev_mode', $dev_mode ); @@ -80,7 +80,7 @@ private function maybe_init() { $test_mode = $this->dev_mode || $test_mode_setting; /** - * Allows WooCommerce to enter test mode. + * Allows WooPayments to enter test mode. * * @see https://woo.com/document/woopayments/testing-and-troubleshooting/testing/#enabling-test-mode * @param bool $test_mode The pre-determined test mode. diff --git a/includes/core/server/request/class-get-account-login-data.md b/includes/core/server/request/class-get-account-login-data.md index 4ea6a6f37e9..3f3675207e4 100644 --- a/includes/core/server/request/class-get-account-login-data.md +++ b/includes/core/server/request/class-get-account-login-data.md @@ -5,7 +5,7 @@ ## Description The `WCPay\Core\Server\Request\Get_Account_Login_Data` class is used to construct the request for getting one-time dashboard login url. -Note that this request sends the test_mode flag only when the site is in the dev mode. +Note that this request sends the test_mode flag only when the site is in sandbox mode. ## Parameters diff --git a/includes/core/server/request/class-get-account.md b/includes/core/server/request/class-get-account.md index 7cdd3cd4330..48606f63de9 100644 --- a/includes/core/server/request/class-get-account.md +++ b/includes/core/server/request/class-get-account.md @@ -5,7 +5,7 @@ ## Description The `WCPay\Core\Server\Request\Get_Account` class is used to construct the request for retrieving account data. -Note that this request sends the test_mode flag only when the site is in the dev mode. +Note that this request sends the test_mode flag only when the site is in sandbox mode. ## Parameters From 18914b9e1418b060efee250b45d833facb7ba012 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 21 Jan 2024 12:07:56 +0000 Subject: [PATCH 56/60] Update version and add changelog entries for release 7.1.0 --- changelog.txt | 48 ++++++++++++++++++ .../7996-wcpayPaymentRequestPayForOrderParams | 4 -- .../8025-fix-safe-mode-message-reverse-host | 4 -- changelog/add-3943-send-blog-theme-to-sift | 4 -- changelog/add-7397-e2e-disputed-order-notice | 5 -- changelog/add-7711-instant-deposit-currency | 4 -- changelog/add-7961-track-transactions-search | 4 -- changelog/add-place-order-tracks | 4 -- changelog/add-prb-load-tracks | 4 -- changelog/add-save-my-info-tracks | 4 -- ...mpatibility-service-include-active-plugins | 4 -- ...4-compatibility-service-include-post-types | 4 -- .../add-transaction-id-to-refund-endpoint | 4 -- changelog/align-stripe-link-behavior | 4 -- changelog/dev-7731-update-dev-mode-choice | 4 -- changelog/dev-7886-add-country-codes-enum | 4 -- changelog/dev-centralize-account-status-logic | 4 -- ...dev-refactor-order-dispute-refundable-util | 3 -- changelog/fix-2199-woopay-duplicate-payments | 5 -- ...2395-rerender-woopay-button-on-cart-update | 4 -- ...-2493-filter-subscriptions-payment-request | 4 -- ...fix-6424-update-settings-deposit-notice-ui | 4 -- changelog/fix-6810-bnpl-sorting | 4 -- ...-6881-stripe-link-blocks-checkout-refactor | 4 -- changelog/fix-7568-tidy-disputed-order-notice | 4 -- .../fix-7799-pay-for-order-error-message | 4 -- changelog/fix-7819-incorrect-test-mode-notice | 4 -- changelog/fix-7881-strict-return-type | 4 -- changelog/fix-7929-link-button-alignment | 4 -- ...nsaction-details-dispute-details-broken-ui | 5 -- ...-transaction-refund-eligible-disputes-only | 4 -- .../fix-7964-typo-for-transaction-actions | 5 -- ...7967-disputed-order-notice-test-mode-check | 4 -- ...ck-items-when-refund-from-transaction-page | 4 -- ...larify-calendar-days-waiting-period-notice | 4 -- changelog/fix-7984-allow-zero-amount-refunds | 4 -- ...-basic-filter-dropdowns-on-analytics-pages | 4 -- ...fix-8040-new-account-waiting-period-notice | 4 -- changelog/fix-e2e-tests | 4 -- changelog/fix-place-order-js-error | 5 -- ...ansaction-refund-options-for-missing-order | 4 -- changelog/fix-trim-woopay-source-url | 4 -- changelog/fix-unnecessary-import-warning | 4 -- changelog/fix-woopay-adapted-extensions | 5 -- changelog/fix-woopay-tablet-breakpoint | 4 -- changelog/merge-upe-non-upe-tests | 4 -- changelog/refactor-logger | 5 -- changelog/refactor-mode-class | 5 -- changelog/send-metadata-in-error-message | 4 -- changelog/subscriptions-core-6.7.1 | 4 -- changelog/subscriptions-core-6.7.1-2 | 4 -- changelog/subscriptions-core-6.7.1-3 | 4 -- changelog/subscriptions-core-6.7.1-4 | 4 -- changelog/update-7579-po-success-modal | 5 -- ...pdate-7856-add-charge-txn-id-to-order-meta | 4 -- changelog/update-dev-mode-labels | 4 -- changelog/update-jetpack-dependencies | 4 -- package-lock.json | 4 +- package.json | 2 +- readme.txt | 50 ++++++++++++++++++- woocommerce-payments.php | 2 +- 61 files changed, 101 insertions(+), 237 deletions(-) delete mode 100644 changelog/7996-wcpayPaymentRequestPayForOrderParams delete mode 100644 changelog/8025-fix-safe-mode-message-reverse-host delete mode 100644 changelog/add-3943-send-blog-theme-to-sift delete mode 100644 changelog/add-7397-e2e-disputed-order-notice delete mode 100644 changelog/add-7711-instant-deposit-currency delete mode 100644 changelog/add-7961-track-transactions-search delete mode 100644 changelog/add-place-order-tracks delete mode 100644 changelog/add-prb-load-tracks delete mode 100644 changelog/add-save-my-info-tracks delete mode 100644 changelog/add-server-3942-compatibility-service-include-active-plugins delete mode 100644 changelog/add-server-3944-compatibility-service-include-post-types delete mode 100644 changelog/add-transaction-id-to-refund-endpoint delete mode 100644 changelog/align-stripe-link-behavior delete mode 100644 changelog/dev-7731-update-dev-mode-choice delete mode 100644 changelog/dev-7886-add-country-codes-enum delete mode 100644 changelog/dev-centralize-account-status-logic delete mode 100644 changelog/dev-refactor-order-dispute-refundable-util delete mode 100644 changelog/fix-2199-woopay-duplicate-payments delete mode 100644 changelog/fix-2395-rerender-woopay-button-on-cart-update delete mode 100644 changelog/fix-2493-filter-subscriptions-payment-request delete mode 100644 changelog/fix-6424-update-settings-deposit-notice-ui delete mode 100644 changelog/fix-6810-bnpl-sorting delete mode 100644 changelog/fix-6881-stripe-link-blocks-checkout-refactor delete mode 100644 changelog/fix-7568-tidy-disputed-order-notice delete mode 100644 changelog/fix-7799-pay-for-order-error-message delete mode 100644 changelog/fix-7819-incorrect-test-mode-notice delete mode 100644 changelog/fix-7881-strict-return-type delete mode 100644 changelog/fix-7929-link-button-alignment delete mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui delete mode 100644 changelog/fix-7960-transaction-refund-eligible-disputes-only delete mode 100644 changelog/fix-7964-typo-for-transaction-actions delete mode 100644 changelog/fix-7967-disputed-order-notice-test-mode-check delete mode 100644 changelog/fix-7969-restock-items-when-refund-from-transaction-page delete mode 100644 changelog/fix-7970-clarify-calendar-days-waiting-period-notice delete mode 100644 changelog/fix-7984-allow-zero-amount-refunds delete mode 100644 changelog/fix-7991-blank-square-in-the-upper-left-corner-of-basic-filter-dropdowns-on-analytics-pages delete mode 100644 changelog/fix-8040-new-account-waiting-period-notice delete mode 100644 changelog/fix-e2e-tests delete mode 100644 changelog/fix-place-order-js-error delete mode 100644 changelog/fix-transaction-refund-options-for-missing-order delete mode 100644 changelog/fix-trim-woopay-source-url delete mode 100644 changelog/fix-unnecessary-import-warning delete mode 100644 changelog/fix-woopay-adapted-extensions delete mode 100644 changelog/fix-woopay-tablet-breakpoint delete mode 100644 changelog/merge-upe-non-upe-tests delete mode 100644 changelog/refactor-logger delete mode 100644 changelog/refactor-mode-class delete mode 100644 changelog/send-metadata-in-error-message delete mode 100644 changelog/subscriptions-core-6.7.1 delete mode 100644 changelog/subscriptions-core-6.7.1-2 delete mode 100644 changelog/subscriptions-core-6.7.1-3 delete mode 100644 changelog/subscriptions-core-6.7.1-4 delete mode 100644 changelog/update-7579-po-success-modal delete mode 100644 changelog/update-7856-add-charge-txn-id-to-order-meta delete mode 100644 changelog/update-dev-mode-labels delete mode 100644 changelog/update-jetpack-dependencies diff --git a/changelog.txt b/changelog.txt index 68da1290131..142b00a5444 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,53 @@ *** WooPayments Changelog *** += 7.1.0 - 2024-01-24 = +* Add - Add active plugins array to compatibility data. +* Add - Add post_types and their counts as an array to compatibility data. +* Add - Add the active theme name of the blog to the compatibility service +* Add - Expose the refund transaction ID in WooCommerce Order Refund API +* Add - Select the proper payment element when using saved Stripe Link tokens or choosing to use Stripe Link for new email. +* Add - Track filtering interactions on the Transactions page. +* Fix - Allow subscription purchase via Payment Request when no shipping methods are present. +* Fix - Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. +* Fix - Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page +* Fix - Checkout error when page URL is too long +* Fix - Fix incorrect test mode notice when left KYC early after going live from builder mode +* Fix - Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. +* Fix - fix pay-for-order quirks and 3DS behavior +* Fix - Fix Safe Mode message reversed host +* Fix - Fix Stripe Link autofill on checkout. +* Fix - Fix Stripe Link button alignment in the Checkout Block +* Fix - Hide the transaction details refund menu for ineligble disputed transactions +* Fix - Improve clarity & readability of disputed order notice (not all text bold). +* Fix - Prevent possible fatal when using get_edit_post_link filter. +* Fix - Re-render WooPay button when cart updates, when checkout updates. +* Fix - Reinstate first deposit waiting period notice in payments overview (fix bug) +* Fix - Remove unnecessary import statement which leads to a warning when first loaded +* Fix - Resolved an error that would occur with WC 8.5.0 when editing a subscription customer from the admin dashboard. +* Fix - Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled. +* Fix - Restock order items when performing full refund from transaction details page +* Fix - Reverting to manual styling over native WordPress components to fix CSS defects on Analytics page +* Fix - Send metadata in error message +* Fix - Show the correct number of days in the new account waiting period notice. +* Fix - Update WooPay tablet breakpoint. +* Fix - Verify that order exists before offering "Partial refund" option on transaction details page. +* Update - Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing. +* Update - Pass currency parameter and not transaction_ids parameter when creating instant deposit. +* Update - Store balance transaction ID in order metadata. +* Update - Updated BNPL sorting in settings for consistency with onboarding. +* Update - Update references to dev mode to use sandbox mode terminology. +* Update - Updates to the styling of the onboarding mode selection page. +* Update - Update style of notices within the deposits section of the settings screen. +* Dev - Added enum class for country codes +* Dev - Add new Tracks events to WooPay Save My Info checkbox +* Dev - Allow test pipelines to pass by slightly adjusting HTML selectors +* Dev - Merge UPE tests into the single and main gateway test file for unit and E2E tests. +* Dev - Place order button Tracks +* Dev - Track payment-request-button loads +* Dev - Update jetpack dependencies for syncing. +* Dev - Updates to account status logic to streamline it. +* Dev - Update subscriptions-core to 6.7.1. + = 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. diff --git a/changelog/7996-wcpayPaymentRequestPayForOrderParams b/changelog/7996-wcpayPaymentRequestPayForOrderParams deleted file mode 100644 index de2d1870de3..00000000000 --- a/changelog/7996-wcpayPaymentRequestPayForOrderParams +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page diff --git a/changelog/8025-fix-safe-mode-message-reverse-host b/changelog/8025-fix-safe-mode-message-reverse-host deleted file mode 100644 index a4b72307417..00000000000 --- a/changelog/8025-fix-safe-mode-message-reverse-host +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix Safe Mode message reversed host diff --git a/changelog/add-3943-send-blog-theme-to-sift b/changelog/add-3943-send-blog-theme-to-sift deleted file mode 100644 index 7f67989d63f..00000000000 --- a/changelog/add-3943-send-blog-theme-to-sift +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add the active theme name of the blog to the compatibility service diff --git a/changelog/add-7397-e2e-disputed-order-notice b/changelog/add-7397-e2e-disputed-order-notice deleted file mode 100644 index 97426df9698..00000000000 --- a/changelog/add-7397-e2e-disputed-order-notice +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: Not user-facing: add e2e test for viewing the dispute details via the disputed order notice - - diff --git a/changelog/add-7711-instant-deposit-currency b/changelog/add-7711-instant-deposit-currency deleted file mode 100644 index 145bc27f8d1..00000000000 --- a/changelog/add-7711-instant-deposit-currency +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Pass currency parameter and not transaction_ids parameter when creating instant deposit. diff --git a/changelog/add-7961-track-transactions-search b/changelog/add-7961-track-transactions-search deleted file mode 100644 index 6781c1b99f6..00000000000 --- a/changelog/add-7961-track-transactions-search +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Track filtering interactions on the Transactions page. diff --git a/changelog/add-place-order-tracks b/changelog/add-place-order-tracks deleted file mode 100644 index 450859bad49..00000000000 --- a/changelog/add-place-order-tracks +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Place order button Tracks diff --git a/changelog/add-prb-load-tracks b/changelog/add-prb-load-tracks deleted file mode 100644 index 5109e5ce0ca..00000000000 --- a/changelog/add-prb-load-tracks +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Track payment-request-button loads diff --git a/changelog/add-save-my-info-tracks b/changelog/add-save-my-info-tracks deleted file mode 100644 index c4fa8337b73..00000000000 --- a/changelog/add-save-my-info-tracks +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Add new Tracks events to WooPay Save My Info checkbox diff --git a/changelog/add-server-3942-compatibility-service-include-active-plugins b/changelog/add-server-3942-compatibility-service-include-active-plugins deleted file mode 100644 index edb6dd72a9a..00000000000 --- a/changelog/add-server-3942-compatibility-service-include-active-plugins +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add active plugins array to compatibility data. diff --git a/changelog/add-server-3944-compatibility-service-include-post-types b/changelog/add-server-3944-compatibility-service-include-post-types deleted file mode 100644 index 3b5aba0e435..00000000000 --- a/changelog/add-server-3944-compatibility-service-include-post-types +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Add post_types and their counts as an array to compatibility data. diff --git a/changelog/add-transaction-id-to-refund-endpoint b/changelog/add-transaction-id-to-refund-endpoint deleted file mode 100644 index c99092fb388..00000000000 --- a/changelog/add-transaction-id-to-refund-endpoint +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Expose the refund transaction ID in WooCommerce Order Refund API diff --git a/changelog/align-stripe-link-behavior b/changelog/align-stripe-link-behavior deleted file mode 100644 index fbc36a1cb22..00000000000 --- a/changelog/align-stripe-link-behavior +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: add - -Select the proper payment element when using saved Stripe Link tokens or choosing to use Stripe Link for new email. diff --git a/changelog/dev-7731-update-dev-mode-choice b/changelog/dev-7731-update-dev-mode-choice deleted file mode 100644 index 2c2ac2efae9..00000000000 --- a/changelog/dev-7731-update-dev-mode-choice +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Updates to the styling of the onboarding mode selection page. diff --git a/changelog/dev-7886-add-country-codes-enum b/changelog/dev-7886-add-country-codes-enum deleted file mode 100644 index e6e2b8aad22..00000000000 --- a/changelog/dev-7886-add-country-codes-enum +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Added enum class for country codes diff --git a/changelog/dev-centralize-account-status-logic b/changelog/dev-centralize-account-status-logic deleted file mode 100644 index 5b3d6d32d86..00000000000 --- a/changelog/dev-centralize-account-status-logic +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Updates to account status logic to streamline it. diff --git a/changelog/dev-refactor-order-dispute-refundable-util b/changelog/dev-refactor-order-dispute-refundable-util deleted file mode 100644 index 276e36cdcb8..00000000000 --- a/changelog/dev-refactor-order-dispute-refundable-util +++ /dev/null @@ -1,3 +0,0 @@ -Significance: patch -Type: dev -Comment: Not user-facing: refactors the refund eligibility logic for disputed orders diff --git a/changelog/fix-2199-woopay-duplicate-payments b/changelog/fix-2199-woopay-duplicate-payments deleted file mode 100644 index 19c6948d923..00000000000 --- a/changelog/fix-2199-woopay-duplicate-payments +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Fix WooPay duplicate charges. - - diff --git a/changelog/fix-2395-rerender-woopay-button-on-cart-update b/changelog/fix-2395-rerender-woopay-button-on-cart-update deleted file mode 100644 index a45d353c10c..00000000000 --- a/changelog/fix-2395-rerender-woopay-button-on-cart-update +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Re-render WooPay button when cart updates, when checkout updates. diff --git a/changelog/fix-2493-filter-subscriptions-payment-request b/changelog/fix-2493-filter-subscriptions-payment-request deleted file mode 100644 index c05650ebbc0..00000000000 --- a/changelog/fix-2493-filter-subscriptions-payment-request +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Allow subscription purchase via Payment Request when no shipping methods are present. diff --git a/changelog/fix-6424-update-settings-deposit-notice-ui b/changelog/fix-6424-update-settings-deposit-notice-ui deleted file mode 100644 index 3657670ba80..00000000000 --- a/changelog/fix-6424-update-settings-deposit-notice-ui +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: update - -Update style of notices within the deposits section of the settings screen. diff --git a/changelog/fix-6810-bnpl-sorting b/changelog/fix-6810-bnpl-sorting deleted file mode 100644 index 790cc782527..00000000000 --- a/changelog/fix-6810-bnpl-sorting +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: update - -Updated BNPL sorting in settings for consistency with onboarding. diff --git a/changelog/fix-6881-stripe-link-blocks-checkout-refactor b/changelog/fix-6881-stripe-link-blocks-checkout-refactor deleted file mode 100644 index b50316fcdbc..00000000000 --- a/changelog/fix-6881-stripe-link-blocks-checkout-refactor +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix Stripe Link autofill on checkout. diff --git a/changelog/fix-7568-tidy-disputed-order-notice b/changelog/fix-7568-tidy-disputed-order-notice deleted file mode 100644 index 39613195023..00000000000 --- a/changelog/fix-7568-tidy-disputed-order-notice +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Improve clarity & readability of disputed order notice (not all text bold). diff --git a/changelog/fix-7799-pay-for-order-error-message b/changelog/fix-7799-pay-for-order-error-message deleted file mode 100644 index 101d5e34fa2..00000000000 --- a/changelog/fix-7799-pay-for-order-error-message +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -fix pay-for-order quirks and 3DS behavior diff --git a/changelog/fix-7819-incorrect-test-mode-notice b/changelog/fix-7819-incorrect-test-mode-notice deleted file mode 100644 index 166132e2a26..00000000000 --- a/changelog/fix-7819-incorrect-test-mode-notice +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix incorrect test mode notice when left KYC early after going live from builder mode diff --git a/changelog/fix-7881-strict-return-type b/changelog/fix-7881-strict-return-type deleted file mode 100644 index 5c2b0cc42be..00000000000 --- a/changelog/fix-7881-strict-return-type +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Prevent possible fatal when using get_edit_post_link filter. diff --git a/changelog/fix-7929-link-button-alignment b/changelog/fix-7929-link-button-alignment deleted file mode 100644 index a6da658f8d8..00000000000 --- a/changelog/fix-7929-link-button-alignment +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix Stripe Link button alignment in the Checkout Block 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 - - diff --git a/changelog/fix-7960-transaction-refund-eligible-disputes-only b/changelog/fix-7960-transaction-refund-eligible-disputes-only deleted file mode 100644 index e35c11107f7..00000000000 --- a/changelog/fix-7960-transaction-refund-eligible-disputes-only +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Hide the transaction details refund menu for ineligble disputed transactions diff --git a/changelog/fix-7964-typo-for-transaction-actions b/changelog/fix-7964-typo-for-transaction-actions deleted file mode 100644 index 603667aa9a7..00000000000 --- a/changelog/fix-7964-typo-for-transaction-actions +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Fixed a typo - - diff --git a/changelog/fix-7967-disputed-order-notice-test-mode-check b/changelog/fix-7967-disputed-order-notice-test-mode-check deleted file mode 100644 index 43f8af2c81b..00000000000 --- a/changelog/fix-7967-disputed-order-notice-test-mode-check +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. diff --git a/changelog/fix-7969-restock-items-when-refund-from-transaction-page b/changelog/fix-7969-restock-items-when-refund-from-transaction-page deleted file mode 100644 index 89d7c64e75a..00000000000 --- a/changelog/fix-7969-restock-items-when-refund-from-transaction-page +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Restock order items when performing full refund from transaction details page diff --git a/changelog/fix-7970-clarify-calendar-days-waiting-period-notice b/changelog/fix-7970-clarify-calendar-days-waiting-period-notice deleted file mode 100644 index 5f1286350f5..00000000000 --- a/changelog/fix-7970-clarify-calendar-days-waiting-period-notice +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Show the correct number of days in the new account waiting period notice. diff --git a/changelog/fix-7984-allow-zero-amount-refunds b/changelog/fix-7984-allow-zero-amount-refunds deleted file mode 100644 index 9a3327f189b..00000000000 --- a/changelog/fix-7984-allow-zero-amount-refunds +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. diff --git a/changelog/fix-7991-blank-square-in-the-upper-left-corner-of-basic-filter-dropdowns-on-analytics-pages b/changelog/fix-7991-blank-square-in-the-upper-left-corner-of-basic-filter-dropdowns-on-analytics-pages deleted file mode 100644 index da22195d61c..00000000000 --- a/changelog/fix-7991-blank-square-in-the-upper-left-corner-of-basic-filter-dropdowns-on-analytics-pages +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Reverting to manual styling over native WordPress components to fix CSS defects on Analytics page diff --git a/changelog/fix-8040-new-account-waiting-period-notice b/changelog/fix-8040-new-account-waiting-period-notice deleted file mode 100644 index 254a87050c8..00000000000 --- a/changelog/fix-8040-new-account-waiting-period-notice +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Reinstate first deposit waiting period notice in payments overview (fix bug) diff --git a/changelog/fix-e2e-tests b/changelog/fix-e2e-tests deleted file mode 100644 index 6be373a93e5..00000000000 --- a/changelog/fix-e2e-tests +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Allow test pipelines to pass by slightly adjusting HTML selectors diff --git a/changelog/fix-place-order-js-error b/changelog/fix-place-order-js-error deleted file mode 100644 index 15ab0d3632d..00000000000 --- a/changelog/fix-place-order-js-error +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Fixes a JS error introduced in an unreleased change - - diff --git a/changelog/fix-transaction-refund-options-for-missing-order b/changelog/fix-transaction-refund-options-for-missing-order deleted file mode 100644 index aa09586aa39..00000000000 --- a/changelog/fix-transaction-refund-options-for-missing-order +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Verify that order exists before offering "Partial refund" option on transaction details page. diff --git a/changelog/fix-trim-woopay-source-url b/changelog/fix-trim-woopay-source-url deleted file mode 100644 index d0542cc8201..00000000000 --- a/changelog/fix-trim-woopay-source-url +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Checkout error when page URL is too long diff --git a/changelog/fix-unnecessary-import-warning b/changelog/fix-unnecessary-import-warning deleted file mode 100644 index e13b9c06bbc..00000000000 --- a/changelog/fix-unnecessary-import-warning +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Remove unnecessary import statement which leads to a warning when first loaded diff --git a/changelog/fix-woopay-adapted-extensions b/changelog/fix-woopay-adapted-extensions deleted file mode 100644 index f1f70ad71f3..00000000000 --- a/changelog/fix-woopay-adapted-extensions +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: Fix WooPay adapted extensions initialization. - - diff --git a/changelog/fix-woopay-tablet-breakpoint b/changelog/fix-woopay-tablet-breakpoint deleted file mode 100644 index 593a5fc67af..00000000000 --- a/changelog/fix-woopay-tablet-breakpoint +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Update WooPay tablet breakpoint. diff --git a/changelog/merge-upe-non-upe-tests b/changelog/merge-upe-non-upe-tests deleted file mode 100644 index 2e6ed78762f..00000000000 --- a/changelog/merge-upe-non-upe-tests +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Merge UPE tests into the single and main gateway test file for unit and E2E tests. diff --git a/changelog/refactor-logger b/changelog/refactor-logger deleted file mode 100644 index 054cac4ec60..00000000000 --- a/changelog/refactor-logger +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: It just changes how we get the same data from the database - - diff --git a/changelog/refactor-mode-class b/changelog/refactor-mode-class deleted file mode 100644 index 054cac4ec60..00000000000 --- a/changelog/refactor-mode-class +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: dev -Comment: It just changes how we get the same data from the database - - diff --git a/changelog/send-metadata-in-error-message b/changelog/send-metadata-in-error-message deleted file mode 100644 index 1d4c516ae8b..00000000000 --- a/changelog/send-metadata-in-error-message +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Send metadata in error message diff --git a/changelog/subscriptions-core-6.7.1 b/changelog/subscriptions-core-6.7.1 deleted file mode 100644 index 28a911d14cb..00000000000 --- a/changelog/subscriptions-core-6.7.1 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Update subscriptions-core to 6.7.1. diff --git a/changelog/subscriptions-core-6.7.1-2 b/changelog/subscriptions-core-6.7.1-2 deleted file mode 100644 index ef0ced053e7..00000000000 --- a/changelog/subscriptions-core-6.7.1-2 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled. diff --git a/changelog/subscriptions-core-6.7.1-3 b/changelog/subscriptions-core-6.7.1-3 deleted file mode 100644 index 83da04c3910..00000000000 --- a/changelog/subscriptions-core-6.7.1-3 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing. diff --git a/changelog/subscriptions-core-6.7.1-4 b/changelog/subscriptions-core-6.7.1-4 deleted file mode 100644 index 96fb34cb28e..00000000000 --- a/changelog/subscriptions-core-6.7.1-4 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -Resolved an error that would occur with WC 8.5.0 when editing a subscription customer from the admin dashboard. diff --git a/changelog/update-7579-po-success-modal b/changelog/update-7579-po-success-modal deleted file mode 100644 index f02eae18ba7..00000000000 --- a/changelog/update-7579-po-success-modal +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: update -Comment: PO success modal design update. - - diff --git a/changelog/update-7856-add-charge-txn-id-to-order-meta b/changelog/update-7856-add-charge-txn-id-to-order-meta deleted file mode 100644 index 38037b5a6d1..00000000000 --- a/changelog/update-7856-add-charge-txn-id-to-order-meta +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Store balance transaction ID in order metadata. diff --git a/changelog/update-dev-mode-labels b/changelog/update-dev-mode-labels deleted file mode 100644 index df9ff952e45..00000000000 --- a/changelog/update-dev-mode-labels +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: update - -Update references to dev mode to use sandbox mode terminology. diff --git a/changelog/update-jetpack-dependencies b/changelog/update-jetpack-dependencies deleted file mode 100644 index 9ff7efa72b6..00000000000 --- a/changelog/update-jetpack-dependencies +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: dev - -Update jetpack dependencies for syncing. diff --git a/package-lock.json b/package-lock.json index 281f044e9ae..ffbacceb596 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "woocommerce-payments", - "version": "7.0.0", + "version": "7.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "woocommerce-payments", - "version": "7.0.0", + "version": "7.1.0", "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 490bab8f986..0152e41271c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-payments", - "version": "7.0.0", + "version": "7.1.0", "main": "webpack.config.js", "author": "Automattic", "license": "GPL-3.0-or-later", diff --git a/readme.txt b/readme.txt index 0c4dc6d82e0..c383c828793 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: 7.0.0 +Stable tag: 7.1.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -94,6 +94,54 @@ Please note that our support for the checkout block is still experimental and th == Changelog == += 7.1.0 - 2024-01-24 = +* Add - Add active plugins array to compatibility data. +* Add - Add post_types and their counts as an array to compatibility data. +* Add - Add the active theme name of the blog to the compatibility service +* Add - Expose the refund transaction ID in WooCommerce Order Refund API +* Add - Select the proper payment element when using saved Stripe Link tokens or choosing to use Stripe Link for new email. +* Add - Track filtering interactions on the Transactions page. +* Fix - Allow subscription purchase via Payment Request when no shipping methods are present. +* Fix - Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. +* Fix - Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page +* Fix - Checkout error when page URL is too long +* Fix - Fix incorrect test mode notice when left KYC early after going live from builder mode +* Fix - Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. +* Fix - fix pay-for-order quirks and 3DS behavior +* Fix - Fix Safe Mode message reversed host +* Fix - Fix Stripe Link autofill on checkout. +* Fix - Fix Stripe Link button alignment in the Checkout Block +* Fix - Hide the transaction details refund menu for ineligble disputed transactions +* Fix - Improve clarity & readability of disputed order notice (not all text bold). +* Fix - Prevent possible fatal when using get_edit_post_link filter. +* Fix - Re-render WooPay button when cart updates, when checkout updates. +* Fix - Reinstate first deposit waiting period notice in payments overview (fix bug) +* Fix - Remove unnecessary import statement which leads to a warning when first loaded +* Fix - Resolved an error that would occur with WC 8.5.0 when editing a subscription customer from the admin dashboard. +* Fix - Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled. +* Fix - Restock order items when performing full refund from transaction details page +* Fix - Reverting to manual styling over native WordPress components to fix CSS defects on Analytics page +* Fix - Send metadata in error message +* Fix - Show the correct number of days in the new account waiting period notice. +* Fix - Update WooPay tablet breakpoint. +* Fix - Verify that order exists before offering "Partial refund" option on transaction details page. +* Update - Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing. +* Update - Pass currency parameter and not transaction_ids parameter when creating instant deposit. +* Update - Store balance transaction ID in order metadata. +* Update - Updated BNPL sorting in settings for consistency with onboarding. +* Update - Update references to dev mode to use sandbox mode terminology. +* Update - Updates to the styling of the onboarding mode selection page. +* Update - Update style of notices within the deposits section of the settings screen. +* Dev - Added enum class for country codes +* Dev - Add new Tracks events to WooPay Save My Info checkbox +* Dev - Allow test pipelines to pass by slightly adjusting HTML selectors +* Dev - Merge UPE tests into the single and main gateway test file for unit and E2E tests. +* Dev - Place order button Tracks +* Dev - Track payment-request-button loads +* Dev - Update jetpack dependencies for syncing. +* Dev - Updates to account status logic to streamline it. +* Dev - Update subscriptions-core to 6.7.1. + = 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. diff --git a/woocommerce-payments.php b/woocommerce-payments.php index ee3eedb1409..d1db912b2e6 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: 7.0.0 + * Version: 7.1.0 * * @package WooCommerce\Payments */ From bb808907b528dff484df38174f4cb14d09592411 Mon Sep 17 00:00:00 2001 From: Miguel Gasca Date: Tue, 23 Jan 2024 12:44:14 +0100 Subject: [PATCH 57/60] Address QIT security errors (#8060) --- .../fix-8059-qit-security-test-failed-in-develop-branch | 4 ++++ includes/class-wc-payments.php | 6 +++--- includes/multi-currency/MultiCurrency.php | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 changelog/fix-8059-qit-security-test-failed-in-develop-branch diff --git a/changelog/fix-8059-qit-security-test-failed-in-develop-branch b/changelog/fix-8059-qit-security-test-failed-in-develop-branch new file mode 100644 index 00000000000..fbcf842d935 --- /dev/null +++ b/changelog/fix-8059-qit-security-test-failed-in-develop-branch @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Comment: Fix QIT security tests errors. diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index f5046144bed..b4b64d4ea23 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -1358,7 +1358,7 @@ function wcpay_show_old_woocommerce_for_norway_notice() { 'WooPayments' ), [ - 'a1' => '', + 'a1' => '', ] ) ?> @@ -1724,10 +1724,10 @@ public static function wcpay_show_old_woocommerce_for_hungary_sweden_and_czech_r $notice, 'WooCommerce', 'WooPayments', - WC_VERSION + esc_html( WC_VERSION ) ), [ - 'a1' => '', + 'a1' => '', ] ) ?> diff --git a/includes/multi-currency/MultiCurrency.php b/includes/multi-currency/MultiCurrency.php index f1c890a656e..bf3df9ad5fd 100644 --- a/includes/multi-currency/MultiCurrency.php +++ b/includes/multi-currency/MultiCurrency.php @@ -1021,7 +1021,7 @@ public function display_geolocation_currency_update_notice() { echo \WC_Payments_Utils::esc_interpolated_html( $message, [ - 'a' => '', + 'a' => '', ] ); echo ' ' . esc_html__( 'Dismiss', 'woocommerce-payments' ) . '

'; From aa38ecab3b69fa54d147e493278c1018b4bf339c Mon Sep 17 00:00:00 2001 From: botwoo Date: Tue, 23 Jan 2024 12:45:10 +0000 Subject: [PATCH 58/60] Amend changelog entries for release 7.1.0 --- changelog.txt | 3 ++- changelog/fix-8059-qit-security-test-failed-in-develop-branch | 4 ---- readme.txt | 3 ++- 3 files changed, 4 insertions(+), 6 deletions(-) delete mode 100644 changelog/fix-8059-qit-security-test-failed-in-develop-branch diff --git a/changelog.txt b/changelog.txt index 142b00a5444..7bc941a66b8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ *** WooPayments Changelog *** -= 7.1.0 - 2024-01-24 = += 7.1.0 - 2023-01-24 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service @@ -11,6 +11,7 @@ * Fix - Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. * Fix - Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page * Fix - Checkout error when page URL is too long +* Fix - Comment: Fix QIT security tests errors. * Fix - Fix incorrect test mode notice when left KYC early after going live from builder mode * Fix - Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. * Fix - fix pay-for-order quirks and 3DS behavior diff --git a/changelog/fix-8059-qit-security-test-failed-in-develop-branch b/changelog/fix-8059-qit-security-test-failed-in-develop-branch deleted file mode 100644 index fbcf842d935..00000000000 --- a/changelog/fix-8059-qit-security-test-failed-in-develop-branch +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Comment: Fix QIT security tests errors. diff --git a/readme.txt b/readme.txt index c383c828793..0f65e609fcb 100644 --- a/readme.txt +++ b/readme.txt @@ -94,7 +94,7 @@ Please note that our support for the checkout block is still experimental and th == Changelog == -= 7.1.0 - 2024-01-24 = += 7.1.0 - 2023-01-24 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service @@ -105,6 +105,7 @@ Please note that our support for the checkout block is still experimental and th * Fix - Allow zero-amount refunds for backwards compatibility with basic payment gateway and to allow re-stock of refunded orders. * Fix - Checking if wcpayPaymentRequestPayForOrderParams before using it in Pay for Order page * Fix - Checkout error when page URL is too long +* Fix - Comment: Fix QIT security tests errors. * Fix - Fix incorrect test mode notice when left KYC early after going live from builder mode * Fix - Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa. * Fix - fix pay-for-order quirks and 3DS behavior From d65a7b959703e896eb8c09e8609bda34d38e58b4 Mon Sep 17 00:00:00 2001 From: botwoo Date: Tue, 23 Jan 2024 12:47:48 +0000 Subject: [PATCH 59/60] Amend changelog entries for release 7.1.0 --- changelog.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7bc941a66b8..1da733beae7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ *** WooPayments Changelog *** -= 7.1.0 - 2023-01-24 = += 7.1.0 - 2024-01-24 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service diff --git a/readme.txt b/readme.txt index 0f65e609fcb..c34b3f0fcc4 100644 --- a/readme.txt +++ b/readme.txt @@ -94,7 +94,7 @@ Please note that our support for the checkout block is still experimental and th == Changelog == -= 7.1.0 - 2023-01-24 = += 7.1.0 - 2024-01-24 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service From 30e54c50192010755efc30aa9d8acc4e260640ce Mon Sep 17 00:00:00 2001 From: botwoo Date: Thu, 25 Jan 2024 08:50:14 +0000 Subject: [PATCH 60/60] Amend changelog entries for release 7.1.0 --- changelog.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1da733beae7..598679d0f3c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ *** WooPayments Changelog *** -= 7.1.0 - 2024-01-24 = += 7.1.0 - 2024-01-25 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service diff --git a/readme.txt b/readme.txt index c34b3f0fcc4..9ff761232e3 100644 --- a/readme.txt +++ b/readme.txt @@ -94,7 +94,7 @@ Please note that our support for the checkout block is still experimental and th == Changelog == -= 7.1.0 - 2024-01-24 = += 7.1.0 - 2024-01-25 = * Add - Add active plugins array to compatibility data. * Add - Add post_types and their counts as an array to compatibility data. * Add - Add the active theme name of the blog to the compatibility service