• 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
..
Commands Loading commit data...