feat(statements): flag billing periods that overlap another statement
ci / lint-test (push) Successful in 46s
ci / lint-test (push) Successful in 46s
An account cannot be billed twice for the same day, so an overlap means those
transactions are in the ledger twice. ANZ statements 107 and 143 overlap by 118
days and put roughly $42,000 of duplicate rows in; nothing anywhere said so.
Two details decide whether this catches the real case:
- Account numbers compare with non-digits stripped. The duplicate got in
because the existing key compared raw text and ANZ wrote the same account
as 408556264 on one statement and 4085-56264 on the other.
- The range is half-open. These statements are issued back-to-back with one
period ending the day the next starts, so inclusive bounds flagged 5 pairs
of which 3 were consecutive and fine. Half-open leaves exactly the 2 real
ones.
NULL bounds are excluded rather than handed to daterange, where NULL means
unbounded and an undated statement would overlap all of history.
Detection only. It does not refuse the import or touch the duplicate rows --
cleaning those is separate, and must supersede rather than delete because every
child of transactions is ON DELETE CASCADE and the curation sits on the
duplicate side.
Both subtleties have a test, and both fail if you undo them.
This commit is contained in:
@@ -206,6 +206,21 @@ export default function StatementsPage() {
|
||||
</td>
|
||||
<td className="px-4 py-3 text-zinc-400 whitespace-nowrap">
|
||||
{formatPeriod(s.billing_start_date, s.billing_end_date)}
|
||||
{/* An account cannot be billed twice for the same day, so
|
||||
an overlap means these transactions are in the ledger
|
||||
twice. Red rather than amber: the balance warning above
|
||||
means a statement doesn't add up, this means the data is
|
||||
double-counted everywhere it is summed. */}
|
||||
{s.overlaps?.length > 0 && (
|
||||
<div
|
||||
className="text-[10px] text-red-400 mt-0.5"
|
||||
title={`Billing period overlaps statement ${s.overlaps
|
||||
.map((o) => `#${o.id} by ${o.days} day${o.days === 1 ? "" : "s"}`)
|
||||
.join(", ")}. The overlapping transactions are likely imported twice.`}
|
||||
>
|
||||
⚠ overlaps #{s.overlaps.map((o) => o.id).join(", #")}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-zinc-400 whitespace-nowrap">
|
||||
{formatDate(s.payment_due_date ?? s.billing_end_date)}
|
||||
|
||||
Reference in New Issue
Block a user