119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
// Add POS pricing and purchase-cost history fields to the stock schema.
|
|
// Idempotent: safe to run more than once.
|
|
/* eslint-disable */
|
|
import PocketBase from "pocketbase";
|
|
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 match = trimmed.match(/^([A-Z0-9_]+)\s*=\s*(.+)$/i);
|
|
if (match && !process.env[match[1]]) {
|
|
process.env[match[1]] = match[2].replace(/^['"]|['"]$/g, "").trim();
|
|
}
|
|
}
|
|
} catch {
|
|
// Fall back to environment variables already supplied by the shell.
|
|
}
|
|
}
|
|
|
|
loadEnvFile(".env");
|
|
loadEnvFile(".env.local");
|
|
|
|
async function main() {
|
|
const url = process.env.NEXT_PUBLIC_POCKETBASE_URL;
|
|
const email = process.env.PB_ADMIN_EMAIL;
|
|
const password = process.env.PB_ADMIN_PASSWORD;
|
|
if (!url || !email || !password) {
|
|
throw new Error(
|
|
"Set NEXT_PUBLIC_POCKETBASE_URL, PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD.",
|
|
);
|
|
}
|
|
|
|
const pb = new PocketBase(url);
|
|
await pb.collection("_superusers").authWithPassword(email, password);
|
|
|
|
const stockItems = await pb.collections.getOne("stock_items");
|
|
const categories = await pb.collections.getOne("categories");
|
|
const stockItemFields = (stockItems.fields ?? []) as Array<
|
|
Record<string, unknown>
|
|
>;
|
|
const existingStockNames = new Set(
|
|
stockItemFields.map((field) => field.name),
|
|
);
|
|
const additions: Array<Record<string, unknown>> = [
|
|
{
|
|
name: "cost_price",
|
|
type: "number",
|
|
required: false,
|
|
options: { min: 0, noDecimal: false },
|
|
},
|
|
{
|
|
name: "selling_price",
|
|
type: "number",
|
|
required: false,
|
|
options: { min: 0, noDecimal: false },
|
|
},
|
|
{
|
|
name: "markup",
|
|
type: "number",
|
|
required: false,
|
|
options: { min: 0, noDecimal: false },
|
|
},
|
|
{
|
|
name: "category",
|
|
type: "relation",
|
|
required: false,
|
|
collectionId: categories.id,
|
|
cascadeDelete: false,
|
|
maxSelect: 1,
|
|
},
|
|
{
|
|
name: "cost_history",
|
|
type: "json",
|
|
required: false,
|
|
options: { maxSize: 0 },
|
|
},
|
|
];
|
|
const missingStockFields = additions.filter(
|
|
(field) => !existingStockNames.has(field.name),
|
|
);
|
|
if (missingStockFields.length > 0) {
|
|
await pb.collections.update(stockItems.id, {
|
|
fields: [...stockItemFields, ...missingStockFields],
|
|
});
|
|
console.log(
|
|
`Added stock_items fields: ${missingStockFields.map((f) => f.name).join(", ")}`,
|
|
);
|
|
} else {
|
|
console.log("stock_items pricing fields already exist");
|
|
}
|
|
|
|
const ledger = await pb.collections.getOne("stock_ledger");
|
|
const ledgerFields = (ledger.fields ?? []) as Array<Record<string, unknown>>;
|
|
if (!ledgerFields.some((field) => field.name === "unit_cost")) {
|
|
await pb.collections.update(ledger.id, {
|
|
fields: [
|
|
...ledgerFields,
|
|
{
|
|
name: "unit_cost",
|
|
type: "number",
|
|
required: false,
|
|
options: { min: 0, noDecimal: false },
|
|
},
|
|
],
|
|
});
|
|
console.log("Added stock_ledger.unit_cost");
|
|
} else {
|
|
console.log("stock_ledger.unit_cost already exists");
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error("[add-stock-pricing-fields] failed:", error);
|
|
process.exit(1);
|
|
});
|