Functional Weave
Code in Python

finance.aged-debt@1.0.0

README.md

1,457 bytes · view raw

# finance.aged-debt

The aged debtors (or aged creditors) report: what is owed, split by how long it
has been overdue as at a date.

Age is counted from the **due date**, not the invoice date, because that is what
"overdue" means and what credit control chases. Days overdue is the calendar
days from the due date to the as-at date: an invoice due on the as-at date is 0
days overdue and still current; one due the day before is 1 day overdue.

The buckets are an argument. `[30, 60, 90]` gives the usual report:

| label | days overdue |
|---|---|
| current | 0 or fewer (not yet due, or due today) |
| 1-30 | 1 to 30 |
| 31-60 | 31 to 60 |
| 61-90 | 61 to 90 |
| 90+ | 91 or more |

`[7, 14]` gives current, 1-7, 8-14 and 14+. The bounds must be whole days,
ascending, the first at least 1. The last label reads "90+" as reports print
it, and `fromDays` (91) says exactly where it starts.

Every bucket appears, even when empty, so the columns of a report never move.
Each lists the references it holds in input order, so a total can always be
traced to its invoices. An unallocated credit (a negative outstanding amount)
reduces the bucket it falls in, as it does on a statement; allocating credits
to invoices first is the caller's choice.

Calendar days, not 30-day months: an invoice due on 31 December 2023 is 91
days overdue on 31 March 2024 (a leap year) but 90 days overdue on 31 March
2026, so it is "90+" in one report and "61-90" in the other.