• Mahmoud Aglan's avatar
    fix(training): stop a deleted programme from silently unbilling its players · a6451e4e
    Mahmoud Aglan authored
    Deleting a programme or a group called `$group->enrollments()->forceDelete()`
    on both paths — hard delete, no soft delete, no audit row, nothing to restore
    from. `enrollments` is the only table GenerateRenewalInvoices bills from, so
    the players were not merely losing history: they stopped existing as far as
    billing was concerned while still training, still members, still owing money.
    
    OC-Sport reorganised its season on 28 August 2026 by deleting the programmes
    and recreating them under new names. 181 enrolments went with them. On
    2 September the renewal run raised 229 invoices, reported a clean success, and
    95 paying players were not among them. Nobody found out until a parent asked
    why no bill had come for his son.
    
    Two halves, because neither alone is enough:
    
    - A destructive delete is refused while anything is enrolled — active or
      cancelled, since a cancelled enrolment is still the only record of what an
      issued invoice bought. Archive the programme, or transfer the players and
      close the group. The count drops the branch scope: an enrolment hidden by
      the active branch is still an enrolment, and reading zero because of it is
      how a guard like this fails open.
    - The renewal command now names every paying player who has invoice history
      and no enrolment at all, and logs them. No guard recovers the rows already
      lost, or catches the next way somebody finds to lose them. An empty enrolment
      set with such players left over is a FAILURE exit — "nothing to bill" and
      "every enrolment was destroyed" produce the same empty set, and the players
      left over are the only thing that tells them apart.
    
    Group deletion moves into TrainingGroupService so the guard sits on every path
    to it; GroupList duplicating the cleanup inline is how one path ended up
    without it.
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    a6451e4e
Name
Last commit
Last update
..
Activities Loading commit data...
Admin Loading commit data...
Assignments Loading commit data...
Attendance Loading commit data...
Audit Loading commit data...
Auth Loading commit data...
Branches Loading commit data...
CashSessions Loading commit data...
Components Loading commit data...
Concerns Loading commit data...
Dashboard Loading commit data...
Documents Loading commit data...
Enrollments Loading commit data...
Evaluations Loading commit data...
Events Loading commit data...
Facilities Loading commit data...
Financial Loading commit data...
Groups Loading commit data...
Guardian Loading commit data...
HR Loading commit data...
Inventory Loading commit data...
Invoices Loading commit data...
Messaging Loading commit data...
Notifications Loading commit data...
POS Loading commit data...
Parent Loading commit data...
Participants Loading commit data...
People Loading commit data...
Portal Loading commit data...
Pricing Loading commit data...
Profile Loading commit data...
Programs Loading commit data...
Public Loading commit data...
Receptionist Loading commit data...
Reports Loading commit data...
Requests Loading commit data...
Roles Loading commit data...
Schedule Loading commit data...
Settings Loading commit data...
Trainer Loading commit data...
Training Loading commit data...
Users Loading commit data...
Wallets Loading commit data...
Website Loading commit data...
WhatsApp Loading commit data...
Wizards Loading commit data...
BranchSwitcher.php Loading commit data...
Dashboard.php Loading commit data...
GlobalSearch.php Loading commit data...