• Mahmoud Aglan's avatar
    feat(billing): charge a mid-month joiner for trainings, not for days · ecae5ecb
    Mahmoud Aglan authored
    Proration counted remaining days on a hardcoded 30-day month, a unit the
    academy never sold. A programme meeting Sunday and Tuesday holds no
    sessions over a long weekend, so someone joining on the 22nd was billed a
    third of a month for perhaps two trainings — and the calendar never
    noticed. September 2026, Sun+Tue: three of the month's nine sessions
    remain on the 22nd, not nine of thirty days.
    
    SessionCountService counts from the timetable rather than from
    training_sessions, because the generator only materialises rows about a
    week ahead and counting rows would under-report the rest of the month —
    exactly the question proration asks. Its rules are the generator's,
    deliberately identical: an active schedule row naming the weekday,
    effective that day, with no training-affecting holiday on it.
    
    The desk now chooses per registration: شهر كامل, نص شهر, or باقي تمرينات
    الشهر. The mode is settable from the browser by design, and safe to be —
    the academy setting remains the gate, and an unrecognised value falls back
    to the default rather than being honoured. Joining after the month's last
    session owes nothing for that month, so no invoice is raised at all; a
    zero-total one is what AccountAnomalyScanner reports as corruption.
    
    Also: a branch whose takings never pass through the system. A partner-run
    site bills nobody — participants enrol unbilled, enrolments are marked
    waived, and the branch's income is entered afterwards on the
    external-revenue screen. Skipping the invoice rather than writing a zero
    one, for the same reason as above. The guard sits before the renewal
    command's adoption step, not after: those enrolments carry no billing date
    precisely because they are off the cycle, and adoption would read that as
    an oversight and put every one of them onto it.
    
    Fixes a latent crash on the way: BranchSettingsService called
    app('current_academy') unguarded, which throws rather than returning null
    outside a request. The renewal command binds no academy, so asking it the
    billing question from the console would have taken the nightly run down.
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    ecae5ecb
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...