Feature

DailyCash

What came in today, what left, and what should still be in the drawer tomorrow morning.

The idea

Sales are never typed in. They’re reconstructed from what the drawer did — because counting cash is something you can actually do at the end of a long day, and remembering every sale is not.

app/lib/core/cash/computations.dart
/// Reconstructed sales: net drawer + other channels + add-backs − coin refill
/// − receivables collected.
///
/// Only DRAWER-funded outflows are added back — carried-cash and GCash
/// portions never touched the drawer, so they don't belong here. The EOD
/// claim is NOT added back (it happens after the day's sales are already
/// counted), and collected receivables are removed (they were already counted
/// as sales on the day the utang was given).
double get totalSales =>
    netDrawer +
    gcashSales +
    receivablesGiven +
    dayExpenses +
    salariesPaid +
    advancesFromDrawer +
    commissionsFromDrawer -
    …

Everything that makes this hard is in that comment. Money leaves the shop through several doors, and only some of them are the drawer. An expense paid from a carried stash, or a commission settled by GCash, must not be added back — it was never in the drawer to begin with.

Where the formulas actually live

In the daily_cash_report view. computations.dart is a deliberate pure-Dart mirror of it, so the arithmetic can be unit-tested without a database — and so a disagreement between the two shows up as a failing test rather than a wrong number on a report.

The coins-only float

One subtlety worth the space, because it took a Sheets formula to explain: what stays in the drawer overnight is coins only.

The day’s expected bills are set aside into a separate to-claim stash the moment the day closes, so the full expected cash leaves the drawer — not just the part that’s been collected. Since the next day’s opening total is seeded from this float, keeping only the coins is what stops unclaimed bills from carrying forward and being counted twice in tomorrow’s expected cash.

What gets recorded

PageRecords
Daily closeThe end-of-day count: bills, coins, GCash sales, what was claimed, coin refill. The rest is derived.
ExpensesWhat was spent, and — importantly — which pocket it came from: the drawer, a carried stash, GCash, a personal card.
ReceivablesUtang given and utang collected. Given counts as a sale that day; collected doesn't count again.
ReimbursementsMoney owed back for things bought on a personal card.
Expected billsBills owed but not yet paid, and the claim against them.
SalariesPaid, and from where.
AdvancesCash advanced to staff, and the settlements that pay it down.
CommissionsEarned and settled.
StaffWho's active, and who a record belongs to.

Reports

ReportShows
MonthlyA row per day for the month, with the day's report one tap away.
DailyOne day in full. Not a menu entry — it's the drill-down from a Monthly row.
IncomeCash-basis income over a period.
CommissionPer staff member: expected sales against actual, and what that earns.
GCashThe GCash ledger and its running balance.

How commission works

Commission is 5% of total sales less salary and settlements. Against that sits any shortfall — cash that should have been there and wasn’t:

app/lib/features/cash/reports/commission_report.dart
final double commission; // 5% of (total sales - salary/settlements)
final double loss;       // max(0, expected - total) — missing cash

double get diff => totalSales - expectedSales;
double get total => commission - loss;

The Loss column shows diff signed: negative and red is money missing, positive and green is a surplus. The Total column subtracts the separate loss value, which is the shortfall floored at zero — a good day doesn’t inflate commission, but a bad one does reduce it.