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

Respect BNPL limits_per_currency (country, min, max) #9626

Merged
merged 10 commits into from
Oct 31, 2024

Conversation

mdmoore
Copy link
Member

@mdmoore mdmoore commented Oct 24, 2024

Fixes #9456

Changes proposed in this Pull Request

As described in #9456, when there is no BNPL offer on PDPs, the PMME is displaying a skeleton loader which resolves to an empty space. This PR solves that by predicting whether the PMME will render any payment methods. If not, the PMME is hidden, with no skeleton displayed and no dead space below the product price. An earlier PR attempted to solve this for minimum price limits only, but rather than the BNPL minimums, the overall Stripe charge limits were used, which differ from BNPL minimums. To solve this, I've aggregated all $limits_per_currency arrays into a function that is used to determine whether any offers will be available. The result is surfaced on the front end via the wcpayStripeSiteMessaging.isBnplAvailable.

This also ensures that the PMME visibility is toggled when product quantity or variation changes result in price changes that affect payment method visibility. This done listening for changes to quantity or variation, then sending a request to get the BNPL availability.

Testing instructions

  1. Enable all BNPL payment methods
  2. Ensure your billing country matches the country in your Stripe merchant account
  3. Test the following scenarios:

No BNPL offers

  1. Create a product with a price of 20 cents.
  2. Visit the product and check that no skeleton loader or dead space appear below the product price.

Quantity Updates

  1. On the same 20 cent product, increase the quantity to 5 or more
  2. The PMME should appear.
  3. Decrease the quantity to 1. The PMME should smoothly disappear with no dead space apparent.

Further tests can be perform using the conditions in the unit test here.

Before
Screen Capture on 2024-10-24 at 16-47-08

After
image


  • Run npm run changelog to add a changelog file, choose patch to leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.
  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Post merge

@botwoo
Copy link
Collaborator

botwoo commented Oct 24, 2024

Test the build

Option 1. Jetpack Beta

  • Install and activate Jetpack Beta.
  • Use this build by searching for PR number 9626 or branch name fix/9456-bnpl-respect-limits-per-currency in your-test.site/wp-admin/admin.php?page=jetpack-beta&plugin=woocommerce-payments

Option 2. Jurassic Ninja - available for logged-in A12s

🚀 Launch a JN site with this branch 🚀

ℹ️ Install this Tampermonkey script to get more options.


Build info:

  • Latest commit: 3eae337
  • Build time: 2024-10-25 19:48:16 UTC

Note: the build is updated when a new commit is pushed to this PR.

Copy link
Contributor

github-actions bot commented Oct 24, 2024

Size Change: +95 B (0%)

Total Size: 1.34 MB

