Skip to content

Commit

Permalink
Merge branch 'develop' into add/9045-split-ece-pms-registration-for-b…
Browse files Browse the repository at this point in the history
…locks
  • Loading branch information
rafaelzaleski authored Jul 9, 2024
2 parents 806e790 + 1c18a0d commit 53461e4
Show file tree
Hide file tree
Showing 11 changed files with 546 additions and 55 deletions.
5 changes: 5 additions & 0 deletions changelog/9001-tokenized-prb-order-origin
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: fix
Comment: Bug fix for PRB feature behind a flag.


4 changes: 4 additions & 0 deletions changelog/as-8871-ece-on-supported-product-types
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Add ECE support for multiple product types.
48 changes: 28 additions & 20 deletions client/express-checkout/event-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
trackExpressCheckoutButtonClick,
trackExpressCheckoutButtonLoad,
} from './tracking';
import { __ } from '@wordpress/i18n';

export const shippingAddressChangeHandler = async ( api, event, elements ) => {
try {
Expand Down Expand Up @@ -77,27 +78,27 @@ export const onConfirmHandler = async (
return abortPayment( event, error.message );
}

// Kick off checkout processing step.
let orderResponse;
if ( ! order ) {
orderResponse = await api.expressCheckoutECECreateOrder(
normalizeOrderData( event, paymentMethod.id )
);
} else {
orderResponse = await api.expressCheckoutECEPayForOrder(
order,
normalizePayForOrderData( event, paymentMethod.id )
);
}
try {
// Kick off checkout processing step.
let orderResponse;
if ( ! order ) {
orderResponse = await api.expressCheckoutECECreateOrder(
normalizeOrderData( event, paymentMethod.id )
);
} else {
orderResponse = await api.expressCheckoutECEPayForOrder(
order,
normalizePayForOrderData( event, paymentMethod.id )
);
}

if ( orderResponse.result !== 'success' ) {
return abortPayment(
event,
getErrorMessageFromNotice( orderResponse.messages )
);
}
if ( orderResponse.result !== 'success' ) {
return abortPayment(
event,
getErrorMessageFromNotice( orderResponse.messages )
);
}

try {
const confirmationRequest = api.confirmIntent( orderResponse.redirect );

// `true` means there is no intent to confirm.
Expand All @@ -109,7 +110,14 @@ export const onConfirmHandler = async (
completePayment( redirectUrl );
}
} catch ( e ) {
return abortPayment( event, e.message );
return abortPayment(
event,
e.message ??
__(
'There was a problem processing the order.',
'woocommerce-payments'
)
);
}
};

Expand Down
189 changes: 165 additions & 24 deletions client/express-checkout/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* global jQuery, wcpayExpressCheckoutParams, wcpayECEPayForOrderParams */
import { __ } from '@wordpress/i18n';
import { debounce } from 'lodash';

/**
* Internal dependencies
Expand All @@ -19,6 +20,7 @@ import {
shippingAddressChangeHandler,
shippingRateChangeHandler,
} from './event-handlers';
import { displayLoginConfirmation } from './utils';

jQuery( ( $ ) => {
// Don't load if blocks checkout is being loaded.
Expand All @@ -30,6 +32,7 @@ jQuery( ( $ ) => {
}

const publishableKey = wcpayExpressCheckoutParams.stripe.publishableKey;
const quantityInputSelector = '.quantity .qty[type=number]';

if ( ! publishableKey ) {
// If no configuration is present, probably this is not the checkout page.
Expand All @@ -50,6 +53,12 @@ jQuery( ( $ ) => {
}
);

let wcPayECEError = '';
const defaultErrorMessage = __(
'There was an error getting the product information.',
'woocommerce-payments'
);

/**
* Object to handle Stripe payment forms.
*/
Expand Down Expand Up @@ -156,7 +165,7 @@ jQuery( ( $ ) => {

const data = {
product_id: productId,
qty: $( '.quantity .qty' ).val(),
qty: $( quantityInputSelector ).val(),
attributes: $( '.variations_form' ).length
? wcpayECE.getAttributes().data
: [],
Expand Down Expand Up @@ -250,9 +259,45 @@ jQuery( ( $ ) => {
wcpayECE.showButton( eceButton );

eceButton.on( 'click', function ( event ) {
// TODO: handle cases where we need login confirmation.
// If login is required for checkout, display redirect confirmation dialog.
if ( getExpressCheckoutData( 'login_confirmation' ) ) {
displayLoginConfirmation( event.expressPaymentType );
return;
}

if ( getExpressCheckoutData( 'is_product_page' ) ) {
const addToCartButton = $( '.single_add_to_cart_button' );

// First check if product can be added to cart.
if ( addToCartButton.is( '.disabled' ) ) {
if (
addToCartButton.is( '.wc-variation-is-unavailable' )
) {
window.alert(
window?.wc_add_to_cart_variation_params
?.i18n_unavailable_text ||
__(
'Sorry, this product is unavailable. Please choose a different combination.',
'woocommerce-payments'
)
);
} else {
window.alert(
__(
'Please select your product options before proceeding.',
'woocommerce-payments'
)
);
}
return;
}

if ( wcPayECEError ) {
window.alert( wcPayECEError );
return;
}

// Add products to the cart if everything is right.
wcpayECE.addToCart();
}

Expand Down Expand Up @@ -291,10 +336,15 @@ jQuery( ( $ ) => {
} );

eceButton.on( 'cancel', async () => {
wcpayECE.paymentAborted = true;
wcpayECE.unblock();
} );

eceButton.on( 'ready', onReadyHandler );

if ( getExpressCheckoutData( 'is_product_page' ) ) {
wcpayECE.attachProductPageEventListeners( elements );
}
},

getSelectedProductData: () => {
Expand Down Expand Up @@ -333,7 +383,7 @@ jQuery( ( $ ) => {

const data = {
product_id: productId,
qty: $( '.quantity .qty' ).val(),
qty: $( quantityInputSelector ).val(),
attributes: $( '.variations_form' ).length
? wcpayECE.getAttributes().data
: [],
Expand All @@ -356,44 +406,132 @@ jQuery( ( $ ) => {
return elements.create( 'expressCheckout', options );
},

getElements: () => {
return $(
'.wcpay-payment-request-wrapper,#wcpay-express-checkout-button-separator'
);
},

hide: () => {
wcpayECE.getElements().hide();
},
attachProductPageEventListeners: ( elements ) => {
$( document.body )
.off( 'woocommerce_variation_has_changed' )
.on( 'woocommerce_variation_has_changed', () => {
wcpayECE.blockExpressCheckoutButton();

$.when( wcpayECE.getSelectedProductData() )
.then( ( response ) => {
/**
* If the customer aborted the express checkout,
* we need to re init the express checkout button to ensure the shipping
* options are refetched. If the customer didn't abort the express checkout,
* and the product's shipping status is consistent,
* we can simply update the express checkout button with the new total and display items.
*/
if (
! wcpayECE.paymentAborted &&
getExpressCheckoutData( 'product' )
.needs_shipping === response.needs_shipping
) {
elements.update( {
amount: response.total.amount,
displayItems: response.displayItems,
} );
} else {
wcpayECE.reInitExpressCheckoutElement(
response
);
}
} )
.catch( () => {
wcpayECE.hide();
} )
.always( () => {
wcpayECE.unblockExpressCheckoutButton();
} );
} );

show: () => {
wcpayECE.getElements().show();
$( '.quantity' )
.off( 'input', '.qty' )
.on(
'input',
'.qty',
debounce( () => {
wcpayECE.blockExpressCheckoutButton();
wcPayECEError = '';

$.when( wcpayECE.getSelectedProductData() )
.then(
( response ) => {
// In case the server returns an unexpected response
if ( typeof response !== 'object' ) {
wcPayECEError = defaultErrorMessage;
}

if (
! wcpayECE.paymentAborted &&
getExpressCheckoutData( 'product' )
.needs_shipping ===
response.needs_shipping
) {
elements.update( {
amount: response.total.amount,
} );
} else {
wcpayECE.reInitExpressCheckoutElement(
response
);
}
},
( response ) => {
wcPayECEError =
response.responseJSON?.error ??
defaultErrorMessage;
}
)
.always( function () {
wcpayECE.unblockExpressCheckoutButton();
} );
}, 250 )
);
},

showButton: ( eceButton ) => {
if ( $( '#wcpay-express-checkout-element' ).length ) {
wcpayECE.show();
eceButton.mount( '#wcpay-express-checkout-element' );
}
reInitExpressCheckoutElement: ( response ) => {
wcpayExpressCheckoutParams.product.needs_shipping =
response.needs_shipping;
wcpayExpressCheckoutParams.product.total = response.total;
wcpayExpressCheckoutParams.product.displayItems =
response.displayItems;
wcpayECE.init();
},

blockButton: () => {
blockExpressCheckoutButton: () => {
// check if element isn't already blocked before calling block() to avoid blinking overlay issues
// blockUI.isBlocked is either undefined or 0 when element is not blocked
if (
$( '#wcpay-express-checkout-button' ).data(
$( '#wcpay-express-checkout-element' ).data(
'blockUI.isBlocked'
)
) {
return;
}

$( '#wcpay-express-checkout-button' ).block( { message: null } );
$( '#wcpay-express-checkout-element' ).block( { message: null } );
},

unblockButton: () => {
unblockExpressCheckoutButton: () => {
wcpayECE.show();
$( '#wcpay-express-checkout-button' ).unblock();
$( '#wcpay-express-checkout-element' ).unblock();
},

getElements: () => {
return $(
'.wcpay-payment-request-wrapper,#wcpay-express-checkout-button-separator'
);
},

show: () => {
wcpayECE.getElements().show();
},

showButton: ( eceButton ) => {
if ( $( '#wcpay-express-checkout-element' ).length ) {
wcpayECE.show();
eceButton.mount( '#wcpay-express-checkout-element' );
}
},

/**
Expand Down Expand Up @@ -454,6 +592,9 @@ jQuery( ( $ ) => {
} );
} );
}

// After initializing a new express checkout button, we need to reset the paymentAborted flag.
wcpayECE.paymentAborted = false;
},
};

Expand Down
Loading

0 comments on commit 53461e4

Please sign in to comment.