diff --git a/client/api/index.js b/client/api/index.js index 2d6ebe7c20..3652653eec 100644 --- a/client/api/index.js +++ b/client/api/index.js @@ -536,6 +536,19 @@ export default class WCStripeAPI { } ); } + /** + * Update cart customer data. + * + * @param {Object} customerData Customer data. + * @return {Promise} Promise for the request to the server. + */ + expressCheckoutUpdateCartCustomer( customerData ) { + return this.postToBlocksAPI( + '/wc/store/v1/cart/update-customer', + customerData + ); + } + /** * Add product to cart from product page. * diff --git a/client/entrypoints/express-checkout/index.js b/client/entrypoints/express-checkout/index.js index 7666fc0b07..d334f10f48 100644 --- a/client/entrypoints/express-checkout/index.js +++ b/client/entrypoints/express-checkout/index.js @@ -8,10 +8,12 @@ import { __ } from '@wordpress/i18n'; import { displayExpressCheckoutNotice, displayLoginConfirmation, + getBillingAddressData, getExpressCheckoutButtonAppearance, getExpressCheckoutButtonStyleSettings, getExpressCheckoutData, getPaymentMethodTypesForExpressMethod, + getTotalPriceFromCart, isManualPaymentMethodCreation, normalizeLineItems, } from 'wcstripe/express-checkout/utils'; @@ -35,11 +37,11 @@ import { EXPRESS_PAYMENT_METHOD_SETTING_APPLE_PAY, EXPRESS_PAYMENT_METHOD_SETTING_GOOGLE_PAY, EXPRESS_PAYMENT_METHOD_SETTING_LINK, + PAYMENT_METHOD_AMAZON_PAY, } from 'wcstripe/stripe-utils/constants'; import { transformCartDataForDisplayItems, transformLabeledDisplayItems, - transformPrice, } from 'wcstripe/express-checkout/transformers/wc-to-stripe'; jQuery( function ( $ ) { @@ -456,6 +458,43 @@ jQuery( function ( $ ) { } } + // When taxes are based on the billing address and Amazon Pay is used, we need to update the cart customer data and recompute taxes + // before we can finalise the payment. + if ( + getExpressCheckoutData( 'taxes_based_on_billing' ) && + event?.expressPaymentType === PAYMENT_METHOD_AMAZON_PAY + ) { + const initialBillingAddress = + getBillingAddressData( event ); + + // Pass the billing address through our standard express checkout address normalization process. + const normalizedBillingData = + await api.expressCheckoutNormalizeAddress( + initialBillingAddress, + {} + ); + + // Update the cart customer data with the normalized billing address, with the initial address as a fallback. + const customerData = { + billing_address: + normalizedBillingData.billing_address || + initialBillingAddress, + }; + const customerUpdateResult = + await api.expressCheckoutUpdateCartCustomer( + customerData + ); + + if ( customerUpdateResult?.totals ) { + const updatedPrice = + getTotalPriceFromCart( customerUpdateResult ); + + await elements.update( { + amount: updatedPrice, + } ); + } + } + const order = options.order ? options.order : 0; const orderDetails = options.orderDetails ?? {}; return await onConfirmHandler( { @@ -560,11 +599,7 @@ jQuery( function ( $ ) { } else { // Cart and Checkout page specific initialization. api.expressCheckoutGetCartDetails().then( ( cart ) => { - const total = transformPrice( - parseInt( cart.totals.total_price, 10 ) - - parseInt( cart.totals.total_refund || 0, 10 ), - cart.totals - ); + const total = getTotalPriceFromCart( cart ); if ( total === 0 && diff --git a/client/express-checkout/utils/index.js b/client/express-checkout/utils/index.js index 79baddbd72..e6c6bea18a 100644 --- a/client/express-checkout/utils/index.js +++ b/client/express-checkout/utils/index.js @@ -2,6 +2,7 @@ import jQuery from 'jquery'; import { isAmazonPayEnabled, isLinkEnabled } from 'wcstripe/stripe-utils'; import { EXPRESS_CHECKOUT_NOTICE_DELAY } from 'wcstripe/data/constants'; +import { transformPrice } from 'wcstripe/express-checkout/transformers/wc-to-stripe'; import { EXPRESS_PAYMENT_METHOD_SETTING_AMAZON_PAY, EXPRESS_PAYMENT_METHOD_SETTING_APPLE_PAY, @@ -404,3 +405,17 @@ export const isManualPaymentMethodCreation = ( ].includes( expressPaymentType ) || hasFreeTrial ); }; + +/** + * Get the total price from a cart response. + * + * @param {Object} cart The cart response from the server. + * @return {number} The total price. + */ +export const getTotalPriceFromCart = ( cart ) => { + return transformPrice( + parseInt( cart.totals.total_price, 10 ) - + parseInt( cart.totals.total_refund || 0, 10 ), + cart.totals + ); +}; diff --git a/client/express-checkout/utils/normalize.js b/client/express-checkout/utils/normalize.js index 9232fc179c..ff009cdb07 100644 --- a/client/express-checkout/utils/normalize.js +++ b/client/express-checkout/utils/normalize.js @@ -346,7 +346,7 @@ export const normalizeShippingAddress = ( shippingAddress ) => { * * @return {Object} The billing address data. */ -const getBillingAddressData = ( event ) => { +export const getBillingAddressData = ( event ) => { const name = event?.billingDetails?.name; const email = event?.billingDetails?.email ?? ''; const billing = event?.billingDetails?.address ?? {};