Commit graph

12 commits

Author SHA1 Message Date
David
2712326dbf Invoices: add PHI 169 (Rooihuiskraal)
Single line, TLB07-CASE 570 ST at 87.00 Hr x R280.00 = R24,360.00 ex VAT,
plus R3,654.00 VAT (15%) for R28,014.00. Escalation is zero, as on every
invoice in this run.

Extracted by coordinate and confirmed against the rendered page.

TLB07 is also on PHI 171 (Cosmo City) over the same period, which the
multi-site ruling covers, so both book to TLB07.

Verified through the real buildIncomeRows: September now totals R369,055.13
across 11 machines, matching the sum of all five invoice totals, with zero
unbooked lines and every machine's month cells equal to its own YTD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-02 06:44:10 +02:00
David
d7ccd7fa80 Invoices: add PHI 168 (Castle Gate)
Fifth line set from the September 2026 plant-hire run. All five codes map
cleanly to register assets, so nothing is left unbooked this time:
MPLANT05 to SC01, RV-01-CAT to RV01, TLB06-CASE to TLB06, TP601-TATA to
TP601, TP602-TATA to TP602.

Extracted by coordinate and confirmed against both rendered pages. The
R14,548.50 column is PLUS VAT (15%), not escalation - escalation is R0.00.

SC01 and TP601 each pick up a second site this period, which the multi-site
ruling covers, so those lines book to the same machine as before.

Verified through the real buildIncomeRows: September now totals R341,041.13
across 11 machines, matching the sum of all four invoice totals, and every
machine's month cells still equal its own YTD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-02 06:37:54 +02:00
David
63016895b9 Plant Register: inline editing, active toggle and cascade-delete impact
WIP carried over from the working tree, committed separately so it does not
sit inside the invoice work.

- inline Edit cells for code / name / type and an active toggle
- GET /api/assets/:id/impact returns the cascade counts so the client can
  confirm before a delete
- DELETE /api/assets/:id hard delete; PocketBase cascade clears the dependent
  income / running / cost-line rows

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-01 15:59:51 +02:00
David
baf0bddde6 Invoices: line-item extraction, booking to plant items, VAT-inclusive income
Adds an Invoices sub-menu under /income with a summary table (one row per
invoice, click to expand the full detail) and the data model behind it.

Data:
- invoices + invoice_lines PocketBase collections, created idempotently by
  scripts/setup-invoice-collections.mjs
- line items transcribed from PHI 166/167/171 with per-invoice arithmetic
  validation in the seed; a bad invoice is refused without blocking the rest
- invoice-*.json in data/source are auto-imported, so adding an invoice is
  one file

Booking:
- manual book-in per line (Booked to), grouped by category
- POST /api/invoice-lines/:id/book moves the income row rather than adding a
  second one, so a booking can be changed freely
- scripts/book-invoice.mjs is idempotent: rows are stamped with
  monthly_income.invoice_line and replaced on re-run
- booked amount follows lib/invoice-booking-policy.json (bookInclusiveVat),
  read by both the app and the CLI so they cannot disagree

Money:
- the R24,205.13 column on these invoices is PLUS VAT, not escalation. The
  seed now rejects VAT that disagrees with the stated rate.
- booked amounts are VAT-inclusive per the client ruling of 2026-10-01; the
  VAT stays visible rather than hidden.

Uploads:
- drag-and-drop PDF attached to invoices.source_pdf
- GET /api/invoices/:id/document proxies it — the collection is rule-locked,
  so a direct PocketBase /api/files link 404s in a browser

