Commit graph

60 commits

Author SHA1 Message Date
SJCoetz
5959d2a1aa fix(buyer-tasks): keep mail_failed POs visible in the PO Draft tab
The po_draft filter previously required po.status === 'draft', so
a failed send (status: 'mail_failed') caused the group to vanish
from buyer-tasks entirely. The only recovery path was the per-PO
Resend button on the order detail page, which is friction. Now
mail_failed groups stay in place so the operator can re-open the
SendPoModal and retry from the same list. po_sent is unchanged— mail_failed must not appear there.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 10:46:32 +02:00
SJCoetz
964b3d51b2 feat(buyer-tasks): surface email_error on buyer task groups
Adds an emailError field on BuyerTaskGroup so the UI can render
the send-pipeline failure reason. The value is truncated to 200
chars at the service boundary to keep the card layout bounded.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 10:31:33 +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
e2896264f4 fix(collection-confirm): add route validation + server-side actor derivation
Co-authored-by: Orca <help@stably.ai>
2026-08-03 02:35:58 +02:00
SJCoetz
dbf02e2511 fix(collection-confirm): restore Book to stock for stock rows + cost guard
Restores the 'Book to stock' action that the page rewrite in f7d3032 dropped from collection-confirm/page.tsx, and routes the cost pencil away from stock rows so the existing cost-edit endpoint (which queries order_items) can't 404 on a stock_purchase_items id.

- New POST /api/v1/collection-confirm/book-stock endpoint + route tests.
- New bookStockRows(rowIds, { actor }) service that mirrors the pre-rewire bookStockLineForRow flow per-row: ledger → cache increment → line update → auto-derive parent send→received.
- PoCard footer now switches on the row mix: stock rows → 'Book to stock'; customer rows → 'Confirm for invoicing'; mixed → both.
- ItemsTable hides the cost pencil when row.source === 'stock' (cost cell stays readable).
- Page-level handleBookStock wired through to the new endpoint with a reload on success.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 02:29:20 +02:00
SJCoetz
c856db1617 fix(collection-confirm): thread null cost through appendCostNote to preserve audit on null→0
Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:46:50 +02:00
SJCoetz
47eff9a6fe feat(collection-confirm): implement confirmOrderItemsForInvoicing with createBatch
Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:40:29 +02:00
SJCoetz
77d2c32df4 fix(collection-confirm): add cost_price to ConfirmRow, rename body to args
Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:29:56 +02:00
SJCoetz
2997b8dcba feat(collection-confirm): implement updateOrderItemCost service
Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:23:37 +02:00
SJCoetz
8b6b83583d fix(collection-confirm): use getOrderItemsCollectionName + populate stock supplier
Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:17:56 +02:00
SJCoetz
15f6ec638d fix(collection-confirm): make listCollectedItems stock leg fail-soft
Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:12:02 +02:00
SJCoetz
efe10b9474 feat(collection-confirm): add service skeleton with listCollectedItems
Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:08:57 +02:00
SJCoetz
f7b5f3677e feat(orders): persist company and rep from review-modal cascade
Extends updateOrderReviewFields' patch type to accept company
(relation id) and rep (free-text snapshot) in addition to the
existing order_number and customer. The modal cascade writes these
when the operator changes the customer; the service now carries
them through to the PB update.

The order_number collision check is unchanged — it only runs for
order_number changes, so the new fields are unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-31 15:29:10 +02:00
SJCoetz
da0a689507 feat(stock-quick-draft): add updateQuickDraftLine service
Adds a TDD'd updateQuickDraftLine function that PATCHes
quantity and/or cost_price on a stock_purchase_items row.
Returns the same discriminated-union shape as its sibling
add/remove functions. No schema changes.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-31 13:38:59 +02:00
SJCoetz
f9a0d08dab fix(tests): mock scaffold destructure + collection-pool + pocketbase startup
- orders-service.test.ts: destructure capture-group bug on regex match
  (was assigning m[0] to 'field', so filter clauses never matched).
  Two pre-seed tests were masked by the bug.
