From ffe32070d0deccd939be20186d4077188c94716c Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Nov 2021 10:40:38 +0200 Subject: [PATCH 1/4] Extract shop currency, country to services --- modules/ppcp-api-client/services.php | 26 ++++++-- .../src/Factory/AmountFactory.php | 22 ++++--- .../src/Factory/ItemFactory.php | 29 ++++++--- .../src/Helper/CurrencySupport.php | 22 ++++--- .../ppcp-api-client/src/Helper/DccApplies.php | 59 +++++++++++-------- modules/ppcp-button/services.php | 8 ++- .../ppcp-button/src/Assets/SmartButton.php | 14 ++++- .../ppcp-button/src/Helper/MessagesApply.php | 20 ++++++- .../src/Helper/MessagesDisclaimers.php | 21 +++++-- .../src/StatusReportModule.php | 4 +- modules/ppcp-wc-gateway/services.php | 4 +- .../ApiClient/Factory/AmountFactoryTest.php | 42 ++++++------- .../ApiClient/Factory/ItemFactoryTest.php | 35 +++++------ 13 files changed, 197 insertions(+), 109 deletions(-) diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index be80943bf..b46886da9 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -266,7 +266,9 @@ return array( return new PayeeFactory(); }, 'api.factory.item' => static function ( ContainerInterface $container ): ItemFactory { - return new ItemFactory(); + return new ItemFactory( + $container->get( 'api.shop.currency' ) + ); }, 'api.factory.shipping' => static function ( ContainerInterface $container ): ShippingFactory { $address_factory = $container->get( 'api.factory.address' ); @@ -274,7 +276,10 @@ return array( }, 'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory { $item_factory = $container->get( 'api.factory.item' ); - return new AmountFactory( $item_factory ); + return new AmountFactory( + $item_factory, + $container->get( 'api.shop.currency' ) + ); }, 'api.factory.payer' => static function ( ContainerInterface $container ): PayerFactory { $address_factory = $container->get( 'api.factory.address' ); @@ -309,9 +314,22 @@ return array( return new AuthorizationFactory(); }, 'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies { - return new DccApplies(); + return new DccApplies( + $container->get( 'api.shop.currency' ), + $container->get( 'api.shop.country' ) + ); }, 'api.helpers.currency-support' => static function ( ContainerInterface $container ) : CurrencySupport { - return new CurrencySupport(); + return new CurrencySupport( + $container->get( 'api.shop.currency' ) + ); + }, + + 'api.shop.currency' => static function ( ContainerInterface $container ) : string { + return get_woocommerce_currency(); + }, + 'api.shop.country' => static function ( ContainerInterface $container ) : string { + $location = wc_get_base_location(); + return $location['country']; }, ); diff --git a/modules/ppcp-api-client/src/Factory/AmountFactory.php b/modules/ppcp-api-client/src/Factory/AmountFactory.php index 7129f9dd3..c8deeb3d0 100644 --- a/modules/ppcp-api-client/src/Factory/AmountFactory.php +++ b/modules/ppcp-api-client/src/Factory/AmountFactory.php @@ -28,13 +28,22 @@ class AmountFactory { */ private $item_factory; + /** + * 3-letter currency code of the shop. + * + * @var string + */ + private $currency; + /** * AmountFactory constructor. * * @param ItemFactory $item_factory The Item factory. + * @param string $currency 3-letter currency code of the shop. */ - public function __construct( ItemFactory $item_factory ) { + public function __construct( ItemFactory $item_factory, string $currency ) { $this->item_factory = $item_factory; + $this->currency = $currency; } /** @@ -45,8 +54,7 @@ class AmountFactory { * @return Amount */ public function from_wc_cart( \WC_Cart $cart ): Amount { - $currency = get_woocommerce_currency(); - $total = new Money( (float) $cart->get_total( 'numeric' ), $currency ); + $total = new Money( (float) $cart->get_total( 'numeric' ), $this->currency ); $total_fees_amount = 0; $fees = WC()->session->get( 'ppcp_fees' ); @@ -57,22 +65,22 @@ class AmountFactory { } $item_total = $cart->get_cart_contents_total() + $cart->get_discount_total() + $total_fees_amount; - $item_total = new Money( (float) $item_total, $currency ); + $item_total = new Money( (float) $item_total, $this->currency ); $shipping = new Money( (float) $cart->get_shipping_total() + $cart->get_shipping_tax(), - $currency + $this->currency ); $taxes = new Money( $cart->get_subtotal_tax(), - $currency + $this->currency ); $discount = null; if ( $cart->get_discount_total() ) { $discount = new Money( (float) $cart->get_discount_total() + $cart->get_discount_tax(), - $currency + $this->currency ); } diff --git a/modules/ppcp-api-client/src/Factory/ItemFactory.php b/modules/ppcp-api-client/src/Factory/ItemFactory.php index b016a68df..10aa40ff8 100644 --- a/modules/ppcp-api-client/src/Factory/ItemFactory.php +++ b/modules/ppcp-api-client/src/Factory/ItemFactory.php @@ -17,7 +17,21 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; * Class ItemFactory */ class ItemFactory { + /** + * 3-letter currency code of the shop. + * + * @var string + */ + private $currency; + /** + * ItemFactory constructor. + * + * @param string $currency 3-letter currency code of the shop. + */ + public function __construct( string $currency ) { + $this->currency = $currency; + } /** * Creates items based off a WooCommerce cart. @@ -27,9 +41,8 @@ class ItemFactory { * @return Item[] */ public function from_wc_cart( \WC_Cart $cart ): array { - $currency = get_woocommerce_currency(); - $items = array_map( - static function ( array $item ) use ( $currency ): Item { + $items = array_map( + function ( array $item ): Item { $product = $item['data']; /** @@ -43,10 +56,10 @@ class ItemFactory { $price_without_tax = (float) wc_get_price_excluding_tax( $product ); $price_without_tax_rounded = round( $price_without_tax, 2 ); $tax = round( $price - $price_without_tax_rounded, 2 ); - $tax = new Money( $tax, $currency ); + $tax = new Money( $tax, $this->currency ); return new Item( mb_substr( $product->get_name(), 0, 127 ), - new Money( $price_without_tax_rounded, $currency ), + new Money( $price_without_tax_rounded, $this->currency ), $quantity, mb_substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ), $tax, @@ -61,13 +74,13 @@ class ItemFactory { $fees_from_session = WC()->session->get( 'ppcp_fees' ); if ( $fees_from_session ) { $fees = array_map( - static function ( \stdClass $fee ) use ( $currency ): Item { + function ( \stdClass $fee ): Item { return new Item( $fee->name, - new Money( (float) $fee->amount, $currency ), + new Money( (float) $fee->amount, $this->currency ), 1, '', - new Money( (float) $fee->tax, $currency ) + new Money( (float) $fee->tax, $this->currency ) ); }, $fees_from_session diff --git a/modules/ppcp-api-client/src/Helper/CurrencySupport.php b/modules/ppcp-api-client/src/Helper/CurrencySupport.php index 925ee4386..9c5bd5bc4 100644 --- a/modules/ppcp-api-client/src/Helper/CurrencySupport.php +++ b/modules/ppcp-api-client/src/Helper/CurrencySupport.php @@ -50,21 +50,27 @@ class CurrencySupport { ); /** - * Returns whether the given currency is supported. + * 3-letter currency code of the shop. * - * @param string $currency 3-letter currency code. - * @return bool + * @var string */ - public function supports_currency( string $currency ): bool { - return in_array( $currency, $this->supported_currencies, true ); + private $currency; + + /** + * CurrencySupport constructor. + * + * @param string $currency 3-letter currency code of the shop. + */ + public function __construct( string $currency ) { + $this->currency = $currency; } /** - * Returns whether the current WC currency is supported. + * Returns whether the currency is supported. * * @return bool */ - public function supports_wc_currency(): bool { - return $this->supports_currency( get_woocommerce_currency() ); + public function supports_currency(): bool { + return in_array( $this->currency, $this->supported_currencies, true ); } } diff --git a/modules/ppcp-api-client/src/Helper/DccApplies.php b/modules/ppcp-api-client/src/Helper/DccApplies.php index 3224ab7b6..ce88fc476 100644 --- a/modules/ppcp-api-client/src/Helper/DccApplies.php +++ b/modules/ppcp-api-client/src/Helper/DccApplies.php @@ -183,18 +183,41 @@ class DccApplies { ), ); + /** + * 3-letter currency code of the shop. + * + * @var string + */ + private $currency; + + /** + * 2-letter country code of the shop. + * + * @var string + */ + private $country; + + /** + * DccApplies constructor. + * + * @param string $currency 3-letter currency code of the shop. + * @param string $country 2-letter country code of the shop. + */ + public function __construct( string $currency, string $country ) { + $this->currency = $currency; + $this->country = $country; + } + /** * Returns whether DCC can be used in the current country and the current currency used. * * @return bool */ public function for_country_currency(): bool { - $country = $this->country(); - $currency = get_woocommerce_currency(); - if ( ! in_array( $country, array_keys( $this->allowed_country_currency_matrix ), true ) ) { + if ( ! in_array( $this->country, array_keys( $this->allowed_country_currency_matrix ), true ) ) { return false; } - $applies = in_array( $currency, $this->allowed_country_currency_matrix[ $country ], true ); + $applies = in_array( $this->currency, $this->allowed_country_currency_matrix[ $this->country ], true ); return $applies; } @@ -204,13 +227,12 @@ class DccApplies { * @return array */ public function valid_cards() : array { - $country = $this->country(); - $cards = array(); - if ( ! isset( $this->country_card_matrix[ $country ] ) ) { + $cards = array(); + if ( ! isset( $this->country_card_matrix[ $this->country ] ) ) { return $cards; } - $supported_currencies = $this->country_card_matrix[ $country ]; + $supported_currencies = $this->country_card_matrix[ $this->country ]; foreach ( $supported_currencies as $card => $currencies ) { if ( $this->can_process_card( $card ) ) { $cards[] = $card; @@ -233,11 +255,10 @@ class DccApplies { * @return bool */ public function can_process_card( string $card ) : bool { - $country = $this->country(); - if ( ! isset( $this->country_card_matrix[ $country ] ) ) { + if ( ! isset( $this->country_card_matrix[ $this->country ] ) ) { return false; } - if ( ! isset( $this->country_card_matrix[ $country ][ $card ] ) ) { + if ( ! isset( $this->country_card_matrix[ $this->country ][ $card ] ) ) { return false; } @@ -245,19 +266,7 @@ class DccApplies { * If the supported currencies array is empty, there are no * restrictions, which currencies are supported by a card. */ - $supported_currencies = $this->country_card_matrix[ $country ][ $card ]; - $currency = get_woocommerce_currency(); - return empty( $supported_currencies ) || in_array( $currency, $supported_currencies, true ); - } - - /** - * Returns the country code of the shop. - * - * @return string - */ - private function country() : string { - $region = wc_get_base_location(); - $country = $region['country']; - return $country; + $supported_currencies = $this->country_card_matrix[ $this->country ][ $card ]; + return empty( $supported_currencies ) || in_array( $this->currency, $supported_currencies, true ); } } diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index fa14e181e..a5901c750 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -70,6 +70,7 @@ return array( $environment = $container->get( 'onboarding.environment' ); $payment_token_repository = $container->get( 'vaulting.repository.payment-token' ); $settings_status = $container->get( 'wcgateway.settings.status' ); + $currency = $container->get( 'api.shop.currency' ); return new SmartButton( $container->get( 'button.url' ), $container->get( 'session.handler' ), @@ -82,7 +83,8 @@ return array( $messages_apply, $environment, $payment_token_repository, - $settings_status + $settings_status, + $currency ); }, 'button.url' => static function ( ContainerInterface $container ): string { @@ -171,7 +173,9 @@ return array( return new ThreeDSecure( $logger ); }, 'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply { - return new MessagesApply(); + return new MessagesApply( + $container->get( 'api.shop.country' ) + ); }, 'button.is-logged-in' => static function ( ContainerInterface $container ): bool { diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 59d25a81f..843cd49ed 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -114,6 +114,13 @@ class SmartButton implements SmartButtonInterface { */ private $payment_token_repository; + /** + * 3-letter currency code of the shop. + * + * @var string + */ + private $currency; + /** * SmartButton constructor. * @@ -129,6 +136,7 @@ class SmartButton implements SmartButtonInterface { * @param Environment $environment The environment object. * @param PaymentTokenRepository $payment_token_repository The payment token repository. * @param SettingsStatus $settings_status The Settings status helper. + * @param string $currency 3-letter currency code of the shop. */ public function __construct( string $module_url, @@ -142,7 +150,8 @@ class SmartButton implements SmartButtonInterface { MessagesApply $messages_apply, Environment $environment, PaymentTokenRepository $payment_token_repository, - SettingsStatus $settings_status + SettingsStatus $settings_status, + string $currency ) { $this->module_url = $module_url; @@ -157,6 +166,7 @@ class SmartButton implements SmartButtonInterface { $this->environment = $environment; $this->payment_token_repository = $payment_token_repository; $this->settings_status = $settings_status; + $this->currency = $currency; } /** @@ -749,7 +759,7 @@ class SmartButton implements SmartButtonInterface { $params = array( 'client-id' => $this->client_id, - 'currency' => get_woocommerce_currency(), + 'currency' => $this->currency, 'integration-date' => PAYPAL_INTEGRATION_DATE, 'components' => implode( ',', $this->components() ), 'vault' => $this->can_save_vault_token() ? 'true' : 'false', diff --git a/modules/ppcp-button/src/Helper/MessagesApply.php b/modules/ppcp-button/src/Helper/MessagesApply.php index f7bc5b3e2..4ca1d36a6 100644 --- a/modules/ppcp-button/src/Helper/MessagesApply.php +++ b/modules/ppcp-button/src/Helper/MessagesApply.php @@ -28,14 +28,28 @@ class MessagesApply { 'AU', ); + /** + * 2-letter country code of the shop. + * + * @var string + */ + private $country; + + /** + * MessagesApply constructor. + * + * @param string $country 2-letter country code of the shop. + */ + public function __construct( string $country ) { + $this->country = $country; + } + /** * Determines whether a credit messaging is enabled for the shops location country. * * @return bool */ public function for_country(): bool { - $region = wc_get_base_location(); - $country = $region['country']; - return in_array( $country, $this->countries, true ); + return in_array( $this->country, $this->countries, true ); } } diff --git a/modules/ppcp-button/src/Helper/MessagesDisclaimers.php b/modules/ppcp-button/src/Helper/MessagesDisclaimers.php index 6737d4c2c..29cb20db3 100644 --- a/modules/ppcp-button/src/Helper/MessagesDisclaimers.php +++ b/modules/ppcp-button/src/Helper/MessagesDisclaimers.php @@ -39,15 +39,28 @@ class MessagesDisclaimers { ), ); + /** + * 2-letter country code of the shop. + * + * @var string + */ + private $country; + + /** + * MessagesDisclaimers constructor. + * + * @param string $country 2-letter country code of the shop. + */ + public function __construct( string $country ) { + $this->country = $country; + } + /** * Returns a disclaimer link based on country. * * @return string */ public function link_for_country(): string { - $region = wc_get_base_location(); - $country = $region['country']; - - return $this->disclaimers[ $country ]['link'] ?? ''; + return $this->disclaimers[ $this->country ]['link'] ?? ''; } } diff --git a/modules/ppcp-status-report/src/StatusReportModule.php b/modules/ppcp-status-report/src/StatusReportModule.php index 8b2fcd617..36707ab8b 100644 --- a/modules/ppcp-status-report/src/StatusReportModule.php +++ b/modules/ppcp-status-report/src/StatusReportModule.php @@ -90,14 +90,14 @@ class StatusReportModule implements ModuleInterface { 'label' => esc_html__( 'Shop country code', 'woocommerce-paypal-payments' ), 'exported_label' => 'Shop country code', 'description' => esc_html__( 'Country / State value on Settings / General / Store Address.', 'woocommerce-paypal-payments' ), - 'value' => wc_get_base_location()['country'], + 'value' => $c->get( 'api.shop.country' ), ), array( 'label' => esc_html__( 'WooCommerce currency supported', 'woocommerce-paypal-payments' ), 'exported_label' => 'WooCommerce currency supported', 'description' => esc_html__( 'Whether PayPal supports the default store currency or not.', 'woocommerce-paypal-payments' ), 'value' => $this->bool_to_html( - $currency_support->supports_wc_currency() + $currency_support->supports_currency() ), ), array( diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 291b83f98..381e48ee4 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -2026,6 +2026,8 @@ return array( }, 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers { - return new MessagesDisclaimers(); + return new MessagesDisclaimers( + $container->get( 'api.shop.country' ) + ); }, ); diff --git a/tests/PHPUnit/ApiClient/Factory/AmountFactoryTest.php b/tests/PHPUnit/ApiClient/Factory/AmountFactoryTest.php index 4d33c1a5f..005f1773e 100644 --- a/tests/PHPUnit/ApiClient/Factory/AmountFactoryTest.php +++ b/tests/PHPUnit/ApiClient/Factory/AmountFactoryTest.php @@ -13,13 +13,13 @@ use function Brain\Monkey\Functions\when; class AmountFactoryTest extends TestCase { + private $currency = 'EUR'; public function testFromWcCartDefault() { $itemFactory = Mockery::mock(ItemFactory::class); - $testee = new AmountFactory($itemFactory); + $testee = new AmountFactory($itemFactory, $this->currency); - $expectedCurrency = 'EUR'; $cart = Mockery::mock(\WC_Cart::class); $cart ->shouldReceive('get_total') @@ -47,8 +47,6 @@ class AmountFactoryTest extends TestCase ->shouldReceive('get_subtotal_tax') ->andReturn(8); - expect('get_woocommerce_currency')->andReturn($expectedCurrency); - $woocommerce = Mockery::mock(\WooCommerce::class); $session = Mockery::mock(\WC_Session::class); when('WC')->justReturn($woocommerce); @@ -56,22 +54,22 @@ class AmountFactoryTest extends TestCase $session->shouldReceive('get')->andReturn([]); $result = $testee->from_wc_cart($cart); - $this->assertEquals($expectedCurrency, $result->currency_code()); + $this->assertEquals($this->currency, $result->currency_code()); $this->assertEquals((float) 1, $result->value()); $this->assertEquals((float) 10, $result->breakdown()->discount()->value()); - $this->assertEquals($expectedCurrency, $result->breakdown()->discount()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->discount()->currency_code()); $this->assertEquals((float) 9, $result->breakdown()->shipping()->value()); - $this->assertEquals($expectedCurrency, $result->breakdown()->shipping()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->shipping()->currency_code()); $this->assertEquals((float) 5, $result->breakdown()->item_total()->value()); - $this->assertEquals($expectedCurrency, $result->breakdown()->item_total()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->item_total()->currency_code()); $this->assertEquals((float) 8, $result->breakdown()->tax_total()->value()); - $this->assertEquals($expectedCurrency, $result->breakdown()->tax_total()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->tax_total()->currency_code()); } public function testFromWcCartNoDiscount() { $itemFactory = Mockery::mock(ItemFactory::class); - $testee = new AmountFactory($itemFactory); + $testee = new AmountFactory($itemFactory, $this->currency); $expectedCurrency = 'EUR'; $expectedTotal = 1; @@ -102,8 +100,6 @@ class AmountFactoryTest extends TestCase ->shouldReceive('get_subtotal_tax') ->andReturn(11); - expect('get_woocommerce_currency')->andReturn($expectedCurrency); - $woocommerce = Mockery::mock(\WooCommerce::class); $session = Mockery::mock(\WC_Session::class); when('WC')->justReturn($woocommerce); @@ -139,15 +135,14 @@ class AmountFactoryTest extends TestCase ->expects('from_wc_order') ->with($order) ->andReturn([$item]); - $testee = new AmountFactory($itemFactory); + $testee = new AmountFactory($itemFactory, $this->currency); - $expectedCurrency = 'EUR'; $order ->shouldReceive('get_total') ->andReturn(100); $order ->shouldReceive('get_currency') - ->andReturn($expectedCurrency); + ->andReturn($this->currency); $order ->shouldReceive('get_shipping_total') ->andReturn(1); @@ -165,11 +160,11 @@ class AmountFactoryTest extends TestCase $this->assertEquals((float) 1.5, $result->breakdown()->shipping()->value()); $this->assertEquals((float) 100, $result->value()); $this->assertEquals((float) 2, $result->breakdown()->tax_total()->value()); - $this->assertEquals($expectedCurrency, $result->breakdown()->discount()->currency_code()); - $this->assertEquals($expectedCurrency, $result->breakdown()->item_total()->currency_code()); - $this->assertEquals($expectedCurrency, $result->breakdown()->shipping()->currency_code()); - $this->assertEquals($expectedCurrency, $result->breakdown()->tax_total()->currency_code()); - $this->assertEquals($expectedCurrency, $result->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->discount()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->item_total()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->shipping()->currency_code()); + $this->assertEquals($this->currency, $result->breakdown()->tax_total()->currency_code()); + $this->assertEquals($this->currency, $result->currency_code()); } public function testFromWcOrderDiscountIsNull() @@ -198,15 +193,14 @@ class AmountFactoryTest extends TestCase ->expects('from_wc_order') ->with($order) ->andReturn([$item]); - $testee = new AmountFactory($itemFactory); + $testee = new AmountFactory($itemFactory, $this->currency); - $expectedCurrency = 'EUR'; $order ->shouldReceive('get_total') ->andReturn(100); $order ->shouldReceive('get_currency') - ->andReturn($expectedCurrency); + ->andReturn($this->currency); $order ->shouldReceive('get_shipping_total') ->andReturn(1); @@ -229,7 +223,7 @@ class AmountFactoryTest extends TestCase public function testFromPayPalResponse($response, $expectsException) { $itemFactory = Mockery::mock(ItemFactory::class); - $testee = new AmountFactory($itemFactory); + $testee = new AmountFactory($itemFactory, $this->currency); if ($expectsException) { $this->expectException(RuntimeException::class); } diff --git a/tests/PHPUnit/ApiClient/Factory/ItemFactoryTest.php b/tests/PHPUnit/ApiClient/Factory/ItemFactoryTest.php index a46e4d67e..6c7204660 100644 --- a/tests/PHPUnit/ApiClient/Factory/ItemFactoryTest.php +++ b/tests/PHPUnit/ApiClient/Factory/ItemFactoryTest.php @@ -12,10 +12,11 @@ use Mockery; class ItemFactoryTest extends TestCase { + private $currency = 'EUR'; public function testFromCartDefault() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $product = Mockery::mock(\WC_Product_Simple::class); $product @@ -41,8 +42,6 @@ class ItemFactoryTest extends TestCase ->expects('get_cart_contents') ->andReturn($items); - expect('get_woocommerce_currency') - ->andReturn('EUR'); expect('wc_get_price_including_tax') ->with($product) ->andReturn(2.995); @@ -78,7 +77,7 @@ class ItemFactoryTest extends TestCase public function testFromCartDigitalGood() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $product = Mockery::mock(\WC_Product_Simple::class); $product @@ -104,8 +103,6 @@ class ItemFactoryTest extends TestCase ->expects('get_cart_contents') ->andReturn($items); - expect('get_woocommerce_currency') - ->andReturn('EUR'); expect('wc_get_price_including_tax') ->with($product) ->andReturn(2.995); @@ -130,7 +127,7 @@ class ItemFactoryTest extends TestCase public function testFromWcOrderDefault() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $product = Mockery::mock(\WC_Product::class); $product @@ -160,7 +157,7 @@ class ItemFactoryTest extends TestCase $order = Mockery::mock(\WC_Order::class); $order ->expects('get_currency') - ->andReturn('EUR'); + ->andReturn($this->currency); $order ->expects('get_items') ->andReturn([$item]); @@ -193,7 +190,7 @@ class ItemFactoryTest extends TestCase public function testFromWcOrderDigitalGood() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $product = Mockery::mock(\WC_Product::class); $product @@ -223,7 +220,7 @@ class ItemFactoryTest extends TestCase $order = Mockery::mock(\WC_Order::class); $order ->expects('get_currency') - ->andReturn('EUR'); + ->andReturn($this->currency); $order ->expects('get_items') ->andReturn([$item]); @@ -251,7 +248,7 @@ class ItemFactoryTest extends TestCase { $name = 'öawjetöagrjjaglörjötairgjaflkögjöalfdgjöalfdjblköajtlkfjdbljslkgjfklösdgjalkerjtlrajglkfdajblköajflköbjsdgjadfgjaöfgjaölkgjkladjgfköajgjaflgöjafdlgjafdögjdsflkgjö4jwegjfsdbvxj öskögjtaeröjtrgt'; $description = 'öawjetöagrjjaglörjötairgjaflkögjöalfdgjöalfdjblköajtlkfjdbljslkgjfklösdgjalkerjtlrajglkfdajblköajflköbjsdgjadfgjaöfgjaölkgjkladjgfköajgjaflgöjafdlgjafdögjdsflkgjö4jwegjfsdbvxj öskögjtaeröjtrgt'; - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $product = Mockery::mock(\WC_Product::class); $product @@ -308,7 +305,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponse() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', @@ -335,7 +332,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseDigitalGood() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', @@ -343,7 +340,7 @@ class ItemFactoryTest extends TestCase 'quantity' => 1, 'unit_amount' => (object) [ 'value' => 1, - 'currency_code' => 'EUR', + 'currency_code' => $this->currency, ], 'category' => Item::DIGITAL_GOODS, ]; @@ -356,7 +353,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseHasTax() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', @@ -377,7 +374,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseThrowsWithoutName() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'description' => 'description', @@ -397,7 +394,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseThrowsWithoutQuantity() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', @@ -417,7 +414,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseThrowsWithStringInQuantity() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', @@ -438,7 +435,7 @@ class ItemFactoryTest extends TestCase public function testFromPayPalResponseThrowsWithWrongUnitAmount() { - $testee = new ItemFactory(); + $testee = new ItemFactory($this->currency); $response = (object) [ 'name' => 'name', From ebabc45dbcc4b1021d2b6ce2656c1fd58a7871a8 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Nov 2021 11:15:56 +0200 Subject: [PATCH 2/4] Extract currency/country lists to services --- modules/ppcp-api-client/services.php | 296 +++++++++++++++--- .../src/Helper/CurrencySupport.php | 38 +-- .../ppcp-api-client/src/Helper/DccApplies.php | 176 +---------- 3 files changed, 273 insertions(+), 237 deletions(-) diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index b46886da9..96acb585d 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -50,31 +50,31 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; return array( - 'api.host' => function( ContainerInterface $container ) : string { + 'api.host' => function( ContainerInterface $container ) : string { return PAYPAL_API_URL; }, - 'api.paypal-host' => function( ContainerInterface $container ) : string { + 'api.paypal-host' => function( ContainerInterface $container ) : string { return PAYPAL_API_URL; }, - 'api.partner_merchant_id' => static function () : string { + 'api.partner_merchant_id' => static function () : string { return ''; }, - 'api.merchant_email' => function () : string { + 'api.merchant_email' => function () : string { return ''; }, - 'api.merchant_id' => function () : string { + 'api.merchant_id' => function () : string { return ''; }, - 'api.key' => static function (): string { + 'api.key' => static function (): string { return ''; }, - 'api.secret' => static function (): string { + 'api.secret' => static function (): string { return ''; }, - 'api.prefix' => static function (): string { + 'api.prefix' => static function (): string { return 'WC-'; }, - 'api.bearer' => static function ( ContainerInterface $container ): Bearer { + 'api.bearer' => static function ( ContainerInterface $container ): Bearer { $cache = new Cache( 'ppcp-paypal-bearer' ); $key = $container->get( 'api.key' ); $secret = $container->get( 'api.secret' ); @@ -90,7 +90,7 @@ return array( $settings ); }, - 'api.endpoint.partners' => static function ( ContainerInterface $container ) : PartnersEndpoint { + 'api.endpoint.partners' => static function ( ContainerInterface $container ) : PartnersEndpoint { return new PartnersEndpoint( $container->get( 'api.host' ), $container->get( 'api.bearer' ), @@ -100,10 +100,10 @@ return array( $container->get( 'api.merchant_id' ) ); }, - 'api.factory.sellerstatus' => static function ( ContainerInterface $container ) : SellerStatusFactory { + 'api.factory.sellerstatus' => static function ( ContainerInterface $container ) : SellerStatusFactory { return new SellerStatusFactory(); }, - 'api.endpoint.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenEndpoint { + 'api.endpoint.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenEndpoint { return new PaymentTokenEndpoint( $container->get( 'api.host' ), $container->get( 'api.bearer' ), @@ -112,7 +112,7 @@ return array( $container->get( 'api.prefix' ) ); }, - 'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint { + 'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint { return new WebhookEndpoint( $container->get( 'api.host' ), @@ -122,7 +122,7 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'api.endpoint.partner-referrals' => static function ( ContainerInterface $container ) : PartnerReferrals { + 'api.endpoint.partner-referrals' => static function ( ContainerInterface $container ) : PartnerReferrals { return new PartnerReferrals( $container->get( 'api.host' ), @@ -131,7 +131,7 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'api.endpoint.identity-token' => static function ( ContainerInterface $container ) : IdentityToken { + 'api.endpoint.identity-token' => static function ( ContainerInterface $container ) : IdentityToken { $logger = $container->get( 'woocommerce.logger.woocommerce' ); $prefix = $container->get( 'api.prefix' ); $settings = $container->get( 'wcgateway.settings' ); @@ -143,7 +143,7 @@ return array( $settings ); }, - 'api.endpoint.payments' => static function ( ContainerInterface $container ): PaymentsEndpoint { + 'api.endpoint.payments' => static function ( ContainerInterface $container ): PaymentsEndpoint { $authorizations_factory = $container->get( 'api.factory.authorization' ); $capture_factory = $container->get( 'api.factory.capture' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); @@ -156,7 +156,7 @@ return array( $logger ); }, - 'api.endpoint.login-seller' => static function ( ContainerInterface $container ) : LoginSeller { + 'api.endpoint.login-seller' => static function ( ContainerInterface $container ) : LoginSeller { $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new LoginSeller( @@ -165,7 +165,7 @@ return array( $logger ); }, - 'api.endpoint.order' => static function ( ContainerInterface $container ): OrderEndpoint { + 'api.endpoint.order' => static function ( ContainerInterface $container ): OrderEndpoint { $order_factory = $container->get( 'api.factory.order' ); $patch_collection_factory = $container->get( 'api.factory.patch-collection-factory' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); @@ -192,54 +192,54 @@ return array( $subscription_helper ); }, - 'api.endpoint.billing-agreements' => static function ( ContainerInterface $container ): BillingAgreementsEndpoint { + 'api.endpoint.billing-agreements' => static function ( ContainerInterface $container ): BillingAgreementsEndpoint { return new BillingAgreementsEndpoint( $container->get( 'api.host' ), $container->get( 'api.bearer' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'api.repository.paypal-request-id' => static function( ContainerInterface $container ) : PayPalRequestIdRepository { + 'api.repository.paypal-request-id' => static function( ContainerInterface $container ) : PayPalRequestIdRepository { return new PayPalRequestIdRepository(); }, - 'api.repository.application-context' => static function( ContainerInterface $container ) : ApplicationContextRepository { + 'api.repository.application-context' => static function( ContainerInterface $container ) : ApplicationContextRepository { $settings = $container->get( 'wcgateway.settings' ); return new ApplicationContextRepository( $settings ); }, - 'api.repository.partner-referrals-data' => static function ( ContainerInterface $container ) : PartnerReferralsData { + 'api.repository.partner-referrals-data' => static function ( ContainerInterface $container ) : PartnerReferralsData { $merchant_email = $container->get( 'api.merchant_email' ); $dcc_applies = $container->get( 'api.helpers.dccapplies' ); return new PartnerReferralsData( $merchant_email, $dcc_applies ); }, - 'api.repository.cart' => static function ( ContainerInterface $container ): CartRepository { + 'api.repository.cart' => static function ( ContainerInterface $container ): CartRepository { $factory = $container->get( 'api.factory.purchase-unit' ); return new CartRepository( $factory ); }, - 'api.repository.payee' => static function ( ContainerInterface $container ): PayeeRepository { + 'api.repository.payee' => static function ( ContainerInterface $container ): PayeeRepository { $merchant_email = $container->get( 'api.merchant_email' ); $merchant_id = $container->get( 'api.merchant_id' ); return new PayeeRepository( $merchant_email, $merchant_id ); }, - 'api.factory.application-context' => static function ( ContainerInterface $container ) : ApplicationContextFactory { + 'api.factory.application-context' => static function ( ContainerInterface $container ) : ApplicationContextFactory { return new ApplicationContextFactory(); }, - 'api.factory.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenFactory { + 'api.factory.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenFactory { return new PaymentTokenFactory(); }, - 'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory { + 'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory { return new WebhookFactory(); }, - 'api.factory.webhook-event' => static function ( ContainerInterface $container ): WebhookEventFactory { + 'api.factory.webhook-event' => static function ( ContainerInterface $container ): WebhookEventFactory { return new WebhookEventFactory(); }, - 'api.factory.capture' => static function ( ContainerInterface $container ): CaptureFactory { + 'api.factory.capture' => static function ( ContainerInterface $container ): CaptureFactory { $amount_factory = $container->get( 'api.factory.amount' ); return new CaptureFactory( $amount_factory ); }, - 'api.factory.purchase-unit' => static function ( ContainerInterface $container ): PurchaseUnitFactory { + 'api.factory.purchase-unit' => static function ( ContainerInterface $container ): PurchaseUnitFactory { $amount_factory = $container->get( 'api.factory.amount' ); $payee_repository = $container->get( 'api.repository.payee' ); @@ -259,39 +259,39 @@ return array( $prefix ); }, - 'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory { + 'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory { return new PatchCollectionFactory(); }, - 'api.factory.payee' => static function ( ContainerInterface $container ): PayeeFactory { + 'api.factory.payee' => static function ( ContainerInterface $container ): PayeeFactory { return new PayeeFactory(); }, - 'api.factory.item' => static function ( ContainerInterface $container ): ItemFactory { + 'api.factory.item' => static function ( ContainerInterface $container ): ItemFactory { return new ItemFactory( $container->get( 'api.shop.currency' ) ); }, - 'api.factory.shipping' => static function ( ContainerInterface $container ): ShippingFactory { + 'api.factory.shipping' => static function ( ContainerInterface $container ): ShippingFactory { $address_factory = $container->get( 'api.factory.address' ); return new ShippingFactory( $address_factory ); }, - 'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory { + 'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory { $item_factory = $container->get( 'api.factory.item' ); return new AmountFactory( $item_factory, $container->get( 'api.shop.currency' ) ); }, - 'api.factory.payer' => static function ( ContainerInterface $container ): PayerFactory { + 'api.factory.payer' => static function ( ContainerInterface $container ): PayerFactory { $address_factory = $container->get( 'api.factory.address' ); return new PayerFactory( $address_factory ); }, - 'api.factory.address' => static function ( ContainerInterface $container ): AddressFactory { + 'api.factory.address' => static function ( ContainerInterface $container ): AddressFactory { return new AddressFactory(); }, - 'api.factory.payment-source' => static function ( ContainerInterface $container ): PaymentSourceFactory { + 'api.factory.payment-source' => static function ( ContainerInterface $container ): PaymentSourceFactory { return new PaymentSourceFactory(); }, - 'api.factory.order' => static function ( ContainerInterface $container ): OrderFactory { + 'api.factory.order' => static function ( ContainerInterface $container ): OrderFactory { $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' ); $payer_factory = $container->get( 'api.factory.payer' ); $application_context_repository = $container->get( 'api.repository.application-context' ); @@ -305,31 +305,237 @@ return array( $payment_source_factory ); }, - 'api.factory.payments' => static function ( ContainerInterface $container ): PaymentsFactory { + 'api.factory.payments' => static function ( ContainerInterface $container ): PaymentsFactory { $authorizations_factory = $container->get( 'api.factory.authorization' ); $capture_factory = $container->get( 'api.factory.capture' ); return new PaymentsFactory( $authorizations_factory, $capture_factory ); }, - 'api.factory.authorization' => static function ( ContainerInterface $container ): AuthorizationFactory { + 'api.factory.authorization' => static function ( ContainerInterface $container ): AuthorizationFactory { return new AuthorizationFactory(); }, - 'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies { + 'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies { return new DccApplies( + $container->get( 'api.dcc-supported-country-currency-matrix' ), + $container->get( 'api.dcc-supported-country-card-matrix' ), $container->get( 'api.shop.currency' ), $container->get( 'api.shop.country' ) ); }, - 'api.helpers.currency-support' => static function ( ContainerInterface $container ) : CurrencySupport { + 'api.helpers.currency-support' => static function ( ContainerInterface $container ) : CurrencySupport { return new CurrencySupport( + $container->get( 'api.supported-currencies' ), $container->get( 'api.shop.currency' ) ); }, - 'api.shop.currency' => static function ( ContainerInterface $container ) : string { + 'api.shop.currency' => static function ( ContainerInterface $container ) : string { return get_woocommerce_currency(); }, - 'api.shop.country' => static function ( ContainerInterface $container ) : string { + 'api.shop.country' => static function ( ContainerInterface $container ) : string { $location = wc_get_base_location(); return $location['country']; }, + + /** + * Currencies supported by PayPal. + * + * From https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ + */ + 'api.supported-currencies' => static function ( ContainerInterface $container ) : array { + return array( + 'AUD', + 'BRL', + 'CAD', + 'CNY', + 'CZK', + 'DKK', + 'EUR', + 'HKD', + 'HUF', + 'ILS', + 'JPY', + 'MYR', + 'MXN', + 'TWD', + 'NZD', + 'NOK', + 'PHP', + 'PLN', + 'GBP', + 'RUB', + 'SGD', + 'SEK', + 'CHF', + 'THB', + 'USD', + ); + }, + + /** + * The matrix which countries and currency combinations can be used for DCC. + */ + 'api.dcc-supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array { + return array( + 'AU' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + 'ES' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + 'FR' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + 'GB' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + 'IT' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + 'US' => array( + 'AUD', + 'CAD', + 'EUR', + 'GBP', + 'JPY', + 'USD', + ), + 'CA' => array( + 'AUD', + 'CAD', + 'CHF', + 'CZK', + 'DKK', + 'EUR', + 'GBP', + 'HKD', + 'HUF', + 'JPY', + 'NOK', + 'NZD', + 'PLN', + 'SEK', + 'SGD', + 'USD', + ), + ); + }, + + /** + * Which countries support which credit cards. Empty credit card arrays mean no restriction on currency. + */ + 'api.dcc-supported-country-card-matrix' => static function ( ContainerInterface $container ) : array { + return array( + 'AU' => array( + 'mastercard' => array(), + 'visa' => array(), + ), + 'ES' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'EUR' ), + ), + 'FR' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'EUR' ), + ), + 'GB' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'GBP', 'USD' ), + ), + 'IT' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'EUR' ), + ), + 'US' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'USD' ), + 'discover' => array( 'USD' ), + ), + 'CA' => array( + 'mastercard' => array(), + 'visa' => array(), + 'amex' => array( 'CAD' ), + 'jcb' => array( 'CAD' ), + ), + ); + }, ); diff --git a/modules/ppcp-api-client/src/Helper/CurrencySupport.php b/modules/ppcp-api-client/src/Helper/CurrencySupport.php index 9c5bd5bc4..adfe13152 100644 --- a/modules/ppcp-api-client/src/Helper/CurrencySupport.php +++ b/modules/ppcp-api-client/src/Helper/CurrencySupport.php @@ -17,37 +17,9 @@ class CurrencySupport { /** * Currencies supported by PayPal. * - * From https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ - * * @var string[] */ - private $supported_currencies = array( - 'AUD', - 'BRL', - 'CAD', - 'CNY', - 'CZK', - 'DKK', - 'EUR', - 'HKD', - 'HUF', - 'ILS', - 'JPY', - 'MYR', - 'MXN', - 'TWD', - 'NZD', - 'NOK', - 'PHP', - 'PLN', - 'GBP', - 'RUB', - 'SGD', - 'SEK', - 'CHF', - 'THB', - 'USD', - ); + private $supported_currencies; /** * 3-letter currency code of the shop. @@ -59,10 +31,12 @@ class CurrencySupport { /** * CurrencySupport constructor. * - * @param string $currency 3-letter currency code of the shop. + * @param string[] $supported_currencies Currencies supported by PayPal. + * @param string $currency 3-letter currency code of the shop. */ - public function __construct( string $currency ) { - $this->currency = $currency; + public function __construct( array $supported_currencies, string $currency ) { + $this->supported_currencies = $supported_currencies; + $this->currency = $currency; } /** diff --git a/modules/ppcp-api-client/src/Helper/DccApplies.php b/modules/ppcp-api-client/src/Helper/DccApplies.php index ce88fc476..6d694536c 100644 --- a/modules/ppcp-api-client/src/Helper/DccApplies.php +++ b/modules/ppcp-api-client/src/Helper/DccApplies.php @@ -19,169 +19,15 @@ class DccApplies { * * @var array */ - private $allowed_country_currency_matrix = array( - 'AU' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - 'ES' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - 'FR' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - 'GB' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - 'IT' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - 'US' => array( - 'AUD', - 'CAD', - 'EUR', - 'GBP', - 'JPY', - 'USD', - ), - 'CA' => array( - 'AUD', - 'CAD', - 'CHF', - 'CZK', - 'DKK', - 'EUR', - 'GBP', - 'HKD', - 'HUF', - 'JPY', - 'NOK', - 'NZD', - 'PLN', - 'SEK', - 'SGD', - 'USD', - ), - ); + private $allowed_country_currency_matrix; /** * Which countries support which credit cards. Empty credit card arrays mean no restriction on - * currency. Otherwise only the currencies in the array are supported. + * currency. * * @var array */ - private $country_card_matrix = array( - 'AU' => array( - 'mastercard' => array(), - 'visa' => array(), - ), - 'ES' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'EUR' ), - ), - 'FR' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'EUR' ), - ), - 'GB' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'GBP', 'USD' ), - ), - 'IT' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'EUR' ), - ), - 'US' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'USD' ), - 'discover' => array( 'USD' ), - ), - 'CA' => array( - 'mastercard' => array(), - 'visa' => array(), - 'amex' => array( 'CAD' ), - 'jcb' => array( 'CAD' ), - ), - ); + private $country_card_matrix; /** * 3-letter currency code of the shop. @@ -200,12 +46,22 @@ class DccApplies { /** * DccApplies constructor. * + * @param array $allowed_country_currency_matrix The matrix which countries and currency combinations can be used for DCC. + * @param array $country_card_matrix Which countries support which credit cards. Empty credit card arrays mean no restriction on + * currency. * @param string $currency 3-letter currency code of the shop. * @param string $country 2-letter country code of the shop. */ - public function __construct( string $currency, string $country ) { - $this->currency = $currency; - $this->country = $country; + public function __construct( + array $allowed_country_currency_matrix, + array $country_card_matrix, + string $currency, + string $country + ) { + $this->allowed_country_currency_matrix = $allowed_country_currency_matrix; + $this->country_card_matrix = $country_card_matrix; + $this->currency = $currency; + $this->country = $country; } /** From 521cbf4e2604f2da669d9b80d626ddbd87bb73b8 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Nov 2021 14:47:34 +0200 Subject: [PATCH 3/4] Require 3DS by default for PSD2 shop countries --- modules/ppcp-api-client/services.php | 40 ++++++++++++++++++++++++++++ modules/ppcp-wc-gateway/services.php | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index 96acb585d..442825ba8 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -335,6 +335,13 @@ return array( $location = wc_get_base_location(); return $location['country']; }, + 'api.shop.is-psd2-country' => static function ( ContainerInterface $container ) : bool { + return in_array( + $container->get( 'api.shop.country' ), + $container->get( 'api.psd2-countries' ), + true + ); + }, /** * Currencies supported by PayPal. @@ -538,4 +545,37 @@ return array( ), ); }, + + 'api.psd2-countries' => static function ( ContainerInterface $container ) : array { + return array( + 'AT', + 'BE', + 'BG', + 'CY', + 'CZ', + 'DK', + 'EE', + 'FI', + 'FR', + 'DE', + 'GB', + 'GR', + 'HU', + 'IE', + 'IT', + 'LV', + 'LT', + 'LU', + 'MT', + 'NL', + 'NO', + 'PL', + 'PT', + 'RO', + 'SK', + 'SI', + 'ES', + 'SE', + ); + }, ); diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 381e48ee4..73239fc66 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -1907,7 +1907,7 @@ return array( ), 'class' => array(), 'input_class' => array( 'wc-enhanced-select' ), - 'default' => 'SCA_WHEN_REQUIRED', + 'default' => $container->get( 'api.shop.is-psd2-country' ) ? '3D_SECURE' : 'NO_3D_SECURE', 'desc_tip' => true, 'options' => array( 'NO_3D_SECURE' => __( 'No 3D Secure (transaction will be denied if 3D Secure is required)', 'woocommerce-paypal-payments' ), From c43a4999aa37e31643ddf832966960d3d9abaeac Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Nov 2021 14:55:31 +0200 Subject: [PATCH 4/4] Replace CurrencySupport class with a service --- modules/ppcp-api-client/services.php | 14 +++--- .../src/Helper/CurrencySupport.php | 50 ------------------- .../src/StatusReportModule.php | 7 +-- 3 files changed, 8 insertions(+), 63 deletions(-) delete mode 100644 modules/ppcp-api-client/src/Helper/CurrencySupport.php diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index 442825ba8..49b1408bf 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -40,7 +40,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; -use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencySupport; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository; @@ -321,12 +320,6 @@ return array( $container->get( 'api.shop.country' ) ); }, - 'api.helpers.currency-support' => static function ( ContainerInterface $container ) : CurrencySupport { - return new CurrencySupport( - $container->get( 'api.supported-currencies' ), - $container->get( 'api.shop.currency' ) - ); - }, 'api.shop.currency' => static function ( ContainerInterface $container ) : string { return get_woocommerce_currency(); @@ -342,6 +335,13 @@ return array( true ); }, + 'api.shop.is-currency-supported' => static function ( ContainerInterface $container ) : bool { + return in_array( + $container->get( 'api.shop.currency' ), + $container->get( 'api.supported-currencies' ), + true + ); + }, /** * Currencies supported by PayPal. diff --git a/modules/ppcp-api-client/src/Helper/CurrencySupport.php b/modules/ppcp-api-client/src/Helper/CurrencySupport.php deleted file mode 100644 index adfe13152..000000000 --- a/modules/ppcp-api-client/src/Helper/CurrencySupport.php +++ /dev/null @@ -1,50 +0,0 @@ -supported_currencies = $supported_currencies; - $this->currency = $currency; - } - - /** - * Returns whether the currency is supported. - * - * @return bool - */ - public function supports_currency(): bool { - return in_array( $this->currency, $this->supported_currencies, true ); - } -} diff --git a/modules/ppcp-status-report/src/StatusReportModule.php b/modules/ppcp-status-report/src/StatusReportModule.php index 36707ab8b..211a5ad51 100644 --- a/modules/ppcp-status-report/src/StatusReportModule.php +++ b/modules/ppcp-status-report/src/StatusReportModule.php @@ -14,10 +14,8 @@ use Dhii\Modular\Module\ModuleInterface; use Interop\Container\ServiceProviderInterface; use Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer; -use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; -use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencySupport; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply; use WooCommerce\PayPalCommerce\Compat\PPEC\PPECHelper; @@ -57,9 +55,6 @@ class StatusReportModule implements ModuleInterface { /* @var Bearer $bearer The bearer. */ $bearer = $c->get( 'api.bearer' ); - $currency_support = $c->get( 'api.helpers.currency-support' ); - assert( $currency_support instanceof CurrencySupport ); - /* @var DccApplies $dcc_applies The ddc applies. */ $dcc_applies = $c->get( 'api.helpers.dccapplies' ); @@ -97,7 +92,7 @@ class StatusReportModule implements ModuleInterface { 'exported_label' => 'WooCommerce currency supported', 'description' => esc_html__( 'Whether PayPal supports the default store currency or not.', 'woocommerce-paypal-payments' ), 'value' => $this->bool_to_html( - $currency_support->supports_currency() + $c->get( 'api.shop.is-currency-supported' ) ), ), array(