Files
Joshua OosthuizenandClaude Sonnet 5 4acbc03b35 Initial commit: multi-company financial management system
Root company app (src/, client/) — GL foundation, AR, and AP:
- Segmented Chart of Accounts (Sage 300-style), double-entry PostingService with
  three-layer balance enforcement (app validation, CHECK constraints, deferred
  DB trigger), gap-free document numbering, RBAC with branch restrictions.
- Accounts Receivable: Customers, Invoices, Credit Notes, Receipts with
  allocation, all posting through PostingService.
- Accounts Payable: Suppliers, Supplier Invoices, Debit Notes, Payments with
  allocation, mirroring AR's posting pattern.
- Tax Codes shared between AR and AP.
- Company-app login is a token handoff from the Account Manager (RS256,
  single-use, company-scoped) rather than a local password.
- Frontend reskinned to the approved mockup: navy sidebar, dashboard, tree-view
  Chart of Accounts, Customer/Supplier 360 pages.

Account Manager (manager/, manager/client/) — central login gateway:
- Password + TOTP 2FA + Google/Microsoft OAuth, company picker, and the RS256
  handoff token issuance that the company app verifies.

Covered by unit + integration tests against a real Postgres database (GL
balance invariants, AR/AP posting correctness and allocation limits, the full
handoff exchange including replay/cross-company/expiry/forgery rejection).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tq2DbEvzHzs13jDFhLaX44
2026-09-03 13:27:19 +02:00

6.7 KiB

Phase 2 — Accounts Receivable: Manual Test Checklist

Adds Customers, Tax Codes, AR Invoices, Credit Notes, and Receipts with allocation — all posting through the existing PostingService, so every one of these creates a real, balanced GL entry you can trace from the Journal Entries screen. Backend correctness (balanced postings, tax calc, allocation limits) is already covered by tests/integration/ar.posting.spec.ts (7 tests, passing) and was additionally verified by hand over the real HTTP API end-to-end. This checklist is for the parts only a human can judge: does the UI make sense, does the data look right, does it match how the business actually invoices customers.

Start the same four dev servers as Phase 1.5 (see PHASE_1.5_TEST_PLAN.md §0) and sign in through the Manager.

0. New nav items

  • Sidebar shows a new Sales section above General Ledger: Customers, Invoices, Receipts
  • Administration section has a new Tax Codes item at the bottom
  • Two tax codes are pre-seeded: STD (15%) and ZERO (0%) — visible at /admin/tax-codes

1. Tax Codes

  • "New Tax Code" creates a code (e.g. EXPORT, Zero-Rated Export, 0) and it appears in the grid
  • Toggling a tax code's Active switch off, then back on, works
  • A tax code is usable immediately on new invoice/credit note lines without a page refresh

2. Customers

  • "New Customer" requires a branch selection; creating one without a branch shows an error
  • A created customer appears in the Customers grid with the right code/name/credit limit/terms
  • Switching the top-right Branch switcher to a single branch filters the Customers grid to that branch only; switching back to Main shows all
  • Clicking a customer row opens their Customer 360 page

3. Customer 360

  • Header shows the customer's name and an Active/Closed status pill
  • Four summary tiles: Outstanding Balance, Overdue (30+ days), Credit Limit, Payment Terms
  • A brand-new customer with no invoices shows R0.00 everywhere, not blank or broken
  • Contact Details card shows code/email/phone/tax number (or "—" for anything empty)
  • Three tabs — Invoices / Payments / Credit Notes — each show "No … yet." until you create one
  • "New Invoice" and "Receive Payment" buttons only appear if you have the AR permissions (test with a restricted role, or trust the code path — both gate on ar.invoice.manage / ar.receipt.manage)

4. Creating and posting an invoice

  • From Customer 360, "New Invoice" opens the invoice form with that customer pre-selected
  • Due date auto-fills from invoice date + the customer's payment terms and is read-only
  • Adding a line, picking a revenue account (only INCOME-type accounts for that customer's branch are offered) and a tax code updates that line's Amount live
  • Applying the STD (15%) tax code to a R1,000 line shows R150 tax and R1,150 line total
  • The footer Subtotal / Tax / Total roll up correctly across multiple lines with different tax codes (including a line with no tax code — contributes 0 to tax)
  • "Save Draft" creates the invoice with status DRAFT and does not create a GL entry — confirm by checking General Ledger's entry count is unchanged
  • From the draft's detail page, "Post Invoice" posts it — status flips to POSTED, and a new entry appears in General Ledger (journal SALES) that is balanced (Debits = Credits)
  • Opening that GL entry shows: one debit line to the AR Control account for the invoice total, one or more credit lines to the revenue account(s) for the subtotal(s), and (if tax was applied) a credit line to Output Tax Payable for the tax total
  • "Post Invoice" directly from the form (skipping the separate detail-page click) also works and lands you on the now-posted invoice
  • A draft invoice can be Voided (status → VOID, no GL entry ever created); a posted invoice has no Void option — only a credit note can reverse it
  • The invoice now appears in the customer's Invoices tab and in the global Invoices list, with the correct balance and status pill

5. Receiving a payment

  • From Customer 360, "Receive Payment" opens the receipt form with the customer pre-selected
  • "Deposited to" only offers accounts marked as a Bank control account
  • Saving and posting a receipt for the invoice's exact total creates a balanced GL entry: debit to Bank, credit to AR Control, journal CASH_RECEIPT
  • The posted receipt's detail page shows an "Allocate Against Invoices" panel listing the customer's open (posted, balance > 0) invoices
  • Clicking "Full" next to an invoice fills in its exact remaining balance (capped at what's still unallocated on the receipt)
  • Applying the allocation reduces both the invoice's balance and the receipt's unallocated amount by the applied amount — reload both pages and confirm the numbers persist
  • Fully allocating a receipt makes the "Allocate" panel show "Fully allocated." instead of the invoice table
  • Attempting to allocate more than a receipt's unallocated amount, or more than an invoice's balance, is rejected with a clear error and changes nothing
  • A part-paid invoice shows the correct partial balance on its detail page and in the Customer 360 Invoices tab

6. Credit notes

  • Create a credit note for the same customer, one line mirroring a posted invoice line (same account, same tax code, same amount)
  • Posting it creates a GL entry that is the mirror image of the invoice's: debit to the revenue account (+ debit to Output Tax if taxed), credit to AR Control — and is balanced
  • The credit note's detail page shows the same "Allocate Against Invoices" panel; allocating it against the open invoice reduces both the invoice's balance and the credit note's remaining balance
  • A draft credit note can be voided; a posted one cannot

7. Cross-cutting checks

  • Every invoice/receipt/credit note number follows its own series (ARINV-2026-######, ARRCT-2026-######, ARCN-2026-######) and never repeats or skips oddly between runs
  • The Dashboard's "Posted Movement by Account Type" bars now reflect AR activity (ASSET bar grows from AR Control + Bank movement, INCOME bar grows from Sales)
  • Switching to a specific branch (not Main) on any AR screen shows only that branch's customers/invoices/receipts
  • No console errors in the browser dev tools while working through this checklist

Once this is ticked (or you've flagged issues), the plan's next step is Accounts Payable — Suppliers, Supplier Invoices, Debit Notes, Payments — built the same way, followed by Tax reporting and then Stock Control.