Skip to content

Commit

Permalink
fix: pricing decimal formatting for tokenized cart (#8998)
Browse files Browse the repository at this point in the history
Co-authored-by: Timur Karimov <timur.karimow.95@gmail.com>
  • Loading branch information
frosso and timur27 authored Jun 24, 2024
1 parent f8c8196 commit 78fba81
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
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

0 comments on commit 78fba81

Please sign in to comment.