diff --git a/changelog.txt b/changelog.txt
index 18c98319d74..73e649d188e 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,11 @@
*** WooPayments Changelog ***
+= 6.9.2 - 2023-12-14 =
+* Add - Notice is added when merchant has funds that are not yet available for deposit.
+* Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected.
+* Fix - Show deposit schedule message when deposits are unrestricted
+* Fix - Transactions List - indicate when a transaction is expected to be included in a future deposit
+
= 6.9.1 - 2023-12-07 =
* Fix - Display Klarna & Afterpay on the checkout for UK based stores
diff --git a/changelog/add-7591-missing-columns-export-csv b/changelog/add-7591-missing-columns-export-csv
new file mode 100644
index 00000000000..668644d2cfc
--- /dev/null
+++ b/changelog/add-7591-missing-columns-export-csv
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export
diff --git a/changelog/add-thank-you-page-tracks b/changelog/add-thank-you-page-tracks
new file mode 100644
index 00000000000..31888d5d917
--- /dev/null
+++ b/changelog/add-thank-you-page-tracks
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Thank you page Tracks event
diff --git a/changelog/cleanup-redundant-script-enqueueing b/changelog/cleanup-redundant-script-enqueueing
new file mode 100644
index 00000000000..20c952d459e
--- /dev/null
+++ b/changelog/cleanup-redundant-script-enqueueing
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Cleanup enqueueing of the scripts which were removed
diff --git a/changelog/deferred-intent b/changelog/deferred-intent
new file mode 100644
index 00000000000..ef5442b5f17
--- /dev/null
+++ b/changelog/deferred-intent
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Improve E2E checkout tests
diff --git a/changelog/dev-fix-multi-currency-e2e-tests b/changelog/dev-fix-multi-currency-e2e-tests
new file mode 100644
index 00000000000..45ac7deccc1
--- /dev/null
+++ b/changelog/dev-fix-multi-currency-e2e-tests
@@ -0,0 +1,5 @@
+Significance: patch
+Type: dev
+Comment: Fix multi-currency e2e tests.
+
+
diff --git a/changelog/dev-test-ci-without-3ds1 b/changelog/dev-test-ci-without-3ds1
new file mode 100644
index 00000000000..f2d4b778788
--- /dev/null
+++ b/changelog/dev-test-ci-without-3ds1
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Comment: Fix declined 3DS card E2E test.
diff --git a/changelog/fix-3693-qualitative-feedback-note b/changelog/fix-3693-qualitative-feedback-note
new file mode 100644
index 00000000000..8862cc0c961
--- /dev/null
+++ b/changelog/fix-3693-qualitative-feedback-note
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Update Qualitative Feedback note to have more efficient sql query.
diff --git a/changelog/fix-7750-include-discount-in-tooltip b/changelog/fix-7750-include-discount-in-tooltip
new file mode 100644
index 00000000000..b600a611e92
--- /dev/null
+++ b/changelog/fix-7750-include-discount-in-tooltip
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Include discount fee in fees tooltip
diff --git a/changelog/fix-account-currency-hook b/changelog/fix-account-currency-hook
new file mode 100644
index 00000000000..23d9628b19f
--- /dev/null
+++ b/changelog/fix-account-currency-hook
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+fix: account currency hook return value
diff --git a/client/components/deposits-overview/deposit-notices.tsx b/client/components/deposits-overview/deposit-notices.tsx
index 7a38783a33b..86f0de918a0 100644
--- a/client/components/deposits-overview/deposit-notices.tsx
+++ b/client/components/deposits-overview/deposit-notices.tsx
@@ -150,3 +150,28 @@ export const NegativeBalanceDepositsPausedNotice: React.FC = () => (
} ) }
);
+
+/**
+ * Renders a notice informing the user that deposits only occur when there are funds available.
+ */
+export const NoFundsAvailableForDepositNotice: React.FC = () => (
+
+ { interpolateComponents( {
+ mixedString: __(
+ 'You have no funds available to deposit. {{whyLink}}Why?{{/whyLink}}',
+ 'woocommerce-payments'
+ ),
+ components: {
+ whyLink: (
+ // Link content is in the format string above. Consider disabling jsx-a11y/anchor-has-content.
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
+
+ ),
+ },
+ } ) }
+
+);
diff --git a/client/components/deposits-overview/deposit-schedule.tsx b/client/components/deposits-overview/deposit-schedule.tsx
index c7eae7bca78..8ae6546655c 100644
--- a/client/components/deposits-overview/deposit-schedule.tsx
+++ b/client/components/deposits-overview/deposit-schedule.tsx
@@ -17,6 +17,7 @@ import type * as AccountOverview from 'wcpay/types/account-overview';
interface DepositScheduleProps {
depositsSchedule: AccountOverview.Account[ 'deposits_schedule' ];
+ showNextDepositDate?: boolean;
}
/**
* Renders the Deposit Schedule details component.
@@ -25,19 +26,30 @@ interface DepositScheduleProps {
*/
const DepositSchedule: React.FC< DepositScheduleProps > = ( {
depositsSchedule,
+ showNextDepositDate,
} ) => {
const nextDepositDate = getNextDepositDate( depositsSchedule );
+ const nextDepositDateString = showNextDepositDate
+ ? sprintf(
+ /** translators: %s: is the date of the next deposit, e.g. "January 1st, 2023". */
+ __(
+ ' – your next deposit is scheduled for {{strong}}%s{{/strong}}',
+ 'woocommerce-payments'
+ ),
+ nextDepositDate
+ )
+ : '';
switch ( depositsSchedule.interval ) {
case 'daily':
return interpolateComponents( {
mixedString: sprintf(
- /** translators: {{strong}}: placeholders are opening and closing strong tags. %s: is the date of the next deposit, e.g. "January 1st, 2023". */
+ /** translators: {{strong}}: placeholders are opening and closing strong tags. %s: is an optional next deposit date message. */
__(
- 'Available funds are automatically dispatched {{strong}}every day{{/strong}} – your next deposit is scheduled for {{strong}}%s{{/strong}}.',
+ 'Available funds are automatically dispatched {{strong}}every day{{/strong}}%s.',
'woocommerce-payments'
),
- nextDepositDate
+ nextDepositDateString
),
components: {
strong: ,
@@ -52,13 +64,13 @@ const DepositSchedule: React.FC< DepositScheduleProps > = ( {
return interpolateComponents( {
mixedString: sprintf(
- /** translators: %1$s: is the day of the week. eg "Friday". %2$s: is the date of the next deposit, e.g. "January 1st, 2023". {{strong}}: placeholders are opening and closing strong tags. */
+ /** translators: %1$s: is the day of the week. eg "Friday". %2$s: is an optional next deposit date message. {{strong}}: placeholders are opening and closing strong tags. */
__(
- 'Available funds are automatically dispatched {{strong}}every %1$s{{/strong}} – your next deposit is scheduled for {{strong}}%2$s{{/strong}}.',
+ 'Available funds are automatically dispatched {{strong}}every %1$s{{/strong}}%2$s.',
'woocommerce-payments'
),
dayOfWeek,
- nextDepositDate
+ nextDepositDateString
),
components: {
strong: ,
@@ -71,12 +83,12 @@ const DepositSchedule: React.FC< DepositScheduleProps > = ( {
if ( monthlyAnchor === 31 ) {
return interpolateComponents( {
mixedString: sprintf(
- /** translators: {{strong}}: placeholders are opening and closing strong tags. %s: is the date of the next deposit, e.g. "January 1st, 2023". */
+ /** translators: {{strong}}: placeholders are opening and closing strong tags. %s: is an optional next deposit date message. */
__(
- 'Available funds are automatically dispatched {{strong}}on the last day of every month{{/strong}} – your next deposit is scheduled for {{strong}}%s{{/strong}}.',
+ 'Available funds are automatically dispatched {{strong}}on the last day of every month{{/strong}}%s.',
'woocommerce-payments'
),
- nextDepositDate
+ nextDepositDateString
),
components: {
strong: ,
@@ -86,16 +98,16 @@ const DepositSchedule: React.FC< DepositScheduleProps > = ( {
return interpolateComponents( {
mixedString: sprintf(
- /** translators: {{strong}}: placeholders are opening and closing strong tags. %1$s: is the day of the month. eg "31st". %2$s: is the date of the next deposit, e.g. "January 1st, 2023". */
+ /** translators: {{strong}}: placeholders are opening and closing strong tags. %1$s: is the day of the month. eg "31st". %2$s: is an optional next deposit date message. */
__(
- 'Available funds are automatically dispatched {{strong}}on the %1$s of every month{{/strong}} – your next deposit is scheduled for {{strong}}%2$s{{/strong}}.',
+ 'Available funds are automatically dispatched {{strong}}on the %1$s of every month{{/strong}}%2$s.',
'woocommerce-payments'
),
getDepositMonthlyAnchorLabel( {
monthlyAnchor: monthlyAnchor,
capitalize: false,
} ),
- nextDepositDate
+ nextDepositDateString
),
components: {
strong: ,
diff --git a/client/components/deposits-overview/index.tsx b/client/components/deposits-overview/index.tsx
index 27c754c0640..8ab797f4977 100644
--- a/client/components/deposits-overview/index.tsx
+++ b/client/components/deposits-overview/index.tsx
@@ -24,6 +24,7 @@ import {
DepositTransitDaysNotice,
NegativeBalanceDepositsPausedNotice,
NewAccountWaitingPeriodNotice,
+ NoFundsAvailableForDepositNotice,
SuspendedDepositNotice,
} from './deposit-notices';
import useRecentDeposits from './hooks';
@@ -35,6 +36,9 @@ const DepositsOverview: React.FC = () => {
overview,
isLoading: isLoadingOverview,
} = useSelectedCurrencyOverview();
+ const isDepositsUnrestricted =
+ wcpaySettings.accountStatus.deposits?.restrictions ===
+ 'deposits_unrestricted';
const selectedCurrency =
overview?.currency || wcpaySettings.accountDefaultCurrency;
const { isLoading: isLoadingDeposits, deposits } = useRecentDeposits(
@@ -44,20 +48,18 @@ const DepositsOverview: React.FC = () => {
const isLoading = isLoadingOverview || isLoadingDeposits;
const availableFunds = overview?.available?.amount ?? 0;
+ const pendingFunds = overview?.pending?.amount ?? 0;
- // If the account has deposits blocked, there is no available balance or it is negative, there is no future deposit expected.
- const isNextDepositExpected =
- ! account?.deposits_blocked && availableFunds > 0;
// If the available balance is negative, deposits may be paused.
const isNegativeBalanceDepositsPaused = availableFunds < 0;
+ // When there are funds pending but no available funds, deposits are paused.
+ const isDepositAwaitingPendingFunds =
+ availableFunds === 0 && pendingFunds > 0;
const hasCompletedWaitingPeriod =
wcpaySettings.accountStatus.deposits?.completed_waiting_period;
// Only show the deposit history section if the page is finished loading and there are deposits. */ }
const showRecentDeposits =
- ! isLoading &&
- deposits?.length > 0 &&
- !! account &&
- ! account?.deposits_blocked;
+ ! isLoading && deposits?.length > 0 && !! account;
// Show a loading state if the page is still loading.
if ( isLoading ) {
@@ -87,7 +89,7 @@ const DepositsOverview: React.FC = () => {
}
// This card isn't shown if there are no deposits, so we can bail early.
- if ( ! isLoading && availableFunds === 0 && deposits.length === 0 ) {
+ if ( ! isLoading && deposits.length === 0 ) {
return null;
}
@@ -98,10 +100,11 @@ const DepositsOverview: React.FC = () => {
{ /* Deposit schedule message */ }
- { isNextDepositExpected && !! account && (
+ { isDepositsUnrestricted && !! account && (
0 }
/>
) }
@@ -112,12 +115,17 @@ const DepositsOverview: React.FC = () => {
) : (
<>
- { isNextDepositExpected && (
-
- ) }
+ { isDepositsUnrestricted &&
+ ! isDepositAwaitingPendingFunds && (
+
+ ) }
{ ! hasCompletedWaitingPeriod && (
) }
+ { hasCompletedWaitingPeriod &&
+ isDepositAwaitingPendingFunds && (
+
+ ) }
{ isNegativeBalanceDepositsPaused && (
) }
diff --git a/client/components/deposits-overview/test/__snapshots__/index.tsx.snap b/client/components/deposits-overview/test/__snapshots__/index.tsx.snap
index 9dcdb85548d..6b4db19d73c 100644
--- a/client/components/deposits-overview/test/__snapshots__/index.tsx.snap
+++ b/client/components/deposits-overview/test/__snapshots__/index.tsx.snap
@@ -17,11 +17,65 @@ exports[`Deposits Overview information Component Renders 1`] = `
>
Deposits
+
+ Available funds are automatically dispatched
+
+ every Monday
+
+ .
+
+ >
+
+
+
+
+
+ It may take 1-3 business days for deposits to reach your bank account.
+
+
+
+
+
+
{
global.wcpaySettings = {
accountStatus: {
deposits: {
+ restrictions: 'deposits_unrestricted',
completed_waiting_period: true,
},
},
diff --git a/client/components/tooltip/style.scss b/client/components/tooltip/style.scss
index aa0cfe52062..26730944226 100644
--- a/client/components/tooltip/style.scss
+++ b/client/components/tooltip/style.scss
@@ -37,6 +37,9 @@
z-index: 100010;
// Initial left position is set to 0 to fix a positioning bug in mobile Safari.
left: 0;
+ white-space: normal;
+ font-size: 12px;
+ font-weight: 400;
&.is-hiding {
opacity: 0 !important;
diff --git a/client/deposits/index.tsx b/client/deposits/index.tsx
index ae5ba238679..7f6e5c30f14 100644
--- a/client/deposits/index.tsx
+++ b/client/deposits/index.tsx
@@ -3,19 +3,80 @@
/**
* External dependencies
*/
-import React from 'react';
+import React, { useState } from 'react';
+import { useDispatch } from '@wordpress/data';
/**
* Internal dependencies.
*/
import Page from 'components/page';
import { TestModeNotice } from 'components/test-mode-notice';
+import BannerNotice from 'components/banner-notice';
+import DepositSchedule from 'components/deposits-overview/deposit-schedule';
+import { useAllDepositsOverviews } from 'data';
import DepositsList from './list';
+const useNextDepositNoticeState = () => {
+ const { updateOptions } = useDispatch( 'wc/admin/options' );
+ const [ isDismissed, setIsDismissed ] = useState(
+ wcpaySettings.isNextDepositNoticeDismissed
+ );
+
+ const setNextDepositNoticeDismissed = () => {
+ setIsDismissed( true );
+ wcpaySettings.isNextDepositNoticeDismissed = true;
+ updateOptions( {
+ wcpay_next_deposit_notice_dismissed: true,
+ } );
+ };
+
+ return {
+ isNextDepositNoticeDismissed: isDismissed,
+ handleDismissNextDepositNotice: setNextDepositNoticeDismissed,
+ };
+};
+
+const NextDepositNotice: React.FC = () => {
+ const {
+ overviews: { account },
+ } = useAllDepositsOverviews();
+ const {
+ isNextDepositNoticeDismissed,
+ handleDismissNextDepositNotice,
+ } = useNextDepositNoticeState();
+
+ const isDepositsUnrestricted =
+ wcpaySettings.accountStatus.deposits?.restrictions ===
+ 'deposits_unrestricted';
+
+ const hasCompletedWaitingPeriod =
+ wcpaySettings.accountStatus.deposits?.completed_waiting_period;
+
+ if (
+ ! isDepositsUnrestricted ||
+ ! hasCompletedWaitingPeriod ||
+ ! account ||
+ isNextDepositNoticeDismissed
+ ) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
+
const DepositsPage: React.FC = () => {
return (
+
);
diff --git a/client/globals.d.ts b/client/globals.d.ts
index eaffe24b8b6..4f791a70795 100644
--- a/client/globals.d.ts
+++ b/client/globals.d.ts
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import {
+import type {
MccsDisplayTreeItem,
Country,
OnboardingFields,
@@ -31,6 +31,10 @@ declare global {
paymentsEnabled?: boolean;
deposits?: {
status: string;
+ restrictions:
+ | 'deposits_unrestricted'
+ | 'deposits_blocked'
+ | 'schedule_restricted';
interval: string;
weekly_anchor: string;
monthly_anchor: null | number;
@@ -116,6 +120,7 @@ declare global {
isStripeBillingEligible: boolean;
capabilityRequestNotices: Record< string, boolean >;
storeName: string;
+ isNextDepositNoticeDismissed: boolean;
};
const wcTracks: any;
diff --git a/client/payment-methods/index.js b/client/payment-methods/index.js
index 950610e6fba..7efb306b0da 100644
--- a/client/payment-methods/index.js
+++ b/client/payment-methods/index.js
@@ -92,7 +92,7 @@ const PaymentMethods = () => {
const [ , updateSelectedPaymentMethod ] = useSelectedPaymentMethod();
- const [ stripeAccountDomesticCurrency ] = useAccountDomesticCurrency();
+ const stripeAccountDomesticCurrency = useAccountDomesticCurrency();
const completeActivation = ( itemId ) => {
updateSelectedPaymentMethod( itemId );
diff --git a/client/transactions/list/deposit.tsx b/client/transactions/list/deposit.tsx
index c0604f0b097..09ceb108ca9 100644
--- a/client/transactions/list/deposit.tsx
+++ b/client/transactions/list/deposit.tsx
@@ -3,18 +3,27 @@
/**
* External dependencies
*/
-import { dateI18n } from '@wordpress/date';
+import React from 'react';
import moment from 'moment';
+import { dateI18n } from '@wordpress/date';
+import { __ } from '@wordpress/i18n';
+import interpolateComponents from '@automattic/interpolate-components';
+import { ExternalLink } from '@wordpress/components';
import { Link } from '@woocommerce/components';
-import React from 'react';
-import { getAdminUrl } from 'wcpay/utils';
+import InfoOutlineIcon from 'gridicons/dist/info-outline';
+
+/**
+ * Internal dependencies
+ */
+import { getAdminUrl } from 'utils';
+import { ClickTooltip } from 'components/tooltip';
interface DepositProps {
depositId?: string;
dateAvailable?: string;
}
-const Deposit = ( { depositId, dateAvailable }: DepositProps ): JSX.Element => {
+const Deposit: React.FC< DepositProps > = ( { depositId, dateAvailable } ) => {
if (
depositId &&
dateAvailable &&
@@ -35,7 +44,26 @@ const Deposit = ( { depositId, dateAvailable }: DepositProps ): JSX.Element => {
return
{ formattedDateAvailable };
}
- return <>>;
+ // Show an icon with a tooltip to communicate that the deposit will be available in the future.
+ return (
+ <>
+ { __( 'Future deposit', 'woocommerce-payments' ) }
+
+ ),
+ },
+ } ) }
+ buttonIcon={
}
+ />
+ >
+ );
};
export default Deposit;
diff --git a/client/transactions/list/index.tsx b/client/transactions/list/index.tsx
index 822047a4afd..931712821a9 100644
--- a/client/transactions/list/index.tsx
+++ b/client/transactions/list/index.tsx
@@ -144,8 +144,11 @@ const getColumns = (
},
{
key: 'date',
- label: __( 'Date / Time', 'woocommerce-payments' ),
- screenReaderLabel: __( 'Date and time', 'woocommerce-payments' ),
+ label: __( 'Date / Time (UTC)', 'woocommerce-payments' ),
+ screenReaderLabel: __(
+ 'Date and time in UTC',
+ 'woocommerce-payments'
+ ),
required: true,
isLeftAligned: true,
defaultOrder: 'desc',
@@ -167,10 +170,41 @@ const getColumns = (
required: true,
isLeftAligned: true,
},
+ {
+ key: 'customer_currency',
+ label: __( 'Paid Currency', 'woocommerce-payments' ),
+ screenReaderLabel: __(
+ 'Customer Currency',
+ 'woocommerce-payments'
+ ),
+ isSortable: true,
+ visible: false,
+ },
+ {
+ key: 'customer_amount',
+ label: __( 'Amount Paid', 'woocommerce-payments' ),
+ screenReaderLabel: __(
+ 'Amount in Customer Currency',
+ 'woocommerce-payments'
+ ),
+ isNumeric: true,
+ isSortable: true,
+ visible: false,
+ },
+ {
+ key: 'deposit_currency',
+ label: __( 'Deposit Currency', 'woocommerce-payments' ),
+ screenReaderLabel: __( 'Deposit Currency', 'woocommerce-payments' ),
+ isSortable: true,
+ visible: false,
+ },
{
key: 'amount',
label: __( 'Amount', 'woocommerce-payments' ),
- screenReaderLabel: __( 'Amount', 'woocommerce-payments' ),
+ screenReaderLabel: __(
+ 'Amount in Deposit Curency',
+ 'woocommerce-payments'
+ ),
isNumeric: true,
isSortable: true,
},
@@ -205,8 +239,8 @@ const getColumns = (
},
{
key: 'source',
- label: __( 'Source', 'woocommerce-payments' ),
- screenReaderLabel: __( 'Source', 'woocommerce-payments' ),
+ label: __( 'Payment Method', 'woocommerce-payments' ),
+ screenReaderLabel: __( 'Payment Method', 'woocommerce-payments' ),
cellClassName: 'is-center-aligned',
},
{
@@ -236,6 +270,14 @@ const getColumns = (
visible: false,
isLeftAligned: true,
},
+ includeDeposit && {
+ key: 'deposit_id',
+ label: __( 'Deposit ID', 'woocommerce-payments' ),
+ screenReaderLabel: __( 'Deposit ID', 'woocommerce-payments' ),
+ cellClassName: 'deposit',
+ isLeftAligned: true,
+ visible: false,
+ },
includeDeposit && {
key: 'deposit',
label: __( 'Deposit date', 'woocommerce-payments' ),
@@ -333,12 +375,6 @@ export const TransactionsList = (
txn.customer_email
);
- const deposit = (
-
- );
const currency = txn.currency.toUpperCase();
const dataType = txn.metadata ? txn.metadata.charge_type : txn.type;
@@ -377,15 +413,33 @@ export const TransactionsList = (
),
};
};
-
- const depositStatus = txn.deposit_status
- ? displayDepositStatus[ txn.deposit_status ]
- : '';
+ const formatCustomerAmount = () => {
+ return {
+ value: formatExportAmount(
+ txn.customer_amount,
+ txn.customer_currency
+ ),
+ display: clickable(
+ formatCurrency( txn.customer_amount, txn.customer_currency )
+ ),
+ };
+ };
const isFinancingType =
-1 !==
[ 'financing_payout', 'financing_paydown' ].indexOf( txn.type );
+ const deposit = ! isFinancingType && (
+
+ );
+
+ const depositStatus = txn.deposit_status
+ ? displayDepositStatus[ txn.deposit_status ]
+ : '';
+
// Map transaction into table row.
const data = {
transaction_id: {
@@ -463,6 +517,15 @@ export const TransactionsList = (
value: txn.customer_country,
display: clickable( txn.customer_country ),
},
+ customer_currency: {
+ value: txn.customer_currency.toUpperCase(),
+ display: clickable( txn.customer_currency.toUpperCase() ),
+ },
+ customer_amount: formatCustomerAmount(),
+ deposit_currency: {
+ value: txn.currency.toUpperCase(),
+ display: clickable( txn.currency.toUpperCase() ),
+ },
amount: formatAmount(),
// fees should display as negative. The format $-9.99 is determined by WC-Admin
fees: formatFees(),
@@ -476,6 +539,10 @@ export const TransactionsList = (
value: calculateRiskMapping( txn.risk_level ),
display: clickable( riskLevel ),
},
+ deposit_id: {
+ value: txn.deposit_id,
+ display: txn.deposit_id,
+ },
deposit: { value: txn.available_on, display: deposit },
deposit_status: {
value: depositStatus,
diff --git a/client/transactions/list/test/__snapshots__/deposit.tsx.snap b/client/transactions/list/test/__snapshots__/deposit.tsx.snap
index ff5e2f4fb9d..5aae20de2e7 100644
--- a/client/transactions/list/test/__snapshots__/deposit.tsx.snap
+++ b/client/transactions/list/test/__snapshots__/deposit.tsx.snap
@@ -11,10 +11,101 @@ exports[`Deposit renders with date and deposit available 1`] = `
`;
-exports[`Deposit renders with date available but no deposit 1`] = `
`;
-
-exports[`Deposit renders with deposit but no date available 1`] = `
`;
+exports[`Deposit renders with date available but no deposit 1`] = `
+
+`;
-exports[`Deposit renders with estimated date and deposit available 1`] = `
`;
+exports[`Deposit renders with deposit but no date available 1`] = `
+
+`;
-exports[`Deposit renders with no date or deposit available 1`] = `
`;
+exports[`Deposit renders with no date or deposit available 1`] = `
+
+`;
diff --git a/client/transactions/list/test/__snapshots__/index.tsx.snap b/client/transactions/list/test/__snapshots__/index.tsx.snap
index 2f460c0f997..c7bfca77b45 100644
--- a/client/transactions/list/test/__snapshots__/index.tsx.snap
+++ b/client/transactions/list/test/__snapshots__/index.tsx.snap
@@ -248,19 +248,19 @@ exports[`Transactions list renders correctly when can filter by several currenci
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
+ >
+ Future deposit
+
+
+
+
+ >
+ Future deposit
+
+
+
+
@@ -1179,19 +1237,19 @@ exports[`Transactions list renders correctly when filtered by currency 1`] = `
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
+ >
+ Future deposit
+
+
+
+
+ >
+ Future deposit
+
+
+
+
@@ -2107,19 +2223,19 @@ exports[`Transactions list renders correctly when filtered by deposit 1`] = `
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
+ >
+ Future deposit
+
+
+
+
+ >
+ Future deposit
+
+
+
+
@@ -3789,19 +3963,19 @@ exports[`Transactions list when not filtered by deposit renders correctly 1`] =
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
+ >
+ Future deposit
+
+
+
+
+ >
+ Future deposit
+
+
+
+
@@ -4762,19 +4994,19 @@ exports[`Transactions list when not filtered by deposit renders table summary on
- Date / Time
+ Date / Time (UTC)
- Date and time
+ Date and time in UTC
- Amount
+ Amount in Deposit Curency
- Source
+ Payment Method
- Source
+ Payment Method
+ >
+ Future deposit
+
+
+
+
+ >
+ Future deposit
+
+
+
+
diff --git a/client/transactions/list/test/deposit.tsx b/client/transactions/list/test/deposit.tsx
index 478baa171a6..2cb87b0b248 100644
--- a/client/transactions/list/test/deposit.tsx
+++ b/client/transactions/list/test/deposit.tsx
@@ -19,16 +19,6 @@ describe( 'Deposit', () => {
expect( link ).toMatchSnapshot();
} );
- test( 'renders with estimated date and deposit available', () => {
- const { container: link } = render(
-
- );
- expect( link ).toMatchSnapshot();
- } );
-
test( 'renders with date available but no deposit', () => {
const { container: link } = render(
diff --git a/client/transactions/list/test/index.tsx b/client/transactions/list/test/index.tsx
index d2706511578..63fbbc01427 100644
--- a/client/transactions/list/test/index.tsx
+++ b/client/transactions/list/test/index.tsx
@@ -302,18 +302,18 @@ describe( 'Transactions list', () => {
} );
test( 'sorts by default field date', () => {
- sortBy( 'Date and time' );
+ sortBy( 'Date and time in UTC' );
expectSortingToBe( 'date', 'asc' );
- sortBy( 'Date and time' );
+ sortBy( 'Date and time in UTC' );
expectSortingToBe( 'date', 'desc' );
} );
test( 'sorts by amount', () => {
- sortBy( 'Amount' );
+ sortBy( 'Amount in Deposit Curency' );
expectSortingToBe( 'amount', 'desc' );
- sortBy( 'Amount' );
+ sortBy( 'Amount in Deposit Curency' );
expectSortingToBe( 'amount', 'asc' );
} );
@@ -609,18 +609,22 @@ describe( 'Transactions list', () => {
const expected = [
'"Transaction Id"',
- '"Date / Time"',
+ '"Date / Time (UTC)"',
'Type',
'Channel',
+ '"Paid Currency"',
+ '"Amount Paid"',
+ '"Deposit Currency"',
'Amount',
'Fees',
'Net',
'"Order #"',
- 'Source',
+ '"Payment Method"',
'Customer',
'Email',
'Country',
'"Risk level"',
+ '"Deposit ID"',
'"Deposit date"',
'"Deposit status"',
];
@@ -675,26 +679,26 @@ describe( 'Transactions list', () => {
); // channel
expect(
getUnformattedAmount( displayFirstTransaction[ 3 ] ).indexOf(
- csvFirstTransaction[ 4 ]
+ csvFirstTransaction[ 7 ]
)
).not.toBe( -1 ); // amount
expect(
-Number( getUnformattedAmount( displayFirstTransaction[ 4 ] ) )
).toEqual(
Number(
- csvFirstTransaction[ 5 ].replace( /['"]+/g, '' ) // strip extra quotes
+ csvFirstTransaction[ 8 ].replace( /['"]+/g, '' ) // strip extra quotes
)
); // fees
expect(
getUnformattedAmount( displayFirstTransaction[ 5 ] ).indexOf(
- csvFirstTransaction[ 6 ]
+ csvFirstTransaction[ 9 ]
)
).not.toBe( -1 ); // net
expect( displayFirstTransaction[ 6 ] ).toBe(
- csvFirstTransaction[ 7 ]
+ csvFirstTransaction[ 10 ]
); // order number
expect( displayFirstTransaction[ 8 ] ).toBe(
- csvFirstTransaction[ 9 ].replace( /['"]+/g, '' ) // strip extra quotes
+ csvFirstTransaction[ 12 ].replace( /['"]+/g, '' ) // strip extra quotes
); // customer
} );
} );
diff --git a/client/utils/account-fees.tsx b/client/utils/account-fees.tsx
index 6ba2674de6d..c2b3214c1b5 100644
--- a/client/utils/account-fees.tsx
+++ b/client/utils/account-fees.tsx
@@ -74,24 +74,31 @@ const getStripeFeeSectionUrl = ( country: string ): string => {
);
};
-const getFeeDescriptionString = ( fee: BaseFee ): string => {
+const getFeeDescriptionString = (
+ fee: BaseFee,
+ discountBasedMultiplier: number
+): string => {
if ( fee.fixed_rate && fee.percentage_rate ) {
return sprintf(
'%1$f%% + %2$s',
- formatFee( fee.percentage_rate ),
- formatCurrency( fee.fixed_rate, fee.currency )
+ formatFee( fee.percentage_rate * discountBasedMultiplier ),
+ formatCurrency(
+ fee.fixed_rate * discountBasedMultiplier,
+ fee.currency
+ )
);
} else if ( fee.fixed_rate ) {
return sprintf(
- '%2$s',
- formatFee( fee.percentage_rate ),
- formatCurrency( fee.fixed_rate, fee.currency )
+ '%1$s',
+ formatCurrency(
+ fee.fixed_rate * discountBasedMultiplier,
+ fee.currency
+ )
);
} else if ( fee.percentage_rate ) {
return sprintf(
'%1$f%%',
- formatFee( fee.percentage_rate ),
- formatCurrency( fee.fixed_rate, fee.currency )
+ formatFee( fee.percentage_rate * discountBasedMultiplier )
);
}
return '';
@@ -109,19 +116,19 @@ export const formatMethodFeesTooltip = (
accountFees: FeeStructure
): JSX.Element => {
if ( ! accountFees ) return <>>;
- const currentBaseFee = getCurrentBaseFee( accountFees );
- // If the current fee doesn't have a fixed or percentage rate, use the base fee's rate. Eg. when there is a promotional discount fee applied. Use this to calculate the total fee too.
- const currentFeeWithBaseFallBack = currentBaseFee.percentage_rate
- ? currentBaseFee
- : accountFees.base;
+
+ const discountAdjustedFeeRate: number =
+ accountFees.discount.length && accountFees.discount[ 0 ].discount
+ ? 1 - accountFees.discount[ 0 ].discount
+ : 1;
const total = {
percentage_rate:
- currentFeeWithBaseFallBack.percentage_rate +
+ accountFees.base.percentage_rate +
accountFees.additional.percentage_rate +
accountFees.fx.percentage_rate,
fixed_rate:
- currentFeeWithBaseFallBack.fixed_rate +
+ accountFees.base.fixed_rate +
accountFees.additional.fixed_rate +
accountFees.fx.fixed_rate,
currency: accountFees.base.currency,
@@ -136,14 +143,20 @@ export const formatMethodFeesTooltip = (
Base fee
- { getFeeDescriptionString( currentFeeWithBaseFallBack ) }
+ { getFeeDescriptionString(
+ accountFees.base,
+ discountAdjustedFeeRate
+ ) }
{ hasFees( accountFees.additional ) ? (
International payment method fee
- { getFeeDescriptionString( accountFees.additional ) }
+ { getFeeDescriptionString(
+ accountFees.additional,
+ discountAdjustedFeeRate
+ ) }
) : (
@@ -152,7 +165,12 @@ export const formatMethodFeesTooltip = (
{ hasFees( accountFees.fx ) ? (
Foreign exchange fee
-
{ getFeeDescriptionString( accountFees.fx ) }
+
+ { getFeeDescriptionString(
+ accountFees.fx,
+ discountAdjustedFeeRate
+ ) }
+
) : (
''
@@ -160,7 +178,10 @@ export const formatMethodFeesTooltip = (
Total per transaction
- { getFeeDescriptionString( total ) }
+ { getFeeDescriptionString(
+ total,
+ discountAdjustedFeeRate
+ ) }
{ wcpaySettings &&
diff --git a/client/utils/test/__snapshots__/account-fees.tsx.snap b/client/utils/test/__snapshots__/account-fees.tsx.snap
index 5ec2897e12b..5388a2b344d 100644
--- a/client/utils/test/__snapshots__/account-fees.tsx.snap
+++ b/client/utils/test/__snapshots__/account-fees.tsx.snap
@@ -10,7 +10,7 @@ exports[`Account fees utility functions formatMethodFeesTooltip() displays base
Base fee
- 12.3% + $4.57
+ 9.84% + $3.65
@@ -18,7 +18,7 @@ exports[`Account fees utility functions formatMethodFeesTooltip() displays base
International payment method fee
- 1%
+ 0.8%
@@ -26,7 +26,7 @@ exports[`Account fees utility functions formatMethodFeesTooltip() displays base
Foreign exchange fee
- 1%
+ 0.8%
@@ -36,7 +36,7 @@ exports[`Account fees utility functions formatMethodFeesTooltip() displays base
- 14.3% + $4.57
+ 11.44% + $3.65
`;
-
-exports[`Account fees utility functions formatMethodFeesTooltip() displays custom fee details, when applicable 1`] = `
-
-`;
diff --git a/client/utils/test/account-fees.tsx b/client/utils/test/account-fees.tsx
index 72cf891067b..c1b181ac160 100644
--- a/client/utils/test/account-fees.tsx
+++ b/client/utils/test/account-fees.tsx
@@ -310,35 +310,6 @@ describe( 'Account fees utility functions', () => {
expect( container ).toMatchSnapshot();
} );
- it( 'displays custom fee details, when applicable', () => {
- const methodFees = mockAccountFees(
- {
- percentage_rate: 0.123,
- fixed_rate: 456.78,
- currency: 'USD',
- },
- [ { percentage_rate: 0.101, fixed_rate: 400.78 } ]
- );
-
- methodFees.additional = {
- percentage_rate: 0.01,
- fixed_rate: 0,
- currency: 'USD',
- };
-
- methodFees.fx = {
- percentage_rate: 0.01,
- fixed_rate: 0,
- currency: 'USD',
- };
-
- const { container } = render(
- formatMethodFeesTooltip( methodFees )
- );
-
- expect( container ).toMatchSnapshot();
- } );
-
it( 'displays base fee, when only promo discount without percentage or fixed', () => {
const methodFees = mockAccountFees(
{
diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php
index 153746bd832..0dc167c4aca 100644
--- a/includes/admin/class-wc-payments-admin.php
+++ b/includes/admin/class-wc-payments-admin.php
@@ -877,6 +877,7 @@ private function get_js_settings(): array {
'isStripeBillingEligible' => WC_Payments_Features::is_stripe_billing_eligible(),
'capabilityRequestNotices' => get_option( 'wcpay_capability_request_dismissed_notices ', [] ),
'storeName' => get_bloginfo( 'name' ),
+ 'isNextDepositNoticeDismissed' => WC_Payments_Features::is_next_deposit_notice_dismissed(),
];
return apply_filters( 'wcpay_js_settings', $this->wcpay_js_settings );
diff --git a/includes/admin/class-wc-rest-payments-settings-controller.php b/includes/admin/class-wc-rest-payments-settings-controller.php
index 1025c697990..057af86e3f5 100644
--- a/includes/admin/class-wc-rest-payments-settings-controller.php
+++ b/includes/admin/class-wc-rest-payments-settings-controller.php
@@ -773,6 +773,11 @@ private function update_account( WP_REST_Request $request ) {
$updated_fields['deposit_schedule_interval'] = $this->wcpay_gateway->get_option( 'deposit_schedule_interval' );
}
+ // If we are updating any deposit schedule values, we should invalidate the next deposit notice dismissed notice option.
+ if ( preg_grep( '/^deposit_schedule_/', array_keys( $updated_fields ) ) ) {
+ delete_option( 'wcpay_next_deposit_notice_dismissed' );
+ }
+
return $this->wcpay_gateway->update_account_settings( $updated_fields );
}
diff --git a/includes/class-wc-payments-features.php b/includes/class-wc-payments-features.php
index 416cac38831..904164421e0 100644
--- a/includes/class-wc-payments-features.php
+++ b/includes/class-wc-payments-features.php
@@ -351,6 +351,15 @@ public static function is_dispute_issuer_evidence_enabled(): bool {
return '1' === get_option( self::DISPUTE_ISSUER_EVIDENCE, '0' );
}
+ /**
+ * Checks whether the next deposit notice on the deposits list screen has been dismissed.
+ *
+ * @return bool
+ */
+ public static function is_next_deposit_notice_dismissed(): bool {
+ return '1' === get_option( 'wcpay_next_deposit_notice_dismissed', '0' );
+ }
+
/**
* Returns feature flags as an array suitable for display on the front-end.
*
diff --git a/includes/class-wc-payments-upe-split-blocks-payment-method.php b/includes/class-wc-payments-upe-split-blocks-payment-method.php
deleted file mode 100644
index 2f1188611ea..00000000000
--- a/includes/class-wc-payments-upe-split-blocks-payment-method.php
+++ /dev/null
@@ -1,26 +0,0 @@
-register( new WC_Payments_UPE_Split_Blocks_Payment_Method() );
+ $payment_method_registry->register( new WC_Payments_Blocks_Payment_Method() );
}
/**
@@ -1645,6 +1644,7 @@ public static function add_wcpay_options_to_woocommerce_permissions_list( $permi
'wcpay_fraud_protection_welcome_tour_dismissed',
'wcpay_capability_request_dismissed_notices',
'wcpay_onboarding_eligibility_modal_dismissed',
+ 'wcpay_next_deposit_notice_dismissed',
],
true
);
diff --git a/includes/class-woopay-tracker.php b/includes/class-woopay-tracker.php
index 123ec606a7b..672e8251b11 100644
--- a/includes/class-woopay-tracker.php
+++ b/includes/class-woopay-tracker.php
@@ -71,6 +71,7 @@ public function __construct( $http ) {
add_action( 'woocommerce_blocks_checkout_order_processed', [ $this, 'checkout_order_processed' ] );
add_action( 'woocommerce_payments_save_user_in_woopay', [ $this, 'must_save_payment_method_to_platform' ] );
add_action( 'before_woocommerce_pay_form', [ $this, 'pay_for_order_page_view' ] );
+ add_action( 'woocommerce_thankyou', [ $this, 'thank_you_page_view' ] );
}
/**
@@ -460,6 +461,22 @@ public function must_save_payment_method_to_platform() {
);
}
+ /**
+ * Record a Tracks event that Thank you page was viewed for a WCPay order.
+ *
+ * @param int $order_id The ID of the order.
+ * @return void
+ */
+ public function thank_you_page_view($order_id) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order || 'woocommerce_payments' !== $order->get_payment_method() ) {
+ return;
+ }
+
+ $this->maybe_record_wcpay_shopper_event( 'order_success_page_view' );
+ }
+
/**
* Record a Tracks event that the WooPay express button locations has been updated.
*
diff --git a/includes/notes/class-wc-payments-notes-qualitative-feedback.php b/includes/notes/class-wc-payments-notes-qualitative-feedback.php
index 266e1dd70f1..031fbd6b473 100644
--- a/includes/notes/class-wc-payments-notes-qualitative-feedback.php
+++ b/includes/notes/class-wc-payments-notes-qualitative-feedback.php
@@ -38,8 +38,27 @@ public static function get_note() {
}
// We should have at least one transaction.
- $token_count = $wpdb->get_var( "select count(*) from {$wpdb->prefix}woocommerce_payment_tokens" );
- if ( 0 === (int) $token_count ) {
+ if ( WC_Payments_Utils::is_hpos_tables_usage_enabled() ) {
+ $result = $wpdb->get_var(
+ "SELECT EXISTS(
+ SELECT 1
+ FROM {$wpdb->prefix}wc_orders_meta
+ WHERE meta_key = '_wcpay_transaction_fee'
+ LIMIT 1)
+ AS count;"
+ );
+ } else {
+ $result = $wpdb->get_var(
+ "SELECT EXISTS(
+ SELECT 1
+ FROM {$wpdb->postmeta}
+ WHERE meta_key = '_wcpay_transaction_fee'
+ LIMIT 1)
+ AS count;"
+ );
+ }
+
+ if ( 1 !== intval( $result ) ) {
return;
}
diff --git a/package-lock.json b/package-lock.json
index 71e547a4303..7e7375967b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "woocommerce-payments",
- "version": "6.9.1",
+ "version": "6.9.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "woocommerce-payments",
- "version": "6.9.1",
+ "version": "6.9.2",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
diff --git a/package.json b/package.json
index 905e6bbbe01..d80cfbe4bd0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce-payments",
- "version": "6.9.1",
+ "version": "6.9.2",
"main": "webpack.config.js",
"author": "Automattic",
"license": "GPL-3.0-or-later",
diff --git a/readme.txt b/readme.txt
index e7f21908b84..8a57aead24b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment
Requires at least: 6.0
Tested up to: 6.4
Requires PHP: 7.3
-Stable tag: 6.9.1
+Stable tag: 6.9.2
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -94,6 +94,13 @@ Please note that our support for the checkout block is still experimental and th
== Changelog ==
+= 6.9.2 - 2023-12-14 =
+* Add - Notice is added when merchant has funds that are not yet available for deposit.
+* Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected.
+* Fix - Show deposit schedule message when deposits are unrestricted
+* Fix - Transactions List - indicate when a transaction is expected to be included in a future deposit
+
+
= 6.9.1 - 2023-12-07 =
* Fix - Display Klarna & Afterpay on the checkout for UK based stores
diff --git a/tests/e2e/config/jest.setup.js b/tests/e2e/config/jest.setup.js
index 00f41b376ad..a29f5138fcb 100644
--- a/tests/e2e/config/jest.setup.js
+++ b/tests/e2e/config/jest.setup.js
@@ -24,6 +24,9 @@ const ERROR_MESSAGES_TO_IGNORE = [
'Scripts that have a dependency on',
'was preloaded using link preload but not used within a few seconds',
'No UI will be shown. CanMakePayment and hasEnrolledInstrument',
+ 'Failed to load resource: the server responded with a status of 404 (Not Found)',
+ 'Store "wc/payments" is already registered.',
+ 'Preflight request for request with keepalive specified is currently not supported',
];
ERROR_MESSAGES_TO_IGNORE.forEach( ( errorMessage ) => {
diff --git a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js b/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js
index 1e9a6a27956..e1062f6d1ca 100644
--- a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js
+++ b/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js
@@ -18,13 +18,10 @@ import { uiUnblocked } from '@woocommerce/e2e-utils/build/page-utils';
const { shopper, merchant } = require( '@woocommerce/e2e-utils' );
const UPE_METHOD_CHECKBOXES = [
- '#inspector-checkbox-control-5', // bancontact
- '#inspector-checkbox-control-6', // eps
'#inspector-checkbox-control-7', // giropay
- '#inspector-checkbox-control-8', // ideal
- '#inspector-checkbox-control-9', // sofort
];
const card = config.get( 'cards.basic' );
+const card2 = config.get( 'cards.basic2' );
const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000;
describe( 'Enabled UPE with deferred intent creation', () => {
@@ -33,11 +30,9 @@ 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 () => {
- await shopperWCP.changeAccountCurrencyTo( 'USD' );
await shopperWCP.logout();
await merchant.login();
await merchantWCP.disablePaymentMethod( UPE_METHOD_CHECKBOXES );
@@ -46,6 +41,7 @@ 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' )
);
@@ -115,10 +111,23 @@ describe( 'Enabled UPE with deferred intent creation', () => {
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', () => {
let timeAdded;
+
it( 'should add the card as a new payment method', async () => {
await shopperWCP.goToPaymentMethods();
await shopperWCP.addNewPaymentMethod( 'basic', card );
@@ -134,14 +143,43 @@ describe( 'Enabled UPE with deferred intent creation', () => {
await expect( page ).toMatch(
`${ card.expires.month }/${ card.expires.year }`
);
+ await waitTwentySecondsSinceLastCardAdded();
+ } );
+
+ it( 'should be able to set payment method as default', async () => {
+ await shopperWCP.goToPaymentMethods();
+ await shopperWCP.addNewPaymentMethod( 'basic2', card2 );
+ // 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(
+ `${ card2.expires.month }/${ card2.expires.year }`
+ );
+ await shopperWCP.setDefaultPaymentMethod( card2.label );
+ // Verify that the card was set as default
+ await expect( page ).toMatch(
+ 'This payment method was successfully set as your default.'
+ );
} );
- it( 'should be able to delete the card', async () => {
+ it( 'should be able to delete cards', async () => {
await shopperWCP.deleteSavedPaymentMethod( card.label );
await expect( page ).toMatch( 'Payment method deleted.' );
+
+ await shopperWCP.deleteSavedPaymentMethod( card2.label );
+ await expect( page ).toMatch( 'Payment method deleted.' );
} );
afterAll( async () => {
+ await waitTwentySecondsSinceLastCardAdded();
+ } );
+
+ async function waitTwentySecondsSinceLastCardAdded() {
// 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."
@@ -153,6 +191,6 @@ describe( 'Enabled UPE with deferred intent creation', () => {
: 0;
await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) );
- } );
+ }
} );
} );
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 9c14db6bdbf..715732b40f9 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.js
@@ -9,7 +9,6 @@ import { shopperWCP } from '../../../utils';
import {
clearCardDetails,
- confirmCardAuthentication,
fillCardDetails,
setupProductCheckout,
} from '../../../utils/payments';
@@ -145,7 +144,6 @@ describe( 'Shopper > Checkout > Failures with various cards', () => {
const declinedCard = config.get( 'cards.declined-3ds' );
await fillCardDetails( page, declinedCard );
await expect( page ).toClick( '#place_order' );
- await confirmCardAuthentication( page, '3DS' );
await page.waitForSelector( 'ul.woocommerce-error' );
const declined3dsCardError = await page.$eval(
'div.woocommerce-NoticeGroup > ul.woocommerce-error',
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.js
index 182802a62ba..23aec018d59 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.js
@@ -64,6 +64,7 @@ describe( 'Shopper Multi-Currency widget', () => {
it( 'should display currency switcher widget if multi-currency is enabled', async () => {
await merchantWCP.addMulticurrencyWidget();
+ await merchant.logout();
await shopper.goToShop();
await page.waitForSelector( '.widget select[name=currency]', {
visible: true,
@@ -72,6 +73,7 @@ describe( 'Shopper Multi-Currency widget', () => {
} );
it( 'should not display currency switcher widget if multi-currency is disabled', async () => {
+ await merchant.login();
await merchantWCP.openWCPSettings();
await merchantWCP.deactivateMulticurrency();
await shopper.goToShop();
diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js
index 0a2d8a8e7f8..aa18cd328a7 100644
--- a/tests/e2e/utils/flows.js
+++ b/tests/e2e/utils/flows.js
@@ -129,6 +129,14 @@ export const shopperWCP = {
await expect( page ).toClick( 'label', { text: label } );
},
+ setDefaultPaymentMethod: async ( label ) => {
+ const [ paymentMethodRow ] = await page.$x(
+ `//tr[contains(., '${ label }')]`
+ );
+ await expect( paymentMethodRow ).toClick( '.button.default' );
+ await page.waitForNavigation( { waitUntil: 'networkidle0' } );
+ },
+
toggleCreateAccount: async () => {
await expect( page ).toClick( '#createaccount' );
},
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index e135eef1a56..df1a348ec90 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -12,7 +12,7 @@
* WC tested up to: 8.3.1
* Requires at least: 6.0
* Requires PHP: 7.3
- * Version: 6.9.1
+ * Version: 6.9.2
*
* @package WooCommerce\Payments
*/