From 79694f8be6a4fc88f6f10d98f4d7107a9f1599ff Mon Sep 17 00:00:00 2001 From: Lixian Zhou Date: Thu, 12 Mar 2026 14:38:52 -0400 Subject: [PATCH] fix --- app/controllers/report.controller.js | 41 +++++++++++++------ .../trans-routes/RouteReportWithSignature.js | 9 ++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/app/controllers/report.controller.js b/app/controllers/report.controller.js index c683fb1..d96250e 100644 --- a/app/controllers/report.controller.js +++ b/app/controllers/report.controller.js @@ -5,12 +5,13 @@ const path = require("path"); const crypto = require("crypto"); const moment = require("moment-timezone"); const archiver = require("archiver"); -const { PDFDocument } = require("pdf-lib"); +const { PDFDocument, rgb } = require("pdf-lib"); const fontkit = require("@pdf-lib/fontkit"); const Report = db.report; const RoutePath = db.route_path; const Employee = db.employee; const Vehicle = db.vehicle; +const Customer = db.customer; const ROOT_DIR = path.resolve(__dirname, "../.."); const TARGET_TIMEZONE = "America/New_York"; @@ -105,6 +106,12 @@ const safeSetField = (form, fieldName, value, options = {}) => { if (typeof options.fontSize === "number") { field.setFontSize(options.fontSize); } + if (options.center === true) { + field.setAlignment(1); + } + if (options.blackText === true) { + field.setTextColor(rgb(0, 0, 0)); + } field.setText(text); return; } catch (_textErr) {} @@ -181,7 +188,7 @@ const appendNoticeLine = (parts, text) => { } }; -const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, vehiclesMap, outboundCustomerStatuses, unicodeFontBytes, allRoutes) => { +const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, vehiclesMap, outboundCustomerStatuses, unicodeFontBytes, allRoutes, customerNotesById) => { const pdfDoc = await PDFDocument.load(templateBytes); pdfDoc.registerFontkit(fontkit); const unicodeFont = await pdfDoc.embedFont(unicodeFontBytes, { subset: true }); @@ -209,7 +216,9 @@ const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, veh safeSetField(form, `name_${row}`, customer?.customer_name || ""); safeSetField(form, `addr_${row}`, customer?.customer_address || ""); safeSetField(form, `phone_${row}`, customer?.customer_phone || ""); - const customerNoteText = resolveNoteFromCandidates(customer, relativeRouteCustomer, customerInOtherRoute); + const customerId = toObjectIdText(customer?.customer_id); + const profileNoteToDriver = (customerNotesById?.get(customerId) || "").toString().trim(); + const customerNoteText = profileNoteToDriver || resolveNoteFromCandidates(customer, relativeRouteCustomer, customerInOtherRoute); safeSetField(form, `note_${row}`, customerNoteText); const pickupTime = formatUtcToLocalHm( @@ -229,14 +238,14 @@ const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, veh if (enterCenterTime) { safeSetField(form, `arrive_${row}`, enterCenterTime); } - safeSetField(form, `y_${row}`, "✓", { fontSize: 11 }); - safeSetField(form, `n_${row}`, "", { fontSize: 11 }); + safeSetField(form, `y_${row}`, "✓", { fontSize: 12, center: true, blackText: true }); + safeSetField(form, `n_${row}`, "", { fontSize: 12, center: true, blackText: true }); } else if (hasInCenterStatusByCandidate(customer, relativeRouteCustomer, customerInOtherRoute)) { - safeSetField(form, `y_${row}`, "✓", { fontSize: 11 }); - safeSetField(form, `n_${row}`, "", { fontSize: 11 }); + safeSetField(form, `y_${row}`, "✓", { fontSize: 12, center: true, blackText: true }); + safeSetField(form, `n_${row}`, "", { fontSize: 12, center: true, blackText: true }); } else { - safeSetField(form, `y_${row}`, "", { fontSize: 11 }); - safeSetField(form, `n_${row}`, "✕", { fontSize: 11 }); + safeSetField(form, `y_${row}`, "", { fontSize: 12, center: true, blackText: true }); + safeSetField(form, `n_${row}`, "✕", { fontSize: 12, center: true, blackText: true }); } const outboundStatus = findOutboundStatusByCustomerId(outboundCustomerStatuses, customer?.customer_id); @@ -440,10 +449,11 @@ exports.exportRouteReportZip = async (req, res) => { return res.status(500).send({ message: "Missing Unicode font file: NotoSansSC-Regular.ttf" }); } - const [routes, drivers, vehicles] = await Promise.all([ + const [routes, drivers, vehicles, customers] = await Promise.all([ RoutePath.find(splitSite.splitSiteGet(req, { schedule_date: date, status: { $ne: "disabled" } })), Employee.find(splitSite.splitSiteGet(req, {})), - Vehicle.find(splitSite.splitSiteGet(req, { status: "active" })) + Vehicle.find(splitSite.splitSiteGet(req, { status: "active" })), + Customer.find(splitSite.splitSiteGet(req, {})) ]); const outboundRoutes = (routes || []).filter((route) => route?.type === "outbound"); @@ -464,6 +474,12 @@ exports.exportRouteReportZip = async (req, res) => { vehicle ]) ); + const customerNotesById = new Map( + (customers || []).map((customer) => [ + toObjectIdText(customer?._id || customer?.id), + (customer?.notes_for_driver || "").toString().trim() + ]) + ); const getRouteVehicleNumber = (route) => { const vehicleId = toObjectIdText(route?.vehicle); const vehicleNumberRaw = vehiclesMap.get(vehicleId)?.vehicle_number; @@ -511,7 +527,8 @@ exports.exportRouteReportZip = async (req, res) => { vehiclesMap, outboundCustomerStatuses, unicodeFontBytes, - routes + routes, + customerNotesById ); const base = sanitizeFileName(route?.name || `route_${i + 1}`) || `route_${i + 1}`; const existingCount = filenameCounter.get(base) || 0; diff --git a/client/src/components/trans-routes/RouteReportWithSignature.js b/client/src/components/trans-routes/RouteReportWithSignature.js index ed1714f..8287392 100644 --- a/client/src/components/trans-routes/RouteReportWithSignature.js +++ b/client/src/components/trans-routes/RouteReportWithSignature.js @@ -85,7 +85,8 @@ const RouteReportWithSignature = () => { (res?.data || []).forEach((customer) => { nextMap.set(customer?.id, { program_type: customer?.program_type || '', - pay_source: customer?.pay_source || '' + pay_source: customer?.pay_source || '', + notes_for_driver: customer?.notes_for_driver || '' }); }); setCustomerMetaById(nextMap); @@ -183,7 +184,9 @@ const RouteReportWithSignature = () => { return { y: '', n: '✗' }; }; - const getRouteNoteToDriverText = (...customerCandidates) => { + const getRouteNoteToDriverText = (customerId, ...customerCandidates) => { + const profileNote = (customerMetaById.get(customerId)?.notes_for_driver || '').toString().trim(); + if (profileNote) return profileNote; for (const item of customerCandidates) { const noteText = (item?.customer_note || '').toString().trim(); if (noteText) return noteText; @@ -317,7 +320,7 @@ const RouteReportWithSignature = () => { const customerInOtherRoute = otherRouteWithThisCustomer?.route_customer_list?.find(cust => cust?.customer_id === customer?.customer_id); const otherOutboundRoute = getOtherOutboundRouteWithThisCustomer(customer?.customer_id); const attendanceDisplay = getAttendanceDisplayByReportLogic(customer, relativeRouteCustomer, customerInOtherRoute); - const routeNoteText = getRouteNoteToDriverText(customer, relativeRouteCustomer, customerInOtherRoute); + const routeNoteText = getRouteNoteToDriverText(customer?.customer_id, customer, relativeRouteCustomer, customerInOtherRoute); return (