mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
fix: adjust exported file column order and copywriting
This commit is contained in:
@@ -50,6 +50,14 @@ func buildMarketingReportWorkbook(items []dto.RepportMarketingItemDTO) ([]byte,
|
||||
if err := setMarketingReportRows(file, items); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := file.SetPanes(marketingReportExportSheetName, &excelize.Panes{
|
||||
Freeze: true,
|
||||
YSplit: 1,
|
||||
TopLeftCell: "A2",
|
||||
ActivePane: "bottomLeft",
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buffer, err := file.WriteToBuffer()
|
||||
if err != nil {
|
||||
@@ -88,6 +96,10 @@ func setMarketingReportColumns(file *excelize.File) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := file.SetRowHeight(sheet, 1, 24); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -110,7 +122,6 @@ func setMarketingReportHeaders(file *excelize.File) error {
|
||||
"Bobot Total (Kg)",
|
||||
"Harga Jual (Rp)",
|
||||
"HPP (Rp)",
|
||||
"HPP Amount (Rp)",
|
||||
"Total (Rp)",
|
||||
}
|
||||
|
||||
@@ -124,7 +135,22 @@ func setMarketingReportHeaders(file *excelize.File) error {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
headerStyle, err := file.NewStyle(&excelize.Style{
|
||||
Font: &excelize.Font{Bold: true, Color: "1F2937"},
|
||||
Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"DCEBFA"}},
|
||||
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
|
||||
Border: []excelize.Border{
|
||||
{Type: "left", Color: "D1D5DB", Style: 1},
|
||||
{Type: "top", Color: "D1D5DB", Style: 1},
|
||||
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
||||
{Type: "right", Color: "D1D5DB", Style: 1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return file.SetCellStyle(sheet, "A1", "Q1", headerStyle)
|
||||
}
|
||||
|
||||
func setMarketingReportRows(file *excelize.File, items []dto.RepportMarketingItemDTO) error {
|
||||
@@ -173,7 +199,6 @@ func setMarketingReportRows(file *excelize.File, items []dto.RepportMarketingIte
|
||||
item.TotalWeightKg,
|
||||
formatMarketingRupiah(item.SalesPricePerKg),
|
||||
formatMarketingRupiah(item.HppPricePerKg),
|
||||
formatMarketingRupiah(item.HppAmount),
|
||||
formatMarketingRupiah(item.SalesAmount),
|
||||
}
|
||||
|
||||
@@ -210,15 +235,81 @@ func setMarketingReportRows(file *excelize.File, items []dto.RepportMarketingIte
|
||||
if err := file.SetCellValue(sheet, "P"+totalRow, formatMarketingRupiah(summary.TotalHppPricePerKg)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellValue(sheet, "Q"+totalRow, formatMarketingRupiah(float64(summary.TotalHppAmount))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellValue(sheet, "R"+totalRow, formatMarketingRupiah(float64(summary.TotalSalesAmount))); err != nil {
|
||||
if err := file.SetCellValue(sheet, "Q"+totalRow, formatMarketingRupiah(float64(summary.TotalSalesAmount))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
if len(items) > 0 {
|
||||
lastDataRow := strconv.Itoa(len(items) + 1)
|
||||
|
||||
dataStyle, err := file.NewStyle(&excelize.Style{
|
||||
Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true},
|
||||
Border: []excelize.Border{
|
||||
{Type: "left", Color: "D1D5DB", Style: 1},
|
||||
{Type: "top", Color: "D1D5DB", Style: 1},
|
||||
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
||||
{Type: "right", Color: "D1D5DB", Style: 1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellStyle(sheet, "A2", "Q"+lastDataRow, dataStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
numericStyle, err := file.NewStyle(&excelize.Style{
|
||||
Alignment: &excelize.Alignment{Horizontal: "right", Vertical: "center"},
|
||||
Border: []excelize.Border{
|
||||
{Type: "left", Color: "D1D5DB", Style: 1},
|
||||
{Type: "top", Color: "D1D5DB", Style: 1},
|
||||
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
||||
{Type: "right", Color: "D1D5DB", Style: 1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellStyle(sheet, "L2", "Q"+lastDataRow, numericStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
totalTextStyle, err := file.NewStyle(&excelize.Style{
|
||||
Font: &excelize.Font{Bold: true, Color: "1F2937"},
|
||||
Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"F3F4F6"}},
|
||||
Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center"},
|
||||
Border: []excelize.Border{
|
||||
{Type: "left", Color: "D1D5DB", Style: 1},
|
||||
{Type: "top", Color: "D1D5DB", Style: 1},
|
||||
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
||||
{Type: "right", Color: "D1D5DB", Style: 1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellStyle(sheet, "A"+totalRow, "Q"+totalRow, totalTextStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
totalNumericStyle, err := file.NewStyle(&excelize.Style{
|
||||
Font: &excelize.Font{Bold: true, Color: "1F2937"},
|
||||
Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"F3F4F6"}},
|
||||
Alignment: &excelize.Alignment{Horizontal: "right", Vertical: "center"},
|
||||
Border: []excelize.Border{
|
||||
{Type: "left", Color: "D1D5DB", Style: 1},
|
||||
{Type: "top", Color: "D1D5DB", Style: 1},
|
||||
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
||||
{Type: "right", Color: "D1D5DB", Style: 1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return file.SetCellStyle(sheet, "L"+totalRow, "Q"+totalRow, totalNumericStyle)
|
||||
}
|
||||
|
||||
func formatMarketingDate(t time.Time) string {
|
||||
|
||||
@@ -56,22 +56,21 @@ type pdfColumn struct {
|
||||
var marketingPdfColumns = []pdfColumn{
|
||||
{"No", 6, "C"},
|
||||
{"Tanggal\nJual", 16, "C"},
|
||||
{"Tanggal\nRealisasi", 16, "C"},
|
||||
{"Tanggal\nRealisasi", 20, "C"},
|
||||
{"Aging\n(Hari)", 9, "C"},
|
||||
{"Gudang\nFisik", 20, "L"},
|
||||
{"Pelanggan", 20, "L"},
|
||||
{"No. DO", 18, "L"},
|
||||
{"Sales", 18, "L"},
|
||||
{"No. Polisi", 18, "L"},
|
||||
{"Tipe\nMarketing", 14, "C"},
|
||||
{"Tipe\nMarketing", 16, "C"},
|
||||
{"Produk", 16, "L"},
|
||||
{"Kuantitas", 13, "R"},
|
||||
{"Bobot Rata-Rata\n(Kg)", 13, "R"},
|
||||
{"Bobot Total Berat\n(Kg)", 14, "R"},
|
||||
{"Bobot\nRata-Rata (Kg)", 18, "R"},
|
||||
{"Bobot\nTotal Berat (Kg)", 18, "R"},
|
||||
{"Harga Jual\n(Rp)", 17, "R"},
|
||||
{"HPP\n(Rp)", 17, "R"},
|
||||
{"Total Jual\n(Rp)", 18, "R"},
|
||||
{"Total HPP\n(Rp)", 18, "R"},
|
||||
{"Total (Rp)", 18, "R"},
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -214,7 +213,7 @@ func calcMarketingRowHeight(pdf *fpdf.Fpdf, values []string, lineH float64) floa
|
||||
cols := marketingPdfColumns
|
||||
maxLines := 1
|
||||
for i, col := range cols {
|
||||
if i >= len(values) || i == 10 {
|
||||
if i >= len(values) || i == 9 {
|
||||
continue
|
||||
}
|
||||
usableW := col.width - 2*margin
|
||||
@@ -238,7 +237,7 @@ func writeMarketingPdfRow(pdf *fpdf.Fpdf, item dto.RepportMarketingItemDTO, valu
|
||||
x := 10.0
|
||||
|
||||
for i, col := range cols {
|
||||
if i == 10 {
|
||||
if i == 9 {
|
||||
drawMarketingTypeBadge(pdf, x, y, col.width, rowH, item.MarketingType)
|
||||
pdf.SetDrawColor(borderR, borderG, borderB)
|
||||
pdf.SetTextColor(40, 40, 40)
|
||||
@@ -283,8 +282,8 @@ func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
|
||||
customer,
|
||||
safeMarketingExportText(item.DoNumber),
|
||||
sales,
|
||||
safeMarketingExportText(item.VehicleNumber),
|
||||
safeMarketingExportText(item.MarketingType), // index 10, overridden by badge
|
||||
safeMarketingExportText(formatMarketingVehicleNumber(item.VehicleNumber)),
|
||||
safeMarketingExportText(item.MarketingType), // index 9, overridden by badge
|
||||
product,
|
||||
formatMarketingPdfNumber(item.Qty),
|
||||
formatMarketingPdfDecimal(item.AverageWeightKg),
|
||||
@@ -292,7 +291,6 @@ func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
|
||||
formatMarketingPdfRupiah(item.SalesPricePerKg),
|
||||
formatMarketingPdfRupiah(item.HppPricePerKg),
|
||||
formatMarketingPdfRupiah(item.SalesAmount),
|
||||
formatMarketingPdfRupiah(item.HppAmount),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,30 +304,9 @@ func writeMarketingPdfTotal(pdf *fpdf.Fpdf, items []dto.RepportMarketingItemDTO)
|
||||
return
|
||||
}
|
||||
|
||||
rowH := 6.5
|
||||
|
||||
if pdf.GetY()+rowH > marketingPdfPageHeight(pdf)-12 {
|
||||
pdf.AddPage()
|
||||
writeMarketingPdfHeader(pdf)
|
||||
}
|
||||
|
||||
pdf.SetFont("Helvetica", "B", 6)
|
||||
pdf.SetFillColor(220, 230, 245)
|
||||
pdf.SetTextColor(30, 64, 120)
|
||||
pdf.SetDrawColor(borderR, borderG, borderB)
|
||||
pdf.SetLineWidth(0.1)
|
||||
|
||||
y := pdf.GetY()
|
||||
x := 10.0
|
||||
|
||||
// merge first 11 cols (No … Tipe Marketing) into "TOTAL" label
|
||||
mergedWidth := 0.0
|
||||
for i := 0; i < 11; i++ {
|
||||
mergedWidth += marketingPdfColumns[i].width
|
||||
}
|
||||
pdf.SetXY(x, y)
|
||||
pdf.CellFormat(mergedWidth, rowH, "TOTAL", "1", 0, "R", true, 0, "")
|
||||
x += mergedWidth
|
||||
lineH := 5.0
|
||||
|
||||
totals := []string{
|
||||
formatMarketingPdfNumber(float64(summary.TotalQty)),
|
||||
@@ -338,13 +315,58 @@ func writeMarketingPdfTotal(pdf *fpdf.Fpdf, items []dto.RepportMarketingItemDTO)
|
||||
formatMarketingPdfRupiah(summary.AverageSalesPrice),
|
||||
formatMarketingPdfRupiah(summary.TotalHppPricePerKg),
|
||||
formatMarketingPdfRupiah(float64(summary.TotalSalesAmount)),
|
||||
formatMarketingPdfRupiah(float64(summary.TotalHppAmount)),
|
||||
}
|
||||
|
||||
margin := pdf.GetCellMargin()
|
||||
maxLines := 1
|
||||
for i, val := range totals {
|
||||
col := marketingPdfColumns[11+i]
|
||||
usableW := col.width - 2*margin
|
||||
if usableW <= 0 {
|
||||
continue
|
||||
}
|
||||
lines := pdf.SplitLines([]byte(val), usableW)
|
||||
n := len(lines)
|
||||
if n == 0 {
|
||||
n = 1
|
||||
}
|
||||
if n > maxLines {
|
||||
maxLines = n
|
||||
}
|
||||
}
|
||||
rowH := float64(maxLines) * lineH
|
||||
|
||||
if pdf.GetY()+rowH > marketingPdfPageHeight(pdf)-12 {
|
||||
pdf.AddPage()
|
||||
writeMarketingPdfHeader(pdf)
|
||||
pdf.SetFont("Helvetica", "B", 6)
|
||||
}
|
||||
|
||||
pdf.SetTextColor(30, 64, 120)
|
||||
pdf.SetDrawColor(borderR, borderG, borderB)
|
||||
pdf.SetLineWidth(0.1)
|
||||
|
||||
y := pdf.GetY()
|
||||
x := 10.0
|
||||
|
||||
const totalFillR, totalFillG, totalFillB = 220, 230, 245
|
||||
|
||||
mergedWidth := 0.0
|
||||
for i := range 11 {
|
||||
mergedWidth += marketingPdfColumns[i].width
|
||||
}
|
||||
pdf.SetFillColor(totalFillR, totalFillG, totalFillB)
|
||||
pdf.Rect(x, y, mergedWidth, rowH, "FD")
|
||||
pdf.SetXY(x, y)
|
||||
pdf.MultiCell(mergedWidth, lineH, "TOTAL", "", "R", false)
|
||||
x += mergedWidth
|
||||
|
||||
for i, val := range totals {
|
||||
col := marketingPdfColumns[11+i]
|
||||
pdf.SetFillColor(totalFillR, totalFillG, totalFillB)
|
||||
pdf.Rect(x, y, col.width, rowH, "FD")
|
||||
pdf.SetXY(x, y)
|
||||
pdf.CellFormat(col.width, rowH, val, "1", 0, "R", true, 0, "")
|
||||
pdf.MultiCell(col.width, lineH, val, "", "R", false)
|
||||
x += col.width
|
||||
}
|
||||
|
||||
@@ -510,6 +532,27 @@ func marketingPdfPageHeight(pdf *fpdf.Fpdf) float64 {
|
||||
return h
|
||||
}
|
||||
|
||||
// formatMarketingVehicleNumber spaces out Indonesian plate segments: D1234MBU → D 1234 MBU.
|
||||
// Returns s unchanged if it doesn't match the [letters][digits][letters] pattern.
|
||||
func formatMarketingVehicleNumber(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
i := 0
|
||||
for i < len(s) && (s[i] >= 'A' && s[i] <= 'Z' || s[i] >= 'a' && s[i] <= 'z') {
|
||||
i++
|
||||
}
|
||||
j := i
|
||||
for j < len(s) && s[j] >= '0' && s[j] <= '9' {
|
||||
j++
|
||||
}
|
||||
if i == 0 || j == i || j == len(s) {
|
||||
return s
|
||||
}
|
||||
return s[:i] + " " + s[i:j] + " " + s[j:]
|
||||
}
|
||||
|
||||
// formatMarketingPdfThousands inserts period every 3 digits.
|
||||
func formatMarketingPdfThousands(v int64) string {
|
||||
negative := v < 0
|
||||
|
||||
Reference in New Issue
Block a user