Commit graph

21 commits

Author SHA1 Message Date
SJCoetz
965f3e3bbe docs(pdf): restore poSubtotal JSDoc + clarify fallback uses || not ??
Co-authored-by: Orca <help@stably.ai>
2026-08-06 11:56:51 +02:00
SJCoetz
b3d9eeb5ce feat(pdf): add poSubtotal helper for PO PDF totals
Co-authored-by: Orca <help@stably.ai>
2026-08-06 11:54:23 +02:00
SJCoetz
76947a9711 chore(stock): remove Location from PDF and UI
The single office bin is the only location, so the field is
unused. Strip it from everywhere the operator sees it:

PDF (stock-item-stocktake-document.tsx):
- Drop Location column + gapMaxLocation from styles, header, rows
- Re-balance widths: Name 23% → 28%, Status 12% → 18%
  (the freed space makes Name properly readable again)

Stock list page (src/app/(app)/stock/page.tsx):
- Drop Location TableHead + TableCell
- Drop location state + input + submit-handler field from the
  New stock item modal
- Drop 'location' from the modal JSDoc field list

Stock detail page (src/app/(app)/stock/[id]/page.tsx):
- Drop the MapPin + item.location display in the header
- Drop the now-unused MapPin import from lucide-react

Fulfill-from-stock dialog (src/components/stock/fulfill-from-stock-dialog.tsx):
- Drop location from the search predicate
- Drop location from the placeholder text
- Drop the '· {item.location}' display in the row

Note: the location field stays on the StockItem type and PB
schema for backward compatibility — removing it from the type
would break any code that still references it, and removing it
from the PB schema is a backend migration. The field is just
no longer surfaced anywhere.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 19:34:56 +02:00
SJCoetz
532f1986e4 feat(stocktake-pdf): add Location column, sort by supplier name
PDF:
- Add Location column between Max and Status (4% gap on each side)
- Re-balance widths: Name 28% → 23%, Status 18% → 12% to make room
- Total still 100% (with consistent 4% gaps between data columns)
- Update JSDoc to reflect new column + sort

Service:
- Sort by expanded supplier name (with item name as secondary sort)
- Items without a supplier sort to the end
- PB-side sort becomes 'supplier,name' so the JS comparator does
  fewer swaps on large lists
- PB can't sort by an expanded relation's field, so the JS
  re-sort is what actually produces the printable grouping

Tests:
- Update mock to handle 'expand: supplier' and populate
  expand.supplier.suppliername on each row
- Update mock to handle comma-separated sort lists (PB accepts
  'supplier,name')
- Add a 'sorts items with no supplier to the end' test
- Update existing sort test to cover multi-supplier grouping

Co-authored-by: Orca <help@stably.ai>
2026-08-03 19:21:50 +02:00
SJCoetz
0cecc7208f polish(stocktake-pdf): widen SKU→Name gap so the separation is visible
The previous 2% gapSkUName was too subtle to read as a column
separator — it was being absorbed by the empty space at the end
of the SKU column. Bumping to 4% (and trimming Name from 30%
to 28% to keep the total at 100%) makes the gap clearly visible
regardless of how long the SKU text is.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 19:06:39 +02:00
SJCoetz
b506670dde polish(stocktake-pdf): status anchors right edge, gaps between columns
- Add width: 100% to table/thead/tr so the row actually fills
  the landscape A4 page width (was collapsing to ~70% of page)
- Move Status to the rightmost column with right-aligned bold
  'Out of stock' as the visual anchor operator scans for
- Drop the trailing spacer column
- Re-balance widths: Name gets the lion's share (30%), Supplier
  shrinks (11%), Current/Min/Max narrower (6/5/6%) and pushed
  further right with explicit gap columns
- Small 2% gap between SKU and Name, 4% gaps between the
  other pairs so the eye groups {SKU, Name, Supplier} as 'what'
  and {Current, Min, Max, Status} as 'how much / how urgent'

Co-authored-by: Orca <help@stably.ai>
2026-08-03 19:00:29 +02:00
SJCoetz
b84aefc2e2 feat: unify buyer task flows by supporting both customer orders and stock purchases in mark-ready API and UI, and fix PDF table layout responsiveness. 2026-08-03 18:52:30 +02:00
SJCoetz
21c54ad24e fix(stocktake-pdf): add cell padding so columns have visible gaps
The previous layout had numeric columns (Current, Min, Max —
right-aligned) flush against the Status column (left-aligned).
A row like '100In stock' read as a single mashed string
because there was no whitespace between the right edge of the
Max column and the left edge of the Status column.

Fix: add paddingRight: 8 to the three numeric columns and
paddingLeft: 8 to the Status column. Right-aligned numbers
now end 8pt before the column boundary, and the Status text
starts 8pt inside its column — visible gap between columns,
even with the Status sitting right next to Max.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 18:29:25 +02:00
SJCoetz
a35e715b21 polish(stocktake-pdf): zebra rows, drop Location, Target→Max, prominent Status, wider Name
Visual layout cleanup on the Stocktake PDF:
- Zebra-stripe alternating rows (subtle slate-50 on even rows,
  white on odd) so adjacent rows scan easily.
