Renames the existing /income/invoices page to "Internal Invoices" and adds a sibling /income/external-invoices page, splitting ONE `invoices` collection by the debtor printed on the invoice: a Mega group company is internal, anything else is external. Never two collections. An invoice must not be able to exist on neither page, and the halves must stay reconcilable against /income. Both routes render through the single components/InvoiceRegisterPage.tsx so they cannot drift apart. lib/invoice-party-policy.json holds the group entity list and lib/invoice-party.ts does the matching. Matching is on debtor name OR debtor_no, never name alone: all three external invoices (PHI 178/186/192) carry an empty debtor name and only a third-party number, so a name-only match would misfile every one of them. An invoice naming neither is never internal - it lands on External and is reported as unclassified rather than silently filed. The split is 16 internal / 3 external across the 19 invoices in the register. Also fixes three things the split would otherwise break: - Booking a line, importing a PDF and retrying an intake can all land on either side depending on the debtor, so the five write paths only revalidated /income/invoices and would have left the other page stale. They now call revalidateInvoicePages() from lib/invoice-revalidate.ts. Route paths live in lib/invoice-routes.ts, which imports no next/* so a client component may import it; the revalidate helper imports next/cache and is server-only. - A site's "Go and assign them" link hard-coded the internal path, so a site whose outstanding lines sit on external invoices would dead-end. SiteSummary now carries the outstanding lines split by party. - verify-auth-routes.mjs now covers the new route. The two routes are siblings by design: isGroupActive matches a child by path prefix, so a nested /income/invoices/external would highlight both leaves at once. Verified: typecheck clean, 41 tests pass (7 new), production build green, anonymous access to both routes 307s to /login, and the mobile checklist passes at 375x812 and 768x1024 - no horizontal page scroll, no tap target under 44px, no text under 12px. The nested line-item table still scrolls inside its own container without stretching the outer table. Note: lib/rows.ts, lib/server-data.ts and the running/insurance feature are someone else's in-flight work and were deliberately left uncommitted here.
19 lines
No EOL
1,004 B
TypeScript
19 lines
No EOL
1,004 B
TypeScript
import { revalidatePath } from "next/cache";
|
|
import { INVOICE_PATHS } from "./invoice-routes";
|
|
|
|
// SERVER-SIDE ONLY — imports `next/cache`, so nothing client-side may pull this in. Route
|
|
// paths live in ./invoice-routes.ts for exactly that reason.
|
|
//
|
|
// Every mutation path must refresh BOTH halves of the register. Booking a line, importing
|
|
// a PDF and retrying an intake can all land on either page depending on the debtor, so
|
|
// revalidating only one leaves the other showing stale rows.
|
|
//
|
|
// Revalidating a page that did not change costs a re-render, not correctness — so the
|
|
// asymmetry is free to fix and expensive to miss. Use `revalidateInvoicePages` instead of a
|
|
// bare `revalidatePath` for anything that writes to `invoices` or `invoice_lines`.
|
|
|
|
// `extra` covers other routes a write may have moved, e.g. /income, whose totals shift
|
|
// when income posts.
|
|
export function revalidateInvoicePages(...extra: string[]) {
|
|
for (const p of [...INVOICE_PATHS, ...extra]) revalidatePath(p);
|
|
} |