Final piece of the bypass-Odoo-POS writer side. When a customer is refunded for an order rung in a PRIOR closed session (yesterday's), the refund cash physically exits TODAY's drawer — so the refund books to TODAY's close-move, not yesterday's. Per Narong's Option B decision (2026-05-11): mirrors Odoo POS's native behavior (refund creates a negative pos.order folded into next session_close); cash flow aligns with the physical drawer; less Odoo write volume than Option A's per-refund reverse entry.
e19b33a (cafe) — single file extension to lib/db/cafe_sessions.ts aggregator. 79 insertions. No migration.bypass_odoo_pos=true, which doesn't happen until R11.5 cutover (separate future session). Gate 2 is regression-only — confirms the aggregator change didn't break any production read path that uses the existing fields. Real cross-session refund verification happens in R11.5 with an actual flag flip + real shift close on get-coffee.
| Suite | Result | Notes |
|---|---|---|
| test-launchpad-fix-prod.mjs | 8/8 | Outdoor SSO bridge fix sanity |
| test-r7-prod.mjs | 14/14 | Dashboard + manager-live |
| test-r8-prod.mjs | 4/4 | Auth/security trio |
| test-cash-carryover-prod.mjs | 9/9 | cafe.sessions read path (same DAO we just extended) |
| test-phase2-cafe-multishop-prod.mjs | 6/6 | Cafe multi-shop |
lib/db/cafe_sessions.ts — aggregateSalesAndPaymentsForSession extension:
+ Detect cafe.order_refunds where refunded_at ∈ session's open window
AND original order.session_id != current session (cross-session only).
+ For each: subtract from gross + subtract from cash bucket (or first
method / synthesized "Refund" bucket as fallback).
+ 2 new diagnostic fields on SessionMoveAggregate:
crossSessionRefundCount
crossSessionRefundTotalUsd
Same-session refunds still handled by the existing orders loop
(state='refunded' → subtract). Cross-session filter avoids double-counting.
No migration, no new column. Timestamp inference works because
cafe.sessions has a partial unique enforcing one open session per
pos_config_id — every refund.refunded_at lands in exactly one session
window per register.
- SQL flip cafe.tenant_config.bypass_odoo_pos=true on get-coffee. - Close a real shift on get-coffee POS. - Wait one cron tick; watch the drain post an account.move to journal 48 "NIX Cafe Sales" in Odoo with the right credit + debit lines. - Generate-and-diff against historical Odoo-auto-created moves (Strategy A from scoping memo). - Issue a refund on a closed-session's order; verify it folds into the NEXT session's close-move per R11.4's design. - Watch one week of bypass-mode operation in production. - Eventually retire the legacy pos.order/pos.session push for the flipped tenant.