Merge branch 'fix/marketing-report-pdf' into 'development'

[FIX][BE] Marketing Report PDF

See merge request mbugroup/lti-api!510
This commit is contained in:
Rivaldi A N S
2026-05-06 06:14:45 +00:00
@@ -55,19 +55,19 @@ type pdfColumn struct {
var marketingPdfColumns = []pdfColumn{ var marketingPdfColumns = []pdfColumn{
{"No", 6, "C"}, {"No", 6, "C"},
{"Tanggal Sales Order", 16, "C"}, {"Tanggal\nJual", 16, "C"},
{"Tanggal Delivery Order", 16, "C"}, {"Tanggal\nRealisasi", 16, "C"},
{"Aging\n(Hari)", 9, "C"}, {"Aging\n(Hari)", 9, "C"},
{"Gudang Fisik", 20, "L"}, {"Gudang\nFisik", 20, "L"},
{"Pelanggan", 20, "L"}, {"Pelanggan", 20, "L"},
{"No. DO", 18, "L"},
{"Sales", 18, "L"}, {"Sales", 18, "L"},
{"Produk", 16, "L"}, {"No. Polisi", 18, "L"},
{"Nomor DO", 14, "C"},
{"Nomor Polisi", 14, "C"},
{"Tipe\nMarketing", 14, "C"}, {"Tipe\nMarketing", 14, "C"},
{"Quantity", 13, "R"}, {"Produk", 16, "L"},
{"Rata-Rata\n(Kg)", 13, "R"}, {"Kuantitas", 13, "R"},
{"Total Berat\n(Kg)", 14, "R"}, {"Bobot Rata-Rata\n(Kg)", 13, "R"},
{"Bobot Total Berat\n(Kg)", 14, "R"},
{"Harga Jual\n(Rp)", 17, "R"}, {"Harga Jual\n(Rp)", 17, "R"},
{"HPP\n(Rp)", 17, "R"}, {"HPP\n(Rp)", 17, "R"},
{"Total Jual\n(Rp)", 18, "R"}, {"Total Jual\n(Rp)", 18, "R"},
@@ -79,14 +79,14 @@ var marketingPdfColumns = []pdfColumn{
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const ( const (
headerR, headerG, headerB = 30, 64, 120 // dark blue header bg headerR, headerG, headerB = 30, 64, 120 // dark blue header bg
headerTextR, headerTextG, headerTextB = 255, 255, 255 // white header text headerTextR, headerTextG, headerTextB = 255, 255, 255 // white header text
rowAltR, rowAltG, rowAltB = 245, 247, 250 // alternating row bg rowAltR, rowAltG, rowAltB = 245, 247, 250 // alternating row bg
borderR, borderG, borderB = 200, 200, 200 // light border borderR, borderG, borderB = 200, 200, 200 // light border
badgeTelurR, badgeTelurG, badgeTelurB = 59, 130, 246 // blue badgeTelurR, badgeTelurG, badgeTelurB = 59, 130, 246 // blue
badgeAyamR, badgeAyamG, badgeAyamB = 34, 197, 94 // green badgeAyamR, badgeAyamG, badgeAyamB = 34, 197, 94 // green
badgeTradingR, badgeTradingG, badgeTradingB = 249, 115, 22 // orange badgeTradingR, badgeTradingG, badgeTradingB = 249, 115, 22 // orange
badgeDefaultR, badgeDefaultG, badgeDefaultB = 107, 114, 128 // gray badgeDefaultR, badgeDefaultG, badgeDefaultB = 107, 114, 128 // gray
) )
@@ -184,50 +184,76 @@ func writeMarketingPdfRows(pdf *fpdf.Fpdf, items []dto.RepportMarketingItemDTO)
pdf.SetDrawColor(borderR, borderG, borderB) pdf.SetDrawColor(borderR, borderG, borderB)
pdf.SetLineWidth(0.1) pdf.SetLineWidth(0.1)
rowH := 6.0 lineH := 5.0
for idx, item := range items { for idx, item := range items {
// page break check values := marketingPdfRowValues(idx+1, item)
rowH := calcMarketingRowHeight(pdf, values, lineH)
if pdf.GetY()+rowH > marketingPdfPageHeight(pdf)-12 { if pdf.GetY()+rowH > marketingPdfPageHeight(pdf)-12 {
pdf.AddPage() pdf.AddPage()
writeMarketingPdfHeader(pdf) writeMarketingPdfHeader(pdf)
pdf.SetFont("Helvetica", "", 6) pdf.SetFont("Helvetica", "", 6)
} }
// alternating bg var fillR, fillG, fillB int
if idx%2 == 1 { if idx%2 == 1 {
pdf.SetFillColor(rowAltR, rowAltG, rowAltB) fillR, fillG, fillB = rowAltR, rowAltG, rowAltB
} else { } else {
pdf.SetFillColor(255, 255, 255) fillR, fillG, fillB = 255, 255, 255
} }
pdf.SetTextColor(40, 40, 40) pdf.SetTextColor(40, 40, 40)
y := pdf.GetY() y := pdf.GetY()
writeMarketingPdfRow(pdf, idx+1, item, rowH, y) writeMarketingPdfRow(pdf, item, values, lineH, rowH, y, fillR, fillG, fillB)
} }
} }
func writeMarketingPdfRow(pdf *fpdf.Fpdf, no int, item dto.RepportMarketingItemDTO, h, y float64) { func calcMarketingRowHeight(pdf *fpdf.Fpdf, values []string, lineH float64) float64 {
fill := true // use the fill colour already set margin := pdf.GetCellMargin()
cols := marketingPdfColumns cols := marketingPdfColumns
x := 10.0 // left margin maxLines := 1
for i, col := range cols {
if i >= len(values) || i == 10 {
continue
}
usableW := col.width - 2*margin
if usableW <= 0 {
continue
}
lines := pdf.SplitLines([]byte(values[i]), usableW)
n := len(lines)
if n == 0 {
n = 1
}
if n > maxLines {
maxLines = n
}
}
return float64(maxLines) * lineH
}
values := marketingPdfRowValues(no, item) func writeMarketingPdfRow(pdf *fpdf.Fpdf, item dto.RepportMarketingItemDTO, values []string, lineH, rowH, y float64, fillR, fillG, fillB int) {
cols := marketingPdfColumns
x := 10.0
for i, col := range cols { for i, col := range cols {
pdf.SetXY(x, y) if i == 10 {
drawMarketingTypeBadge(pdf, x, y, col.width, rowH, item.MarketingType)
if i == 10 { // Tipe Marketing → badge pdf.SetDrawColor(borderR, borderG, borderB)
drawMarketingTypeBadge(pdf, x, y, col.width, h, item.MarketingType) pdf.SetTextColor(40, 40, 40)
} else { } else {
pdf.CellFormat(col.width, h, values[i], "1", 0, col.align, fill, 0, "") pdf.SetFillColor(fillR, fillG, fillB)
pdf.SetDrawColor(borderR, borderG, borderB)
pdf.Rect(x, y, col.width, rowH, "FD")
pdf.SetTextColor(40, 40, 40)
pdf.SetXY(x, y)
pdf.MultiCell(col.width, lineH, values[i], "", col.align, false)
} }
x += col.width x += col.width
} }
pdf.SetXY(10, y+h) pdf.SetXY(10, y+rowH)
} }
func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string { func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
@@ -255,11 +281,11 @@ func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
strconv.Itoa(item.AgingDays), strconv.Itoa(item.AgingDays),
warehouse, warehouse,
customer, customer,
sales,
product,
safeMarketingExportText(item.DoNumber), safeMarketingExportText(item.DoNumber),
sales,
safeMarketingExportText(item.VehicleNumber), safeMarketingExportText(item.VehicleNumber),
safeMarketingExportText(item.MarketingType), // index 10, overridden by badge safeMarketingExportText(item.MarketingType), // index 10, overridden by badge
product,
formatMarketingPdfNumber(item.Qty), formatMarketingPdfNumber(item.Qty),
formatMarketingPdfDecimal(item.AverageWeightKg), formatMarketingPdfDecimal(item.AverageWeightKg),
formatMarketingPdfDecimal(item.TotalWeightKg), formatMarketingPdfDecimal(item.TotalWeightKg),