/** * Copyright (c) 2026 Niolla * All rights reserved. * * This source code is proprietary and confidential. * Unauthorized copying, modification, distribution, or use * of this file, via any medium, is strictly prohibited. */ // app/templates/documents/invoice/invoice.template.js const { log } = require("../../../utils/consoleLog.utill"); module.exports = async (data) => { log("📋 Preparing Invoice data for PDF..."); let payload = data; if (typeof payload === "string") { try { payload = JSON.parse(payload); } catch (error) { payload = {}; } } const source = payload.documentData || payload.document_data || payload.data || payload; const deepFind = (node, keys, visited = new Set()) => { if (!node || typeof node !== "object" || visited.has(node)) { return ""; } visited.add(node); for (const key of keys) { const value = node[key]; if (value !== undefined && value !== null && value !== "") { return value; } } for (const child of Object.values(node)) { const found = deepFind(child, keys, visited); if (found !== "") { return found; } } return ""; }; const pick = (...keys) => { const direct = deepFind(source, keys); if (direct !== "") { return direct; } return deepFind(payload, keys); }; const templateData = { logoUrl: pick("logoUrl", "logo_url") || "https://res.cloudinary.com/dtthuvvir/image/upload/v1780748661/company_logo_transperent_bg_uullzw.png", title: pick("title") || "INVOICE", jobReference: pick( "jobReference", "job_reference", "referenceNumber", "reference_no", "jobRef", "job_ref", ) || "", poNumber: pick("poNumber", "po_number", "poNo", "po_no") || "", date: pick("date") || new Date().toLocaleDateString(), pageLabel: pick("pageLabel", "page_label") || "Page 01 of 02", billToName: pick("billToName", "bill_to_name") || "Client Name", billToAddress: pick("billToAddress", "bill_to_address") || "Address", vesselName: pick("vesselName", "vessel_name") || "", purposeOfCall: pick("purposeOfCall", "purpose_of_call") || "", supplyDate: pick("supplyDate", "supply_date") || "", grt: pick("grt", "GRT") || "", imoNumber: pick("imoNumber", "imo_number", "imo") || "", portCountry: pick("portCountry", "port_country") || "", items: Array.isArray(source.items) ? source.items : [], subtotal: Number(pick("subtotal", "sub_total") || 0), tax: Number(pick("tax") || 0), discount: Number(pick("discount") || 0), total: Number(pick("total") || 0), paymentTerms: pick("paymentTerms", "payment_terms") || "", notes: pick("notes") || "", }; log("✅ Invoice data prepared"); return templateData; };