Extract shop currency, country to services

This commit is contained in:
Alex P 2021-11-30 10:40:38 +02:00
parent cfb10b0cee
commit ffe32070d0
13 changed files with 197 additions and 109 deletions

View file

@ -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'];
},
);

View file

@ -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
);
}

View file

@ -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

View file

@ -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 );
}
}

View file

@ -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 );
}
}

View file

@ -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 {

View file

@ -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',

View file

@ -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 );
}
}

View file

@ -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'] ?? '';
}
}

View file

@ -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(

View file

@ -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' )
);
},
);

View file

@ -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);
}

View file

@ -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',