Skip to content

Recalculate open checkouts when a discount's amounts/currency change #13208

Description

@stilla

DiscountFixed.get_discount_amount does a direct self.amounts[currency] lookup with no fallback. If a merchant edits a DiscountFixed discount (e.g. via DiscountService.update, especially through the legacy amount+currency fields, which replaces the whole amounts map) while an open, unconfirmed checkout still references that discount and a now-removed currency, the checkout ends up in an inconsistent state. DiscountService.update() only blocks the edit when redemptions_count > 0, which doesn't cover this case. Reading the checkout afterwards (e.g. GET /v1/checkouts/client/{client_secret}) then serializes discount_amount and crashes with an unhandled KeyError.

Example: SERVER-4VF, checkout 7e54d8a5-f92c-423e-aaf9-d04a9b48afd5, KeyError: 'czk'.

Instead of only guarding against the edit or patching the read path, DiscountService.update() should proactively reconcile any open checkouts referencing the discount when amounts/currency change: re-run the existing is_applicable(product, currency) check for each affected open checkout and, when it no longer holds, null out the checkout's discount and recompute its totals (net_amount, tax_amount, etc.) the same way _update_checkout already does. This keeps checkouts consistent immediately after the discount edit rather than deferring to (or crashing on) the next checkout read/update.

Related prior art: #13140 fixed the same underlying amounts[currency] indexing issue for the subscription resolve path only (feedback#171); #12339 fixed a similar currency-mismatch crash in checkout product/price updates. Neither covers a discount being edited out from under an already-open checkout.

Sent by @frankie567 from Stilla investigation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions