WFDASH-WEBAPP/scripts/migrations/2026-07-15-add-stock-items-target-qty.ts
SJCoetz e9cf8aaf04 feat(stock): implement stock management workflow
This commit adds the complete v2/v3 stock management functionality:
- add new stock-specific item statuses and update the status visual map
- implement full stock purchase API suite (create, list, retrieve, send, receive)
- reorganize sidebar navigation to group stock-related pages together
- add stock item CRUD APIs, status utilities, low stock filtering, and surplus booking logic
- add database migration for the `stock_items.target_qty` field
- update type definitions and add comprehensive tests for all new stock components
2026-07-15 21:53:20 +02:00

72 lines
2.1 KiB
TypeScript

// scripts/migrations/2026-07-15-add-stock-items-target-qty.ts
//
// One-shot schema migration: add a `target_qty` number field to the
// `stock_items` collection. Used by the bulk-PO-from-low-stock flow
// (see src/app/(app)/stock-orders/new/page.tsx) to compute the order
// qty per line: `order_qty = max(0, target_qty - current_qty)`. Items
// with `target_qty` unset or 0 are opted out of the bulk flow.
//
// Idempotent: re-running is a no-op when the field is already present.
/* eslint-disable */
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
function loadEnvFile(name: string) {
try {
const raw = readFileSync(resolve(process.cwd(), name), "utf8");
for (const line of raw.split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const m = trimmed.match(/^([A-Z0-9_]+)\s*=\s*(.+)$/i);
if (m && !process.env[m[1]]) {
process.env[m[1]] = m[2].replace(/^["']|["']$/g, "").trim();
}
}
} catch {
// .env.local doesn't exist — fall through; PB env vars may be
// set in the shell.
}
}
loadEnvFile(".env.local");
import { getAdminPocketBase } from "@/lib/server/pocketbase-admin";
const COLLECTION_NAME = "stock_items";
const FIELD_NAME = "target_qty";
async function main() {
const pb = await getAdminPocketBase();
const collection = await pb.collections.getOne(COLLECTION_NAME);
const existing = (collection.fields ?? []) as Array<{ name: string }>;
if (existing.some((f) => f.name === FIELD_NAME)) {
console.log(`[stock-items-target-qty] field already present on ${COLLECTION_NAME}`);
return;
}
const newField = {
name: FIELD_NAME,
type: "number",
required: false,
options: {
min: 0,
noDecimal: false,
},
};
await pb.collections.update(collection.id, {
fields: [...existing, newField],
});
console.log(
`[stock-items-target-qty] created field on ${COLLECTION_NAME} (number, optional, min 0)`,
);
}
main().catch((err) => {
console.error("[stock-items-target-qty] failed:", err);
process.exit(1);
});