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

Add ACSS support for WC Subscriptions #4051

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from

Conversation

ricardo
Copy link
Member

@ricardo ricardo commented Mar 13, 2025

Fixes #3831

Changes proposed in this Pull Request:

  • Add ACSS support for WC Subscriptions.
  • Add support for free trial subscriptions for non-deferred intent payment methods.

Testing instructions

  1. Enable the ACSS feature flag:
    • Use the Stripe Dev Tools plugin to enable the ACSS feature flag.
  2. Enable ACSS in Stripe:
    • Navigate to the Stripe Dashboard.
    • Enable "Canadian Pre-Authorized Debits" in the payment methods settings.
  3. Enable ACSS in WC Stripe:
    • Go to WooCommerce > Settings > Payments > Stripe.
    • Enable "Pre-Authorized Debit (ACSS)".
  4. Listen to webhooks:
npm run listen
  1. Change the store currency to CAD.
  2. From the checkout page, use the following information for the address:
    • Country: Canada
    • Province: British Columbia
    • City: Vancouver
    • Postcode: K1A 0B1

Reproduce the following critical flows using ACSS for payments:


  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Changelog entry

  • This Pull Request does not require a changelog entry. (Comment required below)
Changelog Entry Comment

Comment

Post merge

Comment on lines +826 to +827
'payment_schedule' => 'combined',
'interval_description' => __( 'Payments as per agreement', 'woocommerce-gateway-stripe' ),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured it's best to set the payment schedule to combined and the interval description to something that can fit both one-time payments and subscriptions, because the same payment method (and consequently the mandate) can be used for both recurring and non-recurring payments, depending on how the payment method is saved in WooCommerce.

Reference: https://docs.stripe.com/payments/acss-debit#payment-schedule

@@ -436,7 +437,7 @@ public function update_payment_intent_ajax() {
* @throws Exception If the update intent call returns with an error.
* @return array|null An array with result of the update, or nothing
*/
public function update_payment_intent( $payment_intent_id = '', $order_id = null, $save_payment_method = false, $selected_upe_payment_type = '' ) {
public function update_intent( $payment_intent_id = '', $order_id = null, $save_payment_method = false, $selected_upe_payment_type = '' ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method now handles setup intents as well. Looking at the Stripe logs, there was an error where it was incorrectly calling payment_intents/seti_... instead of setup_intents/seti....

Given the similarity of a potential new method for handling only setup intents, I decided to unify both needs into the same function.

I'd appreciate the reviewer double-checking this approach, but I believe it shouldn't affect existing flows, given how minimal the change is.

Comment on lines +1640 to +1642
if ( isset( $intent->mandate ) ) {
$order->update_meta_data( '_stripe_mandate_id', $intent->mandate );
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For payment intents, the mandate ID is only available from the charge object, however for setup intents, the mandate ID can be accessed directly from the intent object.

Comment on lines +1626 to +1628
// TODO: Refactor and add mandate ID support for other payment methods, if necessary.
// The mandate ID is not available for the intent object, so we need to fetch the charge.
// Mandate ID is necessary for renewal payments for certain payment methods and Indian cards.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mandate ID here is necessary for renewal orders. Without it, renewal orders will fail.

I think it's best to keep this as a TODO just to indicate that the approach should be refactored if adding new payment methods, and also to make sure we test other payment methods because I figured this is necessary for at least card and ACSS.

@asumaran I couldn't test BACS subscriptions, but this doesn't seem necessary for ACH as far as I have tested. Can you try processing a renewal order for BACS and make sure this is not needed for BACS? There's a similar check in line 1631.

@ricardo ricardo requested review from a team and cesarcosta99 and removed request for a team March 13, 2025 04:01
@ricardo ricardo linked an issue Mar 14, 2025 that may be closed by this pull request
Base automatically changed from fix/3813-saved-payment-methods to develop March 14, 2025 19:16
@ricardo
Copy link
Member Author

ricardo commented Mar 14, 2025

@cesarcosta99 I fixed the change payment method flows in 5ccf8f8. So the PR is finally ready to be reviewed.

IMO that method shouldn't be used to update the order, but only the intent.

It would be great to have it refactored, but that method became slightly convoluted a long time before these changes, so I've just adapted it to prevent a bug when changing the method for a subscription.

Copy link
Contributor

@cesarcosta99 cesarcosta99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Code LGTM with just one minor request and it also tested well overall. I spotted one issue we may want to fix before merging this.

  • ⚠️ Purchase subscription product
    • ✅ Classic and Blocks checkouts
    • ⚠️ Minor issue found: the Next Payment column don't display the selected payment method, neither in the list or in the subscription view. In the screenshot below, the 200 and 198 IDs are free trial purchases, while 194 and 191 are simple subscription purchases. Note: After manually renewing 194 and 191, the payment method is now displaying, but initially it wasn't.
      image
  • ✅ Purchase free trial subscription
    • Classic and Blocks checkouts
  • ✅ Renew subscription
    • Classic and Blocks checkouts
  • ✅ Automatically renew a subscription
  • ✅ Change payment method
  • ✅ Change payment method to saved token
  • ✅ Change default payment method

*
* @since 5.6.0
* @version x.x.x
*
* @param {string} $payment_intent_id The id of the payment intent to update.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update this param to $intent_id (and its description) to avoid any confusion now that we're expanding support to setup intents as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ACSS: WC Subscription support
2 participants