-
Notifications
You must be signed in to change notification settings - Fork 207
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
Add ACSS payment method and refactor payment processing with deferred intent #3805
base: develop
Are you sure you want to change the base?
Conversation
// If the payment method doesn't support deferred intent, the intent must be created here. | ||
if ( ! supportsDeferredIntent ) { | ||
const intent = await api.createIntent( null, paymentMethodType ); | ||
gatewayUPEComponents[ paymentMethodType ].intentId = intent.id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is similar to how it used to work before #2935, but instead of saving the PI ID to a local variable, we save the intent ID to each specific UPE component object (gatewayUPEComponents
), so we can render the PE only when the PM is selected, and have a different PI for each split UPE that doesn't support deferred intents (In this case it will be only BLIK and ACSS).
client/stripe-utils/utils.js
Outdated
// Also uncheck the radio button if it's selected. | ||
const radioButton = document.querySelector( | ||
'input[name="payment_method"][value="stripe_' + | ||
paymentMethodType + | ||
'"]' | ||
); | ||
|
||
if ( radioButton ) { | ||
radioButton.checked = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a small UX improvement. Before this, the payment method would be hidden, but remain selected, causing an error at checkout.
'acss_debit' => [ | ||
'mandate_options' => [ | ||
'payment_schedule' => 'interval', | ||
'interval_description' => __( 'One-time payment', 'woocommerce-gateway-stripe' ), // TODO: Change to cadence if purchasing a subscription. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO should be handled in #3831.
$payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing | ||
$order = wc_get_order( $order_id ); | ||
$selected_payment_type = $this->get_selected_payment_method_type_from_request(); | ||
|
||
if ( $payment_intent_id && ! $this->payment_methods[ $selected_payment_type ]->supports_deferred_intent() ) { | ||
// Adds customer and metadata to PaymentIntent. | ||
// These parameters cannot be added upon updating the intent via the `/confirm` API. | ||
$this->intent_controller->update_payment_intent( $payment_intent_id, $order_id ); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we should refactor process_payment_with_deferred_intent
below and possibly the entire process_payment
method, but since there's a comment "To be removed." for $_POST['wc-stripe-is-deferred-intent']
, I decided to keep this change at a minimum.
Basically, if an unsupported deferred intent payment method was used, we need to first update the PI , and then process the payment as normal with process_payment_with_deferred_intent
.
This PI update will add customer and mandate data to the PI, as well as attach the PI to the order.
Even though the ACSS method doesn't use a "deferred intent", this is more of a naming problem than a problem with the code and should be refactored when "To be removed." actually happens. I'll find or create an issue for this and link it in the code as a comment.
// Asynchronous payment methods such as bank debits will only provide a charge ID at `payment_intent.processing`, once the required actions are taken by the customer. | ||
// We need to update the order transaction ID, so that the `payment_intent.succeeded` webhook is able to process the order. | ||
case 'payment_intent.processing': | ||
$charge = $this->get_latest_charge_from_intent( $intent ); | ||
$order->set_transaction_id( $charge->id ); | ||
/* translators: transaction id */ | ||
$order->update_status( 'on-hold', sprintf( __( 'Stripe charge awaiting payment: %s.', 'woocommerce-gateway-stripe' ), $charge->id ) ); | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asumaran, @rafaelzaleski – I wanted to invite you to do some inspection of this part of the code, because it touches other direct debit methods.
This change implements handling for payment_intent.processing
, which is a status that is specific to bank debits, so 'd like to get both your 👍/👎 on this change.
- When we select a manual deposit verification for ACH or ACSS and click "place order", the payment intent is set to a "requires_action" status, but at this point it doesn't add any charge information to it. It's like the SCA / 3DS card flow, but the order has already been processed.
- You can check the
wp_wc_orders.transaction_id
column and notice there's no charge ID in there. - Once the customer completes the required action, i.e submits the manual verification of micro deposits, it switches the payment intent status to
processing
– from what I've tested, this is only new to delayed notification methods. - Please validate that the
payment_intent.processing
is the first event that Stripe sends us that contains a charge ID we can use to update the order. Some other events happen in between, e.gpayment_intent.requires_action
,mandate.updated
, but they don't have a charge ID we can use yet. - By updating the
transaction_id
, the subsequent status updates can be captured for this order accordingly.
Let me know if you have any questions about this fix.
You should be able to replicate this from the "Test 2: Checkout with micro deposits verification + delayed notification" testing instructions using BACS or ACH.
From what I tested in develop
, this should fix it for both ACSS and ACH, but I haven't tried with BACS yet, so it would be nice if you can try this as well @asumaran. I'm not sure if BACS requires any action or supports delayed notifications.
Assigned @cesarcosta99 as he will be working on the next PM spike, and @rafaelzaleski and @asumaran can do a quicker spot check of the aforementioned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should also rename this file to something more generic since it's now handling non-deferred intents as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option would be to add a common file that imports the regular deferred-intent.js file and a new one for non-deferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think classic/upe/deferred-intent.js
and classic/upe/index.js
serve similar purposes right now both adding event listeners to the checkout and having some repeat variables (1, 2), so my question was more if deferred-intent
is a good naming?
Also, handleUPECheckout
from index.js
apparently is not being used anymore after the split UPE work.
Perhaps we should unify all these event listeners into a new index.js
or checkout-handler.js
, and keep functions in other files like payment-processing.js
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should unify all these event listeners into a new index.js or checkout-handler.js, and keep functions in other files like payment-processing.js.
I think that's a good idea 👍
WC_Stripe_Payment_Methods::ALIPAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/alipay.svg" class="stripe-alipay-icon stripe-icon" alt="Alipay" />', | ||
WC_Stripe_Payment_Methods::WECHAT_PAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/wechat.svg" class="stripe-wechat-icon stripe-icon" alt="Wechat Pay" />', | ||
WC_Stripe_Payment_Methods::BANCONTACT => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/bancontact.svg" class="stripe-bancontact-icon stripe-icon" alt="Bancontact" />', | ||
WC_Stripe_Payment_Methods::IDEAL => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/ideal.svg" class="stripe-ideal-icon stripe-icon" alt="iDEAL" />', | ||
WC_Stripe_Payment_Methods::P24 => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/p24.svg" class="stripe-p24-icon stripe-icon" alt="P24" />', | ||
WC_Stripe_Payment_Methods::GIROPAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/giropay.svg" class="stripe-giropay-icon stripe-icon" alt="giropay" />', | ||
WC_Stripe_Payment_Methods::KLARNA => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/klarna.svg" class="stripe-klarna-icon stripe-icon" alt="klarna" />', | ||
WC_Stripe_Payment_Methods::AFFIRM => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/affirm.svg" class="stripe-affirm-icon stripe-icon" alt="affirm" />', | ||
WC_Stripe_Payment_Methods::KLARNA => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/klarna.svg" class="stripe-klarna-icon stripe-icon" alt="Klarna" />', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks for fixing this
…merce/woocommerce-gateway-stripe into fix/3804-refactor-deferred-intent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work with ACSS 🚀 I left a couple nitpicks and have some questions before approving, but overall this is looking great!
Due to level3 retrials, the error message when the payment fails is still misleading, this should be fixed in #3830.
Can we add this to that issue description or as a comment just so we have this tracked?
All tests passed, but I wanted to confirm this:
Last step of test 1 and 2 states we should find correct information in the Stripe transaction. I found the correct amount, mandate and customer information, however, I didn't find anything about the order such as ID, or metadata. Are we expecting that, at this point, to be set in the charge on Stripe?
@@ -972,7 +1001,7 @@ private function build_base_payment_intent_request_params( $payment_information | |||
* Determines if mandate data is required for deferred intent UPE payment. | |||
* | |||
* A mandate must be provided before a deferred intent UPE payment can be processed. | |||
* This applies to SEPA, Bancontact, iDeal, Sofort, Cash App and Link payment methods. | |||
* This applies to SEPA, Bancontact, iDeal, Sofort, Cash App, Link payment methods and ACSS Debit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add the missing payment methods here too?
* This applies to SEPA, Bancontact, iDeal, Sofort, Cash App, Link payment methods and ACSS Debit. | |
* This applies to SEPA, Bancontact, iDeal, Sofort, Cash App, Link payment methods, | |
* ACH, ACSS Debit and BACS. |
Added it ✔️.
When you click the charge ID from the WC edit order page and go to the Stripe dashboard, you should be able to see metadata information on the right side of the page right below the customer information, like this: ![]() @cesarcosta99 Are you able to find it? If not, can you try with other payment methods such as cards? Also, are you using the custom orders table / HPOS in WooCommerce? |
Co-authored-by: César Costa <[email protected]>
@ricardo, actually, none of the Stripe IDs in the order edit page is clickable for me. What I did to check the transaction details was to search for the value directly in the Stripe dashboard. And to me, metadata came empty for an ACSS payment: ![]()
Yes, HPOS is enabled. Is this known limitation?
In a card transaction metadata has been correctly set. ![]() |
@ricardo, similar to ACH, should we hide the ACSS payment option from the checkout page if billing country is not supported? |
The Stripe ID was not clickable because I had disabled the ACSS feature flag after test 3. Re-enabling it made it render as expected. I did another attempt on test 1 while being logged out from WP Admin and metadata came in correctly ✅ I saw the dev logs on the Stripe dashboard and can confirm there were failures for the requests containing the metadata with error |
Fixes #3804
For context: #2935 introduced deferred intents, which included major changes to how the checkout flow is handled.
After #2935, a Payment Intent is only created after the UPE is mounted and the payment is about to be confirmed.
This makes it incompatible for ACSS and BLIK, which are payment methods that don't support deferred intent creation (ref).
So, to fix this issue, I introduced a
supports_deferred_intent
property to the UPE Payment method, which should be used to determine how the intent creation and checkout should be handled.Changes proposed in this Pull Request:
WC_Stripe_UPE_Payment_Gateway->process_payment
.payment_intent.processing
webhooks to fix delayed notifications.Known issues
Testing instructions
Setup:
Test 1: Successful checkout
Canada
,Vancouver
,British Columbia
,K1A 0B1
(zip code).Test 2: Checkout with micro deposits verification + delayed notification
{A8C_VALID_EMAIL}[email protected]
.Canada
,Vancouver
,British Columbia
,K1A 0B1
(zip code).000
,11000
,900123456789
, click Confirm > Agree.32
and45
to the verification page and the payment should be confirmed with a 3 minute delay once the micro deposits are verified.payment_intent.processing
webhook and the order status should be set to "On-hold" followed by "Processing" a few moments later.Test 3: Disable feature flag
changelog.txt
andreadme.txt
(or does not apply)Post merge