diff --git a/changelog/fix-backwards-compat-mccy-instance b/changelog/fix-backwards-compat-mccy-instance new file mode 100644 index 00000000000..95a0701ac1c --- /dev/null +++ b/changelog/fix-backwards-compat-mccy-instance @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Provide backwards-compatible method for retrieving the multi-currency instance. diff --git a/changelog/multi-currency-v2 b/changelog/multi-currency-v2 new file mode 100644 index 00000000000..463f61c882e --- /dev/null +++ b/changelog/multi-currency-v2 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Decoupled Multi-currency module from gateway dependencies. diff --git a/client/additional-methods-setup/upe-preview-methods-selector/add-payment-methods-task.js b/client/additional-methods-setup/upe-preview-methods-selector/add-payment-methods-task.js index 76a2f3baa71..fbc23b63b67 100644 --- a/client/additional-methods-setup/upe-preview-methods-selector/add-payment-methods-task.js +++ b/client/additional-methods-setup/upe-preview-methods-selector/add-payment-methods-task.js @@ -36,7 +36,7 @@ import PaymentMethodCheckbox from '../../components/payment-methods-checkboxes/p import { LoadableBlock } from '../../components/loadable'; import LoadableSettingsSection from '../../settings/loadable-settings-section'; import CurrencyInformationForMethods from './currency-information-for-methods'; -import { getMissingCurrenciesTooltipMessage } from 'wcpay/multi-currency/missing-currencies-message'; +import { getMissingCurrenciesTooltipMessage } from 'multi-currency/interface/functions'; import { upeCapabilityStatuses, upeMethods } from '../constants'; import paymentMethodsMap from '../../payment-methods-map'; import ConfirmPaymentMethodActivationModal from 'wcpay/settings/payment-methods-list/activation-modal'; diff --git a/client/additional-methods-setup/upe-preview-methods-selector/currency-information-for-methods.js b/client/additional-methods-setup/upe-preview-methods-selector/currency-information-for-methods.js index f4e1fc02cbc..9639a729c8b 100644 --- a/client/additional-methods-setup/upe-preview-methods-selector/currency-information-for-methods.js +++ b/client/additional-methods-setup/upe-preview-methods-selector/currency-information-for-methods.js @@ -9,11 +9,11 @@ import interpolateComponents from '@automattic/interpolate-components'; /** * Internal dependencies */ +import { useAccountDomesticCurrency } from '../../data'; import { - useAccountDomesticCurrency, useCurrencies, useEnabledCurrencies, -} from '../../data'; +} from 'multi-currency/interface/data'; import WCPaySettingsContext from '../../settings/wcpay-settings-context'; import InlineNotice from 'components/inline-notice'; import PaymentMethodsMap from '../../payment-methods-map'; diff --git a/client/additional-methods-setup/upe-preview-methods-selector/test/add-payment-methods-task.test.js b/client/additional-methods-setup/upe-preview-methods-selector/test/add-payment-methods-task.test.js index 3339e812975..3a12347327f 100644 --- a/client/additional-methods-setup/upe-preview-methods-selector/test/add-payment-methods-task.test.js +++ b/client/additional-methods-setup/upe-preview-methods-selector/test/add-payment-methods-task.test.js @@ -22,11 +22,14 @@ import { useEnabledPaymentMethodIds, useGetPaymentMethodStatuses, useSettings, - useCurrencies, - useEnabledCurrencies, useManualCapture, useAccountDomesticCurrency, } from '../../../data'; +import { + useCurrencies, + useEnabledCurrencies, +} from 'multi-currency/interface/data'; + import WCPaySettingsContext from '../../../settings/wcpay-settings-context'; import { upeCapabilityStatuses } from 'wcpay/additional-methods-setup/constants'; @@ -34,13 +37,16 @@ jest.mock( '../../../data', () => ( { useGetAvailablePaymentMethodIds: jest.fn(), useEnabledPaymentMethodIds: jest.fn(), useSettings: jest.fn(), - useCurrencies: jest.fn(), - useEnabledCurrencies: jest.fn(), useGetPaymentMethodStatuses: jest.fn(), useManualCapture: jest.fn(), useAccountDomesticCurrency: jest.fn(), } ) ); +jest.mock( 'multi-currency/interface/data', () => ( { + useCurrencies: jest.fn(), + useEnabledCurrencies: jest.fn(), +} ) ); + jest.mock( '@wordpress/a11y', () => ( { ...jest.requireActual( '@wordpress/a11y' ), speak: jest.fn(), diff --git a/client/additional-methods-setup/upe-preview-methods-selector/test/currency-information-for-methods.test.js b/client/additional-methods-setup/upe-preview-methods-selector/test/currency-information-for-methods.test.js index fd473249eb7..cc2abefe96d 100644 --- a/client/additional-methods-setup/upe-preview-methods-selector/test/currency-information-for-methods.test.js +++ b/client/additional-methods-setup/upe-preview-methods-selector/test/currency-information-for-methods.test.js @@ -7,18 +7,21 @@ import { render, screen } from '@testing-library/react'; /** * Internal dependencies */ +import { useAccountDomesticCurrency } from '../../../data'; import { useCurrencies, useEnabledCurrencies, - useAccountDomesticCurrency, -} from 'wcpay/data'; +} from 'multi-currency/interface/data'; import CurrencyInformationForMethods from '../currency-information-for-methods'; import WCPaySettingsContext from '../../../settings/wcpay-settings-context'; -jest.mock( 'wcpay/data', () => ( { +jest.mock( '../../../data', () => ( { + useAccountDomesticCurrency: jest.fn(), +} ) ); + +jest.mock( 'multi-currency/interface/data', () => ( { useCurrencies: jest.fn(), useEnabledCurrencies: jest.fn(), - useAccountDomesticCurrency: jest.fn(), } ) ); jest.mock( '@wordpress/a11y', () => ( { diff --git a/client/additional-methods-setup/wizard/task-item.scss b/client/additional-methods-setup/wizard/task-item.scss index c2b7dbb5ec6..ae24c06ac08 100644 --- a/client/additional-methods-setup/wizard/task-item.scss +++ b/client/additional-methods-setup/wizard/task-item.scss @@ -117,6 +117,22 @@ } } + &__visible-description-element { + position: absolute; + margin-left: 40px; + margin-top: 0; + margin-bottom: 1em; + + &.is-muted-color { + color: $gray-700; + } + + .components-external-link svg { + width: 1em; + height: 1em; + } + } + .add-payment-methods-task { &__payment-selector { &-wrapper { diff --git a/client/additional-methods-setup/wizard/task-item.tsx b/client/additional-methods-setup/wizard/task-item.tsx index f1c7ba4177e..a0ec6169bae 100644 --- a/client/additional-methods-setup/wizard/task-item.tsx +++ b/client/additional-methods-setup/wizard/task-item.tsx @@ -16,6 +16,7 @@ interface WizardTaskItemProps { title: string; index: number; className?: string; + visibleDescription?: string; } const WizardTaskItem: React.FC< WizardTaskItemProps > = ( { @@ -23,6 +24,7 @@ const WizardTaskItem: React.FC< WizardTaskItemProps > = ( { title, index, className, + visibleDescription, } ) => { const { isCompleted, isActive } = useContext( WizardTaskContext ); @@ -51,6 +53,16 @@ const WizardTaskItem: React.FC< WizardTaskItemProps > = ( { { title } + { visibleDescription && ! isActive && ( + + { visibleDescription } + + ) }
{ children }
); diff --git a/client/capital/index.tsx b/client/capital/index.tsx index 8d1ab3f4741..81e76ad91b4 100644 --- a/client/capital/index.tsx +++ b/client/capital/index.tsx @@ -15,7 +15,10 @@ import Page from 'components/page'; import { TestModeNotice } from 'components/test-mode-notice'; import ErrorBoundary from 'components/error-boundary'; import ActiveLoanSummary from 'components/active-loan-summary'; -import { formatExplicitCurrency, isZeroDecimalCurrency } from 'utils/currency'; +import { + formatExplicitCurrency, + isZeroDecimalCurrency, +} from 'multi-currency/interface/functions'; import { CapitalLoan } from 'data/capital/types'; import ClickableCell from 'components/clickable-cell'; import Chip from 'components/chip'; diff --git a/client/checkout/woopay/email-input-iframe.js b/client/checkout/woopay/email-input-iframe.js index 83a4f196924..c5ccaceed96 100644 --- a/client/checkout/woopay/email-input-iframe.js +++ b/client/checkout/woopay/email-input-iframe.js @@ -13,8 +13,8 @@ import { appendRedirectionParams, shouldSkipWooPay, deleteSkipWooPayCookie, -} from 'wcpay/checkout/woopay/utils'; -import { getAppearanceType } from 'wcpay/checkout/utils'; +} from './utils'; +import { getAppearanceType } from '../utils'; export const handleWooPayEmailInput = async ( field, diff --git a/client/components/account-balances/balance-block.tsx b/client/components/account-balances/balance-block.tsx index 4b71f4ef273..c9c9535c9ee 100644 --- a/client/components/account-balances/balance-block.tsx +++ b/client/components/account-balances/balance-block.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; /** * Internal dependencies */ -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import Loadable from 'components/loadable'; /** diff --git a/client/components/account-balances/index.tsx b/client/components/account-balances/index.tsx index 2a1ace68487..fa3be8b8422 100644 --- a/client/components/account-balances/index.tsx +++ b/client/components/account-balances/index.tsx @@ -23,7 +23,7 @@ import { } from './balance-tooltip'; import { fundLabelStrings } from './strings'; import { ClickTooltip } from '../tooltip'; -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import { useAllDepositsOverviews } from 'wcpay/data'; import { useSelectedCurrency } from 'wcpay/overview/hooks'; import './style.scss'; diff --git a/client/components/account-status/account-fees/expiration-bar.js b/client/components/account-status/account-fees/expiration-bar.js index 80003bba2a4..2d293e948c9 100644 --- a/client/components/account-status/account-fees/expiration-bar.js +++ b/client/components/account-status/account-fees/expiration-bar.js @@ -4,7 +4,7 @@ * Internal dependencies */ import ProgressBar from 'components/progress-bar'; -import { formatCurrency } from 'utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; const ExpirationBar = ( { feeData: { diff --git a/client/components/account-status/account-fees/expiration-description.js b/client/components/account-status/account-fees/expiration-description.js index a07067b6495..6be5b58681c 100644 --- a/client/components/account-status/account-fees/expiration-description.js +++ b/client/components/account-status/account-fees/expiration-description.js @@ -10,7 +10,7 @@ import moment from 'moment'; /** * Internal dependencies */ -import { formatCurrency } from 'utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; const ExpirationDescription = ( { feeData: { volume_allowance: volumeAllowance, end_time: endTime, ...rest }, diff --git a/client/components/account-status/account-fees/index.js b/client/components/account-status/account-fees/index.js index 93a93293c11..4b77b39e5f3 100644 --- a/client/components/account-status/account-fees/index.js +++ b/client/components/account-status/account-fees/index.js @@ -10,7 +10,10 @@ import { __ } from '@wordpress/i18n'; */ import ExpirationBar from './expiration-bar'; import ExpirationDescription from './expiration-description'; -import { formatCurrencyName, getCurrency } from 'utils/currency'; +import { + formatCurrencyName, + getCurrency, +} from 'multi-currency/interface/functions'; import { formatAccountFeesDescription, getCurrentBaseFee, diff --git a/client/components/active-loan-summary/index.tsx b/client/components/active-loan-summary/index.tsx index 97aac9ac082..0c5059ef87c 100755 --- a/client/components/active-loan-summary/index.tsx +++ b/client/components/active-loan-summary/index.tsx @@ -18,7 +18,7 @@ import { dateI18n } from '@wordpress/date'; /** * Internal dependencies. */ -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import Loadable from 'components/loadable'; import { useActiveLoanSummary } from 'wcpay/data'; import { getAdminUrl } from 'wcpay/utils'; diff --git a/client/components/deposits-overview/index.tsx b/client/components/deposits-overview/index.tsx index 23ce733bf50..5b89c21a95a 100644 --- a/client/components/deposits-overview/index.tsx +++ b/client/components/deposits-overview/index.tsx @@ -16,7 +16,7 @@ import { getHistory } from '@woocommerce/navigation'; * Internal dependencies. */ import { getAdminUrl } from 'wcpay/utils'; -import { formatExplicitCurrency } from 'wcpay/utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import { recordEvent } from 'tracks'; import Loadable from 'components/loadable'; import { useSelectedCurrencyOverview } from 'wcpay/overview/hooks'; diff --git a/client/components/deposits-overview/recent-deposits-list.tsx b/client/components/deposits-overview/recent-deposits-list.tsx index 1fed2448758..88555793d0d 100644 --- a/client/components/deposits-overview/recent-deposits-list.tsx +++ b/client/components/deposits-overview/recent-deposits-list.tsx @@ -21,7 +21,7 @@ import './style.scss'; import DepositStatusChip from 'components/deposit-status-chip'; import { getDepositDate } from 'deposits/utils'; import { CachedDeposit } from 'wcpay/types/deposits'; -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import { getDetailsURL } from 'wcpay/components/details-link'; interface RecentDepositsProps { diff --git a/client/components/disputed-order-notice/index.js b/client/components/disputed-order-notice/index.js index de5b720715a..ab51a52d16e 100644 --- a/client/components/disputed-order-notice/index.js +++ b/client/components/disputed-order-notice/index.js @@ -8,7 +8,7 @@ import { createInterpolateElement } from '@wordpress/element'; * Internal dependencies */ import InlineNotice from 'wcpay/components/inline-notice'; -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import { reasons } from 'wcpay/disputes/strings'; import { getDetailsURL } from 'wcpay/components/details-link'; import { diff --git a/client/components/payment-activity/payment-data-tile.tsx b/client/components/payment-activity/payment-data-tile.tsx index f9bbfbf7318..7c0d190d79f 100644 --- a/client/components/payment-activity/payment-data-tile.tsx +++ b/client/components/payment-activity/payment-data-tile.tsx @@ -9,7 +9,7 @@ import { recordEvent } from 'wcpay/tracks'; /** * Internal dependencies */ -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import Loadable from '../loadable'; import './style.scss'; diff --git a/client/components/welcome/currency-select.tsx b/client/components/welcome/currency-select.tsx index 7f82c412313..32c1e5a3cd9 100644 --- a/client/components/welcome/currency-select.tsx +++ b/client/components/welcome/currency-select.tsx @@ -8,7 +8,7 @@ import { decodeEntities } from '@wordpress/html-entities'; * Internal dependencies */ import { useSelectedCurrency } from 'overview/hooks'; -import { getCurrency } from 'utils/currency'; +import { getCurrency } from 'multi-currency/interface/functions'; import InlineLabelSelect from '../inline-label-select'; import { recordEvent } from 'tracks'; diff --git a/client/data/deposits/actions.js b/client/data/deposits/actions.js index 392b890657c..60b4479ab24 100644 --- a/client/data/deposits/actions.js +++ b/client/data/deposits/actions.js @@ -6,7 +6,7 @@ import { apiFetch } from '@wordpress/data-controls'; import { dispatch } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; -import { formatCurrency } from 'utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; /** * Internal Dependencies diff --git a/client/data/index.ts b/client/data/index.ts index d20938feb56..878ecdc11f6 100644 --- a/client/data/index.ts +++ b/client/data/index.ts @@ -18,7 +18,6 @@ export * from './charges/hooks'; export * from './timeline/hooks'; export * from './disputes/hooks'; export * from './settings/hooks'; -export * from './multi-currency'; export * from './card-readers/hooks'; export * from './capital/hooks'; export * from './documents/hooks'; diff --git a/client/data/multi-currency/index.js b/client/data/multi-currency/index.js deleted file mode 100644 index c524cca8b05..00000000000 --- a/client/data/multi-currency/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/** @format */ - -/** - * Internal dependencies - */ -import reducer from './reducer'; -import * as selectors from './selectors'; -import * as actions from './actions'; -import * as resolvers from './resolvers'; - -export { reducer, selectors, actions, resolvers }; -export * from './hooks'; diff --git a/client/data/store.js b/client/data/store.js index 974efdb1e07..c4387901c37 100644 --- a/client/data/store.js +++ b/client/data/store.js @@ -14,7 +14,6 @@ import * as charges from './charges'; import * as timeline from './timeline'; import * as disputes from './disputes'; import * as settings from './settings'; -import * as multiCurrency from './multi-currency'; import * as readers from './card-readers'; import * as capital from './capital'; import * as documents from './documents'; @@ -33,7 +32,6 @@ export const initStore = () => timeline: timeline.reducer, disputes: disputes.reducer, settings: settings.reducer, - multiCurrency: multiCurrency.reducer, readers: readers.reducer, capital: capital.reducer, documents: documents.reducer, @@ -49,7 +47,6 @@ export const initStore = () => ...timeline.actions, ...disputes.actions, ...settings.actions, - ...multiCurrency.actions, ...readers.actions, ...capital.actions, ...documents.actions, @@ -66,7 +63,6 @@ export const initStore = () => ...timeline.selectors, ...disputes.selectors, ...settings.selectors, - ...multiCurrency.selectors, ...readers.selectors, ...capital.selectors, ...documents.selectors, @@ -82,7 +78,6 @@ export const initStore = () => ...timeline.resolvers, ...disputes.resolvers, ...settings.resolvers, - ...multiCurrency.resolvers, ...readers.resolvers, ...capital.resolvers, ...documents.resolvers, diff --git a/client/deposits/details/index.tsx b/client/deposits/details/index.tsx index 4d47ae51d6a..74aec3f2a7d 100644 --- a/client/deposits/details/index.tsx +++ b/client/deposits/details/index.tsx @@ -34,7 +34,10 @@ import Page from 'components/page'; import ErrorBoundary from 'components/error-boundary'; import { TestModeNotice } from 'components/test-mode-notice'; import InlineNotice from 'components/inline-notice'; -import { formatCurrency, formatExplicitCurrency } from 'utils/currency'; +import { + formatCurrency, + formatExplicitCurrency, +} from 'multi-currency/interface/functions'; import { displayStatus } from '../strings'; import './style.scss'; diff --git a/client/deposits/filters/index.js b/client/deposits/filters/index.js index 34cc4bbdf52..0d6d57afecc 100644 --- a/client/deposits/filters/index.js +++ b/client/deposits/filters/index.js @@ -8,7 +8,7 @@ import { getQuery } from '@woocommerce/navigation'; * Internal dependencies */ import { filters, advancedFilters } from './config'; -import { formatCurrencyName } from '../../utils/currency'; +import { formatCurrencyName } from 'multi-currency/interface/functions'; export const DepositsFilters = ( props ) => { const populateDepositCurrencies = ( filtersConfiguration ) => { diff --git a/client/deposits/instant-deposits/index.tsx b/client/deposits/instant-deposits/index.tsx index 683aecb03a3..64c49bc069f 100644 --- a/client/deposits/instant-deposits/index.tsx +++ b/client/deposits/instant-deposits/index.tsx @@ -12,7 +12,7 @@ import { useState } from '@wordpress/element'; * Internal dependencies */ import './style.scss'; -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import InstantDepositModal from './modal'; import { useInstantDeposit } from 'wcpay/data'; import type * as AccountOverview from 'wcpay/types/account-overview'; diff --git a/client/deposits/instant-deposits/modal.tsx b/client/deposits/instant-deposits/modal.tsx index 25b2783a348..e9d0f530aeb 100644 --- a/client/deposits/instant-deposits/modal.tsx +++ b/client/deposits/instant-deposits/modal.tsx @@ -11,7 +11,10 @@ import { createInterpolateElement } from '@wordpress/element'; /** * Internal dependencies */ -import { formatCurrency, formatExplicitCurrency } from 'utils/currency'; +import { + formatCurrency, + formatExplicitCurrency, +} from 'multi-currency/interface/functions'; import type * as AccountOverview from 'wcpay/types/account-overview'; import './style.scss'; diff --git a/client/deposits/list/index.tsx b/client/deposits/list/index.tsx index 21c48d2f631..03789c466e1 100644 --- a/client/deposits/list/index.tsx +++ b/client/deposits/list/index.tsx @@ -26,7 +26,10 @@ import { useDispatch } from '@wordpress/data'; import { useDeposits, useDepositsSummary } from 'wcpay/data'; import { useReportingExportLanguage } from 'data/index'; import { displayType, displayStatus } from '../strings'; -import { formatExplicitCurrency, formatExportAmount } from 'utils/currency'; +import { + formatExplicitCurrency, + formatExportAmount, +} from 'multi-currency/interface/functions'; import DetailsLink, { getDetailsURL } from 'components/details-link'; import ClickableCell from 'components/clickable-cell'; import Page from '../../components/page'; diff --git a/client/disputes/filters/index.tsx b/client/disputes/filters/index.tsx index 6e8288f2611..0f6fc09069f 100644 --- a/client/disputes/filters/index.tsx +++ b/client/disputes/filters/index.tsx @@ -9,7 +9,7 @@ import { getQuery } from '@woocommerce/navigation'; * Internal dependencies */ import { filters, advancedFilters, DisputesFilterType } from './config'; -import { formatCurrencyName } from '../../utils/currency'; +import { formatCurrencyName } from 'multi-currency/interface/functions'; interface DisputesFiltersProps { storeCurrencies?: string[]; diff --git a/client/disputes/filters/test/index.tsx b/client/disputes/filters/test/index.tsx index c122ba7eb3a..015f28aec19 100644 --- a/client/disputes/filters/test/index.tsx +++ b/client/disputes/filters/test/index.tsx @@ -12,7 +12,7 @@ import { getQuery, updateQueryString } from '@woocommerce/navigation'; * Internal dependencies */ import { DisputesFilters } from '../'; -import { formatCurrencyName } from '../../../utils/currency'; +import { formatCurrencyName } from 'multi-currency/interface/functions'; // TODO: this is a bit of a hack as we're mocking an old version of WC, we should relook at this. jest.mock( '@woocommerce/settings', () => ( { diff --git a/client/disputes/index.tsx b/client/disputes/index.tsx index 0832ee5515b..060afccce35 100644 --- a/client/disputes/index.tsx +++ b/client/disputes/index.tsx @@ -37,7 +37,10 @@ import Page from 'components/page'; import { TestModeNotice } from 'components/test-mode-notice'; import { reasons } from './strings'; import { formatStringValue } from 'utils'; -import { formatExplicitCurrency, formatExportAmount } from 'utils/currency'; +import { + formatExplicitCurrency, + formatExportAmount, +} from 'multi-currency/interface/functions'; import DisputesFilters from './filters'; import DownloadButton from 'components/download-button'; import disputeStatusMapping from 'components/dispute-status-chip/mappings'; diff --git a/client/disputes/info/index.tsx b/client/disputes/info/index.tsx index 7aa20ca6174..12f7ba0e64a 100644 --- a/client/disputes/info/index.tsx +++ b/client/disputes/info/index.tsx @@ -16,7 +16,7 @@ import OrderLink from 'components/order-link'; import { getDetailsURL } from 'components/details-link'; import { reasons } from '../strings'; import { formatStringValue } from 'utils'; -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import './style.scss'; import Loadable from 'components/loadable'; import { Dispute } from 'wcpay/types/disputes'; diff --git a/client/disputes/utils.ts b/client/disputes/utils.ts index e96251c7863..96a1ca40129 100644 --- a/client/disputes/utils.ts +++ b/client/disputes/utils.ts @@ -18,7 +18,10 @@ import { disputeAwaitingResponseStatuses, disputeUnderReviewStatuses, } from 'wcpay/disputes/filters/config'; -import { formatCurrency, formatExplicitCurrency } from 'wcpay/utils/currency'; +import { + formatCurrency, + formatExplicitCurrency, +} from 'multi-currency/interface/functions'; interface IsDueWithinProps { dueBy: CachedDispute[ 'due_by' ] | EvidenceDetails[ 'due_by' ]; diff --git a/client/index.js b/client/index.js index 12d96efc666..11083acffac 100644 --- a/client/index.js +++ b/client/index.js @@ -23,7 +23,7 @@ import DisputesPage from 'disputes'; import RedirectToTransactionDetails from 'disputes/redirect-to-transaction-details'; import DisputeEvidencePage from 'disputes/evidence'; import AdditionalMethodsPage from 'wcpay/additional-methods-setup'; -import MultiCurrencySetupPage from 'wcpay/multi-currency-setup'; +import { MultiCurrencySetupPage } from 'multi-currency/interface/components'; import CardReadersPage from 'card-readers'; import CapitalPage from 'capital'; import OverviewPage from 'overview'; diff --git a/client/multi-currency-setup/wizard/task-item.scss b/client/multi-currency-setup/wizard/task-item.scss deleted file mode 100644 index 9751a378ab6..00000000000 --- a/client/multi-currency-setup/wizard/task-item.scss +++ /dev/null @@ -1,17 +0,0 @@ -.wcpay-wizard-task { - &__visible-description-element { - position: absolute; - margin-left: 40px; - margin-top: 0; - margin-bottom: 1em; - - &.is-muted-color { - color: $gray-700; - } - - .components-external-link svg { - width: 1em; - height: 1em; - } - } -} diff --git a/client/multi-currency-setup/wizard/task-item.tsx b/client/multi-currency-setup/wizard/task-item.tsx deleted file mode 100644 index 93711e4c80f..00000000000 --- a/client/multi-currency-setup/wizard/task-item.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/** - * External dependencies - */ -import React, { useContext } from 'react'; -import classNames from 'classnames'; -import { Icon, check } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import WizardTaskContext from '../../additional-methods-setup/wizard/task/context'; -import './task-item.scss'; - -interface WizardTaskItemProps { - children: React.ReactNode; - title: string; - index: number; - visibleDescription: string; - className?: string; -} - -const WizardTaskItem: React.FC< WizardTaskItemProps > = ( { - children, - title, - index, - visibleDescription, - className, -} ) => { - const { isCompleted, isActive } = useContext( WizardTaskContext ); - - return ( -
  • -
    -
    -
    -
    - { index } -
    - -
    - { title } -
    - { visibleDescription && ! isActive && ( - - { visibleDescription } - - ) } -
    { children }
    -
  • - ); -}; - -export default WizardTaskItem; diff --git a/client/overview/task-list/tasks/dispute-task.tsx b/client/overview/task-list/tasks/dispute-task.tsx index fdf48c03d78..235b92696b9 100644 --- a/client/overview/task-list/tasks/dispute-task.tsx +++ b/client/overview/task-list/tasks/dispute-task.tsx @@ -11,7 +11,7 @@ import { getHistory } from '@woocommerce/navigation'; */ import type { TaskItemProps } from '../types'; import type { CachedDispute } from 'wcpay/types/disputes'; -import { formatCurrency } from 'wcpay/utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import { getAdminUrl } from 'wcpay/utils'; import { recordEvent } from 'tracks'; import { isDueWithin } from 'wcpay/disputes/utils'; diff --git a/client/payment-details/dispute-details/dispute-steps.tsx b/client/payment-details/dispute-details/dispute-steps.tsx index ccc0764f38b..01f87431274 100644 --- a/client/payment-details/dispute-details/dispute-steps.tsx +++ b/client/payment-details/dispute-details/dispute-steps.tsx @@ -16,7 +16,7 @@ import HelpOutlineIcon from 'gridicons/dist/help-outline'; */ import type { Dispute } from 'wcpay/types/disputes'; import { ChargeBillingDetails } from 'wcpay/types/charges'; -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import { ClickTooltip } from 'wcpay/components/tooltip'; import { getDisputeFeeFormatted } from 'wcpay/disputes/utils'; import DisputeDueByDate from './dispute-due-by-date'; diff --git a/client/payment-details/dispute-details/dispute-summary-row.tsx b/client/payment-details/dispute-details/dispute-summary-row.tsx index ac6dada265e..0a43cb223e0 100644 --- a/client/payment-details/dispute-details/dispute-summary-row.tsx +++ b/client/payment-details/dispute-details/dispute-summary-row.tsx @@ -14,7 +14,7 @@ import { dateI18n } from '@wordpress/date'; */ import type { Dispute } from 'wcpay/types/disputes'; import { HorizontalList } from 'wcpay/components/horizontal-list'; -import { formatExplicitCurrency } from 'wcpay/utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import { reasons } from 'wcpay/disputes/strings'; import { formatStringValue } from 'wcpay/utils'; import { ClickTooltip } from 'wcpay/components/tooltip'; diff --git a/client/payment-details/readers/index.js b/client/payment-details/readers/index.js index 9ff428c94fe..193ee236288 100644 --- a/client/payment-details/readers/index.js +++ b/client/payment-details/readers/index.js @@ -19,7 +19,10 @@ import { useCardReaderStats } from 'wcpay/data'; import { TestModeNotice } from 'components/test-mode-notice'; import Page from 'components/page'; import DownloadButton from 'components/download-button'; -import { formatExplicitCurrency, formatExportAmount } from 'utils/currency'; +import { + formatExplicitCurrency, + formatExportAmount, +} from 'multi-currency/interface/functions'; const PaymentCardReaderChargeDetails = ( props ) => { const { readers, chargeError, isLoading } = useCardReaderStats( diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx index 4350d609cd7..4e9d9559a4b 100644 --- a/client/payment-details/summary/index.tsx +++ b/client/payment-details/summary/index.tsx @@ -37,7 +37,10 @@ import { HorizontalList, HorizontalListItem } from 'components/horizontal-list'; import Loadable, { LoadableBlock } from 'components/loadable'; import riskMappings from 'components/risk-level/strings'; import OrderLink from 'components/order-link'; -import { formatCurrency, formatExplicitCurrency } from 'utils/currency'; +import { + formatCurrency, + formatExplicitCurrency, +} from 'multi-currency/interface/functions'; import CustomerLink from 'components/customer-link'; import { ClickTooltip } from 'components/tooltip'; import DisputeStatusChip from 'components/dispute-status-chip'; diff --git a/client/payment-details/timeline/map-events.js b/client/payment-details/timeline/map-events.js index 1cb14d6aa7a..64bc74d91d2 100644 --- a/client/payment-details/timeline/map-events.js +++ b/client/payment-details/timeline/map-events.js @@ -26,7 +26,7 @@ import { formatCurrency, formatFX, formatExplicitCurrency, -} from 'utils/currency'; +} from 'multi-currency/interface/functions'; import { formatFee } from 'utils/fees'; import { getAdminUrl } from 'wcpay/utils'; import { ShieldIcon } from 'wcpay/icons'; diff --git a/client/settings/fraud-protection/advanced-settings/cards/purchase-price-threshold.tsx b/client/settings/fraud-protection/advanced-settings/cards/purchase-price-threshold.tsx index e32b2222d2e..828d1bbf5c8 100644 --- a/client/settings/fraud-protection/advanced-settings/cards/purchase-price-threshold.tsx +++ b/client/settings/fraud-protection/advanced-settings/cards/purchase-price-threshold.tsx @@ -8,7 +8,7 @@ import AmountInput from 'wcpay/components/amount-input'; /** * Internal dependencies */ -import { getCurrency } from 'utils/currency'; +import { getCurrency } from 'multi-currency/interface/functions'; import FraudProtectionRuleCard from '../rule-card'; import FraudProtectionRuleToggle from '../rule-toggle'; import FraudProtectionRuleDescription from '../rule-description'; diff --git a/client/settings/fraud-protection/test/index.test.tsx b/client/settings/fraud-protection/test/index.test.tsx index 0719a904c78..1b78011aad4 100644 --- a/client/settings/fraud-protection/test/index.test.tsx +++ b/client/settings/fraud-protection/test/index.test.tsx @@ -11,7 +11,6 @@ import { useDispatch } from '@wordpress/data'; import FraudProtection from '..'; import { useCurrentProtectionLevel, - useCurrencies, useAdvancedFraudProtectionSettings, useSettings, } from 'wcpay/data'; @@ -29,7 +28,6 @@ jest.mock( 'wcpay/data', () => ( { useAdvancedFraudProtectionSettings: jest.fn(), useCurrentProtectionLevel: jest.fn(), useSettings: jest.fn(), - useCurrencies: jest.fn(), } ) ); jest.mock( '@wordpress/data', () => ( { @@ -44,10 +42,6 @@ const mockUseCurrentProtectionLevel = useCurrentProtectionLevel as jest.MockedFu () => [ string, ( level: string ) => void ] >; -const mockUseCurrencies = useCurrencies as jest.MockedFunction< - () => { currencies: Record< string, any >; isLoading: boolean } ->; - const mockUseAdvancedFraudProtectionSettings = useAdvancedFraudProtectionSettings as jest.MockedFunction< () => [ any[] | string, ( settings: string ) => void ] >; @@ -70,16 +64,6 @@ describe( 'FraudProtection', () => { 'standard', jest.fn(), ] ); - mockUseCurrencies.mockReturnValue( { - isLoading: false, - currencies: { - available: { - EUR: { name: 'Euro', symbol: '€' }, - USD: { name: 'US Dollar', symbol: '$' }, - PLN: { name: 'Polish złoty', symbol: 'zł' }, - }, - }, - } ); mockUseAdvancedFraudProtectionSettings.mockReturnValue( [ [], diff --git a/client/settings/payment-methods-list/index.js b/client/settings/payment-methods-list/index.js index 99a34b40daf..997c2bb9874 100644 --- a/client/settings/payment-methods-list/index.js +++ b/client/settings/payment-methods-list/index.js @@ -22,7 +22,7 @@ import { upeCapabilityStatuses } from 'wcpay/additional-methods-setup/constants' import ConfirmPaymentMethodActivationModal from './activation-modal'; import ConfirmPaymentMethodDeleteModal from './delete-modal'; import CapabilityRequestNotice from './capability-request'; -import { getMissingCurrenciesTooltipMessage } from 'wcpay/multi-currency/missing-currencies-message'; +import { getMissingCurrenciesTooltipMessage } from 'multi-currency/interface/functions'; const PaymentMethodsList = ( { methodIds } ) => { const [ enabledMethodIds ] = useEnabledPaymentMethodIds(); diff --git a/client/settings/payment-methods-section/__tests__/payment-methods-section.test.js b/client/settings/payment-methods-section/__tests__/payment-methods-section.test.js index 2e1f1da1538..d64f2ded639 100644 --- a/client/settings/payment-methods-section/__tests__/payment-methods-section.test.js +++ b/client/settings/payment-methods-section/__tests__/payment-methods-section.test.js @@ -35,8 +35,6 @@ jest.mock( '@woocommerce/components', () => { jest.mock( 'wcpay/data', () => ( { useEnabledPaymentMethodIds: jest.fn(), useGetAvailablePaymentMethodIds: jest.fn(), - useCurrencies: jest.fn().mockReturnValue( { isLoading: true } ), - useEnabledCurrencies: jest.fn().mockReturnValue( {} ), useGetPaymentMethodStatuses: jest.fn().mockReturnValue( {} ), useManualCapture: jest.fn(), useSelectedPaymentMethod: jest.fn(), @@ -45,6 +43,16 @@ jest.mock( 'wcpay/data', () => ( { useSettings: jest.fn().mockReturnValue( { isLoading: false } ), } ) ); +jest.mock( 'multi-currency/interface/data', () => ( { + useCurrencies: jest.fn().mockReturnValue( { isLoading: true } ), + useEnabledCurrencies: jest.fn().mockReturnValue( {} ), +} ) ); + +jest.mock( 'multi-currency/interface/data', () => ( { + useCurrencies: jest.fn().mockReturnValue( { isLoading: true } ), + useEnabledCurrencies: jest.fn().mockReturnValue( {} ), +} ) ); + jest.mock( '@wordpress/data', () => ( { useDispatch: jest .fn() diff --git a/client/transactions/blocked/columns.tsx b/client/transactions/blocked/columns.tsx index 3ecf1554d06..1d75e407cea 100644 --- a/client/transactions/blocked/columns.tsx +++ b/client/transactions/blocked/columns.tsx @@ -10,7 +10,7 @@ import { TableCardColumn, TableCardBodyColumn } from '@woocommerce/components'; /** * Internal dependencies */ -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import TransactionStatusPill from 'wcpay/components/transaction-status-pill'; import { FraudOutcomeTransaction } from '../../data'; import { getDetailsURL } from '../../components/details-link'; diff --git a/client/transactions/blocked/index.tsx b/client/transactions/blocked/index.tsx index e1bdce63664..f6153231f69 100644 --- a/client/transactions/blocked/index.tsx +++ b/client/transactions/blocked/index.tsx @@ -34,7 +34,7 @@ import { getBlockedListColumns, getBlockedListColumnsStructure, } from './columns'; -import { formatExplicitCurrency } from '../../utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import autocompleter from '../fraud-protection/autocompleter'; import DownloadButton from '../../components/download-button'; import { getFraudOutcomeTransactionsExport } from '../../data/transactions/resolvers'; diff --git a/client/transactions/filters/index.tsx b/client/transactions/filters/index.tsx index cbb729ce5d9..ef8c11d4f15 100644 --- a/client/transactions/filters/index.tsx +++ b/client/transactions/filters/index.tsx @@ -9,7 +9,7 @@ import { getQuery } from '@woocommerce/navigation'; * Internal dependencies */ import { getFilters, getAdvancedFilters } from './config'; -import { formatCurrencyName } from '../../utils/currency'; +import { formatCurrencyName } from 'multi-currency/interface/functions'; import { recordEvent } from 'tracks'; interface TransactionsFiltersProps { diff --git a/client/transactions/list/converted-amount.tsx b/client/transactions/list/converted-amount.tsx index 6a74b01a25a..fac4d9acd25 100644 --- a/client/transactions/list/converted-amount.tsx +++ b/client/transactions/list/converted-amount.tsx @@ -12,7 +12,7 @@ import classNames from 'classnames'; /** * Internal dependencies */ -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; declare const window: any; diff --git a/client/transactions/list/index.tsx b/client/transactions/list/index.tsx index 3893df6658a..e123d0319f5 100644 --- a/client/transactions/list/index.tsx +++ b/client/transactions/list/index.tsx @@ -54,7 +54,7 @@ import { formatCurrency, formatExplicitCurrency, formatExportAmount, -} from 'utils/currency'; +} from 'multi-currency/interface/functions'; import { getChargeChannel } from 'utils/charge'; import Deposit from './deposit'; import ConvertedAmount from './converted-amount'; diff --git a/client/transactions/risk-review/columns.tsx b/client/transactions/risk-review/columns.tsx index 59db13c52c8..d7f5de95111 100644 --- a/client/transactions/risk-review/columns.tsx +++ b/client/transactions/risk-review/columns.tsx @@ -13,7 +13,7 @@ import { Button } from '@wordpress/components'; */ import { getDetailsURL } from 'components/details-link'; import ClickableCell from 'components/clickable-cell'; -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import { recordEvent } from 'tracks'; import TransactionStatusPill from 'wcpay/components/transaction-status-pill'; import { FraudOutcomeTransaction } from '../../data'; diff --git a/client/transactions/risk-review/index.tsx b/client/transactions/risk-review/index.tsx index 0681110d678..f83010dc1e8 100644 --- a/client/transactions/risk-review/index.tsx +++ b/client/transactions/risk-review/index.tsx @@ -35,7 +35,7 @@ import { getRiskReviewListColumnsStructure, } from './columns'; import './style.scss'; -import { formatExplicitCurrency } from '../../utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import autocompleter from '../fraud-protection/autocompleter'; import DownloadButton from '../../components/download-button'; import { getFraudOutcomeTransactionsExport } from '../../data/transactions/resolvers'; diff --git a/client/transactions/uncaptured/index.tsx b/client/transactions/uncaptured/index.tsx index 3cf14c956f7..17058760c19 100644 --- a/client/transactions/uncaptured/index.tsx +++ b/client/transactions/uncaptured/index.tsx @@ -17,7 +17,7 @@ import { useAuthorizations, useAuthorizationsSummary } from 'data/index'; import Page from '../../components/page'; import { getDetailsURL } from 'components/details-link'; import ClickableCell from 'components/clickable-cell'; -import { formatExplicitCurrency } from 'utils/currency'; +import { formatExplicitCurrency } from 'multi-currency/interface/functions'; import RiskLevel, { calculateRiskMapping } from 'components/risk-level'; import { recordEvent } from 'tracks'; import CaptureAuthorizationButton from 'wcpay/components/capture-authorization-button'; diff --git a/client/utils/account-fees.tsx b/client/utils/account-fees.tsx index b3d0f5b9f2c..711d3d337ed 100644 --- a/client/utils/account-fees.tsx +++ b/client/utils/account-fees.tsx @@ -1,7 +1,7 @@ /** @format */ /** - * External depencencies + * External dependencies */ import { __, sprintf } from '@wordpress/i18n'; import interpolateComponents from '@automattic/interpolate-components'; @@ -10,7 +10,7 @@ import './account-fees.scss'; /** * Internal dependencies */ -import { formatCurrency } from 'utils/currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import { formatFee } from 'utils/fees'; import React from 'react'; import { BaseFee, DiscountFee, FeeStructure } from 'wcpay/types/fees'; diff --git a/client/utils/test/account-fees.tsx b/client/utils/test/account-fees.tsx index c1b181ac160..3184e42d644 100644 --- a/client/utils/test/account-fees.tsx +++ b/client/utils/test/account-fees.tsx @@ -14,10 +14,10 @@ import { formatMethodFeesTooltip, getCurrentBaseFee, } from '../account-fees'; -import { formatCurrency } from '../currency'; +import { formatCurrency } from 'multi-currency/interface/functions'; import { BaseFee, DiscountFee, FeeStructure } from 'wcpay/types/fees'; -jest.mock( '../currency', () => ( { +jest.mock( 'multi-currency/interface/functions', () => ( { formatCurrency: jest.fn( ( amount: number ): string => { return sprintf( '$%.2f', amount / 100 ); } ), diff --git a/client/vat/form/tasks/company-data-task.tsx b/client/vat/form/tasks/company-data-task.tsx index d2cac07cc67..76c91b7e9ed 100644 --- a/client/vat/form/tasks/company-data-task.tsx +++ b/client/vat/form/tasks/company-data-task.tsx @@ -11,14 +11,14 @@ import { } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import React, { useContext, useEffect, useState } from 'react'; -import CollapsibleBody from 'wcpay/additional-methods-setup/wizard/collapsible-body'; -import WizardTaskItem from 'wcpay/additional-methods-setup/wizard/task-item'; -import WizardTaskContext from 'wcpay/additional-methods-setup/wizard/task/context'; import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ +import CollapsibleBody from 'wcpay/additional-methods-setup/wizard/collapsible-body'; +import WizardTaskItem from 'wcpay/additional-methods-setup/wizard/task-item'; +import WizardTaskContext from 'wcpay/additional-methods-setup/wizard/task/context'; import { VatError, VatFormOnCompleted, diff --git a/client/vat/form/tasks/vat-number-task.tsx b/client/vat/form/tasks/vat-number-task.tsx index 611e214318d..7fad346de00 100644 --- a/client/vat/form/tasks/vat-number-task.tsx +++ b/client/vat/form/tasks/vat-number-task.tsx @@ -11,14 +11,14 @@ import { } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import React, { useContext, useState } from 'react'; -import CollapsibleBody from 'wcpay/additional-methods-setup/wizard/collapsible-body'; -import WizardTaskItem from 'wcpay/additional-methods-setup/wizard/task-item'; -import WizardTaskContext from 'wcpay/additional-methods-setup/wizard/task/context'; import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ +import CollapsibleBody from 'wcpay/additional-methods-setup/wizard/collapsible-body'; +import WizardTaskItem from 'wcpay/additional-methods-setup/wizard/task-item'; +import WizardTaskContext from 'wcpay/additional-methods-setup/wizard/task/context'; import { VatError, VatFormOnCompleted, VatValidationResult } from '../../types'; import '../style.scss'; diff --git a/composer.json b/composer.json index cdb679b4afb..497530e36e1 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ }, "autoload": { "psr-4": { - "WCPay\\MultiCurrency\\": "includes/multi-currency", + "WCPay\\MultiCurrency\\": "multi-currency/src", "WCPay\\Vendor\\": "lib/packages", "WCPay\\": "src" }, diff --git a/includes/class-database-cache.php b/includes/class-database-cache.php index 68b4c7d4d89..042d99f7f9e 100644 --- a/includes/class-database-cache.php +++ b/includes/class-database-cache.php @@ -7,16 +7,17 @@ namespace WCPay; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyCacheInterface; + defined( 'ABSPATH' ) || exit; // block direct access. /** * A class for caching data as an option in the database. */ -class Database_Cache { +class Database_Cache implements MultiCurrencyCacheInterface { const ACCOUNT_KEY = 'wcpay_account_data'; const ONBOARDING_FIELDS_DATA_KEY = 'wcpay_onboarding_fields_data'; const BUSINESS_TYPES_KEY = 'wcpay_business_types_data'; - const CURRENCIES_KEY = 'wcpay_multi_currency_cached_currencies'; const PAYMENT_PROCESS_FACTORS_KEY = 'wcpay_payment_process_factors'; const FRAUD_SERVICES_KEY = 'wcpay_fraud_services_data'; diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index f50acfc5b35..93fab3929d7 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -17,11 +17,12 @@ use WCPay\Exceptions\API_Exception; use WCPay\Logger; use WCPay\Database_Cache; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; /** * Class handling any account connection functionality */ -class WC_Payments_Account { +class WC_Payments_Account implements MultiCurrencyAccountInterface { // ACCOUNT_OPTION is only used in the supporting dev tools plugin, it can be removed once everyone has upgraded. const ACCOUNT_OPTION = 'wcpay_account_data'; @@ -171,6 +172,18 @@ public function get_publishable_key( $is_test ) { return $account['live_publishable_key']; } + /** + * Checks if the account is connected to the payment provider. + * Note: This method is a proxy for `is_stripe_connected` for the MultiCurrencyAccountInterface. + * + * @param bool $on_error Value to return on server error, defaults to false. + * + * @return bool True if the account is connected, false otherwise, $on_error on error. + */ + public function is_provider_connected( bool $on_error = false ): bool { + return $this->is_stripe_connected( $on_error ); + } + /** * Determine if the store has a working Jetpack connection. * @@ -636,11 +649,22 @@ public function get_account_email(): string { * * @return array Currencies. */ - public function get_account_customer_supported_currencies() { + public function get_account_customer_supported_currencies(): array { $account = $this->get_cached_account_data(); return ! empty( $account ) && isset( $account['customer_currencies']['supported'] ) ? $account['customer_currencies']['supported'] : []; } + /** + * List of countries enabled for Stripe platform account. See also this URL: + * https://woocommerce.com/document/woopayments/compatibility/countries/#supported-countries + * + * @return array + */ + public function get_supported_countries(): array { + // This is a wrapper function because of the MultiCurrencyAccountInterface. + return WC_Payments_Utils::supported_countries(); + } + /** * Gets the account live mode value. * @@ -1628,6 +1652,21 @@ private function get_login_url() { ); } + /** + * Get provider onboarding page url. + * + * @return string + */ + public function get_provider_onboarding_page_url(): string { + return add_query_arg( + [ + 'page' => 'wc-admin', + 'path' => '/payments/connect', + ], + admin_url( 'admin.php' ) + ); + } + /** * Get connect url. * @@ -1669,21 +1708,6 @@ public static function get_payments_task_page_url() { ); } - /** - * Get Connect page url. - * - * @return string - */ - public static function get_connect_page_url(): string { - return add_query_arg( - [ - 'page' => 'wc-admin', - 'path' => '/payments/connect', - ], - admin_url( 'admin.php' ) - ); - } - /** * Get overview page url * diff --git a/includes/class-wc-payments-explicit-price-formatter.php b/includes/class-wc-payments-explicit-price-formatter.php index d96bfa4f25f..31c5364cfbe 100644 --- a/includes/class-wc-payments-explicit-price-formatter.php +++ b/includes/class-wc-payments-explicit-price-formatter.php @@ -6,7 +6,6 @@ */ use WCPay\MultiCurrency\MultiCurrency; -use WCPay\Logger; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. diff --git a/includes/class-wc-payments-localization-service.php b/includes/class-wc-payments-localization-service.php index 5ea9375429d..c0c0d7d84f8 100644 --- a/includes/class-wc-payments-localization-service.php +++ b/includes/class-wc-payments-localization-service.php @@ -5,12 +5,14 @@ * @package WooCommerce\Payments */ +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; + defined( 'ABSPATH' ) || exit; /** * WC_Payments_Localization_Service. */ -class WC_Payments_Localization_Service { +class WC_Payments_Localization_Service implements MultiCurrencyLocalizationInterface { const WCPAY_CURRENCY_FORMAT_TRANSIENT = 'wcpay_currency_format'; const WCPAY_LOCALE_INFO_TRANSIENT = 'wcpay_locale_info'; diff --git a/includes/class-wc-payments-settings-service.php b/includes/class-wc-payments-settings-service.php new file mode 100644 index 00000000000..5da12e8a897 --- /dev/null +++ b/includes/class-wc-payments-settings-service.php @@ -0,0 +1,42 @@ +is_dev(); + } + + /** + * Gets the plugin file path. + * + * @return string + */ + public function get_plugin_file_path(): string { + return WCPAY_PLUGIN_FILE; + } + + /** + * Gets the plugin version. + * + * @return string + */ + public function get_plugin_version(): string { + return WCPAY_VERSION_NUMBER; + } +} diff --git a/includes/class-wc-payments-utils.php b/includes/class-wc-payments-utils.php index 755901e15ca..0b2506d73b6 100644 --- a/includes/class-wc-payments-utils.php +++ b/includes/class-wc-payments-utils.php @@ -1270,24 +1270,6 @@ public static function is_store_api_request(): bool { return false; } - /** - * Returns true if the request that's currently being processed is a Store API batch request, false - * otherwise. - * - * @return bool True if the request is a Store API batch request, false otherwise. - */ - public static function is_store_batch_request(): bool { - if ( isset( $_REQUEST['rest_route'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification - $rest_route = sanitize_text_field( $_REQUEST['rest_route'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.NonceVerification - } else { - $url_parts = wp_parse_url( esc_url_raw( $_SERVER['REQUEST_URI'] ?? '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash - $request_path = $url_parts ? rtrim( $url_parts['path'], '/' ) : ''; - $rest_route = str_replace( trailingslashit( rest_get_url_prefix() ), '', $request_path ); - } - - return 1 === preg_match( '@^\/wc\/store(\/v[\d]+)?\/batch@', $rest_route ); - } - /** * Gets the current active theme transient for a given location * Falls back to 'stripe' if no transients are set. diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index 42923e906d5..7897a3c7752 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -42,6 +42,7 @@ use WCPay\WooPay\WooPay_Session; use WCPay\Compatibility_Service; use WCPay\Duplicates_Detection_Service; +use WCPay\WC_Payments_Currency_Manager; /** * Main class for the WooPayments extension. Its responsibility is to initialize the extension. @@ -124,6 +125,13 @@ class WC_Payments { */ private static $localization_service; + /** + * Instance of WC_Payments_Settings_Service, created in init function + * + * @var WC_Payments_Settings_Service + */ + private static $settings_service; + /** * Instance of WC_Payments_Dependency_Service, created in init function * @@ -299,6 +307,13 @@ class WC_Payments { */ private static $duplicates_detection_service; + /** + * Instance of WC_Payments_Currency_Manager, created in init function + * + * @var WC_Payments_Currency_Manager + */ + private static $currency_manager; + /** * Entry point to the initialization logic. */ @@ -468,6 +483,7 @@ public static function init() { include_once __DIR__ . '/class-wc-payments-onboarding-service.php'; include_once __DIR__ . '/class-experimental-abtest.php'; include_once __DIR__ . '/class-wc-payments-localization-service.php'; + include_once __DIR__ . '/class-wc-payments-settings-service.php'; include_once __DIR__ . '/in-person-payments/class-wc-payments-in-person-payments-receipts-service.php'; include_once __DIR__ . '/class-wc-payments-order-service.php'; include_once __DIR__ . '/class-wc-payments-order-success-page.php'; @@ -489,7 +505,8 @@ public static function init() { include_once __DIR__ . '/class-duplicate-payment-prevention-service.php'; include_once __DIR__ . '/class-wc-payments-incentives-service.php'; include_once __DIR__ . '/class-compatibility-service.php'; - include_once __DIR__ . '/multi-currency/wc-payments-multi-currency.php'; + include_once __DIR__ . '/compat/multi-currency/wc-payments-multi-currency.php'; + include_once __DIR__ . '/compat/multi-currency/class-wc-payments-currency-manager.php'; include_once __DIR__ . '/class-duplicates-detection-service.php'; self::$woopay_checkout_service = new Checkout_Service(); @@ -520,6 +537,7 @@ public static function init() { self::$fraud_service = new WC_Payments_Fraud_Service( self::$api_client, self::$customer_service, self::$account, self::$session_service, self::$database_cache ); self::$in_person_payments_receipts_service = new WC_Payments_In_Person_Payments_Receipts_Service(); self::$localization_service = new WC_Payments_Localization_Service(); + self::$settings_service = new WC_Payments_Settings_Service(); self::$failed_transaction_rate_limiter = new Session_Rate_Limiter( Session_Rate_Limiter::SESSION_KEY_DECLINED_CARD_REGISTRY, 5, 10 * MINUTE_IN_SECONDS ); self::$order_success_page = new WC_Payments_Order_Success_Page(); self::$woopay_util = new WooPay_Utilities(); @@ -582,6 +600,9 @@ public static function init() { self::$customer_service_api = new WC_Payments_Customer_Service_API( self::$customer_service ); + self::$currency_manager = new WC_Payments_Currency_Manager( self::get_gateway() ); + self::$currency_manager->init_hooks(); + // Only register hooks of the new `src` service with the same feature of Duplicate_Payment_Prevention_Service. // To avoid register the same hooks twice. wcpay_get_container()->get( \WCPay\Internal\Service\DuplicatePaymentPreventionService::class )->init_hooks(); @@ -1323,6 +1344,15 @@ public static function get_localization_service() { return self::$localization_service; } + /** + * Returns the WC_Payments_Settings_Service + * + * @return WC_Payments_Settings_Service Localization Service instance + */ + public static function get_settings_service() { + return self::$settings_service; + } + /** * Returns the WC_Payments_Action_Scheduler_Service * diff --git a/includes/multi-currency/PaymentMethodsCompatibility.php b/includes/compat/multi-currency/class-wc-payments-currency-manager.php similarity index 69% rename from includes/multi-currency/PaymentMethodsCompatibility.php rename to includes/compat/multi-currency/class-wc-payments-currency-manager.php index 0c5f7d4b736..c00da0d1a69 100644 --- a/includes/multi-currency/PaymentMethodsCompatibility.php +++ b/includes/compat/multi-currency/class-wc-payments-currency-manager.php @@ -1,29 +1,21 @@ multi_currency = $multi_currency; - $this->gateway = $gateway; + public function __construct( WC_Payment_Gateway_WCPay $gateway ) { + $this->gateway = $gateway; } /** @@ -48,17 +38,32 @@ public function __construct( MultiCurrency $multi_currency, WC_Payment_Gateway_W * @return void */ public function init_hooks() { - add_action( - 'update_option_woocommerce_woocommerce_payments_settings', - [ $this, 'add_missing_currencies' ] - ); + add_action( 'update_option_woocommerce_woocommerce_payments_settings', [ $this, 'maybe_add_missing_currencies' ] ); add_action( 'admin_head', [ $this, 'add_payment_method_currency_dependencies_script' ] ); } + /** + * Gets the multi-currency instance or returns null if it's not available. + * This method allows for easier testing by allowing the multi-currency instance to be mocked. + * + * @return \WCPay\MultiCurrency\MultiCurrency|null + */ + public function get_multi_currency_instance() { + if ( ! function_exists( 'WC_Payments_Multi_Currency' ) ) { + return null; + } + + if ( ! WC_Payments_Multi_Currency()->is_initialized() ) { + return null; + } + + return WC_Payments_Multi_Currency(); + } + /** * Returns the currencies needed per enabled payment method * - * @return array The currencies keyed with the related payment method + * @return array The currencies keyed with the related payment method */ public function get_enabled_payment_method_currencies() { $enabled_payment_method_ids = $this->gateway->get_upe_enabled_payment_method_ids(); @@ -97,14 +102,19 @@ function ( $result, $method ) use ( $account_currency ) { /** * Ensures that when a payment method is added from the settings, the needed currency is also added. */ - public function add_missing_currencies() { + public function maybe_add_missing_currencies() { + $multi_currency = $this->get_multi_currency_instance(); + if ( is_null( $multi_currency ) ) { + return; + } + $payment_methods_needing_currency = $this->get_enabled_payment_method_currencies(); if ( empty( $payment_methods_needing_currency ) ) { return; } - $enabled_currencies = $this->multi_currency->get_enabled_currencies(); - $available_currencies = $this->multi_currency->get_available_currencies(); + $enabled_currencies = $multi_currency->get_enabled_currencies(); + $available_currencies = $multi_currency->get_available_currencies(); $missing_currency_codes = []; @@ -137,15 +147,21 @@ public function add_missing_currencies() { * The set_enabled_currencies method throws an exception if any currencies passed are not found in the current available currencies. * Any currencies not found are filtered out above, so we shouldn't need a try/catch here. */ - $this->multi_currency->set_enabled_currencies( array_merge( array_keys( $enabled_currencies ), $missing_currency_codes ) ); + $multi_currency->set_enabled_currencies( array_merge( array_keys( $enabled_currencies ), $missing_currency_codes ) ); } /** - * Adds the notices for currencies that are bound to an UPE payment method. + * Adds the `multiCurrencyPaymentMethodsMap` JS object to the multi-currency settings page. * - * @return void + * This object maps currencies to payment methods that require them, so the multi-currency settings page displays a notice in case of dependencies. */ public function add_payment_method_currency_dependencies_script() { + $multi_currency = $this->get_multi_currency_instance(); + + if ( is_null( $multi_currency ) || ! $multi_currency->is_multi_currency_settings_page() ) { + return; + } + $payment_methods_needing_currency = $this->get_enabled_payment_method_currencies(); if ( empty( $payment_methods_needing_currency ) ) { return; @@ -161,11 +177,10 @@ public function add_payment_method_currency_dependencies_script() { } } - if ( WC_Payments_Multi_Currency()->is_multi_currency_settings_page() ) : ?> + ?> - init_hooks(); + } + + return $instance; } add_action( 'plugins_loaded', 'WC_Payments_Multi_Currency', 12 ); diff --git a/includes/multi-currency/CountryFlags.php b/includes/multi-currency/CountryFlags.php deleted file mode 100644 index e841095255e..00000000000 --- a/includes/multi-currency/CountryFlags.php +++ /dev/null @@ -1,304 +0,0 @@ - '🇦🇩', - 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 => '🇿🇼', - ]; - - /** - * Retrieves a flag by country code. - * - * @param string $country country alpha-2 code (ISO 3166) like US. - * @return string - */ - public static function get_by_country( string $country ): string { - return self::EMOJI_COUNTRIES_FLAGS[ $country ] ?? ''; - } - - /** - * Retrieves a flag by currency code. - * - * @param string $currency currency code (ISO 4217) like USD. - * @return string - */ - public static function get_by_currency( string $currency ): string { - $exceptions = [ - Currency_Code::NETHERLANDS_ANTILLEAN_GUILDER => '', - Currency_Code::BITCOIN => '', - Currency_Code::CENTRAL_AFRICAN_CFA_FRANC => '', - Currency_Code::EAST_CARIBBEAN_DOLLAR => '', - Currency_Code::WEST_AFRICAN_CFA_FRANC => '', - Currency_Code::CFP_FRANC => '', - ]; - - $flag = $exceptions[ $currency ] ?? self::get_by_country( substr( $currency, 0, -1 ) ); - - return $flag; - } -} diff --git a/includes/multi-currency/Helpers/OrderMetaHelper.md b/includes/multi-currency/Helpers/OrderMetaHelper.md deleted file mode 100644 index 84e7a0ff5c7..00000000000 --- a/includes/multi-currency/Helpers/OrderMetaHelper.md +++ /dev/null @@ -1,20 +0,0 @@ -## Order Meta Helper - -The purpose of this helper is to allow merchants to fix or update the Multi-Currency exchange rates on orders if/when they are incorrect. - -### Usage - -* Go to WooCommerce > Status > Tools -* Find the _Enable/Disable Multi-Currency Meta Helper_ option and click the button. You should then receive a notice that the tool was enabled. -* Go to the order that has an issue with the Multi-Currency exchange rate. -* A new meta box named _Multi-Currency Meta Helper_ will appear in the main column near the bottom. - * This will only show for orders where the currency does not match the store currency. An example would be if the store currency is USD and the order currency is EUR. -* There will be information displayed about the order in the meta box. - * If either the Multi-Currency or Stripe exchange rate are not found, they will display _Not Found_. - * If the order is through WooPayments, and if a charge is found, then there will be a _Charge Exchange Rate_ shown. If the _Charge Exchange Rate_ is found, it will also display as a _Suggested Exchange Rate_. -* Enter the new exchange rate to be used into the field, and then click the _Update_ button for the order. -* A new order note will appear stating that the Multi-Currency exchange rate has been updated. - -### Additional Note - -This tool is for edge cases where this data may be missing, which can cause issues with Analytics reporting. Once the exchange rate is updated, the _Import historical data_ tool under Analytics > Settings will need to be run. This will correct data related to any orders that have been adjusted. diff --git a/includes/multi-currency/Helpers/OrderMetaHelper.php b/includes/multi-currency/Helpers/OrderMetaHelper.php deleted file mode 100644 index 208fefc2c26..00000000000 --- a/includes/multi-currency/Helpers/OrderMetaHelper.php +++ /dev/null @@ -1,438 +0,0 @@ -payments_api_client = $payments_api_client; - } - - /** - * Initializes this class' WP hooks. - * - * @return void - */ - public function init_hooks() { - add_action( 'add_meta_boxes', [ $this, 'maybe_add_meta_box' ], 10, 2 ); - add_action( 'save_post', [ $this, 'maybe_update_exchange_rate' ] ); - add_action( 'admin_notices', [ $this, 'maybe_output_errors' ] ); - add_filter( 'get_edit_post_link', [ $this, 'maybe_update_edit_post_link' ] ); - } - - /** - * Outputs and then clears our errors if there are any. - * - * @return void - */ - public function maybe_output_errors() { - if ( $this->has_errors() ) { - foreach ( $this->errors as $error ) { - - ?> -
    -

    Error:

    -
    - clear_errors(); - } - } - - /** - * Updates the exchange rate meta data. - * - * @param int $order_id The order we are working with. - * - * @return void - */ - public function maybe_update_exchange_rate( $order_id ) { - // Verify nonce. - $nonce_value = ! empty( $_POST['wcpay_multi_currency_exchange_rate_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['wcpay_multi_currency_exchange_rate_nonce'] ) ) : false; - if ( false === $nonce_value || ! wp_verify_nonce( $nonce_value, 'wcpay_multi_currency_exchange_rate_nonce_' . $order_id ) || ! current_user_can( 'manage_woocommerce' ) ) { - return; - } - - // Confirm our order is valid, should be worked on, and that a new exchange rate has been passed. - $order = $this->confirm_actions( $order_id ); - if ( ! $order || empty( $_POST['wcpay_multi_currency_exchange_rate'] ) ) { - return; - } - - // Clean the data, confirm the rate is a number, and if it isn't, add error and exit. - $new_exchange_rate = sanitize_text_field( wp_unslash( $_POST['wcpay_multi_currency_exchange_rate'] ) ); - if ( ! is_numeric( $new_exchange_rate ) ) { - $this->add_error( 'Exchange rate value not numeric: ' . $new_exchange_rate ); - return; - } - - // Add the exchange rates to the log. - $old_exchange_rate = $order->get_meta( '_wcpay_multi_currency_order_exchange_rate' ); - $old_exchange_rate = ! empty( $old_exchange_rate ) ? $old_exchange_rate : __( 'Not found', 'woocommerce-payments' ); - $exchange_rate_log = $order->get_meta( '_wcpay_multi_currency_order_exchange_rate_log' ); - $exchange_rate_log = ( is_array( $exchange_rate_log ) ) ? $exchange_rate_log : []; - $current_time = time(); - - $exchange_rate_log[ $current_time ] = [ - 'user_id' => get_current_user_id(), - 'old_rate' => $old_exchange_rate, - 'new_rate' => $new_exchange_rate, - ]; - - // Add an order note stating what was updated. - $note = sprintf( - /* translators: %1 Old exchange rate, or 'Not found' string, %2 new exchange rate */ - __( 'The exchange rate has been updated:
    From: %1$s
    To: %2$s', 'woocommerce-payments' ), - $old_exchange_rate, - $new_exchange_rate - ); - $order->add_order_note( $note, 0, true ); - - // Update the exchange rate and the log on the order. - $order->update_meta_data( '_wcpay_multi_currency_order_exchange_rate', $new_exchange_rate ); - $order->update_meta_data( '_wcpay_multi_currency_order_exchange_rate_log', $exchange_rate_log ); - $order->save_meta_data(); - } - - /** - * Maybe add the meta box. - * - * @param string $post_type Unused. The type of post being viewed. - * @param object $post The post object for the post being viewed. - * - * @return void - */ - public function maybe_add_meta_box( $post_type, $post ) { - // Confirm we should be working on the order, if not, exit. - $order = $this->confirm_actions( $post ); - if ( ! $order || ! function_exists( '\wc_get_page_screen_id' ) ) { - return; - } - - // Get the order edit screen to be able to add the meta box to. - $wc_screen_id = \wc_get_page_screen_id( 'shop-order' ); - - add_meta_box( 'wcpay_mc_order_meta_helper_meta_box', __( 'Multi-Currency Meta Helper', 'woocommerce-payments' ), [ $this, 'display_meta_box_content' ], $wc_screen_id, 'advanced', 'high' ); - } - - /** - * Displays the content of the meta box. - * - * @param \WC_Order $order The order we are working with. - * - * @return void - */ - public function display_meta_box_content( $order ) { - // Again, make sure we are actually working with an order. - $order = wc_get_order( $order ); - if ( ! $order ) { - return; - } - - // Start getting all of the items we need. - $order_currency = strtoupper( $order->get_currency() ); - $intent_id = $order->get_meta( '_intent_id' ); - $payment_method = $order->get_payment_method(); - - // Define the store items. - $store_items = [ - 'store_currency' => [ - 'label' => __( 'Store Currency', 'woocommerce-payments' ), - 'value' => strtoupper( get_woocommerce_currency() ), - ], - ]; - - // Define the order meta items. - $order_meta_items = [ - 'order_currency' => [ - 'label' => __( 'Order Currency', 'woocommerce-payments' ), - 'value' => $order_currency, - ], - 'order_default_currency' => [ - 'label' => __( 'Order Default Currency', 'woocommerce-payments' ), - 'value' => strtoupper( $order->get_meta( '_wcpay_multi_currency_order_default_currency' ) ), - ], - 'payment_method' => [ - 'label' => __( 'Payment Method ID', 'woocommerce-payments' ), - 'value' => $payment_method, - ], - 'payment_method_title' => [ - 'label' => __( 'Payment Method Title', 'woocommerce-payments' ), - 'value' => $order->get_payment_method_title(), - ], - 'intent_id' => [ - 'label' => __( 'Intent ID', 'woocommerce-payments' ), - 'value' => $intent_id, - ], - 'intent_currency' => [ - 'label' => __( 'Intent Currency', 'woocommerce-payments' ), - 'value' => strtoupper( $order->get_meta( '_wcpay_intent_currency' ) ), - ], - 'mc_exchange_rate' => [ - 'label' => __( 'Multi-Currency Exchange Rate', 'woocommerce-payments' ), - 'value' => $order->get_meta( '_wcpay_multi_currency_order_exchange_rate' ), - ], - 'stripe_exchange_rate' => [ - 'label' => __( 'Stripe Exchange Rate', 'woocommerce-payments' ), - 'value' => $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ), - ], - ]; - - // Define the charge (intent) items. - $charge_items = [ - 'charge_exchange_rate' => [ - 'label' => __( 'Charge Exchange Rate', 'woocommerce-payments' ), - 'value' => '', - ], - 'charge_currency' => [ - 'label' => __( 'Charge Currency', 'woocommerce-payments' ), - 'value' => '', - ], - ]; - - if ( ! empty( $intent_id ) ) { - // Attempt to get the intent. - try { - $intent_object = $this->payments_api_client->get_intent( $intent_id ); - } catch ( API_Exception $e ) { - // Log the error returned. - Logger::error( "Error when attempting to get intent ($intent_id):\n" . $e->getMessage() ); - $intent_object = null; - } - - // If we have an intent, then get the charge and the exchange rate from it. - if ( is_a( $intent_object, 'WC_Payments_API_Payment_Intention' ) ) { - $charge_object = $intent_object->get_charge(); - $balance_transaction = $charge_object->get_balance_transaction(); - - // Set the Charge Exchange Rate value from the intent itself. - $charge_items['charge_exchange_rate']['value'] = $balance_transaction['exchange_rate']; - $charge_items['charge_currency']['value'] = strtoupper( $charge_object->get_currency() ); - } - } - - /** - * Zero decimal currencies have a different conversion rate value. - */ - if ( in_array( strtolower( $order_currency ), WC_Payments_Utils::zero_decimal_currencies(), true ) ) { - if ( '' !== $charge_items['charge_exchange_rate']['value'] ) { - $charge_items['charge_exchange_rate']['value'] = $charge_items['charge_exchange_rate']['value'] / 100; - } - } - - // Convert the Stripe exchange amounts to what we use for Multi-Currency. - if ( '' !== $charge_items['charge_exchange_rate']['value'] ) { - $charge_items['charge_exchange_rate']['value'] = 1 / $charge_items['charge_exchange_rate']['value']; - } - if ( '' !== $order_meta_items['stripe_exchange_rate']['value'] ) { - $order_meta_items['stripe_exchange_rate']['value'] = 1 / $order_meta_items['stripe_exchange_rate']['value']; - } - - // Let's see if we can get a suggested rate. - $suggested = false; - if ( empty( $order_meta_items['mc_exchange_rate']['value'] ) ) { - if ( ! empty( $charge_items['charge_exchange_rate']['value'] ) ) { - $suggested = $charge_items['charge_exchange_rate']['value']; - } - if ( ! empty( $order_meta_items['stripe_exchange_rate']['value'] ) ) { - $suggested = $order_meta_items['stripe_exchange_rate']['value']; - } - } - - // Define our labels. - $form_description = __( 'If the exchange rate meta data is missing, update the order with the suggested exchange rate. Once the rate is updated, you can then use the Import historical data tool under Analytics > Settings to correct analytical data.', 'woocommerce-payments' ); - $suggested_label = __( 'Suggested exchange rate: ', 'woocommerce-payments' ); - $new_exchange_rate_label = __( 'New exchange rate:', 'woocommerce-payments' ); - $nonce_value = wp_create_nonce( 'wcpay_multi_currency_exchange_rate_nonce_' . $order->get_id() ); - - // Display the form itself. - ?> -

    - -

    - -

    - -

    - -

    -

    -
    - $store_items, - __( 'Order meta items', 'woocommerce-payments' ) => $order_meta_items, - __( 'Charge items', 'woocommerce-payments' ) => $charge_items, - ]; - - $not_found = __( 'Not found', 'woocommerce-payments' ); - - // Iterate through our display items to display all available information in a table. - echo "\n"; - foreach ( $display_items as $label => $items ) { - echo '\n"; - foreach ( $items as $item ) { - echo '\n"; - } - } - echo "
    ' . esc_html( $label ) . "
    ' . esc_html( $item['label'] ) . ': '; - if ( ! empty( $item['value'] ) ) { - echo esc_html( $item['value'] ); - } else { - echo '' . esc_html( $not_found ) . ''; - } - echo "
    \n"; - } - - /** - * Appends our parameter to the edit post link if needed. - * - * @param string|null $url The current edit post link. - * - * @return string|null - */ - 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; - } - - /** - * Checks to see if the feature is enabled by the request parameter. - * - * @return bool - */ - private function is_feature_enabled(): bool { - // Nonce verification ignored due to this is just checking for a set specific value. - return isset( $_REQUEST['wcpay_mc_meta_helper'] ) && 1 === intval( $_REQUEST['wcpay_mc_meta_helper'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended - } - - /** - * Confirms that we should be working on this order. - * - * @param int|\WC_Order $order The order we're working with. - * - * @return bool|\WC_Order|\WC_Order_Refund Returns false or the order we're working with. - */ - private function confirm_actions( $order ) { - // If the feature is not enabled, exit. - if ( ! $this->is_feature_enabled() ) { - return false; - } - - // If it's actually not an order, or if it's not in a status that accepted a payment, exit. - $order = wc_get_order( $order ); - $paid_statuses = array_merge( wc_get_is_paid_statuses(), [ 'refunded' ] ); - if ( ! $order || ! in_array( $order->get_status(), $paid_statuses, true ) ) { - return false; - } - - // If the store currency and the order currency match, do not display the box. - $store_currency = get_woocommerce_currency(); - $order_currency = $order->get_currency(); - if ( $store_currency === $order_currency ) { - return false; - } - - return $order; - } - - /** - * Adds an error to the stack for us. - * - * @param string $error The error to add to the stack. - * - * @return void - */ - private function add_error( $error ) { - // Refresh the errors, then add the new one. - $this->get_errors(); - $this->errors[] = $error; - - // Update the errors option. - update_option( '_wcpay_multi_currency_order_meta_helper_errors', $this->errors ); - } - - /** - * Gets the errors from the options table. - * - * @return array The array of errors. - */ - private function get_errors(): array { - // Get any errors from the database. - $errors = array_filter( (array) get_option( '_wcpay_multi_currency_order_meta_helper_errors' ) ); - - // If we have any errors currently in our object, add those. - if ( 0 < count( $this->errors ) ) { - $errors = array_merge( $errors, $this->errors ); - } - - // Add all the errors to the object, and return them. - $this->errors = array_unique( $errors ); - - return $this->errors; - } - - /** - * Checks if we have any errors. - * - * @return bool - */ - private function has_errors(): bool { - return 0 < count( $this->get_errors() ); - } - - /** - * Removes the errors from the object and deletes the database option. - * - * @return void - */ - private function clear_errors() { - $this->errors = []; - delete_option( '_wcpay_multi_currency_order_meta_helper_errors' ); - } -} diff --git a/includes/wc-payment-api/class-wc-payments-api-client.php b/includes/wc-payment-api/class-wc-payments-api-client.php index 50aabec994c..13b25e07dd6 100644 --- a/includes/wc-payment-api/class-wc-payments-api-client.php +++ b/includes/wc-payment-api/class-wc-payments-api-client.php @@ -21,11 +21,12 @@ use WCPay\Core\Server\Request; use WCPay\Core\Server\Request\List_Fraud_Outcome_Transactions; use WCPay\Exceptions\Cannot_Combine_Currencies_Exception; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyApiClientInterface; /** * Communicates with WooCommerce Payments API. */ -class WC_Payments_API_Client { +class WC_Payments_API_Client implements MultiCurrencyApiClientInterface { const ENDPOINT_BASE = 'https://public-api.wordpress.com/wpcom/v2'; const ENDPOINT_SITE_FRAGMENT = 'sites/%s'; @@ -191,7 +192,7 @@ public function __construct( $user_agent, $http_client, $wcpay_db ) { * * @return bool */ - public function is_server_connected() { + public function is_server_connected(): bool { return $this->http_client->is_connected(); } @@ -857,7 +858,7 @@ function ( $a, $b ) { * * @throws API_Exception - Error contacting the API. */ - public function get_currency_rates( string $currency_from, $currencies_to = null ) { + public function get_currency_rates( string $currency_from, $currencies_to = null ): array { if ( empty( $currency_from ) ) { throw new API_Exception( __( 'Currency From parameter is required', 'woocommerce-payments' ), diff --git a/client/multi-currency-analytics/index.js b/multi-currency/client/analytics/index.js similarity index 100% rename from client/multi-currency-analytics/index.js rename to multi-currency/client/analytics/index.js diff --git a/client/multi-currency/blocks/currency-switcher.js b/multi-currency/client/blocks/currency-switcher.js similarity index 99% rename from client/multi-currency/blocks/currency-switcher.js rename to multi-currency/client/blocks/currency-switcher.js index 5dee2d130be..75111f42768 100644 --- a/client/multi-currency/blocks/currency-switcher.js +++ b/multi-currency/client/blocks/currency-switcher.js @@ -2,7 +2,10 @@ /** * Internal dependencies */ -import { useEnabledCurrencies, useCurrencies } from 'wcpay/data'; +import { + useEnabledCurrencies, + useCurrencies, +} from 'multi-currency/interface/data'; /** * External dependencies diff --git a/client/components/currency-delete-illustration/index.js b/multi-currency/client/components/currency-delete-illustration/index.js similarity index 100% rename from client/components/currency-delete-illustration/index.js rename to multi-currency/client/components/currency-delete-illustration/index.js diff --git a/client/components/currency-delete-illustration/styles.scss b/multi-currency/client/components/currency-delete-illustration/styles.scss similarity index 100% rename from client/components/currency-delete-illustration/styles.scss rename to multi-currency/client/components/currency-delete-illustration/styles.scss diff --git a/client/multi-currency/preview-modal/index.js b/multi-currency/client/components/preview-modal/index.js similarity index 95% rename from client/multi-currency/preview-modal/index.js rename to multi-currency/client/components/preview-modal/index.js index 9857ddd71e3..60d4fac0a13 100644 --- a/client/multi-currency/preview-modal/index.js +++ b/multi-currency/client/components/preview-modal/index.js @@ -3,7 +3,7 @@ */ import { Modal } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useStoreSettings } from 'wcpay/data'; +import { useStoreSettings } from 'multi-currency/data'; /** * Internal dependencies diff --git a/client/multi-currency/preview-modal/index.scss b/multi-currency/client/components/preview-modal/index.scss similarity index 100% rename from client/multi-currency/preview-modal/index.scss rename to multi-currency/client/components/preview-modal/index.scss diff --git a/client/components/search/index.js b/multi-currency/client/components/search/index.js similarity index 100% rename from client/components/search/index.js rename to multi-currency/client/components/search/index.js diff --git a/client/components/search/style.scss b/multi-currency/client/components/search/style.scss similarity index 100% rename from client/components/search/style.scss rename to multi-currency/client/components/search/style.scss diff --git a/client/components/search/test/__snapshots__/index.js.snap b/multi-currency/client/components/search/test/__snapshots__/index.js.snap similarity index 100% rename from client/components/search/test/__snapshots__/index.js.snap rename to multi-currency/client/components/search/test/__snapshots__/index.js.snap diff --git a/client/components/search/test/index.js b/multi-currency/client/components/search/test/index.js similarity index 100% rename from client/components/search/test/index.js rename to multi-currency/client/components/search/test/index.js diff --git a/client/multi-currency/context.js b/multi-currency/client/context.js similarity index 100% rename from client/multi-currency/context.js rename to multi-currency/client/context.js diff --git a/client/data/multi-currency/action-types.js b/multi-currency/client/data/action-types.js similarity index 100% rename from client/data/multi-currency/action-types.js rename to multi-currency/client/data/action-types.js diff --git a/client/data/multi-currency/actions.js b/multi-currency/client/data/actions.js similarity index 96% rename from client/data/multi-currency/actions.js rename to multi-currency/client/data/actions.js index 7c28cf73781..0b822dde4cb 100644 --- a/client/data/multi-currency/actions.js +++ b/multi-currency/client/data/actions.js @@ -6,13 +6,13 @@ import { apiFetch } from '@wordpress/data-controls'; import { dispatch, select } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { recordEvent } from 'tracks'; /** * Internal Dependencies */ +import { recordEvent } from 'multi-currency/interface/functions'; import TYPES from './action-types'; -import { NAMESPACE, STORE_NAME } from '../constants'; +import { NAMESPACE, STORE_NAME } from './constants'; export function updateCurrencies( data ) { return { diff --git a/multi-currency/client/data/constants.js b/multi-currency/client/data/constants.js new file mode 100644 index 00000000000..eaee38c6ee6 --- /dev/null +++ b/multi-currency/client/data/constants.js @@ -0,0 +1,4 @@ +/** @format */ + +export const NAMESPACE = '/wc/v3/payments'; +export const STORE_NAME = 'wc/payments/multi-currency'; diff --git a/client/data/multi-currency/hooks.js b/multi-currency/client/data/hooks.js similarity index 96% rename from client/data/multi-currency/hooks.js rename to multi-currency/client/data/hooks.js index aa39e24ee6f..ea5c23e5e75 100644 --- a/client/data/multi-currency/hooks.js +++ b/multi-currency/client/data/hooks.js @@ -4,7 +4,11 @@ * External dependencies */ import { useSelect, useDispatch, dispatch } from '@wordpress/data'; -import { STORE_NAME } from '../constants'; + +/** + * Internal dependencies + */ +import { STORE_NAME } from './constants'; export const useCurrencies = () => useSelect( ( select ) => { diff --git a/multi-currency/client/data/index.ts b/multi-currency/client/data/index.ts new file mode 100644 index 00000000000..f1d8d84a456 --- /dev/null +++ b/multi-currency/client/data/index.ts @@ -0,0 +1,20 @@ +/** @format */ + +/** + * Internal dependencies + */ +import { STORE_NAME } from './constants'; +import { initStore } from './store'; + +initStore(); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export const WCPAY_STORE_NAME = STORE_NAME; + +// We only ask for hooks when importing directly from 'multi-currency/data'. +import * as selectors from './selectors'; +import * as actions from './actions'; +import * as resolvers from './resolvers'; + +export { selectors, actions, resolvers }; +export * from './hooks'; diff --git a/client/data/multi-currency/reducer.js b/multi-currency/client/data/reducer.js similarity index 100% rename from client/data/multi-currency/reducer.js rename to multi-currency/client/data/reducer.js diff --git a/client/data/multi-currency/resolvers.js b/multi-currency/client/data/resolvers.js similarity index 93% rename from client/data/multi-currency/resolvers.js rename to multi-currency/client/data/resolvers.js index 4eada7da994..78168ad708a 100644 --- a/client/data/multi-currency/resolvers.js +++ b/multi-currency/client/data/resolvers.js @@ -10,7 +10,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { NAMESPACE } from '../constants'; +import { NAMESPACE } from './constants'; import { updateCurrencies, updateCurrencySettings, @@ -34,7 +34,7 @@ export function* getCurrencies() { } /** - * Retrieve single currency sttings from the site's REST API. + * Retrieve single currency settings from the site's REST API. * * @param {string} currencyCode The currency code to fetch settings for. */ diff --git a/client/data/multi-currency/selectors.js b/multi-currency/client/data/selectors.js similarity index 96% rename from client/data/multi-currency/selectors.js rename to multi-currency/client/data/selectors.js index 6c2a2b20f97..825a9271db0 100644 --- a/client/data/multi-currency/selectors.js +++ b/multi-currency/client/data/selectors.js @@ -13,7 +13,7 @@ const getMultiCurrencyState = ( state ) => { return {}; } - return state.multiCurrency || {}; + return state || {}; }; export const getCurrencies = ( state ) => { diff --git a/multi-currency/client/data/store.js b/multi-currency/client/data/store.js new file mode 100644 index 00000000000..2e142e66f9c --- /dev/null +++ b/multi-currency/client/data/store.js @@ -0,0 +1,28 @@ +/* + * External dependencies + */ +import { registerStore } from '@wordpress/data'; +import { controls } from '@wordpress/data-controls'; + +/** + * Internal dependencies + */ +import { STORE_NAME } from './constants'; +import * as multiCurrency from './'; +import reducer from './reducer'; + +// Extracted into wrapper function to facilitate testing. +export const initStore = () => + registerStore( STORE_NAME, { + reducer, + actions: { + ...multiCurrency.actions, + }, + controls, + selectors: { + ...multiCurrency.selectors, + }, + resolvers: { + ...multiCurrency.resolvers, + }, + } ); diff --git a/client/multi-currency/index.js b/multi-currency/client/index.js similarity index 91% rename from client/multi-currency/index.js rename to multi-currency/client/index.js index a479c326914..f4daf3b9a3a 100644 --- a/client/multi-currency/index.js +++ b/multi-currency/client/index.js @@ -7,8 +7,8 @@ import ReactDOM from 'react-dom'; /** * Internal dependencies */ -import MultiCurrencySettings from './multi-currency-settings'; -import SingleCurrencySettings from './single-currency-settings'; +import MultiCurrencySettings from './settings/multi-currency'; +import SingleCurrencySettings from './settings/single-currency'; import MultiCurrencySettingsContext from './context'; const MultiCurrencySettingsPage = () => { diff --git a/multi-currency/client/interface/assets.js b/multi-currency/client/interface/assets.js new file mode 100644 index 00000000000..3a3a095891a --- /dev/null +++ b/multi-currency/client/interface/assets.js @@ -0,0 +1,6 @@ +/** + * External Dependencies + */ +import paymentMethodsMap from 'wcpay/payment-methods-map'; + +export { paymentMethodsMap }; diff --git a/multi-currency/client/interface/components.js b/multi-currency/client/interface/components.js new file mode 100644 index 00000000000..eddab5ae84e --- /dev/null +++ b/multi-currency/client/interface/components.js @@ -0,0 +1,23 @@ +/** + * Dependencies from WooPayments to MCCY. + */ +// wcpay/additional-methods-setup/* +export { default as CollapsibleBody } from 'wcpay/additional-methods-setup/wizard/collapsible-body'; +export { default as Wizard } from 'wcpay/additional-methods-setup/wizard/wrapper'; +export { default as WizardTask } from 'wcpay/additional-methods-setup/wizard/task'; +export { default as WizardTaskItem } from 'wcpay/additional-methods-setup/wizard/task-item'; +export { default as WizardTaskList } from 'wcpay/additional-methods-setup/wizard/task-list'; +// wcpay/components/* +export { default as ConfirmationModal } from 'wcpay/components/confirmation-modal'; +export { default as Page } from 'wcpay/components/page'; +export { LoadableBlock } from 'wcpay/components/loadable'; +// wcpay/settings/* +export { default as PaymentMethodIcon } from 'wcpay/settings/payment-method-icon'; +export { default as SettingsLayout } from 'wcpay/settings/settings-layout'; +export { default as SettingsSection } from 'wcpay/settings/settings-section'; + +/** + * Dependencies from MCCY to WooPayments. + */ +// multi-currency/setup +export { default as MultiCurrencySetupPage } from 'multi-currency/setup'; diff --git a/multi-currency/client/interface/data.js b/multi-currency/client/interface/data.js new file mode 100644 index 00000000000..af162ddd6ed --- /dev/null +++ b/multi-currency/client/interface/data.js @@ -0,0 +1,10 @@ +/** + * Dependencies from WooPayments to MCCY. + */ +// wcpay/data +export { useSettings, useMultiCurrency } from 'wcpay/data'; + +/** + * Dependencies from MCCY to WooPayments. + */ +export { useCurrencies, useEnabledCurrencies } from 'multi-currency/data'; diff --git a/multi-currency/client/interface/functions.js b/multi-currency/client/interface/functions.js new file mode 100644 index 00000000000..5ffed26e00d --- /dev/null +++ b/multi-currency/client/interface/functions.js @@ -0,0 +1,25 @@ +/** + * Dependencies from WooPayments to MCCY. + */ +// wcpay/tracks +export { recordEvent } from 'wcpay/tracks'; +// wcpay/settings +export { default as WCPaySettingsContext } from 'wcpay/settings/wcpay-settings-context'; +// wcpay/additional-methods-setup/* +export { default as WizardTaskContext } from 'wcpay/additional-methods-setup/wizard/task/context'; +// wcpay/utils/* +export { formatListOfItems } from 'wcpay/utils/format-list-of-items'; + +/** + * Dependencies from MCCY to WooPayments. + */ +export { getMissingCurrenciesTooltipMessage } from 'multi-currency/utils/missing-currencies-message'; +export { + formatCurrency, + formatCurrencyName, + formatFX, + formatExplicitCurrency, + formatExportAmount, + getCurrency, + isZeroDecimalCurrency, +} from 'multi-currency/utils/currency'; diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/delete-button.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/delete-button.js similarity index 92% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/delete-button.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/delete-button.js index cc58435ed22..ad99c04d327 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/delete-button.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/delete-button.js @@ -6,10 +6,12 @@ import { __, sprintf } from '@wordpress/i18n'; import { Button, Icon } from '@wordpress/components'; import interpolateComponents from '@automattic/interpolate-components'; import { useCallback, useState } from '@wordpress/element'; -import ConfirmationModal from 'wcpay/components/confirmation-modal'; -import CurrencyDeleteIllustration from 'wcpay/components/currency-delete-illustration'; -import PaymentMethodIcon from 'wcpay/settings/payment-method-icon'; -import paymentMethodsMap from 'wcpay/payment-methods-map'; +import { + ConfirmationModal, + PaymentMethodIcon, +} from 'multi-currency/interface/components'; +import CurrencyDeleteIllustration from 'multi-currency/components/currency-delete-illustration'; +import { paymentMethodsMap } from 'multi-currency/interface/assets'; const DeleteButton = ( { code, label, symbol, onClick, className } ) => { const [ isConfirmationModalOpen, setIsConfirmationModalOpen ] = useState( diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/index.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/index.js similarity index 97% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/index.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/index.js index 8d08b90ef11..00ac75e0c6e 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/index.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/index.js @@ -15,13 +15,13 @@ import { useCurrencies, useDefaultCurrency, useEnabledCurrencies, -} from 'wcpay/data'; +} from 'multi-currency/data'; import EnabledCurrenciesList from './list'; import EnabledCurrenciesListItem from './list-item'; import EnabledCurrenciesListItemPlaceholder from './list-item-placeholder'; import EnabledCurrenciesModal from './modal'; -import SettingsSection from 'wcpay/settings/settings-section'; +import { SettingsSection } from 'multi-currency/interface/components'; const EnabledCurrenciesSettingsDescription = () => { const LEARN_MORE_URL = diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item-placeholder.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item-placeholder.js similarity index 94% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item-placeholder.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item-placeholder.js index 6a44378e72a..c29d2902a8b 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item-placeholder.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item-placeholder.js @@ -3,7 +3,7 @@ * External dependencies */ import classNames from 'classnames'; -import { LoadableBlock } from 'wcpay/components/loadable'; +import { LoadableBlock } from 'multi-currency/interface/components'; const EnabledCurrenciesListItemPlaceholder = ( { isLoading } ) => { return ( diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item.js similarity index 97% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item.js index 135e95a0a94..0b8d0b14689 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/list-item.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/list-item.js @@ -10,7 +10,7 @@ import { Button } from '@wordpress/components'; * Internal dependencies */ import DeleteButton from './delete-button'; -import MultiCurrencySettingsContext from '../../context'; +import MultiCurrencySettingsContext from 'multi-currency/context'; import { useContext } from 'react'; const EnabledCurrenciesListItem = ( { diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/list.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/list.js similarity index 100% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/list.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/list.js diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox-list.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/modal-checkbox-list.js similarity index 100% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox-list.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/modal-checkbox-list.js diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/modal-checkbox.js similarity index 100% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/modal-checkbox.js diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/modal.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/modal.js similarity index 97% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/modal.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/modal.js index 619e51a01c5..13610e78c17 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/modal.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/modal.js @@ -13,11 +13,11 @@ import { useAvailableCurrencies, useEnabledCurrencies, useDefaultCurrency, -} from 'wcpay/data'; +} from 'multi-currency/data'; import EnabledCurrenciesModalCheckboxList from './modal-checkbox-list'; import EnabledCurrenciesModalCheckbox from './modal-checkbox'; -import ConfirmationModal from 'wcpay/components/confirmation-modal'; -import Search from 'components/search'; +import { ConfirmationModal } from 'multi-currency/interface/components'; +import Search from 'multi-currency/components/search'; import './style.scss'; // TODO: This works when saving, but list does not refresh. diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/style.scss b/multi-currency/client/settings/multi-currency/enabled-currencies-list/style.scss similarity index 100% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/style.scss rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/style.scss diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/test/__snapshots__/index.js.snap b/multi-currency/client/settings/multi-currency/enabled-currencies-list/test/__snapshots__/index.js.snap similarity index 100% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/test/__snapshots__/index.js.snap rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/test/__snapshots__/index.js.snap diff --git a/client/multi-currency/multi-currency-settings/enabled-currencies-list/test/index.js b/multi-currency/client/settings/multi-currency/enabled-currencies-list/test/index.js similarity index 97% rename from client/multi-currency/multi-currency-settings/enabled-currencies-list/test/index.js rename to multi-currency/client/settings/multi-currency/enabled-currencies-list/test/index.js index 38e15b1b04b..fb4e89bd92c 100644 --- a/client/multi-currency/multi-currency-settings/enabled-currencies-list/test/index.js +++ b/multi-currency/client/settings/multi-currency/enabled-currencies-list/test/index.js @@ -14,13 +14,13 @@ import { useCurrencies, useDefaultCurrency, useEnabledCurrencies, -} from 'wcpay/data'; +} from 'multi-currency/data'; -import MultiCurrencySettingsContext from '../../../context'; +import MultiCurrencySettingsContext from 'multi-currency/context'; -jest.mock( 'wcpay/data', () => ( { - useCurrencies: jest.fn(), +jest.mock( 'multi-currency/data', () => ( { useAvailableCurrencies: jest.fn(), + useCurrencies: jest.fn(), useDefaultCurrency: jest.fn(), useEnabledCurrencies: jest.fn(), } ) ); diff --git a/client/multi-currency/multi-currency-settings/index.js b/multi-currency/client/settings/multi-currency/index.js similarity index 87% rename from client/multi-currency/multi-currency-settings/index.js rename to multi-currency/client/settings/multi-currency/index.js index 89ee0fd6361..a2caf57151e 100644 --- a/client/multi-currency/multi-currency-settings/index.js +++ b/multi-currency/client/settings/multi-currency/index.js @@ -6,7 +6,7 @@ import React from 'react'; /** * Internal dependencies */ -import SettingsLayout from '../../settings/settings-layout'; +import { SettingsLayout } from 'multi-currency/interface/components'; import EnabledCurrenciesList from './enabled-currencies-list'; import StoreSettings from './store-settings'; import './style.scss'; diff --git a/client/multi-currency/multi-currency-settings/store-settings/index.js b/multi-currency/client/settings/multi-currency/store-settings/index.js similarity index 95% rename from client/multi-currency/multi-currency-settings/store-settings/index.js rename to multi-currency/client/settings/multi-currency/store-settings/index.js index 9e5be4eb9df..18972164698 100644 --- a/client/multi-currency/multi-currency-settings/store-settings/index.js +++ b/multi-currency/client/settings/multi-currency/store-settings/index.js @@ -11,10 +11,12 @@ import { createInterpolateElement } from '@wordpress/element'; */ import './style.scss'; -import { useStoreSettings } from 'wcpay/data'; -import SettingsSection from 'wcpay/settings/settings-section'; -import { LoadableBlock } from 'wcpay/components/loadable'; -import PreviewModal from 'wcpay/multi-currency/preview-modal'; +import { useStoreSettings } from 'multi-currency/data'; +import { + LoadableBlock, + SettingsSection, +} from 'multi-currency/interface/components'; +import PreviewModal from 'multi-currency/components/preview-modal'; const StoreSettingsDescription = () => { const LEARN_MORE_URL = diff --git a/client/multi-currency/multi-currency-settings/store-settings/style.scss b/multi-currency/client/settings/multi-currency/store-settings/style.scss similarity index 100% rename from client/multi-currency/multi-currency-settings/store-settings/style.scss rename to multi-currency/client/settings/multi-currency/store-settings/style.scss diff --git a/client/multi-currency/multi-currency-settings/store-settings/test/__snapshots__/index.test.js.snap b/multi-currency/client/settings/multi-currency/store-settings/test/__snapshots__/index.test.js.snap similarity index 100% rename from client/multi-currency/multi-currency-settings/store-settings/test/__snapshots__/index.test.js.snap rename to multi-currency/client/settings/multi-currency/store-settings/test/__snapshots__/index.test.js.snap diff --git a/client/multi-currency/multi-currency-settings/store-settings/test/index.test.js b/multi-currency/client/settings/multi-currency/store-settings/test/index.test.js similarity index 95% rename from client/multi-currency/multi-currency-settings/store-settings/test/index.test.js rename to multi-currency/client/settings/multi-currency/store-settings/test/index.test.js index d65d4af5f6b..0aadcd7720d 100644 --- a/client/multi-currency/multi-currency-settings/store-settings/test/index.test.js +++ b/multi-currency/client/settings/multi-currency/store-settings/test/index.test.js @@ -7,10 +7,10 @@ import { render, screen, fireEvent } from '@testing-library/react'; /** * Internal dependencies */ -import { useStoreSettings } from 'wcpay/data'; +import { useStoreSettings } from 'multi-currency/data'; import StoreSettings from '..'; -jest.mock( 'wcpay/data', () => ( { +jest.mock( 'multi-currency/data', () => ( { useStoreSettings: jest.fn(), } ) ); diff --git a/client/multi-currency/multi-currency-settings/style.scss b/multi-currency/client/settings/multi-currency/style.scss similarity index 100% rename from client/multi-currency/multi-currency-settings/style.scss rename to multi-currency/client/settings/multi-currency/style.scss diff --git a/client/multi-currency/multi-currency-settings/test/__snapshots__/index.test.js.snap b/multi-currency/client/settings/multi-currency/test/__snapshots__/index.test.js.snap similarity index 100% rename from client/multi-currency/multi-currency-settings/test/__snapshots__/index.test.js.snap rename to multi-currency/client/settings/multi-currency/test/__snapshots__/index.test.js.snap diff --git a/client/multi-currency/multi-currency-settings/test/index.test.js b/multi-currency/client/settings/multi-currency/test/index.test.js similarity index 92% rename from client/multi-currency/multi-currency-settings/test/index.test.js rename to multi-currency/client/settings/multi-currency/test/index.test.js index 5940e763cc8..3acbfb022c0 100644 --- a/client/multi-currency/multi-currency-settings/test/index.test.js +++ b/multi-currency/client/settings/multi-currency/test/index.test.js @@ -7,7 +7,7 @@ import { render } from '@testing-library/react'; /** * Internal dependencies */ -import SettingsLayout from '../../../settings/settings-layout'; +import { SettingsLayout } from 'multi-currency/interface/components'; import EnabledCurrenciesList from '../enabled-currencies-list'; import StoreSettings from '../store-settings'; diff --git a/client/multi-currency/single-currency-settings/constants.js b/multi-currency/client/settings/single-currency/constants.js similarity index 100% rename from client/multi-currency/single-currency-settings/constants.js rename to multi-currency/client/settings/single-currency/constants.js diff --git a/client/multi-currency/single-currency-settings/currency-preview.js b/multi-currency/client/settings/single-currency/currency-preview.js similarity index 96% rename from client/multi-currency/single-currency-settings/currency-preview.js rename to multi-currency/client/settings/single-currency/currency-preview.js index 952bc537363..8f16f4c5596 100644 --- a/client/multi-currency/single-currency-settings/currency-preview.js +++ b/multi-currency/client/settings/single-currency/currency-preview.js @@ -6,7 +6,10 @@ import React, { useCallback, useEffect, useState } from 'react'; import { __ } from '@wordpress/i18n'; import { Card, CardBody } from '@wordpress/components'; import { TextControlWithAffixes } from '@woocommerce/components'; -import { formatCurrency, isZeroDecimalCurrency } from 'wcpay/utils/currency'; +import { + formatCurrency, + isZeroDecimalCurrency, +} from 'multi-currency/utils/currency'; const CurrencyPreview = ( { storeCurrency, diff --git a/client/multi-currency/single-currency-settings/index.js b/multi-currency/client/settings/single-currency/index.js similarity index 98% rename from client/multi-currency/single-currency-settings/index.js rename to multi-currency/client/settings/single-currency/index.js index 213409c9f47..14a3560f14d 100644 --- a/client/multi-currency/single-currency-settings/index.js +++ b/multi-currency/client/settings/single-currency/index.js @@ -5,8 +5,6 @@ import React, { useContext, useEffect, useState } from 'react'; import { dateI18n } from '@wordpress/date'; import { sprintf, __ } from '@wordpress/i18n'; -import SettingsLayout from 'wcpay/settings/settings-layout'; -import SettingsSection from 'wcpay/settings/settings-section'; import moment from 'moment'; /** @@ -27,9 +25,13 @@ import { useCurrencySettings, useEnabledCurrencies, useStoreSettings, -} from 'wcpay/data'; -import MultiCurrencySettingsContext from '../context'; -import { LoadableBlock } from 'wcpay/components/loadable'; +} from 'multi-currency/data'; +import MultiCurrencySettingsContext from 'multi-currency/context'; +import { + LoadableBlock, + SettingsLayout, + SettingsSection, +} from 'multi-currency/interface/components'; const SingleCurrencySettings = () => { const { diff --git a/client/multi-currency/single-currency-settings/style.scss b/multi-currency/client/settings/single-currency/style.scss similarity index 100% rename from client/multi-currency/single-currency-settings/style.scss rename to multi-currency/client/settings/single-currency/style.scss diff --git a/client/multi-currency/single-currency-settings/test/__snapshots__/index.test.js.snap b/multi-currency/client/settings/single-currency/test/__snapshots__/index.test.js.snap similarity index 100% rename from client/multi-currency/single-currency-settings/test/__snapshots__/index.test.js.snap rename to multi-currency/client/settings/single-currency/test/__snapshots__/index.test.js.snap diff --git a/client/multi-currency/single-currency-settings/test/index.test.js b/multi-currency/client/settings/single-currency/test/index.test.js similarity index 97% rename from client/multi-currency/single-currency-settings/test/index.test.js rename to multi-currency/client/settings/single-currency/test/index.test.js index 5f2597dff2c..0559953e54b 100644 --- a/client/multi-currency/single-currency-settings/test/index.test.js +++ b/multi-currency/client/settings/single-currency/test/index.test.js @@ -15,11 +15,11 @@ import { useEnabledCurrencies, useCurrencySettings, useStoreSettings, -} from 'wcpay/data'; +} from 'multi-currency/data'; -import MultiCurrencySettingsContext from '../../context'; +import MultiCurrencySettingsContext from 'multi-currency/context'; -jest.mock( 'wcpay/data', () => ( { +jest.mock( 'multi-currency/data', () => ( { useCurrencies: jest.fn(), useAvailableCurrencies: jest.fn(), useDefaultCurrency: jest.fn(), diff --git a/client/multi-currency-setup/index.js b/multi-currency/client/setup/index.js similarity index 77% rename from client/multi-currency-setup/index.js rename to multi-currency/client/setup/index.js index 512ab078182..05e76eb67ce 100644 --- a/client/multi-currency-setup/index.js +++ b/multi-currency/client/setup/index.js @@ -3,9 +3,9 @@ /** * Internal dependencies */ -import Page from 'components/page'; import MultiCurrencySetup from './tasks/multi-currency-setup'; -import WCPaySettingsContext from '../settings/wcpay-settings-context'; +import { Page } from 'multi-currency/interface/components'; +import { WCPaySettingsContext } from 'multi-currency/interface/functions'; const MultiCurrencySetupPage = () => { const { isSetupCompleted } = window.wcpaySettings.multiCurrencySetup; diff --git a/client/multi-currency-setup/tasks/add-currencies-task/constants.js b/multi-currency/client/setup/tasks/add-currencies-task/constants.js similarity index 100% rename from client/multi-currency-setup/tasks/add-currencies-task/constants.js rename to multi-currency/client/setup/tasks/add-currencies-task/constants.js diff --git a/client/multi-currency-setup/tasks/add-currencies-task/index.js b/multi-currency/client/setup/tasks/add-currencies-task/index.js similarity index 93% rename from client/multi-currency-setup/tasks/add-currencies-task/index.js rename to multi-currency/client/setup/tasks/add-currencies-task/index.js index 1795edaa6a0..f33fb5e95a3 100644 --- a/client/multi-currency-setup/tasks/add-currencies-task/index.js +++ b/multi-currency/client/setup/tasks/add-currencies-task/index.js @@ -10,23 +10,24 @@ import _ from 'lodash'; /** * Internal dependencies */ -import WizardTaskContext from '../../../additional-methods-setup/wizard/task/context'; -import CollapsibleBody from '../../../additional-methods-setup/wizard/collapsible-body'; -import WizardTaskItem from '../../wizard/task-item'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; +import Search from 'multi-currency/components/search'; +import { + CollapsibleBody, + LoadableBlock, + WizardTaskItem, +} from 'multi-currency/interface/components'; import { useCurrencies, useAvailableCurrencies, useEnabledCurrencies, useDefaultCurrency, -} from 'wcpay/data'; +} from 'multi-currency/data'; // eslint-disable-next-line max-len -import EnabledCurrenciesModalCheckboxList from '../../../multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox-list'; -import EnabledCurrenciesModalCheckbox from '../../../multi-currency/multi-currency-settings/enabled-currencies-list/modal-checkbox'; -import Search from 'components/search'; - -import { LoadableBlock } from '../../../components/loadable'; +import EnabledCurrenciesModalCheckboxList from 'multi-currency/settings/multi-currency/enabled-currencies-list/modal-checkbox-list'; +import EnabledCurrenciesModalCheckbox from 'multi-currency/settings/multi-currency/enabled-currencies-list/modal-checkbox'; import { recommendedCurrencyCodes, numberWords } from './constants'; import { diff --git a/client/multi-currency-setup/tasks/add-currencies-task/index.scss b/multi-currency/client/setup/tasks/add-currencies-task/index.scss similarity index 100% rename from client/multi-currency-setup/tasks/add-currencies-task/index.scss rename to multi-currency/client/setup/tasks/add-currencies-task/index.scss diff --git a/client/multi-currency-setup/tasks/add-currencies-task/test/__snapshots__/index.test.js.snap b/multi-currency/client/setup/tasks/add-currencies-task/test/__snapshots__/index.test.js.snap similarity index 100% rename from client/multi-currency-setup/tasks/add-currencies-task/test/__snapshots__/index.test.js.snap rename to multi-currency/client/setup/tasks/add-currencies-task/test/__snapshots__/index.test.js.snap diff --git a/client/multi-currency-setup/tasks/add-currencies-task/test/index.test.js b/multi-currency/client/setup/tasks/add-currencies-task/test/index.test.js similarity index 97% rename from client/multi-currency-setup/tasks/add-currencies-task/test/index.test.js rename to multi-currency/client/setup/tasks/add-currencies-task/test/index.test.js index f58beb09ced..7041543dadc 100644 --- a/client/multi-currency-setup/tasks/add-currencies-task/test/index.test.js +++ b/multi-currency/client/setup/tasks/add-currencies-task/test/index.test.js @@ -9,23 +9,25 @@ import { useSelect } from '@wordpress/data'; * Internal dependencies */ import AddCurrenciesTask from '..'; +import { useSettings } from 'multi-currency/interface/data'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; import { useCurrencies, useAvailableCurrencies, useDefaultCurrency, useEnabledCurrencies, - useSettings, -} from 'wcpay/data'; +} from 'multi-currency/data'; -import WizardTaskContext from '../../../../additional-methods-setup/wizard/task/context'; import { recommendedCurrencyCodes } from '../constants'; import { __ } from '@wordpress/i18n'; -jest.mock( 'wcpay/data', () => ( { +jest.mock( 'multi-currency/data', () => ( { useCurrencies: jest.fn(), useAvailableCurrencies: jest.fn(), useDefaultCurrency: jest.fn(), useEnabledCurrencies: jest.fn(), +} ) ); +jest.mock( 'multi-currency/interface/data', () => ( { useSettings: jest.fn(), } ) ); diff --git a/client/multi-currency-setup/tasks/add-currencies-task/test/utils.test.js b/multi-currency/client/setup/tasks/add-currencies-task/test/utils.test.js similarity index 100% rename from client/multi-currency-setup/tasks/add-currencies-task/test/utils.test.js rename to multi-currency/client/setup/tasks/add-currencies-task/test/utils.test.js diff --git a/client/multi-currency-setup/tasks/add-currencies-task/utils.js b/multi-currency/client/setup/tasks/add-currencies-task/utils.js similarity index 100% rename from client/multi-currency-setup/tasks/add-currencies-task/utils.js rename to multi-currency/client/setup/tasks/add-currencies-task/utils.js diff --git a/client/multi-currency-setup/tasks/multi-currency-setup.js b/multi-currency/client/setup/tasks/multi-currency-setup.js similarity index 84% rename from client/multi-currency-setup/tasks/multi-currency-setup.js rename to multi-currency/client/setup/tasks/multi-currency-setup.js index 77263d9bf33..cbeb6387bda 100644 --- a/client/multi-currency-setup/tasks/multi-currency-setup.js +++ b/multi-currency/client/setup/tasks/multi-currency-setup.js @@ -7,9 +7,11 @@ import { Card, CardBody } from '@wordpress/components'; /** * Internal dependencies */ -import Wizard from '../../additional-methods-setup/wizard/wrapper'; -import WizardTask from '../../additional-methods-setup/wizard/task'; -import WizardTaskList from '../../additional-methods-setup/wizard/task-list'; +import { + Wizard, + WizardTask, + WizardTaskList, +} from 'multi-currency/interface/components'; import StoreSettingsTask from './store-settings-task'; import SetupCompleteTask from './setup-complete-task'; import AddCurrenciesTask from './add-currencies-task'; diff --git a/client/multi-currency-setup/tasks/multi-currency-setup.scss b/multi-currency/client/setup/tasks/multi-currency-setup.scss similarity index 100% rename from client/multi-currency-setup/tasks/multi-currency-setup.scss rename to multi-currency/client/setup/tasks/multi-currency-setup.scss diff --git a/client/multi-currency-setup/tasks/setup-complete-task/index.js b/multi-currency/client/setup/tasks/setup-complete-task/index.js similarity index 89% rename from client/multi-currency-setup/tasks/setup-complete-task/index.js rename to multi-currency/client/setup/tasks/setup-complete-task/index.js index e846498df0e..6c467ec3a08 100644 --- a/client/multi-currency-setup/tasks/setup-complete-task/index.js +++ b/multi-currency/client/setup/tasks/setup-complete-task/index.js @@ -10,13 +10,15 @@ import { useDispatch } from '@wordpress/data'; /** * Internal dependencies */ -import CollapsibleBody from '../../../additional-methods-setup/wizard/collapsible-body'; -import WizardTaskItem from '../../wizard/task-item'; -import WizardTaskContext from '../../../additional-methods-setup/wizard/task/context'; +import { + CollapsibleBody, + WizardTaskItem, +} from 'multi-currency/interface/components'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; import './index.scss'; -import { useDefaultCurrency } from 'wcpay/data'; +import { useDefaultCurrency } from 'multi-currency/data'; const SetupComplete = () => { const { isActive } = useContext( WizardTaskContext ); diff --git a/client/multi-currency-setup/tasks/setup-complete-task/index.scss b/multi-currency/client/setup/tasks/setup-complete-task/index.scss similarity index 100% rename from client/multi-currency-setup/tasks/setup-complete-task/index.scss rename to multi-currency/client/setup/tasks/setup-complete-task/index.scss diff --git a/client/multi-currency-setup/tasks/setup-complete-task/test/index.test.js b/multi-currency/client/setup/tasks/setup-complete-task/test/index.test.js similarity index 87% rename from client/multi-currency-setup/tasks/setup-complete-task/test/index.test.js rename to multi-currency/client/setup/tasks/setup-complete-task/test/index.test.js index 48c4ac16d7a..a7a9db81872 100644 --- a/client/multi-currency-setup/tasks/setup-complete-task/test/index.test.js +++ b/multi-currency/client/setup/tasks/setup-complete-task/test/index.test.js @@ -6,14 +6,15 @@ import { render } from '@testing-library/react'; /** * Internal dependencies */ -import WizardTaskContext from '../../../../additional-methods-setup/wizard/task/context'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; import SetupCompleteTask from '../../setup-complete-task'; jest.mock( '@wordpress/data', () => ( { useDispatch: jest.fn().mockReturnValue( { updateOptions: jest.fn() } ), } ) ); -jest.mock( 'wcpay/data', () => ( { +jest.mock( 'multi-currency/interface/data', () => ( {} ) ); +jest.mock( 'multi-currency/data', () => ( { useDefaultCurrency: jest.fn().mockReturnValue( { code: 'USD', rate: 1, diff --git a/client/multi-currency-setup/tasks/store-settings-task/index.js b/multi-currency/client/setup/tasks/store-settings-task/index.js similarity index 92% rename from client/multi-currency-setup/tasks/store-settings-task/index.js rename to multi-currency/client/setup/tasks/store-settings-task/index.js index 7e20fc0f3e4..9a3ca8f0666 100644 --- a/client/multi-currency-setup/tasks/store-settings-task/index.js +++ b/multi-currency/client/setup/tasks/store-settings-task/index.js @@ -9,13 +9,16 @@ import interpolateComponents from '@automattic/interpolate-components'; /** * Internal dependencies */ -import WizardTaskContext from '../../../additional-methods-setup/wizard/task/context'; -import CollapsibleBody from '../../../additional-methods-setup/wizard/collapsible-body'; -import WizardTaskItem from '../../wizard/task-item'; -import PreviewModal from '../../../multi-currency/preview-modal'; +import { + CollapsibleBody, + WizardTaskItem, +} from 'multi-currency/interface/components'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; +import { useSettings, useMultiCurrency } from 'multi-currency/interface/data'; +import PreviewModal from 'multi-currency/components/preview-modal'; import './index.scss'; -import { useStoreSettings, useSettings, useMultiCurrency } from 'wcpay/data'; +import { useStoreSettings } from 'multi-currency/data'; const StoreSettingsTask = () => { const { storeSettings, submitStoreSettingsUpdate } = useStoreSettings(); diff --git a/client/multi-currency-setup/tasks/store-settings-task/index.scss b/multi-currency/client/setup/tasks/store-settings-task/index.scss similarity index 100% rename from client/multi-currency-setup/tasks/store-settings-task/index.scss rename to multi-currency/client/setup/tasks/store-settings-task/index.scss diff --git a/client/multi-currency-setup/tasks/store-settings-task/test/__snapshots__/index.test.js.snap b/multi-currency/client/setup/tasks/store-settings-task/test/__snapshots__/index.test.js.snap similarity index 100% rename from client/multi-currency-setup/tasks/store-settings-task/test/__snapshots__/index.test.js.snap rename to multi-currency/client/setup/tasks/store-settings-task/test/__snapshots__/index.test.js.snap diff --git a/client/multi-currency-setup/tasks/store-settings-task/test/index.test.js b/multi-currency/client/setup/tasks/store-settings-task/test/index.test.js similarity index 92% rename from client/multi-currency-setup/tasks/store-settings-task/test/index.test.js rename to multi-currency/client/setup/tasks/store-settings-task/test/index.test.js index e81b7b08f99..d80e8f8d12a 100644 --- a/client/multi-currency-setup/tasks/store-settings-task/test/index.test.js +++ b/multi-currency/client/setup/tasks/store-settings-task/test/index.test.js @@ -7,21 +7,21 @@ import { render, screen, fireEvent } from '@testing-library/react'; /** * Internal dependencies */ -import WizardTaskContext from '../../../../additional-methods-setup/wizard/task/context'; -import { - useCurrencies, - useStoreSettings, - useSettings, - useMultiCurrency, -} from 'wcpay/data'; +import { useCurrencies, useStoreSettings } from 'multi-currency/data'; +import { useSettings, useMultiCurrency } from 'multi-currency/interface/data'; +import { WizardTaskContext } from 'multi-currency/interface/functions'; import StoreSettingsTask from '..'; -jest.mock( 'wcpay/data', () => ( { +jest.mock( 'multi-currency/data', () => ( { useStoreSettings: jest.fn(), useCurrencies: jest.fn(), useSettings: jest.fn(), useMultiCurrency: jest.fn(), } ) ); +jest.mock( 'multi-currency/interface/data', () => ( { + useSettings: jest.fn(), + useMultiCurrency: jest.fn(), +} ) ); const changeableSettings = [ 'enable_storefront_switcher', diff --git a/client/multi-currency-setup/tasks/test/__snapshots__/multi-currency-setup.test.js.snap b/multi-currency/client/setup/tasks/test/__snapshots__/multi-currency-setup.test.js.snap similarity index 100% rename from client/multi-currency-setup/tasks/test/__snapshots__/multi-currency-setup.test.js.snap rename to multi-currency/client/setup/tasks/test/__snapshots__/multi-currency-setup.test.js.snap diff --git a/client/multi-currency-setup/tasks/test/multi-currency-setup.test.js b/multi-currency/client/setup/tasks/test/multi-currency-setup.test.js similarity index 100% rename from client/multi-currency-setup/tasks/test/multi-currency-setup.test.js rename to multi-currency/client/setup/tasks/test/multi-currency-setup.test.js diff --git a/client/multi-currency-setup/test/index.js b/multi-currency/client/setup/test/index.js similarity index 100% rename from client/multi-currency-setup/test/index.js rename to multi-currency/client/setup/test/index.js diff --git a/client/utils/currency/index.js b/multi-currency/client/utils/currency/index.js similarity index 100% rename from client/utils/currency/index.js rename to multi-currency/client/utils/currency/index.js diff --git a/client/utils/currency/test/index.js b/multi-currency/client/utils/currency/test/index.js similarity index 98% rename from client/utils/currency/test/index.js rename to multi-currency/client/utils/currency/test/index.js index 25e67b62c3c..0a08bbdd7db 100644 --- a/client/utils/currency/test/index.js +++ b/multi-currency/client/utils/currency/test/index.js @@ -6,7 +6,7 @@ /** * Internal dependencies */ -import * as utils from 'utils/currency'; +import * as utils from 'multi-currency/utils/currency'; describe( 'Currency utilities', () => { beforeEach( () => { diff --git a/client/multi-currency/__tests__/missing-currencies-message.test.js b/multi-currency/client/utils/missing-currencies-message/__tests__/index.test.js similarity index 89% rename from client/multi-currency/__tests__/missing-currencies-message.test.js rename to multi-currency/client/utils/missing-currencies-message/__tests__/index.test.js index ac74c4ee517..bd7fcff7840 100644 --- a/client/multi-currency/__tests__/missing-currencies-message.test.js +++ b/multi-currency/client/utils/missing-currencies-message/__tests__/index.test.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { getMissingCurrenciesTooltipMessage } from '../missing-currencies-message'; +import { getMissingCurrenciesTooltipMessage } from 'multi-currency/utils/missing-currencies-message'; describe( 'getMissingCurrenciesTooltipMessage', () => { it( 'returns correct string with the given LPM label and currency list', () => { diff --git a/client/multi-currency/missing-currencies-message.ts b/multi-currency/client/utils/missing-currencies-message/index.ts similarity index 91% rename from client/multi-currency/missing-currencies-message.ts rename to multi-currency/client/utils/missing-currencies-message/index.ts index 514ccff973d..b6e68116479 100644 --- a/client/multi-currency/missing-currencies-message.ts +++ b/multi-currency/client/utils/missing-currencies-message/index.ts @@ -6,7 +6,7 @@ import { sprintf, _n } from '@wordpress/i18n'; /** * Internal dependencies */ -import { formatListOfItems } from 'wcpay/utils/format-list-of-items'; +import { formatListOfItems } from 'multi-currency/interface/functions'; export const getMissingCurrenciesTooltipMessage = ( paymentMethodLabel: string, diff --git a/includes/multi-currency/AdminNotices.php b/multi-currency/src/AdminNotices.php similarity index 100% rename from includes/multi-currency/AdminNotices.php rename to multi-currency/src/AdminNotices.php diff --git a/includes/multi-currency/Analytics.php b/multi-currency/src/Analytics.php similarity index 96% rename from includes/multi-currency/Analytics.php rename to multi-currency/src/Analytics.php index ef3f5b17a5a..822ba88efc5 100644 --- a/includes/multi-currency/Analytics.php +++ b/multi-currency/src/Analytics.php @@ -12,7 +12,7 @@ use Automattic\WooCommerce\Utilities\OrderUtil; use WC_Order; use WC_Order_Refund; -use WC_Payments; +use WCPay\MultiCurrency\Interfaces\MultiCurrencySettingsInterface; defined( 'ABSPATH' ) || exit; @@ -42,13 +42,22 @@ class Analytics { */ private $multi_currency; + /** + * Instance of MultiCurrencySettingsInterface. + * + * @var MultiCurrencySettingsInterface $settings_service + */ + private $settings_service; + /** * Constructor * - * @param MultiCurrency $multi_currency Instance of MultiCurrency. + * @param MultiCurrency $multi_currency Instance of MultiCurrency. + * @param MultiCurrencySettingsInterface $settings_service Instance of MultiCurrencySettingsInterface. */ - public function __construct( MultiCurrency $multi_currency ) { - $this->multi_currency = $multi_currency; + public function __construct( MultiCurrency $multi_currency, MultiCurrencySettingsInterface $settings_service ) { + $this->multi_currency = $multi_currency; + $this->settings_service = $settings_service; $this->init(); } @@ -63,7 +72,7 @@ public function init() { $this->register_customer_currencies(); } - if ( WC_Payments::mode()->is_dev() ) { + if ( $this->settings_service->is_dev_mode() ) { add_filter( 'woocommerce_analytics_report_should_use_cache', [ $this, 'disable_report_caching' ] ); } @@ -105,7 +114,7 @@ public function init() { * @return void */ public function register_admin_scripts() { - WC_Payments::register_script_with_dependencies( self::SCRIPT_NAME, 'dist/multi-currency-analytics' ); + $this->multi_currency->register_script_with_dependencies( self::SCRIPT_NAME, 'dist/multi-currency-analytics' ); } /** diff --git a/includes/multi-currency/BackendCurrencies.php b/multi-currency/src/BackendCurrencies.php similarity index 91% rename from includes/multi-currency/BackendCurrencies.php rename to multi-currency/src/BackendCurrencies.php index 9ea009ac4c4..bdb2da92b72 100644 --- a/includes/multi-currency/BackendCurrencies.php +++ b/multi-currency/src/BackendCurrencies.php @@ -7,7 +7,7 @@ namespace WCPay\MultiCurrency; -use WC_Payments_Localization_Service; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; defined( 'ABSPATH' ) || exit; @@ -23,9 +23,9 @@ class BackendCurrencies { protected $multi_currency; /** - * WC_Payments_Localization_Service instance. + * MultiCurrencyLocalizationInterface instance. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ protected $localization_service; @@ -39,10 +39,10 @@ class BackendCurrencies { /** * Constructor. * - * @param MultiCurrency $multi_currency The MultiCurrency instance. - * @param WC_Payments_Localization_Service $localization_service The Localization Service instance. + * @param MultiCurrency $multi_currency The MultiCurrency instance. + * @param MultiCurrencyLocalizationInterface $localization_service The Localization Service instance. */ - public function __construct( MultiCurrency $multi_currency, WC_Payments_Localization_Service $localization_service ) { + public function __construct( MultiCurrency $multi_currency, MultiCurrencyLocalizationInterface $localization_service ) { $this->multi_currency = $multi_currency; $this->localization_service = $localization_service; } diff --git a/includes/multi-currency/Compatibility.php b/multi-currency/src/Compatibility.php similarity index 99% rename from includes/multi-currency/Compatibility.php rename to multi-currency/src/Compatibility.php index 4f60915fb97..87e10cbde78 100644 --- a/includes/multi-currency/Compatibility.php +++ b/multi-currency/src/Compatibility.php @@ -7,8 +7,6 @@ namespace WCPay\MultiCurrency; -use WC_Deposits; -use WC_Deposits_Product_Manager; use WC_Order; use WC_Order_Refund; use WCPay\MultiCurrency\Compatibility\BaseCompatibility; @@ -41,7 +39,7 @@ class Compatibility extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { add_action( 'init', [ $this, 'init_compatibility_classes' ], 11 ); if ( defined( 'DOING_CRON' ) ) { diff --git a/includes/multi-currency/Compatibility/BaseCompatibility.php b/multi-currency/src/Compatibility/BaseCompatibility.php similarity index 95% rename from includes/multi-currency/Compatibility/BaseCompatibility.php rename to multi-currency/src/Compatibility/BaseCompatibility.php index a98073fd113..3e7d1a67a20 100644 --- a/includes/multi-currency/Compatibility/BaseCompatibility.php +++ b/multi-currency/src/Compatibility/BaseCompatibility.php @@ -46,5 +46,5 @@ public function __construct( MultiCurrency $multi_currency, Utils $utils ) { * * @return void */ - abstract protected function init(); + abstract public function init(); } diff --git a/includes/multi-currency/Compatibility/WooCommerceBookings.php b/multi-currency/src/Compatibility/WooCommerceBookings.php similarity index 99% rename from includes/multi-currency/Compatibility/WooCommerceBookings.php rename to multi-currency/src/Compatibility/WooCommerceBookings.php index 5a99534e5d6..756e4eef355 100644 --- a/includes/multi-currency/Compatibility/WooCommerceBookings.php +++ b/multi-currency/src/Compatibility/WooCommerceBookings.php @@ -39,7 +39,7 @@ public function __construct( MultiCurrency $multi_currency, Utils $utils, Fronte * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if Bookings is active. if ( class_exists( 'WC_Bookings' ) ) { if ( ! is_admin() || wp_doing_ajax() ) { diff --git a/includes/multi-currency/Compatibility/WooCommerceDeposits.php b/multi-currency/src/Compatibility/WooCommerceDeposits.php similarity index 99% rename from includes/multi-currency/Compatibility/WooCommerceDeposits.php rename to multi-currency/src/Compatibility/WooCommerceDeposits.php index f92819785c5..e2ffa89d441 100644 --- a/includes/multi-currency/Compatibility/WooCommerceDeposits.php +++ b/multi-currency/src/Compatibility/WooCommerceDeposits.php @@ -20,7 +20,7 @@ class WooCommerceDeposits extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { if ( class_exists( 'WC_Deposits' ) ) { /* * Multi-currency support was added to WooCommerce Deposits in version 2.0.1. diff --git a/includes/multi-currency/Compatibility/WooCommerceFedEx.php b/multi-currency/src/Compatibility/WooCommerceFedEx.php similarity index 97% rename from includes/multi-currency/Compatibility/WooCommerceFedEx.php rename to multi-currency/src/Compatibility/WooCommerceFedEx.php index 738e738150f..8a38d058e40 100644 --- a/includes/multi-currency/Compatibility/WooCommerceFedEx.php +++ b/multi-currency/src/Compatibility/WooCommerceFedEx.php @@ -20,7 +20,7 @@ class WooCommerceFedEx extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if FedEx is active. if ( class_exists( 'WC_Shipping_Fedex_Init' ) ) { add_filter( MultiCurrency::FILTER_PREFIX . 'should_return_store_currency', [ $this, 'should_return_store_currency' ] ); diff --git a/includes/multi-currency/Compatibility/WooCommerceNameYourPrice.php b/multi-currency/src/Compatibility/WooCommerceNameYourPrice.php similarity index 99% rename from includes/multi-currency/Compatibility/WooCommerceNameYourPrice.php rename to multi-currency/src/Compatibility/WooCommerceNameYourPrice.php index 155f99e1a4d..fad352e1d1f 100644 --- a/includes/multi-currency/Compatibility/WooCommerceNameYourPrice.php +++ b/multi-currency/src/Compatibility/WooCommerceNameYourPrice.php @@ -21,7 +21,7 @@ class WooCommerceNameYourPrice extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if Name Your Price is active. if ( class_exists( 'WC_Name_Your_Price' ) ) { // Convert meta prices. diff --git a/includes/multi-currency/Compatibility/WooCommercePointsAndRewards.php b/multi-currency/src/Compatibility/WooCommercePointsAndRewards.php similarity index 98% rename from includes/multi-currency/Compatibility/WooCommercePointsAndRewards.php rename to multi-currency/src/Compatibility/WooCommercePointsAndRewards.php index 9d78886eb41..38819d15322 100644 --- a/includes/multi-currency/Compatibility/WooCommercePointsAndRewards.php +++ b/multi-currency/src/Compatibility/WooCommercePointsAndRewards.php @@ -33,7 +33,7 @@ class WooCommercePointsAndRewards extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed filters if Points & Rewards is active and it's not an admin request. if ( is_admin() || ! class_exists( 'WC_Points_Rewards' ) ) { return; diff --git a/includes/multi-currency/Compatibility/WooCommercePreOrders.php b/multi-currency/src/Compatibility/WooCommercePreOrders.php similarity index 96% rename from includes/multi-currency/Compatibility/WooCommercePreOrders.php rename to multi-currency/src/Compatibility/WooCommercePreOrders.php index 3c3fe9d5efc..b16dd91b646 100644 --- a/includes/multi-currency/Compatibility/WooCommercePreOrders.php +++ b/multi-currency/src/Compatibility/WooCommercePreOrders.php @@ -20,7 +20,7 @@ class WooCommercePreOrders extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if Pre-Orders is active. if ( class_exists( 'WC_Pre_Orders' ) ) { add_filter( 'wc_pre_orders_fee', [ $this, 'wc_pre_orders_fee' ] ); diff --git a/includes/multi-currency/Compatibility/WooCommerceProductAddOns.php b/multi-currency/src/Compatibility/WooCommerceProductAddOns.php similarity index 99% rename from includes/multi-currency/Compatibility/WooCommerceProductAddOns.php rename to multi-currency/src/Compatibility/WooCommerceProductAddOns.php index 7d245cd4e4f..add583059f8 100644 --- a/includes/multi-currency/Compatibility/WooCommerceProductAddOns.php +++ b/multi-currency/src/Compatibility/WooCommerceProductAddOns.php @@ -23,7 +23,7 @@ class WooCommerceProductAddOns extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if Product Add Ons is active. if ( class_exists( 'WC_Product_Addons' ) ) { if ( ! is_admin() && ! defined( 'DOING_CRON' ) ) { diff --git a/includes/multi-currency/Compatibility/WooCommerceSubscriptions.php b/multi-currency/src/Compatibility/WooCommerceSubscriptions.php similarity index 97% rename from includes/multi-currency/Compatibility/WooCommerceSubscriptions.php rename to multi-currency/src/Compatibility/WooCommerceSubscriptions.php index 94294827ea9..6701f6739dd 100644 --- a/includes/multi-currency/Compatibility/WooCommerceSubscriptions.php +++ b/multi-currency/src/Compatibility/WooCommerceSubscriptions.php @@ -7,10 +7,8 @@ namespace WCPay\MultiCurrency\Compatibility; -use WC_Payments_Explicit_Price_Formatter; -use WC_Payments_Features; use WC_Subscription; -use WCPay\Logger; +use WCPay\MultiCurrency\Logger; use WCPay\MultiCurrency\FrontendCurrencies; use WCPay\MultiCurrency\MultiCurrency; @@ -61,9 +59,9 @@ class WooCommerceSubscriptions extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if WC Subscriptions or WCPay Subscriptions are active. - if ( class_exists( 'WC_Subscriptions' ) || WC_Payments_Features::is_wcpay_subscriptions_enabled() ) { + if ( class_exists( 'WC_Subscriptions' ) || class_exists( 'WC_Payments_Subscriptions' ) ) { if ( ! is_admin() && ! defined( 'DOING_CRON' ) ) { $this->frontend_currencies = $this->multi_currency->get_frontend_currencies(); @@ -393,6 +391,10 @@ public function maybe_get_explicit_format_for_subscription_total( $html_price, $ return $html_price; } + if ( ! $this->multi_currency->has_additional_currencies_enabled() ) { + return $html_price; + } + /** * Get the currency code from the subscription, then return the explicit price. * Tell Psalm to ignore the WC_Subscription class, this class is only loaded if Subscriptions is active. @@ -400,7 +402,15 @@ public function maybe_get_explicit_format_for_subscription_total( $html_price, $ * @psalm-suppress UndefinedDocblockClass */ $currency_code = $this->current_my_account_subscription->get_currency() ?? get_woocommerce_currency(); - return WC_Payments_Explicit_Price_Formatter::get_explicit_price_with_currency( $html_price, $currency_code ); + + // This is sourced from WC_Payments_Explicit_Price_Formatter::get_explicit_price_with_currency. + $price_to_check = html_entity_decode( wp_strip_all_tags( $html_price ) ); + + if ( false === strpos( $price_to_check, trim( $currency_code ) ) ) { + return $html_price . ' ' . $currency_code; + } + + return $html_price; } /** diff --git a/includes/multi-currency/Compatibility/WooCommerceUPS.php b/multi-currency/src/Compatibility/WooCommerceUPS.php similarity index 97% rename from includes/multi-currency/Compatibility/WooCommerceUPS.php rename to multi-currency/src/Compatibility/WooCommerceUPS.php index 6a53f47bff3..427aa060d52 100644 --- a/includes/multi-currency/Compatibility/WooCommerceUPS.php +++ b/multi-currency/src/Compatibility/WooCommerceUPS.php @@ -20,7 +20,7 @@ class WooCommerceUPS extends BaseCompatibility { * * @return void */ - protected function init() { + public function init() { // Add needed actions and filters if UPS is active. if ( class_exists( 'WC_Shipping_UPS_Init' ) ) { add_filter( MultiCurrency::FILTER_PREFIX . 'should_return_store_currency', [ $this, 'should_return_store_currency' ] ); diff --git a/multi-currency/src/CountryFlags.php b/multi-currency/src/CountryFlags.php new file mode 100644 index 00000000000..286e77dfbe2 --- /dev/null +++ b/multi-currency/src/CountryFlags.php @@ -0,0 +1,301 @@ + '🇦🇩', + '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' => '🇿🇼', + ]; + + /** + * Retrieves a flag by country code. + * + * @param string $country country alpha-2 code (ISO 3166) like US. + * @return string + */ + public static function get_by_country( string $country ): string { + return self::EMOJI_COUNTRIES_FLAGS[ $country ] ?? ''; + } + + /** + * Retrieves a flag by currency code. + * + * @param string $currency currency code (ISO 4217) like USD. + * @return string + */ + public static function get_by_currency( string $currency ): string { + $exceptions = [ + 'ANG' => '', + 'BTC' => '', + 'XAF' => '', + 'XCD' => '', + 'XOF' => '', + 'XPF' => '', + ]; + + $flag = $exceptions[ $currency ] ?? self::get_by_country( substr( $currency, 0, -1 ) ); + + return $flag; + } +} diff --git a/includes/multi-currency/Currency.php b/multi-currency/src/Currency.php similarity index 89% rename from includes/multi-currency/Currency.php rename to multi-currency/src/Currency.php index 0d9ae84da42..37b8fd17d12 100644 --- a/includes/multi-currency/Currency.php +++ b/multi-currency/src/Currency.php @@ -7,8 +7,7 @@ namespace WCPay\MultiCurrency; -use WC_Payments_Localization_Service; -use WC_Payments_Utils; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; defined( 'ABSPATH' ) || exit; @@ -67,21 +66,21 @@ class Currency implements \JsonSerializable { private $last_updated; /** - * Instance of WC_Payments_Localization_Service. + * Instance of MultiCurrencyLocalizationInterface. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ private $localization_service; /** * Constructor. * - * @param WC_Payments_Localization_Service $localization_service Localization service instance. - * @param string $code Three letter currency code. - * @param float $rate The conversion rate. - * @param int|null $last_updated The time this currency was last updated. + * @param MultiCurrencyLocalizationInterface $localization_service Localization service instance. + * @param string $code Three letter currency code. + * @param float $rate The conversion rate. + * @param int|null $last_updated The time this currency was last updated. */ - public function __construct( WC_Payments_Localization_Service $localization_service, $code = '', float $rate = 1.0, $last_updated = null ) { + public function __construct( MultiCurrencyLocalizationInterface $localization_service, $code = '', float $rate = 1.0, $last_updated = null ) { $this->localization_service = $localization_service; $this->code = $code; $this->rate = $rate; diff --git a/includes/multi-currency/CurrencySwitcherBlock.php b/multi-currency/src/CurrencySwitcherBlock.php similarity index 97% rename from includes/multi-currency/CurrencySwitcherBlock.php rename to multi-currency/src/CurrencySwitcherBlock.php index 95d4762365c..e13902c6ede 100644 --- a/includes/multi-currency/CurrencySwitcherBlock.php +++ b/multi-currency/src/CurrencySwitcherBlock.php @@ -7,9 +7,7 @@ namespace WCPay\MultiCurrency; -use WC_Payments; use function http_build_query; -use function implode; use function urldecode; defined( 'ABSPATH' ) || exit; @@ -60,7 +58,7 @@ public function init_hooks() { */ public function init_block_widget() { // Automatically load dependencies and version. - WC_Payments::register_script_with_dependencies( 'woocommerce-payments/multi-currency-switcher', 'dist/multi-currency-switcher-block' ); + $this->multi_currency->register_script_with_dependencies( 'woocommerce-payments/multi-currency-switcher', 'dist/multi-currency-switcher-block' ); register_block_type( 'woocommerce-payments/multi-currency-switcher', diff --git a/includes/multi-currency/CurrencySwitcherWidget.php b/multi-currency/src/CurrencySwitcherWidget.php similarity index 100% rename from includes/multi-currency/CurrencySwitcherWidget.php rename to multi-currency/src/CurrencySwitcherWidget.php diff --git a/includes/multi-currency/Exceptions/InvalidCurrencyException.php b/multi-currency/src/Exceptions/InvalidCurrencyException.php similarity index 71% rename from includes/multi-currency/Exceptions/InvalidCurrencyException.php rename to multi-currency/src/Exceptions/InvalidCurrencyException.php index 454fa1c7383..c3ec9046a27 100644 --- a/includes/multi-currency/Exceptions/InvalidCurrencyException.php +++ b/multi-currency/src/Exceptions/InvalidCurrencyException.php @@ -7,11 +7,11 @@ namespace WCPay\MultiCurrency\Exceptions; -use WCPay\Exceptions\Base_Exception; +use Exception; defined( 'ABSPATH' ) || exit; /** * Exception for throwing errors when an invalid currency is used. */ -class InvalidCurrencyException extends Base_Exception {} +class InvalidCurrencyException extends Exception {} diff --git a/includes/multi-currency/Exceptions/InvalidCurrencyRateException.php b/multi-currency/src/Exceptions/InvalidCurrencyRateException.php similarity index 71% rename from includes/multi-currency/Exceptions/InvalidCurrencyRateException.php rename to multi-currency/src/Exceptions/InvalidCurrencyRateException.php index e80cc0cb92d..6f0b5b2c007 100644 --- a/includes/multi-currency/Exceptions/InvalidCurrencyRateException.php +++ b/multi-currency/src/Exceptions/InvalidCurrencyRateException.php @@ -7,11 +7,11 @@ namespace WCPay\MultiCurrency\Exceptions; -use WCPay\Exceptions\Base_Exception; +use Exception; defined( 'ABSPATH' ) || exit; /** * Exception for throwing errors when an invalid currency rate is used. */ -class InvalidCurrencyRateException extends Base_Exception {} +class InvalidCurrencyRateException extends Exception {} diff --git a/includes/multi-currency/FrontendCurrencies.php b/multi-currency/src/FrontendCurrencies.php similarity index 94% rename from includes/multi-currency/FrontendCurrencies.php rename to multi-currency/src/FrontendCurrencies.php index da1342ac55a..065d0db24a8 100644 --- a/includes/multi-currency/FrontendCurrencies.php +++ b/multi-currency/src/FrontendCurrencies.php @@ -8,7 +8,7 @@ namespace WCPay\MultiCurrency; use WC_Order; -use WC_Payments_Localization_Service; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; defined( 'ABSPATH' ) || exit; @@ -24,9 +24,9 @@ class FrontendCurrencies { protected $multi_currency; /** - * WC_Payments_Localization_Service instance. + * MultiCurrencyLocalizationInterface instance. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ protected $localization_service; @@ -89,12 +89,12 @@ class FrontendCurrencies { /** * Constructor. * - * @param MultiCurrency $multi_currency The MultiCurrency instance. - * @param WC_Payments_Localization_Service $localization_service The Localization Service instance. - * @param Utils $utils Utils instance. - * @param Compatibility $compatibility Compatibility instance. + * @param MultiCurrency $multi_currency The MultiCurrency instance. + * @param MultiCurrencyLocalizationInterface $localization_service The Localization Service instance. + * @param Utils $utils Utils instance. + * @param Compatibility $compatibility Compatibility instance. */ - public function __construct( MultiCurrency $multi_currency, WC_Payments_Localization_Service $localization_service, Utils $utils, Compatibility $compatibility ) { + public function __construct( MultiCurrency $multi_currency, MultiCurrencyLocalizationInterface $localization_service, Utils $utils, Compatibility $compatibility ) { $this->multi_currency = $multi_currency; $this->localization_service = $localization_service; $this->utils = $utils; diff --git a/includes/multi-currency/FrontendPrices.php b/multi-currency/src/FrontendPrices.php similarity index 100% rename from includes/multi-currency/FrontendPrices.php rename to multi-currency/src/FrontendPrices.php diff --git a/includes/multi-currency/Geolocation.php b/multi-currency/src/Geolocation.php similarity index 84% rename from includes/multi-currency/Geolocation.php rename to multi-currency/src/Geolocation.php index 5bd0b48b7db..4f5da245958 100644 --- a/includes/multi-currency/Geolocation.php +++ b/multi-currency/src/Geolocation.php @@ -7,7 +7,7 @@ namespace WCPay\MultiCurrency; -use WC_Payments_Localization_Service; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; defined( 'ABSPATH' ) || exit; @@ -16,18 +16,18 @@ */ class Geolocation { /** - * WC_Payments_Localization_Service instance. + * MultiCurrencyLocalizationInterface instance. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ protected $localization_service; /** * Constructor. * - * @param WC_Payments_Localization_Service $localization_service The Localization Service instance. + * @param MultiCurrencyLocalizationInterface $localization_service The Localization Service instance. */ - public function __construct( WC_Payments_Localization_Service $localization_service ) { + public function __construct( MultiCurrencyLocalizationInterface $localization_service ) { $this->localization_service = $localization_service; } diff --git a/multi-currency/src/Interfaces/MultiCurrencyAccountInterface.php b/multi-currency/src/Interfaces/MultiCurrencyAccountInterface.php new file mode 100644 index 00000000000..b827c5ca3d8 --- /dev/null +++ b/multi-currency/src/Interfaces/MultiCurrencyAccountInterface.php @@ -0,0 +1,61 @@ +log( $level, $message, [ 'source' => self::LOG_FILE ] ); + } +} diff --git a/includes/multi-currency/MultiCurrency.php b/multi-currency/src/MultiCurrency.php similarity index 89% rename from includes/multi-currency/MultiCurrency.php rename to multi-currency/src/MultiCurrency.php index 0d80518298e..56e2b5815b4 100644 --- a/includes/multi-currency/MultiCurrency.php +++ b/multi-currency/src/MultiCurrency.php @@ -7,20 +7,16 @@ namespace WCPay\MultiCurrency; -use WC_Payments; -use WC_Payments_Account; -use WC_Payments_Utils; -use WC_Payments_API_Client; -use WC_Payments_Localization_Service; -use WCPay\Constants\Country_Code; -use WCPay\Constants\Currency_Code; -use WCPay\Exceptions\API_Exception; -use WCPay\Database_Cache; -use WCPay\Logger; use WCPay\MultiCurrency\Exceptions\InvalidCurrencyException; use WCPay\MultiCurrency\Exceptions\InvalidCurrencyRateException; -use WCPay\MultiCurrency\Helpers\OrderMetaHelper; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyApiClientInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyCacheInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencySettingsInterface; +use WCPay\MultiCurrency\Logger; use WCPay\MultiCurrency\Notes\NoteMultiCurrencyAvailable; +use WCPay\MultiCurrency\Utils; defined( 'ABSPATH' ) || exit; @@ -41,13 +37,6 @@ class MultiCurrency { */ public $id = 'wcpay_multi_currency'; - /** - * The single instance of the class. - * - * @var ?MultiCurrency - */ - protected static $instance = null; - /** * Static flag to show if the currencies initialization has been completed * @@ -140,32 +129,39 @@ class MultiCurrency { protected $enabled_currencies; /** - * Client for making requests to the WooCommerce Payments API + * Instance of MultiCurrencySettingsInterface. + * + * @var MultiCurrencySettingsInterface + */ + private $settings_service; + + /** + * Client for making requests to the API * - * @var WC_Payments_API_Client + * @var MultiCurrencyApiClientInterface */ private $payments_api_client; /** - * Instance of WC_Payments_Account. + * Instance of MultiCurrencyAccountInterface. * - * @var WC_Payments_Account + * @var MultiCurrencyAccountInterface */ private $payments_account; /** - * Instance of WC_Payments_Localization_Service. + * Instance of MultiCurrencyLocalizationInterface. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ private $localization_service; /** - * Instance of Database_Cache. + * Instance of MultiCurrencyCacheInterface. * - * @var Database_Cache + * @var MultiCurrencyCacheInterface */ - private $database_cache; + private $cache; /** * Tracking instance. @@ -181,43 +177,23 @@ class MultiCurrency { */ protected $simulation_params = []; - /** - * Instance of OrderMetaHelper. - * - * @var OrderMetaHelper - */ - private $order_meta_helper; - - /** - * Main MultiCurrency Instance. - * - * Ensures only one instance of MultiCurrency is loaded or can be loaded. - * - * @static - * @return MultiCurrency - Main instance. - */ - public static function instance() { - if ( is_null( self::$instance ) ) { - self::$instance = new self( WC_Payments::get_payments_api_client(), WC_Payments::get_account_service(), WC_Payments::get_localization_service(), WC_Payments::get_database_cache() ); - self::$instance->init_hooks(); - } - return self::$instance; - } /** * Class constructor. * - * @param WC_Payments_API_Client $payments_api_client Payments API client. - * @param WC_Payments_Account $payments_account Payments Account instance. - * @param WC_Payments_Localization_Service $localization_service Localization Service instance. - * @param Database_Cache $database_cache Database Cache instance. - * @param Utils|null $utils Optional Utils instance. + * @param MultiCurrencySettingsInterface $settings_service Settings service. + * @param MultiCurrencyApiClientInterface $payments_api_client Payments API client. + * @param MultiCurrencyAccountInterface $payments_account Payments Account instance. + * @param MultiCurrencyLocalizationInterface $localization_service Localization Service instance. + * @param MultiCurrencyCacheInterface $cache Cache instance. + * @param Utils|null $utils Optional Utils instance. */ - public function __construct( WC_Payments_API_Client $payments_api_client, WC_Payments_Account $payments_account, WC_Payments_Localization_Service $localization_service, Database_Cache $database_cache, Utils $utils = null ) { + public function __construct( MultiCurrencySettingsInterface $settings_service, MultiCurrencyApiClientInterface $payments_api_client, MultiCurrencyAccountInterface $payments_account, MultiCurrencyLocalizationInterface $localization_service, MultiCurrencyCacheInterface $cache, Utils $utils = null ) { + $this->settings_service = $settings_service; $this->payments_api_client = $payments_api_client; $this->payments_account = $payments_account; $this->localization_service = $localization_service; - $this->database_cache = $database_cache; + $this->cache = $cache; // If a Utils instance is not passed as argument, initialize it. This allows to mock it in tests. $this->utils = $utils ?? new Utils(); $this->geolocation = new Geolocation( $this->localization_service ); @@ -225,6 +201,19 @@ public function __construct( WC_Payments_API_Client $payments_api_client, WC_Pay $this->currency_switcher_block = new CurrencySwitcherBlock( $this, $this->compatibility ); } + /** + * Backwards compatibility for the old `instance()` static method. + * + * We need to use this as some plugins still call `MultiCurrency::instance()` directly. + * + * @return null|MultiCurrency - Main instance. + */ + public static function instance() { + if ( function_exists( 'WC_Payments_Multi_Currency' ) ) { + return WC_Payments_Multi_Currency(); + } + } + /** * Initializes this class' WP hooks. * @@ -242,9 +231,9 @@ public function init_hooks() { add_action( 'rest_api_init', [ $this, 'init_rest_api' ] ); add_action( 'widgets_init', [ $this, 'init_widgets' ] ); - $is_frontend_request = ! is_admin() && ! defined( 'DOING_CRON' ) && ! WC()->is_rest_api_request(); + $is_frontend_request = ! is_admin() && ! defined( 'DOING_CRON' ) && ! Utils::is_admin_api_request(); - if ( $is_frontend_request || \WC_Payments_Utils::is_store_api_request() ) { + if ( $is_frontend_request || Utils::is_store_api_request() ) { // Make sure that this runs after the main init function. add_action( 'init', [ $this, 'update_selected_currency_by_url' ], 11 ); add_action( 'init', [ $this, 'update_selected_currency_by_geolocation' ], 12 ); @@ -252,7 +241,7 @@ public function init_hooks() { add_action( 'woocommerce_created_customer', [ $this, 'set_new_customer_currency_meta' ] ); } - if ( ! \WC_Payments_Utils::is_store_batch_request() && ! \WC_Payments_Utils::is_store_api_request() && WC()->is_rest_api_request() ) { + if ( ! Utils::is_store_batch_request() && ! Utils::is_store_api_request() && WC()->is_rest_api_request() ) { if ( isset( $_GET['currency'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification $get_currency_from_query_param = function () { $currency = sanitize_text_field( wp_unslash( $_GET['currency'] ) ); // phpcs:ignore WordPress.Security.NonceVerification @@ -298,26 +287,22 @@ public function init() { $this->update_manual_rate_currencies_notice_option(); } - $payment_method_compat = new PaymentMethodsCompatibility( $this, WC_Payments::get_gateway() ); - $admin_notices = new AdminNotices(); - $user_settings = new UserSettings( $this ); - new Analytics( $this ); + $admin_notices = new AdminNotices(); + $user_settings = new UserSettings( $this ); + new Analytics( $this, $this->settings_service ); $this->frontend_prices = new FrontendPrices( $this, $this->compatibility ); $this->frontend_currencies = new FrontendCurrencies( $this, $this->localization_service, $this->utils, $this->compatibility ); $this->backend_currencies = new BackendCurrencies( $this, $this->localization_service ); $this->tracking = new Tracking( $this ); - $this->order_meta_helper = new OrderMetaHelper( $this->payments_api_client ); // Init all of the hooks. - $payment_method_compat->init_hooks(); $admin_notices->init_hooks(); $user_settings->init_hooks(); $this->frontend_prices->init_hooks(); $this->frontend_currencies->init_hooks(); $this->backend_currencies->init_hooks(); $this->tracking->init_hooks(); - $this->order_meta_helper->init_hooks(); add_action( 'woocommerce_order_refunded', [ $this, 'add_order_meta_on_refund' ], 50, 2 ); @@ -328,7 +313,7 @@ public function init() { } if ( is_admin() ) { - add_action( 'admin_init', [ __CLASS__, 'add_woo_admin_notes' ] ); + add_action( 'admin_init', [ $this, 'add_woo_admin_notes' ] ); } // Update the customer currencies option after an order status change. @@ -350,7 +335,7 @@ public function init_rest_api() { return; } - $api_controller = new RestController( \WC_Payments::create_api_client() ); + $api_controller = new RestController( $this ); $api_controller->register_routes(); } @@ -373,19 +358,19 @@ public function init_widgets() { * @return array The new settings pages. */ public function init_settings_pages( $settings_pages ): array { - // We don't need to check if Stripe is connected for the + // We don't need to check if the payment provider is connected for the // Settings page generation on the incoming CLI and async job calls. if ( ( defined( 'WP_CLI' ) && WP_CLI ) || ( defined( 'WPCOM_JOBS' ) && WPCOM_JOBS ) ) { return $settings_pages; } - if ( $this->payments_account->is_stripe_connected() ) { + if ( $this->payments_account->is_provider_connected() ) { $settings = new Settings( $this ); $settings->init_hooks(); $settings_pages[] = $settings; } else { - $settings_onboard_cta = new SettingsOnboardCta( $this ); + $settings_onboard_cta = new SettingsOnboardCta( $this, $this->payments_account ); $settings_onboard_cta->init_hooks(); $settings_pages[] = $settings_onboard_cta; @@ -410,7 +395,7 @@ public function enqueue_admin_scripts() { $this->register_admin_scripts(); wp_enqueue_script( 'WCPAY_MULTI_CURRENCY_SETTINGS' ); - WC_Payments_Utils::enqueue_style( 'WCPAY_MULTI_CURRENCY_SETTINGS' ); + wp_enqueue_style( 'WCPAY_MULTI_CURRENCY_SETTINGS' ); } /** @@ -433,7 +418,7 @@ public function add_props_to_wcpay_js_config( $config ) { */ public function clear_cache() { Logger::debug( 'Clearing the cache to force new rates to be fetched from the server.' ); - $this->database_cache->delete( Database_Cache::CURRENCIES_KEY ); + $this->cache->delete( MultiCurrencyCacheInterface::CURRENCIES_KEY ); } /** @@ -444,14 +429,14 @@ public function clear_cache() { * @return ?array */ public function get_cached_currencies() { - $cached_data = $this->database_cache->get( Database_Cache::CURRENCIES_KEY ); - // If connection to server cannot be established, or if Stripe is not connected, or if the account is rejected, return expired data or null. - if ( ! $this->payments_api_client->is_server_connected() || ! $this->payments_account->is_stripe_connected() || $this->payments_account->is_account_rejected() ) { + $cached_data = $this->cache->get( MultiCurrencyCacheInterface::CURRENCIES_KEY ); + // If connection to server cannot be established, or if payment provider is not connected, or if the account is rejected, return expired data or null. + if ( ! $this->payments_api_client->is_server_connected() || ! $this->payments_account->is_provider_connected() || $this->payments_account->is_account_rejected() ) { return $cached_data ?? null; } - return $this->database_cache->get_or_add( - Database_Cache::CURRENCIES_KEY, + return $this->cache->get_or_add( + MultiCurrencyCacheInterface::CURRENCIES_KEY, function () { try { $currency_data = $this->payments_api_client->get_currency_rates( strtolower( get_woocommerce_currency() ) ); @@ -459,7 +444,7 @@ function () { 'currencies' => $currency_data, 'updated' => time(), ]; - } catch ( API_Exception $e ) { + } catch ( \Exception $e ) { return null; } }, @@ -601,7 +586,7 @@ public function update_single_currency_settings( string $currency_code, string $ if ( ! is_numeric( $manual_rate ) || 0 >= $manual_rate ) { $message = 'Invalid manual currency rate passed to update_single_currency_settings: ' . $manual_rate; Logger::error( $message ); - throw new InvalidCurrencyRateException( esc_html( $message ), 'wcpay_multi_currency_invalid_currency_rate', 500 ); + throw new InvalidCurrencyRateException( esc_html( $message ), 500 ); } update_option( 'wcpay_multi_currency_manual_rate_' . $currency_code, $manual_rate ); } @@ -639,94 +624,6 @@ public function maybe_update_customer_currencies_option( $order_id ) { update_option( self::CUSTOMER_CURRENCIES_KEY, $currencies ); } - /** - * Sets up the available currencies, which are alphabetical by name. - * - * @return void - */ - private function initialize_available_currencies() { - // Add default store currency with a rate of 1.0. - $woocommerce_currency = get_woocommerce_currency(); - $this->available_currencies[ $woocommerce_currency ] = new Currency( $this->localization_service, $woocommerce_currency, 1.0 ); - - $available_currencies = []; - - $currencies = $this->get_account_available_currencies(); - $cache_data = $this->get_cached_currencies(); - - foreach ( $currencies as $currency_code ) { - $currency_rate = $cache_data['currencies'][ $currency_code ] ?? 1.0; - $update_time = $cache_data['updated'] ?? null; - $new_currency = new Currency( $this->localization_service, $currency_code, $currency_rate, $update_time ); - - // Add this to our list of available currencies. - $available_currencies[ $new_currency->get_name() ] = $new_currency; - } - - ksort( $available_currencies ); - - foreach ( $available_currencies as $currency ) { - $this->available_currencies[ $currency->get_code() ] = $currency; - } - } - - /** - * Sets up the enabled currencies. - * - * @return void - */ - private function initialize_enabled_currencies() { - $available_currencies = $this->get_available_currencies(); - $enabled_currency_codes = get_option( $this->id . '_enabled_currencies', [] ); - $enabled_currency_codes = is_array( $enabled_currency_codes ) ? $enabled_currency_codes : []; - $default_code = $this->get_default_currency()->get_code(); - $default = []; - $enabled_currency_codes[] = $default_code; - - // This allows to keep the alphabetical sorting by name. - $enabled_currencies = array_filter( - $available_currencies, - function ( $currency ) use ( $enabled_currency_codes ) { - return in_array( $currency->get_code(), $enabled_currency_codes, true ); - } - ); - - $this->enabled_currencies = []; - - foreach ( $enabled_currencies as $enabled_currency ) { - // Get the charm and rounding for each enabled currency and add the currencies to the object property. - $currency = clone $enabled_currency; - $charm = get_option( $this->id . '_price_charm_' . $currency->get_id(), 0.00 ); - $rounding = get_option( $this->id . '_price_rounding_' . $currency->get_id(), $currency->get_is_zero_decimal() ? '100' : '1.00' ); - $currency->set_charm( $charm ); - $currency->set_rounding( $rounding ); - - // If the currency is set to be manual, set the rate to the stored manual rate. - $type = get_option( $this->id . '_exchange_rate_' . $currency->get_id(), 'automatic' ); - if ( 'manual' === $type ) { - $manual_rate = get_option( $this->id . '_manual_rate_' . $currency->get_id(), $currency->get_rate() ); - $currency->set_rate( $manual_rate ); - } - - $this->enabled_currencies[ $currency->get_code() ] = $currency; - } - - // Set default currency to the top of the list. - $default[ $default_code ] = $this->enabled_currencies[ $default_code ]; - unset( $this->enabled_currencies[ $default_code ] ); - $this->enabled_currencies = array_merge( $default, $this->enabled_currencies ); - } - - /** - * Sets the default currency. - * - * @return void - */ - private function set_default_currency() { - $available_currencies = $this->get_available_currencies(); - $this->default_currency = $available_currencies[ get_woocommerce_currency() ] ?? null; - } - /** * Gets the currencies available. Initializes it if needed. * @@ -981,7 +878,7 @@ public function get_raw_conversion( float $amount, string $to_currency, string $ if ( 0 >= $from_currency_rate ) { $message = 'Invalid rate for from_currency in get_raw_conversion: ' . $from_currency_rate; Logger::error( $message ); - throw new InvalidCurrencyRateException( esc_html( $message ), 'wcpay_multi_currency_invalid_currency_rate', 500 ); + throw new InvalidCurrencyRateException( esc_html( $message ), 500 ); } $amount = $amount * ( $to_currency_rate / $from_currency_rate ); @@ -1057,24 +954,20 @@ public function display_geolocation_currency_update_notice() { } $message = sprintf( - /* translators: %1 User's country, %2 Selected currency name, %3 Default store currency name */ - __( 'We noticed you\'re visiting from %1$s. We\'ve updated our prices to %2$s for your shopping convenience. Use %3$s instead.', 'woocommerce-payments' ), + /* translators: %1 User's country, %2 Selected currency name, %3 Default store currency name, %4 Link to switch currency */ + __( 'We noticed you\'re visiting from %1$s. We\'ve updated our prices to %2$s for your shopping convenience. Use %3$s instead.', 'woocommerce-payments' ), apply_filters( self::FILTER_PREFIX . 'override_notice_country', WC()->countries->countries[ $country ] ), apply_filters( self::FILTER_PREFIX . 'override_notice_currency_name', $current_currency->get_name() ), - $currencies[ $store_currency ] + esc_html( $currencies[ $store_currency ] ), + esc_url( '?currency=' . $store_currency ) ); $notice_id = md5( $message ); echo ''; } @@ -1098,14 +991,14 @@ public function set_new_customer_currency_meta( $customer_id ) { * * @return void */ - public static function add_woo_admin_notes() { + public function add_woo_admin_notes() { // Do not try to add notes on ajax requests to improve their performance. if ( wp_doing_ajax() ) { return; } if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '4.4.0', '>=' ) ) { - NoteMultiCurrencyAvailable::set_account( WC_Payments::get_account_service() ); + NoteMultiCurrencyAvailable::set_account( $this->payments_account ); NoteMultiCurrencyAvailable::possibly_add_note(); } } @@ -1122,284 +1015,130 @@ public static function remove_woo_admin_notes() { } /** - * Gets the price after adjusting it with the rounding and charm settings. - * - * @param float $price The price to be adjusted. - * @param bool $apply_charm_pricing Whether charm pricing should be applied. - * @param Currency $currency The currency to be used when adjusting. + * Checks if the merchant has enabled automatic currency switching and geolocation. * - * @return float The adjusted price. + * @return bool */ - protected function get_adjusted_price( $price, $apply_charm_pricing, $currency ): float { - $price = $this->ceil_price( $price, (float) $currency->get_rounding() ); - - if ( $apply_charm_pricing ) { - $price += (float) $currency->get_charm(); - } - - // Do not return negative prices (possible because of $currency->get_charm()). - return max( 0, $price ); + public function is_using_auto_currency_switching(): bool { + return 'yes' === get_option( $this->id . '_enable_auto_currency', 'no' ); } /** - * Ceils the price to the next number based on the rounding value. - * - * @param float $price The price to be ceiled. - * @param float $rounding The rounding option. + * Checks if the merchant has enabled the currency switcher widget. * - * @return float The ceiled price. + * @return bool */ - protected function ceil_price( float $price, float $rounding ): float { - if ( 0.00 === $rounding ) { - return $price; - } - return ceil( $price / $rounding ) * $rounding; + public function is_using_storefront_switcher(): bool { + return 'yes' === get_option( $this->id . '_enable_storefront_switcher', 'no' ); } /** - * Returns the currency code stored for the user or in the session. + * Gets the store settings. * - * @return string|null Currency code. + * @return array The store settings. */ - private function get_stored_currency_code() { - $user_id = get_current_user_id(); - - if ( $user_id ) { - return get_user_meta( $user_id, self::CURRENCY_META_KEY, true ); - } - - WC()->initialize_session(); - $currency_code = WC()->session->get( self::CURRENCY_SESSION_KEY ); - - return is_string( $currency_code ) ? $currency_code : null; + public function get_settings() { + return [ + $this->id . '_enable_auto_currency' => $this->is_using_auto_currency_switching(), + $this->id . '_enable_storefront_switcher' => $this->is_using_storefront_switcher(), + 'site_theme' => wp_get_theme()->get( 'Name' ), + 'date_format' => esc_attr( get_option( 'date_format', 'F j, Y' ) ), + 'time_format' => esc_attr( get_option( 'time_format', 'g:i a' ) ), + 'store_url' => esc_attr( get_page_uri( wc_get_page_id( 'shop' ) ) ), + ]; } /** - * Checks to see if the store currency has changed. If it has, this will - * also update the option containing the store currency. + * Updates the store settings * - * @return bool + * @param array $params Update requested values. + * + * @return void */ - private function check_store_currency_for_change(): bool { - $last_known_currency = get_option( $this->id . '_store_currency', false ); - $woocommerce_currency = get_woocommerce_currency(); - - // If the last known currency was not set, update the option to set it and return false. - if ( ! $last_known_currency ) { - update_option( $this->id . '_store_currency', $woocommerce_currency ); - return false; - } + public function update_settings( $params ) { + $updateable_options = [ + 'wcpay_multi_currency_enable_auto_currency', + 'wcpay_multi_currency_enable_storefront_switcher', + ]; - if ( $last_known_currency !== $woocommerce_currency ) { - update_option( $this->id . '_store_currency', $woocommerce_currency ); - return true; + foreach ( $updateable_options as $key ) { + if ( isset( $params[ $key ] ) ) { + update_option( $key, sanitize_text_field( $params[ $key ] ) ); + } } - - return false; } /** - * Called when the store currency has changed. Puts any manual rate currencies into an option for a notice to display. + * Apply client order currency format and reduces the rounding precision to 2. * - * @return void + * @return void */ - private function update_manual_rate_currencies_notice_option() { - $enabled_currencies = $this->get_enabled_currencies(); - $manual_currencies = []; - - // Check enabled currencies for manual rates. - foreach ( $enabled_currencies as $currency ) { - $rate_type = get_option( $this->id . '_exchange_rate_' . $currency->get_id(), false ); - if ( 'manual' === $rate_type ) { - $manual_currencies[] = $currency->get_name(); + public function set_client_format_and_rounding_precision() { + $screen = get_current_screen(); + if ( in_array( $screen->id, [ 'shop_order', 'woocommerce_page_wc-orders' ], true ) ) : + $order = wc_get_order(); + if ( ! $order ) { + return; } - } + $currency = $order->get_currency(); + $currency_format_num_decimals = $this->backend_currencies->get_price_decimals( $currency ); + $currency_format_decimal_sep = $this->backend_currencies->get_price_decimal_separator( $currency ); + $currency_format_thousand_sep = $this->backend_currencies->get_price_thousand_separator( $currency ); + $currency_format = str_replace( [ '%1$s', '%2$s', ' ' ], [ '%s', '%v', ' ' ], $this->backend_currencies->get_woocommerce_price_format( $currency ) ); - if ( 0 < count( $manual_currencies ) ) { - update_option( $this->id . '_show_store_currency_changed_notice', $manual_currencies ); - } + $rounding_precision = wc_get_price_decimals() ?? wc_get_rounding_precision(); + ?> + + remove_currency_settings( $currency ); - } + public function register_script_with_dependencies( string $handler, string $script, array $additional_dependencies = [] ) { + $script_file = $script . '.js'; + $script_src_url = plugins_url( $script_file, $this->settings_service->get_plugin_file_path() ); + $script_asset_path = plugin_dir_path( $this->settings_service->get_plugin_file_path() ) . $script . '.asset.php'; + $script_asset = file_exists( $script_asset_path ) ? require $script_asset_path : [ 'dependencies' => [] ]; // nosemgrep: audit.php.lang.security.file.inclusion-arg -- server generated path is used. + $all_dependencies = array_merge( $script_asset['dependencies'], $additional_dependencies ); + + wp_register_script( + $handler, + $script_src_url, + $all_dependencies, + $this->get_file_version( $script_file ), + true + ); } /** - * Will remove a currency's settings if it is not enabled. + * Get the file modified time as a cache buster if we're in dev mode. * - * @param mixed $currency Currency object or 3 letter currency code. + * @param string $file Local path to the file. * - * @return void + * @return string */ - private function remove_currency_settings( $currency ) { - $code = is_a( $currency, Currency::class ) ? $currency->get_code() : strtoupper( $currency ); + public function get_file_version( $file ) { + $plugin_path = plugin_dir_path( $this->settings_service->get_plugin_file_path() ); - // Bail if the currency code passed is not 3 characters, or if the currency is presently enabled. - if ( 3 !== strlen( $code ) || isset( $this->get_enabled_currencies()[ $code ] ) ) { - return; - } - - $settings = [ - 'price_charm', - 'price_rounding', - 'manual_rate', - 'exchange_rate', - ]; - - // Go through each setting and remove them. - foreach ( $settings as $setting ) { - delete_option( $this->id . '_' . $setting . '_' . strtolower( $code ) ); - } - } - - /** - * Returns the currencies enabled for the Stripe account that are - * also available in WC. - * - * Can be filtered with the 'wcpay_multi_currency_available_currencies' hook. - * - * @return array Array with the available currencies' codes. - */ - private function get_account_available_currencies(): array { - // If Stripe is not connected, return an empty array. This prevents using MC without being connected to Stripe. - if ( ! $this->payments_account->is_stripe_connected() ) { - return []; - } - - $wc_currencies = array_keys( get_woocommerce_currencies() ); - $account_currencies = $wc_currencies; - - $account = $this->payments_account->get_cached_account_data(); - $supported_currencies = $this->payments_account->get_account_customer_supported_currencies(); - if ( $account && ! empty( $supported_currencies ) ) { - $account_currencies = array_map( 'strtoupper', $supported_currencies ); - } - - /** - * Filter the available currencies for WooCommerce Multi-Currency. - * - * This filter can be used to modify the currencies available for WC Pay - * Multi-Currency. Currencies have to be added in uppercase and should - * also be available in `get_woocommerce_currencies` for them to work. - * - * @since 2.8.0 - * - * @param array $available_currencies Current available currencies. Calculated based on - * WC Pay's account currencies and WC currencies. - */ - return apply_filters( self::FILTER_PREFIX . 'available_currencies', array_intersect( $account_currencies, $wc_currencies ) ); - } - - /** - * Checks if the merchant has enabled automatic currency switching and geolocation. - * - * @return bool - */ - public function is_using_auto_currency_switching(): bool { - return 'yes' === get_option( $this->id . '_enable_auto_currency', 'no' ); - } - - /** - * Checks if the merchant has enabled the currency switcher widget. - * - * @return bool - */ - public function is_using_storefront_switcher(): bool { - return 'yes' === get_option( $this->id . '_enable_storefront_switcher', 'no' ); - } - - /** - * Gets the store settings. - * - * @return array The store settings. - */ - public function get_settings() { - return [ - $this->id . '_enable_auto_currency' => $this->is_using_auto_currency_switching(), - $this->id . '_enable_storefront_switcher' => $this->is_using_storefront_switcher(), - 'site_theme' => wp_get_theme()->get( 'Name' ), - 'date_format' => esc_attr( get_option( 'date_format', 'F j, Y' ) ), - 'time_format' => esc_attr( get_option( 'time_format', 'g:i a' ) ), - 'store_url' => esc_attr( get_page_uri( wc_get_page_id( 'shop' ) ) ), - ]; - } - - /** - * Updates the store settings - * - * @param array $params Update requested values. - * - * @return void - */ - public function update_settings( $params ) { - $updateable_options = [ - 'wcpay_multi_currency_enable_auto_currency', - 'wcpay_multi_currency_enable_storefront_switcher', - ]; - - foreach ( $updateable_options as $key ) { - if ( isset( $params[ $key ] ) ) { - update_option( $key, sanitize_text_field( $params[ $key ] ) ); - } + if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $plugin_path . $file ) ) { + return (string) filemtime( $plugin_path . trim( $file, '/' ) ); } - } - - /** - * Apply client order currency format and reduces the rounding precision to 2. - * - * @return void - */ - public function set_client_format_and_rounding_precision() { - $screen = get_current_screen(); - if ( in_array( $screen->id, [ 'shop_order', 'woocommerce_page_wc-orders' ], true ) ) : - $order = wc_get_order(); - if ( ! $order ) { - return; - } - $currency = $order->get_currency(); - $currency_format_num_decimals = $this->backend_currencies->get_price_decimals( $currency ); - $currency_format_decimal_sep = $this->backend_currencies->get_price_decimal_separator( $currency ); - $currency_format_thousand_sep = $this->backend_currencies->get_price_thousand_separator( $currency ); - $currency_format = str_replace( [ '%1$s', '%2$s', ' ' ], [ '%s', '%v', ' ' ], $this->backend_currencies->get_woocommerce_price_format( $currency ) ); - - $rounding_precision = wc_get_price_decimals() ?? wc_get_rounding_precision(); - ?> - - settings_service->get_plugin_version(); } /** @@ -1431,52 +1170,6 @@ public function possible_simulation_activation() { $this->simulate_client_currency(); } - /** - * Enables simulation of client browser currency. - * - * @return void - */ - private function simulate_client_currency() { - if ( ! $this->simulation_params['enable_auto_currency'] ) { - return; - } - - $countries = WC_Payments_Utils::supported_countries(); - - $predefined_simulation_currencies = [ - Currency_Code::UNITED_STATES_DOLLAR => $countries[ Country_Code::UNITED_STATES ], - Currency_Code::POUND_STERLING => $countries[ Country_Code::UNITED_KINGDOM ], - ]; - - $simulation_currency = Currency_Code::UNITED_STATES_DOLLAR === get_option( 'woocommerce_currency', Currency_Code::UNITED_STATES_DOLLAR ) ? Currency_Code::POUND_STERLING : Currency_Code::UNITED_STATES_DOLLAR; - $simulation_currency_name = $this->available_currencies[ $simulation_currency ]->get_name(); - $simulation_country = $predefined_simulation_currencies[ $simulation_currency ]; - - // Simulate client currency from geolocation. - add_filter( - 'wcpay_multi_currency_override_notice_currency_name', - function ( $selected_currency_name ) use ( $simulation_currency_name ) { - return $simulation_currency_name; - } - ); - - // Simulate client country from geolocation. - add_filter( - 'wcpay_multi_currency_override_notice_country', - function ( $selected_country ) use ( $simulation_country ) { - return $simulation_country; - } - ); - - // Always display the notice on simulation screen, prevent duplicate hooks. - if ( ! has_action( 'wp_footer', [ $this, 'display_geolocation_currency_update_notice' ] ) ) { - add_action( 'wp_footer', [ $this, 'display_geolocation_currency_update_notice' ] ); - } - - // Skip recalculating the cart to prevent infinite loop in simulation. - remove_action( 'wp_loaded', [ $this, 'recalculate_cart' ] ); - } - /** * Returns whether the simulation querystring param is set and active * @@ -1538,45 +1231,6 @@ public function get_multi_currency_onboarding_simulation_variables() { return $values; } - /** - * Adds the required querystring parameters to all urls in preview pages. - * - * @return void - */ - private function add_simulation_params_to_preview_urls() { - $params = $this->simulation_params; - add_filter( - 'wp_footer', - function () use ( $params ) { - ?> - - ceil_price( $price, (float) $currency->get_rounding() ); + + if ( $apply_charm_pricing ) { + $price += (float) $currency->get_charm(); + } + + // Do not return negative prices (possible because of $currency->get_charm()). + return max( 0, $price ); + } + + /** + * Ceils the price to the next number based on the rounding value. + * + * @param float $price The price to be ceiled. + * @param float $rounding The rounding option. + * + * @return float The ceiled price. + */ + protected function ceil_price( float $price, float $rounding ): float { + if ( 0.00 === $rounding ) { + return $price; + } + return ceil( $price / $rounding ) * $rounding; + } + + /** + * Sets up the available currencies, which are alphabetical by name. + * + * @return void + */ + private function initialize_available_currencies() { + // Add default store currency with a rate of 1.0. + $woocommerce_currency = get_woocommerce_currency(); + $this->available_currencies[ $woocommerce_currency ] = new Currency( $this->localization_service, $woocommerce_currency, 1.0 ); + + $available_currencies = []; + + $currencies = $this->get_account_available_currencies(); + $cache_data = $this->get_cached_currencies(); + + foreach ( $currencies as $currency_code ) { + $currency_rate = $cache_data['currencies'][ $currency_code ] ?? 1.0; + $update_time = $cache_data['updated'] ?? null; + $new_currency = new Currency( $this->localization_service, $currency_code, $currency_rate, $update_time ); + + // Add this to our list of available currencies. + $available_currencies[ $new_currency->get_name() ] = $new_currency; + } + + ksort( $available_currencies ); + + foreach ( $available_currencies as $currency ) { + $this->available_currencies[ $currency->get_code() ] = $currency; + } + } + + /** + * Sets up the enabled currencies. + * + * @return void + */ + private function initialize_enabled_currencies() { + $available_currencies = $this->get_available_currencies(); + $enabled_currency_codes = get_option( $this->id . '_enabled_currencies', [] ); + $enabled_currency_codes = is_array( $enabled_currency_codes ) ? $enabled_currency_codes : []; + $default_code = $this->get_default_currency()->get_code(); + $default = []; + $enabled_currency_codes[] = $default_code; + + // This allows to keep the alphabetical sorting by name. + $enabled_currencies = array_filter( + $available_currencies, + function ( $currency ) use ( $enabled_currency_codes ) { + return in_array( $currency->get_code(), $enabled_currency_codes, true ); + } + ); + + $this->enabled_currencies = []; + + foreach ( $enabled_currencies as $enabled_currency ) { + // Get the charm and rounding for each enabled currency and add the currencies to the object property. + $currency = clone $enabled_currency; + $charm = get_option( $this->id . '_price_charm_' . $currency->get_id(), 0.00 ); + $rounding = get_option( $this->id . '_price_rounding_' . $currency->get_id(), $currency->get_is_zero_decimal() ? '100' : '1.00' ); + $currency->set_charm( $charm ); + $currency->set_rounding( $rounding ); + + // If the currency is set to be manual, set the rate to the stored manual rate. + $type = get_option( $this->id . '_exchange_rate_' . $currency->get_id(), 'automatic' ); + if ( 'manual' === $type ) { + $manual_rate = get_option( $this->id . '_manual_rate_' . $currency->get_id(), $currency->get_rate() ); + $currency->set_rate( $manual_rate ); + } + + $this->enabled_currencies[ $currency->get_code() ] = $currency; + } + + // Set default currency to the top of the list. + $default[ $default_code ] = $this->enabled_currencies[ $default_code ]; + unset( $this->enabled_currencies[ $default_code ] ); + $this->enabled_currencies = array_merge( $default, $this->enabled_currencies ); + } + + /** + * Sets the default currency. + * + * @return void + */ + private function set_default_currency() { + $available_currencies = $this->get_available_currencies(); + $this->default_currency = $available_currencies[ get_woocommerce_currency() ] ?? null; + } + + /** + * Returns the currency code stored for the user or in the session. + * + * @return string|null Currency code. + */ + private function get_stored_currency_code() { + $user_id = get_current_user_id(); + + if ( $user_id ) { + return get_user_meta( $user_id, self::CURRENCY_META_KEY, true ); + } + + WC()->initialize_session(); + $currency_code = WC()->session->get( self::CURRENCY_SESSION_KEY ); + + return is_string( $currency_code ) ? $currency_code : null; + } + + /** + * Checks to see if the store currency has changed. If it has, this will + * also update the option containing the store currency. + * + * @return bool + */ + private function check_store_currency_for_change(): bool { + $last_known_currency = get_option( $this->id . '_store_currency', false ); + $woocommerce_currency = get_woocommerce_currency(); + + // If the last known currency was not set, update the option to set it and return false. + if ( ! $last_known_currency ) { + update_option( $this->id . '_store_currency', $woocommerce_currency ); + return false; + } + + if ( $last_known_currency !== $woocommerce_currency ) { + update_option( $this->id . '_store_currency', $woocommerce_currency ); + return true; + } + + return false; + } + + /** + * Called when the store currency has changed. Puts any manual rate currencies into an option for a notice to display. + * + * @return void + */ + private function update_manual_rate_currencies_notice_option() { + $enabled_currencies = $this->get_enabled_currencies(); + $manual_currencies = []; + + // Check enabled currencies for manual rates. + foreach ( $enabled_currencies as $currency ) { + $rate_type = get_option( $this->id . '_exchange_rate_' . $currency->get_id(), false ); + if ( 'manual' === $rate_type ) { + $manual_currencies[] = $currency->get_name(); + } + } + + if ( 0 < count( $manual_currencies ) ) { + update_option( $this->id . '_show_store_currency_changed_notice', $manual_currencies ); + } + } + + /** + * Accepts an array of currencies that should have their settings removed. + * + * @param array $currencies Array of Currency objects or 3 letter currency codes. + * + * @return void + */ + private function remove_currencies_settings( array $currencies ) { + + foreach ( $currencies as $currency ) { + $this->remove_currency_settings( $currency ); + } + } + + /** + * Will remove a currency's settings if it is not enabled. + * + * @param mixed $currency Currency object or 3 letter currency code. + * + * @return void + */ + private function remove_currency_settings( $currency ) { + $code = is_a( $currency, Currency::class ) ? $currency->get_code() : strtoupper( $currency ); + + // Bail if the currency code passed is not 3 characters, or if the currency is presently enabled. + if ( 3 !== strlen( $code ) || isset( $this->get_enabled_currencies()[ $code ] ) ) { + return; + } + + $settings = [ + 'price_charm', + 'price_rounding', + 'manual_rate', + 'exchange_rate', + ]; + + // Go through each setting and remove them. + foreach ( $settings as $setting ) { + delete_option( $this->id . '_' . $setting . '_' . strtolower( $code ) ); + } + } + + /** + * Returns the currencies enabled for the payment provider account that are + * also available in WC. + * + * Can be filtered with the 'wcpay_multi_currency_available_currencies' hook. + * + * @return array Array with the available currencies' codes. + */ + private function get_account_available_currencies(): array { + // If the payment provider is not connected, return an empty array. This prevents using MC without being connected to the payment provider. + if ( ! $this->payments_account->is_provider_connected() ) { + return []; + } + + $wc_currencies = array_keys( get_woocommerce_currencies() ); + $account_currencies = $wc_currencies; + + $account = $this->payments_account->get_cached_account_data(); + $supported_currencies = $this->payments_account->get_account_customer_supported_currencies(); + if ( $account && ! empty( $supported_currencies ) ) { + $account_currencies = array_map( 'strtoupper', $supported_currencies ); + } + + /** + * Filter the available currencies for WooCommerce Multi-Currency. + * + * This filter can be used to modify the currencies available for WC Pay + * Multi-Currency. Currencies have to be added in uppercase and should + * also be available in `get_woocommerce_currencies` for them to work. + * + * @since 2.8.0 + * + * @param array $available_currencies Current available currencies. Calculated based on + * WC Pay's account currencies and WC currencies. + */ + return apply_filters( self::FILTER_PREFIX . 'available_currencies', array_intersect( $account_currencies, $wc_currencies ) ); + } + + /** + * Register the CSS and JS admin scripts. + * + * @return void + */ + private function register_admin_scripts() { + $this->register_script_with_dependencies( 'WCPAY_MULTI_CURRENCY_SETTINGS', 'dist/multi-currency', [ 'WCPAY_ADMIN_SETTINGS' ] ); + + wp_register_style( + 'WCPAY_MULTI_CURRENCY_SETTINGS', + plugins_url( 'dist/multi-currency.css', $this->settings_service->get_plugin_file_path() ), + [ 'wc-components', 'WCPAY_ADMIN_SETTINGS' ], + $this->get_file_version( 'dist/multi-currency.css' ), + 'all' + ); + } + + /** + * Enables simulation of client browser currency. + * + * @return void + */ + private function simulate_client_currency() { + if ( ! $this->simulation_params['enable_auto_currency'] ) { + return; + } + + $countries = $this->payments_account->get_supported_countries(); + + $predefined_simulation_currencies = [ + 'USD' => $countries['US'], + 'GBP' => $countries['GB'], + ]; + + $simulation_currency = 'USD' === get_option( 'woocommerce_currency', 'USD' ) ? 'GBP' : 'USD'; + $simulation_currency_name = $this->available_currencies[ $simulation_currency ]->get_name(); + $simulation_country = $predefined_simulation_currencies[ $simulation_currency ]; + + // Simulate client currency from geolocation. + add_filter( + 'wcpay_multi_currency_override_notice_currency_name', + function ( $selected_currency_name ) use ( $simulation_currency_name ) { + return $simulation_currency_name; + } + ); + + // Simulate client country from geolocation. + add_filter( + 'wcpay_multi_currency_override_notice_country', + function ( $selected_country ) use ( $simulation_country ) { + return $simulation_country; + } + ); + + // Always display the notice on simulation screen, prevent duplicate hooks. + if ( ! has_action( 'wp_footer', [ $this, 'display_geolocation_currency_update_notice' ] ) ) { + add_action( 'wp_footer', [ $this, 'display_geolocation_currency_update_notice' ] ); + } + + // Skip recalculating the cart to prevent infinite loop in simulation. + remove_action( 'wp_loaded', [ $this, 'recalculate_cart' ] ); + } + + /** + * Adds the required querystring parameters to all urls in preview pages. + * + * @return void + */ + private function add_simulation_params_to_preview_urls() { + $params = $this->simulation_params; + add_filter( + 'wp_footer', + function () use ( $params ) { + ?> + + is_stripe_connected() ) { + if ( is_null( self::$account ) || ! self::$account->is_provider_connected() ) { return; } @@ -80,9 +80,9 @@ public static function possibly_add_note() { /** * Sets the account service instance reference on the class. * - * @param WC_Payments_Account $account account service instance. + * @param MultiCurrencyAccountInterface $account account service instance. */ - public static function set_account( WC_Payments_Account $account ) { + public static function set_account( MultiCurrencyAccountInterface $account ) { self::$account = $account; } } diff --git a/includes/multi-currency/RestController.php b/multi-currency/src/RestController.php similarity index 78% rename from includes/multi-currency/RestController.php rename to multi-currency/src/RestController.php index 0266b5f4e76..df36b1186b4 100644 --- a/includes/multi-currency/RestController.php +++ b/multi-currency/src/RestController.php @@ -1,21 +1,29 @@ multi_currency = $multi_currency; + } + + /** * Configure REST API routes. */ @@ -144,7 +169,7 @@ public function register_routes() { * @return \WP_REST_Response|\WP_Error Array of the store currencies structure. */ public function get_store_currencies() { - return rest_ensure_response( WC_Payments_Multi_Currency()->get_store_currencies() ); + return rest_ensure_response( $this->multi_currency->get_store_currencies() ); } /** @@ -157,10 +182,10 @@ public function get_store_currencies() { public function update_enabled_currencies( $request ) { $enabled = $request->get_param( 'enabled' ); try { - WC_Payments_Multi_Currency()->set_enabled_currencies( $enabled ); + $this->multi_currency->set_enabled_currencies( $enabled ); $response = $this->get_store_currencies(); } catch ( InvalidCurrencyException $e ) { - $response = new \WP_Error( $e->get_error_code(), $e->getMessage() ); + $response = new \WP_Error( $e->getCode(), $e->getMessage() ); } return rest_ensure_response( $response ); } @@ -176,9 +201,9 @@ public function get_single_currency_settings( $request ) { $currency_code = $request->get_param( 'currency_code' ); try { - $response = WC_Payments_Multi_Currency()->get_single_currency_settings( $currency_code ); + $response = $this->multi_currency->get_single_currency_settings( $currency_code ); } catch ( InvalidCurrencyException $e ) { - $response = new \WP_Error( $e->get_error_code(), $e->getMessage() ); + $response = new \WP_Error( $e->getCode(), $e->getMessage() ); } return rest_ensure_response( $response ); @@ -199,10 +224,10 @@ public function update_single_currency_settings( $request ) { $manual_rate = $request->get_param( 'manual_rate' ) ?? null; try { - WC_Payments_Multi_Currency()->update_single_currency_settings( $currency_code, $exchange_rate_type, $price_rounding, $price_charm, $manual_rate ); - $response = WC_Payments_Multi_Currency()->get_single_currency_settings( $currency_code ); - } catch ( Base_Exception $e ) { - $response = new \WP_Error( $e->get_error_code(), $e->getMessage() ); + $this->multi_currency->update_single_currency_settings( $currency_code, $exchange_rate_type, $price_rounding, $price_charm, $manual_rate ); + $response = $this->multi_currency->get_single_currency_settings( $currency_code ); + } catch ( Exception $e ) { + $response = new \WP_Error( $e->getCode(), $e->getMessage() ); } return rest_ensure_response( $response ); @@ -214,7 +239,7 @@ public function update_single_currency_settings( $request ) { * @return \WP_REST_Response|\WP_Error The store settings as an array. */ public function get_settings() { - return rest_ensure_response( WC_Payments_Multi_Currency()->get_settings() ); + return rest_ensure_response( $this->multi_currency->get_settings() ); } /** @@ -226,7 +251,14 @@ public function get_settings() { */ public function update_settings( $request ) { $params = $request->get_params(); - WC_Payments_Multi_Currency()->update_settings( $params ); - return rest_ensure_response( WC_Payments_Multi_Currency()->get_settings() ); + $this->multi_currency->update_settings( $params ); + return rest_ensure_response( $this->multi_currency->get_settings() ); + } + + /** + * Verify access. + */ + public function check_permission() { + return current_user_can( 'manage_woocommerce' ); } } diff --git a/includes/multi-currency/Settings.php b/multi-currency/src/Settings.php similarity index 96% rename from includes/multi-currency/Settings.php rename to multi-currency/src/Settings.php index 11c74d56619..8fe0a4aafcd 100644 --- a/includes/multi-currency/Settings.php +++ b/multi-currency/src/Settings.php @@ -88,7 +88,7 @@ public function wcpay_multi_currency_settings_page() { * Load inline Emoji detection script on multi-currency settings page */ public function maybe_add_print_emoji_detection_script() { - if ( WC_Payments_Multi_Currency()->is_multi_currency_settings_page() ) { + if ( $this->multi_currency->is_multi_currency_settings_page() ) { print_emoji_detection_script(); } } diff --git a/includes/multi-currency/SettingsOnboardCta.php b/multi-currency/src/SettingsOnboardCta.php similarity index 74% rename from includes/multi-currency/SettingsOnboardCta.php rename to multi-currency/src/SettingsOnboardCta.php index ee89ea5638c..59a2eee286f 100644 --- a/includes/multi-currency/SettingsOnboardCta.php +++ b/multi-currency/src/SettingsOnboardCta.php @@ -7,6 +7,8 @@ namespace WCPay\MultiCurrency; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; + defined( 'ABSPATH' ) || exit; /** @@ -27,15 +29,24 @@ class SettingsOnboardCta extends \WC_Settings_Page { */ private $multi_currency; + /** + * Instance of MultiCurrencyAccountInterface. + * + * @var MultiCurrencyAccountInterface + */ + private $payments_account; + /** * Constructor. * - * @param MultiCurrency $multi_currency The MultiCurrency instance. + * @param MultiCurrency $multi_currency The MultiCurrency instance. + * @param MultiCurrencyAccountInterface $payments_account Payments Account instance. */ - public function __construct( MultiCurrency $multi_currency ) { - $this->multi_currency = $multi_currency; - $this->id = $this->multi_currency->id; - $this->label = _x( 'Multi-currency', 'Settings tab label', 'woocommerce-payments' ); + public function __construct( MultiCurrency $multi_currency, MultiCurrencyAccountInterface $payments_account ) { + $this->multi_currency = $multi_currency; + $this->payments_account = $payments_account; + $this->id = $this->multi_currency->id; + $this->label = _x( 'Multi-currency', 'Settings tab label', 'woocommerce-payments' ); parent::__construct(); } @@ -53,7 +64,7 @@ public function init_hooks() { * Output the call to action button if needing to onboard. */ public function currencies_settings_onboarding_cta() { - $href = \WC_Payments_Account::get_connect_page_url(); + $href = $this->payments_account->get_provider_onboarding_page_url(); ?>

    diff --git a/includes/multi-currency/StorefrontIntegration.php b/multi-currency/src/StorefrontIntegration.php similarity index 100% rename from includes/multi-currency/StorefrontIntegration.php rename to multi-currency/src/StorefrontIntegration.php diff --git a/includes/multi-currency/Tracking.php b/multi-currency/src/Tracking.php similarity index 100% rename from includes/multi-currency/Tracking.php rename to multi-currency/src/Tracking.php diff --git a/includes/multi-currency/UserSettings.php b/multi-currency/src/UserSettings.php similarity index 100% rename from includes/multi-currency/UserSettings.php rename to multi-currency/src/UserSettings.php diff --git a/includes/multi-currency/Utils.php b/multi-currency/src/Utils.php similarity index 51% rename from includes/multi-currency/Utils.php rename to multi-currency/src/Utils.php index 64e5356a77a..b0c1fba84ea 100644 --- a/includes/multi-currency/Utils.php +++ b/multi-currency/src/Utils.php @@ -57,7 +57,7 @@ public function is_page_with_vars( array $pages, array $vars ): bool { * @return boolean */ public static function is_admin_api_request(): bool { - return 0 === stripos( wp_get_referer(), admin_url() ) && WC()->is_rest_api_request() && ! \WC_Payments_Utils::is_store_api_request(); + return 0 === stripos( wp_get_referer(), admin_url() ) && WC()->is_rest_api_request() && ! self::is_store_api_request(); } @@ -71,4 +71,39 @@ public static function is_admin_api_request(): bool { public static function set_customer_session_cookie( bool $set ) { WC()->session->set_customer_session_cookie( $set ); } + + /** + * Returns true if the request is a store REST API request. + * + * @return bool + */ + public static function is_store_api_request() { + if ( function_exists( 'WC' ) && method_exists( WC(), 'is_store_api_request' ) ) { + return WC()->is_store_api_request(); + } + // The logic below is sourced from `WC()->is_store_api_request()`. + if ( empty( $_SERVER['REQUEST_URI'] ) ) { + return false; + } + // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + return false !== strpos( $_SERVER['REQUEST_URI'], trailingslashit( rest_get_url_prefix() ) . 'wc/store/' ); + } + + /** + * Returns true if the request that's currently being processed is a Store API batch request, false + * otherwise. + * + * @return bool True if the request is a Store API batch request, false otherwise. + */ + public static function is_store_batch_request(): bool { + if ( isset( $_REQUEST['rest_route'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + $rest_route = sanitize_text_field( $_REQUEST['rest_route'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.NonceVerification + } else { + $url_parts = wp_parse_url( esc_url_raw( $_SERVER['REQUEST_URI'] ?? '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash + $request_path = $url_parts ? rtrim( $url_parts['path'], '/' ) : ''; + $rest_route = str_replace( trailingslashit( rest_get_url_prefix() ), '', $request_path ); + } + + return 1 === preg_match( '@^\/wc\/store(\/v[\d]+)?\/batch@', $rest_route ); + } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 6e21606d2bb..a0bf916f7a9 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -102,7 +102,7 @@ tests/* - includes/multi-currency + multi-currency/src src diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2a5164e8af3..1eb5fab3f04 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -46,13 +46,13 @@ WC_Subscriptions_Product - + \WC_Product_Addons_Helper \WC_Product_Addons_Helper - + \WC_Name_Your_Price_Helpers \WC_Name_Your_Price_Helpers diff --git a/tasks/release.js b/tasks/release.js index 92559af4ffb..72c3eccdef7 100644 --- a/tasks/release.js +++ b/tasks/release.js @@ -14,11 +14,11 @@ const targetFolder = 'release/' + pluginSlug; const filesToCopy = [ 'assets', 'dist', - 'includes', 'i18n', + 'includes', 'languages', - 'src', 'lib', + 'src', 'templates', 'vendor', 'woocommerce-payments.php', @@ -43,6 +43,10 @@ rm( 'dist/*.map' ); // copy the directories to the release folder cp( '-Rf', filesToCopy, targetFolder ); +// copy the multi-currency files +mkdir( '-p', targetFolder + '/multi-currency' ); +cp( '-R', 'multi-currency/src', targetFolder + '/multi-currency/src' ); + const output = fs.createWriteStream( releaseFolder + '/' + pluginSlug + '.zip' ); diff --git a/tests/js/jest.config.js b/tests/js/jest.config.js index 18c11bc9553..03060196d4c 100644 --- a/tests/js/jest.config.js +++ b/tests/js/jest.config.js @@ -2,13 +2,18 @@ const { jsWithBabel: tsjPreset } = require( 'ts-jest/presets' ); module.exports = { rootDir: '../../', - moduleDirectories: [ 'node_modules', '/client' ], + moduleDirectories: [ + 'node_modules', + '/client', + '/multi-currency/client', + ], moduleNameMapper: { '^react$': '/node_modules/react', '^react-dom$': '/node_modules/react-dom', '^moment$': '/node_modules/moment', '^moment-timezone$': '/node_modules/moment-timezone', '^wcpay(.*)$': '/client$1', + '^multi-currency(.*)$': '/multi-currency/client$1', '^iti/utils$': '/node_modules/intl-tel-input/build/js/utils', '^assets(.*?)(\\?.*)?$': '/assets$1', '^@woocommerce/blocks-registry$': diff --git a/tests/unit/multi-currency/compatibility/test-class-woocommerce-subscriptions.php b/tests/unit/multi-currency/compatibility/test-class-woocommerce-subscriptions.php index 5b71b8f8e7f..c2085b1fe5d 100644 --- a/tests/unit/multi-currency/compatibility/test-class-woocommerce-subscriptions.php +++ b/tests/unit/multi-currency/compatibility/test-class-woocommerce-subscriptions.php @@ -6,6 +6,11 @@ */ use WCPay\MultiCurrency\Compatibility\WooCommerceSubscriptions; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyApiClientInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyCacheInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencySettingsInterface; use WCPay\MultiCurrency\MultiCurrency; use WCPay\MultiCurrency\Utils; @@ -62,7 +67,16 @@ class WCPay_Multi_Currency_WooCommerceSubscriptions_Tests extends WCPAY_UnitTest public function set_up() { parent::set_up(); - $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); + $mock_api_client = $this->createMock( MultiCurrencyApiClientInterface::class ); + $mock_account = $this->createMock( MultiCurrencyAccountInterface::class ); + $mock_localization = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_settings = $this->createMock( MultiCurrencySettingsInterface::class ); + + $this->mock_multi_currency = $this->getMockBuilder( MultiCurrency::class ) + ->setConstructorArgs( [ $mock_settings, $mock_api_client, $mock_account, $mock_localization, $mock_cache ] ) + ->getMock(); + $this->mock_utils = $this->createMock( Utils::class ); $this->woocommerce_subscriptions = new WooCommerceSubscriptions( $this->mock_multi_currency, $this->mock_utils ); @@ -828,18 +842,11 @@ public function test_maybe_get_explicit_format_for_subscription_total() { ->willReturn( true ); // Arrange: Set expectation and return for is_initialized and has_additional_currencies_enabled. - $this->mock_multi_currency - ->expects( $this->once() ) - ->method( 'is_initialized' ) - ->willReturn( true ); $this->mock_multi_currency ->expects( $this->once() ) ->method( 'has_additional_currencies_enabled' ) ->willReturn( true ); - // Arrange: Make sure to set our Multi-Currency instance as our mock instance. - WC_Payments_Explicit_Price_Formatter::set_multi_currency_instance( $this->mock_multi_currency ); - // Arrange/Assert: Apply the woocommerce_subscription_price_string_details filter and confirm the filter does not change the passed array. $this->assertSame( [ 1, 2, 3 ], apply_filters( 'woocommerce_subscription_price_string_details', [ 1, 2, 3 ], $mock_subscription ) ); diff --git a/tests/unit/multi-currency/notes/test-class-note-multi-currency-available-test.php b/tests/unit/multi-currency/notes/test-class-note-multi-currency-available-test.php index 5a985dd0511..e434ae9f661 100644 --- a/tests/unit/multi-currency/notes/test-class-note-multi-currency-available-test.php +++ b/tests/unit/multi-currency/notes/test-class-note-multi-currency-available-test.php @@ -6,6 +6,7 @@ */ use WCPay\MultiCurrency\Notes\NoteMultiCurrencyAvailable; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; /** * Class Note_Multi_Currency_Available_Test tests. @@ -55,8 +56,8 @@ public function test_possibly_add_note_without_account() { } public function test_possibly_add_note_with_account_not_connected() { - $account_mock = $this->createMock( WC_Payments_Account::class ); - $account_mock->method( 'is_stripe_connected' )->willReturn( false ); + $account_mock = $this->createMock( MultiCurrencyAccountInterface::class ); + $account_mock->method( 'is_provider_connected' )->willReturn( false ); NoteMultiCurrencyAvailable::set_account( $account_mock ); NoteMultiCurrencyAvailable::possibly_add_note(); @@ -65,8 +66,8 @@ public function test_possibly_add_note_with_account_not_connected() { } public function test_possibly_add_note_with_connected_account() { - $account_mock = $this->createMock( WC_Payments_Account::class ); - $account_mock->method( 'is_stripe_connected' )->willReturn( true ); + $account_mock = $this->createMock( MultiCurrencyAccountInterface::class ); + $account_mock->method( 'is_provider_connected' )->willReturn( true ); NoteMultiCurrencyAvailable::set_account( $account_mock ); NoteMultiCurrencyAvailable::possibly_add_note(); diff --git a/tests/unit/multi-currency/test-class-analytics.php b/tests/unit/multi-currency/test-class-analytics.php index 00b46e2d7ef..178db790140 100644 --- a/tests/unit/multi-currency/test-class-analytics.php +++ b/tests/unit/multi-currency/test-class-analytics.php @@ -1,6 +1,6 @@ create_can_manage_woocommerce_cap_override( true ); add_filter( 'user_has_cap', $cb ); - $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); + $mock_api_client = $this->createMock( MultiCurrencyApiClientInterface::class ); + $mock_account = $this->createMock( MultiCurrencyAccountInterface::class ); + $mock_localization = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_settings = $this->createMock( MultiCurrencySettingsInterface::class ); + + $this->mock_multi_currency = $this->getMockBuilder( MultiCurrency::class ) + ->setConstructorArgs( [ $mock_settings, $mock_api_client, $mock_account, $mock_localization, $mock_cache ] ) + ->getMock(); $this->mock_multi_currency->expects( $this->any() ) ->method( 'get_all_customer_currencies' ) @@ -82,9 +95,12 @@ public function set_up() { ->method( 'get_available_currencies' ) ->willReturn( $this->get_mock_available_currencies() ); - $this->analytics = new Analytics( $this->mock_multi_currency ); + $this->analytics = new Analytics( $this->mock_multi_currency, $mock_settings ); - $this->localization_service = new WC_Payments_Localization_Service(); + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $this->mock_localization_service->expects( $this->any() ) + ->method( 'get_currency_format' ) + ->willReturn( [ 'num_decimals' => 2 ] ); remove_filter( 'user_has_cap', $cb ); } @@ -164,7 +180,7 @@ public function test_update_order_stats_data_with_multi_currency_order_without_m public function test_update_order_stats_data_with_multi_currency_order() { $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $args = $this->order_args_provider( 123, 0, 1, 15.50, 1.50, 0, 14.00 ); $order = wc_create_order(); @@ -179,7 +195,7 @@ public function test_update_order_stats_data_with_multi_currency_order() { public function test_update_order_stats_data_with_large_order() { $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $args = $this->order_args_provider( 123, 0, 1, 130500.75, 20000, 10000, 100500.75 ); $order = wc_create_order(); @@ -194,7 +210,7 @@ public function test_update_order_stats_data_with_large_order() { public function test_update_order_stats_data_with_stripe_exchange_rate() { $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $args = $this->order_args_provider( 123, 0, 1, 15.50, 1.50, 0, 15.00 ); $order = wc_create_order(); @@ -587,14 +603,19 @@ private function create_can_manage_woocommerce_cap_override( bool $can_manage_wo } private function get_mock_available_currencies() { - $this->localization_service = new WC_Payments_Localization_Service(); + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); if ( empty( $this->mock_available_currencies ) ) { + $this->mock_localization_service + ->expects( $this->any() ) + ->method( 'get_currency_format' ) + ->willReturn( [ 'num_decimals' => 2 ] ); + $this->mock_available_currencies = [ - 'GBP' => new Currency( $this->localization_service, 'GBP', 1.2 ), - 'USD' => new Currency( $this->localization_service, 'USD', 1 ), - 'EUR' => new Currency( $this->localization_service, 'EUR', 0.9 ), - 'ISK' => new Currency( $this->localization_service, 'ISK', 30.52 ), - 'NZD' => new Currency( $this->localization_service, 'NZD', 1.4 ), + 'GBP' => new Currency( $this->mock_localization_service, 'GBP', 1.2 ), + 'USD' => new Currency( $this->mock_localization_service, 'USD', 1 ), + 'EUR' => new Currency( $this->mock_localization_service, 'EUR', 0.9 ), + 'ISK' => new Currency( $this->mock_localization_service, 'ISK', 30.52 ), + 'NZD' => new Currency( $this->mock_localization_service, 'NZD', 1.4 ), ]; } diff --git a/tests/unit/multi-currency/test-class-backend-currencies.php b/tests/unit/multi-currency/test-class-backend-currencies.php index 530efc71b7d..8b333c6f189 100644 --- a/tests/unit/multi-currency/test-class-backend-currencies.php +++ b/tests/unit/multi-currency/test-class-backend-currencies.php @@ -6,6 +6,7 @@ */ use WCPay\MultiCurrency\BackendCurrencies; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; use WCPay\MultiCurrency\MultiCurrency; /** @@ -13,9 +14,9 @@ */ class WCPay_Multi_Currency_Backend_Currencies_Tests extends WCPAY_UnitTestCase { /** - * Mock WC_Payments_Localization_Service. + * Mock MultiCurrencyLocalizationInterface. * - * @var WC_Payments_Localization_Service|PHPUnit_Framework_MockObject_MockObject + * @var MultiCurrencyLocalizationInterface|PHPUnit_Framework_MockObject_MockObject */ private $mock_localization_service; @@ -36,7 +37,7 @@ class WCPay_Multi_Currency_Backend_Currencies_Tests extends WCPAY_UnitTestCase { public function set_up() { parent::set_up(); - $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); // Mock admin part. diff --git a/tests/unit/multi-currency/test-class-compatibility.php b/tests/unit/multi-currency/test-class-compatibility.php index cefb478ca50..ae4cc75dc31 100644 --- a/tests/unit/multi-currency/test-class-compatibility.php +++ b/tests/unit/multi-currency/test-class-compatibility.php @@ -7,6 +7,7 @@ use WCPay\MultiCurrency\Compatibility; use WCPay\MultiCurrency\Currency; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; use WCPay\MultiCurrency\MultiCurrency; use WCPay\MultiCurrency\Utils; @@ -36,11 +37,11 @@ class WCPay_Multi_Currency_Compatibility_Tests extends WCPAY_UnitTestCase { private $mock_utils; /** - * WC_Payments_Localization_Service. + * MultiCurrencyLocalizationInterface. * - * @var WC_Payments_Localization_Service + * @var MultiCurrencyLocalizationInterface */ - private $localization_service; + private $mock_localization_service; /** * Pre-test setup @@ -48,10 +49,15 @@ class WCPay_Multi_Currency_Compatibility_Tests extends WCPAY_UnitTestCase { public function set_up() { parent::set_up(); - $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); - $this->mock_utils = $this->createMock( Utils::class ); - $this->compatibility = new Compatibility( $this->mock_multi_currency, $this->mock_utils ); - $this->localization_service = new WC_Payments_Localization_Service(); + $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); + $this->mock_utils = $this->createMock( Utils::class ); + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $this->mock_localization_service + ->method( 'get_currency_format' ) + ->with( 'USD' ) + ->willReturn( [ 'num_decimals' => 2 ] ); + + $this->compatibility = new Compatibility( $this->mock_multi_currency, $this->mock_utils ); } public function test_init_compatibility_classes_does_not_add_classes_if_one_enabled_currencies() { @@ -108,7 +114,7 @@ public function test_filter_woocommerce_order_query_with_order_in_default_curren $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $this->mock_utils->expects( $this->once() ) ->method( 'is_call_in_backtrace' ) @@ -132,7 +138,7 @@ public function test_filter_woocommerce_order_query_with_order_with_no_exchange_ $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $this->mock_utils->expects( $this->once() ) ->method( 'is_call_in_backtrace' ) @@ -153,7 +159,7 @@ public function test_filter_woocommerce_order_query_with_no_meta() { $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $this->mock_utils->expects( $this->once() ) ->method( 'is_call_in_backtrace' ) @@ -177,7 +183,7 @@ public function test_filter_woocommerce_order_query() { $this->mock_multi_currency->expects( $this->once() ) ->method( 'get_default_currency' ) - ->willReturn( new Currency( $this->localization_service, 'USD', 1.0 ) ); + ->willReturn( new Currency( $this->mock_localization_service, 'USD', 1.0 ) ); $this->mock_utils->expects( $this->once() ) ->method( 'is_call_in_backtrace' ) diff --git a/tests/unit/multi-currency/test-class-country-flags.php b/tests/unit/multi-currency/test-class-country-flags.php index 0ebe63fb8ef..cd3adff8feb 100644 --- a/tests/unit/multi-currency/test-class-country-flags.php +++ b/tests/unit/multi-currency/test-class-country-flags.php @@ -5,7 +5,6 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\CountryFlags; /** @@ -13,7 +12,7 @@ */ class Country_Flags_Test extends WCPAY_UnitTestCase { public function test_get_by_country_returns_emoji_flag() { - $this->assertEquals( CountryFlags::get_by_country( Country_Code::UNITED_STATES ), '🇺🇸' ); + $this->assertEquals( CountryFlags::get_by_country( 'US' ), '🇺🇸' ); } public function test_get_by_country_returns_empty_string() { diff --git a/tests/unit/multi-currency/test-class-currency-switcher-block.php b/tests/unit/multi-currency/test-class-currency-switcher-block.php index f716f6dbe75..2ac0a69fa11 100644 --- a/tests/unit/multi-currency/test-class-currency-switcher-block.php +++ b/tests/unit/multi-currency/test-class-currency-switcher-block.php @@ -10,6 +10,7 @@ use WCPay\MultiCurrency\Currency; use WCPay\MultiCurrency\CurrencySwitcherBlock; use WCPay\MultiCurrency\MultiCurrency; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; /** * CurrencySwitcherBlock unit tests. @@ -37,23 +38,25 @@ class WCPay_Multi_Currency_Currency_Switcher_Block_Tests extends WCPAY_UnitTestC protected $mock_currencies; /** - * WC_Payments_Localization_Service. - * - * @var WC_Payments_Localization_Service + * @var MockObject\MultiCurrencyLocalizationInterface */ - private $localization_service; + private $mock_localization_service; public function set_up() { parent::set_up(); - $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); - $this->mock_compatibility = $this->createMock( Compatibility::class ); - $this->localization_service = new WC_Payments_Localization_Service(); - $this->mock_currencies = [ - new Currency( $this->localization_service, 'USD', 1 ), - new Currency( $this->localization_service, 'CAD', 1.206823 ), - new Currency( $this->localization_service, 'GBP', 0.708099 ), - new Currency( $this->localization_service, 'EUR', 0.826381 ), + $this->mock_multi_currency = $this->createMock( MultiCurrency::class ); + $this->mock_compatibility = $this->createMock( Compatibility::class ); + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $this->mock_localization_service + ->method( 'get_currency_format' ) + ->willReturn( [ 'num_decimals' => 2 ] ); + + $this->mock_currencies = [ + new Currency( $this->mock_localization_service, 'USD', 1 ), + new Currency( $this->mock_localization_service, 'CAD', 1.206823 ), + new Currency( $this->mock_localization_service, 'GBP', 0.708099 ), + new Currency( $this->mock_localization_service, 'EUR', 0.826381 ), ]; $this->currency_switcher_block = new CurrencySwitcherBlock( @@ -219,8 +222,8 @@ public function test_render_currency_option_will_escape_output() { ->method( 'get_enabled_currencies' ) ->willReturn( [ - new Currency( $this->localization_service, 'USD' ), - new Currency( $this->localization_service, $currency_code, 1 ), + new Currency( $this->mock_localization_service, 'USD' ), + new Currency( $this->mock_localization_service, $currency_code, 1 ), ] ); @@ -275,7 +278,7 @@ public function test_widget_does_not_render_on_single_currency() { $this->mock_multi_currency ->expects( $this->once() ) ->method( 'get_enabled_currencies' ) - ->willReturn( [ new Currency( $this->localization_service, 'USD' ) ] ); + ->willReturn( [ new Currency( $this->mock_localization_service, 'USD' ) ] ); // Act/Assert: Confirm that when calling the renger method nothing is returned. $this->assertSame( '', $this->currency_switcher_block->render_block_widget( [], '' ) ); diff --git a/tests/unit/multi-currency/test-class-frontend-currencies.php b/tests/unit/multi-currency/test-class-frontend-currencies.php index bb560d8af9c..d63147de225 100644 --- a/tests/unit/multi-currency/test-class-frontend-currencies.php +++ b/tests/unit/multi-currency/test-class-frontend-currencies.php @@ -410,6 +410,7 @@ public function test_rest_api_ensure_should_return_store_currency_and_should_con $_SERVER['REQUEST_URI'] = $request_uri; $mccy = new WCPay\MultiCurrency\MultiCurrency( + WC_Payments::get_settings_service(), WC_Payments::get_payments_api_client(), WC_Payments::get_account_service(), WC_Payments::get_localization_service(), diff --git a/tests/unit/multi-currency/test-class-frontend-prices.php b/tests/unit/multi-currency/test-class-frontend-prices.php index c38d343dcc9..13d6b4bb34d 100644 --- a/tests/unit/multi-currency/test-class-frontend-prices.php +++ b/tests/unit/multi-currency/test-class-frontend-prices.php @@ -5,8 +5,6 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\Constants\Country_Code; - /** * WCPay\MultiCurrency\FrontendPrices unit tests. */ @@ -216,7 +214,7 @@ function () { ); WC()->session->init(); - WC()->customer->set_location( Country_Code::UNITED_STATES, 'CA' ); + WC()->customer->set_location( 'US', 'CA' ); $shipping_method = new \WC_Shipping_Flat_Rate(); $shipping_method->tax_status = 'taxable'; @@ -260,7 +258,7 @@ function () { ); WC()->session->init(); - WC()->customer->set_location( Country_Code::UNITED_STATES, 'CA' ); + WC()->customer->set_location( 'US', '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 b66543dbf67..92b0b50b166 100644 --- a/tests/unit/multi-currency/test-class-geolocation.php +++ b/tests/unit/multi-currency/test-class-geolocation.php @@ -5,8 +5,6 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\Constants\Country_Code; - /** * WCPay\MultiCurrency\Geolocation unit tests. */ @@ -51,10 +49,10 @@ public function test_get_country_by_customer_location_returns_geolocation_countr add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); - $this->assertSame( Country_Code::CANADA, $this->geolocation->get_country_by_customer_location() ); + $this->assertSame( 'CA', $this->geolocation->get_country_by_customer_location() ); } public function test_get_country_by_customer_location_returns_default_country_when_no_geolocation() { @@ -68,20 +66,20 @@ function () { add_filter( 'woocommerce_customer_default_location', function () { - return Country_Code::BRAZIL; + return 'BR'; } ); - $this->assertSame( Country_Code::BRAZIL, $this->geolocation->get_country_by_customer_location() ); + $this->assertSame( 'BR', $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( Country_Code::CANADA )->willReturn( [ 'currency_code' => 'CAD' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'CA' )->willReturn( [ 'currency_code' => 'CAD' ] ); add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -89,7 +87,7 @@ function () { } public function test_get_currency_by_customer_location_returns_default_currency_code() { - $this->mock_localization_service->method( 'get_country_locale_data' )->with( Country_Code::BRAZIL )->willReturn( [ 'currency_code' => 'BRL' ] ); + $this->mock_localization_service->method( 'get_country_locale_data' )->with( 'BR' )->willReturn( [ 'currency_code' => 'BRL' ] ); add_filter( 'woocommerce_geolocate_ip', @@ -100,7 +98,7 @@ function () { add_filter( 'woocommerce_customer_default_location', function () { - return Country_Code::BRAZIL; + return 'BR'; } ); diff --git a/tests/unit/multi-currency/test-class-multi-currency.php b/tests/unit/multi-currency/test-class-multi-currency.php index 023fd92868c..6d4eddaab84 100644 --- a/tests/unit/multi-currency/test-class-multi-currency.php +++ b/tests/unit/multi-currency/test-class-multi-currency.php @@ -5,11 +5,13 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\Constants\Country_Code; use WCPay\MultiCurrency\Utils; -use WCPay\Database_Cache; use WCPay\MultiCurrency\Exceptions\InvalidCurrencyException; use WCPay\MultiCurrency\Exceptions\InvalidCurrencyRateException; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyApiClientInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyCacheInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencySettingsInterface; use WCPay\MultiCurrency\MultiCurrency; use WCPay\MultiCurrency\Settings; use WCPay\MultiCurrency\SettingsOnboardCta; @@ -65,14 +67,14 @@ class WCPay_Multi_Currency_Tests extends WCPAY_UnitTestCase { /** * Mock of the API client. * - * @var WC_Payments_API_Client + * @var MultiCurrencyApiClientInterface */ private $mock_api_client; /** - * Mock of the WC_Payments_Account. + * Mock of the MultiCurrencyAccountInterface. * - * @var WC_Payments_Account + * @var MultiCurrencyAccountInterface */ private $mock_account; @@ -84,11 +86,18 @@ class WCPay_Multi_Currency_Tests extends WCPAY_UnitTestCase { private $localization_service; /** - * Mock of Database_Cache. + * Mock of MultiCurrencyCacheInterface. * - * @var Database_Cache; + * @var MultiCurrencyCacheInterface; */ - private $mock_database_cache; + private $mock_cache; + + /** + * Mock of MultiCurrencySettingsInterface. + * + * @var MultiCurrencySettingsInterface; + */ + private $mock_settings; /** * Mock of Utils. @@ -456,7 +465,7 @@ public function test_update_selected_currency_by_geolocation_does_not_set_sessio add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -473,7 +482,7 @@ public function test_update_selected_currency_by_geolocation_updates_session_whe add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -488,7 +497,7 @@ public function test_update_selected_currency_by_geolocation_displays_notice() { add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -509,7 +518,7 @@ public function test_update_selected_currency_by_geolocation_does_not_update_if_ add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -534,7 +543,7 @@ public function test_display_geolocation_currency_update_notice() { add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::CANADA; + return 'CA'; } ); @@ -544,11 +553,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, Country_Code::UNITED_STATES ); + WC()->session->set( WCPay\MultiCurrency\MultiCurrency::CURRENCY_SESSION_KEY, 'US' ); add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::UNITED_STATES; + return 'US'; } ); @@ -562,7 +571,7 @@ public function test_display_geolocation_currency_update_notice_does_not_display add_filter( 'woocommerce_geolocate_ip', function () { - return Country_Code::UNITED_STATES; + return 'US'; } ); @@ -721,13 +730,13 @@ public function test_get_raw_conversion_throws_exception_on_invalid_from_rate() public function test_get_cached_currencies_with_no_server_connection() { // Need to create a new instance of MultiCurrency with a different $mock_api_client // Because the mock return value of 'is_server_connected' cannot be overridden. - $mock_api_client = $this->createMock( WC_Payments_API_Client::class ); + $mock_api_client = $this->createMock( MultiCurrencyApiClientInterface::class ); $mock_api_client->method( 'is_server_connected' )->willReturn( false ); $this->init_multi_currency( $mock_api_client ); - $this->mock_database_cache->method( 'get' )->willReturn( $this->mock_cached_currencies ); + $this->mock_cache->method( 'get' )->willReturn( $this->mock_cached_currencies ); $this->assertEquals( $this->mock_cached_currencies, @@ -736,7 +745,7 @@ public function test_get_cached_currencies_with_no_server_connection() { } public function test_get_cached_currencies_with_account_rejected() { - $this->mock_database_cache + $this->mock_cache ->expects( $this->once() ) ->method( 'get' ) ->willReturn( null ); @@ -746,7 +755,7 @@ public function test_get_cached_currencies_with_account_rejected() { ->method( 'is_account_rejected' ) ->willReturn( true ); - $this->mock_database_cache + $this->mock_cache ->expects( $this->never() ) ->method( 'get_or_add' ); @@ -758,11 +767,11 @@ public function test_get_cached_currencies_with_account_rejected() { public function test_get_cached_currencies_fetches_from_server() { $get_or_add_call_count = 1; - $mock_database_cache = $this->createMock( Database_Cache::class ); - $mock_database_cache + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_cache ->expects( $this->exactly( 2 ) ) ->method( 'get_or_add' ) - ->with( Database_Cache::CURRENCIES_KEY, $this->anything(), $this->anything() ) + ->with( MultiCurrencyCacheInterface::CURRENCIES_KEY, $this->anything(), $this->anything() ) ->willReturnCallback( function ( $key, $generator, $validator ) use ( &$get_or_add_call_count ) { if ( 1 === $get_or_add_call_count ) { @@ -776,7 +785,7 @@ function ( $key, $generator, $validator ) use ( &$get_or_add_call_count ) { } ); - $this->init_multi_currency( null, true, null, $mock_database_cache ); + $this->init_multi_currency( null, true, null, $mock_cache ); $currency_from = strtolower( get_woocommerce_currency() ); $currencies_to = get_woocommerce_currencies(); @@ -886,7 +895,7 @@ public function test_enabled_currencies_option_as_string_does_not_fatal() { public function test_get_cached_currencies_with_no_stripe_connection() { $this->init_multi_currency( null, false ); - $this->mock_database_cache->method( 'get' )->willReturn( $this->mock_cached_currencies ); + $this->mock_cache->method( 'get' )->willReturn( $this->mock_cached_currencies ); $this->assertEquals( $this->mock_cached_currencies, $this->multi_currency->get_cached_currencies() @@ -1051,14 +1060,14 @@ public function test_get_all_customer_currencies() { $mock_orders[] = $this->add_mock_order_with_currency_meta( 'EUR' ); $mock_orders[] = $this->add_mock_order_with_currency_meta( 'USD' ); - $mock_database_cache = $this->createMock( Database_Cache::class ); - $mock_database_cache + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_cache ->expects( $this->once() ) ->method( 'get_or_add' ) - ->with( Database_Cache::CURRENCIES_KEY, $this->anything(), $this->anything() ) + ->with( MultiCurrencyCacheInterface::CURRENCIES_KEY, $this->anything(), $this->anything() ) ->willReturn( $this->mock_cached_currencies ); - $this->init_multi_currency( null, true, null, $mock_database_cache ); + $this->init_multi_currency( null, true, null, $mock_cache ); $result = $this->multi_currency->get_all_customer_currencies(); @@ -1073,14 +1082,14 @@ public function test_get_all_customer_currencies_with_option_data() { $mock_option_data = [ 'GBP', 'EUR', 'USD' ]; update_option( MultiCurrency::CUSTOMER_CURRENCIES_KEY, $mock_option_data ); - $mock_database_cache = $this->createMock( Database_Cache::class ); - $mock_database_cache + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_cache ->expects( $this->once() ) ->method( 'get_or_add' ) - ->with( Database_Cache::CURRENCIES_KEY, $this->anything(), $this->anything() ) + ->with( MultiCurrencyCacheInterface::CURRENCIES_KEY, $this->anything(), $this->anything() ) ->willReturn( $this->mock_cached_currencies ); - $this->init_multi_currency( null, true, null, $mock_database_cache ); + $this->init_multi_currency( null, true, null, $mock_cache ); $result = $this->multi_currency->get_all_customer_currencies(); @@ -1103,14 +1112,14 @@ public function test_get_all_customer_currencies_with_invalid_option_data( $opti $mock_orders[] = $this->add_mock_order_with_currency_meta( 'EUR' ); $mock_orders[] = $this->add_mock_order_with_currency_meta( 'USD' ); - $mock_database_cache = $this->createMock( Database_Cache::class ); - $mock_database_cache + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_cache ->expects( $this->once() ) ->method( 'get_or_add' ) - ->with( Database_Cache::CURRENCIES_KEY, $this->anything(), $this->anything() ) + ->with( MultiCurrencyCacheInterface::CURRENCIES_KEY, $this->anything(), $this->anything() ) ->willReturn( $this->mock_cached_currencies ); - $this->init_multi_currency( null, true, null, $mock_database_cache ); + $this->init_multi_currency( null, true, null, $mock_cache ); $result = $this->multi_currency->get_all_customer_currencies(); @@ -1414,31 +1423,31 @@ private function remove_currency_settings_mock( $currency_code, $settings ) { } } - private function init_multi_currency( $mock_api_client = null, $wcpay_account_connected = true, $mock_account = null, $mock_database_cache = null ) { - $this->mock_api_client = $this->createMock( WC_Payments_API_Client::class ); + private function init_multi_currency( $mock_api_client = null, $wcpay_account_connected = true, $mock_account = null, $mock_cache = null ) { + $this->mock_api_client = $this->createMock( MultiCurrencyApiClientInterface::class ); - $this->mock_account = $mock_account ?? $this->createMock( WC_Payments_Account::class ); - $this->mock_account->method( 'is_stripe_connected' )->willReturn( $wcpay_account_connected ); + $this->mock_account = $mock_account ?? $this->createMock( MultiCurrencyAccountInterface::class ); + $this->mock_account->method( 'is_provider_connected' )->willReturn( $wcpay_account_connected ); $this->mock_api_client->method( 'is_server_connected' )->willReturn( true ); - $this->mock_database_cache = $this->createMock( Database_Cache::class ); - $this->mock_database_cache->method( 'get_or_add' )->willReturn( $this->mock_cached_currencies ); + $this->mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $this->mock_cache->method( 'get_or_add' )->willReturn( $this->mock_cached_currencies ); $this->mock_utils = $this->createMock( Utils::class ); + $this->mock_settings = $this->createMock( MultiCurrencySettingsInterface::class ); + $this->multi_currency = new MultiCurrency( + $this->mock_settings, $mock_api_client ?? $this->mock_api_client, $this->mock_account, $this->localization_service, - $mock_database_cache ?? $this->mock_database_cache, + $mock_cache ?? $this->mock_cache, $this->mock_utils ); $this->multi_currency->init_widgets(); $this->multi_currency->init(); - - // Fix an issue in WPCOM tests. - WC_Payments_Explicit_Price_Formatter::set_multi_currency_instance( $this->multi_currency ); } private function add_mock_order_with_currency_meta( $currency ) { diff --git a/tests/unit/multi-currency/test-class-rest-controller.php b/tests/unit/multi-currency/test-class-rest-controller.php index 49ac60ad1be..661b991df52 100644 --- a/tests/unit/multi-currency/test-class-rest-controller.php +++ b/tests/unit/multi-currency/test-class-rest-controller.php @@ -5,6 +5,13 @@ * @package WooCommerce\Payments\Tests */ +use PHPUnit\Framework\MockObject\MockObject; +use WCPay\MultiCurrency\Currency; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyAccountInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyApiClientInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyCacheInterface; +use WCPay\MultiCurrency\Interfaces\MultiCurrencyLocalizationInterface; +use WCPay\MultiCurrency\MultiCurrency; use WCPay\MultiCurrency\RestController; /** @@ -24,6 +31,27 @@ class WCPay_Multi_Currency_Rest_Controller_Tests extends WCPAY_UnitTestCase { */ private $controller; + /** + * Mock MultiCurrency. + * + * @var MultiCurrency|MockObject + */ + private $mock_multi_currency; + + /** + * The localization service. + * + * @var MultiCurrencyLocalizationInterface + */ + private $mock_localization_service; + + /** + * Mock available currencies. + * + * @var array An array of available currencies. + */ + private $mock_available_currencies = []; + /** * Pre-test setup */ @@ -33,13 +61,48 @@ public function set_up() { // Set the user so that we can pass the authentication. wp_set_current_user( 1 ); - $mock_api_client = $this->getMockBuilder( WC_Payments_API_Client::class )->disableOriginalConstructor()->getMock(); - $this->controller = new RestController( $mock_api_client ); + $mock_api_client = $this->createMock( MultiCurrencyApiClientInterface::class ); + $mock_account = $this->createMock( MultiCurrencyAccountInterface::class ); + $mock_localization = $this->createMock( MultiCurrencyLocalizationInterface::class ); + $mock_cache = $this->createMock( MultiCurrencyCacheInterface::class ); + $mock_settings = $this->createMock( WC_Payments_Settings_Service::class ); + + $mock_account->method( 'is_provider_connected' )->willReturn( true ); + $mock_api_client->method( 'is_server_connected' )->willReturn( true ); + + $mock_localization + ->method( 'get_currency_format' ) + ->willReturn( + [ + 'currency_pos' => 'right_space', + 'num_decimals' => 2, + ] + ); + + $this->mock_multi_currency = $this->getMockBuilder( MultiCurrency::class ) + ->setConstructorArgs( [ $mock_settings, $mock_api_client, $mock_account, $mock_localization, $mock_cache ] ) + ->enableOriginalConstructor() + ->onlyMethods( [ 'get_available_currencies' ] ) + ->getMock(); + + $this->mock_multi_currency->expects( $this->any() ) + ->method( 'get_available_currencies' ) + ->willReturn( $this->get_mock_available_currencies() ); + + $this->controller = new RestController( $this->mock_multi_currency ); + } + + /** + * Post-test teardown + */ + public function tear_down() { + remove_all_filters( 'wcpay_multi_currency_available_currencies' ); + parent::tear_down(); } public function test_get_store_currencies_gets_expected_response() { // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_store_currencies() ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_store_currencies() ); // Act: Get the store currencies. $response = $this->controller->get_store_currencies(); @@ -56,7 +119,7 @@ public function test_get_store_currencies_gets_expected_response() { */ public function test_update_enabled_currencies_updates_currencies() { // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_store_currencies() ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_store_currencies() ); // Arrange: Delete the enabled currencies option. delete_option( 'wcpay_multi_currency_enabled_currencies' ); @@ -82,9 +145,8 @@ public function test_update_enabled_currencies_throws_exception_on_unavailable_c $error_currencies = [ 'EUR', 'GBP', 'banana' ]; // Arrange: Set expected result. - $error_code = 'wcpay_multi_currency_invalid_currency'; $error_message = 'Invalid currency passed to set_enabled_currencies: ' . implode( ', ', $error_currencies ); - $expected = rest_ensure_response( new WP_Error( $error_code, $error_message ) ); + $expected = rest_ensure_response( new WP_Error( 500, $error_message ) ); // Arrange: Create the new REST request. $request = new WP_REST_Request( 'POST', self::ROUTE . '/update-enabled-currencies' ); @@ -110,7 +172,7 @@ public function test_get_single_currency_settings() { update_option( 'wcpay_multi_currency_price_charm_usd', 0 ); // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_single_currency_settings( 'USD' ) ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_single_currency_settings( 'USD' ) ); // Arrange: Create the new REST request. $request = new WP_REST_Request( 'GET', self::ROUTE . '/currencies/USD' ); @@ -129,9 +191,8 @@ public function test_get_single_currency_settings() { public function test_get_single_currency_settings_throws_exception_on_unavailable_currency() { // Arrange: Set expected result. - $error_code = 'wcpay_multi_currency_invalid_currency'; $error_message = 'Invalid currency passed to get_single_currency_settings: AAA'; - $expected = rest_ensure_response( new WP_Error( $error_code, $error_message ) ); + $expected = rest_ensure_response( new WP_Error( 500, $error_message ) ); // Arrange: Create the new REST request. $request = new WP_REST_Request( 'GET', self::ROUTE . '/currencies/AAA' ); @@ -162,7 +223,7 @@ public function test_update_single_currency_settings() { update_option( 'wcpay_multi_currency_price_charm_usd', 0 ); // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_single_currency_settings( 'USD' ) ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_single_currency_settings( 'USD' ) ); // Arrange: Now remove all the options. delete_option( 'wcpay_multi_currency_exchange_rate_usd' ); @@ -191,9 +252,8 @@ public function test_update_single_currency_settings() { public function test_update_single_currency_settings_throws_exception_on_unavailable_currency() { // Arrange: Set expected result. - $error_code = 'wcpay_multi_currency_invalid_currency'; $error_message = 'Invalid currency passed to update_single_currency_settings: AAA'; - $expected = rest_ensure_response( new WP_Error( $error_code, $error_message ) ); + $expected = rest_ensure_response( new WP_Error( 500, $error_message ) ); // Arrange: Create the new REST request. $request = new WP_REST_Request( 'POST', self::ROUTE . '/currencies/AAA' ); @@ -220,9 +280,8 @@ public function test_update_single_currency_settings_throws_exception_on_unavail */ public function test_update_single_currency_settings_throws_exception_on_invalid_currency_rate( $manual_rate ) { // Arrange: Set expected result. - $error_code = 'wcpay_multi_currency_invalid_currency_rate'; $error_message = 'Invalid manual currency rate passed to update_single_currency_settings: ' . $manual_rate; - $expected = rest_ensure_response( new WP_Error( $error_code, $error_message ) ); + $expected = rest_ensure_response( new WP_Error( 500, $error_message ) ); // Arrange: Create the new REST request. $request = new WP_REST_Request( 'POST', self::ROUTE . '/currencies/USD' ); @@ -260,7 +319,7 @@ public function update_single_currency_settings_throws_exception_on_invalid_curr public function test_get_settings_gets_expected_response() { // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_settings() ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_settings() ); // Act: Get the settings. $response = $this->controller->get_settings(); @@ -275,7 +334,7 @@ public function test_update_multi_currency_settings() { update_option( 'wcpay_multi_currency_enable_storefront_switcher', 'yes' ); // Arrange: Create expected response. - $expected = rest_ensure_response( WC_Payments_Multi_Currency()->get_settings() ); + $expected = rest_ensure_response( $this->mock_multi_currency->get_settings() ); // Arrange: Now remove all the options. delete_option( 'wcpay_multi_currency_enable_auto_currency' ); @@ -296,4 +355,20 @@ public function test_update_multi_currency_settings() { // Assert: Confirm the response is what we expected. $this->assertEquals( $expected, $response ); } + + private function get_mock_available_currencies() { + $this->mock_localization_service = $this->createMock( MultiCurrencyLocalizationInterface::class ); + if ( empty( $this->mock_available_currencies ) ) { + $this->mock_localization_service + ->expects( $this->any() ) + ->method( 'get_currency_format' ) + ->willReturn( [ 'num_decimals' => 2 ] ); + + $this->mock_available_currencies = [ + 'USD' => new Currency( $this->mock_localization_service, 'USD', 1 ), + ]; + } + + return $this->mock_available_currencies; + } } diff --git a/tests/unit/multi-currency/test-class-settings.php b/tests/unit/multi-currency/test-class-settings.php index 1ccbd373a0c..272a691910b 100644 --- a/tests/unit/multi-currency/test-class-settings.php +++ b/tests/unit/multi-currency/test-class-settings.php @@ -5,8 +5,6 @@ * @package WooCommerce\Payments\Tests */ -use WCPay\MultiCurrency\Currency; - /** * WCPay\MultiCurrency\Settings unit tests. */ diff --git a/tests/unit/multi-currency/test-class-utils.php b/tests/unit/multi-currency/test-class-utils.php index 1f3c9cce762..553df2a0cc1 100644 --- a/tests/unit/multi-currency/test-class-utils.php +++ b/tests/unit/multi-currency/test-class-utils.php @@ -60,8 +60,7 @@ public function test_is_admin_api_request_returns_true() { public function test_is_admin_api_request_returns_false_with_store_api() { $_SERVER['HTTP_REFERER'] = 'http://example.org/wp-admin/'; - $_REQUEST['rest_route'] = '/wc/store/v1/checkout'; - $_SERVER['REQUEST_URI'] = trailingslashit( rest_get_url_prefix() ); + $_SERVER['REQUEST_URI'] = trailingslashit( rest_get_url_prefix() ) . 'wc/store/v1/checkout'; $this->assertFalse( $this->utils->is_admin_api_request() ); diff --git a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php b/tests/unit/test-class-wc-payments-currency-manager.php similarity index 84% rename from tests/unit/multi-currency/test-class-payment-methods-compatibility.php rename to tests/unit/test-class-wc-payments-currency-manager.php index bdbbb767cde..6f13664ec75 100644 --- a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php +++ b/tests/unit/test-class-wc-payments-currency-manager.php @@ -1,14 +1,14 @@ multi_currency_mock = $this - ->getMockBuilder( WCPay\MultiCurrency\MultiCurrency::class ) + $this->multi_currency_mock = $this->getMockBuilder( WCPay\MultiCurrency\MultiCurrency::class ) ->disableOriginalConstructor() ->setMethods( [ @@ -68,8 +67,16 @@ public function set_up() { ->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(); + $this->currency_manager = $this->getMockBuilder( \WCPay\WC_Payments_Currency_Manager::class ) + ->setConstructorArgs( [ $this->gateway_mock ] ) + ->setMethods( [ 'get_multi_currency_instance' ] ) + ->getMock(); + + // Mocking get_multi_currency_instance to return the multi_currency_mock. + $this->currency_manager->method( 'get_multi_currency_instance' ) + ->willReturn( $this->multi_currency_mock ); + + $this->currency_manager->init_hooks(); $this->localization_service = new WC_Payments_Localization_Service(); } @@ -79,7 +86,7 @@ public function test_it_should_not_update_available_currencies_when_enabled_paym $this->gateway_mock->expects( $this->atLeastOnce() )->method( 'get_upe_enabled_payment_method_ids' )->willReturn( [ 'card' ] ); $this->gateway_mock->expects( $this->atLeastOnce() )->method( 'get_account_domestic_currency' )->willReturn( 'USD' ); - $this->payment_methods_compatibility->add_missing_currencies(); + $this->currency_manager->maybe_add_missing_currencies(); } public function test_it_should_not_update_available_currencies_when_not_needed() { @@ -107,7 +114,7 @@ public function test_it_should_not_update_available_currencies_when_not_needed() ); $this->multi_currency_mock->expects( $this->never() )->method( 'set_enabled_currencies' ); - $this->payment_methods_compatibility->add_missing_currencies(); + $this->currency_manager->maybe_add_missing_currencies(); } public function test_it_should_update_available_currencies_when_needed() { @@ -147,7 +154,7 @@ public function test_it_should_update_available_currencies_when_needed() { ) ); - $this->payment_methods_compatibility->add_missing_currencies(); + $this->currency_manager->maybe_add_missing_currencies(); } public function test_it_should_not_update_available_currencies_with_bnpl_methods() { @@ -173,7 +180,7 @@ public function test_it_should_not_update_available_currencies_with_bnpl_methods ); $this->multi_currency_mock->expects( $this->never() )->method( 'set_enabled_currencies' ); - $this->payment_methods_compatibility->add_missing_currencies(); + $this->currency_manager->maybe_add_missing_currencies(); } public function test_it_should_update_available_currencies_with_bnpl_methods() { @@ -207,6 +214,6 @@ public function test_it_should_update_available_currencies_with_bnpl_methods() { ) ); - $this->payment_methods_compatibility->add_missing_currencies(); + $this->currency_manager->maybe_add_missing_currencies(); } } diff --git a/tests/unit/test-class-wc-payments-explicit-price-formatter.php b/tests/unit/test-class-wc-payments-explicit-price-formatter.php index 9c32f3afdb5..728099e4473 100644 --- a/tests/unit/test-class-wc-payments-explicit-price-formatter.php +++ b/tests/unit/test-class-wc-payments-explicit-price-formatter.php @@ -78,6 +78,13 @@ class WC_Payments_Explicit_Price_Formatter_Test extends WCPAY_UnitTestCase { */ private $mock_localization_service; + /** + * Mock of the WC_Payments_Settings_Service. + * + * @var WC_Payments_Settings_Service + */ + private $mock_settings; + /** * Mock of Database_Cache. * @@ -230,7 +237,7 @@ private function init_multi_currency( $mock_api_client = null, $wcpay_account_co $this->mock_api_client = $this->createMock( WC_Payments_API_Client::class ); $this->mock_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_account->method( 'is_stripe_connected' )->willReturn( $wcpay_account_connected ); + $this->mock_account->method( 'is_provider_connected' )->willReturn( $wcpay_account_connected ); $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); @@ -247,8 +254,9 @@ private function init_multi_currency( $mock_api_client = null, $wcpay_account_co $this->mock_database_cache = $this->createMock( Database_Cache::class ); $this->mock_database_cache->method( 'get_or_add' )->willReturn( $this->mock_cached_currencies ); + $this->mock_settings = $this->createMock( WC_Payments_Settings_Service::class ); - $this->multi_currency = new MultiCurrency( $mock_api_client ?? $this->mock_api_client, $this->mock_account, $this->mock_localization_service, $this->mock_database_cache ); + $this->multi_currency = new MultiCurrency( $this->mock_settings, $mock_api_client ?? $this->mock_api_client, $this->mock_account, $this->mock_localization_service, $this->mock_database_cache ); $this->multi_currency->init(); WC_Payments_Explicit_Price_Formatter::set_multi_currency_instance( $this->multi_currency ); diff --git a/tsconfig.json b/tsconfig.json index 3b9efabf45e..f7f56cddd52 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,8 +15,9 @@ "paths": { "assets/*": [ "../assets/*" ], "wcpay/*": [ "./*" ], + "multi-currency/*": [ "../multi-currency/client/*" ], "iti/utils": [ "../node_modules/intl-tel-input/build/js/utils" ], - "react": ["../node_modules/@types/react"] + "react": [ "../node_modules/@types/react" ] }, "types": [ "node", diff --git a/webpack/shared.js b/webpack/shared.js index 7ef039967cd..55c249694ea 100644 --- a/webpack/shared.js +++ b/webpack/shared.js @@ -26,11 +26,11 @@ module.exports = { 'subscription-edit-page': './client/subscription-edit-page.js', tos: './client/tos/index.js', 'payment-gateways': './client/payment-gateways/index.js', - 'multi-currency': './client/multi-currency/index.js', + 'multi-currency': './multi-currency/client/index.js', 'multi-currency-switcher-block': - './client/multi-currency/blocks/currency-switcher.js', + './multi-currency/client/blocks/currency-switcher.js', 'multi-currency-analytics': - './client/multi-currency-analytics/index.js', + './multi-currency/client/analytics/index.js', order: './client/order/index.js', 'subscriptions-empty-state': './client/subscriptions-empty-state/index.js', @@ -113,9 +113,18 @@ module.exports = { }, resolve: { extensions: [ '.ts', '.tsx', '.json', '.js', '.jsx' ], - modules: [ path.join( process.cwd(), 'client' ), 'node_modules' ], + modules: [ + path.join( process.cwd(), 'client' ), + path.join( process.cwd(), 'multi-currency', 'client' ), + 'node_modules', + ], alias: { assets: path.resolve( process.cwd(), 'assets' ), + 'multi-currency': path.resolve( + process.cwd(), + 'multi-currency', + 'client' + ), wcpay: path.resolve( process.cwd(), 'client' ), iti: path.resolve( process.cwd(),