WFDASH-WEBAPP/package.json

126 lines
6.9 KiB
JSON
Raw Normal View History

{
"name": "wfdash",
"version": "0.1.0",
"private": true,
"engines": {
"node": ">=20.9.0"
},
"scripts": {
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "next start",
"lint": "eslint",
"setup": "npx tsx scripts/setup-pocketbase.ts",
"pb:migrate:orders-v2": "npx tsx scripts/migrations/create-order-items-v2-and-collection-pool.ts",
"pb:migrate:quote-attachments": "npx tsx scripts/migrations/create-quote-attachments-and-replies.ts",
"pb:migrate:quote-items-user-edited": "npx tsx scripts/migrations/add-quote-items-user-edited.ts",
"pb:migrate:order-status-in-stock": "echo 'deprecated: orders.status was dropped 2026-06-27. No-op.' && exit 0",
"pb:migrate:orders-rep": "npx tsx scripts/migrations/2026-06-26-add-orders-rep.ts",
"pb:migrate:pos-slip-layouts": "npx tsx scripts/migrations/2026-09-04-create-pos-slip-layouts.ts",
feat(pos): raise a system delivery note on an account sale An account sale at the till used to produce a delivery-note-shaped slip that was rendered entirely on the device and printed on the 80mm thermal printer. Nothing reached the server, so the paperwork the client signed had no record behind it. Cash / card / EFT are untouched and still get the thermal slip. An account sale now creates a real `delivery_notes` record. The DN is raised server-side INSIDE `checkoutSale` rather than by a follow-up call from the till, because the offline queue (`flushQueue`) re-posts `/checkout` and nothing else — a client-side second call would be silently dropped for every sale taken while the network was down, which is exactly when a till is flakiest. `pos_sales.delivery_note` is the idempotency anchor that makes it exactly-once: on a replay it hands back the existing DN instead of making a second one, and a sale whose first attempt left the field blank retries. It self-heals. Deliberately non-fatal: if the DN can't be created the sale still succeeds. The money and the stock movement are real by then; failing the checkout would leave the drawer disagreeing with the stock ledger. The till is told instead. Also in here: - DN number collision retry. The generator reads the highest existing number and adds one, which is not atomic, while PB holds a unique index on it. The POS adds a second concurrent writer, so two creates could collide and 500 on a benign condition. - GET /api/v1/pos/sales now expands customer, customer.company and delivery_note so history.html can rebuild the DN card on a reprint. The nested customer.company matters — customer.company is itself a relation, so without it the card printed a raw PB id where the name belongs. - "Print slip" is hidden for account sales; that tender produces a delivery note, not a slip. New GET /api/v1/pos/delivery-note/[number]/pdf streams the A4 original behind assertPosAuth, so the till's bearer key stays its only credential. It does not point at the CRM's unauthenticated invoicing route. Verified end to end against a live note: DN26100401, correct company, both lines with pricing, PDF attached, stock decremented once, and a replay of the same client_ref returned the same DN without a duplicate.
2026-10-04 11:15:29 +00:00
"pb:migrate:pos-sales-delivery-note": "npx tsx scripts/migrations/2026-10-03-add-pos-sales-delivery-note.ts",
"pb:migrate:audit-log": "npx tsx scripts/migrations/2026-09-25-create-audit-log.ts",
"pb:migrate:rep-trip-legs": "npx tsx scripts/migrations/2026-09-28-create-rep-trip-legs.ts",
"pb:migrate:giellie-chats": "npx tsx scripts/migrations/2026-09-30-create-giellie-chats.ts",
"pb:migrate:place-overrides": "npx tsx scripts/migrations/2026-09-28-create-place-overrides.ts",
"pb:migrate:drop-orders-status": "npx tsx scripts/migrations/2026-06-27-drop-orders-status-and-wipe.ts",
"pb:migrate:add-order-quote-match": "npx tsx scripts/migrations/2026-06-27-add-order-quote-match-fields.ts",
"pb:migrate:add-order-delivery-note-match": "npx tsx scripts/migrations/2026-08-29-add-order-delivery-note-match-fields.ts",
"pb:migrate:quote-attachment-fields": "npx tsx scripts/migrations/2026-09-09-add-quotes-attachment-fields.ts",
"pb:migrate:quote-attachment-fields-maxselect": "npx tsx scripts/migrations/2026-09-09-fix-quote-attachment-fields-maxselect.ts",
"pb:migrate:add-purchase-order-pdfs": "npx tsx scripts/migrations/2026-06-28-add-purchase-order-pdfs.ts",
"pb:migrate:add-companies-coordinates": "npx tsx scripts/migrations/2026-06-28-add-companies-coordinates.ts",
"pb:migrate:convert-customer-fields": "npx tsx scripts/migrations/2026-06-28-convert-customer-fields.ts",
"pb:migrate:raw-price-list": "npx tsx scripts/migrations/2026-06-30-add-raw-price-list.ts",
"pb:migrate:pricelist-notes": "npx tsx scripts/migrations/2026-06-30-add-pricelist-notes.ts",
"pb:migrate:price-list-source-file": "npx tsx scripts/migrations/2026-06-30-add-price-list-source-file.ts",
"pb:migrate:price-list-search-text": "npx tsx scripts/migrations/2026-06-30-add-price-list-search-text.ts",
"pb:backfill:price-list-search-text": "npx tsx scripts/migrations/2026-06-30-backfill-price-list-search-text.ts",
"pb:migrate:price-list-sku-normalised": "npx tsx scripts/migrations/2026-06-30-add-price-list-sku-normalised.ts",
"pb:migrate:quote-items-sku": "npx tsx scripts/migrations/2026-06-30-add-quote-items-sku-and-pricing.ts",
"pb:migrate:rfq-outbound": "npx tsx scripts/migrations/2026-06-30-create-rfq-outbound.ts",
"pb:migrate:sprint-categories": "npx tsx scripts/migrations/2026-07-02-add-sprint-categories-and-claims.ts",
"pb:migrate:po-pdf-tokens": "npx tsx scripts/migrations/2026-07-09-po-pdf-tokens.ts",
"pb:migrate:po-additional-attachments": "npx tsx scripts/migrations/2026-07-09-po-additional-attachments.ts",
"pb:migrate:stock-line-drv-id": "npx tsx scripts/migrations/2026-07-15-add-stock-line-drv-id.ts",
"pb:migrate:stock-purchase-documents-history": "npx tsx scripts/migrations/2026-07-16-add-stock-purchase-documents-history.ts",
"pb:migrate:stock-purchase-send-statuses": "npx tsx scripts/migrations/2026-07-16-add-stock-purchase-send-statuses.ts",
"pb:migrate:stock-purchase-problem-fields": "npx tsx scripts/migrations/2026-07-17-add-stock-purchase-problem-fields.ts",
"pb:migrate:order-items-item-status-index": "npx tsx scripts/migrations/2026-08-04-add-order-items-item-status-index.ts",
"pb:migrate:stock-purchase-booked-fields": "npx tsx scripts/migrations/2026-08-06-add-stock-purchase-booked-fields.ts",
"pb:migrate:stock-purchase-items-catalogue-fields": "npx tsx scripts/migrations/2026-08-07-stock-purchase-items-catalogue-fields.ts",
"pb:migrate:quotes-ai-status": "npx tsx scripts/migrations/2026-08-08-add-quotes-ai-status.ts",
"pb:migrate:quotes-status-index": "npx tsx scripts/migrations/2026-08-04-add-quotes-status-index.ts",
"pb:migrate:ai-settings": "npx tsx scripts/migrations/2026-08-09-add-ai-settings.ts",
"smoke:counter": "npx tsx scripts/smoke/counter.ts",
"smoke:counter-concurrent": "npx tsx scripts/smoke/counter-concurrent.ts",
"smoke:create-from-email": "npx tsx scripts/smoke/create-from-email.ts",
"smoke:management": "npx tsx scripts/smoke/management-flow.ts",
"smoke:mcp-management": "npx tsx scripts/smoke/mcp-management.ts",
"smoke:rest-management": "npx tsx scripts/smoke/rest-management.ts",
"smoke:quotes-ai-pipeline": "npx tsx scripts/smoke/quotes-ai-pipeline.ts",
"smoke:ai-settings": "npx tsx scripts/smoke/ai-settings-round-trip.ts",
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"e2e": "playwright test",
"e2e:ui": "playwright test --ui",
"e2e:install": "playwright install --with-deps chromium"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.116.0",
"@base-ui/react": "^1.5.0",
"@radix-ui/react-slot": "^1.2.4",
"@react-pdf/renderer": "^4.5.1",
"@types/leaflet": "^1.9.21",
"@types/leaflet.heat": "^0.2.5",
"@types/pdf-parse": "^1.1.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"csv-parse": "^7.0.2",
"jspdf": "^2.5.2",
"leaflet": "^1.9.4",
"leaflet.heat": "^0.2.0",
"lucide-react": "^1.16.0",
"mammoth": "^1.12.0",
"next": "16.2.6",
"next-themes": "^0.4.6",
"pdf-lib": "^1.17.1",
"pdf-parse": "^2.4.5",
"pdfjs-dist": "^5.4.296",
"pocketbase": "^0.26.9",
feat(pos): raise a system delivery note on an account sale An account sale at the till used to produce a delivery-note-shaped slip that was rendered entirely on the device and printed on the 80mm thermal printer. Nothing reached the server, so the paperwork the client signed had no record behind it. Cash / card / EFT are untouched and still get the thermal slip. An account sale now creates a real `delivery_notes` record. The DN is raised server-side INSIDE `checkoutSale` rather than by a follow-up call from the till, because the offline queue (`flushQueue`) re-posts `/checkout` and nothing else — a client-side second call would be silently dropped for every sale taken while the network was down, which is exactly when a till is flakiest. `pos_sales.delivery_note` is the idempotency anchor that makes it exactly-once: on a replay it hands back the existing DN instead of making a second one, and a sale whose first attempt left the field blank retries. It self-heals. Deliberately non-fatal: if the DN can't be created the sale still succeeds. The money and the stock movement are real by then; failing the checkout would leave the drawer disagreeing with the stock ledger. The till is told instead. Also in here: - DN number collision retry. The generator reads the highest existing number and adds one, which is not atomic, while PB holds a unique index on it. The POS adds a second concurrent writer, so two creates could collide and 500 on a benign condition. - GET /api/v1/pos/sales now expands customer, customer.company and delivery_note so history.html can rebuild the DN card on a reprint. The nested customer.company matters — customer.company is itself a relation, so without it the card printed a raw PB id where the name belongs. - "Print slip" is hidden for account sales; that tender produces a delivery note, not a slip. New GET /api/v1/pos/delivery-note/[number]/pdf streams the A4 original behind assertPosAuth, so the till's bearer key stays its only credential. It does not point at the CRM's unauthenticated invoicing route. Verified end to end against a live note: DN26100401, correct company, both lines with pricing, PDF attached, stock decremented once, and a replay of the same client_ref returned the same DN without a duplicate.
2026-10-04 11:15:29 +00:00
"qrcode": "^1.5.4",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-leaflet": "^5.0.0",
"react-markdown": "^9.0.1",
"remark-gfm": "^4.0.0",
"shadcn": "^4.8.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^20",
feat(pos): raise a system delivery note on an account sale An account sale at the till used to produce a delivery-note-shaped slip that was rendered entirely on the device and printed on the 80mm thermal printer. Nothing reached the server, so the paperwork the client signed had no record behind it. Cash / card / EFT are untouched and still get the thermal slip. An account sale now creates a real `delivery_notes` record. The DN is raised server-side INSIDE `checkoutSale` rather than by a follow-up call from the till, because the offline queue (`flushQueue`) re-posts `/checkout` and nothing else — a client-side second call would be silently dropped for every sale taken while the network was down, which is exactly when a till is flakiest. `pos_sales.delivery_note` is the idempotency anchor that makes it exactly-once: on a replay it hands back the existing DN instead of making a second one, and a sale whose first attempt left the field blank retries. It self-heals. Deliberately non-fatal: if the DN can't be created the sale still succeeds. The money and the stock movement are real by then; failing the checkout would leave the drawer disagreeing with the stock ledger. The till is told instead. Also in here: - DN number collision retry. The generator reads the highest existing number and adds one, which is not atomic, while PB holds a unique index on it. The POS adds a second concurrent writer, so two creates could collide and 500 on a benign condition. - GET /api/v1/pos/sales now expands customer, customer.company and delivery_note so history.html can rebuild the DN card on a reprint. The nested customer.company matters — customer.company is itself a relation, so without it the card printed a raw PB id where the name belongs. - "Print slip" is hidden for account sales; that tender produces a delivery note, not a slip. New GET /api/v1/pos/delivery-note/[number]/pdf streams the A4 original behind assertPosAuth, so the till's bearer key stays its only credential. It does not point at the CRM's unauthenticated invoicing route. Verified end to end against a live note: DN26100401, correct company, both lines with pricing, PDF attached, stock decremented once, and a replay of the same client_ref returned the same DN without a duplicate.
2026-10-04 11:15:29 +00:00
"@types/qrcode": "^1.5.6",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^9",
"eslint-config-next": "16.2.6",
"jsdom": "^29.1.1",
feat(pos): raise a system delivery note on an account sale An account sale at the till used to produce a delivery-note-shaped slip that was rendered entirely on the device and printed on the 80mm thermal printer. Nothing reached the server, so the paperwork the client signed had no record behind it. Cash / card / EFT are untouched and still get the thermal slip. An account sale now creates a real `delivery_notes` record. The DN is raised server-side INSIDE `checkoutSale` rather than by a follow-up call from the till, because the offline queue (`flushQueue`) re-posts `/checkout` and nothing else — a client-side second call would be silently dropped for every sale taken while the network was down, which is exactly when a till is flakiest. `pos_sales.delivery_note` is the idempotency anchor that makes it exactly-once: on a replay it hands back the existing DN instead of making a second one, and a sale whose first attempt left the field blank retries. It self-heals. Deliberately non-fatal: if the DN can't be created the sale still succeeds. The money and the stock movement are real by then; failing the checkout would leave the drawer disagreeing with the stock ledger. The till is told instead. Also in here: - DN number collision retry. The generator reads the highest existing number and adds one, which is not atomic, while PB holds a unique index on it. The POS adds a second concurrent writer, so two creates could collide and 500 on a benign condition. - GET /api/v1/pos/sales now expands customer, customer.company and delivery_note so history.html can rebuild the DN card on a reprint. The nested customer.company matters — customer.company is itself a relation, so without it the card printed a raw PB id where the name belongs. - "Print slip" is hidden for account sales; that tender produces a delivery note, not a slip. New GET /api/v1/pos/delivery-note/[number]/pdf streams the A4 original behind assertPosAuth, so the till's bearer key stays its only credential. It does not point at the CRM's unauthenticated invoicing route. Verified end to end against a live note: DN26100401, correct company, both lines with pricing, PDF attached, stock decremented once, and a replay of the same client_ref returned the same DN without a duplicate.
2026-10-04 11:15:29 +00:00
"jsqr": "^1.4.0",
"tailwindcss": "^4",
"typescript": "^5",
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.1.8"
}
}