blob: c0eeca11c9cef642bafa35db3251804242305eeb [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
10 wkhtml "github.com/sebastiaanklippert/go-wkhtmltopdf"
11
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 {
56 symbols = "<i>brak</i>."
57 }
58
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020059 data := struct {
60 InvoiceNumber string
61 InvoicerBilling []string
62 InvoicerVAT string
63 InvoicerCompanyNumber string
64 InvoiceeBilling []string
65 InvoiceeVAT string
66 Date time.Time
67 DueDate time.Time
68 IBAN string
69 SWIFT string
70 Proforma bool
71 ReverseVAT bool
72 USCustomer bool
73 Items []item
74 TotalNet string
75 VATTotal string
76 Total string
77 DeliveryCharge string
Serge Bazanski772a1332021-02-17 20:28:51 +010078 Symbols template.HTML
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020079 }{
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020080 InvoiceNumber: i.FinalUid,
81 Date: time.Unix(0, i.Date),
82 DueDate: time.Unix(0, i.DueDate),
83 IBAN: i.Data.Iban,
84 SWIFT: i.Data.Swift,
85 InvoicerVAT: i.Data.InvoicerVatId,
86 InvoicerCompanyNumber: i.Data.InvoicerCompanyNumber,
87 InvoiceeVAT: i.Data.CustomerVatId,
88 Proforma: i.State == pb.Invoice_STATE_PROFORMA,
89 ReverseVAT: i.Data.ReverseVat,
90 USCustomer: i.Data.UsCustomer,
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020091
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020092 InvoicerBilling: make([]string, len(i.Data.InvoicerBilling)),
93 InvoiceeBilling: make([]string, len(i.Data.CustomerBilling)),
Serge Bazanski772a1332021-02-17 20:28:51 +010094 Symbols: template.HTML(symbols),
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020095 }
96
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020097 for d, s := range i.Data.InvoicerBilling {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020098 data.InvoicerBilling[d] = s
99 }
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200100 for d, s := range i.Data.CustomerBilling {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200101 data.InvoiceeBilling[d] = s
102 }
103
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200104 unit := i.Unit
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200105
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200106 for _, it := range i.Data.Item {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200107 data.Items = append(data.Items, item{
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200108 Title: it.Title,
109 Qty: fmt.Sprintf("%d", it.Count),
110 UnitPrice: fmt.Sprintf(unit+"%.2f", float64(it.UnitPrice)/100),
111 VATRate: fmt.Sprintf("%.2f%%", float64(it.Vat)/1000),
112 TotalNet: fmt.Sprintf(unit+"%.2f", float64(it.TotalNet)/100),
113 Total: fmt.Sprintf(unit+"%.2f", float64(it.Total)/100),
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200114 })
115 }
116
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +0200117 data.TotalNet = fmt.Sprintf(unit+"%.2f", float64(i.TotalNet)/100)
118 data.VATTotal = fmt.Sprintf(unit+"%.2f", float64(i.Total-i.TotalNet)/100)
119 data.Total = fmt.Sprintf(unit+"%.2f", float64(i.Total)/100)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200120 data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0))
121
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +0200122 if _, ok := invTmpl[language]; !ok {
123 language = defaultLanguage
124 }
125
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200126 var b bytes.Buffer
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +0200127 err := invTmpl[language].Execute(&b, &data)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200128 if err != nil {
129 return []byte{}, err
130 }
131
132 pdfg, err := wkhtml.NewPDFGenerator()
133 if err != nil {
134 return []byte{}, err
135 }
136 pdfg.Dpi.Set(600)
137 pdfg.NoCollate.Set(false)
138 pdfg.PageSize.Set(wkhtml.PageSizeA4)
139
140 pdfg.AddPage(wkhtml.NewPageReader(&b))
141
142 if err := pdfg.Create(); err != nil {
143 return []byte{}, err
144 }
145 return pdfg.Bytes(), nil
146}