blob: dc80e4154fbda301b953d840aa2592dff922c2ee [file] [log] [blame]
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +02001package main
2
3import (
4 "bytes"
5 "fmt"
6 "html/template"
Serge Bazanski772a1332021-02-17 20:28:51 +01007 "strings"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +02008 "time"
9
Serge Bazanski97b5cd72023-07-28 17:14:50 +000010 wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020011
Sergiusz Bazanski1446e982019-07-21 16:04:23 +020012 pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto"
Sergiusz Bazanskicea71e32019-07-21 15:30:08 +020013 "code.hackerspace.pl/hscloud/bgpwtf/invoice/templates"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020014)
15
16var (
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020017 invTmpl map[string]*template.Template
18
19 languages = []string{"en", "pl"}
20 defaultLanguage = "en"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020021)
22
23func init() {
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020024 invTmpl = make(map[string]*template.Template)
25 for _, language := range languages {
26 filename := fmt.Sprintf("invoice_%s.html", language)
27 a, err := templates.Asset(filename)
28 if err != nil {
29 panic(err)
30 }
31 invTmpl[language] = template.Must(template.New(filename).Parse(string(a)))
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020032 }
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020033}
34
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020035func renderInvoicePDF(i *pb.Invoice, language string) ([]byte, error) {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020036 type item struct {
37 Title string
38 UnitPrice string
39 Qty string
40 VATRate string
41 TotalNet string
42 Total string
43 }
44
Serge Bazanski772a1332021-02-17 20:28:51 +010045 symbols := ""
46 var parts []string
47 for _, code := range i.Data.SpCode {
48 parts = append(parts, code.String())
49 }
50 for _, code := range i.GtuCode {
51 parts = append(parts, code.String())
52 }
53 if len(parts) > 0 {
54 symbols = strings.Join(parts, ", ") + "."
55 } else {
Serge Bazanski87ede252021-05-12 21:05:53 +000056 if language == "en" {
57 symbols = "<i>brak (none)</i>."
58 } else {
59 symbols = "<i>brak</i>."
60 }
Serge Bazanski772a1332021-02-17 20:28:51 +010061 }
62
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020063 data := struct {
64 InvoiceNumber string
65 InvoicerBilling []string
66 InvoicerVAT string
67 InvoicerCompanyNumber string
68 InvoiceeBilling []string
69 InvoiceeVAT string
70 Date time.Time
71 DueDate time.Time
72 IBAN string
73 SWIFT string
74 Proforma bool
75 ReverseVAT bool
76 USCustomer bool
77 Items []item
78 TotalNet string
79 VATTotal string
80 Total string
81 DeliveryCharge string
Serge Bazanski772a1332021-02-17 20:28:51 +010082 Symbols template.HTML
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020083 }{
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020084 InvoiceNumber: i.FinalUid,
85 Date: time.Unix(0, i.Date),
86 DueDate: time.Unix(0, i.DueDate),
87 IBAN: i.Data.Iban,
88 SWIFT: i.Data.Swift,
89 InvoicerVAT: i.Data.InvoicerVatId,
90 InvoicerCompanyNumber: i.Data.InvoicerCompanyNumber,
91 InvoiceeVAT: i.Data.CustomerVatId,
92 Proforma: i.State == pb.Invoice_STATE_PROFORMA,
93 ReverseVAT: i.Data.ReverseVat,
94 USCustomer: i.Data.UsCustomer,
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020095
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020096 InvoicerBilling: make([]string, len(i.Data.InvoicerBilling)),
97 InvoiceeBilling: make([]string, len(i.Data.CustomerBilling)),
Serge Bazanski772a1332021-02-17 20:28:51 +010098 Symbols: template.HTML(symbols),
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020099 }
100
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200101 for d, s := range i.Data.InvoicerBilling {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200102 data.InvoicerBilling[d] = s
103 }
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200104 for d, s := range i.Data.CustomerBilling {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200105 data.InvoiceeBilling[d] = s
106 }
107
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200108 unit := i.Unit
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200109
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200110 for _, it := range i.Data.Item {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200111 data.Items = append(data.Items, item{
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200112 Title: it.Title,
113 Qty: fmt.Sprintf("%d", it.Count),
114 UnitPrice: fmt.Sprintf(unit+"%.2f", float64(it.UnitPrice)/100),
115 VATRate: fmt.Sprintf("%.2f%%", float64(it.Vat)/1000),
116 TotalNet: fmt.Sprintf(unit+"%.2f", float64(it.TotalNet)/100),
117 Total: fmt.Sprintf(unit+"%.2f", float64(it.Total)/100),
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200118 })
119 }
120
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200121 data.TotalNet = fmt.Sprintf(unit+"%.2f", float64(i.TotalNet)/100)
122 data.VATTotal = fmt.Sprintf(unit+"%.2f", float64(i.Total-i.TotalNet)/100)
123 data.Total = fmt.Sprintf(unit+"%.2f", float64(i.Total)/100)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200124 data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0))
125
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +0200126 if _, ok := invTmpl[language]; !ok {
127 language = defaultLanguage
128 }
129
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200130 var b bytes.Buffer
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +0200131 err := invTmpl[language].Execute(&b, &data)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200132 if err != nil {
133 return []byte{}, err
134 }
135
136 pdfg, err := wkhtml.NewPDFGenerator()
137 if err != nil {
138 return []byte{}, err
139 }
140 pdfg.Dpi.Set(600)
141 pdfg.NoCollate.Set(false)
142 pdfg.PageSize.Set(wkhtml.PageSizeA4)
143
144 pdfg.AddPage(wkhtml.NewPageReader(&b))
145
146 if err := pdfg.Create(); err != nil {
147 return []byte{}, err
148 }
149 return pdfg.Bytes(), nil
150}