- quotes-service.test.ts: createQuoteFromEmail now returns 0
  attachments; the n8n flow uploads them in a follow-up step. Update
  the assertion that still expected the old embedded-base64 count.
- collection-pool/page.test.tsx: tests assume ONE supplier group with
  multiple rows; supply that shape and scope the selectors. Also wait
  for data load in the chevron test and gather list items across all
  <ul> elements in the sort control helper.
- pocketbase.ts: wrap authStore.onChange registration defensively so
  the test mock (no authStore) doesn't throw at startup.
- stock-orders/page.tsx: drop the re-export of
  STOCK_PURCHASE_STATUS_VALUES on the page module — Next.js page
  route files only allow the default export.
- collection-confirm/view-model.test.ts: buildConfirmNote input is
  Pick<InvoiceDetails, 'date' | 'number'>; drop the extra setBy fields.

Co-authored-by: Orca <help@stably.ai>
2026-07-31 00:01:24 +02:00
SJCoetz
6329a100e7 fix(stock-quick-draft): isolate new-SKU suppliers, fix empty-string pick, service layer
Co-authored-by: Orca <help@stably.ai>
2026-07-30 23:31:21 +02:00
SJCoetz
98e1f25fd5 fix(stock-quick-draft): supplier-name schema + remove dead resolvePb + pagination cap
Co-authored-by: Orca <help@stably.ai>
2026-07-30 23:14:11 +02:00
SJCoetz
8acb6dcf95 fix(stock-quick-draft): dedicated /drafts endpoint with nested shape, browser-auth
Co-authored-by: Orca <help@stably.ai>
2026-07-30 23:11:27 +02:00
SJCoetz
249a78a7ef fix(stock-quick-draft): add trailing newlines
Co-authored-by: Orca <help@stably.ai>
2026-07-30 22:06:24 +02:00
SJCoetz
f7de9d44fd feat(stock-quick-draft): removeQuickDraftLine
Co-authored-by: Orca <help@stably.ai>
2026-07-30 22:04:37 +02:00
SJCoetz
0ed89aac10 fix(stock-quick-draft): escape filter strings + handle findOrCreateOpenDraft failures
Co-authored-by: Orca <help@stably.ai>
2026-07-30 22:02:39 +02:00
SJCoetz
99374599d7 feat(stock-quick-draft): addQuickDraftLine with find-or-create-open-draft
Co-authored-by: Orca <help@stably.ai>
2026-07-30 21:55:02 +02:00
SJCoetz
3eef60f34c feat(stock-quick-draft): getStockItemSupplierHistory
Co-authored-by: Orca <help@stably.ai>
2026-07-30 21:50:04 +02:00
SJCoetz
eb64f03db6 feat(stock-quick-draft): types + searchStockItemsForQuickDraft
Co-authored-by: Orca <help@stably.ai>
2026-07-30 21:38:58 +02:00
SJCoetz
4535a20eee fix(buyer-tasks): mark-ready puts item into collection pool, not collected
When the operator clicks "Mark as ready" on a buyer-tasks po_sent card
and fills in the note, the item should land in the collection pool
(`item_status: "collection_pool"` + `ready_for_collection: true`) so
a driver can be assigned. Previously the service set
`item_status: "ready_delivery"`, which was rendered as the word
"Collected" on /orders and on /orders tabs — operators reasonably
read that as "driver already picked it up", and the item never
appeared on /collection-pool where they expected to assign a driver.

Now:
- markGroupReady writes a single PB update with the same shape as
  /api/v1/collection-map/items/[id]/assign (collection_pool +
  ready_for_collection: true + notes)
- po_sent buyer-tasks filter excludes collection_pool and assigned,
  so marked-ready items drop out of buyer-tasks and surface on
  /collection-pool instead
