feat(orders): show where an Uber trip went, in the list
ci / lint-test (push) Failing after 41s

Five rows all reading "Order - Uber Trip" are indistinguishable — the list gives
you a date and an amount and nothing to tell one ride from another (user,
2026-07-27). Where the trip went is exactly what separates them, and it was
already stored on expense_metadata.route since this morning; nothing in the list
read it.

getTransactions now joins the receipt (both directions — transaction_id OR
matched_transaction_id, since a card-settled order points at the statement line
instead) and the description cell renders "Terminal 2, Melbourne Airport (MEL)
→ 19 Lady Penrhyn Dr" in the same italic sub-line notes use.

Two deliberate limits:

- **A note the user wrote always wins.** This only fills an empty sub-line; it
  never occupies the notes field, which is theirs.
- **Deliveries are excluded.** Their merchant already identifies them, so the
  restaurant's street address would be clutter on every food order. Gated on
  platform = 'uber'.

The summary keeps the first two comma-segments of each address — a truncation,
not a guess about geography. Uber puts the venue or street first, which is the
identifying part; the full stops with their times stay in the title attribute.
This commit is contained in:
2026-07-27 11:43:55 +10:00
parent 6161ddc9de
commit 3bb67f370d
3 changed files with 107 additions and 3 deletions
+52
View File
@@ -253,3 +253,55 @@ describe("getParticipantBalances", () => {
expect(bobBalance!.unsettled_count).toBe(2);
});
});
describe("getTransactions — order provenance for the description sub-line", () => {
it("carries the route and platform of an order-derived row", async () => {
// Five rows all reading "Order - Uber Trip" are indistinguishable in the
// list; where the trip went is the only thing that separates them, and it
// was already stored.
const { ownerId } = await seedParticipants(pool);
const txId = await insertTransaction(pool, ownerId, { description: "Order - Uber Trip" });
await pool.query(
`INSERT INTO expense_metadata (source, order_reference, platform, route, transaction_id)
VALUES ('email', $1, 'uber',
'[{"label":"Pick-up","time":"7:32 pm","address":"Terminal 2, Melbourne Airport (MEL), Tullamarine VIC 3045, Australia"},
{"label":"Drop-off","time":"8:10 pm","address":"19 Lady Penrhyn Dr, Wyndham Vale VIC 3024, Australia"}]'::jsonb,
$2)`,
[`route-${Date.now()}`, txId]
);
const { data } = await getTransactions(ownerId, { limit: 50, offset: 0 });
const row = data.find((r) => r.id === txId)!;
expect(row.order_platform).toBe("uber");
expect(row.order_route).toHaveLength(2);
expect(row.order_route![0].address).toContain("Melbourne Airport");
});
it("resolves from the statement line for a card-settled order", async () => {
// A card-settled order creates no transaction of its own (I5) — the
// receipt points at the statement line through matched_transaction_id.
const { ownerId } = await seedParticipants(pool);
const txId = await insertTransaction(pool, ownerId, { description: "UBER *TRIP AUCKLAND" });
await pool.query(
`INSERT INTO expense_metadata (source, order_reference, platform, route, matched_transaction_id)
VALUES ('email', $1, 'uber',
'[{"label":"Pick-up","time":null,"address":"64 Federal Street, Auckland 1010, NZ"},
{"label":"Drop-off","time":null,"address":"International Terminal, Auckland 2022, New Zealand"}]'::jsonb,
$2)`,
[`route-card-${Date.now()}`, txId]
);
const { data } = await getTransactions(ownerId, { limit: 50, offset: 0 });
const row = data.find((r) => r.id === txId)!;
expect(row.order_route).toHaveLength(2);
});
it("leaves an ordinary transaction with no route", async () => {
const { ownerId } = await seedParticipants(pool);
const txId = await insertTransaction(pool, ownerId, { description: "COLES 1234" });
const { data } = await getTransactions(ownerId, { limit: 50, offset: 0 });
const row = data.find((r) => r.id === txId)!;
expect(row.order_route).toBeNull();
expect(row.order_platform).toBeNull();
});
});