How a level is chosen
How Customer Payment Reminders calculates what it reports, and why.
The whole module is one decision, made once per customer per day: does this customer get a reminder now, and which one? This is that decision, in order. Every step can be read back in the interface, because "why has nobody chased Acme?" is the question a credit controller actually asks.
1. What counts as overdue
move_type in (out_invoice, out_receipt)
state = posted
payment_state in (not_paid, partial)
invoice_date_due < todayFour deliberate consequences:
- Draft invoices are never chased. Asking somebody to pay an invoice you have not sent them is the fastest way to lose an account.
- Partially paid invoices are still chased, for the remainder. Somebody who pays half and stops is exactly who you need to chase.
- Vendor bills and refunds are ignored. This module chases money owed to you.
- The due date, not the invoice date, decides. An invoice on 60-day terms is not late on day 31.
2. Grouped by the commercial partner
Overdue invoices are collected against the commercial partner — the company, not the contact the invoice was addressed to.
So a customer receives one reminder listing all their overdue invoices, rather than one per invoice. Six emails about six invoices is not six reminders; it is harassment, and it gets your address filtered.
3. Pauses and exclusions
In this order:
- Never Chase on the customer — nothing is ever sent, by the cron or by hand.
- Pause Until in the future — nothing until that date. A pause ending today still holds; it expires the day after.
Both produce a stated reason rather than silence.
4. The minimum
The total overdue across all their invoices is compared with the configured minimum. Below it, they are skipped and told why.
Compared against the total rather than each invoice deliberately: six invoices of £3 is £18 and worth one email.
5. Days overdue
days = today − (due date of the OLDEST overdue invoice)The oldest, not the newest and not the average. A customer with one invoice 90 days late and one 2 days late has a 90-day problem.
6. The level
Of every active level the customer's company can see — its own plus the shared ones — take those whose threshold days has passed, and pick the most severe (highest day count).
The most severe, not the next one up. A customer nobody has chased for four months should receive the sixty-day letter, not restart at seven and be walked politely through an escalation everybody knows is theatre.
7. Has it already been sent?
Each level fires once per customer. If the level chosen is the one already recorded against them, nothing is sent, and the reason says so.
8. The reset
If the chosen level is less severe than the last one sent, it is sent anyway.
This is the case that a naive implementation gets wrong. The customer cleared the old debt — the invoice that earned them the final notice is paid — and has now fallen behind on a new one. They are not a sixty-day problem any more. Keeping them at the harsh level punishes somebody who has just paid you.
What is deliberately not modelled
Interest and charges. The module reminds; it does not compute late-payment interest. That is a legal and contractual matter that varies by jurisdiction and by contract, and getting it subtly wrong in an automated email is worse than not offering it.
Credit limits and blocking. Nothing here stops an order, changes a credit limit, or puts an account on hold. Chasing is a communication problem; blocking is a policy decision, and it should stay a human one.
Promise-to-pay tracking. A pause with a reason and a date covers the same ground with one field instead of a workflow.
Per-invoice escalation. Deliberate — see step 2.
Where each decision is visible
| Decision | Where you see it |
|---|---|
| Overdue set | Overdue button on the customer; the invoice list |
| Days overdue | Days column in Customers to Chase |
| Level chosen | Level column, and the customer's Payment Reminders tab |
| Reason for skipping | The send wizard's Skipped because column |
| What was sent, when | Reminders Sent |