first commit

This commit is contained in:
Isuru Bimsara
2026-08-14 22:46:02 +05:30
commit 81d0e65686
132 changed files with 24398 additions and 0 deletions
@@ -0,0 +1,64 @@
/**
* 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/logic/documents/builders/invoice.builder.js
module.exports = {
sheetName: "Invoice",
build: async (worksheet, data) => {
worksheet.addRow(["INVOICE"]).font = {
bold: true,
size: 18,
};
worksheet.addRow([]);
worksheet.addRow(["Invoice No", data.invoiceNo]);
worksheet.addRow(["Customer", data.customerName]);
worksheet.addRow(["Date", data.date]);
worksheet.addRow([]);
const header = worksheet.addRow([
"Description",
"Qty",
"Rate",
"Amount",
]);
header.font = { bold: true };
let total = 0;
(data.items || []).forEach((item) => {
const amount = item.qty * item.rate;
total += amount;
worksheet.addRow([
item.description,
item.qty,
item.rate,
amount,
]);
});
worksheet.addRow([]);
worksheet.addRow([
"",
"",
"TOTAL",
total,
]).font = {
bold: true,
};
},
};
@@ -0,0 +1,68 @@
/**
* 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/logic/documents/builders/precost.builder.js
module.exports = {
sheetName: "PreCost Estimate",
build: async (worksheet, data) => {
worksheet.addRow(["PreCost Estimate"]).font = {
bold: true,
size: 16,
};
worksheet.addRow([]);
worksheet.addRow([
"Customer",
data.customerName || "",
]);
worksheet.addRow([]);
const header = worksheet.addRow([
"Item",
"Description",
"Qty",
"Unit Price",
"Total",
]);
header.font = { bold: true };
let total = 0;
(data.items || []).forEach((item) => {
const rowTotal = item.quantity * item.unit_price;
total += rowTotal;
worksheet.addRow([
item.item_name,
item.customer_remark ,
item.quantity,
item.unit_price,
rowTotal,
]);
});
worksheet.addRow([]);
worksheet.addRow([
"",
"",
"",
"Grand Total",
total,
]).font = {
bold: true,
};
},
};
@@ -0,0 +1,25 @@
/**
* 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/logic/documents/engine/excel.engine.js
const ExcelJS = require("exceljs");
const generateExcel = async (builder, data) => {
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet(builder.sheetName);
await builder.build(worksheet, data);
return await workbook.xlsx.writeBuffer();
};
module.exports = {
generateExcel,
};
+70
View File
@@ -0,0 +1,70 @@
/**
* 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/logic/documents/engine/pdf.engine.js
const puppeteer = require("puppeteer");
const generatePDF = async (html) => {
const launchConfig = {
args: ["--no-sandbox", "--disable-setuid-sandbox"],
};
if (process.env.PUPPETEER_EXECUTABLE_PATH) {
launchConfig.executablePath = process.env.PUPPETEER_EXECUTABLE_PATH;
} else {
launchConfig.headless = true;
}
const browser = await puppeteer.launch(launchConfig);
try {
const page = await browser.newPage();
await page.setContent(html, {
waitUntil: "load",
});
// Wait for fonts
await page.evaluate(() => document.fonts?.ready);
// Wait for images to fully decode
await page.evaluate(async () => {
const images = Array.from(document.images);
await Promise.all(
images.map((img) => {
if (img.complete && img.naturalHeight !== 0) return;
return new Promise((resolve) => {
img.onload = resolve;
img.onerror = resolve;
});
}),
);
});
// Force layout + paint
await page.evaluate(() => document.body.getBoundingClientRect());
// Extra stability delay (important on servers)
await new Promise((r) => setTimeout(r, 1000));
const buffer = await page.pdf({
format: "A4",
printBackground: true,
});
return buffer;
} finally {
await browser.close();
}
};
module.exports = { generatePDF };
+105
View File
@@ -0,0 +1,105 @@
/**
* 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/logic/documents/index.js
const registry = require("./registry");
const { generateExcel } = require("./engine/excel.engine");
const {
generatePdfFromPreCost,
generatePdfFromInvoice,
generatePdfFromDispatchNote,
generatePdfFromDeliveryNote,
generatePdfFromPO,
generatePdfFromCustomDocument,
generatePdfFromCreditNote,
} = require("../../utils/pdfGenerator");
const formatMeta = {
pdf: {
ext: "pdf",
mime: "application/pdf",
},
excel: {
ext: "xlsx",
mime:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
},
};
const pdfGenerators = {
precost: generatePdfFromPreCost,
invoice: generatePdfFromInvoice,
dispatchnote: generatePdfFromDispatchNote,
deliverynote: generatePdfFromDeliveryNote,
po: generatePdfFromPO,
customdocument: generatePdfFromCustomDocument,
creditnote: generatePdfFromCreditNote,
};
const generateDocument = async (
document,
format,
data
) => {
document = document.toLowerCase().replace(/[\s_-]+/g, "");
format = format.toLowerCase();
const doc = registry[document];
if (!doc) {
const availableTypes = Object.keys(registry).join(", ");
throw new Error(`Unsupported document type: "${document}". Available types: ${availableTypes}`);
}
let fileBuffer;
if (format === "pdf") {
// Format the data using the template
const formattedData = await doc.pdfTemplate(data);
// Get the correct PDF generator for this document type
const pdfGenerator = pdfGenerators[document];
if (pdfGenerator) {
fileBuffer = await pdfGenerator(formattedData);
} else {
throw new Error(`No PDF generator found for document type: ${document}`);
}
}
else if (format === "excel") {
if (doc.excelBuilder) {
fileBuffer = await generateExcel(
doc.excelBuilder,
data
);
} else {
throw new Error(`Excel generation not supported for document type: ${document}`);
}
}
else {
throw new Error("Unsupported format");
}
const meta = formatMeta[format];
return {
fileBuffer,
fileName: `${document}-${Date.now()}.${meta.ext}`,
mimeType: meta.mime,
};
};
module.exports = {
generateDocument,
};
+72
View File
@@ -0,0 +1,72 @@
/**
* 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/logic/documents/registry.js
let buildPreCostTemplate, buildInvoiceTemplate, buildDispatchNoteTemplate, buildDeliveryNoteTemplate, buildPOTemplate, buildCustomDocumentTemplate, buildCreditNoteTemplate;
let precostBuilder, invoiceBuilder;
try {
buildPreCostTemplate = require("../../templates/documents/precost/preCost.template");
buildInvoiceTemplate = require("../../templates/documents/invoice/invoice.template");
buildDispatchNoteTemplate = require("../../templates/documents/dispatchNote/dispatchNote.template");
buildDeliveryNoteTemplate = require("../../templates/documents/deliveryNote/deliveryNote.template");
buildPOTemplate = require("../../templates/documents/po/po.template");
buildCustomDocumentTemplate = require("../../templates/documents/customDocument/customDocument.template");
buildCreditNoteTemplate = require("../../templates/documents/creditNote/creditNote.template");
precostBuilder = require("./builders/precost.builder");
invoiceBuilder = require("./builders/invoice.builder");
console.log("✅ All document templates loaded successfully");
} catch (error) {
console.error("❌ Error loading document templates:", error.message);
console.error(error.stack);
}
const registry = {
precost: {
pdfTemplate: buildPreCostTemplate,
excelBuilder: precostBuilder,
},
invoice: {
pdfTemplate: buildInvoiceTemplate,
excelBuilder: invoiceBuilder,
},
dispatchnote: {
pdfTemplate: buildDispatchNoteTemplate,
excelBuilder: null,
},
deliverynote: {
pdfTemplate: buildDeliveryNoteTemplate,
excelBuilder: null,
},
po: {
pdfTemplate: buildPOTemplate,
excelBuilder: null,
},
customdocument: {
pdfTemplate: buildCustomDocumentTemplate,
excelBuilder: null,
},
creditnote: {
pdfTemplate: buildCreditNoteTemplate,
excelBuilder: null,
},
};
console.log("📋 Registry initialized with keys:", Object.keys(registry));
module.exports = registry;