package pkg
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"net/http"
"strings"
"time"
)
const (
mimetype = "application/vnd.oasis.opendocument.spreadsheet"
metaDashInfManifestXml = `
`
metaXml = `
Numerus
`
stylesXml = `
`
)
func mustWriteInvoicesOds(invoices []*InvoiceEntry, locale *Locale, company *Company) []byte {
columns := []string{
"Date",
"Invoice Num.",
"Customer",
"Status",
"Tags",
"Amount",
}
return mustWriteTableOds(invoices, columns, locale, func(sb *strings.Builder, invoice *InvoiceEntry) {
writeCellDate(sb, invoice.Date)
writeCellString(sb, invoice.Number)
writeCellString(sb, invoice.CustomerName)
writeCellString(sb, invoice.StatusLabel)
writeCellString(sb, strings.Join(invoice.Tags, ","))
writeCellFloat(sb, invoice.Total, locale, company)
})
}
func mustWriteQuotesOds(quotes []*QuoteEntry, locale *Locale, company *Company) []byte {
columns := []string{
"Date",
"Quotation Num.",
"Customer",
"Status",
"Tags",
"Amount",
}
return mustWriteTableOds(quotes, columns, locale, func(sb *strings.Builder, quote *QuoteEntry) {
writeCellDate(sb, quote.Date)
writeCellString(sb, quote.Number)
writeCellString(sb, quote.CustomerName)
writeCellString(sb, quote.StatusLabel)
writeCellString(sb, strings.Join(quote.Tags, ","))
writeCellFloat(sb, quote.Total, locale, company)
})
}
func mustWriteExpensesOds(expenses []*ExpenseEntry, locale *Locale, company *Company) []byte {
columns := []string{
"Contact",
"Invoice Date",
"Invoice Number",
"Status",
"Tags",
"Amount",
}
return mustWriteTableOds(expenses, columns, locale, func(sb *strings.Builder, expense *ExpenseEntry) {
writeCellString(sb, expense.InvoicerName)
writeCellDate(sb, expense.InvoiceDate)
writeCellString(sb, expense.InvoiceNumber)
writeCellString(sb, expense.StatusLabel)
writeCellString(sb, strings.Join(expense.Tags, ","))
writeCellFloat(sb, expense.Amount, locale, company)
})
}
func mustWriteTableOds[K interface{}](rows []*K, columns []string, locale *Locale, writeRow func(*strings.Builder, *K)) []byte {
var sb strings.Builder
sb.WriteString(`
/
/
`)
sb.WriteString(fmt.Sprintf(" \n", len(columns)))
sb.WriteString(`
`)
for _, t := range columns {
writeCellString(&sb, locale.GetC(t, "title"))
}
sb.WriteString(" \n")
for _, row := range rows {
sb.WriteString(" \n")
writeRow(&sb, row)
sb.WriteString(" \n")
}
sb.WriteString(`
`)
return mustWriteOds(sb.String())
}
func mustWriteOds(content string) []byte {
buf := new(bytes.Buffer)
ods := zip.NewWriter(buf)
mustWriteOdsFile(ods, "mimetype", mimetype, zip.Store)
mustWriteOdsFile(ods, "META-INF/manifest.xml", metaDashInfManifestXml, zip.Deflate)
mustWriteOdsFile(ods, "meta.xml", metaXml, zip.Deflate)
mustWriteOdsFile(ods, "styles.xml", stylesXml, zip.Deflate)
mustWriteOdsFile(ods, "content.xml", content, zip.Deflate)
mustClose(ods)
return buf.Bytes()
}
func mustWriteOdsFile(ods *zip.Writer, name string, content string, method uint16) {
f, err := ods.CreateHeader(&zip.FileHeader{
Name: name,
Method: method,
Modified: time.Now(),
})
if err != nil {
panic(err)
}
if _, err = f.Write([]byte(content)); err != nil {
panic(err)
}
}
func writeCellString(sb *strings.Builder, s string) {
sb.WriteString(` `)
if err := xml.EscapeText(sb, []byte(s)); err != nil {
panic(err)
}
sb.WriteString("\n")
}
func writeCellDate(sb *strings.Builder, t time.Time) {
sb.WriteString(fmt.Sprintf(" %s\n", t.Format("2006-01-02"), t.Format("02/01/06")))
}
func writeCellFloat(sb *strings.Builder, s string, locale *Locale, company *Company) {
sb.WriteString(fmt.Sprintf(" %s\n", s, formatPrice(s, locale.Language, "%.[1]*[2]f", company.DecimalDigits, "")))
}
func writeOdsResponse(w http.ResponseWriter, ods []byte, filename string) {
w.Header().Set("Content-Type", "application/vnd.oasis.opendocument.spreadsheet")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
w.WriteHeader(http.StatusOK)
if _, err := w.Write(ods); err != nil {
panic(err)
}
}