Skip to content

Show payment methods available in the PMC on settings page #4252

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

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

Conversation

Mayisha
Copy link
Contributor

@Mayisha Mayisha commented Apr 23, 2025

In the current PMC implementation, we are syncing the enabled/disable payment methods between plugin settings and Stripe dashboard. But the list of available payment methods in plugin settings is not aligned with the payment method configuration. As a result, we show some payment methods in the settings page that are not available in the PMC.

Changes proposed in this Pull Request:

  • Retrieve available payment methods from PMC when get_upe_available_payment_methods is called.
  • Aligned with the cache implementation.
  • If pmc is not enabled, fall back to the previous code.

Testing instructions

  • Go to your Stripe settings page and connect to a Stripe account that does not support some payment methods (i.e, I have tested with an Australian Stripe account)
  • In develop, go to the payment methods tab and notice that you have OXXO, Boleto, ACSS available in the payment method list.
Screenshot 2025-04-30 at 2 55 07 AM
  • Go to the payment methods page in your Stripe dashboard and choose the payment configuration under WooCommerce.
  • Notice that, you do not have OXXO/Boleto/ACSS available here.
  • Now set your store currency to CAD and enable ACSS (Pre-authorized debit).
  • Click Save and refresh your page.
  • Notice that, ACSS is still disabled.
  • In your store logs, you will find the error Error: acss_debit is not available to this merchant.
  • Now checkout to this branch and refresh the Stripe settings page.
  • Confirm that you don't see the unsupported payment methods anymore.
  • Try to enable/disable a few methods and confirm that the changes persists in your plugin settings page and also synced in the Stripe dashboard.

@Mayisha Mayisha marked this pull request as draft April 23, 2025 08:07
@Mayisha Mayisha changed the base branch from develop to fix/add-caching-for-stripe-configuration April 23, 2025 16:56
Base automatically changed from fix/add-caching-for-stripe-configuration to develop April 24, 2025 10:20
Copy link
Member

@diegocurbelo diegocurbelo left a comment

Choose a reason for hiding this comment

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

The implementation looks good, the only comment is renaming the get_upe_available_payment_methods function in WC_Stripe_Payment_Method_Configurations

@diegocurbelo diegocurbelo self-requested a review April 24, 2025 20:52
@daledupreez daledupreez self-requested a review April 29, 2025 09:47
@daledupreez
Copy link
Contributor

@Mayisha, could you add more context to the PR so we can test it before @diegocurbelo is available?

@Mayisha Mayisha marked this pull request as ready for review April 30, 2025 06:53
@Mayisha
Copy link
Contributor Author

Mayisha commented Apr 30, 2025

@daledupreez I have added the description and addressed the feedback.

Copy link
Contributor

@daledupreez daledupreez left a comment

Choose a reason for hiding this comment

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

It looks like there are a number of legitimate unit test failures that we need to resolve before we can merge this.

@Mayisha, let me know if you'd like to hand over work on getting the tests working.

$available_payment_method_ids = [];
$merchant_payment_method_configuration = self::get_primary_configuration( $force_refresh );

