Skip to content

Immediate subscription product-switch can apply a stale discount before it's cleared #13931

Description

@stilla

Bug

When a subscription's product is changed with an immediate proration_behavior (e.g. invoice), and the same request also sends discount_id: null to explicitly clear an existing discount, the discount is not reliably cleared before the immediate order/billing entries are generated. The stale discount can still apply to the newly generated order, reducing (or fully zeroing) the amount charged, even though the request asked to unset it.

A separate follow-up request that changes only the discount (no product_id in the payload) does correctly clear the discount on the subscription going forward, but by then the mispriced order has already been created and paid. That order can't be corrected afterward: void only applies to pending orders, and this one is already paid.

Impact

  • Customer isn't charged the intended amount for the plan switch.
  • The only recovery path today is a fully separate manual one-time order against a one-time product, since the original order can't be voided or recomputed.

Suspected cause

SubscriptionService.update_product() threads a discount_unset sentinel through generate_subscription_update() / apply_update(), which should clear subscription.discount before billing. Existing test coverage (test_proration_with_discount_change) doesn't clearly include the immediate invoice (bill-now) proration behavior specifically combined with a discount removal. Worth checking whether, for proration_behavior=invoice, billing entries/the order get built from the subscription's discount before the unset is actually applied and persisted.

Suggested fix

  • Add test coverage for proration_behavior=invoice combined with clearing an existing discount as part of the same product-change request.
  • Ensure discount resolution/clearing happens before billing entries and the order are generated, consistently across all immediate proration behaviors.

Sent by @allison-polar from Subscription c6baa936 charge investigation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions