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" |
| 7 | "time" |
| 8 | |
| 9 | wkhtml "github.com/sebastiaanklippert/go-wkhtmltopdf" |
| 10 | |
| 11 | "code.hackerspace.pl/hscloud/go/svc/invoice/templates" |
| 12 | pb "code.hackerspace.pl/hscloud/proto/invoice" |
| 13 | ) |
| 14 | |
| 15 | var ( |
| 16 | invTmpl *template.Template |
| 17 | ) |
| 18 | |
| 19 | func init() { |
| 20 | a, err := templates.Asset("invoice.html") |
| 21 | if err != nil { |
| 22 | panic(err) |
| 23 | } |
| 24 | invTmpl = template.Must(template.New("invoice.html").Parse(string(a))) |
| 25 | } |
| 26 | |
| 27 | func renderInvoicePDF(i *pb.Invoice, number string, proforma bool) ([]byte, error) { |
| 28 | now := time.Now() |
| 29 | |
| 30 | type item struct { |
| 31 | Title string |
| 32 | UnitPrice string |
| 33 | Qty string |
| 34 | VATRate string |
| 35 | TotalNet string |
| 36 | Total string |
| 37 | } |
| 38 | |
| 39 | data := struct { |
| 40 | InvoiceNumber string |
| 41 | InvoicerBilling []string |
| 42 | InvoicerVAT string |
| 43 | InvoicerCompanyNumber string |
| 44 | InvoiceeBilling []string |
| 45 | InvoiceeVAT string |
| 46 | Date time.Time |
| 47 | DueDate time.Time |
| 48 | IBAN string |
| 49 | SWIFT string |
| 50 | Proforma bool |
| 51 | ReverseVAT bool |
| 52 | USCustomer bool |
| 53 | Items []item |
| 54 | TotalNet string |
| 55 | VATTotal string |
| 56 | Total string |
| 57 | DeliveryCharge string |
| 58 | }{ |
| 59 | InvoiceNumber: number, |
| 60 | Date: now, |
| 61 | DueDate: now.AddDate(0, 0, int(i.DaysDue)), |
| 62 | IBAN: i.Iban, |
| 63 | SWIFT: i.Swift, |
| 64 | InvoicerVAT: i.InvoicerVatId, |
| 65 | InvoicerCompanyNumber: i.InvoicerCompanyNumber, |
| 66 | InvoiceeVAT: i.CustomerVatId, |
| 67 | Proforma: proforma, |
| 68 | ReverseVAT: i.ReverseVat, |
| 69 | USCustomer: i.UsCustomer, |
| 70 | |
| 71 | InvoicerBilling: make([]string, len(i.InvoicerBilling)), |
| 72 | InvoiceeBilling: make([]string, len(i.CustomerBilling)), |
| 73 | } |
| 74 | |
| 75 | unit := "€" |
| 76 | |
| 77 | for d, s := range i.InvoicerBilling { |
| 78 | data.InvoicerBilling[d] = s |
| 79 | } |
| 80 | for d, s := range i.CustomerBilling { |
| 81 | data.InvoiceeBilling[d] = s |
| 82 | } |
| 83 | |
| 84 | totalNet := 0 |
| 85 | total := 0 |
| 86 | for _, i := range i.Item { |
| 87 | rowTotalNet := int(i.UnitPrice * i.Count) |
| 88 | rowTotal := int(float64(rowTotalNet) * (float64(1) + float64(i.Vat)/100000)) |
| 89 | |
| 90 | totalNet += rowTotalNet |
| 91 | total += rowTotal |
| 92 | data.Items = append(data.Items, item{ |
| 93 | Title: i.Title, |
| 94 | Qty: fmt.Sprintf("%d", i.Count), |
| 95 | UnitPrice: fmt.Sprintf(unit+"%.2f", float64(i.UnitPrice)/100), |
| 96 | VATRate: fmt.Sprintf("%.2f%%", float64(i.Vat)/1000), |
| 97 | TotalNet: fmt.Sprintf(unit+"%.2f", float64(rowTotalNet)/100), |
| 98 | Total: fmt.Sprintf(unit+"%.2f", float64(rowTotal)/100), |
| 99 | }) |
| 100 | } |
| 101 | |
| 102 | data.TotalNet = fmt.Sprintf(unit+"%.2f", float64(totalNet)/100) |
| 103 | data.VATTotal = fmt.Sprintf(unit+"%.2f", float64(total-totalNet)/100) |
| 104 | data.Total = fmt.Sprintf(unit+"%.2f", float64(total)/100) |
| 105 | data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0)) |
| 106 | |
| 107 | var b bytes.Buffer |
| 108 | err := invTmpl.Execute(&b, &data) |
| 109 | if err != nil { |
| 110 | return []byte{}, err |
| 111 | } |
| 112 | |
| 113 | pdfg, err := wkhtml.NewPDFGenerator() |
| 114 | if err != nil { |
| 115 | return []byte{}, err |
| 116 | } |
| 117 | pdfg.Dpi.Set(600) |
| 118 | pdfg.NoCollate.Set(false) |
| 119 | pdfg.PageSize.Set(wkhtml.PageSizeA4) |
| 120 | |
| 121 | pdfg.AddPage(wkhtml.NewPageReader(&b)) |
| 122 | |
| 123 | if err := pdfg.Create(); err != nil { |
| 124 | return []byte{}, err |
| 125 | } |
| 126 | return pdfg.Bytes(), nil |
| 127 | } |