Who can use this: Owner, Manager, Accountant. URL / Route:
/finance/ap/expenses(finance.ap.expenses.index). Detail:finance.ap.expenses.show,edit,update,create,store,destroy. Action endpoints:finance.ap.expenses.post,unpost,reverse,scan-and-prefill,payments.create,payments.store. Bulk:finance.ap.expenses.bulk.index,bulk.template,bulk.parse,bulk.preview,bulk.store. OCR helper:finance.ocr.*(under/finance/ocr). Plan / feature gate:feature:tracker.expenses_direct_pay(default: enabled). OCR scan path also requiresfeature:receipt_scan_enabled(default: enabled). Permissions:purchases.expenses.view,purchases.expenses.create,purchases.expenses.edit_draft,purchases.expenses.delete,purchases.expenses.post,purchases.expenses.reverse. OCR scan/apply useocr.scanandocr.apply.
Purpose
An Expense (also called Direct Pay) is the one-step alternative to Bill + Bill Payment. It records that money has already left a bank or card account and pays for something the same day — taxis, fuel, office supplies, software subscriptions paid by card, anything where you don't track an unpaid balance with a supplier. The expense posts both sides of the journal in one document.
Use a Bill instead if you have an unpaid invoice from the supplier that you need to track, age, and pay later.
Step by step
Browse expenses
- Open
/finance/ap/expenses. Each row shows date, supplier (optional), bank/card account, total, status (Draft / Posted / Reversed), and tags. - Filter by date range, account, supplier, or status.
Create an expense
Route: finance.ap.expenses.create / store. Permission: purchases.expenses.create.
- Click New expense.
- Pick the Bank or Card account that paid for it.
- Optionally pick a Supplier (helps for the Purchases by Supplier report).
- Enter Expense date, Reference, Method (Card / Cash / Bank).
- Add line items: Account / Item, Description, Quantity, Unit price, Tax.
- Optionally tag lines with Dimensions.
- Upload the receipt PDF or photo as an attachment.
- Save as Draft or Save and Post.
Bulk create / import expenses
Route: finance.ap.expenses.bulk.index (page), bulk.template, bulk.parse, bulk.preview, bulk.store. Permission: purchases.expenses.create.
When you have many expenses to enter at once, use Bulk Expenses — open it from the caret next to New expense, or go to /finance/ap/expenses/bulk. Bulk is an input shortcut only: every expense it creates is an ordinary expense, saved through the same rules as one typed on the normal form. There is no special "bulk" record type and no accounting shortcut.
The page has two ways to enter data:
- Manual entry — fill in one card per expense (date, supplier, currency, expense account, description, amount, tax). Add as many cards as you need.
- File import — download a per-document CSV or XLSX template, fill it in, and upload it. One row becomes one single-line expense. The XLSX template has drop-downs on the supplier, currency, expense account, tax code, and pay-from columns so you pick valid values instead of typing them; the tax drop-down shows the code, name, and rate together. A panel of searchable reference lists (accounts, taxes, suppliers) is shown on the import tab, each value with a copy button.
After entering or uploading, click Validate to preview every expense — totals, per-line tax, and any blocking errors are shown before anything is saved. Fix the highlighted rows, then Save as draft or Save and post. The whole batch saves in one transaction: if any document fails, nothing is saved.
To record payment at the same time, turn on Record payment & mark paid and give each expense a Pay-from account (in a file, fill the pay_from_account column). An expense with a pay-from account is created posted and paid; one without it is created as a normal draft.
Scan a receipt (OCR)
Route: finance.ap.expenses.scan-and-prefill, also reachable via the global OCR flow at /finance/ocr (finance.ocr.*). Requires feature:receipt_scan_enabled and ocr.scan permission. Applying the result needs ocr.apply.
- Click Scan receipt on the expense create page.
- Upload a photo or PDF of the receipt.
- The OCR service reads vendor name, date, total, tax, and (where possible) line items.
- Review the prefilled form. Adjust accounts and tax codes as needed.
- Save.
Scan vs attach — automatic based on form state. The scan panel shows a small info note explaining the behaviour:
- If the form is empty, the upload is scanned and the fields are auto-filled.
- If you have already entered any data (supplier, bill no., reference, notes, or any line), the upload is only attached as a file — it is not scanned, so your data is kept. No scan credit is consumed.
This means it's always safe to upload a receipt: it will never overwrite values you typed.
Line-item matching. Where the OCR returns a line description, the system fuzzy-matches it against your inventory:
- If a close match is found (exact name, contains, or small edit-distance — handles single-character OCR misreads like
office-agent-0d→office-agent-08), the line is created as an Item line with the inventory item, account, unit, and price wired automatically. - If no match is found, the line falls back to an Account line with a default expense account so the bill/expense is immediately saveable. You can change the account afterwards.
Tax codes are not extracted from receipts (the engine returns the tax amount, not a code) — pick the right tax code per line manually.
The receipt scan can be triggered against a Bill or an Expense; it picks the appropriate document type from the merchant pattern but you can override.
Edit a draft
Route: finance.ap.expenses.edit / update. Permission: purchases.expenses.edit_draft.
Drafts are freely editable. A posted expense is read-only — to change it, Unpost it first, edit the draft, then post again.
Post an expense
Route: finance.ap.expenses.post. Permission: purchases.expenses.post.
Posting writes:
- Debit the expense / inventory accounts on each line.
- Credit the bank / card account.
- Debit Tax — Recoverable for any recoverable tax.
The journal is balanced in one document, so there is no "Pay" step afterwards.
Unpost
Route: finance.ap.expenses.unpost. Permission: purchases.expenses.reverse.
Returns a posted expense to Draft so you can correct and re-post it. Unposting voids the expense's journal entry — the entry is kept for the audit trail but is marked void and excluded from reports — rather than posting a separate reversal. Unpost is blocked when the period is locked.
Reverse a posted expense
Route: finance.ap.expenses.reverse. Permission: purchases.expenses.reverse.
Posts a reversing journal on the reversal date. Use when a charge is refunded or a wrong card was used — i.e. when you want the correction dated later, not the original entry removed. Blocked if the original date's period is locked.
Delete a draft
Route: finance.ap.expenses.destroy. Permission: purchases.expenses.delete. Allowed only when status is Draft.
Print a PDF
Route: finance.ap.expenses.pdf. Permission: purchases.expenses.view.
Record a payment against an expense
Routes: finance.ap.expenses.payments.create / payments.store. Permission: purchases.expenses.create.
This is for the case where an expense was originally entered as Draft against an "Owe Director" or "Owe Employee" account; the Record payment action lets you pay that off later. For straightforward card/bank expenses you do not use this.
How the journal looks
A JOD 50 fuel expense paid by card (zero-rated):
| Account | Debit | Credit |
|---|---|---|
| Vehicle — Fuel | 50.00 | |
| Bank — Card | 50.00 |
A JOD 117 office-supplies expense, 17% VAT recoverable, paid by card:
| Account | Debit | Credit |
|---|---|---|
| Office supplies | 100.00 | |
| VAT Input (Recoverable) | 17.00 | |
| Bank — Card | 117.00 |
A JOD 117 customs-broker fee with 17% VAT, only 50% recoverable:
| Account | Debit | Credit |
|---|---|---|
| Broker fees | 100.00 | |
| VAT Input (Recoverable) | 8.50 | |
| Broker fees (non-recoverable VAT) | 8.50 | |
| Bank — Card | 117.00 |
The non-recoverable portion is added back to the expense account, so the full JOD 117 actually hits P&L (split across the line and the gross-up).
A stocked-item purchase entered as an expense (JOD 60 of inventory, JOD 10.20 of VAT, paid cash):
| Account | Debit | Credit |
|---|---|---|
| Inventory | 60.00 | |
| VAT Input (Recoverable) | 10.20 | |
| Cash on hand | 70.20 |
Recurring expenses
⚠️ Risk: feature key
tracker.recurring_expensesis declared infinance_features.phpbut thefeature:tracker.recurring_*middleware on/recurring/templateschecks all four recurring keys at once — if any is missing, the page is blocked.
When feature:tracker.recurring_expenses is on you can convert any expense into a Recurring Template (More actions ▸ Make recurring), or open /finance/recurring/templates. Useful for monthly subscriptions paid by card.
When to use which AP document
| Situation | Use this |
|---|---|
| Paid by card / cash on the spot, no AP balance owed | Expense (this page) |
| Supplier sent an invoice you'll pay later | Bill |
| Staff drove their personal car for business | Mileage |
| Same expense every month (subscriptions, rent) | Recurring template of an expense |
| Need to spread freight / duty into inventory cost | Landed cost |
| Imported a stocked item with a card | Expense is fine — Inventory line works the same way as on a Bill |
Common mistakes
- "OCR didn't fill the form." OCR only runs when the form is empty. If you've already typed anything (supplier, reference, line), the upload is just attached. Click Clear form first if you want it to scan.
- Wrong card account → wrong cash-out posting. The bank/card account picked on the expense is what gets credited. If you accidentally posted to the wrong card, Unpost, change the account, re-post.
- VAT not reducing what you owe to the tax authority. Check the tax code — non-recoverable VAT is added back into the expense line, not the recoverable VAT account. See Taxes & VAT.
- Project cost not appearing on profitability. Each line must be tagged to the project (Dimension column). Untagged lines stay in general overhead — see Project profitability.
- "Period locked" → posting, unposting, and reversing all need an open period. Use Reverse (with a later date in an open period) to correct a posted expense whose original period is closed.
Tips
- Drag and drop a receipt PDF or photo onto the New expense page to trigger OCR — no need to open the upload dialog.
- For monthly card subscriptions (SaaS, hosting, mobile bill), create a recurring template once.
- Use the Bulk Expenses flow at
/finance/ap/expenses/bulkwhen entering many card transactions from a statement.
Behaviour and rules
- An expense is single-step — posting writes both sides of the journal in one document. There is no separate Payment.
- The bank/card account on the expense becomes the cash-out account in the journal.
- Tax recoverability behaves the same as on a Bill: the Tax — Recoverable line is split based on the tax code.
- Period lock: posting, unposting, and reversing all require an open period.
- Unposting voids the journal. It does not post a reversal — the original entry is kept (marked void) for audit and dropped from reports.
- Inventory lines on an expense post to Inventory and COGS exactly as on a Bill — Stocked items can be entered through expenses, but it is unusual.
- Bulk create/import always produces ordinary expense records — see Bulk create / import expenses above.
Permissions / restrictions
- View:
purchases.expenses.view. - Create / edit drafts:
purchases.expenses.create,purchases.expenses.edit_draft. - Bulk create / import:
purchases.expenses.create. - Post:
purchases.expenses.post. - Unpost / Reverse:
purchases.expenses.reverse. - Delete (drafts only):
purchases.expenses.delete. - OCR scan/apply:
ocr.scan,ocr.apply(plusfeature:receipt_scan_enabled).
Related
- Bills — for unpaid supplier obligations (the alternative to Expense).
- Mileage — per-km reimbursement instead of fuel receipts.
- Suppliers — supplier profile shows every expense booked against them.
- Recurring transactions — auto-create card-subscription expenses.
- Projects & Finance — tag project costs from an expense line.
- Banking — match card-account expenses against the imported card statement.
- Taxes & VAT — recoverable / non-recoverable VAT handling.
- Settings — sequences, OCR, mileage rate.
- Reports — Expenses by Category, Purchases by Supplier.
- Fiscal years and lock dates.