• Mahmoud Aglan's avatar
    fix(financial): attribute revenue to what was actually sold · 35200985
    Mahmoud Aglan authored
    Measured against the live oc-sport database, subscription revenue read
    457,970 EGP against a genuine 345,257 — overstated by 32.6% — while the
    per-programme breakdown summed to 39,873, about 12% of reality.
    
    Three distinct causes:
    
    POSService::buildInvoiceItems() discarded the item_type/item_id it was
    handed, so every POS line landed with a NULL itemable_type. Reporting
    reads NULL as "programme subscription", which moved 102,000 EGP of
    product sales into subscription revenue — 90% of the error — and meant
    no product-ownership check could ever pass. Lines now carry their
    Product or Kit. A migration backfills history by matching invoice lines
    to their POS lines, filling only NULL rows and only where the match is
    unambiguous; a production dry run matched 44 of 45 with 0 ambiguous.
    
    Pro-rata allocation divided by invoices.total_amount, but line totals
    sum to subtotal_amount — total_amount also carries discount, tax and
    service fees. Every bundled invoice was therefore split on the wrong
    denominator (10,713 EGP).
    
    topPrograms joined enrolments to invoices and dropped anything without
    an invoice_id. Only 88 of 350 enrolments have one, so 75% of programmes
    reported zero. Now a UNION: the exact link where it exists, participant
    fallback where it does not, split evenly across a participant's
    programmes. Reconciles at 333,105 EGP.
    
    Also: the mounted revenue widgets and the receptionist dashboard omitted
    direction='inbound', counting refunds as income, and the widgets' raw
    queries bypassed SoftDeletes and cancelled invoices.
    
    EnrollExistingWizard read BasePrice directly, ignoring membership type
    and every pricing rule, so it quoted a different figure than the
    registration wizard for the same player. Both now go through
    PricingService.
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    35200985
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...
Pricing Loading commit data...
Profile Loading commit data...
Programs Loading commit data...
Public Loading commit data...
Receptionist Loading commit data...
Reports 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...