- ITEM_STATUS_VISUAL.ready_delivery is labelled "Ready for
  Collection" (kept distinct from the actual `collected` state) for
  any other flow that legitimately sets this status (e.g. stock-out)
- new item-status-ui.test.ts locks down the label/tab mapping so
  the regression can't return

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-30 15:25:33 +02:00
SJCoetz
172d562f06 fix(buyer-tasks): generate PO succeeds + supplier stripe + PO badge
generatePoForGroup was creating purchase_orders records without
`po_number`, which is required by the PB schema. PB rejected the
create with 500 ("Failed to create record.") and the operator never
got a PO. Fix:

- New src/lib/server/po-number.ts — server-side generatePONumber()
  that mirrors the client version in pb-helpers.ts (PO-YYYY-MM-NNN
  format) but uses getAdminPocketBase(). Per the data-access rules,
  don't extend pb-helpers.ts; server business logic lives under
  lib/server/.
- generatePoForGroup now generates the PO number, includes
  total_amount (sum of costPrice * quantity) and order_item
  (back-link to the items) in the create payload — mirrors the
  canonical /orders/[id]/process PO-creation flow so the PB admin
  row shows related lines without an extra getList call.
- Test updated to assert the new payload (po_number regex,
  total_amount computed, order_item back-link).

UI while here:
- BuyerTaskGroupCard now renders a deterministic supplier colour
  stripe on the left edge. New src/lib/supplier-color.ts hashes the
  supplierId into a small Tailwind 600 palette (18 colours) so the
  same supplier always shows the same colour, and the supplier name
  gets tinted with the same colour for quick scanning.
- PO number is now shown prominently at the top of the card (in a
  warm-toned badge that matches the AI Insights theme) when one
  exists — po_draft and po_sent tabs. Needs PO tab omits it.

Co-authored-by: Orca <help@stably.ai>
2026-07-30 15:00:18 +02:00
SJCoetz
6fa658df62 feat(buyer-tasks): require audit note when marking ready
The Mark ready action on the buyer-tasks page now mirrors the
collection-pool flow: the operator is asked for a free-text note
(name of who they spoke to, collection number, etc.) before the
items transition to ready_delivery. The note is required, is trimmed,
and is written to order_items.notes alongside the status change so
there's an audit trail.

- Service: markGroupReady now takes a required note param, trims it,
  rejects empty values, and persists the trimmed text to notes.
- Route: /api/v1/buyer-tasks/mark-ready returns 400 when note is
  missing or whitespace-only, and forwards the value to the service.
- Page: BuyerTasksPage swaps the no-input MarkReadyModal for the
  shared MarkReadyDialog, threads the note through the POST body,
  and surfaces server-side validation errors back into the dialog
  rather than only as a toast.
- The old MarkReadyModal is removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 22:38:00 +02:00
SJCoetz
76f1d79082 fix(buyer-tasks): prefill SendPoModal fields from buyer-tasks page
Co-authored-by: Orca <help@stably.ai>
2026-07-29 20:45:12 +02:00
SJCoetz
05242f09f4 feat(buyer-tasks): markGroupReady with cross-order check
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 20:00:45 +02:00
SJCoetz
98a0bc4143 feat(buyer-tasks): generatePoForGroup creates PO and updates items
Co-authored-by: Orca <help@stably.ai>
2026-07-29 19:58:07 +02:00
SJCoetz
b4c9f2d2ce fix(buyer-tasks): use getFullList and tighten item_status filter for po_draft/po_sent
- Switch from getList(1, 500) to getFullList so candidate sets
  aren't silently truncated at 500 rows (matches orders-service
  and quotes-service conventions).
- Tighten the po_draft filter to item_status = po_generated so
  items in downstream statuses (collection_pool, delivered, etc.)
  don't get pulled over the wire.
- Tighten the po_sent filter to exclude item_status in
  {ready_delivery, invoiced, delivered, cancelled} for the same
  reason.
