@medicus.ai/medicus-report-pdf-generator 1.3.13 → 1.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/.vscode/settings.json +3 -3
  2. package/HANDOVER.md +146 -0
  3. package/README.md +26 -26
  4. package/app/i18n.config.js +20 -20
  5. package/app/i18n_wellbeing.config.js +20 -20
  6. package/app/services/localeService.js +28 -28
  7. package/assets/Mediclinic/css/nasco_report.css +6297 -6297
  8. package/assets/Mediclinic/css/nasco_report_rtl.css +851 -851
  9. package/assets/Mediclinic/css/style.css +33 -33
  10. package/assets/Mediclinic/js/js.js +112 -112
  11. package/assets/Mediclinic/js/raphael.js +8437 -8437
  12. package/assets/arabic.css +275 -275
  13. package/assets/charts.min.js +7 -7
  14. package/assets/corporate_report/css/report.css +582 -582
  15. package/assets/corporate_report/css/report_rtl.css +144 -144
  16. package/assets/corporate_report/js/js.js +14 -14
  17. package/assets/data/data.json +124 -124
  18. package/assets/data/data2.json +675 -675
  19. package/assets/data/pdf_data_with_history.json +1255 -1255
  20. package/assets/doctor-note-insight-icon.svg +11 -11
  21. package/assets/imc/css/style.css +61 -61
  22. package/assets/jquery-1.4.min.js +151 -151
  23. package/assets/jquery-2.1.0.min.js +3 -3
  24. package/assets/js.js +201 -201
  25. package/assets/medicus_pdf/arabic.css +444 -444
  26. package/assets/medicus_pdf/styles.css +2427 -2427
  27. package/assets/print.css +4 -4
  28. package/assets/qr-code-style.css +68 -68
  29. package/assets/qrcode.min.js +3 -3
  30. package/assets/raphael-min.js +10 -10
  31. package/assets/sanusx/css/sanusx_report.css +707 -707
  32. package/assets/sizing.js +2 -2
  33. package/assets/styles.css +1545 -1545
  34. package/assets/styles.min.css +1358 -1358
  35. package/assets/translation.js +30 -30
  36. package/assets/wellbeing/css/nasco_report.css +3472 -3472
  37. package/assets/wellbeing/css/nasco_report_rtl.css +679 -679
  38. package/assets/wellbeing/js/js.js +111 -111
  39. package/assets/wellbeing/js/raphael.js +8437 -8437
  40. package/base64/cairo-font.js +2 -2
  41. package/config/Mediclinic.json +37 -37
  42. package/config/Najeeb.ai.json +35 -35
  43. package/config/Pha.json +64 -64
  44. package/config/bionext.json +37 -37
  45. package/config/default.json +35 -35
  46. package/config/diagnostikare.json +34 -34
  47. package/config/maisonsante.json +39 -39
  48. package/config/nasco.json +35 -35
  49. package/config/sanitas.json +35 -35
  50. package/config/sanusx.json +34 -34
  51. package/config/test.txt +4 -4
  52. package/data converter.js +53 -53
  53. package/docs/01-architecture-overview.md +149 -0
  54. package/docs/02-configuration-and-whitelabelling.md +111 -0
  55. package/docs/03-templating-and-rendering.md +71 -0
  56. package/docs/04-report-pipelines.md +128 -0
  57. package/docs/05-questions-and-data-model.md +67 -0
  58. package/docs/06-internationalization.md +59 -0
  59. package/docs/07-email-notifications.md +59 -0
  60. package/docs/08-known-issues-and-technical-debt.md +41 -0
  61. package/docs/README.md +22 -0
  62. package/downloadfile.js +6 -6
  63. package/example.txt +1188 -1188
  64. package/index.js +481 -480
  65. package/lib/big_integral_questionnaire.js +370 -298
  66. package/lib/corporate_report_generator.js +399 -399
  67. package/lib/pdf_generator.min.js +525 -525
  68. package/lib/sanusx_report_generator.js +533 -533
  69. package/lib/sendEmail.js +343 -343
  70. package/lib/template.js +2227 -2227
  71. package/lib/wellbeing_report_generator.js +2164 -2134
  72. package/locales/ar-AE.json +169 -169
  73. package/locales/ar-SA.json +169 -169
  74. package/locales/ar.json +397 -397
  75. package/locales/de.json +169 -169
  76. package/locales/en.json +229 -229
  77. package/locales/fr.json +168 -168
  78. package/locales/pt.json +165 -165
  79. package/locales/wellbeing/ar-AE.json +149 -149
  80. package/locales/wellbeing/ar-SA.json +257 -257
  81. package/locales/wellbeing/de.json +301 -301
  82. package/locales/wellbeing/en.json +423 -423
  83. package/locales/wellbeing/es.json +133 -133
  84. package/locales/wellbeing/fr.json +121 -121
  85. package/locales/wellbeing/it-IT.json +121 -121
  86. package/locales/wellbeing/pt.json +121 -121
  87. package/locales/wellbeing/tr.json +121 -121
  88. package/locales/wellbeing/zh-CN.json +121 -121
  89. package/locales/zh-CN.json +165 -165
  90. package/package.json +47 -47
  91. package/preview-big-integral.js +75 -75
  92. package/run.js +15 -15
  93. package/templates/Mediclinic/blocks/first-section.html +205 -205
  94. package/templates/Mediclinic/blocks/footer.html +7 -7
  95. package/templates/Mediclinic/blocks/header-template.html +5 -5
  96. package/templates/Mediclinic/blocks/header.html +20 -20
  97. package/templates/Mediclinic/blocks/patient-table.html +38 -38
  98. package/templates/Mediclinic/blocks/pdf-header.html +9 -9
  99. package/templates/Mediclinic/blocks/tips.html +8 -8
  100. package/templates/Mediclinic/ltr_no_pages.html +37 -37
  101. package/templates/Mediclinic/rtl_no_pages.html +42 -42
  102. package/templates/Mediclinic/wellbeing_template.html +41 -41
  103. package/templates/Pha/blocks/first-section.html +207 -207
  104. package/templates/Pha/blocks/footer.html +7 -7
  105. package/templates/Pha/blocks/header-template.html +5 -5
  106. package/templates/Pha/blocks/header.html +20 -20
  107. package/templates/Pha/blocks/patient-table.html +38 -38
  108. package/templates/Pha/blocks/pdf-header.html +8 -8
  109. package/templates/Pha/blocks/tips.html +8 -8
  110. package/templates/Pha/ltr_no_pages.html +37 -37
  111. package/templates/Pha/rtl_no_pages.html +42 -42
  112. package/templates/Pha/wellbeing_template.html +41 -41
  113. package/templates/base.html +23 -23
  114. package/templates/blocks/ar-first-page-header.html +68 -68
  115. package/templates/blocks/ar-footer.html +54 -54
  116. package/templates/blocks/ar-header.html +67 -67
  117. package/templates/blocks/biomarker-compact-ar.html +27 -27
  118. package/templates/blocks/biomarker-compact.html +27 -27
  119. package/templates/blocks/biomarker-details.html +41 -41
  120. package/templates/blocks/biomarker-insight.html +22 -22
  121. package/templates/blocks/biomarker-min.html +9 -9
  122. package/templates/blocks/doctor-note.html +11 -11
  123. package/templates/blocks/footer.html +35 -35
  124. package/templates/blocks/header-first-page.html +46 -46
  125. package/templates/blocks/header.html +49 -49
  126. package/templates/blocks/panel-compact.html +38 -38
  127. package/templates/blocks/panel-details.html +16 -16
  128. package/templates/blocks/report-summary.html +16 -16
  129. package/templates/blocks/section-title.html +4 -4
  130. package/templates/blocks/signature.html +16 -16
  131. package/templates/blocks/summary-insight.html +15 -15
  132. package/templates/blocks/summary.html +9 -9
  133. package/templates/corporate_report/cover_page.html +23 -23
  134. package/templates/corporate_report/footer.html +9 -9
  135. package/templates/corporate_report/ltr_no_pages.html +20 -20
  136. package/templates/corporate_report/page.html +24 -24
  137. package/templates/corporate_report/participant_analytics.html +5 -5
  138. package/templates/corporate_report/rtl_no_pages.html +20 -20
  139. package/templates/empty.html +10 -10
  140. package/templates/first_page_head.html +157 -157
  141. package/templates/imc/first-header-template.html +53 -53
  142. package/templates/ltr.html +1368 -1368
  143. package/templates/ltr_no_pages.html +89 -89
  144. package/templates/maisonsante/blocks/first-section.html +151 -207
  145. package/templates/maisonsante/blocks/footer.html +7 -7
  146. package/templates/maisonsante/blocks/header-template.html +5 -5
  147. package/templates/maisonsante/blocks/header.html +20 -20
  148. package/templates/maisonsante/blocks/patient-table.html +38 -38
  149. package/templates/maisonsante/blocks/pdf-header.html +8 -8
  150. package/templates/maisonsante/blocks/tips.html +8 -8
  151. package/templates/maisonsante/ltr_no_pages.html +38 -38
  152. package/templates/maisonsante/rtl_no_pages.html +43 -43
  153. package/templates/maisonsante/wellbeing_template.html +41 -41
  154. package/templates/no_pages.html +1224 -1224
  155. package/templates/popup/popup-template.html +129 -129
  156. package/templates/rtl_no_pages.html +92 -92
  157. package/templates/sanusx/blocks/footer.html +6 -6
  158. package/templates/sanusx/blocks/header.html +20 -20
  159. package/templates/sanusx/blocks/personal-details.html +123 -123
  160. package/templates/sanusx/blocks/predictions-section.html +57 -57
  161. package/templates/sanusx/blocks/recommendations-section.html +6 -6
  162. package/templates/sanusx/blocks/super-power-section.html +29 -29
  163. package/templates/sanusx/blocks/tips.html +8 -8
  164. package/templates/sanusx/ltr_no_pages.html +26 -26
  165. package/templates/sanusx/rtl_no_pages.html +36 -36
  166. package/templates/template.html +1377 -1377
  167. package/templates/wellbeing/blocks/first-section.html +106 -106
  168. package/templates/wellbeing/blocks/footer.html +7 -7
  169. package/templates/wellbeing/blocks/header.html +37 -37
  170. package/templates/wellbeing/blocks/tips.html +8 -8
  171. package/templates/wellbeing/ltr_no_pages.html +35 -35
  172. package/templates/wellbeing/rtl_no_pages.html +36 -36
  173. package/templates/wellbeing/wellbeing_template.html +43 -43
  174. package/test.js +74 -74
  175. package/testing-reports/mediclinic/arabic-data.js +0 -439
  176. package/testing-reports/mediclinic/doctor-data.js +0 -523
  177. package/testing-reports/mediclinic/with-wellbeing.js +0 -415
  178. package/testing-reports/pha/notes-example.js +0 -397