- Drop the Location column — one less thing to fit on the page,
  and the operator has the /stock detail page for that.
- Rename the Target column header to 'Max' (user-facing naming).
- Move the Status column to the right edge and make it bold +
  colour-coded using STOCK_STATUS_STYLES[status].hex, matching
  the on-screen badge palette.
- Widen the Name column (18%→24%) so full stock-item names read
  in one line for most rows.
- Redistribute remaining widths so the table still totals 100%
  of the landscape A4 page width.

Column widths now: SKU 10 / Name 24 / Supplier 18 / Current 9 /
Min 8 / Max 9 / Status 16 / spacer 6 (= 100%).

Co-authored-by: Orca <help@stably.ai>
2026-08-03 18:23:11 +02:00
SJCoetz
6033aba18d fix(stocktake-pdf): match /stock columns + add button on /stock page
The original Stocktake PDF columns (Name, SKU, Location, Unit,
Current qty, blank Actual, Supplier) didn't match what the
operator sees on /stock. They pointed at the wrong list — they
worked for a blank-column walk-through stocktake form, but the
user wants to print the /stock list as it appears on screen.

This rewrite makes the Stocktake PDF mirror the /stock table
column-for-column:
- SKU, Name, Supplier, Current, Min, Target, Location, Status
- Status derived via getStockStatus + STOCK_STATUS_STYLES so
  it matches the on-screen badge label
- Current qty now renders with the unit suffix (matching the
  on-screen cell)
- Target renders '—' when null/undefined/0, matching /stock

Also:
- Switched to landscape A4 to give 8 columns room (was
  portrait).
- Added a copy of the 'Download Stocktake PDF' button on the
  /stock page next to 'New stock item' — both /stock and
  /stock-orders now expose the same endpoint. Button uses the
  same plain <a target='_blank' rel='noopener'> pattern as
  the existing stock-orders buttons, with aria-hidden on the
  Download icon.
- Added a test on /stock for the new link (href, target,
  rel). 33/33 tests pass.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 18:18:58 +02:00
SJCoetz
907a7414b4 fix(pdf): repeat table headers on every page in list reports
Move the thead <View> out of the table and onto the page itself
with the @react-pdf/renderer 'fixed' prop, so reports that span
multiple A4 pages still label their columns. Without this, page 2+
of a long stock-orders report or stocktake would show data without
column headers — making the right-hand 'Actual' column on the
stocktake and the value columns on the orders list unreadable.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 16:23:12 +02:00
SJCoetz
45f1ec6bb7 feat(pdf): list-pdf documents for stock orders + stocktake
Two new @react-pdf/renderer documents backed by renderStockPurchaseListPdf
and renderStockItemStocktakePdf in render.tsx. The Orders PDF mirrors
the on-screen table; the Stocktake PDF adds a blank 'Actual' column
for the operator to fill in during the walk-through. Both inherit
the toString() → Buffer pattern so they run under the same jsdom
test setup as the other PDF renderers.

Co-authored-by: Orca <help@stably.ai>
2026-08-03 16:13:14 +02:00
SJCoetz
4444842ef5 feat: collection-map updates, todays-stops, quote/approval rework, buyer-tasks, e2e
- Add todays-stops test and component to collection-map
- Expand collection-map sidebar and pin-model
- Rework orders/[id]/process page
- Add quotes/[id]/page and process pages
- Add quotes/approvals/[id] page
- Add buyer-tasks generate-po route
- Add quotes partial-approve and pdf routes
- Add purchase-orders [id]/pdf route
- Add e2e create-flows spec
- Add superpowers plan doc
- Update pb_schema-2.json
- Update form components (company, customer, order, quote, supplier)
- Update UI components (button, command, dialog)
- Add collection-pool test components

Co-authored-by: Orca <help@stably.ai>
2026-08-03 09:33:45 +02:00
SJCoetz
7a68cafe35 chore: add logos, opencode config and build assets
This commit includes the temporary Next.js build cache files, public brand
logos, and project configuration added in this change.
2026-07-27 08:21:20 +02:00
SJCoetz
d306b75bdb feat(stock-purchases,driver-app): add stock purchase workflow and driver pickup support
Add complete stock purchase order workflow including:
- Status tracking with sending/mail_failed states and UI labels
- Server-side PDF rendering and document storage
- File proxy API support for stock PO attachments
- Send outcome webhook callback for email notifications

Add driver app support:
- Unified stop list API for both customer deliveries and stock pickups
- Status update endpoint for collected quantities and problem reporting
- Collection map page support for stock pickup locations

