feat(pricing): let a sibling discount apply to one membership tier only
A compound charges a resident 2,200 and a non-resident 2,800, and the second
child of a non-resident 2,400 — while a resident's second child stays at 2,200,
because the resident price is already the discounted one. A sibling_order rule
could say "second child" but not "and only for non-residents", and the
arithmetic has no shortcut: a flat 400 off takes the resident to 1,800, and a
percentage landing on 2,400 from 2,800 lands on 1,886 from 2,200.
The config-only alternative was a second stackable rule holding
fixed_price 220000 to push residents back up. That works arithmetically and is
the wrong answer: it stores the tier's base price in a second table. The day
fees rise and only base_prices is edited — the obvious place — that rule
silently forces every resident back to the old number, with no error and no
missing-price failure to notice. It also prints a +200 EGP "discount" line on a
resident sibling's invoice, because appliedRules is stored verbatim on it.
So sibling_order and family_size gain an optional membership_type list in their
conditions, evaluated as an AND alongside the existing range.
conditions is jsonb with no CHECK constraint, so no migration is needed. The key
is absent from every rule authored before now, isset() is false, and evaluation
is bit-identical for every existing rule on every tenant — additive in the same
sense a nullable column is. It is accepted only where the schema declares it;
normalize() strips it from an age or loyalty rule rather than storing a
condition the engine will never consult. describe() appends the tier to the
existing clause so the picker's rejection reason stays a sentence.
Pinned by 13 tests, the first of which is the one that matters to the other
tenants: absent key, unchanged behaviour.
Co-Authored-By:
Claude Opus 5 (1M context) <noreply@anthropic.com>
Showing
Please register or sign in to comment