Fixes a month-aggregation bug this introduced: buildIncomeRows assigned into
months[i], so a machine with two income rows in one month (one per invoice,
which is normal multi-site use) showed only the last. SS01 September read
R20,700 instead of R35,305 while its own YTD included both. Months now
accumulate, per-month profit is computed once after accumulation, and
lib/rows.test.ts pins it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-01 15:59:30 +02:00
Mega Plant
348395275a Add Umami analytics script to <head>
- src: https://umami-vmyngbmelll45wokwr270wbx.169.239.180.130.sslip.io/script.js
- data-website-id: 86d0bd41-e705-4677-af2d-a4228e7c4b95
- loaded with defer (matches the user's requested snippet)
- placed in <head> of app/layout.tsx so every route is tracked
2026-09-13 19:00:52 +02:00
Mega Plant
2f57a0c25f Brand logo: 3D cube/map icon replaces the M gradient mark
- public/brand/logo.png: 117×115 transparent PNG (source)
- public/icons/icon-192.png, icon-512.png, icon-maskable-512.png: PWA icons derived from logo
- public/icons/favicon.png (64), favicon-32.png (32): favicon sizes
- icon-maskable-512: logo on #003D5B indigo background, 80% safe zone
- layout.tsx: header logo + mobile drawer logo both use the new image
- Sidebar.tsx: drawer header logo uses the new image
- metadata.icons updated to include favicon sizes
- <link rel='icon'> added for 32×32 and 64×64 favicons
2026-09-12 12:12:30 +02:00
Mega Plant
0516220110 Round 4: regressions fixed + mobile standard
Part A — Round 3 regressions:
- A.1: verify-cost-reconciliation.mjs now loads .env.local, wraps in try/catch, exits 1 on any failure
- A.2: Vehicle Costs restored Santam — back to R 14,996.31 (matches row-by-row sum)
- A.3: incl<excl / VAT math / VAT>20% now FATAL — seed exits 2 with full report (4 anomalies on Charl-CCS + Buildsmart)
- A.4: Reconciliation target R 694,962.93 with both deltas itemised (Personnel +R19,800, Santam -R5,322.44, unexplained R 0.00)
- A.5: 'Lines' view uses actual lines (recharts LineChart), no fills; fills only in 'Cost stack'

Part B — Mobile standard:
- B.1: header wraps to 2 rows on mobile; YTD badge cards stack; page-wide overflow eliminated on /income, /charts, /overheads, /running, /expenses
- B.2: IncomeView card row layout stacked — name gets its own line on mobile, never truncated to single char
- B.3: Plant type filter is a <select> dropdown below lg (was 18 pills wrapping to 13 rows); same for sort on /income and /running
- B.4: Plant table first column sticky; -webkit-overflow-scrolling: touch; tables scroll inside their own container
- B.5: All buttons/links use min-h-[44px] tap targets; text below 12px is bumped where it matters
- B.6: Charts legend wraps below title; chart min-height h-44 → h-52 on mobile
- B.7: paddingTop env(safe-area-inset-top) on sticky header for notch/home indicator clearance

AGENTS.md created with the standing mobile checklist rule.
2026-09-12 12:05:43 +02:00
Mega Plant
7194e78079 Round 3 (Parts A-B): charts fixes + expenses/overheads cleanup
- A.1: fixed_expenses per month now threaded through to chart bucket
- A.2: null = no data (forecast), 0 = real plotted zero — distinguishable
- A.3: x-axis clipped to last actual month (IncomeAreaChart + IncomeBarChart + MachineLineChart)
- A.4: chart hues as CSS vars (--color-chart-income/fixed/running) — deeper steps of same hues, validated for CVD
- A.5: chart-type toggle (Lines / Cost stack / Profit) + localStorage persistence + dynamic legend
- A.6: profit on charts page comes from computeProfit()
- B.1: deleted /expenses/plant-overheads, /expenses/insurance, /expenses/tracking (all empty); added /expenses/vehicles; ExpenseSectionPage now has an empty state
- B.2: captured R 157,200 Personnel block, R 100,000 Maintenance, R 10,000 Petty Cash; roll-up reconciles to R 675,162.93 (= sum of non-Plant non-Santam rows; workbook grand total R 1,110,486.87 is internally off by R 14,477.56 vs its own rows)
- B.3: seed flags incl<excl, VAT>20%, broken VAT math — does NOT silently correct; 4 anomalies reported on Charl-CCS + Buildsmart
- B.4: noted that workbook Vehicle Costs subtotal skips Santam (app R 9,673.87 is correct; workbook is wrong)
- B.2 reconciliation assertion added to verify-cost-reconciliation.mjs
- Sidebar updated: Vehicles added, Insurance/Tracking/Plant-Overheads removed
2026-09-12 11:24:18 +02:00
Mega Plant
b70fc8c5c7 Round 2 (Parts B-D): asset register restructure, type field, sequential codes, flat sortable table, cost_lines, removed synthetic code, fail loudly
- B.1: removed running_cost from PB monthly_income schema
- B.2: 40 of 40 machines now have income (was 32/40)
- B.3: removed syntheticCode() + auto-create branch; deleted 2 ghost Z* assets; seed fails loudly on unmatched
- C.1: collapsed 13 cost-component rows into 5 machines + new cost_lines collection; Finance/Insurance/Tracking categories removed from assets
- C.2: type field on assets derived from code prefix
- C.3: sequential codes SC01-07, OC01-02, PC01-02; fixed SITE CONTANER spelling
- C.4: flat sortable plant register table with type filter pills
- C.5: wired filter input on plant register
- D: verified term 2 (insurance) reconciles for all 5 financed machines
2026-09-12 10:24:26 +02:00
Mega Plant
dfb52a45fe Ignore tsconfig.tsbuildinfo (regenerated by tsc) 2026-09-12 09:48:50 +02:00
Mega Plant
c863a88ae5 Auto-create synthetic assets for unmatched machines in seed; update open-questions report 2026-09-12 09:40:18 +02:00
Mega Plant
acf9d52e5f Mega Plant dashboard — fix & harden (Parts 0-5) 2026-09-12 09:35:48 +02:00