57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { errorResponse, requireRole, ApiError } from "@/lib/api";
|
|
import { renderPurchaseOrder } from "@/lib/pdf";
|
|
|
|
export async function GET(_req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
|
|
try {
|
|
await requireRole("admin");
|
|
const { id } = await ctx.params;
|
|
|
|
const po = await prisma.purchaseOrder.findUnique({
|
|
where: { id },
|
|
include: {
|
|
project: { select: { code: true, name: true } },
|
|
lines: {
|
|
include: {
|
|
fastener: { select: { partNumber: true, description: true, supplier: true, unitCost: true } },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
if (!po) throw new ApiError(404, "not_found", "Purchase order not found");
|
|
|
|
const pdf = await renderPurchaseOrder({
|
|
po: {
|
|
id: po.id,
|
|
vendor: po.vendor,
|
|
status: po.status,
|
|
createdAt: po.createdAt,
|
|
sentAt: po.sentAt,
|
|
notes: po.notes,
|
|
},
|
|
project: po.project,
|
|
lines: po.lines.map((l) => ({
|
|
partNumber: l.fastener.partNumber,
|
|
description: l.fastener.description,
|
|
supplier: l.fastener.supplier,
|
|
qty: l.qty,
|
|
// line-level cost overrides the fastener's default if set
|
|
unitCost: l.unitCost ?? l.fastener.unitCost ?? null,
|
|
})),
|
|
});
|
|
|
|
const safeName = `PO-${po.id.slice(0, 8)}.pdf`;
|
|
return new NextResponse(pdf as unknown as BodyInit, {
|
|
status: 200,
|
|
headers: {
|
|
"Content-Type": "application/pdf",
|
|
"Content-Disposition": `inline; filename="${safeName}"`,
|
|
"Cache-Control": "private, no-store",
|
|
},
|
|
});
|
|
} catch (err) {
|
|
return errorResponse(err);
|
|
}
|
|
}
|