• Mahmoud Aglan's avatar
    feat(settlements): settle a member's account instead of editing around it · e45bd6d7
    Mahmoud Aglan authored
    A club that ran on paper for years does not arrive in the system as a
    clean ledger. On the first academy live, 33 players were registered with
    an invoice raised and the "pay now" toggle left off — 25 of them in two
    data-entry evenings — and 27 of those are now carrying an unpaid
    registration month plus an unpaid September renewal. Nine paid for the
    federation card in instalments typed into free-text lines. Eight invoices
    were issued at zero because no price existed yet. Three people exist
    twice. None of that is a bug in one screen; it is a whole class of file
    that reality got ahead of.
    
    The desk had four tools that each did a slice: collect a payment, correct
    one invoice's amount, back-fill missing invoices, register someone who
    started months ago. None of them answers the question an operator has in
    front of a parent — this file is wrong in several ways at once, what do
    we do about all of it — so corrections were made wherever a screen
    allowed them and the ledger drifted further.
    
    SettlementService applies a reviewed set of corrections as one
    transaction and one record: money taken and never entered (on the day it
    was actually taken), a month closed for less than it was billed because
    the player joined halfway through, a month dropped entirely, a month
    nobody billed, a card or kit sold outside the system, a free-text line
    linked to the product it was really paying for, an agreed instalment
    plan, a payment sitting on the wrong month, and an overpayment held as
    wallet credit. Money moves through PaymentService so the ledger, the
    balance and the receipt all happen; stock through InventoryService; a
    waiver is written as the admin_override the roster already knows how to
    explain, leaving subtotal_amount alone so "650 of 900, discounted" still
    reads. Nothing calls auth() or session(): actor, branch and amounts are
    parameters.
    
    AccountAnomalyScanner finds the files rather than waiting for an argument
    at the desk — seven cases, worst first, each with the sentence that says
    what to check. SettlementWorklist lists them with a CSV export;
    AccountSettlementWizard puts one account on a page, proposes the
    corrections that fit what it found, shows exactly what will be collected,
    waived and billed, and demands a written reason before it writes
    anything.
    
    Both screens are gated on a new settlements.manage permission — waiving a
    month is the academy's call, and an owner should not need a platform
    administrator to make it — delivered by migration as well as seeder,
    since db:seed only runs on a first deploy.
    
    Two things the tests caught rather than production: Postgres refuses FOR
    UPDATE on an aggregate, so numbering settlements from max(id) would have
    rolled back a whole settlement the operator had already confirmed; and
    payment_plans_status_check has no 'partial', so a part-paid plan is
    active with the count saying how far along it is.
    
    Verified against a restored oc-sport tenant: 20 settlement cases and 7
    render/permission cases pass, including cross-participant access, a
    future date, an oversized payment, and a failing second action rolling
    the first one back. Full suite 298 tests, no failures.
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    e45bd6d7
Name
Last commit
Last update
Screenshots Loading commit data...
app Loading commit data...
bootstrap Loading commit data...
config Loading commit data...
database Loading commit data...
docker Loading commit data...
docs Loading commit data...
docs-site Loading commit data...
flutter_shell Loading commit data...
gap-filling-plans Loading commit data...
lang Loading commit data...
marketing-site Loading commit data...
plans Loading commit data...
public Loading commit data...
reference/oc-sport Loading commit data...
resources Loading commit data...
routes Loading commit data...
scripts Loading commit data...
storage Loading commit data...
tests Loading commit data...
.dockerignore Loading commit data...
.editorconfig Loading commit data...
.env.example Loading commit data...
.gitattributes Loading commit data...
.gitignore Loading commit data...
.npmrc Loading commit data...
Beanding Guide.txt Loading commit data...
CLAUDE.md Loading commit data...
Dockerfile Loading commit data...
README.md Loading commit data...
artisan Loading commit data...
captain-definition Loading commit data...
composer.json Loading commit data...
composer.lock Loading commit data...
deploy.sh Loading commit data...
elcaptain-sportsonly-db.md Loading commit data...
one-click-app.yml Loading commit data...
package-lock.json Loading commit data...
package.json Loading commit data...
phpunit.xml Loading commit data...
system info.txt Loading commit data...
vite.config.js Loading commit data...
نادى الشيخ زايد كشف بيانات اللاعبين (2).html Loading commit data...