+
$currency_code,
],
];
+
+ $product_price = $product_variations['base_product']['amount'];
+
foreach ( $product->get_children() as $variation_id ) {
$variation = wc_get_product( $variation_id );
if ( $variation ) {
@@ -98,11 +101,13 @@ public function init() {
'amount' => WC_Payments_Utils::prepare_amount( $price, $currency_code ),
'currency' => $currency_code,
];
+
+ $product_price = $product_variations['base_product']['amount'];
}
}
}
- $enabled_upe_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout();
+ $enabled_upe_payment_methods = $this->gateway->get_upe_enabled_payment_method_ids();
// Filter non BNPL out of the list of payment methods.
$bnpl_payment_methods = array_intersect( $enabled_upe_payment_methods, Payment_Method::BNPL_PAYMENT_METHODS );
@@ -118,26 +123,36 @@ public function init() {
WC_Payments::get_file_version( 'dist/product-details.css' ),
);
+ $country = empty( $billing_country ) ? $store_country : $billing_country;
+
+ $script_data = [
+ 'productId' => 'base_product',
+ 'productVariations' => $product_variations,
+ 'country' => $country,
+ 'locale' => WC_Payments_Utils::convert_to_stripe_locale( get_locale() ),
+ 'accountId' => $this->account->get_stripe_account_id(),
+ 'publishableKey' => $this->account->get_publishable_key( WC_Payments::mode()->is_test() ),
+ 'paymentMethods' => array_values( $bnpl_payment_methods ),
+ 'currencyCode' => $currency_code,
+ 'isCart' => is_cart(),
+ 'isCartBlock' => $is_cart_block,
+ 'cartTotal' => WC_Payments_Utils::prepare_amount( $cart_total, $currency_code ),
+ 'nonce' => [
+ 'get_cart_total' => wp_create_nonce( 'wcpay-get-cart-total' ),
+ 'is_bnpl_available' => wp_create_nonce( 'wcpay-is-bnpl-available' ),
+ ],
+ 'wcAjaxUrl' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ ];
+
+ if ( $product ) {
+ $script_data['isBnplAvailable'] = WC_Payments_Utils::is_any_bnpl_method_available( array_values( $bnpl_payment_methods ), $country, $currency_code, $product_price );
+ }
+
// Create script tag with config.
wp_localize_script(
'WCPAY_PRODUCT_DETAILS',
'wcpayStripeSiteMessaging',
- [
- 'productId' => 'base_product',
- 'productVariations' => $product_variations,
- 'country' => empty( $billing_country ) ? $store_country : $billing_country,
- 'locale' => WC_Payments_Utils::convert_to_stripe_locale( get_locale() ),
- 'accountId' => $this->account->get_stripe_account_id(),
- 'publishableKey' => $this->account->get_publishable_key( WC_Payments::mode()->is_test() ),
- 'paymentMethods' => array_values( $bnpl_payment_methods ),
- 'currencyCode' => $currency_code,
- 'isCart' => is_cart(),
- 'isCartBlock' => $is_cart_block,
- 'cartTotal' => WC_Payments_Utils::prepare_amount( $cart_total, $currency_code ),
- 'minimumOrderAmount' => WC_Payments_Utils::get_cached_minimum_amount( $currency_code, true ),
- 'nonce' => wp_create_nonce( 'wcpay-get-cart-total' ),
- 'wcAjaxUrl' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
- ]
+ $script_data
);
// Ensure wcpayConfig is available in the page.
diff --git a/includes/class-wc-payments-redirect-service.php b/includes/class-wc-payments-redirect-service.php
index bc4c3c77a54..7863cf0aa6d 100644
--- a/includes/class-wc-payments-redirect-service.php
+++ b/includes/class-wc-payments-redirect-service.php
@@ -8,6 +8,7 @@
use WCPay\Core\Server\Request\Get_Account_Capital_Link;
use WCPay\Core\Server\Request\Get_Account_Login_Data;
use WCPay\Exceptions\API_Exception;
+use WCPay\Tracker;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
@@ -92,6 +93,7 @@ public function redirect_to_capital_view_offer_page(): void {
$request->set_refresh_url( $refresh_url );
$capital_link = $request->send();
+ Tracker::track_admin( 'wcpay_capital_view_offer_redirect' );
$this->redirect_to( $capital_link['url'] );
} catch ( Exception $e ) {
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..7afbc0e5835 100644
--- a/includes/class-wc-payments-utils.php
+++ b/includes/class-wc-payments-utils.php
@@ -716,59 +716,163 @@ public static function get_filtered_error_status_code( Exception $e ): int {
}
/**
- * Retrieves Stripe minimum order value authorized per currency.
- * The values are based on Stripe's recommendations.
- * See https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts.
+ * Get the BNPL limits per currency for a specific payment method.
*
- * @param string $currency The currency.
- *
- * @return int The minimum amount.
+ * @param string $payment_method The payment method name ('affirm', 'afterpay_clearpay', or 'klarna').
+ * @return array The BNPL limits per currency for the specified payment method.
*/
- public static function get_stripe_minimum_amount( $currency ) {
- switch ( $currency ) {
- case 'AED':
- case 'MYR':
- case 'PLN':
- case 'RON':
- $minimum_amount = 200;
- break;
- case 'BGN':
- $minimum_amount = 100;
- break;
- case 'CZK':
- $minimum_amount = 1500;
- break;
- case 'DKK':
- $minimum_amount = 250;
- break;
- case 'GBP':
- $minimum_amount = 30;
- break;
- case 'HKD':
- $minimum_amount = 400;
- break;
- case 'HUF':
- $minimum_amount = 17500;
- break;
- case 'JPY':
- $minimum_amount = 5000;
- break;
- case 'MXN':
- case 'THB':
- $minimum_amount = 1000;
- break;
- case 'NOK':
- case 'SEK':
- $minimum_amount = 300;
- break;
+ public static function get_bnpl_limits_per_currency( $payment_method ) {
+ switch ( $payment_method ) {
+ case 'affirm':
+ return [
+ Currency_Code::CANADIAN_DOLLAR => [
+ Country_Code::CANADA => [
+ 'min' => 5000,
+ 'max' => 3000000,
+ ], // Represents CAD 50 - 30,000 CAD.
+ ],
+ Currency_Code::UNITED_STATES_DOLLAR => [
+ Country_Code::UNITED_STATES => [
+ 'min' => 5000,
+ 'max' => 3000000,
+ ],
+ ], // Represents USD 50 - 30,000 USD.
+ ];
+ case 'afterpay_clearpay':
+ return [
+ Currency_Code::AUSTRALIAN_DOLLAR => [
+ Country_Code::AUSTRALIA => [
+ 'min' => 100,
+ 'max' => 200000,
+ ], // Represents AUD 1 - 2,000 AUD.
+ ],
+ Currency_Code::CANADIAN_DOLLAR => [
+ Country_Code::CANADA => [
+ 'min' => 100,
+ 'max' => 200000,
+ ], // Represents CAD 1 - 2,000 CAD.
+ ],
+ Currency_Code::NEW_ZEALAND_DOLLAR => [
+ Country_Code::NEW_ZEALAND => [
+ 'min' => 100,
+ 'max' => 200000,
+ ], // Represents NZD 1 - 2,000 NZD.
+ ],
+ Currency_Code::POUND_STERLING => [
+ Country_Code::UNITED_KINGDOM => [
+ 'min' => 100,
+ 'max' => 120000,
+ ], // Represents GBP 1 - 1,200 GBP.
+ ],
+ Currency_Code::UNITED_STATES_DOLLAR => [
+ Country_Code::UNITED_STATES => [
+ 'min' => 100,
+ 'max' => 400000,
+ ], // Represents USD 1 - 4,000 USD.
+ ],
+ ];
+ case 'klarna':
+ return [
+ Currency_Code::UNITED_STATES_DOLLAR => [
+ Country_Code::UNITED_STATES => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents USD 1 - 10,000 USD.
+ ],
+ Currency_Code::POUND_STERLING => [
+ Country_Code::UNITED_KINGDOM => [
+ 'min' => 100,
+ 'max' => 500000,
+ ], // Represents GBP 1 - 5,000 GBP.
+ ],
+ Currency_Code::EURO => [
+ Country_Code::AUSTRIA => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents EUR 1 - 10,000 EUR.
+ Country_Code::BELGIUM => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents EUR 1 - 10,000 EUR.
+ Country_Code::GERMANY => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents EUR 1 - 10,000 EUR.
+ Country_Code::NETHERLANDS => [
+ 'min' => 100,
+ 'max' => 500000,
+ ], // Represents EUR 1 - 5,000 EUR.
+ Country_Code::FINLAND => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents EUR 1 - 10,000 EUR.
+ Country_Code::SPAIN => [
+ 'min' => 100,
+ 'max' => 1000000,
+ ], // Represents EUR 1 - 10,000 EUR.
+ Country_Code::IRELAND => [
+ 'min' => 100,
+ 'max' => 400000,
+ ], // Represents EUR 1 - 4,000 EUR.
+ Country_Code::ITALY => [
+ 'min' => 100,
+ 'max' => 400000,
+ ], // Represents EUR 1 - 4,000 EUR.
+ Country_Code::FRANCE => [
+ 'min' => 100,
+ 'max' => 400000,
+ ], // Represents EUR 1 - 4,000 EUR.
+ ],
+ Currency_Code::DANISH_KRONE => [
+ Country_Code::DENMARK => [
+ 'min' => 100,
+ 'max' => 10000000,
+ ], // Represents DKK 1 - 100,000 DKK.
+ ],
+ Currency_Code::NORWEGIAN_KRONE => [
+ Country_Code::NORWAY => [
+ 'min' => 100,
+ 'max' => 10000000,
+ ], // Represents NOK 1 - 100,000 NOK.
+ ],
+ Currency_Code::SWEDISH_KRONA => [
+ Country_Code::SWEDEN => [
+ 'min' => 100,
+ 'max' => 10000000,
+ ], // Represents SEK 1 - 100,000 SEK.
+ ],
+ ];
default:
- $minimum_amount = 50;
- break;
+ return [];
}
+ }
+
+ /**
+ * Check if any BNPL method is available for a given country, currency, and price.
+ *
+ * @param array $enabled_methods Array of enabled BNPL methods.
+ * @param string $country_code Country code.
+ * @param string $currency_code Currency code.
+ * @param float $price Product price.
+ * @return bool True if any BNPL method is available, false otherwise.
+ */
+ public static function is_any_bnpl_method_available( array $enabled_methods, string $country_code, string $currency_code, float $price ): bool {
+ $price_in_cents = $price;
+
+ foreach ( $enabled_methods as $method ) {
+ $limits = self::get_bnpl_limits_per_currency( $method );
- self::cache_minimum_amount( $currency, $minimum_amount );
+ if ( isset( $limits[ $currency_code ][ $country_code ] ) ) {
+ $min_amount = $limits[ $currency_code ][ $country_code ]['min'];
+ $max_amount = $limits[ $currency_code ][ $country_code ]['max'];
- return $minimum_amount;
+ if ( $price_in_cents >= $min_amount && $price_in_cents <= $max_amount ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
/**
@@ -785,20 +889,12 @@ public static function cache_minimum_amount( $currency, $amount ) {
* Checks if there is a minimum amount required for transactions in a given currency.
*
* @param string $currency The currency to check for.
- * @param bool $fallback_to_local_list Whether to fallback to the local Stripe list if the cached value is not available.
*
* @return int|null Either the minimum amount, or `null` if not available.
*/
- public static function get_cached_minimum_amount( $currency, $fallback_to_local_list = false ) {
+ public static function get_cached_minimum_amount( $currency ) {
$cached = get_transient( 'wcpay_minimum_amount_' . strtolower( $currency ) );
-
- if ( (int) $cached ) {
- return (int) $cached;
- } elseif ( $fallback_to_local_list ) {
- return self::get_stripe_minimum_amount( $currency );
- }
-
- return null;
+ return (int) $cached ? (int) $cached : null;
}
/**
@@ -1247,47 +1343,38 @@ public static function is_cart_block(): bool {
}
/**
- * Returns true if the request that's currently being processed is a Store API request, false
- * otherwise.
+ * Determine if the request that's currently being processed is a Store API request.
*
* @return bool True if request is a Store API request, false otherwise.
*/
public static function is_store_api_request(): bool {
+ // @TODO We should move to a more robust way of getting to the route, like WC is doing in the StoreAPI library. https://github.com/woocommerce/woocommerce/blob/9ac48232a944baa2dbfaa7dd47edf9027cca9519/plugins/woocommerce/src/StoreApi/Authentication.php#L15-L15
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 {
+ // Extract the request path from the request URL.
$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 );
+ $request_path = ! empty( $url_parts['path'] ) ? rtrim( $url_parts['path'], '/' ) : '';
+ // Remove the REST API prefix from the request path to end up with the route.
+ $rest_route = str_replace( trailingslashit( rest_get_url_prefix() ), '', $request_path );
+ }
+
+ // Bail early if the rest route is empty.
+ if ( empty( $rest_route ) ) {
+ return false;
}
+ // Try to match the rest route against the store API route patterns.
foreach ( self::STORE_API_ROUTE_PATTERNS as $pattern ) {
if ( 1 === preg_match( $pattern, $rest_route ) ) {
return true;
}
}
+ // If no match was found, this is not a Store API request.
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-webhook-processing-service.php b/includes/class-wc-payments-webhook-processing-service.php
index eaaeadbcfc8..eceb9617a75 100644
--- a/includes/class-wc-payments-webhook-processing-service.php
+++ b/includes/class-wc-payments-webhook-processing-service.php
@@ -618,7 +618,7 @@ private function process_webhook_dispute_updated( $event_body ) {
switch ( $event_type ) {
case 'charge.dispute.funds_withdrawn':
- $message = __( 'Payment dispute and fees have been deducted from your next deposit', 'woocommerce-payments' );
+ $message = __( 'Payment dispute and fees have been deducted from your next payout', 'woocommerce-payments' );
break;
case 'charge.dispute.funds_reinstated':
$message = __( 'Payment dispute funds have been reinstated', 'woocommerce-payments' );
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index 42923e906d5..264cf340c64 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.
*/
@@ -450,6 +465,7 @@ public static function init() {
include_once __DIR__ . '/exceptions/class-invalid-address-exception.php';
include_once __DIR__ . '/constants/class-base-constant.php';
include_once __DIR__ . '/constants/class-country-code.php';
+ include_once __DIR__ . '/constants/class-country-test-cards.php';
include_once __DIR__ . '/constants/class-currency-code.php';
include_once __DIR__ . '/constants/class-fraud-meta-box-type.php';
include_once __DIR__ . '/constants/class-order-mode.php';
@@ -468,6 +484,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 +506,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 +538,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 +601,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();
@@ -618,6 +640,7 @@ function () {
add_action( 'woocommerce_proceed_to_checkout', [ __CLASS__, 'load_stripe_bnpl_site_messaging' ], 5 );
add_action( 'woocommerce_blocks_enqueue_cart_block_scripts_after', [ __CLASS__, 'load_stripe_bnpl_site_messaging' ] );
add_action( 'wc_ajax_wcpay_get_cart_total', [ __CLASS__, 'ajax_get_cart_total' ] );
+ add_action( 'wc_ajax_wcpay_check_bnpl_availability', [ __CLASS__, 'ajax_check_bnpl_availability' ] );
}
}
@@ -1323,6 +1346,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
*
@@ -1731,6 +1763,26 @@ public static function ajax_get_cart_total() {
wp_send_json( [ 'total' => WC_Payments_Utils::prepare_amount( $cart_total, $currency_code ) ] );
}
+ /**
+ * Check if BNPL is available for the given price, currency, and country.
+ */
+ public static function ajax_check_bnpl_availability() {
+ check_ajax_referer( 'wcpay-is-bnpl-available', 'security' );
+
+ $price = floatval( $_POST['price'] );
+ $currency = sanitize_text_field( wp_unslash( $_POST['currency'] ) );
+ $country = sanitize_text_field( wp_unslash( $_POST['country'] ) );
+
+ $enabled_bnpl_payment_methods = array_intersect(
+ Payment_Method::BNPL_PAYMENT_METHODS,
+ self::get_gateway()->get_upe_enabled_payment_method_ids()
+ );
+
+ $is_available = WC_Payments_Utils::is_any_bnpl_method_available( $enabled_bnpl_payment_methods, $country, $currency, $price );
+
+ wp_send_json_success( [ 'is_available' => $is_available ] );
+ }
+
/**
* Adds custom email field.
*/
@@ -1868,6 +1920,7 @@ public static function add_wcpay_options_to_woocommerce_permissions_list( $permi
'woocommerce_remind_me_later_todo_tasks',
'woocommerce_deleted_todo_tasks',
'wcpay_fraud_protection_welcome_tour_dismissed',
+ 'wcpay_payouts_rename_notice_dismissed',
'wcpay_capability_request_dismissed_notices',
'wcpay_onboarding_eligibility_modal_dismissed',
'wcpay_next_deposit_notice_dismissed',
diff --git a/includes/class-woopay-tracker.php b/includes/class-woopay-tracker.php
index 2da1e544132..78e7ea5c8da 100644
--- a/includes/class-woopay-tracker.php
+++ b/includes/class-woopay-tracker.php
@@ -622,12 +622,22 @@ public function add_frontend_tracks_scripts() {
WC_Payments::register_script_with_dependencies( 'wcpay-frontend-tracks', 'dist/frontend-tracks' );
- wp_enqueue_script( 'wcpay-frontend-tracks' );
+ // Define wcpayConfig before the frontend tracks script if it hasn't been defined yet.
+ $wcpay_config = rawurlencode( wp_json_encode( WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config() ) );
+ wp_add_inline_script(
+ 'wcpay-frontend-tracks',
+ "
+ var wcpayConfig = wcpayConfig || JSON.parse( decodeURIComponent( '" . esc_js( $wcpay_config ) . "' ) );
+ ",
+ 'before'
+ );
wp_localize_script(
'wcpay-frontend-tracks',
'wcPayFrontendTracks',
$frontent_tracks
);
+
+ wp_enqueue_script( 'wcpay-frontend-tracks' );
}
}
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/constants/class-country-test-cards.php b/includes/constants/class-country-test-cards.php
new file mode 100644
index 00000000000..2e9a8287c84
--- /dev/null
+++ b/includes/constants/class-country-test-cards.php
@@ -0,0 +1,95 @@
+ '4242 4242 4242 4242',
+ Country_Code::ARGENTINA => '4000 0003 2000 0021',
+ Country_Code::BRAZIL => '4000 0007 6000 0002',
+ Country_Code::CANADA => '4000 0012 4000 0000',
+ Country_Code::CHILE => '4000 0015 2000 0001',
+ Country_Code::COLOMBIA => '4000 0017 0000 0003',
+ Country_Code::COSTA_RICA => '4000 0018 8000 0005',
+ Country_Code::ECUADOR => '4000 0021 8000 0000',
+ Country_Code::MEXICO => '4000 0048 4000 8001',
+ Country_Code::PANAMA => '4000 0059 1000 0000',
+ Country_Code::PARAGUAY => '4000 0060 0000 0066',
+ Country_Code::PERU => '4000 0060 4000 0068',
+ Country_Code::URUGUAY => '4000 0085 8000 0003',
+ Country_Code::UNITED_ARAB_EMIRATES => '4000 0078 4000 0001',
+ Country_Code::AUSTRIA => '4000 0004 0000 0008',
+ Country_Code::BELGIUM => '4000 0005 6000 0004',
+ Country_Code::BULGARIA => '4000 0010 0000 0000',
+ Country_Code::BELARUS => '4000 0011 2000 0005',
+ Country_Code::CROATIA => '4000 0019 1000 0009',
+ Country_Code::CYPRUS => '4000 0019 6000 0008',
+ Country_Code::CZECHIA => '4000 0020 3000 0002',
+ Country_Code::DENMARK => '4000 0020 8000 0001',
+ Country_Code::ESTONIA => '4000 0023 3000 0009',
+ Country_Code::FINLAND => '4000 0024 6000 0001',
+ Country_Code::FRANCE => '4000 0025 0000 0003',
+ Country_Code::GERMANY => '4000 0027 6000 0016',
+ Country_Code::GIBRALTAR => '4000 0029 2000 0005',
+ Country_Code::GREECE => '4000 0030 0000 0030',
+ Country_Code::HUNGARY => '4000 0034 8000 0005',
+ Country_Code::IRELAND => '4000 0037 2000 0005',
+ Country_Code::ITALY => '4000 0038 0000 0008',
+ Country_Code::LATVIA => '4000 0042 8000 0005',
+ Country_Code::LIECHTENSTEIN => '4000 0043 8000 0004',
+ Country_Code::LITHUANIA => '4000 0044 0000 0000',
+ Country_Code::LUXEMBOURG => '4000 0044 2000 0006',
+ Country_Code::MALTA => '4000 0047 0000 0007',
+ Country_Code::NETHERLANDS => '4000 0052 8000 0002',
+ Country_Code::NORWAY => '4000 0057 8000 0007',
+ Country_Code::POLAND => '4000 0061 6000 0005',
+ Country_Code::PORTUGAL => '4000 0062 0000 0007',
+ Country_Code::ROMANIA => '4000 0064 2000 0001',
+ Country_Code::SAUDI_ARABIA => '4000 0068 2000 0007',
+ Country_Code::SLOVENIA => '4000 0070 5000 0006',
+ Country_Code::SLOVAKIA => '4000 0070 3000 0001',
+ Country_Code::SPAIN => '4000 0072 4000 0007',
+ Country_Code::SWEDEN => '4000 0075 2000 0008',
+ Country_Code::SWITZERLAND => '4000 0075 6000 0009',
+ Country_Code::UNITED_KINGDOM => '4000 0082 6000 0000',
+ Country_Code::AUSTRALIA => '4000 0003 6000 0006',
+ Country_Code::CHINA => '4000 0015 6000 0002',
+ Country_Code::HONG_KONG => '4000 0034 4000 0004',
+ Country_Code::INDIA => '4000 0035 6000 0008',
+ Country_Code::JAPAN => '4000 0039 2000 0003',
+ Country_Code::MALAYSIA => '4000 0045 8000 0002',
+ Country_Code::NEW_ZEALAND => '4000 0055 4000 0008',
+ Country_Code::SINGAPORE => '4000 0070 2000 0003',
+ Country_Code::TAIWAN => '4000 0015 8000 0008',
+ Country_Code::THAILAND => '4000 0076 4000 0003',
+ ];
+
+ /**
+ * Get test card number for a specific country.
+ *
+ * @param string $country_code Two-letter country code.
+ * @return string Test card number
+ */
+ public static function get_test_card_for_country( string $country_code ) {
+ return self::$country_test_cards[ $country_code ] ?? self::$country_test_cards[ Country_Code::UNITED_STATES ];
+ }
+}
diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
index 682b4eac903..9deeab01ca3 100644
--- a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
+++ b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php
@@ -11,6 +11,8 @@
exit;
}
+use Automattic\WooCommerce\Blocks\Package;
+use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
/**
@@ -99,6 +101,10 @@ public function init() {
add_action( 'woocommerce_checkout_order_processed', [ $this->express_checkout_helper, 'add_order_payment_method_title' ], 10, 2 );
$this->express_checkout_ajax_handler->init();
+
+ if ( is_admin() && current_user_can( 'manage_woocommerce' ) ) {
+ $this->register_ece_data_for_block_editor();
+ }
}
/**
@@ -240,11 +246,12 @@ public function scripts() {
'pay_for_order' => wp_create_nonce( 'pay_for_order' ),
],
'checkout' => [
- 'currency_code' => strtolower( get_woocommerce_currency() ),
- 'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
- 'needs_shipping' => WC()->cart->needs_shipping(),
+ 'currency_code' => strtolower( get_woocommerce_currency() ),
+ 'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
+ 'needs_shipping' => WC()->cart->needs_shipping(),
// Defaults to 'required' to match how core initializes this option.
- 'needs_payer_phone' => 'required' === get_option( 'woocommerce_checkout_phone_field', 'required' ),
+ 'needs_payer_phone' => 'required' === get_option( 'woocommerce_checkout_phone_field', 'required' ),
+ 'allowed_shipping_countries' => array_keys( WC()->countries->get_shipping_countries() ?? [] ),
],
'button' => $this->get_button_settings(),
'login_confirmation' => $this->get_login_confirmation_settings(),
@@ -446,4 +453,23 @@ public function filter_gateway_title( $title, $id ) {
return $title;
}
+
+ /**
+ * Add ECE data to `wcSettings` to allow it to be accessed by the front-end JS script in the Block editor.
+ *
+ * @return void
+ */
+ private function register_ece_data_for_block_editor() {
+ $data_registry = Package::container()->get( AssetDataRegistry::class );
+
+ if ( $data_registry->exists( 'ece_data' ) ) {
+ return;
+ }
+
+ $ece_data = [
+ 'button' => $this->get_button_settings(),
+ ];
+
+ $data_registry->add( 'ece_data', $ece_data );
+ }
}
diff --git a/includes/fraud-prevention/class-order-fraud-and-risk-meta-box.php b/includes/fraud-prevention/class-order-fraud-and-risk-meta-box.php
index 5b498ec90c8..70202beb213 100644
--- a/includes/fraud-prevention/class-order-fraud-and-risk-meta-box.php
+++ b/includes/fraud-prevention/class-order-fraud-and-risk-meta-box.php
@@ -7,7 +7,7 @@
namespace WCPay\Fraud_Prevention;
-use WC_Payments_Features;
+use WC_Payments_Admin_Settings;
use WC_Payments_Order_Service;
use WC_Payments_Utils;
use WCPay\Constants\Fraud_Meta_Box_Type;
@@ -54,7 +54,7 @@ public function maybe_add_meta_box() {
// 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_order_fraud_and_risk_meta_box', __( 'Fraud & Risk', 'woocommerce-payments' ), [ $this, 'display_order_fraud_and_risk_meta_box_message' ], $wc_screen_id, 'side', 'default' );
+ add_meta_box( 'wcpay-order-fraud-and-risk-meta-box', __( 'Fraud & Risk', 'woocommerce-payments' ), [ $this, 'display_order_fraud_and_risk_meta_box_message' ], $wc_screen_id, 'side', 'default' );
}
/**
@@ -74,6 +74,7 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
$intent_id = $this->order_service->get_intent_id_for_order( $order );
$charge_id = $this->order_service->get_charge_id_for_order( $order );
$meta_box_type = $this->order_service->get_fraud_meta_box_type_for_order( $order );
+ $risk_level = $this->order_service->get_charge_risk_level_for_order( $order );
$payment_method = $order->get_payment_method();
if ( strstr( $payment_method, 'woocommerce_payments_' ) ) {
@@ -104,6 +105,14 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
'no_action_taken' => __( 'No action taken', 'woocommerce-payments' ),
];
+ $risk_filters_callout = __( 'Adjust risk filters', 'woocommerce-payments' );
+ $risk_filters_url = WC_Payments_Admin_Settings::get_settings_url( [ 'anchor' => '%23fp-settings' ] );
+ $show_adjust_risk_filters_link = true;
+
+ $this->maybe_print_risk_level_block( $risk_level );
+
+ echo '
';
+
switch ( $meta_box_type ) {
case Fraud_Meta_Box_Type::ALLOW:
$description = __( 'The payment for this order passed your risk filtering.', 'woocommerce-payments' );
@@ -114,12 +123,13 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
$description = __( 'The payment for this order was blocked by your risk filtering. There is no pending authorization, and the order can be cancelled to reduce any held stock.', 'woocommerce-payments' );
$callout = __( 'View more details', 'woocommerce-payments' );
$transaction_url = $this->compose_transaction_url_with_tracking( $order->get_id(), '', Rule::FRAUD_OUTCOME_BLOCK );
- echo '
' . esc_html( $statuses['blocked'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $statuses['blocked'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::NOT_CARD:
case Fraud_Meta_Box_Type::NOT_WCPAY:
- $payment_method_title = $order->get_payment_method_title();
+ $payment_method_title = $order->get_payment_method_title();
+ $show_adjust_risk_filters_link = false;
if ( ! empty( $payment_method_title ) && 'Popular payment methods' !== $payment_method_title ) {
$description = sprintf(
@@ -139,7 +149,7 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
$callout = __( 'Learn more', 'woocommerce-payments' );
$callout_url = 'https://woocommerce.com/document/woopayments/fraud-and-disputes/fraud-protection/';
$callout_url = add_query_arg( 'status_is', 'fraud-meta-box-not-wcpay-learn-more', $callout_url );
- echo '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::PAYMENT_STARTED:
@@ -151,7 +161,7 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
$description = __( 'The payment for this order was held for review by your risk filtering. You can review the details and determine whether to approve or block the payment.', 'woocommerce-payments' );
$callout = __( 'Review payment', 'woocommerce-payments' );
$transaction_url = $this->compose_transaction_url_with_tracking( $intent_id, $charge_id, Rule::FRAUD_OUTCOME_REVIEW );
- echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::REVIEW_ALLOWED:
@@ -163,21 +173,21 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
$description = __( 'This transaction was held for review by your risk filters, and the charge was manually blocked after review.', 'woocommerce-payments' );
$callout = __( 'Review payment', 'woocommerce-payments' );
$transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id );
- echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::REVIEW_EXPIRED:
$description = __( 'The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have expired.', 'woocommerce-payments' );
$callout = __( 'Review payment', 'woocommerce-payments' );
$transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id );
- echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::REVIEW_FAILED:
$description = __( 'The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have failed.', 'woocommerce-payments' );
$callout = __( 'Review payment', 'woocommerce-payments' );
$transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id );
- echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . ' ';
+ echo '
' . esc_html( $statuses['held_for_review'] ) . '
' . esc_html( $description ) . '
' . esc_html( $callout ) . '
';
break;
case Fraud_Meta_Box_Type::TERMINAL_PAYMENT:
@@ -194,6 +204,45 @@ public function display_order_fraud_and_risk_meta_box_message( $order ) {
echo '
' . esc_html( $description ) . '
';
break;
}
+
+ if ( $show_adjust_risk_filters_link ) {
+ echo '
' . esc_html( $risk_filters_callout ) . '
';
+ }
+
+ echo '
';
+ }
+
+ /**
+ * Prints the risk level block.
+ *
+ * @param string $risk_level The risk level to display.
+ *
+ * @return void
+ */
+ private function maybe_print_risk_level_block( $risk_level ) {
+ $valid_risk_levels = [ 'normal', 'elevated', 'highest' ];
+
+ if ( ! in_array( $risk_level, $valid_risk_levels, true ) ) {
+ return;
+ }
+
+ $titles = [
+ 'normal' => __( 'Normal', 'woocommerce-payments' ),
+ 'elevated' => __( 'Elevated', 'woocommerce-payments' ),
+ 'highest' => __( 'High', 'woocommerce-payments' ),
+ ];
+
+ $descriptions = [
+ 'normal' => __( 'This payment shows a lower than normal risk of fraudulent activity.', 'woocommerce-payments' ),
+ 'elevated' => __( 'This order has a moderate risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.', 'woocommerce-payments' ),
+ 'highest' => __( 'This order has a high risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.', 'woocommerce-payments' ),
+ ];
+
+ echo '
';
+ echo '
' . esc_html( $titles[ $risk_level ] ) . '
';
+ echo '
';
+ echo '
' . esc_html( $descriptions[ $risk_level ] ) . '
';
+ echo '
';
}
/**
diff --git a/includes/multi-currency/Analytics.php b/includes/multi-currency/Analytics.php
index ef3f5b17a5a..822ba88efc5 100644
--- a/includes/multi-currency/Analytics.php
+++ b/includes/multi-currency/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/includes/multi-currency/BackendCurrencies.php
index 9ea009ac4c4..bdb2da92b72 100644
--- a/includes/multi-currency/BackendCurrencies.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility.php
index 4f60915fb97..87e10cbde78 100644
--- a/includes/multi-currency/Compatibility.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/BaseCompatibility.php
index a98073fd113..3e7d1a67a20 100644
--- a/includes/multi-currency/Compatibility/BaseCompatibility.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceBookings.php
index 5a99534e5d6..756e4eef355 100644
--- a/includes/multi-currency/Compatibility/WooCommerceBookings.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceDeposits.php
index f92819785c5..e2ffa89d441 100644
--- a/includes/multi-currency/Compatibility/WooCommerceDeposits.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceFedEx.php
index 738e738150f..8a38d058e40 100644
--- a/includes/multi-currency/Compatibility/WooCommerceFedEx.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceNameYourPrice.php
index 155f99e1a4d..fad352e1d1f 100644
--- a/includes/multi-currency/Compatibility/WooCommerceNameYourPrice.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommercePointsAndRewards.php
index 9d78886eb41..38819d15322 100644
--- a/includes/multi-currency/Compatibility/WooCommercePointsAndRewards.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommercePreOrders.php
index 3c3fe9d5efc..b16dd91b646 100644
--- a/includes/multi-currency/Compatibility/WooCommercePreOrders.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceProductAddOns.php
index 7d245cd4e4f..add583059f8 100644
--- a/includes/multi-currency/Compatibility/WooCommerceProductAddOns.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceSubscriptions.php
index 94294827ea9..6701f6739dd 100644
--- a/includes/multi-currency/Compatibility/WooCommerceSubscriptions.php
+++ b/includes/multi-currency/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/includes/multi-currency/Compatibility/WooCommerceUPS.php
index 6a53f47bff3..427aa060d52 100644
--- a/includes/multi-currency/Compatibility/WooCommerceUPS.php
+++ b/includes/multi-currency/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/includes/multi-currency/CountryFlags.php b/includes/multi-currency/CountryFlags.php
index e841095255e..286e77dfbe2 100644
--- a/includes/multi-currency/CountryFlags.php
+++ b/includes/multi-currency/CountryFlags.php
@@ -7,9 +7,6 @@
namespace WCPay\MultiCurrency;
-use WCPay\Constants\Country_Code;
-use WCPay\Constants\Currency_Code;
-
defined( 'ABSPATH' ) || exit;
/**
@@ -18,257 +15,257 @@
class CountryFlags {
const EMOJI_COUNTRIES_FLAGS = [
- Country_Code::ANDORRA => '🇦🇩',
- Country_Code::UNITED_ARAB_EMIRATES => '🇦🇪',
- Country_Code::AFGHANISTAN => '🇦🇫',
- Country_Code::ANTIGUA_AND_BARBUDA => '🇦🇬',
- Country_Code::ANGUILLA => '🇦🇮',
- Country_Code::ALBANIA => '🇦🇱',
- Country_Code::ARMENIA => '🇦🇲',
- Country_Code::ANGOLA => '🇦🇴',
- Country_Code::ANTARCTICA => '🇦🇶',
- Country_Code::ARGENTINA => '🇦🇷',
- Country_Code::AMERICAN_SAMOA => '🇦🇸',
- Country_Code::AUSTRIA => '🇦🇹',
- Country_Code::AUSTRALIA => '🇦🇺',
- Country_Code::ARUBA => '🇦🇼',
- Country_Code::ALAND_ISLANDS => '🇦🇽',
- Country_Code::AZERBAIJAN => '🇦🇿',
- Country_Code::BOSNIA_AND_HERZEGOVINA => '🇧🇦',
- Country_Code::BARBADOS => '🇧🇧',
- Country_Code::BANGLADESH => '🇧🇩',
- Country_Code::BELGIUM => '🇧🇪',
- Country_Code::BURKINA_FASO => '🇧🇫',
- Country_Code::BULGARIA => '🇧🇬',
- Country_Code::BAHRAIN => '🇧🇭',
- Country_Code::BURUNDI => '🇧🇮',
- Country_Code::BENIN => '🇧🇯',
- Country_Code::SAINT_BARTHELEMY => '🇧🇱',
- Country_Code::BERMUDA => '🇧🇲',
- Country_Code::BRUNEI => '🇧🇳',
- Country_Code::BOLIVIA => '🇧🇴',
- Country_Code::CARIBBEAN_NETHERLANDS => '🇧🇶',
- Country_Code::BRAZIL => '🇧🇷',
- Country_Code::BAHAMAS => '🇧🇸',
- Country_Code::BHUTAN => '🇧🇹',
- Country_Code::BOUVET_ISLAND => '🇧🇻',
- Country_Code::BOTSWANA => '🇧🇼',
- Country_Code::BELARUS => '🇧🇾',
- Country_Code::BELIZE => '🇧🇿',
- Country_Code::CANADA => '🇨🇦',
- Country_Code::COCOS_KEELING_ISLANDS => '🇨🇨',
- Country_Code::DEMOCRATIC_REPUBLIC_OF_THE_CONGO => '🇨🇩',
- Country_Code::CENTRAL_AFRICAN_REPUBLIC => '🇨🇫',
- Country_Code::CONGO => '🇨🇬',
- Country_Code::SWITZERLAND => '🇨🇭',
- Country_Code::IVORY_COAST => '🇨🇮',
- Country_Code::COOK_ISLANDS => '🇨🇰',
- Country_Code::CHILE => '🇨🇱',
- Country_Code::CAMEROON => '🇨🇲',
- Country_Code::CHINA => '🇨🇳',
- Country_Code::COLOMBIA => '🇨🇴',
- Country_Code::COSTA_RICA => '🇨🇷',
- Country_Code::CUBA => '🇨🇺',
- Country_Code::CABO_VERDE => '🇨🇻',
- 'CW' => '🇨🇼',
- 'CX' => '🇨🇽',
- Country_Code::CYPRUS => '🇨🇾',
- Country_Code::CZECHIA => '🇨🇿',
- Country_Code::GERMANY => '🇩🇪',
- Country_Code::DJIBOUTI => '🇩🇯',
- Country_Code::DENMARK => '🇩🇰',
- Country_Code::DOMINICA => '🇩🇲',
- Country_Code::DOMINICAN_REPUBLIC => '🇩🇴',
- Country_Code::ALGERIA => '🇩🇿',
- Country_Code::ECUADOR => '🇪🇨',
- Country_Code::ESTONIA => '🇪🇪',
- Country_Code::EGYPT => '🇪🇬',
- 'EH' => '🇪🇭',
- Country_Code::ERITREA => '🇪🇷',
- Country_Code::SPAIN => '🇪🇸',
- Country_Code::ETHIOPIA => '🇪🇹',
- 'EU' => '🇪🇺',
- Country_Code::FINLAND => '🇫🇮',
- Country_Code::FIJI => '🇫🇯',
- 'FK' => '🇫🇰',
- Country_Code::MICRONESIA => '🇫🇲',
- 'FO' => '🇫🇴',
- Country_Code::FRANCE => '🇫🇷',
- Country_Code::GABON => '🇬🇦',
- Country_Code::UNITED_KINGDOM => '🇬🇧',
- Country_Code::GRENADA => '🇬🇩',
- Country_Code::GEORGIA => '🇬🇪',
- 'GF' => '🇬🇫',
- 'GG' => '🇬🇬',
- Country_Code::GHANA => '🇬🇭',
- Country_Code::GIBRALTAR => '🇬🇮',
- 'GL' => '🇬🇱',
- Country_Code::GAMBIA => '🇬🇲',
- Country_Code::GUINEA => '🇬🇳',
- 'GP' => '🇬🇵',
- Country_Code::EQUATORIAL_GUINEA => '🇬🇶',
- Country_Code::GREECE => '🇬🇷',
- 'GS' => '🇬🇸',
- Country_Code::GUATEMALA => '🇬🇹',
- 'GU' => '🇬🇺',
- Country_Code::GUINEA_BISSAU => '🇬🇼',
- Country_Code::GUYANA => '🇬🇾',
- Country_Code::HONG_KONG => '🇭🇰',
- 'HM' => '🇭🇲',
- Country_Code::HONDURAS => '🇭🇳',
- Country_Code::CROATIA => '🇭🇷',
- Country_Code::HAITI => '🇭🇹',
- Country_Code::HUNGARY => '🇭🇺',
- Country_Code::INDONESIA => '🇮🇩',
- Country_Code::IRELAND => '🇮🇪',
- Country_Code::ISRAEL => '🇮🇱',
- 'IM' => '🇮🇲',
- Country_Code::INDIA => '🇮🇳',
- Country_Code::BRITISH_INDIAN_OCEAN_TERRITORY => '🇮🇴',
- Country_Code::IRAQ => '🇮🇶',
- Country_Code::IRAN => '🇮🇷',
- Country_Code::ICELAND => '🇮🇸',
- Country_Code::ITALY => '🇮🇹',
- 'JE' => '🇯🇪',
- Country_Code::JAMAICA => '🇯🇲',
- Country_Code::JORDAN => '🇯🇴',
- Country_Code::JAPAN => '🇯🇵',
- Country_Code::KENYA => '🇰🇪',
- Country_Code::KYRGYZSTAN => '🇰🇬',
- Country_Code::CAMBODIA => '🇰🇭',
- Country_Code::KIRIBATI => '🇰🇮',
- Country_Code::COMOROS => '🇰🇲',
- Country_Code::SAINT_KITTS_AND_NEVIS => '🇰🇳',
- Country_Code::NORTH_KOREA => '🇰🇵',
- Country_Code::SOUTH_KOREA => '🇰🇷',
- Country_Code::KUWAIT => '🇰🇼',
- 'KY' => '🇰🇾',
- Country_Code::KAZAKHSTAN => '🇰🇿',
- Country_Code::LAOS => '🇱🇦',
- Country_Code::LEBANON => '🇱🇧',
- Country_Code::SAINT_LUCIA => '🇱🇨',
- Country_Code::LIECHTENSTEIN => '🇱🇮',
- Country_Code::SRI_LANKA => '🇱🇰',
- Country_Code::LIBERIA => '🇱🇷',
- Country_Code::LESOTHO => '🇱🇸',
- Country_Code::LITHUANIA => '🇱🇹',
- Country_Code::LUXEMBOURG => '🇱🇺',
- Country_Code::LATVIA => '🇱🇻',
- Country_Code::LIBYA => '🇱🇾',
- Country_Code::MOROCCO => '🇲🇦',
- Country_Code::MONACO => '🇲🇨',
- Country_Code::MOLDOVA => '🇲🇩',
- Country_Code::MONTENEGRO => '🇲🇪',
- 'MF' => '🇲🇫',
- Country_Code::MADAGASCAR => '🇲🇬',
- Country_Code::MARSHALL_ISLANDS => '🇲🇭',
- Country_Code::NORTH_MACEDONIA => '🇲🇰',
- Country_Code::MALI => '🇲🇱',
- Country_Code::MYANMAR => '🇲🇲',
- Country_Code::MONGOLIA => '🇲🇳',
- 'MO' => '🇲🇴',
- 'MP' => '🇲🇵',
- 'MQ' => '🇲🇶',
- Country_Code::MAURITANIA => '🇲🇷',
- 'MS' => '🇲🇸',
- Country_Code::MALTA => '🇲🇹',
- Country_Code::MAURITIUS => '🇲🇺',
- Country_Code::MALDIVES => '🇲🇻',
- Country_Code::MALAWI => '🇲🇼',
- Country_Code::MEXICO => '🇲🇽',
- Country_Code::MALAYSIA => '🇲🇾',
- Country_Code::MOZAMBIQUE => '🇲🇿',
- Country_Code::NAMIBIA => '🇳🇦',
- 'NC' => '🇳🇨',
- Country_Code::NIGER => '🇳🇪',
- 'NF' => '🇳🇫',
- Country_Code::NIGERIA => '🇳🇬',
- Country_Code::NICARAGUA => '🇳🇮',
- Country_Code::NETHERLANDS => '🇳🇱',
- Country_Code::NORWAY => '🇳🇴',
- Country_Code::NEPAL => '🇳🇵',
- Country_Code::NAURU => '🇳🇷',
- 'NU' => '🇳🇺',
- Country_Code::NEW_ZEALAND => '🇳🇿',
- Country_Code::OMAN => '🇴🇲',
- Country_Code::PANAMA => '🇵🇦',
- Country_Code::PERU => '🇵🇪',
- 'PF' => '🇵🇫',
- Country_Code::PAPUA_NEW_GUINEA => '🇵🇬',
- Country_Code::PHILIPPINES => '🇵🇭',
- Country_Code::PAKISTAN => '🇵🇰',
- Country_Code::POLAND => '🇵🇱',
- 'PM' => '🇵🇲',
- 'PN' => '🇵🇳',
- 'PR' => '🇵🇷',
- Country_Code::PALESTINE => '🇵🇸',
- Country_Code::PORTUGAL => '🇵🇹',
- Country_Code::PALAU => '🇵🇼',
- Country_Code::PARAGUAY => '🇵🇾',
- Country_Code::QATAR => '🇶🇦',
- 'RE' => '🇷🇪',
- Country_Code::ROMANIA => '🇷🇴',
- Country_Code::SERBIA => '🇷🇸',
- Country_Code::RUSSIA => '🇷🇺',
- Country_Code::RWANDA => '🇷🇼',
- Country_Code::SAUDI_ARABIA => '🇸🇦',
- Country_Code::SOLOMON_ISLANDS => '🇸🇧',
- Country_Code::SEYCHELLES => '🇸🇨',
- Country_Code::SUDAN => '🇸🇩',
- Country_Code::SWEDEN => '🇸🇪',
- Country_Code::SINGAPORE => '🇸🇬',
- 'SH' => '🇸🇭',
- Country_Code::SLOVENIA => '🇸🇮',
- 'SJ' => '🇸🇯',
- Country_Code::SLOVAKIA => '🇸🇰',
- Country_Code::SIERRA_LEONE => '🇸🇱',
- Country_Code::SAN_MARINO => '🇸🇲',
- Country_Code::SENEGAL => '🇸🇳',
- Country_Code::SOMALIA => '🇸🇴',
- Country_Code::SURINAME => '🇸🇷',
- Country_Code::SOUTH_SUDAN => '🇸🇸',
- Country_Code::SAO_TOME_AND_PRINCIPE => '🇸🇹',
- Country_Code::EL_SALVADOR => '🇸🇻',
- 'SX' => '🇸🇽',
- Country_Code::SYRIA => '🇸🇾',
- Country_Code::ESWATINI => '🇸🇿',
- 'TC' => '🇹🇨',
- Country_Code::CHAD => '🇹🇩',
- 'TF' => '🇹🇫',
- Country_Code::TOGO => '🇹🇬',
- Country_Code::THAILAND => '🇹🇭',
- Country_Code::TAJIKISTAN => '🇹🇯',
- 'TK' => '🇹🇰',
- Country_Code::EAST_TIMOR => '🇹🇱',
- Country_Code::TURKMENISTAN => '🇹🇲',
- Country_Code::TUNISIA => '🇹🇳',
- Country_Code::TONGA => '🇹🇴',
- Country_Code::TURKEY => '🇹🇷',
- Country_Code::TRINIDAD_AND_TOBAGO => '🇹🇹',
- Country_Code::TUVALU => '🇹🇻',
- Country_Code::TAIWAN => '🇹🇼',
- Country_Code::TANZANIA => '🇹🇿',
- Country_Code::UKRAINE => '🇺🇦',
- Country_Code::UGANDA => '🇺🇬',
- 'UM' => '🇺🇲',
- Country_Code::UNITED_STATES => '🇺🇸',
- Country_Code::URUGUAY => '🇺🇾',
- Country_Code::UZBEKISTAN => '🇺🇿',
- Country_Code::VATICAN_CITY => '🇻🇦',
- Country_Code::SAINT_VINCENT_AND_THE_GRENADINES => '🇻🇨',
- Country_Code::VENEZUELA => '🇻🇪',
- 'VG' => '🇻🇬',
- 'VI' => '🇻🇮',
- Country_Code::VIETNAM => '🇻🇳',
- Country_Code::VANUATU => '🇻🇺',
- 'WF' => '🇼🇫',
- Country_Code::SAMOA => '🇼🇸',
- Country_Code::KOSOVO => '🇽🇰',
- Country_Code::YEMEN => '🇾🇪',
- 'YT' => '🇾🇹',
- Country_Code::SOUTH_AFRICA => '🇿🇦',
- Country_Code::ZAMBIA => '🇿🇲',
- Country_Code::ZIMBABWE => '🇿🇼',
+ 'AD' => '🇦🇩',
+ 'AE' => '🇦🇪',
+ 'AF' => '🇦🇫',
+ 'AG' => '🇦🇬',
+ 'AI' => '🇦🇮',
+ 'AL' => '🇦🇱',
+ 'AM' => '🇦🇲',
+ 'AO' => '🇦🇴',
+ 'AQ' => '🇦🇶',
+ 'AR' => '🇦🇷',
+ 'AS' => '🇦🇸',
+ 'AT' => '🇦🇹',
+ 'AU' => '🇦🇺',
+ 'AW' => '🇦🇼',
+ 'AX' => '🇦🇽',
+ 'AZ' => '🇦🇿',
+ 'BA' => '🇧🇦',
+ 'BB' => '🇧🇧',
+ 'BD' => '🇧🇩',
+ 'BE' => '🇧🇪',
+ 'BF' => '🇧🇫',
+ 'BG' => '🇧🇬',
+ 'BH' => '🇧🇭',
+ 'BI' => '🇧🇮',
+ 'BJ' => '🇧🇯',
+ 'BL' => '🇧🇱',
+ 'BM' => '🇧🇲',
+ 'BN' => '🇧🇳',
+ 'BO' => '🇧🇴',
+ 'BQ' => '🇧🇶',
+ 'BR' => '🇧🇷',
+ 'BS' => '🇧🇸',
+ 'BT' => '🇧🇹',
+ 'BV' => '🇧🇻',
+ 'BW' => '🇧🇼',
+ 'BY' => '🇧🇾',
+ 'BZ' => '🇧🇿',
+ 'CA' => '🇨🇦',
+ 'CC' => '🇨🇨',
+ 'CD' => '🇨🇩',
+ 'CF' => '🇨🇫',
+ 'CG' => '🇨🇬',
+ 'CH' => '🇨🇭',
+ 'CI' => '🇨🇮',
+ 'CK' => '🇨🇰',
+ 'CL' => '🇨🇱',
+ 'CM' => '🇨🇲',
+ 'CN' => '🇨🇳',
+ 'CO' => '🇨🇴',
+ 'CR' => '🇨🇷',
+ 'CU' => '🇨🇺',
+ 'CV' => '🇨🇻',
+ 'CW' => '🇨🇼',
+ 'CX' => '🇨🇽',
+ 'CY' => '🇨🇾',
+ 'CZ' => '🇨🇿',
+ 'DE' => '🇩🇪',
+ 'DJ' => '🇩🇯',
+ 'DK' => '🇩🇰',
+ 'DM' => '🇩🇲',
+ 'DO' => '🇩🇴',
+ 'DZ' => '🇩🇿',
+ 'EC' => '🇪🇨',
+ 'EE' => '🇪🇪',
+ 'EG' => '🇪🇬',
+ 'EH' => '🇪🇭',
+ 'ER' => '🇪🇷',
+ 'ES' => '🇪🇸',
+ 'ET' => '🇪🇹',
+ 'EU' => '🇪🇺',
+ 'FI' => '🇫🇮',
+ 'FJ' => '🇫🇯',
+ 'FK' => '🇫🇰',
+ 'FM' => '🇫🇲',
+ 'FO' => '🇫🇴',
+ 'FR' => '🇫🇷',
+ 'GA' => '🇬🇦',
+ 'GB' => '🇬🇧',
+ 'GD' => '🇬🇩',
+ 'GE' => '🇬🇪',
+ 'GF' => '🇬🇫',
+ 'GG' => '🇬🇬',
+ 'GH' => '🇬🇭',
+ 'GI' => '🇬🇮',
+ 'GL' => '🇬🇱',
+ 'GM' => '🇬🇲',
+ 'GN' => '🇬🇳',
+ 'GP' => '🇬🇵',
+ 'GQ' => '🇬🇶',
+ 'GR' => '🇬🇷',
+ 'GS' => '🇬🇸',
+ 'GT' => '🇬🇹',
+ 'GU' => '🇬🇺',
+ 'GW' => '🇬🇼',
+ 'GY' => '🇬🇾',
+ 'HK' => '🇭🇰',
+ 'HM' => '🇭🇲',
+ 'HN' => '🇭🇳',
+ 'HR' => '🇭🇷',
+ 'HT' => '🇭🇹',
+ 'HU' => '🇭🇺',
+ 'ID' => '🇮🇩',
+ 'IE' => '🇮🇪',
+ 'IL' => '🇮🇱',
+ 'IM' => '🇮🇲',
+ 'IN' => '🇮🇳',
+ 'IO' => '🇮🇴',
+ 'IQ' => '🇮🇶',
+ 'IR' => '🇮🇷',
+ 'IS' => '🇮🇸',
+ 'IT' => '🇮🇹',
+ 'JE' => '🇯🇪',
+ 'JM' => '🇯🇲',
+ 'JO' => '🇯🇴',
+ 'JP' => '🇯🇵',
+ 'KE' => '🇰🇪',
+ 'KG' => '🇰🇬',
+ 'KH' => '🇰🇭',
+ 'KI' => '🇰🇮',
+ 'KM' => '🇰🇲',
+ 'KN' => '🇰🇳',
+ 'KP' => '🇰🇵',
+ 'KR' => '🇰🇷',
+ 'KW' => '🇰🇼',
+ 'KY' => '🇰🇾',
+ 'KZ' => '🇰🇿',
+ 'LA' => '🇱🇦',
+ 'LB' => '🇱🇧',
+ 'LC' => '🇱🇨',
+ 'LI' => '🇱🇮',
+ 'LK' => '🇱🇰',
+ 'LR' => '🇱🇷',
+ 'LS' => '🇱🇸',
+ 'LT' => '🇱🇹',
+ 'LU' => '🇱🇺',
+ 'LV' => '🇱🇻',
+ 'LY' => '🇱🇾',
+ 'MA' => '🇲🇦',
+ 'MC' => '🇲🇨',
+ 'MD' => '🇲🇩',
+ 'ME' => '🇲🇪',
+ 'MF' => '🇲🇫',
+ 'MG' => '🇲🇬',
+ 'MH' => '🇲🇭',
+ 'MK' => '🇲🇰',
+ 'ML' => '🇲🇱',
+ 'MM' => '🇲🇲',
+ 'MN' => '🇲🇳',
+ 'MO' => '🇲🇴',
+ 'MP' => '🇲🇵',
+ 'MQ' => '🇲🇶',
+ 'MR' => '🇲🇷',
+ 'MS' => '🇲🇸',
+ 'MT' => '🇲🇹',
+ 'MU' => '🇲🇺',
+ 'MV' => '🇲🇻',
+ 'MW' => '🇲🇼',
+ 'MX' => '🇲🇽',
+ 'MY' => '🇲🇾',
+ 'MZ' => '🇲🇿',
+ 'NA' => '🇳🇦',
+ 'NC' => '🇳🇨',
+ 'NE' => '🇳🇪',
+ 'NF' => '🇳🇫',
+ 'NG' => '🇳🇬',
+ 'NI' => '🇳🇮',
+ 'NL' => '🇳🇱',
+ 'NO' => '🇳🇴',
+ 'NP' => '🇳🇵',
+ 'NR' => '🇳🇷',
+ 'NU' => '🇳🇺',
+ 'NZ' => '🇳🇿',
+ 'OM' => '🇴🇲',
+ 'PA' => '🇵🇦',
+ 'PE' => '🇵🇪',
+ 'PF' => '🇵🇫',
+ 'PG' => '🇵🇬',
+ 'PH' => '🇵🇭',
+ 'PK' => '🇵🇰',
+ 'PL' => '🇵🇱',
+ 'PM' => '🇵🇲',
+ 'PN' => '🇵🇳',
+ 'PR' => '🇵🇷',
+ 'PS' => '🇵🇸',
+ 'PT' => '🇵🇹',
+ 'PW' => '🇵🇼',
+ 'PY' => '🇵🇾',
+ 'QA' => '🇶🇦',
+ 'RE' => '🇷🇪',
+ 'RO' => '🇷🇴',
+ 'RS' => '🇷🇸',
+ 'RU' => '🇷🇺',
+ 'RW' => '🇷🇼',
+ 'SA' => '🇸🇦',
+ 'SB' => '🇸🇧',
+ 'SC' => '🇸🇨',
+ 'SD' => '🇸🇩',
+ 'SE' => '🇸🇪',
+ 'SG' => '🇸🇬',
+ 'SH' => '🇸🇭',
+ 'SI' => '🇸🇮',
+ 'SJ' => '🇸🇯',
+ 'SK' => '🇸🇰',
+ 'SL' => '🇸🇱',
+ 'SM' => '🇸🇲',
+ 'SN' => '🇸🇳',
+ 'SO' => '🇸🇴',
+ 'SR' => '🇸🇷',
+ 'SS' => '🇸🇸',
+ 'ST' => '🇸🇹',
+ 'SV' => '🇸🇻',
+ 'SX' => '🇸🇽',
+ 'SY' => '🇸🇾',
+ 'SZ' => '🇸🇿',
+ 'TC' => '🇹🇨',
+ 'TD' => '🇹🇩',
+ 'TF' => '🇹🇫',
+ 'TG' => '🇹🇬',
+ 'TH' => '🇹🇭',
+ 'TJ' => '🇹🇯',
+ 'TK' => '🇹🇰',
+ 'TL' => '🇹🇱',
+ 'TM' => '🇹🇲',
+ 'TN' => '🇹🇳',
+ 'TO' => '🇹🇴',
+ 'TR' => '🇹🇷',
+ 'TT' => '🇹🇹',
+ 'TV' => '🇹🇻',
+ 'TW' => '🇹🇼',
+ 'TZ' => '🇹🇿',
+ 'UA' => '🇺🇦',
+ 'UG' => '🇺🇬',
+ 'UM' => '🇺🇲',
+ 'US' => '🇺🇸',
+ 'UY' => '🇺🇾',
+ 'UZ' => '🇺🇿',
+ 'VA' => '🇻🇦',
+ 'VC' => '🇻🇨',
+ 'VE' => '🇻🇪',
+ 'VG' => '🇻🇬',
+ 'VI' => '🇻🇮',
+ 'VN' => '🇻🇳',
+ 'VU' => '🇻🇺',
+ 'WF' => '🇼🇫',
+ 'WS' => '🇼🇸',
+ 'XK' => '🇽🇰',
+ 'YE' => '🇾🇪',
+ 'YT' => '🇾🇹',
+ 'ZA' => '🇿🇦',
+ 'ZM' => '🇿🇲',
+ 'ZW' => '🇿🇼',
];
/**
@@ -289,12 +286,12 @@ public static function get_by_country( string $country ): 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 => '',
+ 'ANG' => '',
+ 'BTC' => '',
+ 'XAF' => '',
+ 'XCD' => '',
+ 'XOF' => '',
+ 'XPF' => '',
];
$flag = $exceptions[ $currency ] ?? self::get_by_country( substr( $currency, 0, -1 ) );
diff --git a/includes/multi-currency/Currency.php b/includes/multi-currency/Currency.php
index 0d9ae84da42..37b8fd17d12 100644
--- a/includes/multi-currency/Currency.php
+++ b/includes/multi-currency/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/includes/multi-currency/CurrencySwitcherBlock.php
index 95d4762365c..e13902c6ede 100644
--- a/includes/multi-currency/CurrencySwitcherBlock.php
+++ b/includes/multi-currency/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/Exceptions/InvalidCurrencyException.php b/includes/multi-currency/Exceptions/InvalidCurrencyException.php
index 454fa1c7383..c3ec9046a27 100644
--- a/includes/multi-currency/Exceptions/InvalidCurrencyException.php
+++ b/includes/multi-currency/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/includes/multi-currency/Exceptions/InvalidCurrencyRateException.php
index e80cc0cb92d..6f0b5b2c007 100644
--- a/includes/multi-currency/Exceptions/InvalidCurrencyRateException.php
+++ b/includes/multi-currency/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/includes/multi-currency/FrontendCurrencies.php
index da1342ac55a..065d0db24a8 100644
--- a/includes/multi-currency/FrontendCurrencies.php
+++ b/includes/multi-currency/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/Geolocation.php b/includes/multi-currency/Geolocation.php
index 5bd0b48b7db..4f5da245958 100644
--- a/includes/multi-currency/Geolocation.php
+++ b/includes/multi-currency/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/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 ) {
-
- ?>
-
- 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 '' . esc_html( $label ) . " \n";
- foreach ( $items as $item ) {
- echo '' . esc_html( $item['label'] ) . ': ';
- if ( ! empty( $item['value'] ) ) {
- echo esc_html( $item['value'] );
- } else {
- echo '' . esc_html( $not_found ) . ' ';
- }
- echo " \n";
- }
- }
- 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/multi-currency/Interfaces/MultiCurrencyAccountInterface.php b/includes/multi-currency/Interfaces/MultiCurrencyAccountInterface.php
new file mode 100644
index 00000000000..b827c5ca3d8
--- /dev/null
+++ b/includes/multi-currency/Interfaces/MultiCurrencyAccountInterface.php
@@ -0,0 +1,61 @@
+log( $level, $message, [ 'source' => self::LOG_FILE ] );
+ }
+}
diff --git a/includes/multi-currency/MultiCurrency.php b/includes/multi-currency/MultiCurrency.php
index 0d80518298e..9313a987dc9 100644
--- a/includes/multi-currency/MultiCurrency.php
+++ b/includes/multi-currency/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,25 @@ 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() ) {
+ // Due to autoloader limitations, we shouldn't initiate MCCY settings if the plugin was just upgraded:
+ // https://github.com/Automattic/woocommerce-payments/issues/9676.
+ if ( did_action( 'upgrader_process_complete' ) ) {
+ return $settings_pages;
+ }
+
+ 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 +401,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 +424,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 +435,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 +450,7 @@ function () {
'currencies' => $currency_data,
'updated' => time(),
];
- } catch ( API_Exception $e ) {
+ } catch ( \Exception $e ) {
return null;
}
},
@@ -601,7 +592,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 +630,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 +884,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 +960,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 '
';
- // No need to escape here as the function called handles it.
+ // No need to escape here as the contents of $message is already escaped.
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo \WC_Payments_Utils::esc_interpolated_html(
- $message,
- [
- 'a' => '',
- ]
- );
+ echo $message;
echo ' ' . esc_html__( 'Dismiss', 'woocommerce-payments' ) . '
';
}
@@ -1098,14 +997,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 +1021,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 );
-
- // 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' );
- }
+ public function get_file_version( $file ) {
+ $plugin_path = plugin_dir_path( $this->settings_service->get_plugin_file_path() );
- /**
- * 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 +1176,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 +1237,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/README.md b/includes/multi-currency/README.md
new file mode 100644
index 00000000000..96d828ce2d1
--- /dev/null
+++ b/includes/multi-currency/README.md
@@ -0,0 +1,5 @@
+# WooPayments multi-currency directory
+
+This directory contains the multi-currency module, which has been decoupled and extracted from the gateway code.
+
+The module is responsible for handling all multi-currency functionality, both back-end and front-end.
diff --git a/includes/multi-currency/RestController.php b/includes/multi-currency/RestController.php
index 0266b5f4e76..df36b1186b4 100644
--- a/includes/multi-currency/RestController.php
+++ b/includes/multi-currency/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/includes/multi-currency/Settings.php
index 11c74d56619..8fe0a4aafcd 100644
--- a/includes/multi-currency/Settings.php
+++ b/includes/multi-currency/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/includes/multi-currency/SettingsOnboardCta.php
index ee89ea5638c..59a2eee286f 100644
--- a/includes/multi-currency/SettingsOnboardCta.php
+++ b/includes/multi-currency/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/Utils.php b/includes/multi-currency/Utils.php
index 64e5356a77a..7b8c98e4df5 100644
--- a/includes/multi-currency/Utils.php
+++ b/includes/multi-currency/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,46 @@ 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/' );
+ }
+
+ /**
+ * Determine if the request that's currently being processed is a Store API batch request.
+ *
+ * @return bool True if the request is a Store API batch request, false otherwise.
+ */
+ public static function is_store_batch_request(): bool {
+ // @TODO We should move to a more robust way of getting to the route, like WC is doing in the StoreAPI library. https://github.com/woocommerce/woocommerce/blob/9ac48232a944baa2dbfaa7dd47edf9027cca9519/plugins/woocommerce/src/StoreApi/Authentication.php#L15-L15
+ 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 {
+ // Extract the request path from the request URL.
+ $url_parts = wp_parse_url( esc_url_raw( $_SERVER['REQUEST_URI'] ?? '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ $request_path = ! empty( $url_parts['path'] ) ? rtrim( $url_parts['path'], '/' ) : '';
+ // Remove the REST API prefix from the request path to end up with the route.
+ $rest_route = str_replace( trailingslashit( rest_get_url_prefix() ), '', $request_path );
+ }
+
+ // Bail early if the rest route is empty.
+ if ( empty( $rest_route ) ) {
+ return false;
+ }
+
+ return 1 === preg_match( '@^\/wc\/store(\/v[\d]+)?\/batch@', $rest_route );
+ }
}
diff --git a/client/multi-currency-analytics/index.js b/includes/multi-currency/client/analytics/index.js
similarity index 100%
rename from client/multi-currency-analytics/index.js
rename to includes/multi-currency/client/analytics/index.js
diff --git a/client/multi-currency/blocks/currency-switcher.js b/includes/multi-currency/client/blocks/currency-switcher.js
similarity index 99%
rename from client/multi-currency/blocks/currency-switcher.js
rename to includes/multi-currency/client/blocks/currency-switcher.js
index 5dee2d130be..75111f42768 100644
--- a/client/multi-currency/blocks/currency-switcher.js
+++ b/includes/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/includes/multi-currency/client/components/currency-delete-illustration/index.js
similarity index 100%
rename from client/components/currency-delete-illustration/index.js
rename to includes/multi-currency/client/components/currency-delete-illustration/index.js
diff --git a/client/components/currency-delete-illustration/styles.scss b/includes/multi-currency/client/components/currency-delete-illustration/styles.scss
similarity index 100%
rename from client/components/currency-delete-illustration/styles.scss
rename to includes/multi-currency/client/components/currency-delete-illustration/styles.scss
diff --git a/client/multi-currency/preview-modal/index.js b/includes/multi-currency/client/components/preview-modal/index.js
similarity index 95%
rename from client/multi-currency/preview-modal/index.js
rename to includes/multi-currency/client/components/preview-modal/index.js
index 9857ddd71e3..60d4fac0a13 100644
--- a/client/multi-currency/preview-modal/index.js
+++ b/includes/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/includes/multi-currency/client/components/preview-modal/index.scss
similarity index 100%
rename from client/multi-currency/preview-modal/index.scss
rename to includes/multi-currency/client/components/preview-modal/index.scss
diff --git a/client/components/search/index.js b/includes/multi-currency/client/components/search/index.js
similarity index 100%
rename from client/components/search/index.js
rename to includes/multi-currency/client/components/search/index.js
diff --git a/client/components/search/style.scss b/includes/multi-currency/client/components/search/style.scss
similarity index 100%
rename from client/components/search/style.scss
rename to includes/multi-currency/client/components/search/style.scss
diff --git a/client/components/search/test/__snapshots__/index.js.snap b/includes/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 includes/multi-currency/client/components/search/test/__snapshots__/index.js.snap
diff --git a/client/components/search/test/index.js b/includes/multi-currency/client/components/search/test/index.js
similarity index 100%
rename from client/components/search/test/index.js
rename to includes/multi-currency/client/components/search/test/index.js
diff --git a/client/multi-currency/context.js b/includes/multi-currency/client/context.js
similarity index 100%
rename from client/multi-currency/context.js
rename to includes/multi-currency/client/context.js
diff --git a/client/data/multi-currency/action-types.js b/includes/multi-currency/client/data/action-types.js
similarity index 100%
rename from client/data/multi-currency/action-types.js
rename to includes/multi-currency/client/data/action-types.js
diff --git a/client/data/multi-currency/actions.js b/includes/multi-currency/client/data/actions.js
similarity index 96%
rename from client/data/multi-currency/actions.js
rename to includes/multi-currency/client/data/actions.js
index 7c28cf73781..0b822dde4cb 100644
--- a/client/data/multi-currency/actions.js
+++ b/includes/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/includes/multi-currency/client/data/constants.js b/includes/multi-currency/client/data/constants.js
new file mode 100644
index 00000000000..eaee38c6ee6
--- /dev/null
+++ b/includes/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/includes/multi-currency/client/data/hooks.js
similarity index 96%
rename from client/data/multi-currency/hooks.js
rename to includes/multi-currency/client/data/hooks.js
index aa39e24ee6f..ea5c23e5e75 100644
--- a/client/data/multi-currency/hooks.js
+++ b/includes/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/includes/multi-currency/client/data/index.ts b/includes/multi-currency/client/data/index.ts
new file mode 100644
index 00000000000..f1d8d84a456
--- /dev/null
+++ b/includes/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/includes/multi-currency/client/data/reducer.js
similarity index 100%
rename from client/data/multi-currency/reducer.js
rename to includes/multi-currency/client/data/reducer.js
diff --git a/client/data/multi-currency/resolvers.js b/includes/multi-currency/client/data/resolvers.js
similarity index 93%
rename from client/data/multi-currency/resolvers.js
rename to includes/multi-currency/client/data/resolvers.js
index 4eada7da994..78168ad708a 100644
--- a/client/data/multi-currency/resolvers.js
+++ b/includes/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/includes/multi-currency/client/data/selectors.js
similarity index 96%
rename from client/data/multi-currency/selectors.js
rename to includes/multi-currency/client/data/selectors.js
index 6c2a2b20f97..825a9271db0 100644
--- a/client/data/multi-currency/selectors.js
+++ b/includes/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/includes/multi-currency/client/data/store.js b/includes/multi-currency/client/data/store.js
new file mode 100644
index 00000000000..2e142e66f9c
--- /dev/null
+++ b/includes/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/includes/multi-currency/client/index.js
similarity index 91%
rename from client/multi-currency/index.js
rename to includes/multi-currency/client/index.js
index a479c326914..f4daf3b9a3a 100644
--- a/client/multi-currency/index.js
+++ b/includes/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/includes/multi-currency/client/interface/assets.js b/includes/multi-currency/client/interface/assets.js
new file mode 100644
index 00000000000..3a3a095891a
--- /dev/null
+++ b/includes/multi-currency/client/interface/assets.js
@@ -0,0 +1,6 @@
+/**
+ * External Dependencies
+ */
+import paymentMethodsMap from 'wcpay/payment-methods-map';
+
+export { paymentMethodsMap };
diff --git a/includes/multi-currency/client/interface/components.js b/includes/multi-currency/client/interface/components.js
new file mode 100644
index 00000000000..eddab5ae84e
--- /dev/null
+++ b/includes/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/includes/multi-currency/client/interface/data.js b/includes/multi-currency/client/interface/data.js
new file mode 100644
index 00000000000..af162ddd6ed
--- /dev/null
+++ b/includes/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/includes/multi-currency/client/interface/functions.js b/includes/multi-currency/client/interface/functions.js
new file mode 100644
index 00000000000..5ffed26e00d
--- /dev/null
+++ b/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/multi-currency/client/settings/multi-currency/index.js
similarity index 87%
rename from client/multi-currency/multi-currency-settings/index.js
rename to includes/multi-currency/client/settings/multi-currency/index.js
index 89ee0fd6361..a2caf57151e 100644
--- a/client/multi-currency/multi-currency-settings/index.js
+++ b/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/multi-currency/client/settings/multi-currency/style.scss
similarity index 100%
rename from client/multi-currency/multi-currency-settings/style.scss
rename to includes/multi-currency/client/settings/multi-currency/style.scss
diff --git a/client/multi-currency/multi-currency-settings/test/__snapshots__/index.test.js.snap b/includes/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 includes/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/includes/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 includes/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/includes/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/includes/multi-currency/client/settings/single-currency/constants.js
similarity index 100%
rename from client/multi-currency/single-currency-settings/constants.js
rename to includes/multi-currency/client/settings/single-currency/constants.js
diff --git a/client/multi-currency/single-currency-settings/currency-preview.js b/includes/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 includes/multi-currency/client/settings/single-currency/currency-preview.js
index 952bc537363..8f16f4c5596 100644
--- a/client/multi-currency/single-currency-settings/currency-preview.js
+++ b/includes/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/includes/multi-currency/client/settings/single-currency/index.js
similarity index 98%
rename from client/multi-currency/single-currency-settings/index.js
rename to includes/multi-currency/client/settings/single-currency/index.js
index 213409c9f47..14a3560f14d 100644
--- a/client/multi-currency/single-currency-settings/index.js
+++ b/includes/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/includes/multi-currency/client/settings/single-currency/style.scss
similarity index 100%
rename from client/multi-currency/single-currency-settings/style.scss
rename to includes/multi-currency/client/settings/single-currency/style.scss
diff --git a/client/multi-currency/single-currency-settings/test/__snapshots__/index.test.js.snap b/includes/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 includes/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/includes/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 includes/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/includes/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/includes/multi-currency/client/setup/index.js
similarity index 77%
rename from client/multi-currency-setup/index.js
rename to includes/multi-currency/client/setup/index.js
index 512ab078182..05e76eb67ce 100644
--- a/client/multi-currency-setup/index.js
+++ b/includes/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/includes/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 includes/multi-currency/client/setup/tasks/add-currencies-task/constants.js
diff --git a/client/multi-currency-setup/tasks/add-currencies-task/index.js b/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/multi-currency/client/setup/tasks/add-currencies-task/utils.js
diff --git a/client/multi-currency-setup/tasks/multi-currency-setup.js b/includes/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 includes/multi-currency/client/setup/tasks/multi-currency-setup.js
index 77263d9bf33..cbeb6387bda 100644
--- a/client/multi-currency-setup/tasks/multi-currency-setup.js
+++ b/includes/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/includes/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 includes/multi-currency/client/setup/tasks/multi-currency-setup.scss
diff --git a/client/multi-currency-setup/tasks/setup-complete-task/index.js b/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/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/includes/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 includes/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/includes/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/includes/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 includes/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/includes/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 includes/multi-currency/client/setup/tasks/test/multi-currency-setup.test.js
diff --git a/client/multi-currency-setup/test/index.js b/includes/multi-currency/client/setup/test/index.js
similarity index 100%
rename from client/multi-currency-setup/test/index.js
rename to includes/multi-currency/client/setup/test/index.js
diff --git a/client/utils/currency/index.js b/includes/multi-currency/client/utils/currency/index.js
similarity index 100%
rename from client/utils/currency/index.js
rename to includes/multi-currency/client/utils/currency/index.js
diff --git a/client/utils/currency/test/index.js b/includes/multi-currency/client/utils/currency/test/index.js
similarity index 98%
rename from client/utils/currency/test/index.js
rename to includes/multi-currency/client/utils/currency/test/index.js
index 25e67b62c3c..0a08bbdd7db 100644
--- a/client/utils/currency/test/index.js
+++ b/includes/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/includes/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 includes/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/includes/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/includes/multi-currency/client/utils/missing-currencies-message/index.ts
similarity index 91%
rename from client/multi-currency/missing-currencies-message.ts
rename to includes/multi-currency/client/utils/missing-currencies-message/index.ts
index 514ccff973d..b6e68116479 100644
--- a/client/multi-currency/missing-currencies-message.ts
+++ b/includes/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/notes/class-wc-payments-notes-instant-deposits-eligible.php b/includes/notes/class-wc-payments-notes-instant-deposits-eligible.php
index af86a20d16e..8cd07c1513d 100644
--- a/includes/notes/class-wc-payments-notes-instant-deposits-eligible.php
+++ b/includes/notes/class-wc-payments-notes-instant-deposits-eligible.php
@@ -30,7 +30,7 @@ public static function get_note() {
$note->set_title(
sprintf(
/* translators: %s: WooPayments */
- __( 'You’re now eligible to receive Instant Deposits with %s', 'woocommerce-payments' ),
+ __( 'You’re now eligible to receive Instant Payouts with %s', 'woocommerce-payments' ),
'WooPayments'
)
);
@@ -38,10 +38,10 @@ public static function get_note() {
WC_Payments_Utils::esc_interpolated_html(
sprintf(
/* translators: %s: WooPayments */
- __( "Get immediate access to your funds when you need them – including nights, weekends, and holidays. With %s' Instant Deposits feature , you're able to transfer your earnings to a debit card within minutes.", 'woocommerce-payments' ),
+ __( "Get immediate access to your funds when you need them – including nights, weekends, and holidays. With %s' Instant Payouts feature , you're able to transfer your earnings to a debit card within minutes.", 'woocommerce-payments' ),
'WooPayments'
),
- [ 'a' => '' ]
+ [ 'a' => ' ' ]
)
);
$note->set_content_data( (object) [] );
@@ -50,8 +50,8 @@ public static function get_note() {
$note->set_source( 'woocommerce-payments' );
$note->add_action(
self::NOTE_NAME,
- __( 'Request an instant deposit', 'woocommerce-payments' ),
- 'https://woocommerce.com/document/woopayments/deposits/instant-deposits/#request-an-instant-deposit',
+ __( 'Request an instant payout', 'woocommerce-payments' ),
+ 'https://woocommerce.com/document/woopayments/payouts/instant-payouts/#request-an-instant-payout',
'unactioned',
true
);
diff --git a/includes/payment-methods/class-affirm-payment-method.php b/includes/payment-methods/class-affirm-payment-method.php
index f65794e555d..24dba99b021 100644
--- a/includes/payment-methods/class-affirm-payment-method.php
+++ b/includes/payment-methods/class-affirm-payment-method.php
@@ -11,7 +11,6 @@
use WC_Payments_Utils;
use WCPay\Constants\Country_Code;
use WCPay\Constants\Currency_Code;
-use WCPay\MultiCurrency\MultiCurrency;
/**
* Affirm Payment Method class extending UPE base class
@@ -35,29 +34,17 @@ public function __construct( $token_service ) {
$this->dark_icon_url = plugins_url( 'assets/images/payment-methods/affirm-logo-dark.svg', WCPAY_PLUGIN_FILE );
$this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::CANADIAN_DOLLAR ];
$this->accept_only_domestic_payment = true;
- $this->limits_per_currency = [
- Currency_Code::CANADIAN_DOLLAR => [
- Country_Code::CANADA => [
- 'min' => 5000,
- 'max' => 3000000,
- ], // Represents CAD 50 - 30,000 CAD.
- ],
- Currency_Code::UNITED_STATES_DOLLAR => [
- Country_Code::UNITED_STATES => [
- 'min' => 5000,
- 'max' => 3000000,
- ], // Represents USD 50 - 30,000 USD.
- ],
- ];
+ $this->limits_per_currency = WC_Payments_Utils::get_bnpl_limits_per_currency( self::PAYMENT_METHOD_STRIPE_ID );
$this->countries = [ Country_Code::UNITED_STATES, Country_Code::CANADA ];
}
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php
index f4d1ef541aa..a0a4acbbf30 100644
--- a/includes/payment-methods/class-afterpay-payment-method.php
+++ b/includes/payment-methods/class-afterpay-payment-method.php
@@ -34,38 +34,7 @@ public function __construct( $token_service ) {
$this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::CANADIAN_DOLLAR, Currency_Code::AUSTRALIAN_DOLLAR, Currency_Code::NEW_ZEALAND_DOLLAR, Currency_Code::POUND_STERLING ];
$this->countries = [ Country_Code::UNITED_STATES, Country_Code::CANADA, Country_Code::AUSTRALIA, Country_Code::NEW_ZEALAND, Country_Code::UNITED_KINGDOM ];
$this->accept_only_domestic_payment = true;
- $this->limits_per_currency = [
- Currency_Code::AUSTRALIAN_DOLLAR => [
- Country_Code::AUSTRALIA => [
- 'min' => 100,
- 'max' => 200000,
- ], // Represents AUD 1 - 2,000 AUD.
- ],
- Currency_Code::CANADIAN_DOLLAR => [
- Country_Code::CANADA => [
- 'min' => 100,
- 'max' => 200000,
- ], // Represents CAD 1 - 2,000 CAD.
- ],
- Currency_Code::NEW_ZEALAND_DOLLAR => [
- Country_Code::NEW_ZEALAND => [
- 'min' => 100,
- 'max' => 200000,
- ], // Represents NZD 1 - 2,000 NZD.
- ],
- Currency_Code::POUND_STERLING => [
- Country_Code::UNITED_KINGDOM => [
- 'min' => 100,
- 'max' => 120000,
- ], // Represents GBP 1 - 1,200 GBP.
- ],
- Currency_Code::UNITED_STATES_DOLLAR => [
- Country_Code::UNITED_STATES => [
- 'min' => 100,
- 'max' => 400000,
- ], // Represents USD 1 - 4,000 USD.
- ],
- ];
+ $this->limits_per_currency = WC_Payments_Utils::get_bnpl_limits_per_currency( self::PAYMENT_METHOD_STRIPE_ID );
}
/**
@@ -102,9 +71,10 @@ public function get_icon( string $account_country = null ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-bancontact-payment-method.php b/includes/payment-methods/class-bancontact-payment-method.php
index 6d4f845416c..422636084ff 100644
--- a/includes/payment-methods/class-bancontact-payment-method.php
+++ b/includes/payment-methods/class-bancontact-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-becs-payment-method.php b/includes/payment-methods/class-becs-payment-method.php
index 1d2c20b5b70..763a181d059 100644
--- a/includes/payment-methods/class-becs-payment-method.php
+++ b/includes/payment-methods/class-becs-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return __( 'Test mode: use the test account number 000123456 . Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here .', 'woocommerce-payments' );
}
}
diff --git a/includes/payment-methods/class-cc-payment-method.php b/includes/payment-methods/class-cc-payment-method.php
index 4ec498aa182..3f0c114aa8a 100644
--- a/includes/payment-methods/class-cc-payment-method.php
+++ b/includes/payment-methods/class-cc-payment-method.php
@@ -8,6 +8,7 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Test_Cards;
/**
* Credit card Payment Method class extending UPE base class
@@ -67,9 +68,16 @@ public function get_title( string $account_country = null, $payment_details = fa
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
- return __( 'Test mode: use test card 4242 4242 4242 4242 or refer to our testing guide .', 'woocommerce-payments' );
+ public function get_testing_instructions( string $account_country ) {
+ $test_card_number = Country_Test_Cards::get_test_card_for_country( $account_country );
+
+ return sprintf(
+ // Translators: %s is a test card number.
+ __( 'Use test card %s or refer to our testing guide .', 'woocommerce-payments' ),
+ $test_card_number
+ );
}
}
diff --git a/includes/payment-methods/class-eps-payment-method.php b/includes/payment-methods/class-eps-payment-method.php
index 5b2e73ed441..ab936ace70d 100644
--- a/includes/payment-methods/class-eps-payment-method.php
+++ b/includes/payment-methods/class-eps-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-giropay-payment-method.php b/includes/payment-methods/class-giropay-payment-method.php
index b117382f0da..82095ffbf33 100644
--- a/includes/payment-methods/class-giropay-payment-method.php
+++ b/includes/payment-methods/class-giropay-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-ideal-payment-method.php b/includes/payment-methods/class-ideal-payment-method.php
index 084499b6efe..5c1ac9abfbe 100644
--- a/includes/payment-methods/class-ideal-payment-method.php
+++ b/includes/payment-methods/class-ideal-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-klarna-payment-method.php b/includes/payment-methods/class-klarna-payment-method.php
index 44b93f56979..aaea0697423 100644
--- a/includes/payment-methods/class-klarna-payment-method.php
+++ b/includes/payment-methods/class-klarna-payment-method.php
@@ -34,76 +34,7 @@ public function __construct( $token_service ) {
$this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::POUND_STERLING, Currency_Code::EURO, Currency_Code::DANISH_KRONE, Currency_Code::NORWEGIAN_KRONE, Currency_Code::SWEDISH_KRONA ];
$this->accept_only_domestic_payment = true;
$this->countries = [ Country_Code::UNITED_STATES, Country_Code::UNITED_KINGDOM, Country_Code::AUSTRIA, Country_Code::GERMANY, Country_Code::NETHERLANDS, Country_Code::BELGIUM, Country_Code::SPAIN, Country_Code::ITALY, Country_Code::IRELAND, Country_Code::DENMARK, Country_Code::FINLAND, Country_Code::NORWAY, Country_Code::SWEDEN, Country_Code::FRANCE ];
- $this->limits_per_currency = [
- Currency_Code::UNITED_STATES_DOLLAR => [
- Country_Code::UNITED_STATES => [
- 'min' => 0,
- 'max' => 1000000,
- ],
- ],
- Currency_Code::POUND_STERLING => [
- Country_Code::UNITED_KINGDOM => [
- 'min' => 0,
- 'max' => 1150000,
- ],
- ],
- Currency_Code::EURO => [
- Country_Code::AUSTRIA => [
- 'min' => 1,
- 'max' => 1000000,
- ],
- Country_Code::BELGIUM => [
- 'min' => 1,
- 'max' => 1000000,
- ],
- Country_Code::GERMANY => [
- 'min' => 1,
- 'max' => 1000000,
- ],
- Country_Code::NETHERLANDS => [
- 'min' => 1,
- 'max' => 1500000,
- ],
- Country_Code::FINLAND => [
- 'min' => 0,
- 'max' => 1000000,
- ],
- Country_Code::SPAIN => [
- 'min' => 0,
- 'max' => 1000000,
- ],
- Country_Code::IRELAND => [
- 'min' => 0,
- 'max' => 400000,
- ],
- Country_Code::ITALY => [
- 'min' => 0,
- 'max' => 1000000,
- ],
- Country_Code::FRANCE => [
- 'min' => 3500,
- 'max' => 400000,
- ],
- ],
- Currency_Code::DANISH_KRONE => [
- Country_Code::DENMARK => [
- 'min' => 100,
- 'max' => 100000000,
- ],
- ],
- Currency_Code::NORWEGIAN_KRONE => [
- Country_Code::NORWAY => [
- 'min' => 0,
- 'max' => 100000000,
- ],
- ],
- Currency_Code::SWEDISH_KRONA => [
- Country_Code::SWEDEN => [
- 'min' => 0,
- 'max' => 15000000,
- ],
- ],
- ];
+ $this->limits_per_currency = WC_Payments_Utils::get_bnpl_limits_per_currency( self::PAYMENT_METHOD_STRIPE_ID );
}
/**
@@ -139,9 +70,10 @@ public function get_countries() {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-link-payment-method.php b/includes/payment-methods/class-link-payment-method.php
index 6a9b904a03f..c5c189bbad8 100644
--- a/includes/payment-methods/class-link-payment-method.php
+++ b/includes/payment-methods/class-link-payment-method.php
@@ -34,9 +34,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-p24-payment-method.php b/includes/payment-methods/class-p24-payment-method.php
index 8718911b480..4237beab155 100644
--- a/includes/payment-methods/class-p24-payment-method.php
+++ b/includes/payment-methods/class-p24-payment-method.php
@@ -36,9 +36,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-sepa-payment-method.php b/includes/payment-methods/class-sepa-payment-method.php
index 8ea671f7706..012828be15c 100644
--- a/includes/payment-methods/class-sepa-payment-method.php
+++ b/includes/payment-methods/class-sepa-payment-method.php
@@ -40,9 +40,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return __( 'Test mode: use the test account number AT611904300234573201 . Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here .', 'woocommerce-payments' );
}
}
diff --git a/includes/payment-methods/class-sofort-payment-method.php b/includes/payment-methods/class-sofort-payment-method.php
index 2f4f4fba212..291ff6c2b95 100644
--- a/includes/payment-methods/class-sofort-payment-method.php
+++ b/includes/payment-methods/class-sofort-payment-method.php
@@ -37,9 +37,10 @@ public function __construct( $token_service ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- public function get_testing_instructions() {
+ public function get_testing_instructions( string $account_country ) {
return '';
}
}
diff --git a/includes/payment-methods/class-upe-payment-method.php b/includes/payment-methods/class-upe-payment-method.php
index eaaad1bfbad..2e69e916c1b 100644
--- a/includes/payment-methods/class-upe-payment-method.php
+++ b/includes/payment-methods/class-upe-payment-method.php
@@ -171,11 +171,28 @@ public function is_enabled_at_checkout( string $account_country ) {
// This part ensures that when payment limits for the currency declared, those will be respected (e.g. BNPLs).
if ( [] !== $this->limits_per_currency ) {
+ $order = null;
+ if ( is_wc_endpoint_url( 'order-pay' ) ) {
+ $order = wc_get_order( absint( get_query_var( 'order-pay' ) ) );
+ $order = is_a( $order, 'WC_Order' ) ? $order : null;
+ }
+
$currency = get_woocommerce_currency();
+ if ( $order ) {
+ $currency = $order->get_currency();
+ }
+
// If the currency limits are not defined, we allow the PM for now (gateway has similar validation for limits).
- // Additionally, we don't engage with limits verification in no-checkout context (cart is not available or empty).
- if ( isset( $this->limits_per_currency[ $currency ], WC()->cart ) ) {
- $amount = WC_Payments_Utils::prepare_amount( WC()->cart->get_total( '' ), $currency );
+ $total = null;
+ if ( $order ) {
+ $total = $order->get_total();
+ } elseif ( isset( WC()->cart ) ) {
+ $total = WC()->cart->get_total( '' );
+ }
+
+ if ( isset( $this->limits_per_currency[ $currency ], WC()->cart ) && ! empty( $total ) ) {
+ $amount = WC_Payments_Utils::prepare_amount( $total, $currency );
+
if ( $amount > 0 ) {
$range = null;
if ( isset( $this->limits_per_currency[ $currency ][ $account_country ] ) ) {
@@ -253,9 +270,10 @@ public function get_payment_token_for_user( $user, $payment_method_id ) {
/**
* Returns testing credentials to be printed at checkout in test mode.
*
+ * @param string $account_country The country of the account.
* @return string
*/
- abstract public function get_testing_instructions();
+ abstract public function get_testing_instructions( string $account_country );
/**
* Returns the payment method icon URL or an empty string.
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/package-lock.json b/package-lock.json
index 8f0358c6674..866b3bae7b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,19 +1,19 @@
{
"name": "woocommerce-payments",
- "version": "8.4.0",
+ "version": "8.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "woocommerce-payments",
- "version": "8.4.0",
+ "version": "8.5.0",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@automattic/interpolate-components": "1.2.1",
"@fingerprintjs/fingerprintjs": "3.4.1",
- "@stripe/connect-js": "3.3.12",
- "@stripe/react-connect-js": "3.3.13",
+ "@stripe/connect-js": "3.3.16",
+ "@stripe/react-connect-js": "3.3.17",
"@stripe/react-stripe-js": "2.5.1",
"@stripe/stripe-js": "1.15.1",
"@woocommerce/explat": "2.3.0",
@@ -9158,16 +9158,16 @@
}
},
"node_modules/@stripe/connect-js": {
- "version": "3.3.12",
- "resolved": "https://registry.npmjs.org/@stripe/connect-js/-/connect-js-3.3.12.tgz",
- "integrity": "sha512-hXbgvGq9Lb6BYgsb8lcbjL76Yqsxr0yAj6T9ZFTfUK0O4otI5GSEWum9do9rf/E5OfYy6fR1FG/77Jve2w1o6Q=="
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/@stripe/connect-js/-/connect-js-3.3.16.tgz",
+ "integrity": "sha512-lMUKJJaDl6qzjp+czNn+N6wMwFXwLawmB2jNNgds8SeR+bXCVCXevzJ8dfF92KfmexKg++hBYagF9e99sEMBJQ=="
},
"node_modules/@stripe/react-connect-js": {
- "version": "3.3.13",
- "resolved": "https://registry.npmjs.org/@stripe/react-connect-js/-/react-connect-js-3.3.13.tgz",
- "integrity": "sha512-kMxYjeQUcl/ixu/mSeX5QGIr/MuP+YxFSEBdb8j6w+tbK82tmcjyFDgoQTQwVXNqUV6jI66Kks3XcfpPRfeiJA==",
+ "version": "3.3.17",
+ "resolved": "https://registry.npmjs.org/@stripe/react-connect-js/-/react-connect-js-3.3.17.tgz",
+ "integrity": "sha512-uxCh6ACcSWS/t0kBeqvvRieBI9pRxh2rPxt6NpjrTg3Ft1ZDleUfg9OAjkfoOT3Ta+FTomouA19l2ju7If2h5A==",
"peerDependencies": {
- "@stripe/connect-js": ">=3.3.11",
+ "@stripe/connect-js": ">=3.3.16",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
diff --git a/package.json b/package.json
index 952111032f4..ba36d21ebc4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce-payments",
- "version": "8.4.0",
+ "version": "8.5.0",
"main": "webpack.config.js",
"author": "Automattic",
"license": "GPL-3.0-or-later",
@@ -38,6 +38,7 @@
"test:e2e-dev": "NODE_CONFIG_DIR='tests/e2e/config' JEST_PUPPETEER_CONFIG='tests/e2e/config/jest-puppeteer.config.js' wp-scripts test-e2e --config tests/e2e/config/jest.config.js --puppeteer-interactive",
"test:e2e-performance": "NODE_CONFIG_DIR='tests/e2e/config' wp-scripts test-e2e --config tests/e2e/config/jest.performance.config.js",
"test:e2e-pw": "./tests/e2e-pw/test-e2e-pw.sh",
+ "test:e2e-pw-update-snapshots": "npm run test:e2e-pw -- --update-snapshots",
"test:e2e-pw-ui": "./tests/e2e-pw/test-e2e-pw-ui.sh",
"test:e2e-pw-ci": "npx playwright test --config=tests/e2e-pw/playwright.config.ts --grep-invert @todo",
"test:update-snapshots": "npm run test:js -- --updateSnapshot",
@@ -77,8 +78,8 @@
"dependencies": {
"@automattic/interpolate-components": "1.2.1",
"@fingerprintjs/fingerprintjs": "3.4.1",
- "@stripe/connect-js": "3.3.12",
- "@stripe/react-connect-js": "3.3.13",
+ "@stripe/connect-js": "3.3.16",
+ "@stripe/react-connect-js": "3.3.17",
"@stripe/react-stripe-js": "2.5.1",
"@stripe/stripe-js": "1.15.1",
"@woocommerce/explat": "2.3.0",
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 6e21606d2bb..e997f0fa2fd 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -102,7 +102,7 @@
tests/*
- includes/multi-currency
+ includes/multi-currency/*
src
diff --git a/readme.txt b/readme.txt
index cc050c3699e..3ab2095536d 100644
--- a/readme.txt
+++ b/readme.txt
@@ -2,9 +2,9 @@
Contributors: woocommerce, automattic
Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment gateway
Requires at least: 6.0
-Tested up to: 6.6
+Tested up to: 6.7
Requires PHP: 7.3
-Stable tag: 8.4.0
+Stable tag: 8.5.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -24,7 +24,7 @@ Features previously only available on your payment provider’s website are now
- View the details of [payments, refunds, and other transactions](https://woocommerce.com/document/woopayments/managing-money/).
- View and respond to [disputes and chargebacks](https://woocommerce.com/document/woopayments/fraud-and-disputes/managing-disputes/).
-- [Track deposits](https://woocommerce.com/document/woopayments/deposits/) into your bank account or debit card.
+- [Track payouts](https://woocommerce.com/document/woopayments/payouts/) into your bank account or debit card.
**Pay as you go**
@@ -94,6 +94,40 @@ Please note that our support for the checkout block is still experimental and th
== Changelog ==
+= 8.5.0 - 2024-11-13 =
+* Add - Add country-specific test card numbers for credit card testing
+* Add - Add risk level information to the fraud and risk box on the order details page.
+* Add - Add support for allowedShippingCountries in Express Checkout Element.
+* Fix - Avoid PHP warnings for requests with an empty path.
+* Fix - BNPL methods now work properly in Pay for Order when they are available. Default values are also provided when available.
+* Fix - fix: payment method icon alt text
+* Fix - Fix compatibility issues with CustomSelectControl component styles for WordPress 6.7
+* Fix - Fix duplicate saving of 3DS card entry after checkout
+* Fix - Fixed single product page view tracks when BNPL and PRB payment methods are inactive.
+* Fix - Fix PMME appearance in checkout
+* Fix - Fix settings display on the advanced fraud protection page.
+* Fix - Fix WooPay button preview in plugin settings.
+* Fix - Fix WooPay duplicated Save my info section.
+* Fix - Include missing scripts that handle refunds for non credit card payments in the order details page.
+* Fix - Introducing consistency in colors for deposits across pages
+* Fix - Prevent dead space on product pages when no BNPL offers are available.
+* Fix - Provide backwards-compatible method for retrieving the multi-currency instance.
+* Fix - Register Expresss Checkout block only when enabled in the settings
+* Fix - Remove unnecessary '.woocommerce-table' css overrides to fix WC Analytics styling and a11y issues
+* Fix - Use 'Withdrawal' and 'Deducted' labels when referring to withdrawal deposits, to more accurately communicate the type of transaction that has occurred
+* Update - Add in-memory cache fallback for our database-cached objects in case of database write failures.
+* Update - Decoupled Multi-currency module from gateway dependencies.
+* Update - Improvements to events during onboarding flow.
+* Update - Refactor loadStripe for Express Checkouts.
+* Update - Rename 'deposit' to 'payout' across various places in the WooPayments admin UI, docs and doc URLs.
+* Update - update: payment method "test mode" label at checkout to be displayed only when payment method is selected
+* Update - update: show LPM payment method icon on order success page
+* Update - Use preview versions of the actual ECE buttons in the Block editor.
+* Update - When tracking is enabled, send a tracks event when the merchant is redirected to a Stripe Capital offer.
+* Dev - Add Jest tests for the disputed order notices
+* Dev - Add unit tests for the Capital Loans page component.
+* Dev - Bump WC tested up to version to 9.4.0
+
= 8.4.0 - 2024-10-23 =
* Add - Add test mode badge to classic checkout and add payment method.
* Add - Using Floating Labels with Stripe Appearance API for Blocks Checkout
diff --git a/tasks/release.js b/tasks/release.js
index 92559af4ffb..92b8c2986de 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 );
+// The '/includes/multi-currency/client' directory is removed because '/includes/multi-currency/*' should contain only server-side files.
+// Furthermore, the './client' directory is already included in 'dist' during the build step.
+rm( '-rf', targetFolder + '/includes/multi-currency/client' );
+
const output = fs.createWriteStream(
releaseFolder + '/' + pluginSlug + '.zip'
);
diff --git a/tests/e2e-pw/README.md b/tests/e2e-pw/README.md
index c91f61a345d..9bcbd373f33 100644
--- a/tests/e2e-pw/README.md
+++ b/tests/e2e-pw/README.md
@@ -39,7 +39,7 @@ Prefer the use of [user-facing attribute or test-id locators](https://playwright
```ts
// Prefer locating by role, label, text, or test id when possible. See https://playwright.dev/docs/locators
-await page.getByRole( 'button', { name: 'All deposits' } ).click();
+await page.getByRole( 'button', { name: 'All payouts' } ).click();
await page.getByLabel( 'Select a deposit status' ).selectOption( 'Pending' );
await expect( page.getByText( 'Order received' ) ).toBeVisible();
await page.getByTestId( 'accept-dispute-button' ).click();
@@ -56,7 +56,7 @@ Visual regression tests are captured by the [`toHaveScreenshot()` function](http
await expect( page ).toHaveScreenshot();
await expect(
- page.getByRole( 'button', { name: 'All deposits' } )
+ page.getByRole( 'button', { name: 'All payouts' } )
).toHaveScreenshot();
```
diff --git a/tests/e2e-pw/specs/merchant/__snapshots__/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png b/tests/e2e-pw/specs/merchant/__snapshots__/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png
index a982090d756..394c5495e14 100644
Binary files a/tests/e2e-pw/specs/merchant/__snapshots__/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png and b/tests/e2e-pw/specs/merchant/__snapshots__/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png differ
diff --git a/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts b/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
index c0e20768b36..6c2e6b41e72 100644
--- a/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
+++ b/tests/e2e-pw/specs/merchant/merchant-admin-deposits.spec.ts
@@ -10,7 +10,7 @@ test.describe( 'Merchant deposits', () => {
test( 'Load the deposits list page', async ( { page } ) => {
await page.goto(
- '/wp-admin/admin.php?page=wc-admin&path=/payments/deposits'
+ '/wp-admin/admin.php?page=wc-admin&path=/payments/payouts'
);
// Wait for the deposits table to load.
@@ -20,14 +20,14 @@ test.describe( 'Merchant deposits', () => {
expect(
page.getByRole( 'heading', {
- name: 'Deposit history',
+ name: 'Payout history',
} )
).toBeVisible();
} );
test( 'Select deposits list advanced filters', async ( { page } ) => {
await page.goto(
- '/wp-admin/admin.php?page=wc-admin&path=/payments/deposits'
+ '/wp-admin/admin.php?page=wc-admin&path=/payments/payouts'
);
// Wait for the deposits table to load.
@@ -36,7 +36,7 @@ test.describe( 'Merchant deposits', () => {
.waitFor( { state: 'hidden' } );
// Open the advanced filters.
- await page.getByRole( 'button', { name: 'All deposits' } ).click();
+ await page.getByRole( 'button', { name: 'All payouts' } ).click();
await page.getByRole( 'button', { name: 'Advanced filters' } ).click();
// Select a filter
@@ -45,7 +45,7 @@ test.describe( 'Merchant deposits', () => {
// Select a filter option
await page
- .getByLabel( 'Select a deposit status', {
+ .getByLabel( 'Select a payout status', {
exact: true,
} )
.selectOption( 'Pending' );
diff --git a/tests/e2e-pw/specs/shopper/klarna-checkout-purchase.spec.ts b/tests/e2e-pw/specs/shopper/klarna-checkout-purchase.spec.ts
index b810f32ecb0..1ce6d5917a0 100644
--- a/tests/e2e-pw/specs/shopper/klarna-checkout-purchase.spec.ts
+++ b/tests/e2e-pw/specs/shopper/klarna-checkout-purchase.spec.ts
@@ -68,6 +68,7 @@ test.describe( 'Klarna Checkout', () => {
await shopperPage
.locator( '.wc_payment_methods' )
.getByText( 'Klarna' )
+ .nth( 1 )
.click();
await shopper.placeOrder( shopperPage );
diff --git a/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js b/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js
index 47a7c18363d..9363910e44b 100644
--- a/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js
+++ b/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js
@@ -16,7 +16,7 @@ describe( 'Admin deposits', () => {
it( 'page should load without any errors', async () => {
await merchantWCP.openDeposits();
await expect( page ).toMatchElement( 'h2', {
- text: 'Deposit history',
+ text: 'Payout history',
} );
await takeScreenshot( 'merchant-admin-deposits' );
} );
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js
index 4bf7ea14b9b..8c8c4a30c83 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js
@@ -8,9 +8,12 @@ import { uiUnblocked } from '@woocommerce/e2e-utils/build/page-utils';
* Internal dependencies
*/
import { merchantWCP, shopperWCP } from '../../../utils/flows';
-import { setupProductCheckout } from '../../../utils/payments';
+import {
+ selectOnCheckout,
+ setupProductCheckout,
+} from '../../../utils/payments';
-const bnplProviders = [ [ 'Affirm' ], [ 'Afterpay' ] ];
+const bnplProviders = [ [ 'affirm' ], [ 'afterpay_clearpay' ] ];
const UPE_METHOD_CHECKBOXES = [
"//label[contains(text(), 'Affirm')]/preceding-sibling::span/input[@type='checkbox']", // affirm
@@ -49,8 +52,8 @@ describe.each( cardTestingPreventionStates )(
describe.each( bnplProviders )(
`Checkout with %s, carding protection ${ cardTestingPreventionEnabled }`,
- ( providerName ) => {
- it( `should successfully place order with ${ providerName }`, async () => {
+ ( providerId ) => {
+ it( `should successfully place order with ${ providerId }`, async () => {
await shopperWCP.emptyCart();
await setupProductCheckout(
config.get( 'addresses.customer.billing' ),
@@ -58,12 +61,7 @@ describe.each( cardTestingPreventionStates )(
);
await uiUnblocked();
// Select BNPL provider as payment method.
- const xPathPaymentMethodSelector = `//*[@id='payment']/ul/li/label[contains(text(), '${ providerName }')]`;
- await page.waitForXPath( xPathPaymentMethodSelector );
- const [ paymentMethodLabel ] = await page.$x(
- xPathPaymentMethodSelector
- );
- await paymentMethodLabel.click();
+ await selectOnCheckout( providerId, page );
// Check the token presence when card testing prevention is enabled.
if ( cardTestingPreventionEnabled ) {
diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js
index 8ceda112015..87d5740af7d 100644
--- a/tests/e2e/utils/flows.js
+++ b/tests/e2e/utils/flows.js
@@ -35,7 +35,7 @@ const WCPAY_CONNECT =
const WCPAY_DISPUTES =
baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/disputes';
const WCPAY_DEPOSITS =
- baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/deposits';
+ baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/payouts';
const WCPAY_TRANSACTIONS =
baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/transactions';
const WCPAY_MULTI_CURRENCY =
diff --git a/tests/fixtures/captured-payments/discount.json b/tests/fixtures/captured-payments/discount.json
index a4abc8f1419..2fa6a911d74 100644
--- a/tests/fixtures/captured-payments/discount.json
+++ b/tests/fixtures/captured-payments/discount.json
@@ -67,6 +67,6 @@
"fixed": "Fixed fee: -$0.30"
}
},
- "netString": "Net deposit: $105.48 USD"
+ "netString": "Net payout: $105.48 USD"
}
}
diff --git a/tests/fixtures/captured-payments/foreign-card.json b/tests/fixtures/captured-payments/foreign-card.json
index d78a39b09ba..234878b2372 100644
--- a/tests/fixtures/captured-payments/foreign-card.json
+++ b/tests/fixtures/captured-payments/foreign-card.json
@@ -55,6 +55,6 @@
"additional-international": "International card fee: 1%",
"additional-fx": "Foreign exchange fee: 1%"
},
- "netString": "Net deposit: $95.47 USD"
+ "netString": "Net payout: $95.47 USD"
}
}
diff --git a/tests/fixtures/captured-payments/fx-decimal.json b/tests/fixtures/captured-payments/fx-decimal.json
index af570251b01..b95e9318c84 100644
--- a/tests/fixtures/captured-payments/fx-decimal.json
+++ b/tests/fixtures/captured-payments/fx-decimal.json
@@ -47,6 +47,6 @@
"base": "Base fee: 2.9% + $0.30",
"additional-fx": "Foreign exchange fee: 1%"
},
- "netString": "Net deposit: $100.65 USD"
+ "netString": "Net payout: $100.65 USD"
}
}
diff --git a/tests/fixtures/captured-payments/fx-foreign-card.json b/tests/fixtures/captured-payments/fx-foreign-card.json
index 834e1ea580c..836c8433065 100644
--- a/tests/fixtures/captured-payments/fx-foreign-card.json
+++ b/tests/fixtures/captured-payments/fx-foreign-card.json
@@ -47,6 +47,6 @@
"base": "Base fee: 2.9% + $0.30",
"additional-international": "International card fee: 1%"
},
- "netString": "Net deposit: $96.80 USD"
+ "netString": "Net payout: $96.80 USD"
}
}
diff --git a/tests/fixtures/captured-payments/fx-partial-capture.json b/tests/fixtures/captured-payments/fx-partial-capture.json
index be8d55c3f08..f10ff7aa9e9 100644
--- a/tests/fixtures/captured-payments/fx-partial-capture.json
+++ b/tests/fixtures/captured-payments/fx-partial-capture.json
@@ -64,6 +64,6 @@
"fixed": "Fixed fee: -$0.03"
}
},
- "netString": "Net deposit: $16.79 USD"
+ "netString": "Net payout: $16.79 USD"
}
}
diff --git a/tests/fixtures/captured-payments/fx-with-capped-fee.json b/tests/fixtures/captured-payments/fx-with-capped-fee.json
index b8ca2d7f6be..8c1b602a3eb 100644
--- a/tests/fixtures/captured-payments/fx-with-capped-fee.json
+++ b/tests/fixtures/captured-payments/fx-with-capped-fee.json
@@ -57,6 +57,6 @@
"additional-international": "International card fee: 1.5%",
"additional-fx": "Foreign exchange fee: 1%"
},
- "netString": "Net deposit: $971.04 USD"
+ "netString": "Net payout: $971.04 USD"
}
}
diff --git a/tests/fixtures/captured-payments/fx.json b/tests/fixtures/captured-payments/fx.json
index ab61a700a87..8ceee7b7438 100644
--- a/tests/fixtures/captured-payments/fx.json
+++ b/tests/fixtures/captured-payments/fx.json
@@ -48,6 +48,6 @@
"base": "Base fee: 2.9% + $0.30",
"additional-fx": "Foreign exchange fee: 1%"
},
- "netString": "Net deposit: $95.84 USD"
+ "netString": "Net payout: $95.84 USD"
}
}
diff --git a/tests/fixtures/captured-payments/jpy-payment.json b/tests/fixtures/captured-payments/jpy-payment.json
index 0361538516d..6c7a6b3ee05 100644
--- a/tests/fixtures/captured-payments/jpy-payment.json
+++ b/tests/fixtures/captured-payments/jpy-payment.json
@@ -59,6 +59,6 @@
"additional-international": "International card fee: 2%",
"additional-fx": "Foreign exchange fee: 2%"
},
- "netString": "Net deposit: ¥4,507 JPY"
+ "netString": "Net payout: ¥4,507 JPY"
}
}
diff --git a/tests/fixtures/captured-payments/only-base-fee.json b/tests/fixtures/captured-payments/only-base-fee.json
index d9867053c18..8bc5bf67d38 100644
--- a/tests/fixtures/captured-payments/only-base-fee.json
+++ b/tests/fixtures/captured-payments/only-base-fee.json
@@ -35,6 +35,6 @@
},
"expectation": {
"feeString": "Base fee (2.9% + $0.30): -$0.74",
- "netString": "Net deposit: $14.26 USD"
+ "netString": "Net payout: $14.26 USD"
}
}
diff --git a/tests/fixtures/captured-payments/partial-capture.json b/tests/fixtures/captured-payments/partial-capture.json
index a902014a17f..d6112a5cf70 100644
--- a/tests/fixtures/captured-payments/partial-capture.json
+++ b/tests/fixtures/captured-payments/partial-capture.json
@@ -38,6 +38,6 @@
},
"expectation": {
"feeString": "Base fee (2.9% + $0.30): -$0.82",
- "netString": "Net deposit: $17.18 USD"
+ "netString": "Net payout: $17.18 USD"
}
}
diff --git a/tests/fixtures/captured-payments/subscription.json b/tests/fixtures/captured-payments/subscription.json
index 168337a34dc..b7312ea0c02 100644
--- a/tests/fixtures/captured-payments/subscription.json
+++ b/tests/fixtures/captured-payments/subscription.json
@@ -56,6 +56,6 @@
"additional-fx": "Foreign exchange fee: 1%",
"additional-wcpay-subscription": "Subscription transaction fee: 1%"
},
- "netString": "Net deposit: $52.87 USD"
+ "netString": "Net payout: $52.87 USD"
}
}
diff --git a/tests/js/jest.config.js b/tests/js/jest.config.js
index 18c11bc9553..7a918a8d63c 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',
+ '/includes/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(.*)$': '/includes/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/admin/test-class-wc-payments-admin.php b/tests/unit/admin/test-class-wc-payments-admin.php
index 25612ab0f9a..6a16577f18c 100644
--- a/tests/unit/admin/test-class-wc-payments-admin.php
+++ b/tests/unit/admin/test-class-wc-payments-admin.php
@@ -271,7 +271,7 @@ public function data_maybe_redirect_from_payments_admin_child_pages() {
false,
[
'page' => 'wc-admin',
- 'path' => '/payments/deposits',
+ 'path' => '/payments/payouts',
],
],
'not working Jetpack connection - valid Stripe account' => [
@@ -280,7 +280,7 @@ public function data_maybe_redirect_from_payments_admin_child_pages() {
true,
[
'page' => 'wc-admin',
- 'path' => '/payments/deposits',
+ 'path' => '/payments/payouts',
],
],
'working Jetpack connection - valid Stripe account' => [
diff --git a/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php b/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php
index 42560d5da90..383b6a9c50d 100644
--- a/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php
+++ b/tests/unit/admin/test-class-wc-rest-payments-accounts-controller.php
@@ -48,6 +48,9 @@ public function set_up() {
$property_reflection->setAccessible( true );
$this->original_api_client = $property_reflection->getValue( $account_service );
$property_reflection->setValue( $account_service, $this->mock_api_client );
+
+ // Clear the account cache before each test.
+ $account_service->clear_cache();
}
public function tear_down() {
diff --git a/tests/unit/core/service/test-class-wc-payments-customer-service-api.php b/tests/unit/core/service/test-class-wc-payments-customer-service-api.php
index e4d64b5b02e..3e7e515187e 100644
--- a/tests/unit/core/service/test-class-wc-payments-customer-service-api.php
+++ b/tests/unit/core/service/test-class-wc-payments-customer-service-api.php
@@ -41,7 +41,7 @@ class WC_Payments_Customer_Service_API_Test extends WCPAY_UnitTestCase {
/**
* Filter callback to return the mock http client
*
- * @return void
+ * @return WC_Payments_Http|MockObject
*/
public function replace_http_client() {
return $this->mock_http_client;
@@ -79,6 +79,9 @@ public function tear_down() {
[ $this, 'replace_http_client' ]
);
+ // Clear the cache after each test.
+ $this->customer_service->delete_cached_payment_methods();
+
parent::tear_down();
}
@@ -316,7 +319,7 @@ function ( $data ): bool {
$response = $this->customer_service_api->get_payment_methods_for_customer( 'cus_12345' );
- // When the payment methods are unable to update, a empty array is sent back.
+ // When the payment methods are unable to update, an empty array is sent back.
$this->assertEquals( [], $response );
}
@@ -447,19 +450,19 @@ function ( $data ): bool {
$response = $this->customer_service_api->get_payment_methods_for_customer( 'cus_123' );
$this->assertEquals( $mock_payment_methods, $response );
- // check if can retrieve from cache.
+ // check if we can retrieve from cache.
$db_cache = WC_Payments::get_database_cache();
$cache_response = $db_cache->get( Database_Cache::PAYMENT_METHODS_KEY_PREFIX . 'cus_123_card' );
$this->assertEquals( $mock_payment_methods, $cache_response );
// set up the user for customer.
- update_user_option( 1, self::CUSTOMER_LIVE_META_KEY, 'cus_test123' );
+ update_user_option( 1, self::CUSTOMER_LIVE_META_KEY, 'cus_123' );
// run the method.
- $this->customer_service_api->clear_cached_payment_methods_for_user( 'cus_123' );
+ $this->customer_service_api->clear_cached_payment_methods_for_user( 1 );
// check that cache is empty.
- $cache_response = $db_cache->get( Database_Cache::PAYMENT_METHODS_KEY_PREFIX . 'cus_12345_card' );
+ $cache_response = $db_cache->get( Database_Cache::PAYMENT_METHODS_KEY_PREFIX . 'cus_123_card' );
$this->assertEquals( null, $cache_response );
}
diff --git a/tests/unit/fraud-prevention/test-class-order-fraud-and-risk-meta-box.php b/tests/unit/fraud-prevention/test-class-order-fraud-and-risk-meta-box.php
index dbe604c82e2..e8ea5223e13 100644
--- a/tests/unit/fraud-prevention/test-class-order-fraud-and-risk-meta-box.php
+++ b/tests/unit/fraud-prevention/test-class-order-fraud-and-risk-meta-box.php
@@ -12,7 +12,6 @@
* Fraud_Prevention_Service_Test unit tests.
*/
class Order_Fraud_And_Risk_Meta_Box_Test extends WCPAY_UnitTestCase {
-
/**
* Test WC_Order object.
*
@@ -72,11 +71,16 @@ public function test_display_order_fraud_and_risk_meta_box_message_with_provider
->method( 'get_fraud_meta_box_type_for_order' )
->willReturn( $meta_box_type );
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( '' );
+
// Act: Call the method to display the meta box.
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
// Assert: Check to make sure the expected string has been output.
- $this->expectOutputString( $expected_output );
+ $this->expectOutputString( $this->compose_fraud_and_risk_actions_block( $expected_output ) );
}
public function display_order_fraud_and_risk_meta_box_message_provider() {
@@ -91,7 +95,7 @@ public function display_order_fraud_and_risk_meta_box_message_provider() {
],
'Fraud_Meta_Box_Type_REVIEW' => [
'meta_box_type' => Fraud_Meta_Box_Type::REVIEW,
- 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. You can review the details and determine whether to approve or block the payment.
Review payment ',
+ 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. You can review the details and determine whether to approve or block the payment.
Review payment
',
],
'Fraud_Meta_Box_Type_REVIEW_ALLOWED' => [
'meta_box_type' => Fraud_Meta_Box_Type::REVIEW_ALLOWED,
@@ -99,15 +103,15 @@ public function display_order_fraud_and_risk_meta_box_message_provider() {
],
'Fraud_Meta_Box_Type_REVIEW_BLOCKED' => [
'meta_box_type' => Fraud_Meta_Box_Type::REVIEW_BLOCKED,
- 'expected_output' => ' Held for review
This transaction was held for review by your risk filters, and the charge was manually blocked after review.
Review payment ',
+ 'expected_output' => ' Held for review
This transaction was held for review by your risk filters, and the charge was manually blocked after review.
Review payment
',
],
'Fraud_Meta_Box_Type_REVIEW_EXPIRED' => [
'meta_box_type' => Fraud_Meta_Box_Type::REVIEW_EXPIRED,
- 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have expired.
Review payment ',
+ 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have expired.
Review payment
',
],
'Fraud_Meta_Box_Type_REVIEW_FAILED' => [
'meta_box_type' => Fraud_Meta_Box_Type::REVIEW_FAILED,
- 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have failed.
Review payment ',
+ 'expected_output' => ' Held for review
The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have failed.
Review payment
',
],
'Fraud_Meta_Box_Type_TERMINAL_PAYMENT' => [
'meta_box_type' => Fraud_Meta_Box_Type::TERMINAL_PAYMENT,
@@ -130,6 +134,10 @@ public function test_display_order_fraud_and_risk_meta_box_message_exits_if_no_o
->expects( $this->never() )
->method( 'get_fraud_meta_box_type_for_order' );
+ $this->mock_order_service
+ ->expects( $this->never() )
+ ->method( 'get_charge_risk_level_for_order' );
+
// Act: Call the method to display the meta box.
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( 'fake_order' );
@@ -154,11 +162,16 @@ public function test_display_order_fraud_and_risk_meta_box_message_block() {
->method( 'get_fraud_meta_box_type_for_order' )
->willReturn( Fraud_Meta_Box_Type::BLOCK );
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( '' );
+
// Act: Call the method to display the meta box.
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
// Assert: Check to make sure the expected string has been output.
- $this->expectOutputString( ' Blocked
The payment for this order was blocked by your risk filtering. There is no pending authorization, and the order can be cancelled to reduce any held stock.
View more details ' );
+ $this->expectOutputString( $this->compose_fraud_and_risk_actions_block( ' Blocked
The payment for this order was blocked by your risk filtering. There is no pending authorization, and the order can be cancelled to reduce any held stock.
View more details
' ) );
}
/**
@@ -183,6 +196,11 @@ public function test_display_order_fraud_and_risk_meta_box_message_not_card_with
->method( 'get_fraud_meta_box_type_for_order' )
->willReturn( Fraud_Meta_Box_Type::NOT_CARD );
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( '' );
+
// Arrange: Update the order's payment method.
$this->order->set_payment_method( $payment_method_id );
$this->order->set_payment_method_title( $payment_method_title );
@@ -192,7 +210,7 @@ public function test_display_order_fraud_and_risk_meta_box_message_not_card_with
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
// Assert: Check to make sure the expected string has been output.
- $this->expectOutputString( $expected_output );
+ $this->expectOutputString( $this->compose_fraud_and_risk_actions_block( $expected_output, false ) );
}
public function display_order_fraud_and_risk_meta_box_message_not_card_provider() {
@@ -200,17 +218,17 @@ public function display_order_fraud_and_risk_meta_box_message_not_card_provider(
'simulate legacy UPE Popular payment methods' => [
'payment_method_id' => 'woocommerce_payments',
'payment_method_title' => 'Popular payment methods',
- 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments.
Learn more ',
+ 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments.
Learn more
',
],
'simulate legacy UPE Bancontact' => [
'payment_method_id' => 'woocommerce_payments',
'payment_method_title' => 'Bancontact',
- 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Bancontact.
Learn more ',
+ 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Bancontact.
Learn more
',
],
'simulate split UPE Bancontact' => [
'payment_method_id' => 'woocommerce_payments_bancontact',
'payment_method_title' => 'Bancontact',
- 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Bancontact.
Learn more ',
+ 'expected_output' => 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Bancontact.
Learn more
',
],
];
}
@@ -232,6 +250,11 @@ public function test_display_order_fraud_and_risk_meta_box_message_not_wcpay() {
->method( 'get_fraud_meta_box_type_for_order' )
->willReturn( '' );
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( '' );
+
// Arrange: Update the order's payment method.
$this->order->set_payment_method( 'bacs' );
$this->order->save();
@@ -240,7 +263,7 @@ public function test_display_order_fraud_and_risk_meta_box_message_not_wcpay() {
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
// Assert: Check to make sure the expected string has been output.
- $this->expectOutputString( 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Direct bank transfer.
Learn more ' );
+ $this->expectOutputString( $this->compose_fraud_and_risk_actions_block( 'Risk filtering is only available for orders processed using credit cards with WooPayments. This order was processed with Direct bank transfer.
Learn more
', false ) );
}
public function test_display_order_fraud_and_risk_meta_box_message_default() {
@@ -260,10 +283,165 @@ public function test_display_order_fraud_and_risk_meta_box_message_default() {
->method( 'get_fraud_meta_box_type_for_order' )
->willReturn( '' );
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( '' );
+
+ // Act: Call the method to display the meta box.
+ $this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
+
+ // Assert: Check to make sure the expected string has been output.
+ $this->expectOutputString( $this->compose_fraud_and_risk_actions_block( 'Risk filtering through WooPayments was not found on this order, it may have been created while filtering was not enabled.
' ) );
+ }
+
+ public function test_display_risk_level_normal_in_order_fraud_and_risk_meta_box() {
+ // Arrange: Set the return results for the order service methods.
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_intent_id_for_order' )
+ ->willReturn( 'pi_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_id_for_order' )
+ ->willReturn( 'ch_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_fraud_meta_box_type_for_order' )
+ ->willReturn( Fraud_Meta_Box_Type::ALLOW );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( 'normal' );
+
+ // Act: Call the method to display the meta box.
+ $this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
+
+ // Assert: Check to make sure the expected string has been output.
+ $risk_level_block = $this->compose_fraud_and_risk_level_block( 'normal', 'Normal', 'This payment shows a lower than normal risk of fraudulent activity.' );
+ $risk_actions_block = $this->compose_fraud_and_risk_actions_block( ' No action taken
The payment for this order passed your risk filtering.
' );
+
+ $this->expectOutputString( $risk_level_block . $risk_actions_block );
+ }
+
+ public function test_display_risk_level_elevated_in_order_fraud_and_risk_meta_box() {
+ // Arrange: Set the return results for the order service methods.
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_intent_id_for_order' )
+ ->willReturn( 'pi_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_id_for_order' )
+ ->willReturn( 'ch_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_fraud_meta_box_type_for_order' )
+ ->willReturn( Fraud_Meta_Box_Type::ALLOW );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( 'elevated' );
+
+ // Act: Call the method to display the meta box.
+ $this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
+
+ // Assert: Check to make sure the expected string has been output.
+ $risk_level_block = $this->compose_fraud_and_risk_level_block( 'elevated', 'Elevated', 'This order has a moderate risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.' );
+ $risk_actions_block = $this->compose_fraud_and_risk_actions_block( ' No action taken
The payment for this order passed your risk filtering.
' );
+
+ $this->expectOutputString( $risk_level_block . $risk_actions_block );
+ }
+
+ public function test_display_risk_level_highest_in_order_fraud_and_risk_meta_box() {
+ // Arrange: Set the return results for the order service methods.
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_intent_id_for_order' )
+ ->willReturn( 'pi_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_id_for_order' )
+ ->willReturn( 'ch_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_fraud_meta_box_type_for_order' )
+ ->willReturn( Fraud_Meta_Box_Type::ALLOW );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( 'highest' );
+
+ // Act: Call the method to display the meta box.
+ $this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
+
+ // Assert: Check to make sure the expected string has been output.
+ $risk_level_block = $this->compose_fraud_and_risk_level_block( 'highest', 'High', 'This order has a high risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.' );
+ $risk_actions_block = $this->compose_fraud_and_risk_actions_block( ' No action taken
The payment for this order passed your risk filtering.
' );
+
+ $this->expectOutputString( $risk_level_block . $risk_actions_block );
+ }
+
+ public function test_do_not_display_risk_level_in_order_fraud_and_risk_meta_box_with_invalid_risk_level() {
+ // Arrange: Set the return results for the order service methods.
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_intent_id_for_order' )
+ ->willReturn( 'pi_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_id_for_order' )
+ ->willReturn( 'ch_mock' );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_fraud_meta_box_type_for_order' )
+ ->willReturn( Fraud_Meta_Box_Type::ALLOW );
+
+ $this->mock_order_service
+ ->expects( $this->once() )
+ ->method( 'get_charge_risk_level_for_order' )
+ ->willReturn( 'unknown' );
+
// Act: Call the method to display the meta box.
$this->order_fraud_and_risk_meta_box->display_order_fraud_and_risk_meta_box_message( $this->order );
// Assert: Check to make sure the expected string has been output.
- $this->expectOutputString( 'Risk filtering through WooPayments was not found on this order, it may have been created while filtering was not enabled.
' );
+ $risk_actions_block = $this->compose_fraud_and_risk_actions_block( ' No action taken
The payment for this order passed your risk filtering.
' );
+
+ $this->expectOutputString( $risk_actions_block );
+ }
+
+ private function compose_fraud_and_risk_level_block( $risk_level, $title, $description ) {
+ $output = '';
+ $output .= '
' . $title . '
';
+ $output .= '
';
+ $output .= '
' . $description . '
';
+ $output .= '
';
+
+ return $output;
+ }
+
+ private function compose_fraud_and_risk_actions_block( $content, $show_adjust_risk_filters_link = true ) {
+ $output = '';
+ $output .= $content;
+
+ if ( $show_adjust_risk_filters_link ) {
+ $output .= '
Adjust risk filters
';
+ }
+
+ $output .= '
';
+
+ return $output;
}
}
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/test-class-database-cache.php b/tests/unit/test-class-database-cache.php
index e8f5e8822ab..4b23eece139 100644
--- a/tests/unit/test-class-database-cache.php
+++ b/tests/unit/test-class-database-cache.php
@@ -163,7 +163,6 @@ function () use ( &$called_generator ) {
public function test_get_or_add_handles_error_when_there_was_no_old_data() {
$refreshed = false;
$called_generator = false;
- $value = [ 'mock' => true ];
$res = $this->database_cache->get_or_add(
self::MOCK_KEY,
@@ -220,7 +219,7 @@ public function test_get_or_add_does_not_refresh_errored_out_invalid_value() {
$res = $this->database_cache->get_or_add(
self::MOCK_KEY,
- function () use ( $value ) {
+ function () use ( $value, &$called_generator ) {
$called_generator = true;
return $value;
},
@@ -235,6 +234,290 @@ function () use ( $value ) {
$this->assert_cache_contains( $old, true );
}
+ public function test_get_or_add_does_not_refresh_on_subsequent_db_write_errors() {
+ $old = [ 'old' => true ];
+ $value = [ 'mock' => true ];
+ $another_value = [ 'another_mock' => true ];
+
+ // Write an expired cache value.
+ $this->write_mock_cache( $old, time() - YEAR_IN_SECONDS );
+
+ // All DB write queries will fail.
+ add_filter(
+ 'query',
+ function ( $query ) {
+ if ( str_starts_with( $query, 'UPDATE' ) || str_starts_with( $query, 'INSERT INTO' ) ) {
+ return false;
+ }
+
+ return $query;
+ }
+ );
+
+ // First call will call the generator, fail to write to the DB, and cache the value in the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $value, &$called_generator ) {
+ $called_generator = true;
+
+ return $value;
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+ $this->assert_cache_contains( $old );
+
+ // The second call will NOT call the generator, but the value will be returned from the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( &$called_generator ) {
+ $called_generator = true;
+
+ return [];
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertFalse( $refreshed );
+ $this->assertFalse( $called_generator );
+ $this->assert_cache_contains( $old );
+
+ remove_all_filters( 'query' );
+
+ // The third call will NOT call the generator, NOT write to the DB, but the value will be returned from the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( &$called_generator ) {
+ $called_generator = true;
+
+ return [];
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertFalse( $refreshed );
+ $this->assertFalse( $called_generator );
+ $this->assert_cache_contains( $old );
+
+ // Fourth call will call the generator, write to the DB, and cache the value in the in-memory cache,
+ // but only because we are forcing it to refresh.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $another_value, &$called_generator ) {
+ $called_generator = true;
+
+ return $another_value;
+ },
+ '__return_true',
+ true, // It will refresh only because we are forcing it.
+ $refreshed
+ );
+
+ $this->assertEquals( $another_value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+ $this->assert_cache_contains( $another_value );
+ }
+
+ public function test_get_or_add_with_no_cached_data_fetches_but_does_not_refresh_on_subsequent_db_write_errors() {
+ $value = [ 'mock' => true ];
+ $another_value = [ 'another_mock' => true ];
+
+ // All DB write queries will fail.
+ add_filter(
+ 'query',
+ function ( $query ) {
+ if ( str_starts_with( $query, 'UPDATE' ) || str_starts_with( $query, 'INSERT INTO' ) ) {
+ return false;
+ }
+
+ return $query;
+ }
+ );
+
+ // First call will call the generator, fail to write to the DB, and cache the value in the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $value, &$called_generator ) {
+ $called_generator = true;
+
+ return $value;
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+
+ // The second call will NOT call the generator, but the value will be returned from the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( &$called_generator ) {
+ $called_generator = true;
+
+ return [];
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertFalse( $refreshed );
+ $this->assertFalse( $called_generator );
+
+ remove_all_filters( 'query' );
+
+ // Third call will call the generator, write to the DB, and cache the value in the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $another_value, &$called_generator ) {
+ $called_generator = true;
+
+ return $another_value;
+ },
+ '__return_true',
+ true, // It will refresh only because we are forcing it.
+ $refreshed
+ );
+
+ $this->assertEquals( $another_value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+ $this->assert_cache_contains( $another_value );
+ }
+
+ public function test_get_or_add_refreshes_on_cache_cleared_despite_previous_db_write_errors() {
+ $old = [ 'old' => true ];
+ $value = [ 'mock' => true ];
+ $another_value = [ 'another_mock' => true ];
+
+ // Write an expired cache value.
+ $this->write_mock_cache( $old, time() - YEAR_IN_SECONDS );
+
+ // All DB write queries will fail.
+ add_filter(
+ 'query',
+ function ( $query ) {
+ if ( str_starts_with( $query, 'UPDATE' ) || str_starts_with( $query, 'INSERT INTO' ) ) {
+ return false;
+ }
+
+ return $query;
+ }
+ );
+
+ // First call will call the generator, fail to write to the DB, and cache the value in the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $value, &$called_generator ) {
+ $called_generator = true;
+
+ return $value;
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+ $this->assert_cache_contains( $old );
+
+ // The second call will NOT call the generator, but the value will be returned from the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( &$called_generator ) {
+ $called_generator = true;
+
+ return [];
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $value, $res );
+ $this->assertFalse( $refreshed );
+ $this->assertFalse( $called_generator );
+
+ // Clear the cache.
+ $this->database_cache->delete( self::MOCK_KEY );
+
+ // Third call will call the generator, fail to write to the DB, and cache the value in the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( $another_value, &$called_generator ) {
+ $called_generator = true;
+
+ return $another_value;
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $another_value, $res );
+ $this->assertTrue( $refreshed );
+ $this->assertTrue( $called_generator );
+
+ // Fourth call will NOT call the generator, but the value will be returned from the in-memory cache.
+ $called_generator = false;
+ $refreshed = false;
+ $res = $this->database_cache->get_or_add(
+ self::MOCK_KEY,
+ function () use ( &$called_generator ) {
+ $called_generator = true;
+
+ return [];
+ },
+ '__return_true',
+ false,
+ $refreshed
+ );
+
+ $this->assertEquals( $another_value, $res );
+ $this->assertFalse( $refreshed );
+ $this->assertFalse( $called_generator );
+
+ remove_all_filters( 'query' );
+ }
+
public function test_get_or_add_does_not_refresh_if_disabled() {
$refreshed = false;
$value = [ 'mock' => true ];
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php
index b638c07e6dd..bb90e4f4460 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php
@@ -197,6 +197,21 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
*/
private $locale_backup;
+
+ /**
+ * Backup of $wp->query_vars
+ *
+ * @var array
+ */
+ private $wp_query_vars_backup;
+
+ /**
+ * Backup of $wp_query->query_vars
+ *
+ * @var array
+ */
+ private $wp_query_query_vars_backup;
+
/**
* Pre-test setup
*/
@@ -281,6 +296,11 @@ public function set_up() {
wcpay_get_test_container()->replace( OrderService::class, $mock_order_service );
$this->locale_backup = WC()->countries->get_country_locale();
+
+ global $wp;
+ global $wp_query;
+ $this->wp_query_vars_backup = $wp->query_vars;
+ $this->wp_query_query_vars_backup = $wp_query->query_vars;
}
/**
@@ -318,6 +338,11 @@ public function tear_down() {
wcpay_get_test_container()->reset_all_replacements();
WC()->session->set( 'wc_notices', [] );
WC()->countries->locale = $this->locale_backup;
+
+ global $wp;
+ global $wp_query;
+ $wp->query_vars = $this->wp_query_vars_backup;
+ $wp_query->query_vars = $this->wp_query_query_vars_backup;
}
public function test_process_redirect_payment_intent_processing() {
@@ -706,6 +731,77 @@ function ( $order ) {
$this->assertFalse( $afterpay_method->is_enabled_at_checkout( 'US' ) );
}
+ public function test_payment_methods_enabled_based_on_currency_limits() {
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ WC()->session->init();
+ WC()->cart->empty_cart();
+ // Total is 100 USD, which is above both payment methods (Affirm and AfterPay) minimums.
+ WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 10 );
+ WC()->cart->calculate_totals();
+
+ $affirm_method = $this->payment_methods['affirm'];
+ $afterpay_method = $this->payment_methods['afterpay_clearpay'];
+
+ $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ }
+
+ public function test_payment_methods_disabled_based_on_currency_limits() {
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ WC()->session->init();
+ WC()->cart->empty_cart();
+ // Total is 40 USD, which is below Affirm minimum.
+ WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 4 );
+ WC()->cart->calculate_totals();
+
+ $affirm_method = $this->payment_methods['affirm'];
+ $afterpay_method = $this->payment_methods['afterpay_clearpay'];
+
+ $this->assertFalse( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ }
+
+ public function test_payment_methods_enabled_based_on_currency_limits_in_order_pay() {
+ global $wp;
+ global $wp_query;
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ // Total is 100 USD, which is above both payment methods (Affirm and AfterPay) minimums.
+ $order = WC_Helper_Order::create_order( 1, 100 );
+ $order_id = $order->get_id();
+ $wp->query_vars = [ 'order-pay' => strval( $order_id ) ];
+ $wp_query->query_vars = [ 'order-pay' => strval( $order_id ) ];
+
+ $affirm_method = $this->payment_methods['affirm'];
+ $afterpay_method = $this->payment_methods['afterpay_clearpay'];
+
+ $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ }
+
+ public function test_payment_methods_disabled_based_on_currency_limits_in_order_pay() {
+ global $wp;
+ global $wp_query;
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ // Total is 40 USD, which is below Affirm minimum.
+ $order = WC_Helper_Order::create_order( 1, 40 );
+ $order_id = $order->get_id();
+ $wp->query_vars = [ 'order-pay' => strval( $order_id ) ];
+ $wp_query->query_vars = [ 'order-pay' => strval( $order_id ) ];
+ $order->set_currency( 'USD' );
+
+ $affirm_method = $this->payment_methods['affirm'];
+ $afterpay_method = $this->payment_methods['afterpay_clearpay'];
+
+ $this->assertFalse( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ }
+
public function test_only_valid_payment_methods_returned_for_currency() {
$card_method = $this->payment_methods['card'];
$giropay_method = $this->payment_methods['giropay'];
diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php
index 1c471baa5fd..962c7bc4d8b 100644
--- a/tests/unit/test-class-wc-payments-checkout.php
+++ b/tests/unit/test-class-wc-payments-checkout.php
@@ -103,9 +103,6 @@ public function set_up() {
->disableOriginalConstructor()
->getMock();
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
- $this->mock_wcpay_account
- ->method( 'get_account_country' )
- ->willReturn( 'US' );
$this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class );
$this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
@@ -309,6 +306,9 @@ public function test_force_network_saved_cards_disabled_when_should_not_use_stri
}
public function test_link_payment_method_provided_when_card_enabled() {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$icon_url = 'test-icon-url';
$dark_icon_url = 'test-dark-icon-url';
$this->mock_wcpay_gateway
@@ -382,7 +382,7 @@ public function test_link_payment_method_provided_when_card_enabled() {
'darkIcon' => $dark_icon_url,
'showSaveOption' => true,
'countries' => [],
- 'testingInstructions' => 'Test mode: use test card 4242 4242 4242 4242 or refer to our testing guide .',
+ 'testingInstructions' => 'Use test card 4242 4242 4242 4242 or refer to our testing guide .',
'forceNetworkSavedCards' => false,
],
'link' => [
@@ -404,6 +404,10 @@ public function test_link_payment_method_provided_when_card_enabled() {
* @dataProvider non_reusable_payment_method_provider
*/
public function test_no_save_option_for_non_reusable_payment_method( $payment_method_id, $payment_method_class ) {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
+
$this->mock_wcpay_gateway
->expects( $this->any() )
->method( 'get_payment_method_ids_enabled_at_checkout' )
@@ -434,6 +438,9 @@ public function non_reusable_payment_method_provider() {
}
public function test_no_save_option_for_reusable_payment_payment_with_subscription_in_cart() {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$this->mock_wcpay_gateway
->method( 'is_subscription_item_in_cart' )
->willReturn( true );
@@ -460,6 +467,9 @@ public function test_no_save_option_for_reusable_payment_payment_with_subscripti
}
public function test_no_save_option_for_reusable_payment_payment_but_with_saved_cards_disabled() {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$this->mock_wcpay_gateway
->method( 'is_subscription_item_in_cart' )
->willReturn( false );
@@ -486,6 +496,9 @@ public function test_no_save_option_for_reusable_payment_payment_but_with_saved_
}
public function test_save_option_for_reusable_payment_payment() {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$this->mock_wcpay_gateway
->method( 'is_subscription_item_in_cart' )
->willReturn( false );
@@ -512,6 +525,9 @@ public function test_save_option_for_reusable_payment_payment() {
}
public function test_upe_appearance_transients() {
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$this->mock_wcpay_gateway
->expects( $this->any() )
->method( 'get_payment_method_ids_enabled_at_checkout' )
@@ -536,4 +552,60 @@ public function test_upe_appearance_transients() {
$this->assertSame( 'night', $js_config['wcBlocksUPEAppearanceTheme'] );
$this->assertFalse( $js_config['upeAddPaymentMethodAppearance'] );
}
+
+ /**
+ * Data provider for testing different country card numbers
+ */
+ public function country_test_cards_provider(): array {
+ return [
+ 'US card' => [
+ 'country' => 'US',
+ 'expected_card' => '4242 4242 4242 4242',
+ ],
+ 'Brazil card' => [
+ 'country' => 'BR',
+ 'expected_card' => '4000 0007 6000 0002',
+ ],
+ 'UK card' => [
+ 'country' => 'GB',
+ 'expected_card' => '4000 0082 6000 0000',
+ ],
+ 'Invalid country defaults to US' => [
+ 'country' => 'XX',
+ 'expected_card' => '4242 4242 4242 4242',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider country_test_cards_provider
+ */
+ public function test_credit_card_testing_instructions_by_country( string $country, string $expected_card ) {
+ $cc_payment_method = new CC_Payment_Method( $this->mock_token_service );
+
+ $this->mock_wcpay_account
+ ->expects( $this->once() )
+ ->method( 'get_account_country' )
+ ->willReturn( $country );
+
+ $this->mock_wcpay_gateway
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [ 'card' ] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->willReturn( $cc_payment_method );
+
+ $config = $this->system_under_test->get_payment_fields_js_config();
+
+ $expected_instructions = sprintf(
+ 'Use test card %s or refer to our testing guide .',
+ $expected_card
+ );
+
+ $this->assertEquals(
+ $expected_instructions,
+ $config['paymentMethodsConfig']['card']['testingInstructions']
+ );
+ }
}
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/tests/unit/test-class-wc-payments-utils.php b/tests/unit/test-class-wc-payments-utils.php
index a7aba06f9ab..61aa747fc00 100644
--- a/tests/unit/test-class-wc-payments-utils.php
+++ b/tests/unit/test-class-wc-payments-utils.php
@@ -931,12 +931,6 @@ public function test_get_cached_minimum_amount_returns_null_without_cache() {
$this->assertNull( $result );
}
- public function test_get_cached_minimum_amount_returns_amount_fallbacking_from_stripe_list() {
- delete_transient( 'wcpay_minimum_amount_usd' );
- $result = WC_Payments_Utils::get_cached_minimum_amount( 'usd', true );
- $this->assertSame( 50, $result );
- }
-
public function test_get_last_refund_from_order_id_returns_correct_refund() {
$order = WC_Helper_Order::create_order();
$refund_1 = wc_create_refund( [ 'order_id' => $order->get_id() ] );
@@ -1115,8 +1109,98 @@ public function test_is_store_api_request_with_another_request() {
}
public function test_is_store_api_request_with_malformed_url() {
- $_SERVER['REQUEST_URI'] = '///wp-json/wp/v2/users';
+ $_SERVER['REQUEST_URI'] = '///wp-json/wc/store/v1/checkout';
$this->assertFalse( WC_Payments_Utils::is_store_api_request() );
}
+
+ public function test_is_store_api_request_with_url_with_no_path() {
+ $_SERVER['REQUEST_URI'] = '?something';
+ $this->assertFalse( WC_Payments_Utils::is_store_api_request() );
+
+ $_SERVER['REQUEST_URI'] = '';
+ $this->assertFalse( WC_Payments_Utils::is_store_api_request() );
+ }
+
+ public function test_is_any_bnpl_method_available() {
+ // Price within range for Afterpay/Clearpay in the US.
+ $this->assertTrue(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay' ],
+ 'US',
+ 'USD',
+ 100
+ )
+ );
+
+ // Price within range for Klarna in the US.
+ $this->assertTrue(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'klarna' ],
+ 'US',
+ 'USD',
+ 500
+ )
+ );
+
+ // Price below minimum for all methods.
+ $this->assertFalse(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay', 'klarna', 'affirm' ],
+ 'US',
+ 'USD',
+ 0.50
+ )
+ );
+
+ // Price above maximum for all methods.
+ $this->assertFalse(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay', 'klarna', 'affirm' ],
+ 'US',
+ 'USD',
+ 4000000
+ )
+ );
+
+ // Unsupported country.
+ $this->assertFalse(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay', 'klarna', 'affirm' ],
+ 'RU',
+ 'RUB',
+ 100
+ )
+ );
+
+ // Unsupported currency.
+ $this->assertFalse(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay', 'klarna', 'affirm' ],
+ 'US',
+ 'JPY',
+ 100
+ )
+ );
+
+ // Empty enabled methods array.
+ $this->assertFalse(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [],
+ 'US',
+ 'USD',
+ 100
+ )
+ );
+
+ // Different country, same currency (Afterpay/Clearpay in Canada).
+ $this->assertTrue(
+ WC_Payments_Utils::is_any_bnpl_method_available(
+ [ 'afterpay_clearpay' ],
+ 'CA',
+ 'CAD',
+ 100
+ )
+ );
+ }
}
diff --git a/tests/unit/test-class-wc-payments-webhook-processing-service.php b/tests/unit/test-class-wc-payments-webhook-processing-service.php
index 053fd7a554f..bf58120532c 100644
--- a/tests/unit/test-class-wc-payments-webhook-processing-service.php
+++ b/tests/unit/test-class-wc-payments-webhook-processing-service.php
@@ -1356,7 +1356,7 @@ public function test_dispute_funds_withdrawn_order_note() {
->method( 'add_order_note' )
->with(
$this->matchesRegularExpression(
- '/Payment dispute and fees have been deducted from your next deposit/'
+ '/Payment dispute and fees have been deducted from your next payout/'
)
);
diff --git a/tsconfig.json b/tsconfig.json
index 3b9efabf45e..13218eb83d0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -15,8 +15,9 @@
"paths": {
"assets/*": [ "../assets/*" ],
"wcpay/*": [ "./*" ],
+ "multi-currency/*": [ "../includes/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..7fe200a9f7a 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': './includes/multi-currency/client/index.js',
'multi-currency-switcher-block':
- './client/multi-currency/blocks/currency-switcher.js',
+ './includes/multi-currency/client/blocks/currency-switcher.js',
'multi-currency-analytics':
- './client/multi-currency-analytics/index.js',
+ './includes/multi-currency/client/analytics/index.js',
order: './client/order/index.js',
'subscriptions-empty-state':
'./client/subscriptions-empty-state/index.js',
@@ -113,9 +113,17 @@ 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(), 'includes/multi-currency/client' ),
+ 'node_modules',
+ ],
alias: {
assets: path.resolve( process.cwd(), 'assets' ),
+ 'multi-currency': path.resolve(
+ process.cwd(),
+ 'includes/multi-currency/client'
+ ),
wcpay: path.resolve( process.cwd(), 'client' ),
iti: path.resolve(
process.cwd(),
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index 7283bb20728..506001dfd88 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -8,10 +8,10 @@
* Text Domain: woocommerce-payments
* Domain Path: /languages
* WC requires at least: 7.6
- * WC tested up to: 9.3.3
+ * WC tested up to: 9.4.0
* Requires at least: 6.0
* Requires PHP: 7.3
- * Version: 8.4.0
+ * Version: 8.5.0
* Requires Plugins: woocommerce
*
* @package WooCommerce\Payments