Expense claims.
A teacher buys markers for the lab. A bursar pays a courier out of pocket. A coach fronts the bus fare for a fixture. That money belongs to the school, and the person who spent it should get it back cleanly — with a receipt, an approver's signature, and a trail anyone can audit. YESS expense claims are exactly that: a one-line reimbursement request the staff member submits, an inbox where an approver decides, and — on the finance route — a pending expense that drops straight into the school's ledger workflow. This handbook is precise about what runs end to end today and what the schema has reserved for later.
- 2reimburse routes
- 1approval step
- 6chapters
- ≈9 minto read
Prologue
A claim is a single, honest row#
Before we open a screen, one thing to set straight, because YESS is deliberately modest here. An expense claim is not a multi-page expense report with a dozen line items and a mileage calculator. It is a single flat record: one title, one amount, one date, one receipt link, and a choice of how the staff member wants the money back. That is the whole shape of it — and for the most common reimbursement a school ever processes, that is all it needs to be.
The claims desk lives at /dashboard/expense-claims. It is separate from the school's outgoing expenses ledger (bills to suppliers, diesel, rent — covered in the finance handbook). Expenses are money the school decides to spend; claims are money a staff member already spent and wants back. The two meet at exactly one point — approving a claim on the finance route files an expense — and this book walks you right up to that seam and tells you honestly where the automation stops.
Money spent for the school, claimed back with a receipt and a signature — nothing more complicated than it has to be.
Chapter one
Submitting a claim#
Any staff member can submit a claim — there is no special permission to file one; the platform simply needs to resolve who you are as a staff record. Open /dashboard/expense-claims, click New expense claim, and fill in a short form:
The six fields on a claim
- 1
What it was for
A required title — 'Markers for the chemistry lab', 'Courier to the exam board'. This is the one-line description the approver reads first.
- 2
Amount
A required positive number — the database enforces amount greater than zero, so a zero or negative claim is rejected before it is saved. The claim carries a currency (the school's default, XAF unless configured otherwise).
- 3
Date
The date the money was spent, defaulting to today. It becomes the expense date if the claim is routed to finance.
- 4
Reimburse via
The staff member's choice of how they want the money back — Finance reimbursement (the school pays it directly) or Add to my next payslip (the payroll route). Chapter three is honest about what each actually does today.
- 5
Details
An optional free-text note for anything the title cannot hold — who it was paid to, why it was urgent, what the receipt covers.
- 6
Receipt link
An optional URL pointing at the receipt. Today this is a plain link field, not a file-upload widget — paste a link to the receipt stored in your drive or a messaging thread.
Submit, and the claim is created with status submitted — the queue every approver works from. YESS stamps the claimant from your own session (a trigger fills in the staff id and the creator, so a claim can never be filed in someone else's name), records the action in the finance audit log, and the claim appears at the top of your My claims tab.
Chapter two
The approver's inbox#
A second tab, Approval inbox, appears only for staff who can approve — anyone holding finance_expenses.approve or finance_payroll.approve (a principal, an accountant, an HR manager, a school admin). Everyone else sees only their own claims. The inbox lists every submitted claim in the school, oldest first, each card showing the claimant's name and staff id alongside the title, amount, date, and chosen route.
Two buttons per claim: Approve and Reject. Both call a single database function, decide_expense_claim, which does the careful work server-side: it confirms the approver belongs to the claim's school, re-checks that they actually hold one of the two approve permissions (so the guard lives in the database, not just in the hidden UI), and refuses a claim that has already been decided. A reject stamps the claim rejected with the approver and a timestamp; an approve stamps it approved and, on the finance route, fires the ledger step in chapter three.
Chapter three
Where an approved claim goes#
This is the chapter to read slowly, because the two routes behave very differently — and the difference is easy to over-promise.
The finance route
Approving a claim marked Finance reimbursement does real work. YESS ensures a "Staff Reimbursements" expense category exists for the school (creating it the first time), then files a row in the school's /dashboard/expenses ledger with the claim's amount, date, and description — and links that expense back to the claim. Critically, the expense is filed with status pending approval, not paid. It joins the ordinary expense queue, where the finance manager approves it like any other bill; only that approval posts the double-entry journal.
So the claim's own approval is the first of two gates. The finance manager still opens the expenses queue and approves the reimbursement expense before any cash movement or ledger entry happens. And one setup caveat: the auto-created "Staff Reimbursements" category ships without a chart-of-accounts code, so the very first time you use this route, link that category to a GL account at /dashboard/expenses/categories — otherwise the ledger posting is skipped even after the expense is approved. Do it once and every future reimbursement posts cleanly to /dashboard/accounting/journal.
The payroll route
Approving a claim marked Add to my next payslip records the decision and marks the claim approved — and, today, that is where it stops. The claim carries a payroll-run link in its schema, but no payroll code reads pending claims to fold them into a run yet. Treat the payroll route as an intent flag the approver honours by hand — add the amount to the staff member's next payslip in /dashboard/payroll yourself — not as an automatic payslip line. The full payroll integration is on the roadmap.
Chapter four
Who sees what#
Visibility is enforced at the database row level, not by hiding a button. A claim is readable by three kinds of person and no one else:
- The claimant — a staff member always sees their own claims, and only their own, on the My claims tab.
- Finance and payroll viewers — anyone with
finance_expenses.vieworfinance_payroll.viewsees every claim in the school, which is what powers the approval inbox. - Nobody across school lines — every policy is scoped to the school, so a claim never leaks to another tenant.
Editing follows the same discipline: a staff member can only touch their own claim while it is still a draft or submitted, and can only delete a draft. Once a claim is approved or rejected it is settled — the decision path runs through the secure function, which is the only way a claim's status ever changes.
Chapter five
What this module does well#
Five things done right
- 1
A claimant you can trust
A trigger stamps the staff id and creator from the logged-in session, so a claim can never be filed in another person's name. The claimant on the record is always the person who submitted it.
- 2
Approval enforced twice
The approve/reject function checks the school and the permission inside the database itself, on top of the UI only showing the inbox to approvers. A view-only user cannot decide a claim even if they reach the call.
- 3
Decisions that cannot double-fire
The decide function refuses any claim not currently awaiting a verdict, so an approve and a stray second click can never both land — a claim is decided exactly once.
- 4
A real bridge to the ledger
On the finance route, approval files a pending-approval expense in the expense ledger workflow under a dedicated 'Staff Reimbursements' category, linked back to the claim — the reimbursement enters the same accounting spine as every other outgoing.
- 5
Audited end to end
Both submitting and deciding a claim write to the finance audit log against the claims table, so who filed what and who approved it is always reconstructable.
Planned & honest gaps
What is still to come#
The request-and-approve core is solid and wired. The edges — the payroll leg, the final "paid" state, richer claims — are honestly thin, and the tagline's promise of a reimbursement that "lands in the ledger" is a two-gate, one-time-setup story rather than a single click. Here is the straight picture.
Six honest gaps
- 1
The payroll route is a flag
Choosing 'Add to my next payslip' records the intent but nothing folds the claim into a payroll run automatically; the payroll-run link on the claim is never populated by code yet. Auto-adding an approved claim as a payslip line is planned.
- 2
No 'paid' close-out
The claim lifecycle stops at 'approved'. Marking a reimbursement actually paid — and reflecting that back on the claim — is done on the expenses or payroll side today; a claim-level 'reimbursed' state is planned.
- 3
GL code needs a one-time setup
The auto-created 'Staff Reimbursements' category ships without a chart-of-accounts code, so the first reimbursement will not post to the journal until an admin links it. Shipping that category pre-linked is planned.
- 4
One line, no attachments
A claim is a single amount with a receipt URL — no multi-item claims, no file upload, no mileage or per-diem calculators, no policy limits. Richer claim shapes are on the roadmap.
- 5
Approver notes & route override
The decide function accepts a decision note and a route override, but the approve/reject buttons send neither today. Surfacing a notes box and a route toggle at decision time is planned.
- 6
No notification on decision
Submitting and deciding are audit-logged but do not yet notify the claimant that their claim was approved or rejected. Wiring the decision into the notifications fabric is planned.
Adjacent modules
Where claims connect#
Claims sit between the person who spent the money and the ledger that accounts for it. They lean on finance for the expense and the posting, and — on the roadmap — on payroll for the payslip line.
Adjacent modules
- 20Finance, fees & accountingApproving a finance-route claim files a pending expense under 'Staff Reimbursements'; approving that expense posts the double-entry journal.
- 21Budgets & procurementReimbursement expenses land in the same expense ledger a budget line tracks, so a claim counts against the department's budget.
- 19Payroll & taxThe 'Add to my next payslip' route is designed to fold an approved claim into a payroll run — the planned payroll integration.
- 18HR & recruitmentA claim is filed against a staff record; who can approve is a matter of the HR permission grants a role carries.
- 17NotificationsDecision notices to the claimant are the planned link into the notifications fabric — approved, rejected, and reimbursed alerts.
Tutorial
Do it step by step#
Get money back for something you bought for the school — from the receipt in your pocket to the expense in the ledger. Five steps, split between the claimant and the approver.
- 1
File the claim
As the staff member who spent the money, open /dashboard/expense-claims, click New expense claim, and enter what it was for, the amount, the date, how you want it back (finance or payslip), and a link to the receipt. Submit — it lands in the approver's inbox as submitted.Anyone can file a claim — there's no special permission. The claimant is stamped from your session, so you can only ever file in your own name.
- 2
Approve or reject
As an approver (holdingfinance_expenses.approveorfinance_payroll.approve), open the Approval inbox tab, read the claim, and choose Approve or Reject. The decision is stamped with your name and the time, and a claim can only be decided once. - 3
Let the finance route file the expense
An approved Finance reimbursement claim files a pending-approval expense under a 'Staff Reimbursements' category, linked back to the claim, in /dashboard/expenses.The first time you use this route, link the 'Staff Reimbursements' category to a GL account at /dashboard/expenses/categories, or the ledger posting is skipped.
- 4
Approve the expense to post the ledger
The finance manager approves that reimbursement expense in the normal expenses queue — the second gate — which posts the balanced journal entry to /dashboard/accounting/journal. For the payroll route, add the amount to the next run in /dashboard/payroll by hand for now. - 5
Confirm it on the claim
Back on /dashboard/expense-claims, the claimant sees the claim marked approved and its value counted in their KPI strip. The actual "paid" close-out lives on the expenses or payroll side today.
Money spent for the school, claimed in a line, decided by a name, and carried into the ledger — reimbursement with a paper trail.