• Mahmoud Aglan's avatar
    fix(pricing): count a player's age forwards, and hold the picker to the same ceiling as the engine · 54df3e88
    Mahmoud Aglan authored
    Carbon 3 signs its differences: `$a->diffIn*($b)` answers `$b − $a`. The
    pricing engine asked it the other way round —
    `now()->diffInYears($birthday)` — so every participant it priced arrived
    at the rules with a negative age and a negative membership duration.
    
    The damage ran in both directions at once. A rule with a `min` never
    matched anyone again: the loyalty and annual recipes both ask for twelve
    months, and −25 is not twelve. A rule with a `max` matched the entire
    academy: the juniors recipe is `max: 6`, and −34 is comfortably under
    six, so one click in the rule builder would have taken 10% off every
    price in the club. The registration wizard computed age correctly in its
    own provisional context, which is why the desk saw one price at
    registration and another at renewal.
    
    Age and tenure now read from the older moment forward, through two named
    helpers that say why, and a date in the future is no age rather than a
    negative one.
    
    Alongside it, the discount picker: `selectedDiscountIds` is a public
    Livewire property, so it is a list the browser sends, and the total was
    summed from whatever ids arrived. applyDiscount() refuses a blocked rule
    and diverts an above-ceiling one into an approval request; neither guard
    survived to where the money was worked out. The engine's verdict is
    re-read there now, the academy's global discount ceiling applies to a
    hand-assembled total exactly as it does at step 8, a manual discount
    above the actor's cap reaches neither the total nor the invoice
    snapshot, and the picker's state is #[Locked] — it is driven entirely
    by wire:click, so nothing needed to arrive from the browser at all.
    
    Also here, found while reading for the above:
    
    - POSTerminal::updateQuantity() did not check the index exists, so an
      invented one wrote a cart line made of a quantity and nothing else.
    - The same reversed diff in four other places: overdue invoices and
      renewals reported negative days on the dashboard and in reminder
      messages, expiring memberships reported negative days remaining, and
      a product's months-active pinned to 1, inflating its average monthly
      movement to its entire lifetime sales.
    - validateCoupon() still carried a comment promising academy-wide
      coupons, three commits after branch_owns_the_catalogue removed them.
    
    Verified: 379 tests green on SQLite and against the restored OC-Sport
    tenant. That tenant carries one pricing rule (sibling_order, 4 EGP) and
    no invoice with a discount snapshot, so there is no historical billing
    to correct — the bug was waiting on the first age or loyalty rule.
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    54df3e88
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...