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