Narong, 2026-07-24, after testing on staging. nix-cafe only. No migration, no backend change.
His report:
"Currently, after being applied BOGO, sales are generated as $0 but the line item is not calculated inside Discounts which results in Total amount of Discounts per Day/TIme period not being accurate." → "Make sure that in each POS sale, if it's modified in Discount form, then it should be recorded."
NIX records discounts in two places, and the reports only read one of them:
orders.discount_usd — the order-level manual discount.order_lines.discount_usd — the per-line discount. BOGO and % promotions
only ever write here.
sumDiscountsForSession summed only orders.discount_usd, on the strength of a
docstring claiming the order-create path folded line discounts into it. It does not — createOrder
subtracts the line sum from the subtotal and leaves orders.discount_usd as the manual discount alone.
So every promotional dollar was invisible, and the "Number of discounts" count was understated too.
Fix: the effective discount per order is orders.discount_usd + SUM(order_lines.discount_usd), grouped by
the order primary key so the order-level figure isn't multiplied across its lines (there is a test
guarding exactly that), then rolled up. One indexed LEFT JOIN — no correlated subquery.
⚠️ The tempting alternative — writing the line sum back into orders.discount_usd — would be wrong:
total = postLineSubtotal + tax − discount would then double-subtract and corrupt every receipt. That
reasoning is now recorded in the code.
Narrower than it first looked. The Dashboard and Reports pages were already correct — their DAOs
compute totalDiscount = totalOrderDiscount + totalLineDiscount and the UI reads that. The three broken
surfaces are the consumers of the fixed functions:
| Surface | Status |
|---|---|
| Daily Sales Report — matches his "per Day" wording | was wrong → fixed |
| Closing Session PDF — "Discounts" section | was wrong → fixed |
| Shift Report | was wrong → fixed |
| Dashboard / Reports pages | already correct |
| Data | Reported before | Correct | Hidden |
|---|---|---|---|
| Local session (88 orders) | $2.73 · 4 discounts | $11.81 · 14 discounts | 77% of all discounts |
staging 06ff1e07 | $0.00 | $4.25 | 100% |
staging 129dc772 | $0.00 | $2.00 | 100% |
Both staging shifts had no manual discount, so their reports showed a flat $0.00 — a total blackout of the BOGO discounts actually given. The count was wrong as well as the amount.

Expectations are computed by independent SQL, never by re-running the DAO's own logic. The local suite was then re-run with the fix stashed:
✗ sumDiscountsForSession total = order-level + line-level: DAO $2.73 != expected $11.81 ✗ sumDiscountsForSession count = orders with ANY discount: DAO count 4 != expected 14 ✗ batch agrees with independent SQL: session b8c21982…: DAO $2.73 != expected $11.81
| Suite | Result |
|---|---|
| Local — real DAOs vs independent SQL, single + batch, no-inflation guard, negative control | 7/7 |
| Staging — Shift Report HTML from the deployed Worker, both sessions | 7/7 |
| Staging smoke | 5/5 |
tsc --noEmit | clean |
For refunded / partially-refunded orders the line discounts are summed in full, not scaled by refunded quantity — matching how the existing order-level discount is already treated. Consistent, but it means a fully-refunded order still contributes its discount to the day's total. Netting those out is a separate semantics decision and needs Narong's call.
nix-cafe staging d48d2b7 (Worker 8e103eda). No migration. Parked for the
scheduled prod promote.