fix(groups): show what a player paid this month, and why it is that number
The roster's الدفع column answered a different question from the one it
appeared to answer, in three compounding ways.
It showed a LIFETIME subscription total beside a monthly bill. A player who paid
650 in July, 1,200 for a kit bag and 650 in August read as "2,500" for the
current month. Two months of subscriptions were simply added together.
"Subscription" was defined as "an invoice line with no product link" — a
negative definition, so every hand-typed line became subscription money. That
kit bag was typed as free text, so it landed in the subscription figure, was
missing from product revenue, and left the same screen reporting the player had
never bought the kit they had paid for.
The red "has not paid" flag came from an unrelated calculation: matching invoice
text with ilike %اشتراك% plus the programme name. Substring matching on Arabic
also decides that تجهيزي contains زي. On live data the flag and the amount
disagreed on 28 of 247 active enrolments — red rows showing a green figure. The
template's "show unpaid only if flagged AND the amount is zero" guard was not
defensive coding; it was two sources of truth being reconciled where the
disagreement stopped being visible.
The figure is now this billing cycle only, derived from the programme's own
cycle rather than the calendar month, and one computation feeds the amount, the
row flag and the header counts — so they cannot contradict each other again.
Each figure is colour-coded by WHY it is that number, with a legend above the
table: paid in full, pro-rated for a mid-month join, admin discount, line price
override, instalment, partial, unpaid, not yet billed, free. All of it was
already recorded in invoice and line metadata and never surfaced; the reason,
who applied it and the original price now appear on the row. Colour never
carries the meaning alone — each amount also shows a glyph, a label and a
screen-reader sentence, and every case sits at 4.5:1 against white.
The migration links hand-typed product lines to their product where the full
trimmed description matches a product name exactly. Substrings are deliberately
not matched and ambiguous lines are left alone: 44 lines / 209,200 EGP link
safely, 23 lines / 42,800 EGP are reported for a human instead of guessed at.
Verified by replaying the real production rows behind both reported screenshots
through the service: every figure the user questioned is now explained.
Co-Authored-By:
Claude Opus 5 (1M context) <noreply@anthropic.com>
Showing
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Please register or sign in to comment