Bad Debt / Write-Offs is where ERP discipline either begins or breaks.
Write Off an Uncollectible Invoice as Bad Debt looks operational from far away. In a real finance team, it is a chain of assertions: the right actor started the work, the required records existed, the control policy was applied, the state change was preserved, and the outcome can be explained later without rebuilding the transaction from emails and spreadsheets.
The expected business outcome is specific: Uncollectible amounts are properly expensed; AR aging is not inflated by dead receivables; bad debt expense is tracked for management and tax purposes.
The control flow a finance team actually needs.
Step 1
Write-Off Require Approval Workflow...
Step 2
Reason Code Be Selected From A...
Step 3
Write-Off Create A GL Entry Reversing...
Step 4
Written-Off Invoices Be Excluded From...
Step 5
Recovery Be Supported
The ERP surface involved.
Module
Bad Debt / Write-Offs
Actors
AR Manager, CFO (approver), Accounting System
Tier
Tier 1
Finance area
Accounts Receivable & Order-to-Cash
Region lens
US and UK finance teams
Publication date
March 22, 2026
Write-off must require approval workflow above configurable amount threshold; reason code must be selected from a configurable list; write-off must create a GL entry reversing the AR balance without modifying original invoice lines; written-off invoices must be excluded from aging but reportable in a bad debt report; recovery must be supported (reopen invoice and apply payment); partial write-off must leave invoice partially open; write-off reversal must be auditable; non-functional: approval notification < 30 seconds.
US and UK teams have different compliance hooks, but the same control problem.
US teams usually care about clean evidence for audit support, vendor records, payment controls, tax reporting, and management review. UK teams usually care about VAT-ready records, approval evidence, digital-record discipline, and traceable postings. The country-specific details differ, but the operating pattern is the same: the ERP needs controlled records, explicit ownership, defensible state changes, and evidence that survives beyond the person who completed the task.
The control matrix.
| Control area | Requirement | Acceptance proof |
|---|---|---|
| Control 1 | Write-off must require approval workflow above configurable amount threshold | Given an invoice delinquent beyond the write-off eligibility threshold |
| Control 2 | reason code must be selected from a configurable list | when AR manager submits a write-off request with reason code |
| Control 3 | write-off must create a GL entry reversing the AR balance without modifying original invoice lines | then system routes to CFO if above approval threshold, on approval posts GL entry DR bad_debt_expense CR accounts_receivable, sets invoice status=WRITTEN_OFF, and excludes invoice from aging |
| Control 4 | written-off invoices must be excluded from aging but reportable in a bad debt report | negative) when write-off is submitted without a reason code then 422 REASON_CODE_REQUIRED is returned. |
| Control 5 | recovery must be supported (reopen invoice and apply payment | Uncollectible amounts are properly expensed; AR aging is not inflated by dead receivables; bad debt expense is tracked for management and tax purposes. |
| Control 6 | partial write-off must leave invoice partially open | Uncollectible amounts are properly expensed; AR aging is not inflated by dead receivables; bad debt expense is tracked for management and tax purposes. |
Audit evidence is a chain, not a folder.
| Evidence layer | What should be preserved |
|---|---|
| Business event | An invoice has been delinquent for 180+ days and the customer is unresponsive or insolvent; AR manager identifies the invoice in the collections queue and initiates a write-off request citing the reason (bankruptcy, dispute settled at $0, small balance); the request routes to CFO for approval above a threshold; once approved, the system posts a journal entry (DR Bad Debt Expense, CR Accounts Receivable) and marks the invoice as Written Off; the invoice exits the aging report; if payment is later received, a recovery journal entry reverses the write-off and posts cash. |
| Control rules | Write-off must require approval workflow above configurable amount threshold; reason code must be selected from a configurable list; write-off must create a GL entry reversing the AR balance without modifying original invoice lines; written-off invoices must be excluded from aging but reportable in a bad debt report; recovery must be supported (reopen invoice and apply payment); partial write-off must leave invoice partially open; write-off reversal must be auditable; non-functional: approval notification < 30 seconds. |
| Acceptance proof | Given an invoice delinquent beyond the write-off eligibility threshold; when AR manager submits a write-off request with reason code; then system routes to CFO if above approval threshold, on approval posts GL entry DR bad_debt_expense CR accounts_receivable, sets invoice status=WRITTEN_OFF, and excludes invoice from aging; (negative) when write-off is submitted without a reason code then 422 REASON_CODE_REQUIRED is returned. |
| Data record | |
| System event | |
| Lifecycle state | |
The useful version of this workflow is not only fast. It is inspectable. A controller, auditor, or operator should be able to move from source event to system record to state transition to final business outcome without guessing.
Implementation contracts.
Reference data model
`bad_debt_writeoff` { id: string, invoice_id: invoice_*, customer_id: cust_*, write_off_amount_minor: int64, currency_code: char(3), reason_code: string, approved_by: string, approved_at: timestamp, journal_entry_id: je_*, status: enum }; references sales_invoice; supports partial write-off leaving invoice partially open; (reference, product may differ).API and events
`POST /v1/write-offs` { invoice_id, amount_minor, currency_code, reason_code, external_id } -> 201 { id, status: PENDING_APPROVAL }; `POST /v1/write-offs/{id}/approve` -> 200; emits `ar.invoice.written_off`; idempotent via `external_id`.State transitions
`PENDING_APPROVAL -> APPROVED -> POSTED`; terminal `REVERSED`; guard: REVERSED re-opens invoice and posts recovery entry; approval required above configured threshold.Common implementation traps.
Treating the workflow as data entry
If the ERP only stores the final record, the team loses the decision trail that explains how the record became valid.
Hiding exception logic
Exceptions need owners, reason codes, and time stamps. A vague pending state is not a control.
Posting without recovery design
Retries, duplicate submissions, and partial failures must be explicit so the system does not create inconsistent records.
Skipping evidence design
A workflow that cannot produce evidence on demand will eventually push finance teams back into manual screenshots and spreadsheets.
Where Rivane fits.
Rivane is built for finance workflows where automation must stay tied to source documents, approvals, state transitions, ledger impact, reporting, and audit evidence. Use this guide as a checklist for evaluating whether an ERP workflow is merely digitized or actually controlled.
References and source basis.
These sources provide the standards, regulatory, or government context around the flow. They are included so the guide is useful to finance operators, auditors, and implementation teams, not only buyers reading software copy.