fix(accounting): stop a failed claim from re-posting the accrual every run
Booking the accruals against the live books exposed a real defect, and it cost
one duplicate entry before it was caught.
Nine rows in sa_players carry a membership NUMBER in member_id (101, 1015,
897000) instead of a member row id. The accrual run reached the first of them,
the foreign key on accounts_receivable.member_id refused the insert, and the
exception escaped the loop that records claims in posting_accruals. That loop
runs AFTER the journal entry is posted, so the entry stood at the full batch
total with only the claims written before the failure. The next run read the
remaining documents as never accrued and posted a SECOND entry for them — and
would have posted one more every night, because the failure is deterministic.
AccrualService::batch now treats a claim it cannot write as something to report,
not something to throw: the entry is already posted, so abandoning the rest of
the batch is the one response guaranteed to corrupt the ledger. A member id that
does not resolve costs the receivable, never the claim — posting_accruals is the
system of record and already tracks obligations for non-members. Member
existence is resolved once per batch, not once per claim.
Phase_112_003 repairs what the two runs left: the duplicate is reversed rather
than deleted so the correction stays visible, its claims move to the entry that
actually posted their money, and the 110 claims plus 32 receivables that were
never written are backfilled against it. It verifies the entry and its claims
agree before finishing, and does nothing at all unless production matches the
exact broken shape.
Why the clone missed it: the verification harness built tables with
CREATE TABLE ... LIKE, which silently drops foreign keys — so the constraint
that breaks production did not exist in the clone, and the run came back green.
The harness now copies DDL via SHOW CREATE TABLE and asserts the foreign key
count matches the source (409/409).
Verified against a clone of the actual broken production state: net movement for
sa_subscription_accrual is 104,769.00 not 184,938.00, all 135 claims equal their
entry to the cent, 1,316 claims total 835,167.93, trial balance diff 0.00, and
both the repair and the fixed runner post nothing on a second pass.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>
Showing
Please register or sign in to comment