Expense Tracker
What it is
A log of operational costs that are not purchase orders — transport, port fees, customs, warehousing, bank charges and so on. Each expense can be linked to an invoice so the cost shows up against that job for profitability.
Who can open it
Needs the finance.payments feature grant while FEATURE_GRANULAR_RBAC is on; the owner
bypasses it. With the flag off, any signed-in account can reach it by URL.
Before you start
recorded_by is written as the literal string System User on every save. The logged-in account is
never captured, so there is no audit trail of who entered a cost. If you need to know who added
something, put a name in the description — nothing else records it.
The list is fetched unscoped and filtered in the browser. Every entity's expenses are loaded and then narrowed to the one selected in the header. Two consequences: with no entity selected you see everything, and the entity switcher changes what you see without re-querying.
There is no undo. The bin icon deletes the row after one confirm.
Amounts are never totalled, which is just as well — an expense carries its own currency and mixing them would need a rate this screen does not have.
Every control on the page
| Control | What it does |
|---|---|
| + Add Expense | Opens the entry dialog |
| 🗑 (per row) | Deletes that expense after "Delete this expense record?" |
The entry dialog:
| Field | Notes |
|---|---|
| DATE | Defaults to today |
| CATEGORY | Transport, Port Fees, Customs, Warehousing, Packing, Logistics, Bank Charges, Telecom, Office, Other. Fixed list — there is no way to add one |
| VENDOR / DESCRIPTION | Free text, e.g. "Courier charges for MV Pacific" |
| AMOUNT | Must be greater than zero |
| CURRENCY | USD, INR or AED only. Defaults to USD, and is not taken from the entity |
| LINK TO INVOICE (FOR PROFIT ANALYSIS) | Optional. The list is the 100 most recently created invoices — an older invoice cannot be chosen here |
| ASSOCIATED SUPPLIER | Optional |
| Cancel / Save |
The table — Date, Description, Category, Linked Job, Amount, and the delete control. No column is sortable; rows are newest expense date first. There is no search box, so a long list has to be read.
What it writes
One row in expenses, carrying the entity from the header switcher, recorded_by: 'System User',
and status: 'paid' — the status is never asked for and is always paid.
Deleting removes the row outright.
Nothing else changes. An expense does not touch an invoice, a supplier balance or the ledger; the link to an invoice is for reporting only.
When it goes wrong
"Valid amount and category are required." The amount is zero or blank.
The save fails with a database message. The commonest cause is no entity selected — entity_id
is taken straight from the header switcher and the column will not accept null.
An invoice you want to link is not in the list. Only the 100 most recent are offered. There is no search in that dropdown.
You see expenses from another company. Select an entity in the header — with none selected the screen shows every entity's rows.
You cannot tell who logged a cost. Expected — see the warning above.
Related screens
- Accounting — the Tally handover.
- Supplier Payments — money paid to vendors, recorded separately.
- Invoices — the job an expense can be linked to.