# Money in Drawer (Cash in Drawer KPI)

This document describes how the **Money in Drawer** / **Cash in Drawer** KPI is calculated in this project.

It is a **cash-movement** metric: only money that physically enters or leaves the drawer is counted. Unpaid invoice sales are **not** included (they are accounts receivable, not cash).

---

## API fields

Returned by:

- `GET /api/v1/analytics/kpi?timeRange=7d`
- `GET /api/v1/analytics/consolidated?timeRange=7d`

| Field | Description |
|---|---|
| `moneyInDrawer` | Final KPI amount for the selected period |
| `moneyInDrawerBreakdown` | Each inflow / outflow component (for UI debug / detail cards) |

Date range comes from the frontend (`timeRange`, or `from` / `to`).

---

## Formula

```text
CashInDrawer =
  paidBills
+ invoiceReceivablePayments
+ cashReceivablePayments
+ customerAdvanceIn
+ cashInWithoutAccount
+ directNetProfitAdjustments   // increase adds cash; decrease removes cash
− cashOuts
− payablePaymentsCash          // paymentMethod != "Advance"
− paidExpenses
− paidPayroll
− vendorAdvanceIn
```

Equivalent:

```text
moneyInDrawer = inflows − outflows
```

Where:

```text
inflows =
  paidBills
+ invoiceReceivablePayments
+ cashReceivablePayments
+ customerAdvanceIn
+ cashInWithoutAccount
+ max(directNetProfitAdjustments, 0)

outflows =
  cashOuts
+ payablePaymentsCash
+ paidExpenses
+ paidPayroll
+ vendorAdvanceIn
+ max(−directNetProfitAdjustments, 0)
```

`directNetProfitAdjustments` is already signed:

- `effect: "increase"` → positive amount (cash into drawer)
- `effect: "decrease"` → negative amount (cash out of drawer)

---

## Component details

### Inflows (money enters drawer)

| Component | Meaning | Source |
|---|---|---|
| `paidBills` | POS / bill sales that are paid | Bills in range with `status` in `paid` / `completed`, or `paymentStatus: paid` |
| `invoiceReceivablePayments` | Cash collected on invoice AR | `ReceivablePayment` on records with `receivableType != "cash"` |
| `cashReceivablePayments` | Cash collected on manual cash AR | `ReceivablePayment` on records with `receivableType: "cash"` |
| `customerAdvanceIn` | Customer prepaid money | `AdvancePayment` where `entityType: "customer"` and `paymentType: "in"` |
| `cashInWithoutAccount` | General cash-in (not linked to an account) | `CashIn` where `accountId` is null / missing |
| `directNetProfitAdjustments` | Direct profit entries that go to the drawer | Active `NetProfitEntry` in range (`increase` adds, `decrease` subtracts) |

### Outflows (money leaves drawer)

| Component | Meaning | Source |
|---|---|---|
| `cashOuts` | Cash taken out | All `CashOut` in range |
| `payablePaymentsCash` | Paying vendors with cash | `PayablePayment` where `paymentMethod != "Advance"` |
| `paidExpenses` | Paid expenses | Expenses with `status: "paid"` in range |
| `paidPayroll` | Paid payroll | Payroll with `status: "paid"` in range |
| `vendorAdvanceIn` | Cash given to vendor as advance balance | `AdvancePayment` where `entityType: "vendor"` and `paymentType: "in"` |

---

## What is intentionally excluded

| Event | Why excluded |
|---|---|
| Unpaid invoice totals | Sale creates AR only; cash is not in drawer yet |
| Cash receivable principal when created | Manual AR balance only; cash arrives on payment |
| Cash-in linked to an account (`accountId` set) | Account-linked cash-in must not change drawer |
| Payable paid with `paymentMethod: "Advance"` / `paymentSource: "advance"` | Uses vendor advance balance; cash already left when advance was funded |
| Customer advance `out` (applied to invoice) | Cash was already counted when advance was received |
| Product cost / COGS | Inventory cost, not drawer cash |

---

## Relation to other KPIs

| KPI | What it measures |
|---|---|
| **Total Revenue** | Sales performance (paid bills + invoices), including unpaid invoices |
| **Net Profit** | Gross profit − expenses/payroll ± direct net profit |
| **Accounts Receivable** | Invoice outstanding + cash outstanding |
| **Money in Drawer** | Physical cash movement only |

Rules:

- **Invoice receivables** affect revenue / net profit and AR.
- **Cash receivables** affect AR and drawer (on payment only), **not** revenue / net profit.
- **Direct profit** affects net profit **and** money in drawer (cash is assumed to enter/leave the drawer when the entry is created).

---

## Example

Period: one day

| Event | Amount | Drawer impact |
|---|---|---|
| Paid bill | +500 | +500 |
| Invoice created (unpaid) | 1000 | 0 |
| Invoice payment received | +200 | +200 |
| Cash receivable payment | +50 | +50 |
| Customer advance in | +100 | +100 |
| Direct profit increase | +80 | +80 |
| Cash-out | −30 | −30 |
| Payable paid with cash | −120 | −120 |
| Payable paid from advance | −90 | 0 |
| Paid expense | −40 | −40 |
| Paid payroll | −60 | −60 |
| Vendor advance in | −25 | −25 |

```text
moneyInDrawer =
  500 + 200 + 50 + 100 + 80
  − 30 − 120 − 40 − 60 − 25
  = 655
```

---

## Frontend usage

Read:

```js
const moneyInDrawer = data.cards?.moneyInDrawer ?? data.moneyInDrawer ?? 0;
const breakdown = data.cards?.moneyInDrawerBreakdown ?? data.moneyInDrawerBreakdown;
```

Show `moneyInDrawer` on the KPI card. Optionally show `moneyInDrawerBreakdown` in a detail popover.

---

## Implementation location

- Formula: `src/modules/analytics/analytics.controller.js` → `collectRangeMetrics`
- Direct profit model: `src/modules/net-profit-entries/`
- Invoice payments are stored as `ReceivablePayment` so collections are counted correctly