package/index.js CHANGED
@@ -1,480 +1,481 @@
1
- const { generateHTMLStaging, generatePDF, generatePatientQR } = require("./lib/pdf_generator.min");
2
- const {
3
- generateHTMLWellbeingReport,
4
- generatePDFWellbeingReport,
5
- generateHTMLWellbeingReportWithSmartReport,
6
- generatePDFReport
7
- } = require("./lib/wellbeing_report_generator");
8
- const { generateSanusXReport, generateHTMLSanusXReport } = require("./lib/sanusx_report_generator");
9
- const fs = require('fs');
10
- const os = require('os');
11
- const crypto = require('crypto');
12
- const { sendNascoEmail, sendEmailNotification } = require('./lib/sendEmail')
13
- const path = require('path');
14
- const { generatePDFCorporateReport, generateHTMLCorporateReport } = require('./lib/corporate_report_generator')
15
-
16
- // Best-effort fire-and-forget cleanup for per-call temp files. Never throws.
17
- const safeUnlink = (filePath) => {
18
- if (!filePath) return Promise.resolve();
19
- return fs.promises.unlink(filePath).catch(() => { });
20
- };
21
-
22
- module.exports = {
23
-
24
- generateHTMLStaging,
25
-
26
- generateMedicusPDF: async (base64Object, isDebugging, isDownloadable, onlyHTML) => {
27
- let LOGS = '';
28
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
29
- let PDF_FILE_PATH = __dirname + '/output/sample.pdf';
30
- if (isDebugging) {
31
- if (fs.existsSync(LOGS_FILE_PATH)) {
32
- fs.unlinkSync(LOGS_FILE_PATH);
33
- }
34
- if (fs.existsSync(PDF_FILE_PATH)) {
35
- fs.unlinkSync(PDF_FILE_PATH);
36
- }
37
- }
38
- // 1: save incoming base64
39
- if (isDebugging) {
40
- console.log('1: save incoming base64');
41
- LOGS += '1: save incoming base64' + '\n' + '=============' + '\n';
42
- // LOGS += base64Object + '\n\n\n';
43
- }
44
-
45
-
46
- // 2: save decoded json string
47
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
48
- if (isDebugging) {
49
- console.log('2: save decoded json string');
50
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
51
- LOGS += json + '\n\n\n';
52
- }
53
-
54
-
55
- // 3: save decoded json
56
- const decodedJSON = JSON.parse(json);
57
- if (isDebugging) {
58
- console.log('3: save decoded json string')
59
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
60
- LOGS += decodedJSON + '\n\n\n';
61
- }
62
-
63
-
64
- let html = await generateHTMLStaging(decodedJSON, isDebugging);
65
- let fileBuffer, base64data = ''
66
- if (!onlyHTML) {
67
- // 4: save PDF buffer
68
- const startDate = Date.now();
69
- fileBuffer = await generatePDF(html);
70
- console.log(`Took ${Date.now() - startDate} ms.`);
71
- if (isDebugging) {
72
- console.log('4: save PDF buffer')
73
- LOGS += '4: save PDF buffer' + '\n' + '=============' + '\n';
74
- LOGS += fileBuffer + '\n\n\n';
75
- }
76
-
77
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
78
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
79
-
80
- // 5: save encoded base64
81
- base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
82
- if (isDebugging) {
83
- console.log('5: save encoded base64');
84
- LOGS += '5: save encoded base64' + '\n' + '=============' + '\n';
85
- LOGS += base64data + '\n\n\n';
86
- }
87
- }
88
- if (onlyHTML) {
89
- return html;
90
- } else {
91
- if (isDownloadable) {
92
- return fileBuffer;
93
- } else {
94
- return base64data;
95
- }
96
- }
97
-
98
- },
99
-
100
- generateNascoPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
101
- let reportData = JSON.parse(data)
102
- let base64Object = reportData.data
103
- let LOGS = '';
104
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
105
- let PDF_FILE_PATH = __dirname + '/output/nasco-sample.pdf';
106
-
107
- let mailConfig = {
108
- host: reportData.host,
109
- port: reportData.port,
110
- authUser: reportData.authUser,
111
- authPass: reportData.authPass,
112
- sendFromEmail: reportData.sendFromEmail,
113
- secure: reportData.secure
114
- }
115
- if (isDebugging) {
116
- if (fs.existsSync(LOGS_FILE_PATH)) {
117
- fs.unlinkSync(LOGS_FILE_PATH);
118
- }
119
-
120
- if (fs.existsSync(PDF_FILE_PATH)) {
121
- fs.unlinkSync(PDF_FILE_PATH);
122
- }
123
- }
124
-
125
- // 1: save decoded json string
126
- if (isDebugging) {
127
- console.log('2: save json string');
128
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
129
- LOGS += base64Object + '\n\n\n';
130
- }
131
- // 2: save decoded json string
132
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
133
- if (isDebugging) {
134
- console.log('2: save decoded json string');
135
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
136
- LOGS += json + '\n\n\n';
137
- }
138
-
139
- // 3: save decoded json
140
- const decodedJSON = JSON.parse(json);
141
- if (isDebugging) {
142
- console.log('3: save decoded json string')
143
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
144
- LOGS += decodedJSON + '\n\n\n';
145
- }
146
- let html = await generateHTMLWellbeingReport(decodedJSON, isDebugging, reportData.client, reportData.language);
147
-
148
- // 3: save PDF buffer
149
- let fileBuffer = await generatePDFWellbeingReport(html);
150
- if (isDebugging) {
151
- console.log('3: save PDF buffer')
152
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
153
- LOGS += fileBuffer + '\n\n\n';
154
- }
155
-
156
- console.log("PDF_FILE_PATH", PDF_FILE_PATH)
157
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
158
-
159
- // 4: save encoded base64
160
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
161
- if (isDebugging) {
162
- console.log('4: save encoded base64');
163
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
164
- LOGS += base64data + '\n\n\n';
165
- }
166
-
167
-
168
- // 5: save logs to file
169
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
170
- if (isDebugging) {
171
- console.log('5: save logs to file');
172
- }
173
-
174
- if (isDownloadable) {
175
- return fileBuffer;
176
- } else {
177
- if (shouldSendEmail)
178
- return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
179
- else
180
- return base64data;
181
- }
182
- },
183
-
184
- /**
185
- * Generate full PDF report with encryption
186
- * @param {string} data - JSON string containing report data with base64 encoded content
187
- * @param {boolean} isDebugging - Enable debug mode (saves logs and keeps output files)
188
- * @param {boolean} isDownloadable - If true, returns PDF buffer; otherwise returns base64 string
189
- * @param {boolean} shouldSendEmail - If true, sends email with PDF attachment and returns email result
190
- * @param {Array<string>} [selectedLabs=[]] - Array of selected lab names for header logos
191
- * @param {boolean} [showHeaderLogo=true] - Whether to display logo in PDF header
192
- * @returns {Promise<Buffer|string|object>} Returns encrypted PDF buffer if isDownloadable, base64 string if not sending email, or email result if shouldSendEmail
193
- */
194
- generateFullPdf: async (data, isDebugging, isDownloadable, shouldSendEmail, selectedLabs = [], showHeaderLogo = true) => {
195
- let reportData = JSON.parse(data);
196
- let base64Object = reportData.data;
197
-
198
- // Per-call unique identifiers so concurrent callers never share a path.
199
- // Even when two requests overlap, each one owns its own input/output
200
- // files and email attachment, eliminating cross-user PDF swapping.
201
- const callId = crypto.randomUUID();
202
- const tmpDir = os.tmpdir();
203
- const tmpInputPath = path.join(tmpDir, `wb-${callId}-in.pdf`);
204
- const tmpEncryptedPath = path.join(tmpDir, `wb-${callId}-enc.pdf`);
205
- let tmpEmailAttachmentPath = null;
206
-
207
- let LOGS = '';
208
- const LOGS_FILE_PATH = isDebugging
209
- ? path.join(__dirname, 'output', `LOGS-${callId}.txt`)
210
- : null;
211
-
212
- const mailConfig = {
213
- host: reportData.host,
214
- port: reportData.port,
215
- authUser: reportData.authUser,
216
- authPass: reportData.authPass,
217
- sendFromEmail: reportData.sendFromEmail,
218
- secure: reportData.secure,
219
- };
220
-
221
- if (isDebugging) {
222
- console.log('2: save json string');
223
- LOGS += '2: save json string\n===============\n' + base64Object + '\n\n\n';
224
- }
225
-
226
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
227
-
228
- if (isDebugging) {
229
- console.log('2: save decoded json string');
230
- LOGS += '2: save decoded json string\n===============\n' + json + '\n\n\n';
231
- }
232
-
233
- const decodedJSON = JSON.parse(json);
234
-
235
- if (isDebugging) {
236
- console.log('3: save decoded json string');
237
- LOGS += '3: save decoded json\n===============\n' + JSON.stringify(decodedJSON, null, 2) + '\n\n\n';
238
- }
239
-
240
- const html = await generateHTMLWellbeingReportWithSmartReport(
241
- decodedJSON,
242
- isDebugging,
243
- reportData.client,
244
- reportData.language,
245
- selectedLabs || [],
246
- showHeaderLogo || true
247
- );
248
-
249
- const fileBuffer = await generatePDFReport({ ...html, client: reportData.client, footer: decodedJSON?.footer });
250
-
251
- if (isDebugging) {
252
- console.log('3: save PDF buffer');
253
- LOGS += '3: save PDF buffer\n===============\n' + '[binary content omitted]' + '\n\n\n';
254
- }
255
-
256
- try {
257
- // Write the unencrypted PDF to a per-call temp file.
258
- // qpdf needs a real input path; using a uuid-suffixed file in
259
- // os.tmpdir() guarantees no concurrent caller can overwrite it.
260
- await fs.promises.writeFile(tmpInputPath, fileBuffer);
261
-
262
- const qpdf = await import('node-qpdf2');
263
-
264
- // Encrypt to a per-call output file. We can't use qpdf's stdout
265
- // mode (output omitted) because node-qpdf2's spawn helper joins
266
- // stdout chunks as strings, which corrupts binary PDF bytes.
267
- await qpdf.encrypt({
268
- input: tmpInputPath,
269
- output: tmpEncryptedPath,
270
- keyLength: 256,
271
- password: reportData.pdfPassword,
272
- });
273
-
274
- const encryptedBuffer = await fs.promises.readFile(tmpEncryptedPath);
275
-
276
- const base64data = encryptedBuffer.toString('base64');
277
- if (isDebugging) {
278
- console.log('4: save encoded base64');
279
- LOGS += '4: save encoded base64\n===============\n' + base64data + '\n\n\n';
280
- }
281
-
282
- if (isDebugging && LOGS_FILE_PATH) {
283
- await fs.promises.writeFile(LOGS_FILE_PATH, LOGS, 'utf8');
284
- console.log('5: save logs to file');
285
- }
286
-
287
- if (isDownloadable) {
288
- return encryptedBuffer;
289
- }
290
-
291
- if (shouldSendEmail) {
292
- // Write the encrypted buffer to a dedicated per-call file just
293
- // for the email attachment. sendNascoEmail expects a path
294
- // (nodemailer reads it from disk), so we materialize it once,
295
- // pass it in, then unlink in the finally block.
296
- tmpEmailAttachmentPath = path.join(tmpDir, `wb-${callId}-mail.pdf`);
297
- await fs.promises.writeFile(tmpEmailAttachmentPath, encryptedBuffer);
298
- return await sendNascoEmail(
299
- decodedJSON.wellbeing,
300
- tmpEmailAttachmentPath,
301
- mailConfig,
302
- reportData.client
303
- );
304
- }
305
-
306
- return base64data;
307
- } finally {
308
- await Promise.all([
309
- safeUnlink(tmpInputPath),
310
- safeUnlink(tmpEncryptedPath),
311
- safeUnlink(tmpEmailAttachmentPath),
312
- ]);
313
- }
314
- },
315
-
316
- generateSanuxPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
317
- let reportData = JSON.parse(data)
318
- let base64Object = reportData.data
319
- let LOGS = '';
320
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
321
- let PDF_FILE_PATH = __dirname + '/output/sanusx-sample.pdf';
322
-
323
- let mailConfig = {
324
- host: reportData.host,
325
- port: reportData.port,
326
- authUser: reportData.authUser,
327
- authPass: reportData.authPass,
328
- sendFromEmail: reportData.sendFromEmail,
329
- secure: reportData.secure
330
- }
331
- if (isDebugging) {
332
- if (fs.existsSync(LOGS_FILE_PATH)) {
333
- fs.unlinkSync(LOGS_FILE_PATH);
334
- }
335
-
336
- if (fs.existsSync(PDF_FILE_PATH)) {
337
- fs.unlinkSync(PDF_FILE_PATH);
338
- }
339
- }
340
-
341
- // 1: save decoded json string
342
- if (isDebugging) {
343
- console.log('2: save json string');
344
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
345
- LOGS += base64Object + '\n\n\n';
346
- }
347
- // 2: save decoded json string
348
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
349
- if (isDebugging) {
350
- console.log('2: save decoded json string');
351
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
352
- LOGS += json + '\n\n\n';
353
- }
354
-
355
- // 3: save decoded json
356
- const decodedJSON = JSON.parse(json);
357
- if (isDebugging) {
358
- console.log('3: save decoded json string')
359
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
360
- LOGS += decodedJSON + '\n\n\n';
361
- }
362
- let html = await generateHTMLSanusXReport(decodedJSON, isDebugging, reportData.client, reportData.language);
363
-
364
- // 3: save PDF buffer
365
- let fileBuffer = await generateSanusXReport(html);
366
- if (isDebugging) {
367
- console.log('3: save PDF buffer')
368
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
369
- LOGS += fileBuffer + '\n\n\n';
370
- }
371
-
372
- console.log("PDF_FILE_PATH", PDF_FILE_PATH)
373
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
374
-
375
- // 4: save encoded base64
376
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
377
- if (isDebugging) {
378
- console.log('4: save encoded base64');
379
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
380
- LOGS += base64data + '\n\n\n';
381
- }
382
-
383
-
384
- // 5: save logs to file
385
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
386
- if (isDebugging) {
387
- console.log('5: save logs to file');
388
- }
389
-
390
- if (isDownloadable) {
391
- return fileBuffer;
392
- } else {
393
- if (shouldSendEmail)
394
- return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
395
- else
396
- return base64data;
397
- }
398
- },
399
-
400
- sendEmail: async (json) => {
401
- const decodedJSON = JSON.parse(json);
402
- const email = await sendEmailNotification(decodedJSON)
403
- return email
404
- },
405
-
406
- generateQrCode: async (json) => {
407
- let fileBuffer = await generatePatientQR(json)
408
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
409
- return base64data
410
- },
411
-
412
- generateCorporateReportPDF: async (json, isDebugging, isDownloadable) => {
413
-
414
- let LOGS = '';
415
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
416
- let PDF_FILE_PATH = __dirname + '/output/corporate-report-sample.pdf';
417
-
418
- if (isDebugging) {
419
- if (fs.existsSync(LOGS_FILE_PATH)) {
420
- fs.unlinkSync(LOGS_FILE_PATH);
421
- }
422
-
423
- if (fs.existsSync(PDF_FILE_PATH)) {
424
- fs.unlinkSync(PDF_FILE_PATH);
425
- }
426
- }
427
-
428
- // 1: save decoded json string
429
- if (isDebugging) {
430
- console.log('2: save json string');
431
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
432
- LOGS += json + '\n\n\n';
433
- }
434
-
435
-
436
- // 2: save decoded json
437
- const decodedJSON = JSON.parse(json);
438
- if (isDebugging) {
439
- console.log('2: save decoded json string')
440
- LOGS += '2: save decoded json' + '\n' + '=============' + '\n';
441
- LOGS += decodedJSON + '\n\n\n';
442
- }
443
-
444
-
445
- let html = await generateHTMLCorporateReport(decodedJSON, isDebugging);
446
-
447
-
448
- // 3: save PDF buffer
449
- let fileBuffer = await generatePDFCorporateReport(html);
450
- if (isDebugging) {
451
- console.log('3: save PDF buffer')
452
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
453
- LOGS += fileBuffer + '\n\n\n';
454
- }
455
-
456
-
457
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
458
-
459
- // 4: save encoded base64
460
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
461
- if (isDebugging) {
462
- console.log('4: save encoded base64');
463
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
464
- LOGS += base64data + '\n\n\n';
465
- }
466
-
467
-
468
- // 5: save logs to file
469
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
470
- if (isDebugging) {
471
- console.log('5: save logs to file');
472
- }
473
-
474
- if (isDownloadable) {
475
- return fileBuffer;
476
- } else {
477
- return base64data;
478
- }
479
- },
480
- }
1
+ const { generateHTMLStaging, generatePDF, generatePatientQR } = require("./lib/pdf_generator.min");
2
+ const {
3
+ generateHTMLWellbeingReport,
4
+ generatePDFWellbeingReport,
5
+ generateHTMLWellbeingReportWithSmartReport,
6
+ generatePDFReport
7
+ } = require("./lib/wellbeing_report_generator");
8
+ const { generateSanusXReport, generateHTMLSanusXReport } = require("./lib/sanusx_report_generator");
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+ const crypto = require('crypto');
12
+ const { sendNascoEmail, sendEmailNotification } = require('./lib/sendEmail')
13
+ const path = require('path');
14
+ const { generatePDFCorporateReport, generateHTMLCorporateReport } = require('./lib/corporate_report_generator')
15
+
16
+ // Best-effort fire-and-forget cleanup for per-call temp files. Never throws.
17
+ const safeUnlink = (filePath) => {
18
+ if (!filePath) return Promise.resolve();
19
+ return fs.promises.unlink(filePath).catch(() => { });
20
+ };
21
+
22
+ module.exports = {
23
+
24
+ generateHTMLStaging,
25
+
26
+ generateMedicusPDF: async (base64Object, isDebugging, isDownloadable, onlyHTML) => {
27
+ let LOGS = '';
28
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
29
+ let PDF_FILE_PATH = __dirname + '/output/sample.pdf';
30
+ if (isDebugging) {
31
+ if (fs.existsSync(LOGS_FILE_PATH)) {
32
+ fs.unlinkSync(LOGS_FILE_PATH);
33
+ }
34
+ if (fs.existsSync(PDF_FILE_PATH)) {
35
+ fs.unlinkSync(PDF_FILE_PATH);
36
+ }
37
+ }
38
+ // 1: save incoming base64
39
+ if (isDebugging) {
40
+ console.log('1: save incoming base64');
41
+ LOGS += '1: save incoming base64' + '\n' + '=============' + '\n';
42
+ // LOGS += base64Object + '\n\n\n';
43
+ }
44
+
45
+
46
+ // 2: save decoded json string
47
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
48
+ if (isDebugging) {
49
+ console.log('2: save decoded json string');
50
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
51
+ LOGS += json + '\n\n\n';
52
+ }
53
+
54
+
55
+ // 3: save decoded json
56
+ const decodedJSON = JSON.parse(json);
57
+ if (isDebugging) {
58
+ console.log('3: save decoded json string')
59
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
60
+ LOGS += decodedJSON + '\n\n\n';
61
+ }
62
+
63
+
64
+ let html = await generateHTMLStaging(decodedJSON, isDebugging);
65
+ let fileBuffer, base64data = ''
66
+ if (!onlyHTML) {
67
+ // 4: save PDF buffer
68
+ const startDate = Date.now();
69
+ fileBuffer = await generatePDF(html);
70
+ console.log(`Took ${Date.now() - startDate} ms.`);
71
+ if (isDebugging) {
72
+ console.log('4: save PDF buffer')
73
+ LOGS += '4: save PDF buffer' + '\n' + '=============' + '\n';
74
+ LOGS += fileBuffer + '\n\n\n';
75
+ }
76
+
77
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
78
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
79
+
80
+ // 5: save encoded base64
81
+ base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
82
+ if (isDebugging) {
83
+ console.log('5: save encoded base64');
84
+ LOGS += '5: save encoded base64' + '\n' + '=============' + '\n';
85
+ LOGS += base64data + '\n\n\n';
86
+ }
87
+ }
88
+ if (onlyHTML) {
89
+ return html;
90
+ } else {
91
+ if (isDownloadable) {
92
+ return fileBuffer;
93
+ } else {
94
+ return base64data;
95
+ }
96
+ }
97
+
98
+ },
99
+
100
+ generateNascoPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
101
+ let reportData = JSON.parse(data)
102
+ let base64Object = reportData.data
103
+ let LOGS = '';
104
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
105
+ let PDF_FILE_PATH = __dirname + '/output/nasco-sample.pdf';
106
+
107
+ let mailConfig = {
108
+ host: reportData.host,
109
+ port: reportData.port,
110
+ authUser: reportData.authUser,
111
+ authPass: reportData.authPass,
112
+ sendFromEmail: reportData.sendFromEmail,
113
+ secure: reportData.secure
114
+ }
115
+ if (isDebugging) {
116
+ if (fs.existsSync(LOGS_FILE_PATH)) {
117
+ fs.unlinkSync(LOGS_FILE_PATH);
118
+ }
119
+
120
+ if (fs.existsSync(PDF_FILE_PATH)) {
121
+ fs.unlinkSync(PDF_FILE_PATH);
122
+ }
123
+ }
124
+
125
+ // 1: save decoded json string
126
+ if (isDebugging) {
127
+ console.log('2: save json string');
128
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
129
+ LOGS += base64Object + '\n\n\n';
130
+ }
131
+ // 2: save decoded json string
132
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
133
+ if (isDebugging) {
134
+ console.log('2: save decoded json string');
135
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
136
+ LOGS += json + '\n\n\n';
137
+ }
138
+
139
+ // 3: save decoded json
140
+ const decodedJSON = JSON.parse(json);
141
+ if (isDebugging) {
142
+ console.log('3: save decoded json string')
143
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
144
+ LOGS += decodedJSON + '\n\n\n';
145
+ }
146
+ let html = await generateHTMLWellbeingReport(decodedJSON, isDebugging, reportData.client, reportData.language);
147
+
148
+ // 3: save PDF buffer
149
+ let fileBuffer = await generatePDFWellbeingReport(html);
150
+ if (isDebugging) {
151
+ console.log('3: save PDF buffer')
152
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
153
+ LOGS += fileBuffer + '\n\n\n';
154
+ }
155
+
156
+ console.log("PDF_FILE_PATH", PDF_FILE_PATH)
157
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
158
+
159
+ // 4: save encoded base64
160
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
161
+ if (isDebugging) {
162
+ console.log('4: save encoded base64');
163
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
164
+ LOGS += base64data + '\n\n\n';
165
+ }
166
+
167
+
168
+ // 5: save logs to file
169
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
170
+ if (isDebugging) {
171
+ console.log('5: save logs to file');
172
+ }
173
+
174
+ if (isDownloadable) {
175
+ return fileBuffer;
176
+ } else {
177
+ if (shouldSendEmail)
178
+ return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
179
+ else
180
+ return base64data;
181
+ }
182
+ },
183
+
184
+ /**
185
+ * Generate full PDF report with encryption
186
+ * @param {string} data - JSON string containing report data with base64 encoded content
187
+ * @param {boolean} isDebugging - Enable debug mode (saves logs and keeps output files)
188
+ * @param {boolean} isDownloadable - If true, returns PDF buffer; otherwise returns base64 string
189
+ * @param {boolean} shouldSendEmail - If true, sends email with PDF attachment and returns email result
190
+ * @param {Array<string>} [selectedLabs=[]] - Array of selected lab names for header logos
191
+ * @param {boolean} [showHeaderLogo=true] - Whether to display logo in PDF header
192
+ * @returns {Promise<Buffer|string|object>} Returns encrypted PDF buffer if isDownloadable, base64 string if not sending email, or email result if shouldSendEmail
193
+ */
194
+ generateFullPdf: async (data, isDebugging, isDownloadable, shouldSendEmail, selectedLabs = [], showHeaderLogo = true) => {
195
+ let reportData = JSON.parse(data);
196
+ let base64Object = reportData.data;
197
+
198
+ // Per-call unique identifiers so concurrent callers never share a path.
199
+ // Even when two requests overlap, each one owns its own input/output
200
+ // files and email attachment, eliminating cross-user PDF swapping.
201
+ const callId = crypto.randomUUID();
202
+ const tmpDir = os.tmpdir();
203
+ const tmpInputPath = path.join(tmpDir, `wb-${callId}-in.pdf`);
204
+ const tmpEncryptedPath = path.join(tmpDir, `wb-${callId}-enc.pdf`);
205
+ let tmpEmailAttachmentPath = null;
206
+
207
+ let LOGS = '';
208
+ const LOGS_FILE_PATH = isDebugging
209
+ ? path.join(__dirname, 'output', `LOGS-${callId}.txt`)
210
+ : null;
211
+
212
+ const mailConfig = {
213
+ host: reportData.host,
214
+ port: reportData.port,
215
+ authUser: reportData.authUser,
216
+ authPass: reportData.authPass,
217
+ sendFromEmail: reportData.sendFromEmail,
218
+ secure: reportData.secure,
219
+ };
220
+
221
+ if (isDebugging) {
222
+ console.log('2: save json string');
223
+ LOGS += '2: save json string\n===============\n' + base64Object + '\n\n\n';
224
+ }
225
+
226
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
227
+
228
+ if (isDebugging) {
229
+ console.log('2: save decoded json string');
230
+ LOGS += '2: save decoded json string\n===============\n' + json + '\n\n\n';
231
+ }
232
+
233
+ const decodedJSON = JSON.parse(json);
234
+
235
+ if (isDebugging) {
236
+ console.log('3: save decoded json string');
237
+ LOGS += '3: save decoded json\n===============\n' + JSON.stringify(decodedJSON, null, 2) + '\n\n\n';
238
+ }
239
+
240
+ const html = await generateHTMLWellbeingReportWithSmartReport(
241
+ decodedJSON,
242
+ isDebugging,
243
+ reportData.client,
244
+ reportData.language,
245
+ selectedLabs || [],
246
+ showHeaderLogo || true
247
+ );
248
+
249
+ const fileBuffer = await generatePDFReport({ ...html, client: reportData.client, footer: decodedJSON?.footer });
250
+
251
+ if (isDebugging) {
252
+ console.log('3: save PDF buffer');
253
+ LOGS += '3: save PDF buffer\n===============\n' + '[binary content omitted]' + '\n\n\n';
254
+ }
255
+
256
+ try {
257
+ // Write the unencrypted PDF to a per-call temp file.
258
+ // qpdf needs a real input path; using a uuid-suffixed file in
259
+ // os.tmpdir() guarantees no concurrent caller can overwrite it.
260
+ await fs.promises.writeFile(tmpInputPath, fileBuffer);
261
+
262
+ const qpdf = await import('node-qpdf2');
263
+
264
+ // Encrypt to a per-call output file. We can't use qpdf's stdout
265
+ // mode (output omitted) because node-qpdf2's spawn helper joins
266
+ // stdout chunks as strings, which corrupts binary PDF bytes.
267
+ await qpdf.encrypt({
268
+ input: tmpInputPath,
269
+ output: tmpEncryptedPath,
270
+ keyLength: 256,
271
+ password: reportData.pdfPassword,
272
+ });
273
+
274
+ const encryptedBuffer = await fs.promises.readFile(tmpEncryptedPath);
275
+
276
+ const base64data = encryptedBuffer.toString('base64');
277
+ if (isDebugging) {
278
+ console.log('4: save encoded base64');
279
+ LOGS += '4: save encoded base64\n===============\n' + base64data + '\n\n\n';
280
+ }
281
+
282
+ if (isDebugging && LOGS_FILE_PATH) {
283
+ await fs.promises.writeFile(LOGS_FILE_PATH, LOGS, 'utf8');
284
+ console.log('5: save logs to file');
285
+ }
286
+
287
+ if (isDownloadable) {
288
+ return encryptedBuffer;
289
+ }
290
+
291
+ if (shouldSendEmail) {
292
+ // Write the encrypted buffer to a dedicated per-call file just
293
+ // for the email attachment. sendNascoEmail expects a path
294
+ // (nodemailer reads it from disk), so we materialize it once,
295
+ // pass it in, then unlink in the finally block.
296
+ tmpEmailAttachmentPath = path.join(tmpDir, `wb-${callId}-mail.pdf`);
297
+ await fs.promises.writeFile(tmpEmailAttachmentPath, encryptedBuffer);
298
+ return await sendNascoEmail(
299
+ decodedJSON.wellbeing,
300
+ tmpEmailAttachmentPath,
301
+ mailConfig,
302
+ reportData.client
303
+ );
304
+ }
305
+
306
+ return base64data;
307
+ } finally {
308
+ await Promise.all([
309
+ safeUnlink(tmpInputPath),
310
+ safeUnlink(tmpEncryptedPath),
311
+ safeUnlink(tmpEmailAttachmentPath),
312
+ ]);
313
+ }
314
+ },
315
+
316
+ //not used
317
+ generateSanuxPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
318
+ let reportData = JSON.parse(data)
319
+ let base64Object = reportData.data
320
+ let LOGS = '';
321
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
322
+ let PDF_FILE_PATH = __dirname + '/output/sanusx-sample.pdf';
323
+
324
+ let mailConfig = {
325
+ host: reportData.host,
326
+ port: reportData.port,
327
+ authUser: reportData.authUser,
328
+ authPass: reportData.authPass,
329
+ sendFromEmail: reportData.sendFromEmail,
330
+ secure: reportData.secure
331
+ }
332
+ if (isDebugging) {
333
+ if (fs.existsSync(LOGS_FILE_PATH)) {
334
+ fs.unlinkSync(LOGS_FILE_PATH);
335
+ }
336
+
337
+ if (fs.existsSync(PDF_FILE_PATH)) {
338
+ fs.unlinkSync(PDF_FILE_PATH);
339
+ }
340
+ }
341
+
342
+ // 1: save decoded json string
343
+ if (isDebugging) {
344
+ console.log('2: save json string');
345
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
346
+ LOGS += base64Object + '\n\n\n';
347
+ }
348
+ // 2: save decoded json string
349
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
350
+ if (isDebugging) {
351
+ console.log('2: save decoded json string');
352
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
353
+ LOGS += json + '\n\n\n';
354
+ }
355
+
356
+ // 3: save decoded json
357
+ const decodedJSON = JSON.parse(json);
358
+ if (isDebugging) {
359
+ console.log('3: save decoded json string')
360
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
361
+ LOGS += decodedJSON + '\n\n\n';
362
+ }
363
+ let html = await generateHTMLSanusXReport(decodedJSON, isDebugging, reportData.client, reportData.language);
364
+
365
+ // 3: save PDF buffer
366
+ let fileBuffer = await generateSanusXReport(html);
367
+ if (isDebugging) {
368
+ console.log('3: save PDF buffer')
369
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
370
+ LOGS += fileBuffer + '\n\n\n';
371
+ }
372
+
373
+ console.log("PDF_FILE_PATH", PDF_FILE_PATH)
374
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
375
+
376
+ // 4: save encoded base64
377
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
378
+ if (isDebugging) {
379
+ console.log('4: save encoded base64');
380
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
381
+ LOGS += base64data + '\n\n\n';
382
+ }
383
+
384
+
385
+ // 5: save logs to file
386
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
387
+ if (isDebugging) {
388
+ console.log('5: save logs to file');
389
+ }
390
+
391
+ if (isDownloadable) {
392
+ return fileBuffer;
393
+ } else {
394
+ if (shouldSendEmail)
395
+ return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
396
+ else
397
+ return base64data;
398
+ }
399
+ },
400
+ //not used
401
+ sendEmail: async (json) => {
402
+ const decodedJSON = JSON.parse(json);
403
+ const email = await sendEmailNotification(decodedJSON)
404
+ return email
405
+ },
406
+ //not used
407
+ generateQrCode: async (json) => {
408
+ let fileBuffer = await generatePatientQR(json)
409
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
410
+ return base64data
411
+ },
412
+ //not used
413
+ generateCorporateReportPDF: async (json, isDebugging, isDownloadable) => {
414
+
415
+ let LOGS = '';
416
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
417
+ let PDF_FILE_PATH = __dirname + '/output/corporate-report-sample.pdf';
418
+
419
+ if (isDebugging) {
420
+ if (fs.existsSync(LOGS_FILE_PATH)) {
421
+ fs.unlinkSync(LOGS_FILE_PATH);
422
+ }
423
+
424
+ if (fs.existsSync(PDF_FILE_PATH)) {
425
+ fs.unlinkSync(PDF_FILE_PATH);
426
+ }
427
+ }
428
+
429
+ // 1: save decoded json string
430
+ if (isDebugging) {
431
+ console.log('2: save json string');
432
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
433
+ LOGS += json + '\n\n\n';
434
+ }
435
+
436
+
437
+ // 2: save decoded json
438
+ const decodedJSON = JSON.parse(json);
439
+ if (isDebugging) {
440
+ console.log('2: save decoded json string')
441
+ LOGS += '2: save decoded json' + '\n' + '=============' + '\n';
442
+ LOGS += decodedJSON + '\n\n\n';
443
+ }
444
+
445
+
446
+ let html = await generateHTMLCorporateReport(decodedJSON, isDebugging);
447
+
448
+
449
+ // 3: save PDF buffer
450
+ let fileBuffer = await generatePDFCorporateReport(html);
451
+ if (isDebugging) {
452
+ console.log('3: save PDF buffer')
453
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
454
+ LOGS += fileBuffer + '\n\n\n';
455
+ }
456
+
457
+
458
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
459
+
460
+ // 4: save encoded base64
461
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
462
+ if (isDebugging) {
463
+ console.log('4: save encoded base64');
464
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
465
+ LOGS += base64data + '\n\n\n';
466
+ }
467
+
468
+
469
+ // 5: save logs to file
470
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
471
+ if (isDebugging) {
472
+ console.log('5: save logs to file');
473
+ }
474
+
475
+ if (isDownloadable) {
476
+ return fileBuffer;
477
+ } else {
478
+ return base64data;
479
+ }
480
+ },
481
+ }