feat: refine OT flow, reports, theming and sidebar UX

This commit is contained in:
Luciano Milani
2026-07-02 22:19:03 +01:00
parent 8231bba3f9
commit 9bf176b385
48 changed files with 3469 additions and 599 deletions
+43 -30
View File
@@ -48,37 +48,53 @@ func Generate(meta DocMeta, items []LineItem, staffTotal float64, outPath string
tr := f.UnicodeTranslatorFromDescriptor("")
t := func(s string) string { return tr(s) }
hasLogo := addLogo(f, meta.CompanyLogo)
headerTop := 15.0
leftX := 15.0
leftW := 120.0
if hasLogo {
leftW = 100.0
rightX := 135.0
rightW := 60.0
// Header (left): logo always reserves its own vertical space.
leftY := headerTop
const logoSize = 24.0
if addLogo(f, meta.CompanyLogo, leftX, leftY, logoSize, logoSize) {
leftY += logoSize + 3
}
// Header
f.SetXY(leftX, leftY)
f.SetFont("Helvetica", "B", 18)
f.CellFormat(leftW, 10, t(meta.CompanyName), "", 0, "L", false, 0, "")
f.SetFont("Helvetica", "B", 14)
f.CellFormat(60, 10, t(meta.DocType), "", 1, "R", false, 0, "")
f.CellFormat(leftW, 10, t(meta.CompanyName), "", 1, "L", false, 0, "")
leftY = f.GetY()
f.SetFont("Helvetica", "", 9)
if meta.CompanyNIF != "" {
f.CellFormat(leftW, 5, t("NIF: ")+meta.CompanyNIF, "", 0, "L", false, 0, "")
} else {
f.CellFormat(leftW, 5, "", "", 0, "L", false, 0, "")
f.SetXY(leftX, leftY)
f.CellFormat(leftW, 5, t("NIF: ")+meta.CompanyNIF, "", 1, "L", false, 0, "")
leftY = f.GetY()
}
f.SetFont("Helvetica", "", 11)
f.CellFormat(60, 5, t(meta.DocNumber), "", 1, "R", false, 0, "")
f.SetFont("Helvetica", "", 9)
if meta.CompanyAddress != "" {
f.SetXY(leftX, leftY)
f.MultiCell(leftW, 5, t(meta.CompanyAddress), "", "L", false)
leftY = f.GetY()
}
f.Ln(3)
curY := f.GetY()
f.SetXY(135, curY-3)
f.CellFormat(60, 5, t("Data: ")+meta.IssuedAt, "", 1, "R", false, 0, "")
f.SetY(curY + 3)
f.Ln(3)
// Header (right): document meta.
f.SetXY(rightX, headerTop)
f.SetFont("Helvetica", "B", 14)
f.CellFormat(rightW, 10, t(meta.DocType), "", 1, "R", false, 0, "")
f.SetFont("Helvetica", "", 11)
f.SetXY(rightX, headerTop+15)
f.CellFormat(rightW, 6, t(meta.DocNumber), "", 1, "R", false, 0, "")
f.SetXY(rightX, headerTop+26)
f.CellFormat(rightW, 6, t("Data: ")+meta.IssuedAt, "", 1, "R", false, 0, "")
// Continue after whichever side ended lower.
rightBottom := headerTop + 32
if leftY < rightBottom {
leftY = rightBottom
}
f.SetY(leftY + 4)
// Client block
if meta.ClientName != "" {
@@ -148,7 +164,7 @@ func Generate(meta DocMeta, items []LineItem, staffTotal float64, outPath string
return f.OutputFileAndClose(outPath)
}
func addLogo(f *fpdf.Fpdf, logo string) bool {
func addLogo(f *fpdf.Fpdf, logo string, x, y, w, h float64) bool {
logo = strings.TrimSpace(logo)
if logo == "" {
return false
@@ -172,10 +188,9 @@ func addLogo(f *fpdf.Fpdf, logo string) bool {
if strings.Contains(meta, "image/jpeg") || strings.Contains(meta, "image/jpg") {
imgType = "JPG"
}
opts := fpdf.ImageOptions{ImageType: imgType, ReadDpi: true}
opts := fpdf.ImageOptions{ImageType: imgType, ReadDpi: false}
f.RegisterImageOptionsReader("company_logo", opts, bytes.NewReader(raw))
f.ImageOptions("company_logo", 15, 14, 26, 0, false, opts, 0, "")
f.SetX(45)
f.ImageOptions("company_logo", x, y, w, h, false, opts, 0, "")
return true
}
@@ -198,17 +213,15 @@ func addLogo(f *fpdf.Fpdf, logo string) bool {
if strings.Contains(ct, "jpeg") || strings.Contains(ct, "jpg") {
imgType = "JPG"
}
opts := fpdf.ImageOptions{ImageType: imgType, ReadDpi: true}
opts := fpdf.ImageOptions{ImageType: imgType, ReadDpi: false}
f.RegisterImageOptionsReader("company_logo", opts, bytes.NewReader(buf.Bytes()))
f.ImageOptions("company_logo", 15, 14, 26, 0, false, opts, 0, "")
f.SetX(45)
f.ImageOptions("company_logo", x, y, w, h, false, opts, 0, "")
return true
}
if _, err := os.Stat(logo); err == nil {
opts := fpdf.ImageOptions{ReadDpi: true}
f.ImageOptions(logo, 15, 14, 26, 0, false, opts, 0, "")
f.SetX(45)
opts := fpdf.ImageOptions{ReadDpi: false}
f.ImageOptions(logo, x, y, w, h, false, opts, 0, "")
return true
}