Filename Size Change
release/woocommerce-payments/dist/product-details.js 12.1 kB +95 B (+1%)
ℹ️ View Unchanged
Filename Size
release/woocommerce-payments/assets/css/admin.css 1.37 kB
release/woocommerce-payments/assets/css/admin.rtl.css 1.37 kB
release/woocommerce-payments/assets/css/success.css 173 B
release/woocommerce-payments/assets/css/success.rtl.css 173 B
release/woocommerce-payments/dist/blocks-checkout-rtl.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.js 67.2 kB
release/woocommerce-payments/dist/cart-block.js 16.8 kB
release/woocommerce-payments/dist/cart.js 5.73 kB
release/woocommerce-payments/dist/checkout-rtl.css 1.21 kB
release/woocommerce-payments/dist/checkout.css 1.21 kB
release/woocommerce-payments/dist/checkout.js 32.8 kB
release/woocommerce-payments/dist/express-checkout-rtl.css 230 B
release/woocommerce-payments/dist/express-checkout.css 230 B
release/woocommerce-payments/dist/express-checkout.js 14.8 kB
release/woocommerce-payments/dist/frontend-tracks.js 858 B
release/woocommerce-payments/dist/index-rtl.css 39.2 kB
release/woocommerce-payments/dist/index.css 39.2 kB
release/woocommerce-payments/dist/index.js 302 kB
release/woocommerce-payments/dist/multi-currency-analytics.js 1.08 kB
release/woocommerce-payments/dist/multi-currency-rtl.css 3.37 kB
release/woocommerce-payments/dist/multi-currency-switcher-block.js 60.6 kB
release/woocommerce-payments/dist/multi-currency.css 3.37 kB
release/woocommerce-payments/dist/multi-currency.js 55.6 kB
release/woocommerce-payments/dist/order-rtl.css 730 B
release/woocommerce-payments/dist/order.css 730 B
release/woocommerce-payments/dist/order.js 42.7 kB
release/woocommerce-payments/dist/payment-gateways-rtl.css 1.32 kB
release/woocommerce-payments/dist/payment-gateways.css 1.32 kB
release/woocommerce-payments/dist/payment-gateways.js 39.3 kB
release/woocommerce-payments/dist/payment-request-rtl.css 230 B
release/woocommerce-payments/dist/payment-request.css 230 B
release/woocommerce-payments/dist/payment-request.js 14.2 kB
release/woocommerce-payments/dist/plugins-page-rtl.css 386 B
release/woocommerce-payments/dist/plugins-page.css 386 B
release/woocommerce-payments/dist/plugins-page.js 20.1 kB
release/woocommerce-payments/dist/product-details-rtl.css 433 B
release/woocommerce-payments/dist/product-details.css 436 B
release/woocommerce-payments/dist/settings-rtl.css 11.6 kB
release/woocommerce-payments/dist/settings.css 11.5 kB
release/woocommerce-payments/dist/settings.js 225 kB
release/woocommerce-payments/dist/subscription-edit-page.js 703 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal-rtl.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.js 20.2 kB
release/woocommerce-payments/dist/subscription-product-onboarding-toast.js 730 B
release/woocommerce-payments/dist/subscriptions-empty-state-rtl.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.js 19.3 kB
release/woocommerce-payments/dist/tokenized-payment-request-rtl.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.js 15 kB
release/woocommerce-payments/dist/tos-rtl.css 235 B
release/woocommerce-payments/dist/tos.css 235 B
release/woocommerce-payments/dist/tos.js 21.8 kB
release/woocommerce-payments/dist/woopay-direct-checkout.js 6.14 kB
release/woocommerce-payments/dist/woopay-express-button.js 24.6 kB
release/woocommerce-payments/dist/woopay-rtl.css 4.52 kB
release/woocommerce-payments/dist/woopay.css 4.49 kB
release/woocommerce-payments/dist/woopay.js 71.6 kB
release/woocommerce-payments/includes/subscriptions/assets/css/plugin-page.css 625 B
release/woocommerce-payments/includes/subscriptions/assets/js/plugin-page.js 814 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/i18n-loader.js 2.46 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/jetpack-script-data.js 735 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/react-jsx-runtime.js 553 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/i18n-loader.js 1.02 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/script-data.js 69 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/babel.config.js 163 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.js 14.2 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.rtl.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.js 280 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.rtl.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.css 625 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.js 333 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.rtl.css 626 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-users.js 417 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-ajax.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-callables.js 584 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.css 215 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.css 721 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.js 412 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-users.js 621 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/about.css 1.04 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-empty-state.css 294 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css 408 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin.css 3.59 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/checkout.css 301 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/modal.css 746 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css 574 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css 414 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js 543 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js 9.4 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js 6.78 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js 3.84 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js 545 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js 2.52 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js 22.2 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js 11.7 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js 1.29 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js 507 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js 358 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js 428 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js 1.38 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js 782 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/modal.js 1.09 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js 1.26 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.css 391 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.js 3.04 kB

compressed-size-action

