Explained simply · sales-floating-shifts-cash-management · April 2026 · BCPOS
In RMH the shift is called a Batch and it is tied to the register (terminal). When you open a batch on Register 1, everything that happens there belongs to Batch #47 — no matter who is operating it.
| Time | Register | Batch | Action on switch |
|---|---|---|---|
| 8:00 – 10:30 | Register 1 | Batch #47 | Close + count cash drawer |
| 10:30 – 2:00 | Register 5 | Batch #48 | Close + count cash drawer |
| 2:00 – 4:00 | Register 9 | Batch #49 | Close + count cash drawer |
Result:
RMH auto-creates the next batch when you close the previous one. If you close on Monday at 10pm, the new batch opens with Monday's date. But that batch is used all day Tuesday. When SAP/accounting reads the open date, it thinks the batch is Monday's. A familiar accounting headache.
Two new concepts:
Batch #47 → Register 1 (8:00–10:30)
Batch #48 → Register 5 (10:30–2:00)
Batch #49 → Register 9 (2:00–4:00)
3 counts, 3 reports, 0 unified view
Segment 1 → Terminal 1 (8:00–10:30)
Segment 2 → Terminal 5 (10:30–2:00)
Segment 3 → Terminal 9 (2:00–4:00)
1 count, 1 report, 1 owner
At the end of the day Maria counts once: "$347.50". The system expected $345.00. Over/short: +$2.50. One line in the report. One productivity view.
QIIUB has a BusinessDate field that is computed from the first sale of the shift (adjusted by the Location's BusinessDayEndTime). SAP/accounting reads BusinessDate, not OpenedAtUtc. Problem solved — the wall-clock time the shift opened no longer matters.
Not every business handles the cash drawer the same way. QIIUB supports 3 policies per terminal:
| Policy | How it works | Cash tracking | Typical industry |
|---|---|---|---|
| CarryDrawer | The cashier carries the cash drawer tray with them when they switch terminals. A single pool of cash. | At Shift level only | Supermarkets, retail, pharmacies, gas stations |
| FixedDrawer | The cash drawer stays fixed on the terminal. When the employee arrives or leaves, a handoff count is performed. | Per-segment snapshot (StartingCash / EndingCash) | High-volume chains, hardware stores, bars |
| NoDrawer | No physical cash drawer. The server carries their own cash, or the terminal is card-only. | None at terminal level. Server bank reconciled at close. | Restaurants (servers), kiosks, card-only terminals |
The policy is configured per terminal (TerminalSetting.CashDrawerPolicy) with a default per location. Same schema, different behavior depending on the business.
This is the most interesting part of the design. QIIUB's POS is offline-first: each terminal has its own local database and can operate without internet.
Merged (tombstone).The Connector translates each RMH batch into a QIIUB shift, but in a simple, 1:1 way:
| RMH | QIIUB (via Connector) | |
|---|---|---|
| 1 Batch | → | 1 Shift + 1 ShiftSegment |
| BatchStatus (bitmask) | → | ShiftStatus enum + IsBlindClose + IsExported |
| OpeningTime | → | OpenedAtUtc |
| CashierID | → | EmployeeId |
| RegisterID | → | CurrentTerminalId + ShiftSegment.TerminalId |
| (does not exist) | → | BusinessDate (computed from first sale) |
| (does not exist) | → | SourceSystem = ConnectorRMH, SourceId = "Batch#48" |
SourceSystem != NativeQIIUB).IsBlindClose, IsExported, Status.SourceSystem and SourceId always identify where the data came from.QIIUB supports 3 closeout patterns, configurable per location and terminal:
| Type | What happens | Who counts | Final status |
|---|---|---|---|
| Full Close | The cashier sees the expected amount, counts the cash drawer, enters the actual amount. | The cashier | Closed |
| Blind Close | The POS hides the expected amount. The cashier counts blind and enters their count. | The cashier (without seeing expected) | Closed + IsBlindClose |
| Deferred Count (Bargain City pattern) |
The cashier does NOT count at the terminal. The cash drawer goes straight to the safe. The manager counts later. | The manager (from the safe) | PendingCount → Closed |
If a shift stays in PendingCount longer than MaxPendingCountHours (default: 24h), the system raises an alert.
A shift can move through these states:
| State | Meaning | Allowed transitions |
|---|---|---|
| Open | Employee actively working, can ring sales | Suspended, PendingCount, Closed, Voided |
| Suspended | On break or lunch. Can resume on the same or a different terminal. | Open (resume) |
| PendingCount | Blind closeout — cash drawer in the safe, awaiting manager count | Closed (manager counts) |
| Closed | Fully reconciled, close amount entered | Final state — does not change |
| Merged | Absorbed by another shift during offline reconciliation (tombstone) | Final state — does not change |
| Voided | Cancelled by manager — only allowed if it has zero transactions | Final state — does not change |
RMH: the batch belongs to the terminal. 3 terminals = 3 batches = 3 counts.
Native QIIUB: the shift belongs to the employee. 3 terminals = 1 shift, 3 segments, 1 count.
RMH via Connector: each batch becomes 1 simple shift (read-only, no floating).
But they gain corrected BusinessDate, explicit fields, and unified reports.
Floating = once they migrate to the native QIIUB POS.
Companion: Technical diagrams (sales-floating-shifts-cash-management)