import { Elysia, t } from "elysia"; import prisma from "../lib/prisma"; export const rawMaterialsRoute = new Elysia({ prefix: "/raw-materials" }) .get("/", async () => { const rawMaterials = await prisma.rawMaterial.findMany({ orderBy: { name: "asc" }, }); return rawMaterials; }) .get("/:id", async ({ params, status }) => { const id = parseInt(params.id); if (isNaN(id)) return status(400, { message: "Invalid ID" }); const rawMaterial = await prisma.rawMaterial.findUnique({ where: { id }, include: { bomItems: { include: { productVariant: { include: { product: { select: { id: true, name: true, translations: { select: { langCode: true, name: true } } } } } } } } } }); if (!rawMaterial) return status(404, { message: "Raw material not found" }); const result = { ...rawMaterial, bomItems: rawMaterial.bomItems.map((item) => { const prod = item.productVariant?.product; if (!prod) return item; const thName = prod.translations?.find((t) => t.langCode === "th")?.name; const fallbackName = prod.translations?.[0]?.name; const resolvedName = prod.name || thName || fallbackName || `Product #${prod.id}`; return { ...item, productVariant: { ...item.productVariant, product: { ...prod, name: resolvedName, } } }; }) }; return result; }) .post("/bulk", async ({ body, status }) => { try { const items = Array.isArray(body) ? body : [body]; if (items.length === 0) { return status(400, { message: "Payload must be a non-empty array" }); } const results = await prisma.$transaction(async (tx) => { const records = []; for (const item of items) { const name = String(item.name || "").trim(); if (!name) continue; const unit = String(item.unit || "piece").trim() || "piece"; const rawPrice = item.pricePerUnit; const pricePerUnit = typeof rawPrice === "string" ? (parseFloat(rawPrice) || 0) : Number(rawPrice) || 0; const record = await tx.rawMaterial.upsert({ where: { name }, create: { name, unit, pricePerUnit, }, update: { unit, pricePerUnit, }, }); records.push(record); } return records; }); return status(200, { success: true, count: results.length, items: results, }); } catch (err: any) { console.error("Bulk raw material import failed:", err); return status(500, { message: "Failed to bulk import raw materials", error: err.message }); } }, { body: t.Array( t.Object({ name: t.String(), unit: t.Optional(t.String()), pricePerUnit: t.Union([t.Number(), t.String()]), }) ), detail: { tags: ["raw-materials"] } }) .post("/", async ({ body, status }) => { try { const rawMaterial = await prisma.rawMaterial.create({ data: body, }); return status(201, rawMaterial); } catch (err) { console.error(err); return status(500, { message: "Failed to create raw material" }); } }, { body: t.Object({ name: t.String(), unit: t.String(), pricePerUnit: t.Number(), }), detail: { tags: ["raw-materials"] } }) .put("/:id", async ({ params, body, status }) => { const id = parseInt(params.id); if (isNaN(id)) return status(400, { message: "Invalid ID" }); try { const updateData: any = {}; if (body.name !== undefined) updateData.name = String(body.name).trim(); if (body.unit !== undefined) updateData.unit = String(body.unit).trim(); if (body.pricePerUnit !== undefined) { updateData.pricePerUnit = typeof body.pricePerUnit === "string" ? parseFloat(body.pricePerUnit) || 0 : Number(body.pricePerUnit) || 0; } const rawMaterial = await prisma.rawMaterial.update({ where: { id }, data: updateData, }); return rawMaterial; } catch (err: any) { console.error(err); return status(500, { message: "Failed to update raw material", error: err.message }); } }, { body: t.Object({ name: t.Optional(t.String()), unit: t.Optional(t.String()), pricePerUnit: t.Optional(t.Union([t.Number(), t.String()])), }), detail: { tags: ["raw-materials"] } }) .delete("/:id", async ({ params, status }) => { const id = parseInt(params.id); if (isNaN(id)) return status(400, { message: "Invalid ID" }); try { await prisma.rawMaterial.delete({ where: { id }, }); return { success: true }; } catch (err) { console.error(err); return status(500, { message: "Failed to delete raw material" }); } }, { detail: { tags: ["raw-materials"] } });