Skip to content

Fix payments sorting lexicographically instead of numerically by amount - #228

Open
aalavala wants to merge 1 commit into
JJFromTenex:mainfrom
aalavala:fix/payment-amount-sort
Open

aalavala wants to merge 1 commit into
JJFromTenex:mainfrom
aalavala:fix/payment-amount-sort

Conversation

@aalavala

Copy link
Copy Markdown

What changed

Sorting payments by amount was comparing amounts as strings instead of numbers, so a shorter amount with a high leading digit (like 994) could rank above a larger amount (like 9873) on both /payments and GET /api/payments?sort=amount. Amounts now sort by actual numeric value.

How I verified it

npx vitest run src/data/queries.test.ts against the old comparator — failed as expected:

✕ sortPayments > orders amounts numerically, not lexicographically
  expected [ 'pay_small', 'pay_large' ] to deeply equal [ 'pay_large', 'pay_small' ]

After the fix, same test passes, and npm test — 4 files, 29 tests, all passing (money/date/csv unaffected, queries.test.ts is new).

Checked live against the running dev server: curl "http://localhost:3000/api/payments?sort=amount&direction=desc" — top 5 are now 47980, 47935, 47880, 47826, 47778 (strictly decreasing; previously three- and four-digit amounts were interleaved out of order).

Acceptance criteria

(No ticket for this — these are the asks from the bug report itself.)

  • Find the root cause: file and line, why it produces the result, whether the same pattern exists elsewhere.
  • Fix the root cause.
  • Add a unit test that fails on the old comparator and passes on the new one.
  • Show the top five payments by amount for manual verification.

Deliberately not done

  • No ticket filed in docs/tickets/ for this — it was found ad hoc while manually testing the export feature, not from a tracked backlog item.
  • Didn't add a lint rule or broader test guard against localeCompare being misapplied to a non-string field elsewhere in the future — this fix is scoped to the one confirmed instance.
  • The export route (GET /api/payments/export) calls the same sortPayments, so it's fixed automatically, not as a separate change — worth knowing it's a shared fix surface, not something addressed twice.

sortPayments compared String(amount).localeCompare(String(amount)) instead
of the numbers themselves, so a shorter amount with a higher leading digit
(e.g. 994) ranked above a longer, larger amount (e.g. 9873) — visible on
/payments and GET /api/payments with sort=amount.

Every other localeCompare in the codebase sorts ISO date strings, which is
safe (fixed-width, lexicographic order matches chronological order); this
was the only place applying string comparison to a number. analytics.ts
already sorts numerically elsewhere (b.volume - a.volume) — this fix
matches that existing pattern instead of introducing a new one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant