fix(payment): resolve minimum_amount rejection for promotion codes in foreign currencies and trials (#23300, #23299)
Closed
DI
4d ago+277+277+012345678901234567890123456789-28-28-01234567890123456789
Summary
Fixes #23300 and Fixes #23299.
Stripe promotion codes created with a minimum_amount constraint (such as $269.00 USD for unlimited first-year membership) were being rejected under two conditions:
- Adaptive Pricing / Currency Conversion (#23299): When international customers check out in non-USD currencies (e.g. GBP £209.82, EUR €249), Stripe evaluates the
minimum_amountagainst the presentment currency rather than USD, rejecting the promotion code. - Trial Checkouts (#23300): When checkout sessions include a trial period (
trial_period_days), the initial amount due is $0, violating the promo code's positiveminimum_amountrequirement. - Subscription Upgrades with Currency Mismatch: During subscription modifications, applying a promo code with currency/minimum constraints triggers
stripe.error.InvalidRequestError.
Changes
-
backend/utils/stripe.py(create_subscription_checkout_session):- Suppresses
trial_period_dayswhenpromotion_code_idis provided (trial_period_days and not promotion_code_id). - Disables Adaptive Pricing (
session_params['adaptive_pricing'] = {'enabled': False}) whenpromotion_code_idis supplied, keeping presentment in the promo code's native USD currency. - Adds automatic fallback to the underlying Stripe coupon (
discounts=[{"coupon": coupon_id}]) if Stripe rejectsSession.createdue to a promo codeminimum_amount/ currency mismatch.
- Suppresses
-
backend/routers/payment.py:- In
create_checkout_session_endpoint: suppressestrial_period_dayswhen a validresolved_checkout_promo_idis passed. - In
upgrade_subscription_endpoint: catchesstripe.error.InvalidRequestErroronSubscription.modifyandSubscriptionSchedule.modifywhen promo code minimum amount or currency restrictions are encountered, extracts the underlying coupon, applies[{"coupon": coupon_id}], and safely retires single-use promotion codes (active=False).
- In
-
backend/tests/unit/test_payment_promo_currency_minimum_amount.py:- Unit tests covering:
- Promo code checkout with trial requested suppresses trial.
- Promo code checkout disables adaptive pricing.
- Checkout session creation gracefully falls back to underlying coupon on minimum amount error.
- Subscription upgrade gracefully falls back to underlying coupon and deactivates single-use promo code when minimum amount check fails.
- Unit tests covering:
Testing
- Ran unit tests:
python -m pytest backend/tests/unit/test_payment_promo_currency_minimum_amount.py backend/tests/unit/test_payment_promotion_codes.py -v - Result: 24 passed, 0 failed, 100% pass rate.
Payout Information
- Payout Wallet:
0xC345C07229307d4f1c7935aD2cAe48e390215808(USDC on Polygon / Base / Arbitrum) - Contributor: @Dimank92