import { createRoute } from "../../../../../modules/api-utils/createRoute"; import { generatedQuotes } from "../../../../../managers/generatedQuotes"; import { apiResponse } from "../../../../../modules/api-utils/apiResponse"; import { injectPdfMetadata } from "../../../../../modules/pdf-utils"; import { ContentfulStatusCode } from "hono/utils/http-status"; import { authMiddleware } from "../../../../middleware/authorization"; import GenericError from "../../../../../Errors/GenericError"; const VALID_FETCH_ACTIONS = ["download", "print"] as const; type FetchAction = (typeof VALID_FETCH_ACTIONS)[number]; /* GET /v1/sales/opportunities/:identifier/quote/:quoteId/download?fetchAction=download|print */ export default createRoute( "get", ["/opportunities/:identifier/quote/:quoteId/download"], async (c) => { const quoteId = c.req.param("quoteId"); const user = c.get("user"); const fetchAction = c.req.query("fetchAction") as FetchAction | undefined; if (!fetchAction || !VALID_FETCH_ACTIONS.includes(fetchAction)) { throw new GenericError({ status: 400, name: "InvalidFetchAction", message: `Query parameter 'fetchAction' is required and must be one of: ${VALID_FETCH_ACTIONS.join(", ")}`, }); } const downloadedAt = new Date().toISOString(); const quote = await generatedQuotes.recordDownload(quoteId, { id: user.id, name: user.name, email: user.email, fetchAction, }); // Inject download-time metadata into the PDF's document properties const pdfWithMetadata = await injectPdfMetadata(quote.quoteFile, { downloadedAt, downloadedById: user.id, downloadedByName: user.name ?? undefined, downloadedByEmail: user.email ?? undefined, }); const response = apiResponse.successful("Quote downloaded successfully!", { id: quote.id, quoteFileName: quote.quoteFileName, mimeType: "application/pdf", contentBase64: Buffer.from(pdfWithMetadata).toString("base64"), }); return c.json(response, response.status as ContentfulStatusCode); }, authMiddleware({ permissions: ["sales.opportunity.quote.download"] }), );