JEISA-WEBAPP/scripts/test-po-api.mjs
Dave 0b8f003f87 feat(po): add MCP server, agent-friendly PO API, and PDF rendering
- server/pb-mcp.mjs: 15-tool MCP server for purchase-order workflow
  (CRUD, suppliers, stock, customers, customer POs, validate_draft,
  generate_order_number)
- src/lib/api/purchaseOrders.ts: typed helpers shared by UI + MCP + n8n
- src/components/purchase-orders/pdf.ts: jsPDF PO generator
- src/components/purchase-orders/ViewOrderDialog.tsx: read-only dialog
- src/components/purchase-orders/AttachmentsDialog.tsx: attachment mgmt
- src/components/purchase-orders/NumberInput.tsx: numeric input
- scripts/mcp-create-po.mjs: end-to-end driver (MCP stdio smoke test)
- pocketbase/pb_migrations/1786200007_*: schema migration
- docs/MCP_AND_N8N.md: MCP + n8n integration guide

Verified end-to-end via MCP: generate_order_number → create_purchase_order
with snapshot_items for an actual quote (DRILL-19042 / 161053).
2026-09-07 11:12:13 +02:00

54 lines
No EOL
1.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Smoke test for the API helpers in src/lib/api/purchaseOrders.ts.
*
* node scripts/test-po-api.mjs
*
* Connects as admin, lists POs, soft-deletes one, restores it.
* Run after `node scripts/push-migrations.mjs --apply --only=1786200007`
* so the `deleted` field exists on `purchase_orders`.
*/
import PocketBase from 'pocketbase';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
const PB_URL = process.env.POCKETBASE_URL || 'https://pb.jeistk.apphub.co.za';
const PB_EMAIL = process.env.POCKETBASE_ADMIN_EMAIL || 'david@wfsales.co.za';
const PB_PASSWORD = process.env.POCKETBASE_ADMIN_PASSWORD || '1234567890';
const apiModule = await import('../src/lib/api/purchaseOrders.ts');
const { listPurchaseOrders, softDeletePurchaseOrder, restorePurchaseOrder } = apiModule;
const pb = new PocketBase(PB_URL);
pb.autoCancellation(false);
console.log(`[test] auth as ${PB_EMAIL} …`);
await pb.admins.authWithPassword(PB_EMAIL, PB_PASSWORD);
console.log('[test] OK');
const records = await listPurchaseOrders(pb, { perPage: 5 });
console.log(`[test] listed ${records.items.length} POs (filter respected).`);
if (records.items.length === 0) {
console.log('[test] no POs to soft-delete. done.');
process.exit(0);
}
const target = records.items[0];
console.log(`[test] soft-deleting ${target.id} …`);
await softDeletePurchaseOrder(pb, target.id);
const after = await listPurchaseOrders(pb, { perPage: 5 });
const stillPresent = after.items.some((r) => r.id === target.id);
console.log(`[test] after soft-delete: ${stillPresent ? 'STILL PRESENT (bad)' : 'HIDDEN (good)'}.`);
console.log(`[test] restoring ${target.id} …`);
await restorePurchaseOrder(pb, target.id);
const restored = await listPurchaseOrders(pb, { perPage: 5 });
const isBack = restored.items.some((r) => r.id === target.id);
console.log(`[test] after restore: ${isBack ? 'BACK (good)' : 'MISSING (bad)'}.`);
console.log('[test] PASS');