# POS shifts: opening, closing, X and Z reports

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

 1. Open — declare opening cash float, choose a device and warehouse.
 2. Trade — sell, refund, drop cash, pay-in, pay-out. Cashiers can join the
    shift as contributors.
 3. X-report (optional, any number of times) — mid-day snapshot, shift stays
    open.
 4. 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

 1. Open the POS tool, go to More → Shift.
 2. Tap Close shift.
 3. Hand-count the cash drawer.
 4. Enter the declared closing cash.
 5. 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 closingDeclared to expectedCash if not provided (variance = 0).
 * Stamps the Z-report with forceClosed: true and the reason.
 * Writes a shift.force_close staff-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.