fix(rest): emit discount totals[] entry as a negative amount#132
Conversation
damaz91
left a comment
There was a problem hiding this comment.
Thanks for the PR! The fix is correct and the new integration test verifies the behavior.
I have a couple of suggestions:
-
Regenerate Sample Output: Since the sign of the discount total has changed, the sample interaction log
rest/python/client/flower_shop/sample_output/happy_path_dialog.mdis now out of sync. Could you please regenerate it? You can do this by running the scriptrest/python/client/flower_shop/extract_json_dialog.sh(make sure your server is running or the script will start one) and then copying the generated file to thesample_outputdirectory.Specifically, the
totalssection in the sample output should show a negative discount:{ "type": "discount", "amount": -650 } -
Node.js Server Bug: I noticed that the Node.js implementation has the exact same bug. In
rest/nodejs/src/api/checkout.tsaround line 363:checkout.totals.push({ type: "discount", amount: discountAmount });
It should be
-discountAmount.If you'd like, you can fix it in this PR as well, or we can address it in a separate issue/PR.
Otherwise, this looks good to go.
|
Thanks for the review! Both addressed:
|
The flower-shop checkout appended the discount to totals[] with a positive amount, so the receipt did not reconcile (subtotal + discount != total) and the entry violated total.json, which constrains discount/items_discount amounts with exclusiveMaximum: 0. Per discount.md the applied[].amount is the magnitude (always positive) while the totals[] entry is its signed effect on the receipt (negative for a discount). Negate only the totals[] entry; applied[].amount and the allocation stay positive. Adds a test asserting the discount total is negative, applied amounts stay positive, and subtotal + discount == total; corrects the existing case-insensitive test, which asserted the old positive value.
Regenerates the discount totals[] entries in the happy-path dialog to match the corrected sign (now -650). The applied[].amount entries stay positive (the magnitude). Scoped to the discount lines only; the file is otherwise still on the 2026-01-23 profile shape (predates Universal-Commerce-Protocol#129) and is out of scope for this PR.
The Node.js server had the same sign bug as the Python server: the discount was pushed to totals[] with a positive amount, so the receipt did not reconcile and the entry violated total.json (exclusiveMaximum: 0). Negate only the totals[] entry; applied[].amount and the allocation stay positive (the magnitude, per discount.md). Adds a test driving recalculateTotals against an in-memory catalog: the discount total is negative, the receipt reconciles (subtotal + discount == total), and applied[].amount stays positive.
de0a7cb to
922f776
Compare
What
The Python Flower Shop server appends the applied discount to
totals[]with a positive amount. Booting the server and creating a checkout forbouquet_roses(3500) withdiscounts.codes: ["10OFF"]returns:Two problems with the
+350:total.jsonconstrainsdiscount/items_discountamounts withexclusiveMaximum: 0(they must be strictly negative).3500 + 350 ≠ 3150. Perdiscount.md("Allocation Details"): "theapplied[].amountdescribes the magnitude of the applied discount (always positive); the correspondingtotals[]entry amount represents its signed effect on the receipt (negative for discounts)."Fix
Negate only the
totals[]entry (amount=-discount_amount).applied[].amountand the allocation stay positive, per the spec's magnitude-vs-signed-effect split. After the fix the same request returns{"type": "discount", "amount": -350}andsubtotal + discount == total.Tests
test_discount_total_is_negative_and_receipt_reconciles— asserts the discount totals entry is strictly negative,applied[].amountstays positive, and the receipt reconciles.test_discount_code_matches_case_insensitivelyasserted the old positive value ([100]→[-100]).rest/python/serversuite passes.