Include matching PocketBase migrations, type definitions, and stock inventory fulfillment logic.
2026-07-18 22:43:50 +02:00
SJCoetz
ae88a2f3bc feat(invoicing): add complete delivery note workflow
This commit adds the full end-to-end delivery note workflow for the invoicing system:
- Added `letterheadForCompany` utility to infer the correct letterhead from a company name
- Created the DeliveryNoteDocument PDF component and server-side render function
- Added API endpoints for delivery note creation, PDF retrieval, printing, and print tracking
- Updated the PickingSlip component to support both invoice and delivery note headers
- Added view models for grouping, filtering, and displaying delivery note items
- Updated AGENTS.md with PocketBase schema and attachment best practices for new workflows
- Added comprehensive test coverage for all new components and API routes
2026-07-14 17:35:36 +02:00
SJCoetz
7f924ccc45 refactor: switch hardcoded UI colors to semantic theme tokens
Overhaul the app's color system by replacing all hardcoded Tailwind color classes with semantic theme variables to ensure consistent theming across all components, pages, and tests.

Additional changes:
- Add assigned date support for order item status updates: add `assignedDate` field to the order item status PATCH API, implement server-side normalization/validation, and add corresponding tests
- Refactor purchase order PDF workflows to use the consolidated `purchase_orders.documents` field instead of the legacy separate `purchase_order_pdfs` collection
- Fix quote number parsing and formatting to support both dashed (Q-YYYY-MM-NNN) and dashless (QYYYYMMNNN) formats
- Rename `driver_pool` item status to `collection_pool` across the codebase
- Add null handling for order item quantities and pricing to display "—" for missing values
- Improve filter tab styling: make mobile tabs scrollable, prevent text wrapping, hide scrollbar
- Add new utility scripts, API routes, migrations, and polish small UI/UX fixes including tsconfig updates and theme hook improvements
2026-07-07 17:22:03 +02:00
SJCoetz
9cdcb3b096 feat: implement sku-based catalogue pricing matching workflow
This commit adds the full end-to-end SKU pricing match flow for quote items:
- Add new QuoteItem and PriceListRow fields for SKU and pricing metadata
- Add sku_normalised to price_list for robust format-agnostic SKU matching
- Refactor price list search to use modular search builder and filter helpers
- Add database migrations, backfill scripts, and new package commands
- Update catalogue search UI and fix quote list accidental click behavior
- Add comprehensive unit, smoke, and end-to-end test suites
- Update documentation for the new price search and extraction logic
2026-06-30 21:20:53 +02:00
SJCoetz
6c07a91693 refactor: drop order-level status, shift to item-driven workflow
This commit overhauls the order management system to use item-level status tracking instead of a single order-level status:
- Remove deprecated `orders.status` field and add `invoiced` and quote match audit fields
- Add `isOrderComplete` utility with tests to validate fully delivered orders
- Add purchase order PDF rendering support and tooling
- Add geo coordinate fields for companies/customers with map link UI
- Add REST management APIs for customers, companies, and suppliers
- Update customer/company services to use relation fields instead of free text
- Add status pill and tab filter components for item status visualization
- Add quote-to-order matching logic and unit tests
- Update all pages, components, and tests to match the new schema
- Include all required PocketBase migrations and schema updates
2026-06-29 13:06:01 +02:00
SJCoetz
588e9762c2 feat: add quote templates, improved email, new statuses
Add complete quote template functionality, enhanced outbound email sending, new quote statuses, and supporting infrastructure:
- Add new quote statuses (template, sending, mail_failed) with tailored UI styling for status pills
- Implement full template workflows: save real quotes as templates, create new quotes from existing templates
- Add support for custom quote dates and extended validity periods on generated PDF documents
- Build out improved email pipeline with persisted compose fields and retry functionality for failed sends
- Add attachment direction tracking to categorize inbound, outbound, and generated quote attachments
- Fix tooltip component to properly handle Radix `asChild` prop to avoid React DOM attribute errors
- Add comprehensive test coverage, schema migrations, and update sample test and production data
2026-06-24 22:57:01 +02:00
SJCoetz
714e910949 feat: add branded quote PDF generation and in-app viewer
This commit adds full quote PDF generation functionality with per-company letterhead branding:
- Server-side PDF rendering using @react-pdf/renderer matching the sample quote layout
- In-app modal PDF viewer with print, download, and new-tab controls
- Letterhead service to fetch and apply company-specific branding (CNL/ISHERWOOD)
- ZAR currency and date formatting utilities for South African quotes
- Updated QuoteAttachment type to handle PocketBase's array-based file tokens
- Fixed PocketBase attachment URL generation in quote email card
- Removed deprecated `included_in_quote` field from QuoteItem and quotes service
- Updated quote item creation test to validate draft item logic
- Added comprehensive unit tests for PDF rendering and formatting helpers
- Added dev scripts for debugging PDF and image rendering issues
- Added sample generated PDF files for visual verification
- Updated tsconfig to exclude development scripts directory
- Added @react-pdf/renderer production dependency
- Removed JEI as a valid letterhead option per requirements
2026-06-23 08:30:38 +02:00