feat(discount): add gift_line_item_id to applied discount#578
feat(discount): add gift_line_item_id to applied discount#578prateek-ct wants to merge 4 commits into
Conversation
Some promotions grant a free or discounted line item (buy-one-get-one, free-gift-with-purchase) rather than reducing an existing item's price. Today applied_discount can only describe an amount-based effect, so a gifted line item has no structured link back to the discount that produced it -- a platform sees a mystery zero-price item with no attribution. Adds an optional gift_line_item_id field to applied_discount, pointing at the line_items[] entry the discount granted. Omitted for ordinary amount-based discounts, so this is backward compatible.
| }, | ||
| "description": "Breakdown of where this discount was allocated. Sum of allocation amounts equals total amount." | ||
| }, | ||
| "gift_line_item_id": { |
There was a problem hiding this comment.
Some ecommerce systems allow for multiple gifts or bonus products being triggered from a single promotion. i.e. buy x, get gift y. Buy a 2nd x, get a 2nd gift y.
Could we make this an array?
There was a problem hiding this comment.
Good catch - done. Changed gift_line_item_id to gift_line_item_ids (array of strings) so promotions that grant multiple gift units from a single discount (e.g. "buy 2, get 2 free" scaling with quantity) can be represented. Added a second example showing the multi-gift case with the latest commit.
| { | ||
| "code": "FREEGIFT", | ||
| "title": "Free Socks with Shoe Purchase", | ||
| "amount": 1200, |
There was a problem hiding this comment.
maybe naive question, but what's the rationale of keeping the amount here? shouldn't it be automatically computed based on "gift_line_item_id" to avoid discrepancies?
There was a problem hiding this comment.
Not naive at all , your question made me rethink this properly and it turned up a real mistake in my example- the gift line item's price was zeroed out. Fixed now , it shows its actual price like any other line item with the discount as its own items_discount entry in that line item's totals, so the total nets to 0 (or less, for partial-price gifts). Pushed in a recent commit, happy to have you take another look.
amount on the discount itself is still required though, even with the line item priced correctly. Nothing stops a second, unrelated discount from also touching that same line item , its totals[] can carry more than one items_discount entry with no way to tell which came from which discount. amount is what lets you attribute the value to this specific discount, same as for every other discount type.
Per review feedback: some promotions grant more than one gift unit from a single discount (e.g. "buy 2, get 2 free" scaling with quantity), which a single gift_line_item_id string couldn't represent. - gift_line_item_id (string) -> gift_line_item_ids (array of strings) - Added a multi-gift example - Clarified why applied_discount.amount stays required even when gift_line_item_ids is present: a gift line item's serialized price is already zeroed by the discount, and there's no separate "regular price" field to recover its value from, so amount is the only place that value is communicated
The gift examples zeroed item.price to reflect the discount, which contradicts how every other discount in this spec already works: item.price stays at the regular value and the discount shows up as a separate items_discount entry in that line item's totals[]. Fixed both examples to follow that convention, and added allocations so the gift-granting applied_discount entries are consistent with how amount-based discounts already report their breakdown. Also corrects the "why amount stays required" rationale: it's not because the value is otherwise unrecoverable (it now is, from the line item's own price/totals) -- it's required for the same reason every other discount keeps it explicit, so a platform doesn't have to cross-reference line_items[] or sum allocations[] just to read what a discount was worth.
The previous wording justified amount as "consistency" with ordinary discounts, which is a style preference, not a real constraint -- easy to read as "not actually needed." Replace it with the concrete reason: allocations is optional (nothing to sum in the simple case), and even when a gift line item's own totals are correct, a second, unrelated discount can add its own items_discount entry to the same line item with no way to tell which entry came from which discount. amount is the only value always attributable to this specific discount.
Description
Some promotions grant a free or discounted line item (buy-one-get-one, free-gift-with-purchase) rather than reducing the price of an item the buyer already has. Today
applied_discountcan only describe an amount-based effect — a business granting a gift line item has no structured way to link it back to the discount that produced it, so a platform/agent sees an unexplained zero-price item inline_items[].This adds an optional
gift_line_item_idfield toapplied_discount, pointing at theline_items[]entry the discount granted. It's omitted for ordinary amount-based discounts, so this is backward compatible.Motivated by implementing the discount extension against a commerce backend whose "gift line item" cart discount type is a common, first-class promotion pattern — this gap surfaced immediately when mapping that feature onto the current schema.
Category (Required)
ucp-schematool (resolver, linter, validator). (Requires Maintainer approval)Related Issues
None filed yet — happy to open one first if maintainers would rather see this go through a fuller proposal before schema changes.
Checklist
!for breaking changes).Screenshots / Logs (if applicable)
N/A — schema/documentation change only.