On this page
The change under testCore happy pathEdge cases to coverRegression checks (make sure nothing else moved)The open definitional questionData‑integrity noteFor Quality
What to test, and where the edges are. The change is tiny, but it has a few real edge cases worth exercising.
The change under test
- Web:
packages/clinic-web/.../invoices/InvoiceInfo.js:118 - Mobile:
packages/clinic-mobile/.../invoices/InvoicesInfo.js:99 - New formula:
percentage = total ? (discount / (total + discount)) * 100 : undefined, rounded with.toFixed(1).
Core happy path
- Open Finances → Invoices, click Show Analytics, click the Discount
tile to filter to discounted invoices.
- Read the Total and Discount amounts from the tiles.
- Verify the tile percentage equals
Discount ÷ (Total + Discount) × 100,
rounded to one decimal.
Known‑good reference (sandbox, discounted filter): Discount ₺2,373.25, Total ₺18,301.75 → 2373.25 / (18301.75 + 2373.25) = 11.48 % → 11.5 %. (The old code gave 2373.25 / 18301.75 = 13.0 %.)
Edge cases to cover
| # | Scenario | Expected |
|---|---|---|
| 1 | No tax (VAT‑Exempt) invoices only | Tile equals the true "percent off": discount ÷ subtotal. This is the exact case. |
| 2 | Taxed invoices in scope | Tile is slightly lower than discount ÷ subtotal, because the denominator is subtotal + tax. Confirm it's between the old (too high) and the pre‑tax true value. |
| 3 | Zero discount in scope | The Discount tile is hidden entirely ({discount ? … : null}). |
| 4 | Discount present but total is 0 (e.g. only balance invoices, all filtered out of total) | Percentage is undefined / blank — no divide‑by‑zero, no Infinity, no NaN. |
| 5 | Balance invoices in the mix | total excludes balanceInvoice rows (filter(p => !p.balanceInvoice)) but discount sums all rows. Verify the intended scope: a discount sitting only on a balance invoice still contributes to the numerator while its total is excluded from the denominator. Flag if this skews the percentage. |
| 6 | 100 % discount (total after discount = 0 but discount > 0, non‑balance) | Denominator total + discount = discount, so tile shows 100.0 %. Confirm it doesn't read blank or error. |
| 7 | Web vs mobile parity | Same filter/date range should yield the same percentage on both clients. |
| 8 | Rounding display | Whole values print without a trailing .0 (e.g. 1, not 1.0), because of Number(...). Fractional values keep one decimal (11.5). |
| 9 | Rounding to 0 | A very small discount (e.g. the unfiltered set: ₺2,373 on ₺246,439) rounds to 1. Confirm tiny discounts round sanely and never negative. |
Regression checks (make sure nothing else moved)
- Other tiles unchanged: Paid, Required To Pay, Remaining, Tax, Insurance,
Diagnostic Fee, Released still use value / total — their percentages must be identical to before this change.
- Money amounts unchanged: every tile's currency figure is untouched.
- Invoice detail unchanged: expanding a row still shows the same
Subtotal/Discount/Tax/Total (e.g. 500 − 75 + 63.76 = 488.76).
The open definitional question
The per‑invoice stored discountPercent is discount ÷ subtotal (invoiceUtils.js:145), a pre‑tax base. The tile now uses discount ÷ (total + discount) = discount ÷ (subtotal + tax), a tax‑inclusive base. They diverge on taxed invoices. This is not a bug in the fix, but QA should confirm with product which basis is canonical for the summary bar. If the tile should match the per‑invoice figure exactly, the denominator would need to subtract tax (total + discount − tax).
Data‑integrity note
No database writes are involved, so there is nothing to verify at the storage layer — only the rendered number. Confirm the value recomputes correctly on filter/date changes without a page reload.