End-of-day balancing
End-of-day (EOD) is the discipline of declaring physical cash, comparing it to system cash, and accounting for every cent of difference before anyone goes home. The EOD wizard runs both at the till level (per teller) and at the branch level (manager sign-off).

Two levels of EOD
There is a per-till EOD and a branch-level EOD; they run in sequence.
- **Till EOD** — each teller runs this for their own till session. Declares denomination breakdown, reconciles, handles variance, returns cash to vault.
- **Branch EOD** — branch manager runs this once every till session is closed. Counts vault, validates checks, posts cut-off journal, signs off.
Till EOD step-by-step
- **Counter close** — teller stops accepting new customers, completes any in-progress transaction.
- **Open wizard** — from till session form, click End of Day.
- **Sweep excess** — if till balance exceeds the expected return-to-vault amount (often equal to opening float), system suggests a sweep first.
- **Declare denomination** — teller counts cash drawer, enters bill and coin counts. System computes declared total live.
- **Reconcile** — system compares declared total to expected (= opening float + cash-ins − cash-outs).
- **Zero variance path** — teller confirms, supervisor counter-signs, cash returned to vault, session moves to closed_clean.
- **Non-zero variance path** — system raises a draft incident, teller and supervisor recount, if confirmed the incident is opened formally and the session moves to closed_with_variance once accepted at the correct authoriser cap.
- **Final journal** — system posts: Dr Vault Cash / Cr Till Cash for the declared returning balance, and Dr/Cr the variance to overage income / shortage expense as appropriate.
Branch EOD step-by-step
- Wait for all tellers to close (system shows progress: 'Till sessions closed: 3/3').
- Run vault count with the second key-holder.
- Open Branch EOD wizard from branch session.
- Wizard runs the seven validation checks listed on the Branch Session page.
- Resolve any blocks (open incidents, overnight max breach).
- Approve any documented overrides.
- Sign off — the cut-off journal posts and the branch session moves to closed_clean or closed_with_override.
Variance handling
Variance is the difference between declared cash and expected cash. Convention: positive variance = overage (more cash than expected), negative variance = shortage. The system treats both identically — both require an incident.
| Variance band | Required action | Authoriser |
|---|---|---|
| KES 0 | Confirm clean, close | Teller |
| KES 1 – 50 | Auto-close incident with reason 'rounding/counting' if policy allows | Teller (auto) |
| KES 51 – 5,000 | Open incident, document cause, accept | Supervisor |
| KES 5,001 – 50,000 | Open incident, document cause, possibly recovery from teller, accept | Branch manager |
| KES 50,001 – 250,000 | Open level-2 incident, investigation, possibly suspend teller | Regional manager |
| > KES 250,000 | Open level-3 incident, treasury escalation, police if theft suspected | Head of treasury / CFO |
Denomination mismatch (with zero net variance)
Sometimes the total matches but the denomination breakdown does not — the till expected 30 × KES 1,000 but actually has 28 × 1,000 + 4 × 500. This is normally fine (customers used different denominations) but the system logs it. Persistent denomination drift can indicate either a poorly stocked branch (running out of small notes) or — less commonly — a switch attempt.
Accounting effect
Per till EOD, the journals posted are:
Per branch EOD, the cut-off journal locks the day. No further postings to today's cash accounts at this branch without a formal reopen.
| Step | Dr | Cr |
|---|---|---|
| Cash return to vault | Vault cash GL | Till cash GL |
| Shortage accepted (variance < 0) | Cash shortage expense | Till cash GL (residual) |
| Overage accepted (variance > 0) | Till cash GL (residual) | Cash overage income |
| Shortage recovered from teller | Receivable from teller | Cash shortage expense (reversal) |
Best-practice timings
Most institutions target:
- Counter close: 17:00 sharp (or branch-defined)
- All till EODs complete: by 17:30
- Branch EOD signed off: by 17:45
- All branches reporting closed to treasury dashboard: by 18:00
Worked scenarios
Scenario — Recovering a KES 12,000 shortage
| Character | Role |
|---|---|
| Kimani Mwangi | Senior teller |
| Florence Achieng | Branch manager |
| Peter Otieno | Supervisor (recount) |
| Aisha Hassan | HR |
Timeline
- Day 1, 17:05: Kimani's till declared count is KES 12,000 below expected. He recounts twice. Variance confirmed. (Till EOD wizard variance −12,000)
- Day 1, 17:15: Peter joins the recount. Confirms KES 12,000 shortage. Drawer denomination shows missing 12 × KES 1,000 notes. (Recount confirmed)
- Day 1, 17:25: Florence reviews the transaction log. Identifies a KES 12,000 withdrawal at 14:42 that may have been overpaid (member only signed for KES 12,000 but possibly received KES 24,000). (Suspected over-payment to member)
- Day 1, 17:30: Florence calls the member, asks her to recount what she received. She confirms she got KES 24,000 — a stack of 12 with 12 wrapped inside. (Cause confirmed)
- Day 1, 17:40: Florence asks member to return KES 12,000 next morning. Member agrees. Incident opened with cause 'teller error — overpayment'. (Incident INC/2026/0412)
- Day 1, 17:45: Florence accepts the variance at branch-manager cap for tonight. Till closes with variance. Cut-off proceeds. (Till session closed_with_variance)
- Day 2, 09:30: Member returns with KES 12,000. Florence receipts as 'shortage recovery'. Incident closed with note 'recovered next day'. (Receivable reversed; expense net zero)
- Day 5: Kimani is required to attend cash-counting refresher per HR retraining policy after 1 overpayment in quarter. (Training record updated)
Outcome — Shortage recovered next day; no net loss; teller retrained; incident closed clean.
Reference
Till EOD wizard fields
| Field | Type | Notes |
|---|---|---|
| expected_closing_balance | Monetary, computed | Opening + ins − outs |
| declared_denomination_lines | O2M | Per denomination count + value |
| declared_total | Monetary, computed | Sum of declared lines |
| variance | Monetary, computed | declared − expected |
| variance_reason | Selection | counting / overpayment / theft / unknown / other |
| variance_notes | Text | Free narrative |
| supervisor_id | M2O res.users | Counter-signer |
| recovery_expected | Boolean | True if cause is likely recoverable |
| incident_id | M2O mfi.cash.incident | Auto-populated if variance > 0 |
Variance reason codes
| Code | Meaning | Default authoriser |
|---|---|---|
| counting | Teller counted wrong | Supervisor |
| overpayment | Customer received more than signed for | Branch manager |
| underpayment | Customer received less than signed for | Branch manager |
| denomination_swap | Wrong denomination given/received | Supervisor |
| theft_suspected | Apparent theft | Regional manager + police |
| fraud_suspected | Apparent internal fraud | Head of treasury + audit |
| system_error | Posting/reversal not reflected in cash | Branch manager + ICT |
| unknown | Cause not identified | Branch manager |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| EOD wizard says variance even though I counted three times | Recent void or reversal did not flow into cash leg | Run Till Movement Report. Look for a reversal that posted to GL but not to till cash. Branch manager re-posts a manual cash leg with reason. |
| EOD wizard won't accept zero in declared coins box | Coin denomination required-field policy | Tick the 'No coins handled' checkbox at the top of the denomination editor — system bypasses coin fields. |
| Cannot accept variance — 'authoriser cap exceeded' | Variance is above current role's cap | Escalate to next role per the cap table. The system pages them automatically; they sign off remotely. |
| Branch EOD wizard hangs on 'all till sessions closed' | One till session in zombie state (closed but not finalised) | Branch manager opens the orphan till session, runs its EOD wizard fresh, then branch EOD proceeds. |
| Cut-off journal posted but Treasury dashboard still shows branch as open | Dashboard cache lag or webhook miss | Treasury → Refresh, or wait one minute. If persistent, check the dashboard refresh cron and the websocket health. |

