phonepe #34

Merged
allentj merged 17 commits from phonepe into dev 2025-05-20 09:14:05 +00:00
4 changed files with 300 additions and 211 deletions

View File

@ -7,6 +7,7 @@
{
"source": "functions",
"codebase": "default",
"timeoutSeconds": 300,
"ignore": [
"node_modules",
".git",

View File

@ -18,6 +18,8 @@
"form-data": "^4.0.1",
"functions": "file:",
"html-to-text": "^9.0.5",
"jspdf": "^3.0.1",
"jspdf-autotable": "^5.0.2",
"long": "^5.3.2",
"mailgun.js": "^10.4.0",
"node-fetch": "^2.7.0",
@ -1101,6 +1103,14 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
"integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
@ -2859,6 +2869,12 @@
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz",
"integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA=="
},
"node_modules/@types/raf": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"optional": true
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
@ -2924,6 +2940,12 @@
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
"optional": true
},
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"optional": true
},
"node_modules/@types/yargs": {
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
@ -3066,6 +3088,17 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"bin": {
"atob": "bin/atob.js"
},
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@ -3248,6 +3281,15 @@
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"optional": true,
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -3379,6 +3421,17 @@
"node-int64": "^0.4.0"
}
},
"node_modules/btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
"bin": {
"btoa": "bin/btoa.js"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
@ -3494,6 +3547,25 @@
],
"peer": true
},
"node_modules/canvg": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
"optional": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
"core-js": "^3.8.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.7",
"rgbcolor": "^1.0.1",
"stackblur-canvas": "^2.0.0",
"svg-pathdata": "^6.0.3"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -3659,6 +3731,17 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-js": {
"version": "3.42.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz",
"integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==",
"hasInstallScript": true,
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
@ -3713,6 +3796,15 @@
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"optional": true,
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
@ -3888,6 +3980,15 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/dompurify": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz",
"integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==",
"optional": true,
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
@ -4269,6 +4370,11 @@
"bser": "2.1.1"
}
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -4833,6 +4939,19 @@
"node": ">=14"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"optional": true,
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
@ -6047,6 +6166,31 @@
"node": ">=10"
}
},
"node_modules/jspdf": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.1.tgz",
"integrity": "sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==",
"dependencies": {
"@babel/runtime": "^7.26.7",
"atob": "^2.1.2",
"btoa": "^1.2.1",
"fflate": "^0.8.1"
},
"optionalDependencies": {
"canvg": "^3.0.11",
"core-js": "^3.6.0",
"dompurify": "^3.2.4",
"html2canvas": "^1.0.0-rc.5"
}
},
"node_modules/jspdf-autotable": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.2.tgz",
"integrity": "sha512-YNKeB7qmx3pxOLcNeoqAv3qTS7KuvVwkFe5AduCawpop3NOkBUtqDToxNc225MlNecxT4kP2Zy3z/y/yvGdXUQ==",
"peerDependencies": {
"jspdf": "^2 || ^3"
}
},
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
@ -6765,6 +6909,12 @@
"url": "https://ko-fi.com/killymxi"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"optional": true
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -6960,6 +7110,15 @@
"node": ">=0.4.x"
}
},
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"optional": true,
"dependencies": {
"performance-now": "^2.1.0"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -7003,6 +7162,12 @@
"node": ">= 6"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"optional": true
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@ -7108,6 +7273,15 @@
"node": ">=14"
}
},
"node_modules/rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"optional": true,
"engines": {
"node": ">= 0.8.15"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -7431,6 +7605,15 @@
"node": ">=10"
}
},
"node_modules/stackblur-canvas": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
"optional": true,
"engines": {
"node": ">=0.1.14"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@ -7579,6 +7762,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"optional": true,
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/teeny-request": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
@ -7671,6 +7863,15 @@
"node": ">=8"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"optional": true,
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/tiny-inflate": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
@ -7931,6 +8132,15 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"optional": true,
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",

View File

@ -25,6 +25,8 @@
"form-data": "^4.0.1",
"functions": "file:",
"html-to-text": "^9.0.5",
"jspdf": "^3.0.1",
"jspdf-autotable": "^5.0.2",
"long": "^5.3.2",
"mailgun.js": "^10.4.0",
"node-fetch": "^2.7.0",

View File

@ -4,12 +4,8 @@ import * as os from 'os';
import * as path from 'path';
import { format } from 'date-fns';
import { sendEmailWithAttachmentUtil } from "../../../utils/emailService";
const pdfMake = require('pdfmake/build/pdfmake');
const pdfFonts = require('pdfmake/build/vfs_fonts');
pdfMake.vfs = pdfFonts.pdfMake ? pdfFonts.pdfMake.vfs : pdfFonts.vfs;
import { jsPDF } from "jspdf";
import 'jspdf-autotable';
const admin = getAdmin();
const logger = getLogger();
@ -54,216 +50,96 @@ export class InvoiceService {
const cgst = hasGst ? baseAmount * 0.09 : 0;
const formattedDate = format(data.paymentDate, 'dd/MM/yyyy');
const doc = new jsPDF();
const docDefinition: any = {
content: [
{
columns: [
[
{ text: data.businessName, style: 'businessName' },
{ text: data.address, style: 'businessAddress' },
hasGst ? { text: `GSTIN: ${data.gstNumber}`, style: 'businessDetails' } : {}
],
[
{ text: 'RECEIPT', style: 'invoiceTitle', alignment: 'right' },
{ text: `Receipt #: ${data.invoiceNumber}`, style: 'invoiceDetails', alignment: 'right' },
{ text: `Date: ${formattedDate}`, style: 'invoiceDetails', alignment: 'right' }
]
]
},
{ canvas: [{ type: 'line', x1: 0, y1: 5, x2: 515, y2: 5, lineWidth: 0.5 }] },
{ text: '', margin: [0, 10] },
doc.setFontSize(20);
doc.setFont('helvetica', 'bold');
doc.text(data.businessName, 20, 20);
{
style: 'customerBox',
table: {
widths: ['*'],
doc.setFontSize(12);
doc.setFont('helvetica', 'normal');
doc.text(data.address, 20, 30);
if (hasGst) {
doc.text(`GSTIN: ${data.gstNumber}`, 20, 40);
}
doc.setFontSize(24);
doc.setFont('helvetica', 'bold');
doc.text('RECEIPT', 190, 20, { align: 'right' });
doc.setFontSize(12);
doc.text(`Receipt #: ${data.invoiceNumber}`, 190, 30, { align: 'right' });
doc.text(`Date: ${formattedDate}`, 190, 40, { align: 'right' });
doc.line(20, 45, 190, 45);
doc.setFontSize(12);
doc.setFont('helvetica', 'bold');
doc.text('Receipt To:', 20, 60);
doc.setFont('helvetica', 'normal');
doc.text(data.customerName, 20, 70);
doc.text(`Phone: ${data.phoneNumber}`, 20, 80);
doc.text(`Email: ${data.email}`, 20, 90);
(doc as any).autoTable({
startY: 110,
head: [['No.', 'Description', 'HSN/SAC', 'Amount (INR)']],
body: [
[
{
stack: [
{ text: 'Receipt To:', style: 'customerTitle' },
{ text: data.customerName, style: 'customerDetails' },
{ text: `Phone: ${data.phoneNumber}`, style: 'customerDetails' },
{ text: `Email: ${data.email}`, style: 'customerDetails' }
['1', `${data.planName} Subscription`, '999723', baseAmount.toFixed(2)]
],
margin: [10, 10]
headStyles: { fillColor: [220, 220, 220], textColor: [0, 0, 0], fontStyle: 'bold' },
styles: { halign: 'center' },
columnStyles: {
0: { halign: 'center', cellWidth: 20 },
1: { halign: 'left' },
2: { halign: 'center', cellWidth: 40 },
3: { halign: 'right', cellWidth: 40 }
}
]
]
},
layout: 'lightHorizontalLines'
},
{ text: '', margin: [0, 10] },
{
table: {
headerRows: 1,
widths: [30, '*', 80, 100],
body: [
[
{ text: 'No.', style: 'tableHeader', alignment: 'center' },
{ text: 'Description', style: 'tableHeader' },
{ text: 'HSN/SAC', style: 'tableHeader', alignment: 'center' },
{ text: 'Amount (INR)', style: 'tableHeader', alignment: 'right' }
],
[
{ text: '1', alignment: 'center' },
{ text: `${data.planName} Subscription` },
{ text: '999723', alignment: 'center' },
{ text: baseAmount.toFixed(2), alignment: 'right' }
]
]
}
},
{ text: '', margin: [0, 10] },
{
columns: [
{ width: '*', text: '' },
{
width: 'auto',
table: {
widths: [100, 100],
body: hasGst ? [
[
{ text: 'Taxable Amount:', alignment: 'right' },
{ text: `${baseAmount.toFixed(2)} INR`, alignment: 'right' }
],
[
{ text: 'SGST (9%):', alignment: 'right' },
{ text: `${sgst.toFixed(2)} INR`, alignment: 'right' }
],
[
{ text: 'CGST (9%):', alignment: 'right' },
{ text: `${cgst.toFixed(2)} INR`, alignment: 'right' }
],
[
{ text: 'Total Amount:', style: 'totalAmount', alignment: 'right' },
{ text: `${data.amount.toFixed(2)} INR`, style: 'totalAmount', alignment: 'right' }
]
] : [
[
{ text: 'Total Amount:', style: 'totalAmount', alignment: 'right' },
{ text: `${data.amount.toFixed(2)} INR`, style: 'totalAmount', alignment: 'right' }
]
]
},
layout: {
hLineWidth: function(i: number, node: any) {
return (i === node.table.body.length - 1) ? 0.5 : 0;
},
vLineWidth: function() { return 0; }
}
}
]
},
{ text: '', margin: [0, 20] },
{
style: 'paymentBox',
table: {
widths: ['*'],
body: [
[
{
stack: [
{ text: 'Payment Information:', style: 'paymentTitle' },
{ text: `Transaction ID: ${data.transactionId}`, style: 'paymentDetails' },
{ text: `Payment Method: ${data.paymentMethod}`, style: 'paymentDetails' },
{ text: `Payment Date: ${formattedDate}`, style: 'paymentDetails' }
],
margin: [10, 10]
}
]
]
},
layout: 'lightHorizontalLines'
},
{ text: '', margin: [0, 20] },
{ text: 'Thank you for your business!', style: 'footer', alignment: 'center' },
{ text: 'This is a computer-generated receipt and does not require a signature.', style: 'disclaimer', alignment: 'center' }
],
styles: {
businessName: {
fontSize: 20,
bold: true,
margin: [0, 0, 0, 5]
},
businessAddress: {
fontSize: 12,
margin: [0, 0, 0, 5]
},
businessDetails: {
fontSize: 12
},
invoiceTitle: {
fontSize: 24,
bold: true
},
invoiceDetails: {
fontSize: 12,
margin: [0, 5, 0, 0]
},
customerBox: {
margin: [0, 10, 0, 10]
},
customerTitle: {
fontSize: 12,
bold: true,
margin: [0, 0, 0, 5]
},
customerDetails: {
fontSize: 12,
margin: [0, 2, 0, 0]
},
tableHeader: {
fontSize: 12,
bold: true,
margin: [0, 5, 0, 5]
},
totalAmount: {
fontSize: 12,
bold: true
},
paymentBox: {
margin: [0, 10, 0, 10]
},
paymentTitle: {
fontSize: 12,
bold: true,
margin: [0, 0, 0, 5]
},
paymentDetails: {
fontSize: 12,
margin: [0, 2, 0, 0]
},
footer: {
fontSize: 12,
italics: true,
margin: [0, 0, 0, 5]
},
disclaimer: {
fontSize: 10
}
},
defaultStyle: {
font: 'Helvetica'
}
};
const pdfDoc = pdfMake.createPdf(docDefinition);
await new Promise<void>((resolve, reject) => {
pdfDoc.getBuffer((buffer: Buffer) => {
fs.writeFile(tempFilePath, buffer, (err) => {
if (err) reject(err);
else resolve();
});
});
});
const finalY = (doc as any).lastAutoTable.finalY + 20;
if (hasGst) {
doc.text('Taxable Amount:', 150, finalY, { align: 'right' });
doc.text(`${baseAmount.toFixed(2)} INR`, 190, finalY, { align: 'right' });
doc.text('SGST (9%):', 150, finalY + 10, { align: 'right' });
doc.text(`${sgst.toFixed(2)} INR`, 190, finalY + 10, { align: 'right' });
doc.text('CGST (9%):', 150, finalY + 20, { align: 'right' });
doc.text(`${cgst.toFixed(2)} INR`, 190, finalY + 20, { align: 'right' });
doc.setFont('helvetica', 'bold');
doc.text('Total Amount:', 150, finalY + 30, { align: 'right' });
doc.text(`${data.amount.toFixed(2)} INR`, 190, finalY + 30, { align: 'right' });
} else {
doc.setFont('helvetica', 'bold');
doc.text('Total Amount:', 150, finalY, { align: 'right' });
doc.text(`${data.amount.toFixed(2)} INR`, 190, finalY, { align: 'right' });
}
const paymentY = hasGst ? finalY + 50 : finalY + 20;
doc.setFont('helvetica', 'bold');
doc.text('Payment Information:', 20, paymentY);
doc.setFont('helvetica', 'normal');
doc.text(`Transaction ID: ${data.transactionId}`, 20, paymentY + 10);
doc.text(`Payment Method: ${data.paymentMethod}`, 20, paymentY + 20);
doc.text(`Payment Date: ${formattedDate}`, 20, paymentY + 30);
doc.setFontSize(12);
doc.setFont('helvetica', 'italic');
doc.text('Thank you for your business!', 105, 270, { align: 'center' });
doc.setFontSize(10);
doc.setFont('helvetica', 'normal');
doc.text('This is a computer-generated receipt and does not require a signature.', 105, 280, { align: 'center' });
fs.writeFileSync(tempFilePath, Buffer.from(doc.output('arraybuffer')));
const invoicePath = `invoices/${data.invoiceNumber}.pdf`;
const bucket = admin.storage().bucket();
await bucket.upload(tempFilePath, {