phonepe #31
286
functions/package-lock.json
generated
286
functions/package-lock.json
generated
@ -22,12 +22,14 @@
|
||||
"mailgun.js": "^10.4.0",
|
||||
"node-fetch": "^2.7.0",
|
||||
"pdfjs-dist": "^5.0.375",
|
||||
"pdfmake": "^0.2.20",
|
||||
"twilio": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/long": "^5.0.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/pdfmake": "^0.2.11",
|
||||
"firebase-functions-test": "^3.1.0",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
@ -1260,6 +1262,52 @@
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@foliojs-fork/fontkit": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.2.tgz",
|
||||
"integrity": "sha512-IfB5EiIb+GZk+77TRB86AHroVaqfq8JRFlUbz0WEwsInyCG0epX2tCPOy+UfaWPju30DeVoUAXfzWXmhn753KA==",
|
||||
"dependencies": {
|
||||
"@foliojs-fork/restructure": "^2.0.2",
|
||||
"brotli": "^1.2.0",
|
||||
"clone": "^1.0.4",
|
||||
"deep-equal": "^1.0.0",
|
||||
"dfa": "^1.2.0",
|
||||
"tiny-inflate": "^1.0.2",
|
||||
"unicode-properties": "^1.2.2",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@foliojs-fork/linebreak": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.2.tgz",
|
||||
"integrity": "sha512-ZPohpxxbuKNE0l/5iBJnOAfUaMACwvUIKCvqtWGKIMv1lPYoNjYXRfhi9FeeV9McBkBLxsMFWTVVhHJA8cyzvg==",
|
||||
"dependencies": {
|
||||
"base64-js": "1.3.1",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@foliojs-fork/linebreak/node_modules/base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
},
|
||||
"node_modules/@foliojs-fork/pdfkit": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.15.3.tgz",
|
||||
"integrity": "sha512-Obc0Wmy3bm7BINFVvPhcl2rnSSK61DQrlHU8aXnAqDk9LCjWdUOPwhgD8Ywz5VtuFjRxmVOM/kQ/XLIBjDvltw==",
|
||||
"dependencies": {
|
||||
"@foliojs-fork/fontkit": "^1.9.2",
|
||||
"@foliojs-fork/linebreak": "^1.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"jpeg-exif": "^1.1.4",
|
||||
"png-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@foliojs-fork/restructure": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz",
|
||||
"integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA=="
|
||||
},
|
||||
"node_modules/@google-cloud/firestore": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz",
|
||||
@ -2787,6 +2835,25 @@
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pdfkit": {
|
||||
"version": "0.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.13.9.tgz",
|
||||
"integrity": "sha512-RDG8Yb1zT7I01FfpwK7nMSA433XWpblMqSCtA5vJlSyavWZb303HUYPCel6JTiDDFqwGLvtAnYbH8N/e0Cb89g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pdfmake": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/pdfmake/-/pdfmake-0.2.11.tgz",
|
||||
"integrity": "sha512-gglgMQhnG6C2kco13DJlvokqTxL+XKxHwCejElH8fSCNF9ZCkRK6Mzo011jQ0zuug+YlIgn6BpcpZrARyWdW3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/pdfkit": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz",
|
||||
@ -3261,6 +3328,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.24.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
||||
@ -3483,6 +3558,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
|
||||
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
@ -3625,6 +3708,11 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
@ -3653,6 +3741,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deep-equal": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||
"dependencies": {
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-date-object": "^1.0.5",
|
||||
"is-regex": "^1.1.4",
|
||||
"object-is": "^1.1.5",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
@ -3677,6 +3784,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
@ -3712,6 +3835,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
|
||||
},
|
||||
"node_modules/diff-sequences": {
|
||||
"version": "29.6.3",
|
||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
|
||||
@ -4351,6 +4479,14 @@
|
||||
"resolved": "",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
|
||||
@ -4950,6 +5086,21 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-date-object": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
|
||||
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
@ -5772,6 +5923,11 @@
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-exif": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz",
|
||||
"integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ=="
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -6366,6 +6522,29 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
@ -6456,6 +6635,11 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
@ -6548,6 +6732,31 @@
|
||||
"@napi-rs/canvas": "^0.1.67"
|
||||
}
|
||||
},
|
||||
"node_modules/pdfmake": {
|
||||
"version": "0.2.20",
|
||||
"resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.20.tgz",
|
||||
"integrity": "sha512-bGbxbGFP5p8PWNT3Phsu1ZcRLnRfF6jmnuKTkgmt6i5PZzSdX6JaB+NeTz9q+aocfW8SE9GUjL3o/5GroBqGcQ==",
|
||||
"dependencies": {
|
||||
"@foliojs-fork/linebreak": "^1.1.2",
|
||||
"@foliojs-fork/pdfkit": "^0.15.3",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"xmldoc": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/pdfmake/node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
@ -6599,6 +6808,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/png-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
|
||||
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||
@ -6789,6 +7003,25 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"set-function-name": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@ -7023,6 +7256,20 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-name": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
|
||||
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"functions-have-names": "^1.2.3",
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@ -7424,6 +7671,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
|
||||
},
|
||||
"node_modules/tmpl": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
@ -7582,6 +7834,24 @@
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
@ -7842,6 +8112,22 @@
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xmldoc": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.1.tgz",
|
||||
"integrity": "sha512-sOOqgsjl3PU6iBw+fBUGAkTCE+JFK+sBaOL3pnZgzqk2/yvOD7RlFmZtDRJAEBzdpOYxSXyOQH4mjubdfs3MSg==",
|
||||
"dependencies": {
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xmldoc/node_modules/sax": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
@ -29,12 +29,14 @@
|
||||
"mailgun.js": "^10.4.0",
|
||||
"node-fetch": "^2.7.0",
|
||||
"pdfjs-dist": "^5.0.375",
|
||||
"pdfmake": "^0.2.20",
|
||||
"twilio": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/long": "^5.0.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/pdfmake": "^0.2.11",
|
||||
"firebase-functions-test": "^3.1.0",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import { getAdmin, getLogger } from "../../../shared/config";
|
||||
import PDFDocument from 'pdfkit';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { format } from 'date-fns';
|
||||
import { sendEmailWithAttachmentUtil } from "../../../utils/emailService";
|
||||
import * as pdfMake from 'pdfmake/build/pdfmake';
|
||||
import * as pdfFonts from 'pdfmake/build/vfs_fonts';
|
||||
|
||||
(pdfMake as any).vfs = pdfFonts.vfs;
|
||||
|
||||
const admin = getAdmin();
|
||||
const logger = getLogger();
|
||||
@ -43,99 +46,223 @@ export class InvoiceService {
|
||||
async generateInvoice(data: InvoiceData): Promise<string> {
|
||||
try {
|
||||
const tempFilePath = path.join(os.tmpdir(), `invoice_${data.invoiceNumber}.pdf`);
|
||||
const doc = new PDFDocument({ margin: 50 });
|
||||
|
||||
// Create a write stream to the temporary file
|
||||
const writeStream = fs.createWriteStream(tempFilePath);
|
||||
doc.pipe(writeStream);
|
||||
|
||||
// Check if GST is applicable
|
||||
const hasGst = data.gstNumber && data.gstNumber.length > 0;
|
||||
const baseAmount = hasGst ? data.amount / 1.18 : data.amount;
|
||||
const sgst = hasGst ? baseAmount * 0.09 : 0;
|
||||
const cgst = hasGst ? baseAmount * 0.09 : 0;
|
||||
|
||||
// Add business details
|
||||
doc.fontSize(20).font('Helvetica-Bold').text(data.businessName, 50, 50);
|
||||
doc.fontSize(12).font('Helvetica').text(data.address, 50, 75, { width: 250 });
|
||||
if (hasGst) {
|
||||
doc.text(`GSTIN: ${data.gstNumber}`, 50, 115);
|
||||
const formattedDate = format(data.paymentDate, 'dd/MM/yyyy');
|
||||
|
||||
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] },
|
||||
|
||||
{
|
||||
style: 'customerBox',
|
||||
table: {
|
||||
widths: ['*'],
|
||||
body: [
|
||||
[
|
||||
{
|
||||
stack: [
|
||||
{ text: 'Receipt To:', style: 'customerTitle' },
|
||||
{ text: data.customerName, style: 'customerDetails' },
|
||||
{ text: `Phone: ${data.phoneNumber}`, style: 'customerDetails' },
|
||||
{ text: `Email: ${data.email}`, style: 'customerDetails' }
|
||||
],
|
||||
margin: [10, 10]
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
layout: 'lightHorizontalLines'
|
||||
},
|
||||
{ text: '', margin: [0, 10] },
|
||||
|
||||
// Add invoice title and details
|
||||
doc.fontSize(24).font('Helvetica-Bold').text('RECEIPT', 400, 50, { align: 'right' });
|
||||
doc.fontSize(12).font('Helvetica').text(`Receipt #: ${data.invoiceNumber}`, 400, 80, { align: 'right' });
|
||||
doc.text(`Date: ${format(data.paymentDate, 'dd/MM/yyyy')}`, 400, 95, { align: 'right' });
|
||||
|
||||
// Add customer details
|
||||
doc.rect(50, 150, 500, 80).stroke();
|
||||
doc.fontSize(12).font('Helvetica-Bold').text('Receipt To:', 60, 160);
|
||||
doc.fontSize(12).font('Helvetica').text(data.customerName, 60, 175);
|
||||
doc.text(`Phone: ${data.phoneNumber}`, 60, 190);
|
||||
doc.text(`Email: ${data.email}`, 60, 205);
|
||||
|
||||
// Add table header
|
||||
const tableTop = 260;
|
||||
doc.rect(50, tableTop, 500, 30).stroke();
|
||||
doc.fontSize(12).font('Helvetica-Bold').text('No.', 60, tableTop + 10, { width: 30, align: 'center' });
|
||||
doc.text('Description', 100, tableTop + 10, { width: 250 });
|
||||
doc.text('HSN/SAC', 350, tableTop + 10, { width: 80, align: 'center' });
|
||||
doc.text('Amount (INR)', 430, tableTop + 10, { width: 100, align: 'right' });
|
||||
|
||||
// Add table row
|
||||
const rowTop = tableTop + 30;
|
||||
doc.rect(50, rowTop, 500, 30).stroke();
|
||||
doc.fontSize(12).font('Helvetica').text('1', 60, rowTop + 10, { width: 30, align: 'center' });
|
||||
doc.text(`${data.planName} Subscription`, 100, rowTop + 10, { width: 250 });
|
||||
doc.text('999723', 350, rowTop + 10, { width: 80, align: 'center' });
|
||||
doc.text(baseAmount.toFixed(2), 430, rowTop + 10, { width: 100, align: 'right' });
|
||||
|
||||
// Add totals
|
||||
let currentY = rowTop + 50;
|
||||
|
||||
if (hasGst) {
|
||||
doc.fontSize(12).font('Helvetica').text('Taxable Amount:', 350, currentY, { width: 100, align: 'right' });
|
||||
doc.text(`${baseAmount.toFixed(2)} INR`, 450, currentY, { width: 100, align: 'right' });
|
||||
currentY += 20;
|
||||
|
||||
doc.text('SGST (9%):', 350, currentY, { width: 100, align: 'right' });
|
||||
doc.text(`${sgst.toFixed(2)} INR`, 450, currentY, { width: 100, align: 'right' });
|
||||
currentY += 20;
|
||||
|
||||
doc.text('CGST (9%):', 350, currentY, { width: 100, align: 'right' });
|
||||
doc.text(`${cgst.toFixed(2)} INR`, 450, currentY, { width: 100, align: 'right' });
|
||||
currentY += 20;
|
||||
{
|
||||
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] },
|
||||
|
||||
doc.moveTo(350, currentY).lineTo(550, currentY).stroke();
|
||||
currentY += 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] },
|
||||
|
||||
doc.fontSize(12).font('Helvetica-Bold').text('Total Amount:', 350, currentY, { width: 100, align: 'right' });
|
||||
doc.text(`${data.amount.toFixed(2)} INR`, 450, currentY, { width: 100, align: 'right' });
|
||||
{
|
||||
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] },
|
||||
|
||||
// Add payment information
|
||||
currentY += 40;
|
||||
doc.rect(50, currentY, 500, 80).stroke();
|
||||
doc.fontSize(12).font('Helvetica-Bold').text('Payment Information:', 60, currentY + 10);
|
||||
doc.fontSize(12).font('Helvetica').text(`Transaction ID: ${data.transactionId}`, 60, currentY + 30);
|
||||
doc.text(`Payment Method: ${data.paymentMethod}`, 60, currentY + 45);
|
||||
doc.text(`Payment Date: ${format(data.paymentDate, 'dd/MM/yyyy')}`, 60, currentY + 60);
|
||||
{ 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'
|
||||
}
|
||||
};
|
||||
|
||||
// Add footer
|
||||
currentY += 100;
|
||||
doc.fontSize(12).font('Helvetica-Oblique').text('Thank you for your business!', 50, currentY, { align: 'center' });
|
||||
doc.fontSize(10).font('Helvetica').text('This is a computer-generated receipt and does not require a signature.', 50, currentY + 20, { align: 'center' });
|
||||
const pdfDoc = pdfMake.createPdf(docDefinition);
|
||||
|
||||
// Finalize the PDF
|
||||
doc.end();
|
||||
|
||||
// Wait for the file to be written
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
writeStream.on('finish', () => resolve());
|
||||
writeStream.on('error', reject);
|
||||
pdfDoc.getBuffer((buffer) => {
|
||||
fs.writeFile(tempFilePath, buffer, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Upload to Firebase Storage using admin SDK
|
||||
const invoicePath = `invoices/${data.invoiceNumber}.pdf`;
|
||||
const bucket = admin.storage().bucket();
|
||||
await bucket.upload(tempFilePath, {
|
||||
@ -145,10 +272,8 @@ export class InvoiceService {
|
||||
},
|
||||
});
|
||||
|
||||
// Clean up the temporary file
|
||||
fs.unlinkSync(tempFilePath);
|
||||
|
||||
// Return the storage path
|
||||
return invoicePath;
|
||||
} catch (error: any) {
|
||||
logger.error('Error generating invoice:', error);
|
||||
@ -158,11 +283,10 @@ export class InvoiceService {
|
||||
|
||||
async getInvoiceDownloadUrl(invoicePath: string): Promise<string> {
|
||||
try {
|
||||
// Using admin SDK to generate a signed URL
|
||||
const bucket = admin.storage().bucket();
|
||||
const file = bucket.file(invoicePath);
|
||||
|
||||
const expirationMs = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||
const expirationMs = 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const [signedUrl] = await file.getSignedUrl({
|
||||
action: 'read',
|
||||
@ -193,7 +317,6 @@ export class InvoiceService {
|
||||
const data = docSnapshot.data();
|
||||
const paymentsData = data?.payments || [];
|
||||
|
||||
// Find the payment by referenceNumber or transactionId
|
||||
let found = false;
|
||||
for (let i = 0; i < paymentsData.length; i++) {
|
||||
if (paymentsData[i].referenceNumber === paymentId ||
|
||||
@ -224,15 +347,12 @@ export class InvoiceService {
|
||||
|
||||
async sendInvoiceEmail(invoicePath: string, emailOptions: EmailOptions): Promise<boolean> {
|
||||
try {
|
||||
// Get the download URL for the invoice
|
||||
const downloadUrl = await this.getInvoiceDownloadUrl(invoicePath);
|
||||
|
||||
// Format the date
|
||||
const formattedDate = emailOptions.additionalData?.paymentDate
|
||||
? new Date(emailOptions.additionalData.paymentDate).toLocaleDateString('en-GB')
|
||||
: new Date().toLocaleDateString('en-GB');
|
||||
|
||||
// Create email HTML content if not provided
|
||||
const emailHtml = emailOptions.customHtml || `
|
||||
<html>
|
||||
<body>
|
||||
@ -255,7 +375,6 @@ export class InvoiceService {
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Send the email with attachment
|
||||
await sendEmailWithAttachmentUtil(
|
||||
emailOptions.recipientEmail,
|
||||
emailOptions.subject || 'Your Fitlien Membership Invoice',
|
||||
@ -285,10 +404,8 @@ export class InvoiceService {
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
// Generate the invoice
|
||||
const invoicePath = await this.generateInvoice(invoiceData);
|
||||
|
||||
// Update the payment record with the invoice path
|
||||
const updateSuccess = await this.updateInvoicePath(membershipId, paymentId, invoicePath);
|
||||
|
||||
if (!updateSuccess) {
|
||||
@ -300,10 +417,8 @@ export class InvoiceService {
|
||||
};
|
||||
}
|
||||
|
||||
// Get a download URL for the invoice
|
||||
const downloadUrl = await this.getInvoiceDownloadUrl(invoicePath);
|
||||
|
||||
// Send email if email options are provided
|
||||
let emailSent = false;
|
||||
if (emailOptions && emailOptions.recipientEmail) {
|
||||
emailSent = await this.sendInvoiceEmail(invoicePath, emailOptions);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user