Commit graph

9 commits

Author SHA1 Message Date
482c1adf25 chore(agents): add wfdash-rep-visit-batch-pin skill
Bulk-pin a list of customers to a PocketBase site from a rep's visit log
(typically Gary's driving-mode WhatsApp pins). Encodes the PB quirks we
hit during the Khuseleka batch:

- PB filter field on customers is 'customer' (not 'name'); fuzzy match
  with customer~"X"
- coordinates is a geoPoint on both customers and rep_visits
  ({"lat": X, "lon": Y} GeoJSON, not a flat string)
- site_location is free-text on customers and does NOT exist on
  rep_visits (PB silently drops unknown keys on writes)
- position_source is a select with ["tracker", "manual"]; manual is
  the backfill marker
- PB admin auth email lives in .env.local (PB_ADMIN_EMAIL), never
  hardcode
- local pb_schema-2.json snapshot is stale (missing site_location) —
  live PB is source of truth
- SAST = UTC+2; convert WhatsApp timestamps before stamping
- single-letter driving-mode typos → pin the canonical PB record,
  ask before assuming
- zero-hit names → skip by default; ask before creating new
  customers

Same folder as wfdash-giellie; available to any agent that loads the
project's skills folder.
2026-09-20 23:49:58 +02:00
Dave
6344948b0b feat: add driverless collection confirm and new order tooling
This commit adds several key features, improvements, and cleanups across the codebase:
- Add `order_items.confirm_collected` MCP/REST endpoint to mark order items as collected without requiring driver assignment
- Add standalone order creation and order split APIs for flexible order management
- Update order list sort to oldest-first to align with user workflow of working through oldest orders first
- Improve order search to show cross-tab matches and display source tab indicators on search results
- Add customer name similarity check to warn about mismatched QuickBooks customers during invoice creation
- Remove supplier name column from delivery note PDFs and clean up related data passing across delivery note routes
- Add validation and debug logging to ItemIntelPopover for missing item ID on apply actions
- Remove unused OrderItemContextPopoverTrigger component from order detail page
- Add delivery note regeneration script and update test suites for new and existing functionality
- Update documentation and add test coverage for the new collection confirm tool
2026-08-12 01:13:46 +02:00
Dave
47d58db0c9 feat(mcp): add price_list.add_items tool for agent-driven catalogue upsert
Add a new MCP tool that lets the agent read a supplier PDF, quote PDF,
or pasted supplier email with its native vision, extract the per-line
fields, and commit them to the price_list catalogue in one round-trip.

Why: the only pre-existing path was operator upload via /pricelist ->
n8n ingest -> raw_price_list -> AI extraction -> price_list. That flow
is async, human-in-the-loop, and gates on n8n being healthy. This
tool gives the agent a synchronous shortcut for ad-hoc catalogue
updates -- paste a PDF, get the catalogue updated, no async hops.

The agent does the OCR; the tool does the commit. No LLM work moves
into the MCP server.

Behaviour:

- Dedupe by (sku, supplier) -- exact match. Different suppliers with
  the same SKU get separate rows.
- Upsert policy: cost_price overwrites (latest price wins).
  Description, selling_price, unit, category, subcategory, brand,
  markup, stock_qty, search_text, sku_normalised also patched in
  place on update.
- sku_normalised auto-computed (uppercase, strip non-alphanumeric --
  same canonical form price-list-match.ts uses).
- search_text auto-computed (lowercased, space-separated concat of
  sku + description + brand + supplier + category + subcategory +
  synonyms).
- Skipped items returned with per-item reason (missing_sku,
  missing_supplier, invalid_cost_price, pb_write_failed). Never
  silent.
- Bulk cap 500 items per call; larger lists rejected with
  too_many_items reason.
- source_file_id + source_label supported so new rows can be
  traced back to a raw_price_list upload (optional).
- Supplier stored verbatim on price_list.supplier (free-text field,
  no FK resolution -- same as the live schema).

Files:

- src/lib/server/price-list-service.ts (new) -- addPriceListItems +
  buildSearchText + computeSellingPrice helpers
- src/lib/server/price-list-service.test.ts (new) -- 17 tests
  covering validation, upsert, dedupe filter shape, normalisation
- src/app/api/mcp/route.ts -- new tool definition + dispatch block
- src/app/api/mcp/route.test.ts -- 2 dispatch tests + tool-list
  assertion update
- .agents/skills/wfdash-giellie/SKILL.md -- new section "8. Price-
  list catalogue" documenting input/output shapes + failure modes

Tests:

- 134/134 pass across the affected files
- 1775/1778 in the full suite (3 pre-existing failures unrelated
  to this change: pocketbase-admin.test.ts PB mock mismatch,
  quotes/items/[id]/attachments/upload/route.test.ts timeout,
  supplier-form.test.tsx race -- all reproducible on main)
- npm run build clean
2026-08-10 12:45:05 +02:00
SJCoetz
87cead1bcf feat(mcp): expand stock purchase invoice matching service with 5 phases
Build out the buyer-side PO reconciliation workflow that landed in
60d3204 ('stock purchase invoice reconciliation tool') into a full
3-document × 2-PO-kind matching service. The tool now covers every
real-life supplier document the buyer can receive.

Renamed the service entry point from matchAndReceiveFromInvoice to
matchAndReceiveFromPoDocument (old name kept as a back-compat alias).
The MCP tool name stays stock_purchases.match_and_receive_from_invoice
so existing callers don't break; the input arg shape changed from
'invoice:' to 'document:' (old 'invoice:' arg still accepted for
back-compat).

Phase 1 — supplier_sku backfill (prep work, not in service code)
Phase 2 — auto-detect stock vs customer POs (single tool, both kinds)
Phase 3 — GRN (delivery-note) mode via new mode: 'grn' flag
Phase 4 — pack-size inference (Orapi case: per-unit vs per-pack)
Phase 5 — PO reference normalisation (PO202608017 vs PO-2026-08-017)

Also adds 3 new MCP tools for the collection-confirm buyer workflow:
collection_confirm.list, collection_confirm.upload_invoice,
collection_confirm.confirm_order_items.

Docs: updated .agents/skills/wfdash-giellie/SKILL.md and
src/app/api/mcp/FEATURE-REQUESTS.md to describe the new modes and
shape. 1,661/1,664 vitest tests pass; the 3 failing tests are
pre-existing (PocketBase SDK mock mismatch in pocketbase-admin.test,
5s timeout in quotes/items/[id]/attachments/upload/route.test —
both reproducible on main without this change).
2026-08-09 20:23:36 +02:00
SJCoetz
60d320411d feat(mcp): add stock purchase invoice reconciliation tool
Add the full buyer-side supplier invoice reconciliation workflow:
- Include the new `stock_purchases.match_and_receive_from_invoice` MCP tool for deterministic PO-invoice matching
- Create core matching service with strict, rule-based line matching (sku → supplier_sku → description overlap)
- Support dry-run default mode to validate matches before committing
- Add automatic attachment handling with standard `supplier_invoice_*` naming convention
- Add full test suite for the matching logic
- Update documentation and agent skill profile to document the new tool and workflow

Pre-existing test failures (3 total) are unrelated to this change.
2026-08-09 16:59:44 +02:00
SJCoetz
63048e51c9 feat: add AI quote processing pipeline and admin settings UI
Add complete end-to-end AI-powered quote extraction workflow:
- Disable PB SDK auto-cancellation to support parallel batch requests
- Add required runtime dependencies for AI processing and document parsing
- Implement AI settings backend, operator UI, and REST API routes
- Add quote ingestion, insight population, and manual re-run AI endpoints
- Build service layers for quote items, AI settings, and structured item insights
- Fix attachment upload handling and quote item history blob parsing
- Add supporting migrations, smoke tests, and shared utility functions
- Export previously private helper functions for cross-service reuse
2026-08-09 16:17:29 +02:00
SJCoetz
c41908f4b7 feat(quote-items): CRUD via REST + MCP for AI auto-fill agents
Closes architectural gap #1 from the Giellie skill (the operator's AI
agent could ingest quotes via /api/mcp but had no way to enumerate,
add, or patch the resulting line items - every auto-price flow had to
stop and ask a human for the item IDs).

