Commit graph

16 commits

Author SHA1 Message Date
SJCoetz
3664eef898 feat(po): resend purchase order from sent / mail_failed / sending statuses
Work by another agent on the PO send flow. Adds a 'Resend' CTA
on the order detail page for POs that were already sent
(operator wants to send another copy to the supplier), plus
acceptance of the same flow from the modal. Includes:

- purchase-orders-service: accept 'sent' as a resend-from state
  (in addition to 'draft' and 'mail_failed')
- send-po-modal: title flips to 'Resend Purchase Order ...' when
  the PO was previously sent; 'Send' button becomes 'Resend'
- send-po-modal.test: covers the resend path
- orders/[id]/page: shows Resend button in the same sendable
  state group as Send (was draft / mail_failed, now also 'sent')
- purchase-orders pdf route: updates docstring to reflect that
  status is the outbound-email pipeline's responsibility
- stock-purchases pdf route: download URL uses file proxy for
  admin-auth compatibility

Co-authored-by: Orca <help@stably.ai>
2026-08-04 20:05:52 +02:00
SJCoetz
aea1ab67f3 fix(po-send): push dashboardBaseUrl + outcomeUrl on n8n webhook body
The n8n Code node that posts the SMTP outcome back to the
/api/v1/purchase-orders/[id]/send-email/outcome route couldn't
read env vars at runtime (N8N_BLOCK_ENV_ACCESS_IN_NODE=true in
docker-compose), so it composed the callback URL from fields on
the webhook body. The route never pushed dashboardBaseUrl or
outcomeUrl, so n8n fell back to a relative URL, the request
died, n8n returned HTTP 500, and the route flipped the PO to
mail_failed with a misleading '[webhook] Webhook returned HTTP
500' message.

DASHBOARD_URL is already defined in .env (labelled 'used by n8n
workflows to call back into this app') — the route just never
read it. Now the route pushes both the dashboard base and a
pre-built absolute outcome URL, trimmed of trailing slashes, and
omitted (not empty) when DASHBOARD_URL is unset so the existing
'missing' branch in n8n fires clearly.

A new test file asserts all three cases: with DASHBOARD_URL,
with a trailing slash, and without the env var.

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

Co-authored-by: Orca <help@stably.ai>
2026-08-03 11:23:40 +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
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
f44f090351 test(po-attachments): use node env so the 25 MB cap assertion works 2026-07-09 23:39:12 +02:00
SJCoetz
2b3b50596c feat(po): include additional_attachments in send-email webhook 2026-07-09 23:25:05 +02:00
SJCoetz
9bc9d389ce test(po-attachments): use NextRequest instead of any cast 2026-07-09 23:20:10 +02:00
SJCoetz
1477265db9 feat(po-attachments): add delete route for PO additional attachments 2026-07-09 23:18:51 +02:00
SJCoetz
fff095caae test(po-attachments): cover delete route behaviour 2026-07-09 23:16:53 +02:00
SJCoetz
b362d92256 feat(po-attachments): add upload route for PO additional attachments 2026-07-09 23:15:08 +02:00
SJCoetz
a16b8fcdcb test(po-attachments): cover upload route behaviour 2026-07-09 23:01:55 +02:00
SJCoetz
f146e42ed0 test(po-pdf): cover token capture + proxy routing 2026-07-09 22:23:49 +02:00
SJCoetz
6a7dcc0af2 fix(po-pdf): capture PB token on upload and route GET through proxy 2026-07-09 22:18:53 +02:00
SJCoetz
1e99d23e8b feat(po-pdf): add token field to PurchaseOrderDocumentEntry 2026-07-09 22:17:21 +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
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