fix(sponsor-reports): make Purchase Details describe itself on every view - #1046
Conversation
buildPurchaseLinesQuery destructured paymentMethod away and the control was hidden on the line views, so filtering to invoiced orders and clicking Line Items silently widened 22 items to 250. The lines endpoint now supports the filter, so it is carried through at every grain. ref: https://app.clickup.com/t/86bbh5vat
getPurchaseDetailsByItemRows still claimed the lines-grain query drops paymentMethod, but it calls buildPurchaseLinesQuery, which now carries it through. Same false claim as the one already fixed at the query builder itself, missed on the first sweep. ref: https://app.clickup.com/t/86bbh5vat
A soft-canceled line leaves its parent order Paid, so the Status column read Paid on a dead row and the per-sponsor chip counted it. Both now read the line. Adds the two freshness columns. ref: https://app.clickup.com/t/86bbh5vat
…ssertions The timestamps test used the same epoch for both fields and asserted only "at least one match", so it couldn't catch a swapped or missing cell. Now uses two distinct values and pins them to the row's final two cells. The live-count test asserted row count loosely (>2) without proving which rows rendered; now pins the exact count and asserts the canceled row's identity. ref: https://app.clickup.com/t/86bbh5vat
The drill-down rendered the parent order's status on a canceled line, and the group chip described deliberately-filtered canceled orders as 'purchased'. Aggregates are unchanged (decision 8) - the wording is not. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com>
…rity Exact-equality on the chip catalog value closes the gap where a substring guard could pass a reworded defect or unrelated copy. A new header/cell cardinality check on the nested contributor table catches a header array desync that a positional last-two-cells check alone would miss, in both the by-sponsor (10 cols) and all-sponsors (11 cols) layouts. ref: https://app.clickup.com/t/86bbh5vat
A refund never changes purchase status, so a fully refunded order read as a clean Paid on screen; the CSV already carried the field. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com>
…ader order refunded_amount rendered left-aligned while invoice_total (the table's other currency column) is right-aligned. Also strengthened the header-order test to assert the complete 14-key sequence instead of only the appended tail, so a reorder among the original 11 columns is caught too. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com>
Total Paid is gross and sat unlabelled beside Total Refunded, whose dollar is inside it. Canceled orders are excluded by default at both grains and nothing in the UI said so. ref: https://app.clickup.com/t/86bbh5vat
…drifting CustomTheme's global MuiFormHelperText override makes helper text position: absolute, anchored to the nearest positioned ancestor. The new note is a sibling of MuiDropdown, not a child of its internal FormControl, so it had no positioned ancestor and drifted to the initial containing block instead of sitting under the dropdown. Override back to static on this instance so it renders in normal flow and reserves its own height. ref: https://app.clickup.com/t/86bbh5vat
…est title
The lines_count chip still said "{count} lines" even though canceled
lines render (struck through) but aren't counted, so a group showing 2
rows could read "1 lines" — reworded to "{count} live lines" to match
the byitem chip's phrasing.
LinesManifestView had no columnheader-count-vs-cell-count assertion,
so a HEADERS/TableCell desync would misalign columns without failing
any test; added the same guard ByItemView already has for its
contributor table.
The ByItemView it.each drill-down test title formatted the mount
function as %i, rendering "NaN cells per row" in CI output; reworded
to use only the arguments actually referenced.
ref: https://app.clickup.com/t/86bbh5vat
Co-Authored-By: Claude <noreply@anthropic.com>
The chip is fed liveLineCount while canceled lines still render, so the
copy has to say which number it is. This module's i18n mock renders the
chip from the key and count only, so the existing count assertion is
value-independent: the English could regress to "{count} lines" and every
DOM test would still pass. Mirrors the By Item chip's catalog copy test.
ref: https://app.clickup.com/t/86bbh5vat
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Updates the Sponsor Reports “Purchase Details” UI to be self-describing and consistent across Orders / Line Items / By Item grains, aligning displayed state and freshness at the correct (line vs order) level.
Changes:
- Keeps the Payment Method filter visible and carried through across grain switches, including lines queries and exports.
- Adds/updates UI chrome + copy so totals/filters communicate their semantics (gross paid, canceled-default exclusion, “live lines” wording).
- Surfaces new columns (refund amount + freshness timestamps) and corrects line-level status rendering for canceled lines.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pages/sponsors/sponsor-reports/purchase-details-report-page/index.js | Adds status helper text and makes Payment Method filter visible across views |
| src/pages/sponsors/sponsor-reports/purchase-details-report-page/tests/index.test.js | Adds assertions for Payment Method visibility + self-describing chrome |
| src/i18n/en.json | Updates/introduces copy for gross paid label, canceled note, live lines wording, and new column headers |
| src/components/sponsors/reports/OrdersTable.js | Adds refunded + freshness columns to the Orders table |
| src/components/sponsors/reports/LinesManifestView.js | Counts “live lines”, renders canceled line state explicitly, adds freshness columns |
| src/components/sponsors/reports/ByItemView.js | Carries and renders line-level cancellation + freshness in drill-down rows |
| src/components/sponsors/reports/tests/OrdersTable.test.js | Adds tests for refunded + freshness columns and header order |
| src/components/sponsors/reports/tests/LinesManifestView.test.js | Adds tests for line-level canceled status, freshness columns, and live-line counting |
| src/components/sponsors/reports/tests/ByItemView.test.js | Adds tests for drill-down status/freshness and chip copy |
| src/actions/sponsor-reports-actions.js | Stops dropping paymentMethod from line-grain query builder |
| src/actions/tests/sponsor-reports-query.test.js | Updates query-builder expectations to include payment_method at line grain |
| src/actions/tests/sponsor-reports-actions.test.js | Updates lines endpoint request test to expect payment_method filtering |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…trol The note explaining that canceled orders are excluded by default rendered next to the Purchase Status dropdown but was not associated with it, so screen readers never announced the two together. The note is a sibling rather than a FormControl child, so MUI cannot wire this up itself; the dropdown spreads unrecognised props onto the Select, so aria-describedby reaches the rendered control. ref: https://app.clickup.com/t/86bbh5vat
… icon Helper text under the Purchase Status dropdown made that filter twice the height of its siblings, and the center-aligned filter row rendered it out of line with them. Switch to the repo's existing hover-info idiom, an aria-hidden fa-info-circle carrying the copy in its title, so every filter is the same height again. That idiom is sighted-only, so the same copy is repeated in a visually-hidden span the Select points at via aria-describedby, keeping the note announced with its control. Renames the key to filter_status_info, matching the label_key + _info convention the rest of the app uses for hover info. ref: https://app.clickup.com/t/86bbh5vat
| line leaves its order Paid, so rendering purchase.status | ||
| printed "Paid" on a dead row — and the strikethrough that | ||
| was the only other signal does not survive CSV export. */} | ||
| {line.is_canceled ? ( |
There was a problem hiding this comment.
@caseylocker This branch cannot render once sponsor-reports-api#40 is deployed: the only
line rows that reach it are ones whose parent order is already Canceled, where both
branches print the same label with the same tone.
include_cancelled is written in exactly one place — sponsor-reports-actions.js:226,
if (status === "Canceled") — so asking for canceled rows also emits status==Canceled,
which PurchaseLineDetailsFilter resolves to purchase__status
(purchase_line_details_filter.py:20). A soft-canceled line on a Paid order — the exact
row this change targets — is excluded by default, then excluded again by the status clause
the moment you try to un-hide it. statusTone("Canceled") returns default either way, so
in every reachable state this renders identically to the previous line.purchase?.status.
The API deliberately made this a separate axis, and it is already exercised there:
test_include_cancelled_true_restores_line_level_canceled_items
(apps/reports/tests/test_purchase_details_lines_endpoints.py:123) sends
?include_cancelled=true with no status filter and gets AV3 back — is_canceled: true
inside a Paid order. The fixture comment states it directly: "NO status selection could
ever remove it -- line-level cancellation is a separate axis". The frontend is the only
side coupling the two.
Suggested fix: give include_cancelled its own control rather than deriving it from the
status value — a "Show canceled" checkbox in FilterBar, carried as its own filter key and
emitted independently in buildReportQuery. That is the shape this repo already uses for
showArchived (.claude/rules/summit-admin-archive-pattern.md). The current coupling stays
correct at order grain; only the line grain needs the extra axis. The same fix makes the
By Item contributor branch at ByItemView.js:467 reachable, and lets the Purchase Status
note describe both axes truthfully on the line views.
There was a problem hiding this comment.
Confirmed and fixed in c8bc53f.
You're right that the branch was unreachable. include_cancelled had exactly one write site, sponsor-reports-actions.js:226, and buildReportQuery is the single builder for the details, lines, By Item and both CSV paths, so the coupling closed the axis everywhere at once. Every row that could reach the pill already had purchase.status === "Canceled", and since StatusPill maps both spellings of canceled to tone default and status_canceled is literally "Canceled", the two arms rendered an identical chip. Same for ByItemView.js:467.
Took the separate control. One change to the shape you suggested: the status coupling stays, as an OR rather than a replacement.
if (status === "Canceled" || showCanceled) query.include_cancelled = "true";Emitting include_cancelled only from the checkbox would regress the Orders view. purchase_details_report_view.py:44 excludes status='Canceled' by default, so a Canceled selection without the flag returns zero rows and the dropdown option goes dead. There's a test pinning that direction specifically, so a later cleanup can't quietly drop it.
The checkbox is on every grain, not the line views only. Filters are carried across a view switch, so a control that appears and vanishes would leave a live filter behind an invisible control, which is the same silent-filter class this report set out to fix.
Also updated the Purchase Status note per your last point: it's now grain-aware, since the line grains hide a second kind of row the order grain has no concept of.
One correction on the citation: .claude/rules/summit-admin-archive-pattern.md isn't in this repo, there's no .claude/ directory here. The doc lives in the fn-skills vault at patterns/show-admin/summit-admin-archive-pattern.md. The precedent itself is real in-repo, showArchived in form-template-actions.js, show-pages-actions.js and others, and the shape matched, so the checkbox follows it.
Full suite 1528 passing.
include_cancelled was written in exactly one place, derived from the status value. Asking for canceled rows therefore also emitted status==Canceled, which resolves to purchase__status at line grain, so a soft-canceled line inside a Paid order was excluded by default and excluded again the moment you tried to un-hide it. The line-level status pill added here was unreachable in consequence: every row that could render it already had a Canceled parent, where both branches print the same chip. Adds a Show canceled checkbox carried as its own filter key. The status coupling stays as an OR rather than being replaced -- the orders endpoint excludes Canceled by default, so a Canceled selection without the flag would return no rows and the dropdown option would go dead. Shown on every grain rather than the line views only: filters are carried across a view switch, and a hidden control holding a live filter is the silent-filter class this report set out to fix. The canceled-default note is now grain-aware, since the line grains hide a second kind of row the order grain has no concept of. Co-Authored-By: Claude <noreply@anthropic.com>
santipalenque
left a comment
There was a problem hiding this comment.
Looks good, just a couple of nitpicks, in general lets keep the comments concise
| {/* the line's own state — its parent order can be Paid | ||
| while this specific line is canceled */} | ||
| {c.isCanceled ? ( | ||
| <StatusPill |
There was a problem hiding this comment.
nit: can you change the status in the reducer ? so this render looks cleaner ?
There was a problem hiding this comment.
Done in d0b0ec6. One note on where: the reducer stores the API rows raw (sponsor-reports-purchase-details-by-item-reducer.js:64), so the resolution went into groupLinesByItem, which already builds the contributor. The cell is a single StatusPill again.
The canceled label drops its T.translate as a result. No visible change, and the statusMix chips in this same component already render raw status strings.
LinesManifestView keeps its branch. It renders straight off the API rows with no mapping layer, so matching this would mean adding one for symmetry alone.
| const extraControls = (draft, update) => ( | ||
| <> | ||
| <Box sx={{ width: 200 }}> | ||
| {/* The default excludes canceled orders at BOTH grains and nothing said so, |
There was a problem hiding this comment.
do we need this comment just to explain an alignment ? seems unnecessary
There was a problem hiding this comment.
No we don't. Cut. Kept two lines for the part that is not visible in the code: the icon is aria-hidden, so deleting the "duplicate" hidden span silently breaks the screen-reader path.
| {T.translate(statusNoteKey(view))} | ||
| </Box> | ||
| </Box> | ||
| {/* The second cancellation axis, which the status dropdown cannot reach: |
There was a problem hiding this comment.
again, this could be a one-liner
There was a problem hiding this comment.
Trimmed to two lines, just why the axis has to be separate from the status filter.
…mments Review nits from santipalenque. groupLinesByItem now resolves a contributor's status to the line's own state, so the drill-down cell is a single StatusPill again instead of a branch. The canceled label loses its T.translate wrapper, which matches the statusMix chips in the same component -- they already render raw status strings -- and the catalog value is "Canceled" either way. The behavioural guarantee moves with it: the mapper test now asserts the resolved status, and the view test only asserts the cell renders what it is handed. LinesManifestView keeps its branch: it renders straight off the API rows with no mapping layer, so following this would mean inventing one for symmetry alone. Comments trimmed to the non-obvious half. The status note keeps why the copy is duplicated into a visually-hidden span (the icon is aria-hidden, so deleting the "duplicate" silently breaks the screen-reader path a test pins) and drops the alignment rationale. The checkbox comment keeps why the axis has to be separate. Co-Authored-By: Claude <noreply@anthropic.com>
|
@caseylocker LGTM please review the changes requested by @santipalenque and we are good to merge many thanks |
@smarcet this should be good now - as long as the changes for @santipalenque are ok. There was a jest ci failure on the last push but I re-ran it and it looks like it was a hiccup. All green. |
…view (#1046) * fix(sponsor-reports): keep Payment Method applied across grain switches buildPurchaseLinesQuery destructured paymentMethod away and the control was hidden on the line views, so filtering to invoiced orders and clicking Line Items silently widened 22 items to 250. The lines endpoint now supports the filter, so it is carried through at every grain. ref: https://app.clickup.com/t/86bbh5vat * docs(sponsor-reports): fix second stale paymentMethod-drop comment getPurchaseDetailsByItemRows still claimed the lines-grain query drops paymentMethod, but it calls buildPurchaseLinesQuery, which now carries it through. Same false claim as the one already fixed at the query builder itself, missed on the first sweep. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): show the line's own state in the manifest A soft-canceled line leaves its parent order Paid, so the Status column read Paid on a dead row and the per-sponsor chip counted it. Both now read the line. Adds the two freshness columns. ref: https://app.clickup.com/t/86bbh5vat * test(sponsor-reports): strengthen manifest freshness and live-count assertions The timestamps test used the same epoch for both fields and asserted only "at least one match", so it couldn't catch a swapped or missing cell. Now uses two distinct values and pins them to the row's final two cells. The live-count test asserted row count loosely (>2) without proving which rows rendered; now pins the exact count and asserts the canceled row's identity. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): By Item drill-down shows line state and freshness The drill-down rendered the parent order's status on a canceled line, and the group chip described deliberately-filtered canceled orders as 'purchased'. Aggregates are unchanged (decision 8) - the wording is not. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com> * test(sponsor-reports): pin By Item chip copy and drill-down column parity Exact-equality on the chip catalog value closes the gap where a substring guard could pass a reworded defect or unrelated copy. A new header/cell cardinality check on the nested contributor table catches a header array desync that a positional last-two-cells check alone would miss, in both the by-sponsor (10 cols) and all-sponsors (11 cols) layouts. ref: https://app.clickup.com/t/86bbh5vat * feat(sponsor-reports): surface refunded amount and freshness on Orders A refund never changes purchase status, so a fully refunded order read as a clean Paid on screen; the CSV already carried the field. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com> * fix(sponsor-reports): right-align refunded amount, pin full Orders header order refunded_amount rendered left-aligned while invoice_total (the table's other currency column) is right-aligned. Also strengthened the header-order test to assert the complete 14-key sequence instead of only the appended tail, so a reorder among the original 11 columns is caught too. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com> * fix(sponsor-reports): label the gross total and the canceled default Total Paid is gross and sat unlabelled beside Total Refunded, whose dollar is inside it. Canceled orders are excluded by default at both grains and nothing in the UI said so. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): flow the status helper text in-page instead of drifting CustomTheme's global MuiFormHelperText override makes helper text position: absolute, anchored to the nearest positioned ancestor. The new note is a sibling of MuiDropdown, not a child of its internal FormControl, so it had no positioned ancestor and drifted to the initial containing block instead of sitting under the dropdown. Override back to static on this instance so it renders in normal flow and reserves its own height. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): reword lines chip, add header/cell guard, fix test title The lines_count chip still said "{count} lines" even though canceled lines render (struck through) but aren't counted, so a group showing 2 rows could read "1 lines" — reworded to "{count} live lines" to match the byitem chip's phrasing. LinesManifestView had no columnheader-count-vs-cell-count assertion, so a HEADERS/TableCell desync would misalign columns without failing any test; added the same guard ByItemView already has for its contributor table. The ByItemView it.each drill-down test title formatted the mount function as %i, rendering "NaN cells per row" in CI output; reworded to use only the arguments actually referenced. ref: https://app.clickup.com/t/86bbh5vat Co-Authored-By: Claude <noreply@anthropic.com> * test(sponsor-reports): pin the lines_count copy in the catalog The chip is fed liveLineCount while canceled lines still render, so the copy has to say which number it is. This module's i18n mock renders the chip from the key and count only, so the existing count assertion is value-independent: the English could regress to "{count} lines" and every DOM test would still pass. Mirrors the By Item chip's catalog copy test. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): announce the canceled-default note with its control The note explaining that canceled orders are excluded by default rendered next to the Purchase Status dropdown but was not associated with it, so screen readers never announced the two together. The note is a sibling rather than a FormControl child, so MUI cannot wire this up itself; the dropdown spreads unrecognised props onto the Select, so aria-describedby reaches the rendered control. ref: https://app.clickup.com/t/86bbh5vat * fix(sponsor-reports): carry the canceled-default note as a hover info icon Helper text under the Purchase Status dropdown made that filter twice the height of its siblings, and the center-aligned filter row rendered it out of line with them. Switch to the repo's existing hover-info idiom, an aria-hidden fa-info-circle carrying the copy in its title, so every filter is the same height again. That idiom is sighted-only, so the same copy is repeated in a visually-hidden span the Select points at via aria-describedby, keeping the note announced with its control. Renames the key to filter_status_info, matching the label_key + _info convention the rest of the app uses for hover info. ref: https://app.clickup.com/t/86bbh5vat * feat(sponsor-reports): give canceled rows their own filter axis include_cancelled was written in exactly one place, derived from the status value. Asking for canceled rows therefore also emitted status==Canceled, which resolves to purchase__status at line grain, so a soft-canceled line inside a Paid order was excluded by default and excluded again the moment you tried to un-hide it. The line-level status pill added here was unreachable in consequence: every row that could render it already had a Canceled parent, where both branches print the same chip. Adds a Show canceled checkbox carried as its own filter key. The status coupling stays as an OR rather than being replaced -- the orders endpoint excludes Canceled by default, so a Canceled selection without the flag would return no rows and the dropdown option would go dead. Shown on every grain rather than the line views only: filters are carried across a view switch, and a hidden control holding a live filter is the silent-filter class this report set out to fix. The canceled-default note is now grain-aware, since the line grains hide a second kind of row the order grain has no concept of. Co-Authored-By: Claude <noreply@anthropic.com> * refactor(sponsor-reports): resolve line status in the mapper, trim comments Review nits from santipalenque. groupLinesByItem now resolves a contributor's status to the line's own state, so the drill-down cell is a single StatusPill again instead of a branch. The canceled label loses its T.translate wrapper, which matches the statusMix chips in the same component -- they already render raw status strings -- and the catalog value is "Canceled" either way. The behavioural guarantee moves with it: the mapper test now asserts the resolved status, and the view test only asserts the cell renders what it is handed. LinesManifestView keeps its branch: it renders straight off the API rows with no mapping layer, so following this would mean inventing one for symmetry alone. Comments trimmed to the non-obvious half. The status note keeps why the copy is duplicated into a visually-hidden span (the icon is aria-hidden, so deleting the "duplicate" silently breaks the screen-reader path a test pins) and drops the alignment rationale. The checkbox comment keeps why the axis has to be separate. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
ref: https://app.clickup.com/t/86bbh5vat
Frontend half of "Purchase Details: the report does not describe itself". Backend half is fntechgit/sponsor-reports-api#40.
DEPLOY GATE: merge and deploy sponsor-reports-api#40 first
This PR must not reach production ahead of the API. If it ships first:
payment_method. base-api-utils drops undeclared filter fields silently on the AND path, so the filter reads as applied and does nothing. Before this PR the control was hidden, which was at least honest.refunded_amountandis_canceledare already on origin/main, so the refund column works today regardless.Deploying this
No config. The diff touches no
.env, webpack config,package.json,yarn.lock, Dockerfile or workflow, and adds no newprocess.envreads. The three new i18n keys ship inside the bundle, so there is no separate translation step.Merge target is
master, notmain.Routine in-place redeploy inside the running container, per
summit-admin-docker:Clones
$BRANCH(master), runsyarn installandyarn build, swaps the release directory and prunes older deployments. Nothing else restarts.Host note: the dev container is
show-admin-dev-2on the dev docker server, with the wrapper at~/repos/summit-admin-docker. Production is not on the microservices droplet, so use whichever of the Production Docker hosts servesshowadmin.fnvirtual.app.Order still matters: sponsor-reports-api #40 has to be in production first, for the reasons under "DEPLOY GATE" above.
Optional before merge: commenting
/deploy-previewon this PR builds it and publishes a Netlify preview atpr-1046--<site>.netlify.app. Only one PR can hold the alias at a time, because FNid does not allow wildcards in redirect URIs.Verifying it landed: the prod index is served
cf-cache-status: DYNAMIC, so it reflects the origin with no purge. Fetch/and confirm themain_<hash>.jsfilename changed;last-modifiedon the index dates the deploy. Bundle names are hashed, so no user hard-refresh is needed.Smoke test on Purchase Details: the Show canceled checkbox appears on all three views, Synced and Source Updated populate, and the By Item drill-down shows Canceled for a soft-canceled line inside a Paid order.
What changed
Payment Method survives a grain switch.
buildPurchaseLinesQuerydestructuredpaymentMethodaway and the control was hidden on the line views, so filtering to invoiced orders and clicking Line Items silently widened 22 items to 250. The lines endpoint now supports the filter, so it is carried at every grain. This also reaches the By Item rows and the lines CSV export, which share the same builder.Line rows show their own state, not the parent order's. Cancellation is soft and per line: a canceled line leaves its order Paid, so dead rows read "Paid" in both the Line Items manifest and the By Item drill-down. Both now branch on the line's own
is_canceled. Canceled lines still render, struck through; they are only excluded from the counts.Freshness on every view.
synced_atandsource_updated_atappended to the Orders table, the Line Items manifest, and the By Item drill-down, in that order, all through the existingformatCheckoutTime. On line rows these are the line's own values, not the parent order's.Refunds are visible on Orders. A refund never changes purchase status, so a fully refunded order read as a clean Paid on screen forever. The CSV already carried
refunded_amount; the table now does too, right-aligned to match the other money column.The chrome stops lying. Total Paid is labelled as gross (the figure is unchanged, deliberately: Total Refunded sits beside it). The Purchase Status control now states that canceled orders are excluded unless you select Canceled. The By Item chip no longer describes deliberately-filtered canceled orders as "purchased", and the per-sponsor line chip now says "live lines" since it counts only those.
Testing
Full suite green: 166 suites, 1520 tests. Every new assertion was verified by deliberately breaking the thing it guards and watching it fail, then reverting. That is how three weak assertions were caught and replaced: a freshness test that used one timestamp for two columns and so could not tell them apart, a header assertion that could not see a reordered column, and a copy guard that could not see the copy regress.
Known gaps, deliberately not addressed here
MuiFormHelperTexttoposition: absolute, and this instance overrides it back tostaticso it flows under the control.currencyAmountFromCentstakes a currency argument that neitherinvoice_total(pre-existing) norrefunded_amountpasses. Fixing only the new column would put two symbols on one row, so both want fixing together.