Adds:
  - GET  /api/v1/quote_items        (list w/ filter, sort, expand)
  - POST /api/v1/quote_items        (create on existing quote)
  - GET  /api/v1/quote_items/[id]   (fetch one)
  - PATCH /api/v1/quote_items/[id]  (whitelisted patch)
  - quote_items.list  MCP tool
  - quote_items.get   MCP tool
  - quote_items.create MCP tool
  - quote_items.update MCP tool

Patch whitelist on update is identical to bulk_update_quote_items:
  cost_price, selling_price, description, sku, unit, supplier, markup,
  pricing_source, pricing_notes, matched_price_list_id, user_edited
Everything else (id, quote, created, updated, quantity, is_processed)
returns 400 / MCP error with the allow-list echoed back so the agent
can self-correct.

quote_items.update does NOT enforce the already_priced skip - that's
the safety-net for bulk_update_quote_items. Single-row patches are
explicit writes.

Newly created rows have is_processed=false forced server-side; Giellie
still cannot flip the flag (architectural gap #2 unchanged - that's a
UI gate by design).

Also: removed "JEI" from quotes.company_letterhead select values on
the live PB - valid values are now ["CNL", "ISHERWOOD"]. Use the
uppercase form when setting this field.

Giellie skill doc refreshed: tool count 69 to 73, new "quote_items
CRUD" subsection, three new REST rows, architectural gap #1 marked
RESOLVED, hard rule #1 updated to cover the new endpoint, new worked
example for "add a missing line item + price it", change-log entry.