- Drop the redundant ready_delivery post-filter on po_sent now
  that the PB layer handles it.
- Tests capture the filter string passed to getFullList and assert
  its clauses so regressions are caught.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 19:56:53 +02:00
SJCoetz
49acc04fd1 fix(buyer-tasks): type-safe expand traversal for customer/company
Co-authored-by: Orca <help@stably.ai>
2026-07-29 19:53:09 +02:00
SJCoetz
463917d755 feat(buyer-tasks): listBuyerTasks service with grouping
Co-authored-by: Orca <help@stably.ai>
2026-07-29 19:52:41 +02:00
SJCoetz
74c73e9f17 feat(orders): totals + add/remove items in review modal
Two related enhancements to the orders review modal:

* Tier 1 — header totals: the "Order items" header now shows the
  item count plus the cost and selling totals (qty*price summed
  across the live draft state). Uses formatCurrency from
  pb-helpers.ts for the ZAR formatting.

* Tier 2 — add/remove items: the edit-mode items list now has an
  "Add item" button (Plus icon) and a per-row Trash icon. New rows
  get a sentinel id like "__new_1" and a left-edge accent stripe;
  rows flagged for removal flip to a strikethrough + reduced opacity
  with disabled inputs (toggle button flips to an Undo2 icon).

  On save, the route posts to /api/v1/orders/[id]/review-save with
  new itemsToAdd and itemsToRemove arrays. The service layer adds
  createOrderItems + softFlagOrderItems handlers (set
  item_status="removed" — operator confirmed the value is in the
  PB admin schema). The modal re-keys the new drafts with the
  returned PB ids so a follow-up save treats them as existing
  items.

  Partial-failure UI now has three sections (updates / adds /
  removes) sharing a labelled FailureSection helper. Response
  envelope now includes itemsAdded and itemsRemoved alongside the
  existing items block, plus a flat partialFailures array for
  the toast summary.

  Type cleanup: "removed" added to ItemStatus and the
  ITEM_STATUS_VISUAL map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 18:54:49 +02:00
