Files
mrp-qrcode/app/api/v1/operations/[id]/card.pdf/route.ts
T
jason 5847a175af
Build and Push Docker Image / build (push) Successful in 1m11s
stage 5-6
2026-04-21 13:14:27 -05:00

80 lines
2.5 KiB
TypeScript

import { type NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { errorResponse, requireRole, ApiError } from "@/lib/api";
import { renderOperationCard, type OperationCardData } from "@/lib/pdf";
/**
* Admin-only. Stream a one-page traveler card PDF for the given operation.
* We respond with `Content-Disposition: inline` so hitting the link in a
* new tab previews the PDF rather than forcing a download — makes the
* "print for the shop floor" flow a single click.
*/
export async function GET(_req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
try {
await requireRole("admin");
const { id } = await ctx.params;
const op = await prisma.operation.findUnique({
where: { id },
include: {
machine: { select: { name: true, kind: true } },
part: {
select: {
code: true,
name: true,
material: true,
qty: true,
assembly: {
select: {
code: true,
name: true,
project: { select: { code: true, name: true } },
},
},
},
},
},
});
if (!op) throw new ApiError(404, "not_found", "Operation not found");
const data: OperationCardData = {
project: op.part.assembly.project,
assembly: { code: op.part.assembly.code, name: op.part.assembly.name },
part: {
code: op.part.code,
name: op.part.name,
material: op.part.material,
qty: op.part.qty,
},
operation: {
id: op.id,
sequence: op.sequence,
name: op.name,
qrToken: op.qrToken,
machineName: op.machine?.name ?? null,
machineKind: op.machine?.kind ?? null,
settings: op.settings,
materialNotes: op.materialNotes,
instructions: op.instructions,
qcRequired: op.qcRequired,
plannedMinutes: op.plannedMinutes,
plannedUnits: op.plannedUnits,
},
};
const pdf = await renderOperationCard(data);
const safeName = `${op.part.code}-op${op.sequence}.pdf`.replace(/[^A-Za-z0-9._-]/g, "_");
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);
}
}