Tests: 82 passing across the three touched files (was 63 before).
Type-check: zero new errors (pre-existing 29 in
orders-service-review.test.ts unchanged).

Deployment: pending operator rebuild + redeploy. Until then
POST /api/v1/quote_items returns 404 and the new tools don't appear
in tools/list.

Co-authored-by: Orca <help@stably.ai>
2026-08-05 02:40:09 +02:00
SJCoetz
0455ddd346 docs(giellie): correct tool count (70 → 69) + add post-redeploy verification
The earlier change log claimed the catalog went 69 → 70 after wiring
tools.discovery, but tools.discovery was already in the catalog from
the start — only its runtime behavior changed from 'Unknown tool' to
functional. Live post-redeploy smoke test confirms 69 tools.

Fix all six '70' references in the doc to '69', and append a second
change-log entry recording what was verified live after the redeploy:
  - tools.discovery returns the flat 69-tool catalog via JSON-RPC ✅
  - GET /api/mcp still works ✅
  - 5 other bugs reproduce exactly as documented (validates the doc) ✅
  - ISHERWOOD + CNL letterhead PDF regeneration on Q000087 still works ✅

Co-authored-by: Orca <help@stably.ai>
2026-08-04 22:53:46 +02:00
SJCoetz
8fe80fefc8 docs(giellie): refresh skill doc — corrected host, all tokens, smoke-test findings
Bring the Giellie agent's operating manual in line with the live production
state after the 2026-08-04 smoke test against https://wfdash.apphub.co.za.

Bugs / quirks documented (with workarounds):
  - tools.discovery was unwired; now fixed in code (separate commit),
    live server needs redeploy before response changes
  - orders.list silently ignores 'filter'; only 'search' is honoured
  - quotes.lookup returns opaque 'fetch failed' — use quotes.list instead
  - collection_pool.list + sprint.list return 'Missing collection context'
  - orders.get 'not found' for at least one valid id
  - quotes.items.rewrite was incorrectly listed as an MCP tool (it's REST)

Architectural gaps documented:
  - No quote_items.list MCP tool; quotes.create_from_email returns item
    count only, so a freshly-ingested quote's item IDs can't be recovered
    via the agent API
  - is_processed is intentionally NOT in bulk_update_quote_items whitelist;
    end-to-end create→price→render pipeline requires human in the UI

Credentials & endpoints now include every token the agent might need:
AGENT_API_KEY, PB admin email/password, n8n base URL + API key, six
n8n webhook URLs (rewriter, price-list match, PO send, AI insights,
markup approval, customer list, QB invoice creator), TomTom map key.

Other updates:
  - Replaced stale base URL wfdash.davidels.dev with wfdash.apphub.co.za
  - Bumped tool count 69 → 70 (tools.discovery added to catalog)
  - Added three-way tool discovery guide (tools/list, tools.discovery,
    GET /api/mcp)
  - Added 'Quote PDF rendering' guide explaining the 422 gates,
    status transitions, and letterhead codes
  - Added change log at the bottom
  - All worked examples updated to the correct host

Co-authored-by: Orca <help@stably.ai>
2026-08-04 22:47:55 +02:00