fix: single PayPal button on checkout; Stripe stays visible
Cart checkout had two payment-UX defects: 1. PayPal Smart Buttons rendered three buttons by default: the yellow PayPal button, "Pay Later" financing, and "Debit or Credit Card" (PayPal-branded card flow). For MPS, credit-card checkout goes through Stripe — the PayPal card button is redundant and pushes a competing flow into the same panel. Fix: append `disable-funding=paylater,card` to the PayPal SDK URL so only the single PayPal Smart Button renders. 2. Stripe lost visibility on the right column when the buyer had no card on file yet. The "Add a credit card payment method" CTA only appeared in the left panel; next to PayPal + crypto on the right, the credit-card path looked unsupported. Fix: when stripe is enabled and the shop is stripe-ready but the buyer has no active card, surface a "Pay with Credit Card — Add Card" CTA in the right column, alongside the PayPal Smart Button. /billing then runs the existing card-add flow. Tests: - test_cart_checkout_for_shop asserts "Pay with Credit Card" renders in the right column when no card is on file. - test_paypal_smart_buttons_collapsed_to_one is a template-grep asserting the SDK URL carries disable-funding=paylater,card.
This commit is contained in:
parent
9c68971971
commit
2e1bde37d3
2 changed files with 39 additions and 4 deletions
|
|
@ -54,6 +54,11 @@
|
|||
{% include "snippets/csrf.j2" %}
|
||||
<button type="submit" class="cart-checkout-button mps-button">Yes, Confirm Checkout with Active Credit Card</button>
|
||||
</form>
|
||||
{% elif stripe_enabled and request.shop and request.shop.is_stripe_ready and cart.requires_payment %}
|
||||
{# No card on file yet — give the buyer a prominent CTA on the right
|
||||
column so Stripe stays visible alongside PayPal and crypto. /billing
|
||||
adds the card; the buyer returns here to confirm checkout. #}
|
||||
<a href="/billing" class="cart-checkout-button mps-button">Pay with Credit Card — Add Card</a>
|
||||
{% endif %}
|
||||
|
||||
{# PayPal checkout button #}
|
||||
|
|
@ -86,7 +91,10 @@
|
|||
{% endif %}
|
||||
|
||||
<div id="paypal-button-container"></div>
|
||||
<script src="https://www.paypal.com/sdk/js?client-id={{ request.shop.paypal_client_id }}¤cy=USD"></script>
|
||||
{# disable-funding=paylater,card hides the secondary "Pay Later" and
|
||||
"Debit or Credit Card" Smart Buttons so only the single yellow
|
||||
PayPal button renders. Credit-card checkout flows through Stripe. #}
|
||||
<script src="https://www.paypal.com/sdk/js?client-id={{ request.shop.paypal_client_id }}¤cy=USD&disable-funding=paylater,card"></script>
|
||||
<script>
|
||||
// Store all order IDs for multi-shop support
|
||||
var allPayPalOrderIds = [];
|
||||
|
|
|
|||
|
|
@ -629,9 +629,13 @@ class AuthenticatedFunctionalTests(_AuthenticatedBase):
|
|||
# With multiple payment methods enabled (Stripe + PayPal), checkout
|
||||
# renders directly instead of redirecting to /billing for Stripe setup
|
||||
self.assertEqual(200, res_csrf_checkout.status_int)
|
||||
self.assertIn(
|
||||
"Please confirm your order.", res_csrf_checkout.body.decode()
|
||||
)
|
||||
checkout_body = res_csrf_checkout.body.decode()
|
||||
self.assertIn("Please confirm your order.", checkout_body)
|
||||
# Stripe stays a visible option on the right column even when the
|
||||
# buyer has no card on file yet — otherwise the credit-card path
|
||||
# is buried in the left panel and easy to miss next to PayPal /
|
||||
# crypto CTAs.
|
||||
self.assertIn("Pay with Credit Card", checkout_body)
|
||||
|
||||
def test_cart_checkout_logic_with_none_stripe_user_shop(self):
|
||||
"""Test the specific logic that was causing AttributeError in cart checkout.
|
||||
|
|
@ -1750,6 +1754,29 @@ class AuthenticatedFunctionalTests(_AuthenticatedBase):
|
|||
# Should fail with error
|
||||
self.assertIn(res.status_int, [400, 404, 500])
|
||||
|
||||
def test_paypal_smart_buttons_collapsed_to_one(self):
|
||||
"""PayPal SDK URL on cart_checkout disables paylater + card
|
||||
funding so only the single yellow PayPal Smart Button renders.
|
||||
|
||||
Without disable-funding, the SDK renders three buttons: PayPal,
|
||||
Pay Later, and Debit or Credit Card. Credit-card checkout flows
|
||||
through Stripe in MPS — the bottom PayPal-branded card button
|
||||
is redundant and confusing.
|
||||
|
||||
Template-level assertion: the SDK URL in cart_checkout.j2 carries
|
||||
disable-funding=paylater,card. A full render test was flaky against
|
||||
the test harness (transaction boundaries vs. session-cart fixture);
|
||||
this single grep on the file is the smallest stable check.
|
||||
"""
|
||||
import os
|
||||
template_path = os.path.join(
|
||||
os.path.dirname(__file__), "..", "templates", "cart_checkout.j2",
|
||||
)
|
||||
with open(template_path) as fh:
|
||||
content = fh.read()
|
||||
self.assertIn("paypal.com/sdk/js", content)
|
||||
self.assertIn("disable-funding=paylater,card", content)
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
def test_shop_paypal_enabled_toggle(self, mock_smtp):
|
||||
"""Test that shop PayPal can be enabled/disabled via settings."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue