Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: pricing decimal formatting for tokenized cart #8998

Merged
merged 7 commits into from
Jun 24, 2024
5 changes: 5 additions & 0 deletions changelog/fix-tokenized-cart-zero-decimal-currency
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: fix
Comment: fix: tokenized PRB with zero decimal currency


Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Internal dependencies
*/
import { transformPrice } from '../wc-to-stripe';

global.wcpayPaymentRequestParams = {};
global.wcpayPaymentRequestParams.checkout = {};

describe( 'wc-to-stripe transformers', () => {
describe( 'transformPrice', () => {
afterEach( () => {
delete global.wcpayPaymentRequestParams.checkout.currency_decimals;
} );

it( 'transforms the price', () => {
expect( transformPrice( 180, { currency_minor_unit: 2 } ) ).toBe(
180
);
} );

it( 'transforms the price if the currency is configured with one decimal', () => {
// with one decimal, `180` would mean `18.0`.
// But since Stripe expects the price to be in cents, the return value should be `1800`
expect( transformPrice( 180, { currency_minor_unit: 1 } ) ).toBe(
1800
);
} );

it( 'transforms the price if the currency is configured with two decimals', () => {
// with two decimals, `1800` would mean `18.00`.
// But since Stripe expects the price to be in cents, the return value should be `1800`
expect( transformPrice( 1800, { currency_minor_unit: 2 } ) ).toBe(
1800
);
} );

it( 'transforms the price if the currency is a zero decimal currency (e.g.: Yen)', () => {
global.wcpayPaymentRequestParams.checkout.currency_decimals = 0;
// with zero decimals, `18` would mean `18`.
expect( transformPrice( 18, { currency_minor_unit: 0 } ) ).toBe(
18
);
} );

it( 'transforms the price if the currency a zero decimal currency (e.g.: Yen) but it is configured with one decimal', () => {
global.wcpayPaymentRequestParams.checkout.currency_decimals = 0;
// with zero decimals, `18` would mean `18`.
// But since Stripe expects the price to be in the minimum currency amount, the return value should be `18`
expect( transformPrice( 180, { currency_minor_unit: 1 } ) ).toBe(
18
);
} );
} );
} );
13 changes: 11 additions & 2 deletions client/tokenized-payment-request/transformers/wc-to-stripe.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { getPaymentRequestData } from '../frontend-utils';

/**
* GooglePay/ApplePay expect the prices to be formatted in cents.
* But WooCommerce has a setting to define the number of decimals for amounts.
Expand All @@ -14,9 +19,13 @@ import { __ } from '@wordpress/i18n';
*
* @return {number} the price amount for GooglePay/ApplePay, always expressed in cents.
*/
export const transformPrice = ( price, priceObject ) =>
export const transformPrice = ( price, priceObject ) => {
const currencyDecimals =
getPaymentRequestData( 'checkout' )?.currency_decimals ?? 2;

// making sure the decimals are always correctly represented for GooglePay/ApplePay, since they don't allow us to specify the decimals.
price * 10 ** ( 2 - priceObject.currency_minor_unit );
return price * 10 ** ( currencyDecimals - priceObject.currency_minor_unit );
};

/**
* Transforms the data from the Store API Cart response to `displayItems` for the Stripe PRB.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,7 @@ public function scripts() {
],
'checkout' => [
'currency_code' => strtolower( get_woocommerce_currency() ),
'currency_decimals' => WC_Payments::get_localization_service()->get_currency_format( get_woocommerce_currency() )['num_decimals'],
'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.
Expand Down
Loading