@awadheshs109/billing 1.0.29 → 2.0.12
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.
- package/README.md +136 -132
- package/dist/index.d.mts +128 -46
- package/dist/index.d.ts +128 -46
- package/dist/index.js +941 -106
- package/dist/index.mjs +928 -106
- package/package.json +14 -8
package/dist/index.mjs
CHANGED
|
@@ -77,13 +77,22 @@ var InvoiceCalculator = class {
|
|
|
77
77
|
0
|
|
78
78
|
);
|
|
79
79
|
const discountAmount = subtotal * (discount / 100);
|
|
80
|
-
const
|
|
81
|
-
const taxAmount =
|
|
80
|
+
const taxableAmount = subtotal - discountAmount;
|
|
81
|
+
const taxAmount = taxableAmount * (tax / 100);
|
|
82
|
+
const total = taxableAmount + taxAmount;
|
|
82
83
|
return {
|
|
83
|
-
subtotal
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
subtotal: Number(
|
|
85
|
+
subtotal.toFixed(2)
|
|
86
|
+
),
|
|
87
|
+
taxAmount: Number(
|
|
88
|
+
taxAmount.toFixed(2)
|
|
89
|
+
),
|
|
90
|
+
discountAmount: Number(
|
|
91
|
+
discountAmount.toFixed(2)
|
|
92
|
+
),
|
|
93
|
+
total: Number(
|
|
94
|
+
total.toFixed(2)
|
|
95
|
+
)
|
|
87
96
|
};
|
|
88
97
|
}
|
|
89
98
|
};
|
|
@@ -91,7 +100,7 @@ var InvoiceCalculator = class {
|
|
|
91
100
|
// src/core/billing.ts
|
|
92
101
|
var Billing = class {
|
|
93
102
|
static getVersion() {
|
|
94
|
-
return "
|
|
103
|
+
return "2.0.1";
|
|
95
104
|
}
|
|
96
105
|
};
|
|
97
106
|
Billing.calculateGST = calculateGST;
|
|
@@ -100,6 +109,14 @@ Billing.calculateDiscount = calculateDiscount;
|
|
|
100
109
|
Billing.formatCurrency = formatCurrency;
|
|
101
110
|
Billing.InvoiceCalculator = InvoiceCalculator;
|
|
102
111
|
|
|
112
|
+
// src/constants/tax-rates.ts
|
|
113
|
+
var TAX_RATES = {
|
|
114
|
+
GST_5: 5,
|
|
115
|
+
GST_12: 12,
|
|
116
|
+
GST_18: 18,
|
|
117
|
+
GST_28: 28
|
|
118
|
+
};
|
|
119
|
+
|
|
103
120
|
// src/utils/date.ts
|
|
104
121
|
function formatDate(date = /* @__PURE__ */ new Date(), locale = "en-IN") {
|
|
105
122
|
return new Intl.DateTimeFormat(locale, {
|
|
@@ -123,135 +140,891 @@ function isValidGST(gst) {
|
|
|
123
140
|
return /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/i.test(gst);
|
|
124
141
|
}
|
|
125
142
|
|
|
126
|
-
// src/
|
|
127
|
-
var
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
143
|
+
// src/config/default-invoice-config.ts
|
|
144
|
+
var defaultInvoiceConfig = {
|
|
145
|
+
currency: "INR",
|
|
146
|
+
tax: 0,
|
|
147
|
+
discount: 0,
|
|
148
|
+
company: {
|
|
149
|
+
name: "",
|
|
150
|
+
address: "",
|
|
151
|
+
phone: ""
|
|
152
|
+
},
|
|
153
|
+
customer: {
|
|
154
|
+
name: "",
|
|
155
|
+
email: ""
|
|
156
|
+
},
|
|
157
|
+
features: {
|
|
158
|
+
showSellerGST: true,
|
|
159
|
+
showBuyerGST: true,
|
|
160
|
+
showPAN: true,
|
|
161
|
+
showTransport: true,
|
|
162
|
+
showEWay: true,
|
|
163
|
+
showBankDetails: true,
|
|
164
|
+
showTerms: true,
|
|
165
|
+
showSignature: true,
|
|
166
|
+
showSoftwareCredit: true,
|
|
167
|
+
showBranchDetails: true,
|
|
168
|
+
showPaymentDetails: true,
|
|
169
|
+
showPaymentTransactions: true,
|
|
170
|
+
showAmountWords: true
|
|
171
|
+
},
|
|
172
|
+
branding: {
|
|
173
|
+
showSoftwareCredit: true,
|
|
174
|
+
softwareCreditText: "Generated using Zentris Billing",
|
|
175
|
+
logoText: "ZENTRIS",
|
|
176
|
+
logoSubText: "Billing Engine"
|
|
177
|
+
},
|
|
178
|
+
theme: {
|
|
179
|
+
primaryColor: "#221b67",
|
|
180
|
+
accentColor: "#009688"
|
|
181
|
+
}
|
|
132
182
|
};
|
|
133
183
|
|
|
134
|
-
// src/
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
184
|
+
// src/normalizers/invoice-normalizer.ts
|
|
185
|
+
var InvoiceNormalizer = class {
|
|
186
|
+
static normalize(invoice) {
|
|
187
|
+
return {
|
|
188
|
+
...defaultInvoiceConfig,
|
|
189
|
+
...invoice,
|
|
190
|
+
items: invoice.items || [],
|
|
191
|
+
company: {
|
|
192
|
+
name: invoice.company?.name || defaultInvoiceConfig.company?.name || "",
|
|
193
|
+
address: invoice.company?.address || defaultInvoiceConfig.company?.address || "",
|
|
194
|
+
phone: invoice.company?.phone || defaultInvoiceConfig.company?.phone || "",
|
|
195
|
+
email: invoice.company?.email,
|
|
196
|
+
gstNumber: invoice.company?.gstNumber,
|
|
197
|
+
panNumber: invoice.company?.panNumber,
|
|
198
|
+
website: invoice.company?.website,
|
|
199
|
+
bankDetails: invoice.company?.bankDetails,
|
|
200
|
+
branches: invoice.company?.branches || []
|
|
201
|
+
},
|
|
202
|
+
customer: {
|
|
203
|
+
name: invoice.customer?.name || defaultInvoiceConfig.customer?.name || "",
|
|
204
|
+
email: invoice.customer?.email || defaultInvoiceConfig.customer?.email || "",
|
|
205
|
+
phone: invoice.customer?.phone,
|
|
206
|
+
gstNumber: invoice.customer?.gstNumber,
|
|
207
|
+
address: invoice.customer?.address
|
|
208
|
+
},
|
|
209
|
+
features: {
|
|
210
|
+
...defaultInvoiceConfig.features,
|
|
211
|
+
...invoice.features
|
|
212
|
+
},
|
|
213
|
+
branding: {
|
|
214
|
+
...defaultInvoiceConfig.branding,
|
|
215
|
+
...invoice.branding
|
|
216
|
+
},
|
|
217
|
+
theme: {
|
|
218
|
+
...defaultInvoiceConfig.theme,
|
|
219
|
+
...invoice.theme
|
|
220
|
+
},
|
|
221
|
+
payment: invoice.payment ? {
|
|
222
|
+
...invoice.payment,
|
|
223
|
+
transactions: invoice.payment.transactions || []
|
|
224
|
+
} : void 0,
|
|
225
|
+
terms: invoice.terms || []
|
|
226
|
+
};
|
|
166
227
|
}
|
|
167
228
|
};
|
|
168
229
|
|
|
169
|
-
// src/
|
|
170
|
-
var
|
|
171
|
-
static
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
${item.quantity},
|
|
177
|
-
${item.rate}`
|
|
178
|
-
)
|
|
179
|
-
].join("\n");
|
|
230
|
+
// src/renderers/invoice-renderer.ts
|
|
231
|
+
var InvoiceRenderer = class {
|
|
232
|
+
static renderHTML(invoice, summary, template) {
|
|
233
|
+
return template(
|
|
234
|
+
invoice,
|
|
235
|
+
summary
|
|
236
|
+
);
|
|
180
237
|
}
|
|
181
238
|
};
|
|
182
239
|
|
|
183
|
-
// src/exporters/
|
|
184
|
-
var
|
|
240
|
+
// src/exporters/csv-exporter.ts
|
|
241
|
+
var CsvExporter = class {
|
|
185
242
|
static generate(invoice) {
|
|
186
|
-
|
|
187
|
-
invoice,
|
|
188
|
-
|
|
189
|
-
|
|
243
|
+
const summary = InvoiceCalculator.summary(
|
|
244
|
+
invoice.items,
|
|
245
|
+
invoice.tax || 0,
|
|
246
|
+
invoice.discount || 0
|
|
190
247
|
);
|
|
248
|
+
const rows = [
|
|
249
|
+
`Invoice No,${invoice.invoiceNo}`,
|
|
250
|
+
`Date,${invoice.date}`,
|
|
251
|
+
`Customer,${invoice.customer.name}`,
|
|
252
|
+
`Payment Status,${invoice.payment?.status || "pending"}`,
|
|
253
|
+
"",
|
|
254
|
+
"Description,Quantity,Rate,Amount",
|
|
255
|
+
...invoice.items.map(
|
|
256
|
+
(item) => `${item.description},${item.quantity},${item.rate},${item.quantity * item.rate}`
|
|
257
|
+
),
|
|
258
|
+
"",
|
|
259
|
+
`Subtotal,,,${summary.subtotal}`,
|
|
260
|
+
`Tax Amount,,,${summary.taxAmount}`,
|
|
261
|
+
`Discount Amount,,,${summary.discountAmount}`,
|
|
262
|
+
`Grand Total,,,${summary.total}`
|
|
263
|
+
];
|
|
264
|
+
return rows.join("\n");
|
|
191
265
|
}
|
|
192
266
|
};
|
|
193
267
|
|
|
194
268
|
// src/templates/classic.template.ts
|
|
195
269
|
function classicInvoiceTemplate(invoice, summary) {
|
|
270
|
+
const currency = invoice.currency || "INR";
|
|
271
|
+
const items = invoice.items.map(
|
|
272
|
+
(item, index) => `
|
|
273
|
+
<tr>
|
|
274
|
+
<td>
|
|
275
|
+
${index + 1}
|
|
276
|
+
</td>
|
|
277
|
+
<td>
|
|
278
|
+
${item.description}
|
|
279
|
+
</td>
|
|
280
|
+
<td>
|
|
281
|
+
${item.quantity}
|
|
282
|
+
</td>
|
|
283
|
+
<td>
|
|
284
|
+
${Billing.formatCurrency(item.rate, currency)}
|
|
285
|
+
</td>
|
|
286
|
+
<td>
|
|
287
|
+
${Billing.formatCurrency(item.quantity * item.rate, currency)}
|
|
288
|
+
</td>
|
|
289
|
+
</tr>
|
|
290
|
+
`
|
|
291
|
+
).join("");
|
|
196
292
|
return `
|
|
197
|
-
|
|
198
|
-
|
|
293
|
+
<!DOCTYPE html>
|
|
294
|
+
<html lang="en">
|
|
295
|
+
<head>
|
|
296
|
+
<meta charset="UTF-8" />
|
|
297
|
+
<meta
|
|
298
|
+
name="viewport"
|
|
299
|
+
content="width=device-width, initial-scale=1.0"
|
|
300
|
+
/>
|
|
301
|
+
<title>
|
|
302
|
+
${invoice.type || "INVOICE"}
|
|
303
|
+
</title>
|
|
304
|
+
<style>
|
|
305
|
+
* {
|
|
306
|
+
box-sizing: border-box;
|
|
307
|
+
}
|
|
308
|
+
body {
|
|
309
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
310
|
+
background: #ffffff;
|
|
311
|
+
padding: 0;
|
|
312
|
+
margin: 0;
|
|
313
|
+
color: #222222;
|
|
314
|
+
-webkit-print-color-adjust: exact;
|
|
315
|
+
print-color-adjust: exact;
|
|
316
|
+
}
|
|
317
|
+
.receipt-container {
|
|
318
|
+
width: 100%;
|
|
319
|
+
max-width: 100%;
|
|
320
|
+
margin: auto;
|
|
321
|
+
background: #ffffff;
|
|
322
|
+
padding: 40px;
|
|
323
|
+
}
|
|
324
|
+
.top-header {
|
|
325
|
+
display: flex;
|
|
326
|
+
justify-content: space-between;
|
|
327
|
+
align-items: flex-start;
|
|
328
|
+
margin-bottom: 35px;
|
|
329
|
+
}
|
|
330
|
+
.company-name {
|
|
331
|
+
font-size: 28px;
|
|
332
|
+
font-weight: 700;
|
|
333
|
+
margin-bottom: 10px;
|
|
334
|
+
}
|
|
335
|
+
.company-address {
|
|
336
|
+
font-size: 13px;
|
|
337
|
+
line-height: 1.5;
|
|
338
|
+
}
|
|
339
|
+
.invoice-title {
|
|
340
|
+
font-size: 34px;
|
|
341
|
+
font-weight: 700;
|
|
342
|
+
letter-spacing: 1px;
|
|
343
|
+
}
|
|
344
|
+
.address-section {
|
|
345
|
+
display: grid;
|
|
346
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
347
|
+
gap: 25px;
|
|
348
|
+
margin-bottom: 30px;
|
|
349
|
+
}
|
|
350
|
+
.address-box h3 {
|
|
351
|
+
font-size: 16px;
|
|
352
|
+
margin-bottom: 8px;
|
|
353
|
+
}
|
|
354
|
+
.address-box p {
|
|
355
|
+
font-size: 13px;
|
|
356
|
+
line-height: 1.5;
|
|
357
|
+
}
|
|
358
|
+
.invoice-details td {
|
|
359
|
+
padding: 4px 0;
|
|
360
|
+
font-size: 13px;
|
|
361
|
+
}
|
|
362
|
+
.invoice-details td:first-child {
|
|
363
|
+
font-weight: 700;
|
|
364
|
+
padding-right: 10px;
|
|
365
|
+
}
|
|
366
|
+
.items-table {
|
|
367
|
+
width: 100%;
|
|
368
|
+
border-collapse: collapse;
|
|
369
|
+
margin-top: 15px;
|
|
370
|
+
}
|
|
371
|
+
.items-table th {
|
|
372
|
+
background: #f3f3f3;
|
|
373
|
+
padding: 10px;
|
|
374
|
+
border: 1px solid #cccccc;
|
|
375
|
+
font-size: 13px;
|
|
376
|
+
text-align: center;
|
|
377
|
+
}
|
|
378
|
+
.items-table td {
|
|
379
|
+
border: 1px solid #cccccc;
|
|
380
|
+
padding: 9px;
|
|
381
|
+
font-size: 12px;
|
|
382
|
+
line-height: 1.4;
|
|
383
|
+
word-break: break-word;
|
|
384
|
+
}
|
|
385
|
+
.items-table td:nth-child(1),
|
|
386
|
+
.items-table td:nth-child(3) {
|
|
387
|
+
text-align: center;
|
|
388
|
+
width: 60px;
|
|
389
|
+
}
|
|
390
|
+
.items-table td:nth-child(4),
|
|
391
|
+
.items-table td:nth-child(5) {
|
|
392
|
+
text-align: right;
|
|
393
|
+
width: 120px;
|
|
394
|
+
}
|
|
395
|
+
.total-wrapper {
|
|
396
|
+
display: flex;
|
|
397
|
+
justify-content: flex-end;
|
|
398
|
+
margin-top: 18px;
|
|
399
|
+
}
|
|
400
|
+
.total-box {
|
|
401
|
+
width: 320px;
|
|
402
|
+
}
|
|
403
|
+
.total-table td {
|
|
404
|
+
padding: 10px;
|
|
405
|
+
font-size: 14px;
|
|
406
|
+
}
|
|
407
|
+
.total-table td:last-child {
|
|
408
|
+
text-align: right;
|
|
409
|
+
}
|
|
410
|
+
.total-table tr:last-child td {
|
|
411
|
+
border: 1px solid #cccccc;
|
|
412
|
+
font-size: 24px;
|
|
413
|
+
font-weight: 700;
|
|
414
|
+
}
|
|
415
|
+
.notes {
|
|
416
|
+
margin-top: 35px;
|
|
417
|
+
}
|
|
418
|
+
.notes h3 {
|
|
419
|
+
margin-bottom: 10px;
|
|
420
|
+
font-size: 15px;
|
|
421
|
+
}
|
|
422
|
+
.notes p {
|
|
423
|
+
font-size: 12px;
|
|
424
|
+
line-height: 1.6;
|
|
425
|
+
}
|
|
426
|
+
.signature-section {
|
|
427
|
+
margin-top: 45px;
|
|
428
|
+
display: flex;
|
|
429
|
+
justify-content: flex-end;
|
|
430
|
+
}
|
|
431
|
+
.signature {
|
|
432
|
+
font-size: 34px;
|
|
433
|
+
font-family: cursive;
|
|
434
|
+
margin-bottom: 5px;
|
|
435
|
+
}
|
|
436
|
+
.signature-label {
|
|
437
|
+
border-top: 1px solid #222222;
|
|
438
|
+
padding-top: 5px;
|
|
439
|
+
font-size: 11px;
|
|
440
|
+
}
|
|
441
|
+
.footer {
|
|
442
|
+
margin-top: 40px;
|
|
443
|
+
text-align: center;
|
|
444
|
+
color: #777777;
|
|
445
|
+
font-size: 11px;
|
|
446
|
+
}
|
|
447
|
+
</style>
|
|
448
|
+
</head>
|
|
199
449
|
<body>
|
|
200
|
-
|
|
201
|
-
<div class="
|
|
202
|
-
|
|
203
|
-
<h1>INVOICE</h1>
|
|
204
|
-
|
|
450
|
+
<div class="receipt-container">
|
|
451
|
+
<div class="top-header">
|
|
205
452
|
<div>
|
|
206
|
-
|
|
207
|
-
|
|
453
|
+
<div class="company-name">
|
|
454
|
+
${invoice.company?.name || "Zentris Pvt Ltd"}
|
|
208
455
|
</div>
|
|
209
|
-
|
|
210
|
-
<h3>BILL TO</h3>
|
|
211
|
-
|
|
456
|
+
<div class="company-address">
|
|
212
457
|
<p>
|
|
213
|
-
${invoice.
|
|
214
|
-
<br/>
|
|
215
|
-
${invoice.customer.address}
|
|
458
|
+
${invoice.company?.address || "Mumbai, India"}
|
|
216
459
|
</p>
|
|
217
|
-
|
|
460
|
+
<p>
|
|
461
|
+
${invoice.company?.phone || "+91 9999999999"}
|
|
462
|
+
</p>
|
|
463
|
+
<p>
|
|
464
|
+
${invoice.company?.email || "support@zentris.com"}
|
|
465
|
+
</p>
|
|
466
|
+
<p>
|
|
467
|
+
GSTIN:
|
|
468
|
+
${invoice.company?.gstNumber || "27ABCDE1234F1Z5"}
|
|
469
|
+
</p>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
<div class="invoice-title">
|
|
473
|
+
${invoice.type || "INVOICE"}
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
<div class="address-section">
|
|
477
|
+
<div class="address-box">
|
|
478
|
+
<h3>Seller</h3>
|
|
479
|
+
<p>
|
|
480
|
+
${invoice.company?.name || "Zentris Pvt Ltd"}
|
|
481
|
+
</p>
|
|
482
|
+
<p>
|
|
483
|
+
${invoice.company?.address || "Mumbai"}
|
|
484
|
+
</p>
|
|
485
|
+
</div>
|
|
486
|
+
<div class="address-box">
|
|
487
|
+
<h3>Buyer</h3>
|
|
488
|
+
<p>
|
|
489
|
+
${invoice.customer?.name || "Customer Name"}
|
|
490
|
+
</p>
|
|
491
|
+
<p>
|
|
492
|
+
${invoice.customer?.company || ""}
|
|
493
|
+
</p>
|
|
494
|
+
<p>
|
|
495
|
+
${invoice.customer?.address || "Customer Address"}
|
|
496
|
+
</p>
|
|
497
|
+
<p>
|
|
498
|
+
${invoice.customer?.phone || ""}
|
|
499
|
+
</p>
|
|
500
|
+
</div>
|
|
501
|
+
<div class="invoice-details">
|
|
218
502
|
<table>
|
|
219
|
-
|
|
220
503
|
<tr>
|
|
504
|
+
<td>Invoice Number</td>
|
|
505
|
+
<td>${invoice.invoiceNo || "INV-001"}</td>
|
|
506
|
+
</tr>
|
|
507
|
+
<tr>
|
|
508
|
+
<td>Date</td>
|
|
509
|
+
<td>${invoice.date || (/* @__PURE__ */ new Date()).toLocaleDateString()}</td>
|
|
510
|
+
</tr>
|
|
511
|
+
<tr>
|
|
512
|
+
<td>Due Date</td>
|
|
513
|
+
<td>${invoice.dueDate || ""}</td>
|
|
514
|
+
</tr>
|
|
515
|
+
<tr>
|
|
516
|
+
<td>Payment Mode</td>
|
|
517
|
+
<td>${invoice.payment?.mode || "Bank Transfer"}</td>
|
|
518
|
+
</tr>
|
|
519
|
+
<tr>
|
|
520
|
+
<td>Status</td>
|
|
521
|
+
<td>${invoice.payment?.status || "Pending"}</td>
|
|
522
|
+
</tr>
|
|
523
|
+
</table>
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
<table class="items-table">
|
|
527
|
+
<thead>
|
|
528
|
+
<tr>
|
|
529
|
+
<th>Number</th>
|
|
221
530
|
<th>Description</th>
|
|
531
|
+
<th>Qty</th>
|
|
532
|
+
<th>Rate</th>
|
|
222
533
|
<th>Amount</th>
|
|
223
534
|
</tr>
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
535
|
+
</thead>
|
|
536
|
+
<tbody>
|
|
537
|
+
${items}
|
|
538
|
+
</tbody>
|
|
539
|
+
</table>
|
|
540
|
+
<div class="total-wrapper">
|
|
541
|
+
<div class="total-box">
|
|
542
|
+
<table class="total-table">
|
|
227
543
|
<tr>
|
|
228
|
-
<td
|
|
544
|
+
<td>Subtotal</td>
|
|
229
545
|
<td>
|
|
230
|
-
|
|
546
|
+
${Billing.formatCurrency(summary.subtotal, currency)}
|
|
547
|
+
</td>
|
|
548
|
+
</tr>
|
|
549
|
+
<tr>
|
|
550
|
+
<td>Tax</td>
|
|
551
|
+
<td>
|
|
552
|
+
${Billing.formatCurrency(summary.taxAmount, currency)}
|
|
553
|
+
</td>
|
|
554
|
+
</tr>
|
|
555
|
+
<tr>
|
|
556
|
+
<td>Discount</td>
|
|
557
|
+
<td>
|
|
558
|
+
${Billing.formatCurrency(summary.discountAmount, currency)}
|
|
559
|
+
</td>
|
|
560
|
+
</tr>
|
|
561
|
+
<tr>
|
|
562
|
+
<td>Total</td>
|
|
563
|
+
<td>
|
|
564
|
+
${Billing.formatCurrency(summary.total, currency)}
|
|
231
565
|
</td>
|
|
232
566
|
</tr>
|
|
233
|
-
`
|
|
234
|
-
).join("")}
|
|
235
|
-
|
|
236
567
|
</table>
|
|
237
|
-
|
|
238
|
-
<div>
|
|
239
|
-
Subtotal:
|
|
240
|
-
\u20B9${summary.subtotal}
|
|
241
568
|
</div>
|
|
242
|
-
|
|
243
|
-
<div>
|
|
244
|
-
Tax:
|
|
245
|
-
\u20B9${summary.tax}
|
|
246
569
|
</div>
|
|
570
|
+
<div class="notes">
|
|
571
|
+
<h3>Terms and Conditions</h3>
|
|
572
|
+
<p>
|
|
573
|
+
${invoice.notes || "Payment due within 15 days. Thank you for your business."}
|
|
574
|
+
</p>
|
|
575
|
+
</div>
|
|
576
|
+
${invoice.signature ? `
|
|
577
|
+
<div class="signature-section">
|
|
578
|
+
<div class="signature-box">
|
|
579
|
+
<div class="signature">
|
|
580
|
+
${invoice.signature}
|
|
581
|
+
</div>
|
|
582
|
+
<div class="signature-label">
|
|
583
|
+
Authorized Signature
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
` : ""}
|
|
588
|
+
<div class="footer">
|
|
589
|
+
Generated using Zentris Billing
|
|
590
|
+
</div>
|
|
591
|
+
</div>
|
|
592
|
+
</body>
|
|
593
|
+
</html>
|
|
594
|
+
`;
|
|
595
|
+
}
|
|
247
596
|
|
|
597
|
+
// src/templates/classic.template2.ts
|
|
598
|
+
function classicInvoiceTemplate2(invoice, summary) {
|
|
599
|
+
const currency = invoice.currency || "INR";
|
|
600
|
+
const items = invoice.items.map(
|
|
601
|
+
(item, index) => `
|
|
602
|
+
<tr>
|
|
603
|
+
<td class="center">
|
|
604
|
+
${index + 1}
|
|
605
|
+
</td>
|
|
606
|
+
<td>
|
|
607
|
+
<b>${item.description}</b>
|
|
608
|
+
</td>
|
|
609
|
+
<td class="center">
|
|
610
|
+
${item.hsn || "8302"}
|
|
611
|
+
</td>
|
|
612
|
+
<td class="center">
|
|
613
|
+
${item.quantity}
|
|
614
|
+
</td>
|
|
615
|
+
<td class="right">
|
|
616
|
+
${Billing.formatCurrency(item.rate, currency)}
|
|
617
|
+
</td>
|
|
618
|
+
<td class="right">
|
|
619
|
+
${Billing.formatCurrency(item.quantity * item.rate, currency)}
|
|
620
|
+
</td>
|
|
621
|
+
</tr>
|
|
622
|
+
`
|
|
623
|
+
).join("");
|
|
624
|
+
return `
|
|
625
|
+
<!DOCTYPE html>
|
|
626
|
+
<html lang="en">
|
|
627
|
+
<head>
|
|
628
|
+
<meta charset="UTF-8"/>
|
|
629
|
+
<meta
|
|
630
|
+
name="viewport"
|
|
631
|
+
content="width=device-width, initial-scale=1.0"
|
|
632
|
+
/>
|
|
633
|
+
<title>
|
|
634
|
+
${invoice.type || "TAX INVOICE"}
|
|
635
|
+
</title>
|
|
636
|
+
<style>
|
|
637
|
+
*{
|
|
638
|
+
margin:0;
|
|
639
|
+
padding:0;
|
|
640
|
+
box-sizing:border-box;
|
|
641
|
+
font-family:Arial, Helvetica, sans-serif;
|
|
642
|
+
}
|
|
643
|
+
body{
|
|
644
|
+
background:#efefef;
|
|
645
|
+
padding:10px;
|
|
646
|
+
}
|
|
647
|
+
.invoice{
|
|
648
|
+
width:100%;
|
|
649
|
+
max-width:1000px;
|
|
650
|
+
margin:auto;
|
|
651
|
+
background:#fff;
|
|
652
|
+
border:2px solid #333;
|
|
653
|
+
color:#111;
|
|
654
|
+
}
|
|
655
|
+
table{
|
|
656
|
+
width:100%;
|
|
657
|
+
border-collapse:collapse;
|
|
658
|
+
}
|
|
659
|
+
td,th{
|
|
660
|
+
border:1px solid #333;
|
|
661
|
+
padding:4px 6px;
|
|
662
|
+
vertical-align:top;
|
|
663
|
+
font-size:12px;
|
|
664
|
+
}
|
|
665
|
+
.header{
|
|
666
|
+
padding:15px;
|
|
667
|
+
border-bottom:2px solid #333;
|
|
668
|
+
}
|
|
669
|
+
.top-flex{
|
|
670
|
+
display:flex;
|
|
671
|
+
justify-content:space-between;
|
|
672
|
+
align-items:flex-start;
|
|
673
|
+
}
|
|
674
|
+
.company-name{
|
|
675
|
+
font-size:32px;
|
|
676
|
+
font-weight:900;
|
|
677
|
+
color:#221b67;
|
|
678
|
+
line-height:1;
|
|
679
|
+
}
|
|
680
|
+
.green-strip{
|
|
681
|
+
background:#009688;
|
|
682
|
+
color:#fff;
|
|
683
|
+
font-size:13px;
|
|
684
|
+
font-weight:bold;
|
|
685
|
+
padding:6px 10px;
|
|
686
|
+
margin-top:8px;
|
|
687
|
+
display:inline-block;
|
|
688
|
+
}
|
|
689
|
+
.address{
|
|
690
|
+
margin-top:10px;
|
|
691
|
+
font-size:13px;
|
|
692
|
+
line-height:1.5;
|
|
693
|
+
}
|
|
694
|
+
.right-top{
|
|
695
|
+
text-align:right;
|
|
696
|
+
font-size:12px;
|
|
697
|
+
line-height:1.5;
|
|
698
|
+
}
|
|
699
|
+
.logo{
|
|
700
|
+
margin-top:10px;
|
|
701
|
+
font-size:28px;
|
|
702
|
+
font-weight:900;
|
|
703
|
+
color:#2a2a75;
|
|
704
|
+
}
|
|
705
|
+
.logo-sub{
|
|
706
|
+
font-size:10px;
|
|
707
|
+
letter-spacing:2px;
|
|
708
|
+
color:#999;
|
|
709
|
+
}
|
|
710
|
+
.invoice-title{
|
|
711
|
+
text-align:center;
|
|
712
|
+
font-size:18px;
|
|
713
|
+
font-weight:900;
|
|
714
|
+
}
|
|
715
|
+
.bold{
|
|
716
|
+
font-weight:bold;
|
|
717
|
+
}
|
|
718
|
+
.center{
|
|
719
|
+
text-align:center;
|
|
720
|
+
}
|
|
721
|
+
.right{
|
|
722
|
+
text-align:right;
|
|
723
|
+
}
|
|
724
|
+
.product-table th{
|
|
725
|
+
background:#f5f5f5;
|
|
726
|
+
font-size:11px;
|
|
727
|
+
}
|
|
728
|
+
.product-table td{
|
|
729
|
+
height:28px;
|
|
730
|
+
font-size:11px;
|
|
731
|
+
}
|
|
732
|
+
.total-row td{
|
|
733
|
+
font-size:15px;
|
|
734
|
+
font-weight:bold;
|
|
735
|
+
}
|
|
736
|
+
.amount-words{
|
|
737
|
+
padding:8px 12px;
|
|
738
|
+
font-size:12px;
|
|
739
|
+
line-height:1.6;
|
|
740
|
+
border-top:1px solid #333;
|
|
741
|
+
border-bottom:1px solid #333;
|
|
742
|
+
}
|
|
743
|
+
.tax-table th{
|
|
744
|
+
background:#f5f5f5;
|
|
745
|
+
}
|
|
746
|
+
.bank-details{
|
|
747
|
+
padding:8px;
|
|
748
|
+
line-height:1.7;
|
|
749
|
+
font-size:12px;
|
|
750
|
+
}
|
|
751
|
+
.qr{
|
|
752
|
+
width:100px;
|
|
753
|
+
height:100px;
|
|
754
|
+
border:3px solid #000;
|
|
755
|
+
margin:auto;
|
|
756
|
+
display:flex;
|
|
757
|
+
justify-content:center;
|
|
758
|
+
align-items:center;
|
|
759
|
+
font-size:12px;
|
|
760
|
+
font-weight:bold;
|
|
761
|
+
}
|
|
762
|
+
.certified{
|
|
763
|
+
text-align:center;
|
|
764
|
+
padding-top:10px;
|
|
765
|
+
font-size:11px;
|
|
766
|
+
font-weight:bold;
|
|
767
|
+
}
|
|
768
|
+
.company-sign{
|
|
769
|
+
text-align:center;
|
|
770
|
+
font-size:16px;
|
|
771
|
+
font-weight:bold;
|
|
772
|
+
padding:15px 0;
|
|
773
|
+
}
|
|
774
|
+
.computer-note{
|
|
775
|
+
text-align:center;
|
|
776
|
+
margin-top:60px;
|
|
777
|
+
transform:rotate(-10deg);
|
|
778
|
+
font-size:11px;
|
|
779
|
+
color:#333;
|
|
780
|
+
}
|
|
781
|
+
.terms{
|
|
782
|
+
padding:10px;
|
|
783
|
+
line-height:1.5;
|
|
784
|
+
font-size:11px;
|
|
785
|
+
}
|
|
786
|
+
.signature{
|
|
787
|
+
height:70px;
|
|
788
|
+
padding:10px;
|
|
789
|
+
font-weight:bold;
|
|
790
|
+
}
|
|
791
|
+
.footer{
|
|
792
|
+
padding:10px 0;
|
|
793
|
+
font-size:14px;
|
|
794
|
+
text-align:center;
|
|
795
|
+
}
|
|
796
|
+
@media print{
|
|
797
|
+
body{
|
|
798
|
+
background:#fff;
|
|
799
|
+
padding:0;
|
|
800
|
+
}
|
|
801
|
+
.invoice{
|
|
802
|
+
border:none;
|
|
803
|
+
max-width:100%;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
</style>
|
|
807
|
+
</head>
|
|
808
|
+
<body>
|
|
809
|
+
<div class="invoice">
|
|
810
|
+
<div class="header">
|
|
811
|
+
<div class="top-flex">
|
|
248
812
|
<div>
|
|
249
|
-
|
|
250
|
-
|
|
813
|
+
<div class="company-name">
|
|
814
|
+
${invoice.company?.name || "Zentris Pvt Ltd"}
|
|
251
815
|
</div>
|
|
252
|
-
|
|
816
|
+
<div class="green-strip">
|
|
817
|
+
Manufacturing & Software Billing Solutions
|
|
818
|
+
</div>
|
|
819
|
+
<div class="address">
|
|
820
|
+
${invoice.company?.address || "Mumbai, India"}
|
|
821
|
+
<br>
|
|
822
|
+
Phone:
|
|
823
|
+
${invoice.company?.phone || "+91 9999999999"}
|
|
824
|
+
<br>
|
|
825
|
+
Email:
|
|
826
|
+
${invoice.company?.email || "support@zentris.com"}
|
|
827
|
+
<br>
|
|
828
|
+
GSTIN:
|
|
829
|
+
${invoice.company?.gstNumber || "27ABCDE1234F1Z5"}
|
|
830
|
+
</div>
|
|
831
|
+
</div>
|
|
832
|
+
<div class="right-top">
|
|
833
|
+
Invoice:
|
|
834
|
+
${invoice.invoiceNo}
|
|
835
|
+
<br>
|
|
836
|
+
Date:
|
|
837
|
+
${invoice.date}
|
|
838
|
+
<br>
|
|
839
|
+
Due:
|
|
840
|
+
${invoice.dueDate || ""}
|
|
841
|
+
<div class="logo">
|
|
842
|
+
ZENTRIS
|
|
843
|
+
<div class="logo-sub">
|
|
844
|
+
BILLING ENGINE
|
|
845
|
+
</div>
|
|
846
|
+
</div>
|
|
847
|
+
</div>
|
|
848
|
+
</div>
|
|
849
|
+
</div>
|
|
850
|
+
<table>
|
|
851
|
+
<tr>
|
|
852
|
+
<td width="35%">
|
|
853
|
+
<span class="bold">
|
|
854
|
+
PAN :
|
|
855
|
+
</span>
|
|
856
|
+
${invoice.company?.panNumber || "ABCDE1234F"}
|
|
857
|
+
</td>
|
|
858
|
+
<td width="40%" class="invoice-title">
|
|
859
|
+
${invoice.type || "TAX INVOICE"}
|
|
860
|
+
</td>
|
|
861
|
+
<td width="25%" class="right bold">
|
|
862
|
+
ORIGINAL FOR RECIPIENT
|
|
863
|
+
</td>
|
|
864
|
+
</tr>
|
|
865
|
+
</table>
|
|
866
|
+
<table>
|
|
867
|
+
<tr>
|
|
868
|
+
<td width="40%" class="center bold">
|
|
869
|
+
Customer Detail
|
|
870
|
+
</td>
|
|
871
|
+
<td colspan="2"></td>
|
|
872
|
+
</tr>
|
|
873
|
+
<tr>
|
|
874
|
+
<td>
|
|
875
|
+
<b>M/S:</b>
|
|
876
|
+
${invoice.customer?.name}
|
|
877
|
+
<br><br>
|
|
878
|
+
<b>Company:</b>
|
|
879
|
+
${invoice.customer?.company || ""}
|
|
880
|
+
<br><br>
|
|
881
|
+
<b>Address:</b>
|
|
882
|
+
${invoice.customer?.address}
|
|
883
|
+
<br><br>
|
|
884
|
+
<b>Phone:</b>
|
|
885
|
+
${invoice.customer?.phone || ""}
|
|
886
|
+
<br><br>
|
|
887
|
+
<b>GSTIN:</b>
|
|
888
|
+
${invoice.customer?.gstNumber || ""}
|
|
889
|
+
</td>
|
|
890
|
+
<td width="30%">
|
|
891
|
+
<b>Payment Mode:</b>
|
|
892
|
+
${invoice.payment?.mode || "UPI"}
|
|
893
|
+
<br><br>
|
|
894
|
+
<b>Transport:</b>
|
|
895
|
+
${invoice.transport || "Blue Dart"}
|
|
896
|
+
<br><br>
|
|
897
|
+
<b>E-Way Bill:</b>
|
|
898
|
+
${invoice.eway || "78456378"}
|
|
899
|
+
</td>
|
|
900
|
+
<td width="30%">
|
|
901
|
+
<b>Status:</b>
|
|
902
|
+
${invoice.payment?.status || "Pending"}
|
|
903
|
+
</td>
|
|
904
|
+
</tr>
|
|
905
|
+
</table>
|
|
906
|
+
<table class="product-table">
|
|
907
|
+
<tr>
|
|
908
|
+
<th width="5%">
|
|
909
|
+
Sr
|
|
910
|
+
</th>
|
|
911
|
+
<th width="40%">
|
|
912
|
+
Description
|
|
913
|
+
</th>
|
|
914
|
+
<th width="13%">
|
|
915
|
+
HSN
|
|
916
|
+
</th>
|
|
917
|
+
<th width="13%">
|
|
918
|
+
Qty
|
|
919
|
+
</th>
|
|
920
|
+
<th width="14%">
|
|
921
|
+
Rate
|
|
922
|
+
</th>
|
|
923
|
+
<th width="15%">
|
|
924
|
+
Amount
|
|
925
|
+
</th>
|
|
926
|
+
</tr>
|
|
927
|
+
${items}
|
|
928
|
+
<tr class="total-row">
|
|
929
|
+
<td colspan="2" class="right">
|
|
930
|
+
TOTAL
|
|
931
|
+
</td>
|
|
932
|
+
<td></td>
|
|
933
|
+
<td class="center">
|
|
934
|
+
${invoice.items.length}
|
|
935
|
+
</td>
|
|
936
|
+
<td></td>
|
|
937
|
+
<td class="right">
|
|
938
|
+
${Billing.formatCurrency(summary.total, currency)}
|
|
939
|
+
</td>
|
|
940
|
+
</tr>
|
|
941
|
+
</table>
|
|
942
|
+
<div class="amount-words">
|
|
943
|
+
<b>Total in words:</b>
|
|
944
|
+
${invoice.amountWords || "Amount payable as per invoice"}
|
|
945
|
+
</div>
|
|
946
|
+
<table class="tax-table">
|
|
947
|
+
<tr>
|
|
948
|
+
<th>
|
|
949
|
+
Taxable
|
|
950
|
+
</th>
|
|
951
|
+
<th>
|
|
952
|
+
Tax %
|
|
953
|
+
</th>
|
|
954
|
+
<th>
|
|
955
|
+
Tax Amount
|
|
956
|
+
</th>
|
|
957
|
+
<th>
|
|
958
|
+
Discount
|
|
959
|
+
</th>
|
|
960
|
+
<th>
|
|
961
|
+
Grand Total
|
|
962
|
+
</th>
|
|
963
|
+
</tr>
|
|
964
|
+
<tr>
|
|
965
|
+
<td class="right">
|
|
966
|
+
${summary.subtotal.toFixed(2)}
|
|
967
|
+
</td>
|
|
968
|
+
<td class="center">
|
|
969
|
+
${invoice.tax || 0}%
|
|
970
|
+
</td>
|
|
971
|
+
<td class="right">
|
|
972
|
+
${summary.taxAmount.toFixed(2)}
|
|
973
|
+
</td>
|
|
974
|
+
<td class="right">
|
|
975
|
+
${summary.discountAmount.toFixed(2)}
|
|
976
|
+
</td>
|
|
977
|
+
<td class="right bold">
|
|
978
|
+
${summary.total.toFixed(2)}
|
|
979
|
+
</td>
|
|
980
|
+
</tr>
|
|
981
|
+
</table>
|
|
982
|
+
<table>
|
|
983
|
+
<tr>
|
|
984
|
+
<td width="60%">
|
|
985
|
+
<div class="bank-details">
|
|
986
|
+
<b>Bank:</b>
|
|
987
|
+
ICICI BANK
|
|
988
|
+
<br>
|
|
989
|
+
<b>Account:</b>
|
|
990
|
+
2715500356
|
|
991
|
+
<br>
|
|
992
|
+
<b>IFSC:</b>
|
|
993
|
+
ICIC000045
|
|
994
|
+
<br>
|
|
995
|
+
<b>UPI:</b>
|
|
996
|
+
zentris@icici
|
|
997
|
+
</div>
|
|
998
|
+
</td>
|
|
999
|
+
<td width="40%" class="center">
|
|
1000
|
+
<div class="qr">
|
|
1001
|
+
QR CODE
|
|
1002
|
+
</div>
|
|
1003
|
+
<div style="margin-top:8px;">
|
|
1004
|
+
Pay using UPI
|
|
1005
|
+
</div>
|
|
1006
|
+
</td>
|
|
1007
|
+
</tr>
|
|
1008
|
+
</table>
|
|
1009
|
+
<div class="terms">
|
|
1010
|
+
<b>Terms & Conditions</b>
|
|
1011
|
+
<br><br>
|
|
1012
|
+
Payment due within 15 days.
|
|
1013
|
+
<br>
|
|
1014
|
+
Goods once sold will not be taken back.
|
|
1015
|
+
<br>
|
|
1016
|
+
Subject to Mumbai jurisdiction.
|
|
1017
|
+
</div>
|
|
1018
|
+
<div class="company-sign">
|
|
1019
|
+
For
|
|
1020
|
+
${invoice.company?.name || "Zentris Pvt Ltd"}
|
|
1021
|
+
<br><br>
|
|
1022
|
+
${invoice.signature || "Authorised Signatory"}
|
|
1023
|
+
</div>
|
|
1024
|
+
</div>
|
|
1025
|
+
<div class="footer">
|
|
1026
|
+
Generated using Zentris Billing
|
|
253
1027
|
</div>
|
|
254
|
-
|
|
255
1028
|
</body>
|
|
256
1029
|
</html>
|
|
257
1030
|
`;
|
|
@@ -259,20 +1032,62 @@ Total:
|
|
|
259
1032
|
|
|
260
1033
|
// src/exporters/html-exporter.ts
|
|
261
1034
|
var HtmlExporter = class {
|
|
1035
|
+
static generate(invoice, options) {
|
|
1036
|
+
const normalizedInvoice = InvoiceNormalizer.normalize(invoice);
|
|
1037
|
+
const summary = InvoiceCalculator.summary(
|
|
1038
|
+
normalizedInvoice.items,
|
|
1039
|
+
normalizedInvoice.tax || 0,
|
|
1040
|
+
normalizedInvoice.discount || 0
|
|
1041
|
+
);
|
|
1042
|
+
const template = options?.template === "gst" ? classicInvoiceTemplate2 : classicInvoiceTemplate;
|
|
1043
|
+
return InvoiceRenderer.renderHTML(
|
|
1044
|
+
normalizedInvoice,
|
|
1045
|
+
summary,
|
|
1046
|
+
template
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
// src/exporters/json-exporter.ts
|
|
1052
|
+
var JsonExporter = class {
|
|
262
1053
|
static generate(invoice) {
|
|
263
1054
|
const summary = InvoiceCalculator.summary(
|
|
264
1055
|
invoice.items,
|
|
265
|
-
invoice.tax,
|
|
266
|
-
invoice.discount
|
|
1056
|
+
invoice.tax || 0,
|
|
1057
|
+
invoice.discount || 0
|
|
1058
|
+
);
|
|
1059
|
+
return JSON.stringify(
|
|
1060
|
+
{
|
|
1061
|
+
invoice,
|
|
1062
|
+
summary,
|
|
1063
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1064
|
+
},
|
|
1065
|
+
null,
|
|
1066
|
+
2
|
|
267
1067
|
);
|
|
268
|
-
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
// src/exporters/pdf-exporter.ts
|
|
1072
|
+
import puppeteer from "puppeteer";
|
|
1073
|
+
var PdfExporter = class {
|
|
1074
|
+
static async generate(html) {
|
|
1075
|
+
const browser = await puppeteer.launch({ headless: true });
|
|
1076
|
+
const page = await browser.newPage();
|
|
1077
|
+
await page.setContent(html, { waitUntil: "networkidle0" });
|
|
1078
|
+
const pdfBuffer = await page.pdf({
|
|
1079
|
+
format: "A4",
|
|
1080
|
+
printBackground: true
|
|
1081
|
+
});
|
|
1082
|
+
await browser.close();
|
|
1083
|
+
return Buffer.from(pdfBuffer);
|
|
269
1084
|
}
|
|
270
1085
|
};
|
|
271
1086
|
|
|
272
1087
|
// src/generators/invoice-generator.ts
|
|
273
1088
|
var InvoiceGenerator = class {
|
|
274
|
-
static
|
|
275
|
-
return
|
|
1089
|
+
static toHTML(invoice, options) {
|
|
1090
|
+
return HtmlExporter.generate(invoice, options);
|
|
276
1091
|
}
|
|
277
1092
|
static toCSV(invoice) {
|
|
278
1093
|
return CsvExporter.generate(invoice);
|
|
@@ -280,17 +1095,24 @@ var InvoiceGenerator = class {
|
|
|
280
1095
|
static toJSON(invoice) {
|
|
281
1096
|
return JsonExporter.generate(invoice);
|
|
282
1097
|
}
|
|
283
|
-
static
|
|
284
|
-
|
|
1098
|
+
static async toPDF(invoice, options) {
|
|
1099
|
+
const html = this.toHTML(invoice, options);
|
|
1100
|
+
return PdfExporter.generate(html);
|
|
285
1101
|
}
|
|
286
1102
|
};
|
|
1103
|
+
|
|
1104
|
+
// src/version.ts
|
|
1105
|
+
var VERSION = "2.0.1";
|
|
287
1106
|
export {
|
|
288
1107
|
Billing,
|
|
289
1108
|
BillingError,
|
|
290
1109
|
InvoiceCalculator,
|
|
291
1110
|
InvoiceError,
|
|
292
1111
|
InvoiceGenerator,
|
|
1112
|
+
InvoiceNormalizer,
|
|
1113
|
+
InvoiceRenderer,
|
|
293
1114
|
TAX_RATES,
|
|
1115
|
+
VERSION,
|
|
294
1116
|
ValidationError,
|
|
295
1117
|
calculateDiscount,
|
|
296
1118
|
calculateGST,
|