pelagia-portal/App/app/(portal)/approvals/[id]/manager-line-edit-actions.ts
2026-05-18 23:18:58 +05:30

87 lines
2.6 KiB
TypeScript

"use server";
import { auth } from "@/auth";
import { db } from "@/lib/db";
import { hasPermission } from "@/lib/permissions";
import { revalidatePath } from "next/cache";
import { z } from "zod";
type ActionResult = { ok: true } | { error: string };
const lineItemSchema = z.object({
name: z.string().min(1),
description: z.string().optional(),
quantity: z.coerce.number().positive(),
unit: z.string().min(1),
size: z.string().optional(),
unitPrice: z.coerce.number().nonnegative(),
gstRate: z.coerce.number().min(0).max(1).default(0.18),
});
export async function managerEditLineItems({
poId,
lineItems,
}: {
poId: string;
lineItems: Array<{ name: string; description?: string; quantity: number; unit: string; size?: string; unitPrice: number }>;
}): Promise<ActionResult> {
const session = await auth();
if (!session?.user || !hasPermission(session.user.role, "approve_po")) {
return { error: "Forbidden" };
}
const parsed = z.array(lineItemSchema).min(1).safeParse(lineItems);
if (!parsed.success) return { error: parsed.error.errors[0].message };
const po = await db.purchaseOrder.findUnique({
where: { id: poId },
include: { lineItems: { orderBy: { sortOrder: "asc" } } },
});
if (!po) return { error: "PO not found" };
if (po.status !== "MGR_REVIEW") return { error: "Line items can only be edited while the PO is under review." };
const originalSnapshot = po.lineItems.map((li) => ({
name: (li as typeof li & { name: string }).name,
description: li.description ?? undefined,
quantity: Number(li.quantity),
unit: li.unit,
size: li.size ?? undefined,
unitPrice: Number(li.unitPrice),
}));
const newTotal = parsed.data.reduce(
(sum, item) => sum + item.quantity * item.unitPrice * (1 + item.gstRate),
0
);
await db.purchaseOrder.update({
where: { id: poId },
data: {
totalAmount: newTotal,
lineItems: {
deleteMany: {},
create: parsed.data.map((item, idx) => ({
name: item.name,
description: item.description ?? null,
quantity: item.quantity,
unit: item.unit,
size: item.size ?? null,
unitPrice: item.unitPrice,
totalPrice: item.quantity * item.unitPrice,
gstRate: item.gstRate,
sortOrder: idx,
})),
},
actions: {
create: {
actionType: "MANAGER_LINE_EDIT",
actorId: session.user.id,
metadata: { original: originalSnapshot },
},
},
},
});
revalidatePath(`/approvals/${poId}`);
return { ok: true };
}