• 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
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...
gap-filling-plans 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...