if ( $merchant_payment_method_configuration ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not clear on why this code is not checking/calling self::is_enabled(). We are checking that in get_upe_enabled_payment_method_ids() below, and in the current calling code, so I am not sure why we're skipping the check here.

My initial suspicion is that is_enabled() is checking for write permissions, where we only need to read what functions are available for the account. But then I got confused across the various cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My initial suspicion is that is_enabled() is checking for write permissions, where we only need to read what functions are available for the account. But then I got confused across the various cases.

is_enabled() returns true if PMC is enabled for this account. PMC is enabled only if the account has been re-authenticated using the connect OAuth flow. If an account still uses manual keys (which we used to support many versions before), we can not retrieve the PMC for those accounts. So for these accounts, we need to fallback to the available and enabled payment methods list stored in the DB.

I am not clear on why this code is not checking/calling self::is_enabled()

I had the other version too when I was checking this in the configuration class. Are you proposing this would be better?

Copy link
Contributor

Choose a reason for hiding this comment

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

Most of my confusion stems from my lack of context and noticing that we're not following the same pattern as get_upe_enabled_payment_method_ids(), which has the following code in develop at the moment:

/**
* Get the UPE enabled payment method IDs.
*
* @param bool $force_refresh Whether to force a refresh of the payment method configuration from Stripe.
* @return array
*/
public static function get_upe_enabled_payment_method_ids( $force_refresh = false ) {
// If the payment method configurations API is not enabled, we fallback to the enabled payment methods stored in the DB.
if ( ! self::is_enabled() ) {
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
return isset( $stripe_settings['upe_checkout_experience_accepted_payments'] ) && ! empty( $stripe_settings['upe_checkout_experience_accepted_payments'] )
? $stripe_settings['upe_checkout_experience_accepted_payments']
: [ WC_Stripe_Payment_Methods::CARD ];
}
// Migrate payment methods from DB to Stripe PMC if needed
self::maybe_migrate_payment_methods_from_db_to_pmc();
$enabled_payment_method_ids = [];
$merchant_payment_method_configuration = self::get_primary_configuration( $force_refresh );
if ( $merchant_payment_method_configuration ) {
foreach ( $merchant_payment_method_configuration as $payment_method_id => $payment_method ) {
if ( isset( $payment_method->display_preference->value ) && 'on' === $payment_method->display_preference->value ) {
$enabled_payment_method_ids[] = $payment_method_id;
}
}
}
return $enabled_payment_method_ids;
}

In particular, we have local code that returns valid data in the code block starting with if ( ! self::is_enabled() ) {. That is likely for backwards compatibility, but I am wondering why we're not using the same defensive approach in this new method. I am OK with us doing so, but I think we should then document that difference very clearly, as that's a fairly subtle difference between the two methods that is not obvious.

Copy link

github-actions bot commented May 5, 2025

📈 PHP Unit Code Coverage Report

Package Line Rate Health
includes/abstracts/abstract-wc-stripe-payment-gateway.php 48%
includes/class-wc-stripe-payment-method-configurations.php 96%
includes/payment-methods/class-wc-stripe-upe-payment-gateway.php 48%
Summary 45% (7265 / 16309)

@Mayisha Mayisha requested a review from daledupreez May 5, 2025 06:26
@Mayisha
Copy link
Contributor Author

Mayisha commented May 5, 2025

@daledupreez I have addressed the feedback. Can I have another 👀 from you?

Copy link
Contributor

@daledupreez daledupreez left a comment

Choose a reason for hiding this comment

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

I haven't tested yet, but I have some feedback up from inspection. It may be a while before I can fully test, so want to get this feedback to you sooner.

$available_payment_method_ids = [];
$merchant_payment_method_configuration = self::get_primary_configuration( $force_refresh );

if ( $merchant_payment_method_configuration ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Most of my confusion stems from my lack of context and noticing that we're not following the same pattern as get_upe_enabled_payment_method_ids(), which has the following code in develop at the moment:

/**
* Get the UPE enabled payment method IDs.
*
* @param bool $force_refresh Whether to force a refresh of the payment method configuration from Stripe.
* @return array
*/
public static function get_upe_enabled_payment_method_ids( $force_refresh = false ) {
// If the payment method configurations API is not enabled, we fallback to the enabled payment methods stored in the DB.
if ( ! self::is_enabled() ) {
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
return isset( $stripe_settings['upe_checkout_experience_accepted_payments'] ) && ! empty( $stripe_settings['upe_checkout_experience_accepted_payments'] )
? $stripe_settings['upe_checkout_experience_accepted_payments']
: [ WC_Stripe_Payment_Methods::CARD ];
}
// Migrate payment methods from DB to Stripe PMC if needed
self::maybe_migrate_payment_methods_from_db_to_pmc();
$enabled_payment_method_ids = [];
$merchant_payment_method_configuration = self::get_primary_configuration( $force_refresh );
if ( $merchant_payment_method_configuration ) {
foreach ( $merchant_payment_method_configuration as $payment_method_id => $payment_method ) {
if ( isset( $payment_method->display_preference->value ) && 'on' === $payment_method->display_preference->value ) {
$enabled_payment_method_ids[] = $payment_method_id;
}
}
}
return $enabled_payment_method_ids;
}

In particular, we have local code that returns valid data in the code block starting with if ( ! self::is_enabled() ) {. That is likely for backwards compatibility, but I am wondering why we're not using the same defensive approach in this new method. I am OK with us doing so, but I think we should then document that difference very clearly, as that's a fairly subtle difference between the two methods that is not obvious.

@@ -37,7 +37,7 @@ class WC_Stripe_UPE_Payment_Gateway extends WC_Gateway_Stripe {
WC_Stripe_Payment_Methods::BOLETO => WC_Stripe_UPE_Payment_Method_Boleto::class,
WC_Stripe_Payment_Methods::IDEAL => WC_Stripe_UPE_Payment_Method_Ideal::class,
WC_Stripe_Payment_Methods::OXXO => WC_Stripe_UPE_Payment_Method_Oxxo::class,
WC_Stripe_Payment_Methods::SEPA => WC_Stripe_UPE_Payment_Method_Sepa::class,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change intentionally part of this PR? I just want to make sure, because it's a minor thing that could have unexpected consequences!

Comment on lines +749 to +751
if ( ! WC_Stripe_Payment_Method_Configurations::is_enabled() ) {
return $available_payment_method_ids;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a comment explaining why this condition is needed?

I am especially confused because the old behaviour was to filter the local list, while we're now only filtering the list when we're not fetching data from Stripe.

@@ -244,9 +244,9 @@ public function register_routes() {
*/
public function get_settings() {
$is_upe_enabled = WC_Stripe_Feature_Flags::is_upe_checkout_enabled();
$enabled_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_enabled_payment_method_ids( true ) : WC_Stripe_Helper::get_legacy_enabled_payment_method_ids();
Copy link
Contributor

Choose a reason for hiding this comment

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

It may be worth adding a comment around the choice to trigger these calls in this order, just to make it clear why we're making the calls with the true argument in only this first call.

Suggested change
$enabled_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_enabled_payment_method_ids( true ) : WC_Stripe_Helper::get_legacy_enabled_payment_method_ids();
// Note that we want to refresh the Stripe Payment Method Configuration cache exactly once
// when UPE is enabled, so we force a refresh on this first call only, and not when calling
// get_upe_available_payment_methods() below.
$enabled_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_enabled_payment_method_ids( true ) : WC_Stripe_Helper::get_legacy_enabled_payment_method_ids();

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.

3 participants