Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "fmt" |
| 6 | "html/template" |
Serge Bazanski | 772a133 | 2021-02-17 20:28:51 +0100 | [diff] [blame^] | 7 | "strings" |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 8 | "time" |
| 9 | |
| 10 | wkhtml "github.com/sebastiaanklippert/go-wkhtmltopdf" |
| 11 | |
Sergiusz Bazanski | 1446e98 | 2019-07-21 16:04:23 +0200 | [diff] [blame] | 12 | pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto" |
Sergiusz Bazanski | cea71e3 | 2019-07-21 15:30:08 +0200 | [diff] [blame] | 13 | "code.hackerspace.pl/hscloud/bgpwtf/invoice/templates" |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 14 | ) |
| 15 | |
| 16 | var ( |
Sergiusz Bazanski | a818ef2 | 2019-06-07 10:37:22 +0200 | [diff] [blame] | 17 | invTmpl map[string]*template.Template |
| 18 | |
| 19 | languages = []string{"en", "pl"} |
| 20 | defaultLanguage = "en" |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 21 | ) |
| 22 | |
| 23 | func init() { |
Sergiusz Bazanski | a818ef2 | 2019-06-07 10:37:22 +0200 | [diff] [blame] | 24 | 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 Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 32 | } |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 33 | } |
| 34 | |
Sergiusz Bazanski | a818ef2 | 2019-06-07 10:37:22 +0200 | [diff] [blame] | 35 | func renderInvoicePDF(i *pb.Invoice, language string) ([]byte, error) { |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 36 | type item struct { |
| 37 | Title string |
| 38 | UnitPrice string |
| 39 | Qty string |
| 40 | VATRate string |
| 41 | TotalNet string |
| 42 | Total string |
| 43 | } |
| 44 | |
Serge Bazanski | 772a133 | 2021-02-17 20:28:51 +0100 | [diff] [blame^] | 45 | 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 Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 59 | 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 Bazanski | 772a133 | 2021-02-17 20:28:51 +0100 | [diff] [blame^] | 78 | Symbols template.HTML |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 79 | }{ |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 80 | 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 Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 91 | |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 92 | InvoicerBilling: make([]string, len(i.Data.InvoicerBilling)), |
| 93 | InvoiceeBilling: make([]string, len(i.Data.CustomerBilling)), |
Serge Bazanski | 772a133 | 2021-02-17 20:28:51 +0100 | [diff] [blame^] | 94 | Symbols: template.HTML(symbols), |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 95 | } |
| 96 | |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 97 | for d, s := range i.Data.InvoicerBilling { |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 98 | data.InvoicerBilling[d] = s |
| 99 | } |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 100 | for d, s := range i.Data.CustomerBilling { |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 101 | data.InvoiceeBilling[d] = s |
| 102 | } |
| 103 | |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 104 | unit := i.Unit |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 105 | |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 106 | for _, it := range i.Data.Item { |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 107 | data.Items = append(data.Items, item{ |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 108 | 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 Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 114 | }) |
| 115 | } |
| 116 | |
Sergiusz Bazanski | 3976e3c | 2019-05-01 15:27:49 +0200 | [diff] [blame] | 117 | 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 Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 120 | data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0)) |
| 121 | |
Sergiusz Bazanski | a818ef2 | 2019-06-07 10:37:22 +0200 | [diff] [blame] | 122 | if _, ok := invTmpl[language]; !ok { |
| 123 | language = defaultLanguage |
| 124 | } |
| 125 | |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 126 | var b bytes.Buffer |
Sergiusz Bazanski | a818ef2 | 2019-06-07 10:37:22 +0200 | [diff] [blame] | 127 | err := invTmpl[language].Execute(&b, &data) |
Sergiusz Bazanski | fb18c99 | 2019-05-01 12:27:03 +0200 | [diff] [blame] | 128 | 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 | } |