Comment on lines -727 to -763
public static function get_stripe_minimum_amount( $currency ) {
switch ( $currency ) {
case 'AED':
case 'MYR':
case 'PLN':
case 'RON':
$minimum_amount = 200;
break;
case 'BGN':
$minimum_amount = 100;
break;
case 'CZK':
$minimum_amount = 1500;
break;
case 'DKK':
$minimum_amount = 250;
break;
case 'GBP':
$minimum_amount = 30;
break;
case 'HKD':
$minimum_amount = 400;
break;
case 'HUF':
$minimum_amount = 17500;
break;
case 'JPY':
$minimum_amount = 5000;
break;
case 'MXN':
case 'THB':
$minimum_amount = 1000;
break;
case 'NOK':
case 'SEK':
$minimum_amount = 300;
break;
Copy link
Member Author

@mdmoore mdmoore Oct 24, 2024

Choose a reason for hiding this comment

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

Mentioned in the PR description, this was added to handle BNPL minimum amounts but is actually comprised of Stripe minimum amounts. It's was only used for that purpose and is safe to remove.

Comment on lines +895 to 898
public static function get_cached_minimum_amount( $currency ) {
$cached = get_transient( 'wcpay_minimum_amount_' . strtolower( $currency ) );

if ( (int) $cached ) {
return (int) $cached;
} elseif ( $fallback_to_local_list ) {
return self::get_stripe_minimum_amount( $currency );
}

return null;
return (int) $cached ? (int) $cached : null;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Similar to the previous comment, reverting this back to it's state prior to #9355.

@mdmoore mdmoore requested review from a team and brettshumaker and removed request for a team October 24, 2024 20:57
Copy link
Contributor

@brettshumaker brettshumaker left a comment

Choose a reason for hiding this comment

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

This is in pretty good shape save for my note about reusing a nonce across ajax actions. I also left a few comments to try and get a things tweaked to match up with limits I see in Stripe's documentation.

@@ -1713,7 +1714,7 @@ public static function ajax_get_woopay_signature() {
* Get cart total.
*/
public static function ajax_get_cart_total() {
check_ajax_referer( 'wcpay-get-cart-total', 'security' );
check_ajax_referer( 'wcpay-bnpl-nonce', 'security' );
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I'd rather see this method use a separate nonce than the BNPL method below. I don't think there's much of an "attack vector" here, but it's best practice for each ajax action to use their own nonce.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair enough! Done in 613bb62.

'isCart' => is_cart(),
'isCartBlock' => $is_cart_block,
'cartTotal' => WC_Payments_Utils::prepare_amount( $cart_total, $currency_code ),
'nonce' => wp_create_nonce( 'wcpay-bnpl-nonce' ),
Copy link
Contributor

Choose a reason for hiding this comment

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

I noted this in class-wc-payments-utils.php as well, but I think we should separate the nonces here.

Comment on lines 785 to 786
'max' => 1150000,
], // Represents GBP 1 - 11,500 GBP.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be 5,000 GBP.

Suggested change
'max' => 1150000,
], // Represents GBP 1 - 11,500 GBP.
'max' => 500000,
], // Represents GBP 1 - 5,000 GBP.

'max' => 400000,
], // Represents EUR 1 - 4,000 EUR.
Country_Code::FRANCE => [
'min' => 3500,
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like France should also be 100.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for going through all of these again. Very much appreciated.

Country_Code::FRANCE => [
'min' => 3500,
'max' => 400000,
], // Represents EUR 35 - 4000 EUR.
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nitpick to keep the formatting consistent (and adjust for the lower limit).

Suggested change
], // Represents EUR 35 - 4000 EUR.
], // Represents EUR 1 - 4,000 EUR.

@mdmoore mdmoore requested a review from brettshumaker October 25, 2024 17:53
@mdmoore
Copy link
Member Author

mdmoore commented Oct 25, 2024

Thanks @brettshumaker. All of the changes have been addressed.

Copy link
Contributor

@brettshumaker brettshumaker left a comment

Choose a reason for hiding this comment

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

Thanks for handling those last few bits! This was working and testing as described for me.

@mdmoore mdmoore added this pull request to the merge queue Oct 25, 2024
@mdmoore mdmoore removed this pull request from the merge queue due to a manual request Oct 25, 2024
}
}
}

$enabled_upe_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout();
$enabled_upe_payment_methods = $this->gateway->get_upe_enabled_payment_method_ids();
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 just ensures we're getting all of the enabled BNPL payment methods. get_payment_method_ids_enabled_at_checkout() is a filtered list for checkout. This means, if you visit a PDP while you have products in the cart, you might not see the correct BNPL methods in the PMME. For example, with a $5 product in the cart, a $60 PDP won't display Affirm ($50 minimum) because it's been filtered out based on cart totals. Demo here, second example from the bottom. This change solves that.

@mdmoore
Copy link
Member Author

mdmoore commented Oct 31, 2024

Hey @brettshumaker 👋 - I added one last commit (3eae337) after your previous approval, if you don't mind taking a quick look.

@mdmoore mdmoore added this pull request to the merge queue Oct 31, 2024
Merged via the queue into develop with commit ccff836 Oct 31, 2024
25 checks passed
@mdmoore mdmoore deleted the fix/9456-bnpl-respect-limits-per-currency branch October 31, 2024 18:58
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.

Update PMME implementation on the PDP to eliminate dead space
3 participants