SJCoetz
43011d4d5e feat(item-history): wire description-fuzzy matcher into getItemHistory
Co-authored-by: Orca <help@stably.ai>
2026-07-29 17:43:59 +02:00
SJCoetz
22df511293 merge
Co-authored-by: Orca <help@stably.ai>
2026-07-29 16:49:37 +02:00
SJCoetz
96e071330a test(orders): reconcile duplicate test file state
A post-commit re-edit of the test file introduced a duplicate
updateOrderItemsPrices describe block at the tail. All tests still
pass (the duplicates run independently). Keep the file aligned
with HEAD.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 16:24:03 +02:00
SJCoetz
deb224ac10 test(orders): add tests for cross-order, filter escape, unique-constraint
Cross-order rejection (Fix #3), PB filter quote escape (Fix #6), and
mapping of PB unique-index write errors to OrderNumberCollisionError
(Fix #7) get full coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 16:20:48 +02:00
SJCoetz
53b778691e fix(orders): validate item order_id in updateOrderItemsPrices
A request to order A could include an item ID from order B and
silently modify it. Read the current row and reject with failed[]
when current.order does not match orderId. Test covers the cross-
order case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 16:20:41 +02:00
SJCoetz
3f8836d981 fix(item-history): query pos collection for stock_qty (was stock_purchase_items, which doesn't exist)
Co-authored-by: Orca <help@stably.ai>
2026-07-29 16:02:13 +02:00
SJCoetz
d2f6a0cd0b chore(item-history): move getAdminPocketBase import to top, drop unused PB type alias
Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:56:42 +02:00
SJCoetz
7df7a8850f feat(item-history): add getItemHistory service with 5 PB queries
Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:51:58 +02:00
SJCoetz
cfc974c080 fix(orders): review-marker review fixes (collection helper, empty patch, markup_percent)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:32:41 +02:00
SJCoetz
91f7bf860b feat(orders): add updateOrderItemsPrices with batch + per-row failure
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:15:35 +02:00
SJCoetz
aa7db0d801 refactor(orders): use ORDER_COLLECTION constant + rejects.toMatchObject in review tests
Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:11:02 +02:00
SJCoetz
811493bedb feat(collection-pool): add page and service function
Restores the /collection-pool feature in this codebase.

- src/lib/server/orders-service.ts
  - Re-adds `listCollectionPool({ status, page, perPage })` which
    queries the `collection_pool` PB collection via the admin
    client (filter on pool_status, sort -created, expand
    order_item/order/supplier/drv_id). MCP route.ts already
    imported this — without it, the MCP route failed to
    compile.

- src/app/(app)/collection-pool/{page,components,view-model}*.tsx
  - Re-creates the page directory (5 files, 2 315 lines) carrying
    the supplier-group + per-stop checkbox UI, the
    `CollectionPoolRowSource = "customer" | "stock"` union, the
    assignment-state badge helpers (buildProximityMarkerMap,
    buildSupplierGroups, buildVisibleRows), and the
    MarkReadyDialog / AssignDriverDialog wiring.

- src/app/api/mcp/route.test.ts
  - Adds `const listCollectionPool = vi.fn()` and exposes it in
    the vi.mock factory so the existing collection_pool.list test
    cases (and the bulk_update_quote_items ones that call
    `.mockReset()` on every fixture) stop crashing with
    'ReferenceError: listCollectionPool is not defined'.

Not in this commit (kept narrow per request):
- The /api/v1/collection-pool route handler and its test
- The 'Collection Pool' entry in the sidebar nav
- The migration script that creates the live `collection_pool`
  PB collection (it doesn't exist on the cloud PB instance
  yet; the page render relies on it being created separately
  or via `npm run pb:migrate:orders-v2`)
2026-07-27 15:04:30 +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
3d3a012174 fix(api,layout): sprint 500 chunk + add 9 missing top-level agent routes + metadataBase; drop unused collection_pool feature; quote counter fix migration
src/app/api/v1/sprint/attachment-counts/route.ts
  - Chunk itemIds into batches of 80 before building the PocketBase filter;
    the live cap was hit at ~115 IDs × 15 chars and surfaced as a
    generic Next 500 ("Something went wrong while processing your
    request.") that hid the real cause. 7 chunks for the sprint
    page's max of 500 items.

src/app/layout.tsx
  - Add metadataBase derived from NEXT_PUBLIC_SITE_URL /
    NEXT_PUBLIC_POCKETBASE_URL. Silences the per-page
    "metadataBase not set" warning during dev renders and gives
    OG / Twitter cards a stable canonical base.

src/app/api/v1/{quotes,order-items,purchase-orders,stock,
stock-purchases,users,sprint,driver,ai-insights}/route.ts (NEW)
  - Add the missing top-level collection routes the agent API
    needs. seven are straight passthroughs to their PB collection;
    /sprint proxies to quote_items with optional claimStatus and
    category query params; /driver lists PB users (no role field
    in PB so callers narrow with ?filter=); /ai-insights returns
    a roll-up count + most-recent regenerate timestamp across the
    four collections that carry ai_* JSON fields.

src/app/api/v1/collection-pool/{route.ts,route.test.ts},
src/app/(app)/collection-pool/{page.tsx,page.test.tsx,
view-model.ts,view-model.test.ts,components.tsx} (DELETED)
  - Drop the collection_pool feature entirely: PB has no
    collection_pool collection on the live instance
    (pb:migrate:orders-v2 was never run), the codebase comment
    in purchase-orders-service.ts says "now-removed", and the
    sidebar entrypoint has been migrated to /sprint + /deliveries.
    The replacement operational status is the `item_status =
    "collection_pool"` enum value on order_items, which stays.

src/lib/server/orders-service.ts (+ test), src/lib/pb-helpers.ts,
src/components/sidebar.tsx, src/components/ui/assign-driver-dialog.tsx,
src/app/(app)/collection-map/sidebar.tsx,
src/app/api/mcp/route.ts (+ test) (MODIFIED)
  - Remove listCollectionPool + getCollectionPool +
    updateCollectionPoolStatus, the /collection-pool sidebar entry,
    the deep-link in assign-driver-dialog and collection-map
    sidebar, and the collection_pool.list MCP tool (the tool,
    handler, and test mock).

scripts/migrations/2026-07-26-fix-quote-counter-and-reassign-numbers.ts (NEW)
  - One-shot migration script that:
      1. Reads every quote, sorts by created ASC.
      2. Reassigns clean Q202607001 … Q202607{N} over the whole
         table (including the e+22 garbage and the legacy
         Qnnnnnn rows).
      3. Sets quote_counters.(year=2026, month=7).last_seq = N
         so the next /api/v1/quotes/next-number returns a clean,
         atomic, unique number.
    Default mode = dry-run; pass --apply to write.
    Already executed against the live cloud PB during this session
    (verified: 200/200 rows updated, counter at 200, next-number
    returns Q202607201, Q202607202, Q202607203 on consecutive calls).

AGENTS.md (MODIFIED)
  - Add data-layer-discipline block matching the style of the
    three existing blocks. Documents which layer is legacy (pb-helpers)
    vs current (lib/server/*-service.ts via /api/v1/*), gives the
    migration order (customers → orders → quotes → suppliers →
    companies → rest), and includes the grep one-liner future AI
    agents should run before extending pb-helpers.

Not in this commit (your WIP, untouched):
  src/app/(app)/{dashboard,delivery-notes,layout,orders/[id],
  quotes/[id],quotes/approvals,quotes,sprint}/page.tsx,
  src/app/(auth)/login/page.tsx, src/components/charts/*,
  src/components/{company-form,customer-form,quote-email-card,
  sprint-item-pricing-modal,supplier-form,theme-bootstrap,
  theme-picker}*.{tsx,test.tsx}, src/app/api/invoicing/delivery-note/*
  src/app/api/v1/quotes/[id]/pdf/route.ts, src/app/globals.css,
  src/lib/{item-status-ui,pdf/quote-document,quote-status*,themes,
  types}.ts, src/lib/server/{order-item-status*,quotes-service}.ts,
  src/styles/themes.css, APP_CAPABILITIES.md, README.md,
  docs/SHIPPED.md, scripts/smoke/screenshot-pages.mjs,
  and the new untracked files under docs/, scripts/migrations/
  2026-07-19…25, src/app/{(app)/deliveries,(app)/delivery-notes,
  api/v1/ai-insights/rerun,api/v1/deliveries,api/v1/delivery-notes,
  api/v1/quotes/[id]/partial-approve,api/v1/quotes/[id]/split},
  src/components/{ai-insights-panel,ai-insights-renderer,
  ai-item-history-trigger,brand-stripe,delivery-notes,ui/stock-item-search,
  ui/duplicate-warning,ui/duplicate-warning.test}.tsx, supplier-form.test.tsx,
  src/lib/{pb-helpers-duplicate.test,server/deliveries-service*,
  server/delivery-notes-service*}, public/wfdash-logo*.png,
  opencode.jsonc.
2026-07-26 22:18:49 +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
71f7671e89 feat: add stock line support to collection pool
Add full integration for stock supplier pickup lines into the collection pool workflow:
- Add two idempotent database migrations for stock line drv_id and state tracking
- Update stock purchase number format to POyyMMddNNSTK convention
- Extend collection pool to load both customer order items and stock purchase items
- Add stock-specific UI, driver assignment flow, and mark collected action
- Update type definitions and service logic for stock purchases and line items
- Add comprehensive test coverage for all new workflows
2026-07-16 20:41:42 +02:00