diff --git a/App/pelagia-portal/app/(portal)/po/[id]/actions.ts b/App/pelagia-portal/app/(portal)/po/[id]/actions.ts
index 219d0f9..aa28917 100644
--- a/App/pelagia-portal/app/(portal)/po/[id]/actions.ts
+++ b/App/pelagia-portal/app/(portal)/po/[id]/actions.ts
@@ -48,6 +48,42 @@ export async function provideVendorId({
return { ok: true };
}
+export async function submitDraftPo(
+ poId: string
+): Promise<{ ok: true } | { error: string }> {
+ const session = await auth();
+ if (!session?.user) return { error: "Unauthorized" };
+
+ const po = await db.purchaseOrder.findUnique({
+ where: { id: poId },
+ include: { submitter: true },
+ });
+ if (!po) return { error: "PO not found" };
+ if (po.status !== "DRAFT") return { error: "Only draft purchase orders can be submitted." };
+ if (po.submitterId !== session.user.id && session.user.role !== "SUPERUSER") {
+ return { error: "You can only submit your own purchase orders." };
+ }
+
+ await db.purchaseOrder.update({
+ where: { id: poId },
+ data: {
+ status: "MGR_REVIEW",
+ submittedAt: new Date(),
+ actions: {
+ create: { actionType: "SUBMITTED", actorId: session.user.id },
+ },
+ },
+ });
+
+ const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } });
+ await notify({ event: "PO_SUBMITTED", po, recipients: [po.submitter, ...managers] });
+
+ revalidatePath(`/po/${poId}`);
+ revalidatePath("/dashboard");
+ revalidatePath("/my-orders");
+ return { ok: true };
+}
+
export async function discardDraftPo(
poId: string
): Promise<{ ok: true } | { error: string }> {
diff --git a/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts b/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts
index 8d5d7e6..7a390a8 100644
--- a/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts
+++ b/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts
@@ -41,7 +41,7 @@ export async function updatePo(
return { error: "You can only edit your own purchase orders." };
}
- const intent = formData.get("intent") as "save" | "resubmit";
+ const intent = formData.get("intent") as "save" | "submit" | "resubmit";
const parsed = createPoSchema.safeParse({
title: formData.get("title"),
@@ -74,7 +74,9 @@ export async function updatePo(
0
);
+ const isSubmit = intent === "submit" && po.status === "DRAFT";
const isResubmit = intent === "resubmit" && po.status === "EDITS_REQUESTED";
+ const shouldSubmit = isSubmit || isResubmit;
// Before mutating, snapshot the current PO state so the manager can see
// exactly what the submitter changed when they resubmit after edits requested.
@@ -150,8 +152,8 @@ export async function updatePo(
tcPaymentTerms: data.tcPaymentTerms ?? null,
tcOthers: data.tcOthers ?? null,
totalAmount: total,
- status: isResubmit ? "MGR_REVIEW" : "DRAFT",
- submittedAt: isResubmit ? new Date() : po.submittedAt,
+ status: shouldSubmit ? "MGR_REVIEW" : "DRAFT",
+ submittedAt: shouldSubmit ? new Date() : po.submittedAt,
lineItems: {
deleteMany: {},
create: data.lineItems.map((item, idx) => ({
@@ -168,18 +170,18 @@ export async function updatePo(
})),
},
actions: {
- create: isResubmit
+ create: shouldSubmit
? {
actionType: "SUBMITTED",
actorId: session.user.id,
- ...(resubmitSnapshot ? { metadata: { editSnapshot: resubmitSnapshot } } : {}),
+ ...(isResubmit && resubmitSnapshot ? { metadata: { editSnapshot: resubmitSnapshot } } : {}),
}
: undefined,
},
},
});
- if (isResubmit) {
+ if (shouldSubmit) {
const [fullPo, managers] = await Promise.all([
db.purchaseOrder.findUnique({ where: { id: poId }, include: { submitter: true } }),
db.user.findMany({ where: { role: "MANAGER", isActive: true } }),
diff --git a/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx b/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx
index 519bd01..21de1be 100644
--- a/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx
+++ b/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx
@@ -53,12 +53,13 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) {
accountId: li.accountId ?? undefined,
}))
);
- const [submitting, setSubmitting] = useState<"save" | "resubmit" | null>(null);
+ const [submitting, setSubmitting] = useState<"save" | "submit" | "resubmit" | null>(null);
const [error, setError] = useState("");
const hasPerLineAccounts = po.lineItems.some((li) => li.accountId);
const [multiAccount, setMultiAccount] = useState(hasPerLineAccounts);
const [defaultAccountId, setDefaultAccountId] = useState(po.accountId ?? "");
+ const canSubmit = po.status === "DRAFT";
const canResubmit = po.status === "EDITS_REQUESTED";
async function handleSubmit(intent: "save" | "resubmit") {
@@ -283,6 +284,12 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) {
className="rounded-lg border border-neutral-300 bg-white px-4 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:opacity-60 transition-colors">
{submitting === "save" ? "Saving…" : "Save Draft"}
+ {canSubmit && (
+
+ )}
{canResubmit && (