POS shifts: opening, closing, X and Z reports
A shift is the business day at a register. Every cash sale, refund, drop, and paid-in is bound to one. When you close it, LaunchMyStore freezes a Z-report — the immutable record of the day’s drawer.
The shift lifecycle
- Open — declare opening cash float, choose a device and warehouse.
- Trade — sell, refund, drop cash, pay-in, pay-out. Cashiers can join the shift as contributors.
- X-report (optional, any number of times) — mid-day snapshot, shift stays open.
- Close — count the drawer, declare closing cash, generate the Z-report. Shift is now immutable.
Opening cash float
The opening float is the cash you put in the drawer at the start of the day to make change — typically $100 or $200 in mixed denominations. When you open a shift, the register asks for it and stores it as the shift’s opening float.
This number anchors the math at close. The system computes:
expected_cash = opening_float
+ sum(cash sales)
- sum(cash refunds)
+ sum(paid_in)
- sum(paid_out)
- sum(drops)If your hand-count at close matches expected_cash, your variance is $0 and the drawer balances.
Cash movements during the shift
The five cash-movement types recorded against the shift:
sale— auto-created when a cash-tender order posts.refund— auto-created when a cash refund posts.drop— cashier moves cash out of the drawer to the safe.paid_in— cashier adds cash to the drawer (change-fund top-up).paid_out— cashier removes cash for a non-sale reason (petty cash, expense).
Every movement carries an optional reason field. Use it — auditors and your future self will thank you.
X-report: mid-shift snapshot
An X-report is the same shape as a Z-report, but the shift stays open and nothing is persisted. Call it any time during the day to see:
- Gross sales by tender (cash, card, gift card)
- Refund and void totals
- Expected cash currently in the drawer
- Item count and discount totals
X-reports are great for handoffs (e.g., one cashier hands the drawer to another and they both want to agree on the count) without locking the shift.
Endpoint: GET /pos/shifts/:id/x-report. The shift must be open — closed shifts return 400 Use Z-report for closed shifts.
Z-report: end-of-day, immutable
The Z-report is generated once, at close, and cached on the shift in its zReport field. Re-printing it later returns the same bytes, even if movements are appended afterward (they can’t be — the shift is locked).
How to close a shift
- Open the POS tool, go to More → Shift.
- Tap Close shift.
- Hand-count the cash drawer.
- Enter the declared closing cash.
- Optionally leave a closing note — required if there is a variance.
At close, the system computes:
closingExpected= the formula above.closingDeclared= what you typed.variance=closingDeclared - closingExpected. Negative is short, positive is over.zReport= full structured snapshot, frozen forever.
Reading the Z-report
The Z-report breaks the day down into three groups:
- Tender totals — cash, card, gift card, split, with counts and amounts.
- Cash reconciliation — opening, expected, declared, variance.
- Staff activity — orders per contributor, refunds per contributor.
Multi-staff on one shift
A shift is shared across cashiers via a list of contributors on the shift. The opener is the “owner”; everyone else joins as a contributor with a joinedAt timestamp. When a contributor clocks out, their entry gets a leftAt stamp but is preserved for the audit trail.
This is why the register’s “current shift” lookup matches you whether you opened the shift or joined it as a contributor — a cashier who joined a shift opened by someone else still sees it as their current shift.
Force-close (manager-only)
If a cashier walks out without closing — or the register lost network mid-close — a manager can force-close from the backend (UI for this is coming to the admin). Force-close:
- Defaults
closingDeclaredtoexpectedCashif not provided (variance = 0). - Stamps the Z-report with
forceClosed: trueand the reason. - Writes a
shift.force_closestaff-audit row.
Common issues
- Variance keeps showing as positive every day — staff is forgetting to record cash paid_out for expenses.
- Variance is large negative — check for missed refunds, miscounted change, or stolen-cash escalation.
- “Shift already closed” at close — another cashier or manager closed it from a second device. Pull the Z-report instead.
FAQ
Can I edit a Z-report after the fact?
No. Once a shift is closed, the Z-report is immutable. If you noticed an error, post a correcting cash movement on a future shift with a clear reason note, or void/refund the offending order.
How many X-reports can I run?
As many as you like. X-reports are read-only snapshots and don’t change shift state.
What if I forgot to set an opening float?
The shift opens with a float of $0. Your expected cash will be off by the real opening amount — just declare it via a paid_in movement at the start of the day, with reason “Opening float correction”.
Where do I see end-of-day totals?
The Z-report card appears in the POS tool the moment you close the shift. Closed shifts also show up under Orders → Shifts history with their Z-reports re-printable on demand.
Can two shifts be open on the same register at the same time?
No. Only one open shift is allowed per register at a time — a new cashier opening on the same register joins the existing shift as a contributor instead of starting a fresh one.
What happens if power dies mid-sale?
The order isn’t persisted until the backend confirms. On reconnect, the cart is restored from the register’s local cache and you re-tender. Inventory and cash are never decremented for a sale that didn’t finalize.