2019-05-01 10:27:03 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"html/template"
|
2021-02-17 19:28:51 +00:00
|
|
|
"strings"
|
2019-05-01 10:27:03 +00:00
|
|
|
"time"
|
|
|
|
|
2023-07-28 17:14:50 +00:00
|
|
|
wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
|
2019-05-01 10:27:03 +00:00
|
|
|
|
2019-07-21 14:04:23 +00:00
|
|
|
pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto"
|
2019-07-21 13:30:08 +00:00
|
|
|
"code.hackerspace.pl/hscloud/bgpwtf/invoice/templates"
|
2019-05-01 10:27:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2019-06-07 08:37:22 +00:00
|
|
|
invTmpl map[string]*template.Template
|
|
|
|
|
|
|
|
languages = []string{"en", "pl"}
|
|
|
|
defaultLanguage = "en"
|
2019-05-01 10:27:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2019-06-07 08:37:22 +00:00
|
|
|
invTmpl = make(map[string]*template.Template)
|
|
|
|
for _, language := range languages {
|
|
|
|
filename := fmt.Sprintf("invoice_%s.html", language)
|
|
|
|
a, err := templates.Asset(filename)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
invTmpl[language] = template.Must(template.New(filename).Parse(string(a)))
|
2019-05-01 10:27:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 08:37:22 +00:00
|
|
|
func renderInvoicePDF(i *pb.Invoice, language string) ([]byte, error) {
|
2019-05-01 10:27:03 +00:00
|
|
|
type item struct {
|
|
|
|
Title string
|
|
|
|
UnitPrice string
|
|
|
|
Qty string
|
|
|
|
VATRate string
|
|
|
|
TotalNet string
|
|
|
|
Total string
|
|
|
|
}
|
|
|
|
|
2021-02-17 19:28:51 +00:00
|
|
|
symbols := ""
|
|
|
|
var parts []string
|
|
|
|
for _, code := range i.Data.SpCode {
|
|
|
|
parts = append(parts, code.String())
|
|
|
|
}
|
|
|
|
for _, code := range i.GtuCode {
|
|
|
|
parts = append(parts, code.String())
|
|
|
|
}
|
|
|
|
if len(parts) > 0 {
|
|
|
|
symbols = strings.Join(parts, ", ") + "."
|
|
|
|
} else {
|
2021-05-12 21:05:53 +00:00
|
|
|
if language == "en" {
|
|
|
|
symbols = "<i>brak (none)</i>."
|
|
|
|
} else {
|
|
|
|
symbols = "<i>brak</i>."
|
|
|
|
}
|
2021-02-17 19:28:51 +00:00
|
|
|
}
|
|
|
|
|
2019-05-01 10:27:03 +00:00
|
|
|
data := struct {
|
|
|
|
InvoiceNumber string
|
|
|
|
InvoicerBilling []string
|
|
|
|
InvoicerVAT string
|
|
|
|
InvoicerCompanyNumber string
|
|
|
|
InvoiceeBilling []string
|
|
|
|
InvoiceeVAT string
|
|
|
|
Date time.Time
|
|
|
|
DueDate time.Time
|
|
|
|
IBAN string
|
|
|
|
SWIFT string
|
|
|
|
Proforma bool
|
|
|
|
ReverseVAT bool
|
|
|
|
USCustomer bool
|
|
|
|
Items []item
|
|
|
|
TotalNet string
|
|
|
|
VATTotal string
|
|
|
|
Total string
|
|
|
|
DeliveryCharge string
|
2021-02-17 19:28:51 +00:00
|
|
|
Symbols template.HTML
|
2019-05-01 10:27:03 +00:00
|
|
|
}{
|
2019-05-01 13:27:49 +00:00
|
|
|
InvoiceNumber: i.FinalUid,
|
|
|
|
Date: time.Unix(0, i.Date),
|
|
|
|
DueDate: time.Unix(0, i.DueDate),
|
|
|
|
IBAN: i.Data.Iban,
|
|
|
|
SWIFT: i.Data.Swift,
|
|
|
|
InvoicerVAT: i.Data.InvoicerVatId,
|
|
|
|
InvoicerCompanyNumber: i.Data.InvoicerCompanyNumber,
|
|
|
|
InvoiceeVAT: i.Data.CustomerVatId,
|
|
|
|
Proforma: i.State == pb.Invoice_STATE_PROFORMA,
|
|
|
|
ReverseVAT: i.Data.ReverseVat,
|
|
|
|
USCustomer: i.Data.UsCustomer,
|
|
|
|
|
|
|
|
InvoicerBilling: make([]string, len(i.Data.InvoicerBilling)),
|
|
|
|
InvoiceeBilling: make([]string, len(i.Data.CustomerBilling)),
|
2021-02-17 19:28:51 +00:00
|
|
|
Symbols: template.HTML(symbols),
|
2019-05-01 10:27:03 +00:00
|
|
|
}
|
|
|
|
|
2019-05-01 13:27:49 +00:00
|
|
|
for d, s := range i.Data.InvoicerBilling {
|
2019-05-01 10:27:03 +00:00
|
|
|
data.InvoicerBilling[d] = s
|
|
|
|
}
|
2019-05-01 13:27:49 +00:00
|
|
|
for d, s := range i.Data.CustomerBilling {
|
2019-05-01 10:27:03 +00:00
|
|
|
data.InvoiceeBilling[d] = s
|
|
|
|
}
|
|
|
|
|
2019-05-01 13:27:49 +00:00
|
|
|
unit := i.Unit
|
2019-05-01 10:27:03 +00:00
|
|
|
|
2019-05-01 13:27:49 +00:00
|
|
|
for _, it := range i.Data.Item {
|
2019-05-01 10:27:03 +00:00
|
|
|
data.Items = append(data.Items, item{
|
2019-05-01 13:27:49 +00:00
|
|
|
Title: it.Title,
|
|
|
|
Qty: fmt.Sprintf("%d", it.Count),
|
|
|
|
UnitPrice: fmt.Sprintf(unit+"%.2f", float64(it.UnitPrice)/100),
|
|
|
|
VATRate: fmt.Sprintf("%.2f%%", float64(it.Vat)/1000),
|
|
|
|
TotalNet: fmt.Sprintf(unit+"%.2f", float64(it.TotalNet)/100),
|
|
|
|
Total: fmt.Sprintf(unit+"%.2f", float64(it.Total)/100),
|
2019-05-01 10:27:03 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-05-01 13:27:49 +00:00
|
|
|
data.TotalNet = fmt.Sprintf(unit+"%.2f", float64(i.TotalNet)/100)
|
|
|
|
data.VATTotal = fmt.Sprintf(unit+"%.2f", float64(i.Total-i.TotalNet)/100)
|
|
|
|
data.Total = fmt.Sprintf(unit+"%.2f", float64(i.Total)/100)
|
2019-05-01 10:27:03 +00:00
|
|
|
data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0))
|
|
|
|
|
2019-06-07 08:37:22 +00:00
|
|
|
if _, ok := invTmpl[language]; !ok {
|
|
|
|
language = defaultLanguage
|
|
|
|
}
|
|
|
|
|
2019-05-01 10:27:03 +00:00
|
|
|
var b bytes.Buffer
|
2019-06-07 08:37:22 +00:00
|
|
|
err := invTmpl[language].Execute(&b, &data)
|
2019-05-01 10:27:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pdfg, err := wkhtml.NewPDFGenerator()
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
pdfg.Dpi.Set(600)
|
|
|
|
pdfg.NoCollate.Set(false)
|
|
|
|
pdfg.PageSize.Set(wkhtml.PageSizeA4)
|
|
|
|
|
|
|
|
pdfg.AddPage(wkhtml.NewPageReader(&b))
|
|
|
|
|
|
|
|
if err := pdfg.Create(); err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
return pdfg.Bytes(), nil
|
|
|
|
}
|