Skip to content

fix(rest/python): rebuild discounts.applied idempotently on recalculation - #154

Merged
damaz91 merged 1 commit into
Universal-Commerce-Protocol:mainfrom
XiaolongZhang-TT:fix/python-discount-applied-dedup-on-update
Jul 30, 2026
Merged

fix(rest/python): rebuild discounts.applied idempotently on recalculation#154
damaz91 merged 1 commit into
Universal-Commerce-Protocol:mainfrom
XiaolongZhang-TT:fix/python-discount-applied-dedup-on-update

Conversation

@XiaolongZhang-TT

@XiaolongZhang-TT XiaolongZhang-TT commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description

_recalculate_totals rebuilt checkout.totals from scratch on every create/update but appended to discounts.applied without resetting it. Because the persisted checkout (reloaded on each update) already carries the applied entries from the previous response, an update that omits the discounts field accumulates a duplicate applied entry on every recalculation.

Repro: create a checkout with discounts.codes = ["10OFF"] (response applied has 1 entry), then PUT /checkout-sessions/{id} with a body that omits discounts (e.g. a quantity / shipping change) → the response discounts.applied lists the discount twice, and keeps growing with each such update.

Root causerest/python/server/services/checkout_service.py, _recalculate_totals: checkout.totals is reset (checkout.totals = []) at the top of each recalculation, but discounts.applied is never reset, so it accumulates once the reloaded checkout brings back the prior entries.

Fix: reset checkout.discounts.applied = None before recomputing — the same "server is the authority, rebuild from scratch" pattern already used for totals. This matches discount.json, where applied carries ucp_request: "omit" (a server-authoritative output field), so it must be rebuilt idempotently rather than appended to.

Category (Required)

  • Samples / Conformance: Maintaining samples and the conformance suite. (Requires Maintainer approval)

Related Issues

None — this is a newly identified bug in the Python sample server (unrelated to #121 / #134).

Checklist

  • I have followed the Contributing Guide (including Conventional Commits title requirements and ! for breaking changes).
  • I have updated the documentation (if applicable). — N/A, no documentation changes.
  • My changes pass all local linting and formatting checks. (ruff check + ruff format clean)
  • I have added tests that prove my fix is effective or that my feature works. (test_discount_applied_is_not_duplicated_on_update)
  • New and existing unit tests pass locally with my changes. (Python integration suite: 12 passed)
  • (For Core/Capability) I have included/updated the relevant JSON schemas. — N/A, no schema changes.
  • I have regenerated Python Pydantic models by running generate_models.sh under python_sdk. — N/A, no schema changes.

Screenshots / Logs (if applicable)

Before/after from the regression test — discounts.applied after an update that omits the discounts field:

Before (bug):

applied == ["10OFF", "10OFF"]   # duplicated on each update

After (fix):

applied == ["10OFF"]            # rebuilt idempotently

Full Python integration suite:

12 passed, 2 warnings in 1.76s

…tion

_recalculate_totals rebuilt checkout.totals from scratch on every
create/update but appended to discounts.applied without resetting it.
Because the persisted (and reloaded) checkout already carries the applied
entries from the previous response, an update that omits the discounts
field accumulated a duplicate applied entry on every recalculation.

Reset discounts.applied before recomputing it, mirroring how totals is
rebuilt. The server is the authority for applied discounts (discount.json
marks applied as ucp_request:"omit"), so the list must be rebuilt
idempotently.

Add a regression test (test_discount_applied_is_not_duplicated_on_update)
that creates a checkout with a discount code, then updates it without
re-submitting discounts and asserts applied stays a single entry.
@XiaolongZhang-TT
XiaolongZhang-TT force-pushed the fix/python-discount-applied-dedup-on-update branch from 5753a97 to ea664f4 Compare July 30, 2026 05:30
@XiaolongZhang-TT
XiaolongZhang-TT marked this pull request as ready for review July 30, 2026 05:31
@XiaolongZhang-TT

Copy link
Copy Markdown
Contributor Author

Marking this ready for review. Quick context for reviewers:

Open to a different reset location if a reviewer prefers it.

@damaz91 damaz91 added status:needs-triage Signal that the PR is ready for human triage status:under-review and removed status:needs-triage Signal that the PR is ready for human triage labels Jul 30, 2026
@damaz91
damaz91 merged commit 012630d into Universal-Commerce-Protocol:main Jul 30, 2026
15 checks passed
@XiaolongZhang-TT
XiaolongZhang-TT deleted the fix/python-discount-applied-dedup-on-update branch July 31, 2026 03:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants