mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 05:21:57 +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 {
|
if err := setMarketingReportRows(file, items); err != nil {
|
||||||
return nil, err
|
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()
|
buffer, err := file.WriteToBuffer()
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +122,6 @@ func setMarketingReportHeaders(file *excelize.File) error {
|
|||||||
"Bobot Total (Kg)",
|
"Bobot Total (Kg)",
|
||||||
"Harga Jual (Rp)",
|
"Harga Jual (Rp)",
|
||||||
"HPP (Rp)",
|
"HPP (Rp)",
|
||||||
"HPP Amount (Rp)",
|
|
||||||
"Total (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 {
|
func setMarketingReportRows(file *excelize.File, items []dto.RepportMarketingItemDTO) error {
|
||||||
@@ -173,7 +199,6 @@ func setMarketingReportRows(file *excelize.File, items []dto.RepportMarketingIte
|
|||||||
item.TotalWeightKg,
|
item.TotalWeightKg,
|
||||||
formatMarketingRupiah(item.SalesPricePerKg),
|
formatMarketingRupiah(item.SalesPricePerKg),
|
||||||
formatMarketingRupiah(item.HppPricePerKg),
|
formatMarketingRupiah(item.HppPricePerKg),
|
||||||
formatMarketingRupiah(item.HppAmount),
|
|
||||||
formatMarketingRupiah(item.SalesAmount),
|
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 {
|
if err := file.SetCellValue(sheet, "P"+totalRow, formatMarketingRupiah(summary.TotalHppPricePerKg)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := file.SetCellValue(sheet, "Q"+totalRow, formatMarketingRupiah(float64(summary.TotalHppAmount))); err != nil {
|
if err := file.SetCellValue(sheet, "Q"+totalRow, formatMarketingRupiah(float64(summary.TotalSalesAmount))); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := file.SetCellValue(sheet, "R"+totalRow, formatMarketingRupiah(float64(summary.TotalSalesAmount))); err != nil {
|
|
||||||
return err
|
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 {
|
func formatMarketingDate(t time.Time) string {
|
||||||
|
|||||||
@@ -56,22 +56,21 @@ type pdfColumn struct {
|
|||||||
var marketingPdfColumns = []pdfColumn{
|
var marketingPdfColumns = []pdfColumn{
|
||||||
{"No", 6, "C"},
|
{"No", 6, "C"},
|
||||||
{"Tanggal\nJual", 16, "C"},
|
{"Tanggal\nJual", 16, "C"},
|
||||||
{"Tanggal\nRealisasi", 16, "C"},
|
{"Tanggal\nRealisasi", 20, "C"},
|
||||||
{"Aging\n(Hari)", 9, "C"},
|
{"Aging\n(Hari)", 9, "C"},
|
||||||
{"Gudang\nFisik", 20, "L"},
|
{"Gudang\nFisik", 20, "L"},
|
||||||
{"Pelanggan", 20, "L"},
|
{"Pelanggan", 20, "L"},
|
||||||
{"No. DO", 18, "L"},
|
{"No. DO", 18, "L"},
|
||||||
{"Sales", 18, "L"},
|
{"Sales", 18, "L"},
|
||||||
{"No. Polisi", 18, "L"},
|
{"No. Polisi", 18, "L"},
|
||||||
{"Tipe\nMarketing", 14, "C"},
|
{"Tipe\nMarketing", 16, "C"},
|
||||||
{"Produk", 16, "L"},
|
{"Produk", 16, "L"},
|
||||||
{"Kuantitas", 13, "R"},
|
{"Kuantitas", 13, "R"},
|
||||||
{"Bobot Rata-Rata\n(Kg)", 13, "R"},
|
{"Bobot\nRata-Rata (Kg)", 18, "R"},
|
||||||
{"Bobot Total Berat\n(Kg)", 14, "R"},
|
{"Bobot\nTotal Berat (Kg)", 18, "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 (Rp)", 18, "R"},
|
||||||
{"Total HPP\n(Rp)", 18, "R"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -214,7 +213,7 @@ func calcMarketingRowHeight(pdf *fpdf.Fpdf, values []string, lineH float64) floa
|
|||||||
cols := marketingPdfColumns
|
cols := marketingPdfColumns
|
||||||
maxLines := 1
|
maxLines := 1
|
||||||
for i, col := range cols {
|
for i, col := range cols {
|
||||||
if i >= len(values) || i == 10 {
|
if i >= len(values) || i == 9 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
usableW := col.width - 2*margin
|
usableW := col.width - 2*margin
|
||||||
@@ -238,7 +237,7 @@ func writeMarketingPdfRow(pdf *fpdf.Fpdf, item dto.RepportMarketingItemDTO, valu
|
|||||||
x := 10.0
|
x := 10.0
|
||||||
|
|
||||||
for i, col := range cols {
|
for i, col := range cols {
|
||||||
if i == 10 {
|
if i == 9 {
|
||||||
drawMarketingTypeBadge(pdf, x, y, col.width, rowH, item.MarketingType)
|
drawMarketingTypeBadge(pdf, x, y, col.width, rowH, item.MarketingType)
|
||||||
pdf.SetDrawColor(borderR, borderG, borderB)
|
pdf.SetDrawColor(borderR, borderG, borderB)
|
||||||
pdf.SetTextColor(40, 40, 40)
|
pdf.SetTextColor(40, 40, 40)
|
||||||
@@ -283,8 +282,8 @@ func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
|
|||||||
customer,
|
customer,
|
||||||
safeMarketingExportText(item.DoNumber),
|
safeMarketingExportText(item.DoNumber),
|
||||||
sales,
|
sales,
|
||||||
safeMarketingExportText(item.VehicleNumber),
|
safeMarketingExportText(formatMarketingVehicleNumber(item.VehicleNumber)),
|
||||||
safeMarketingExportText(item.MarketingType), // index 10, overridden by badge
|
safeMarketingExportText(item.MarketingType), // index 9, overridden by badge
|
||||||
product,
|
product,
|
||||||
formatMarketingPdfNumber(item.Qty),
|
formatMarketingPdfNumber(item.Qty),
|
||||||
formatMarketingPdfDecimal(item.AverageWeightKg),
|
formatMarketingPdfDecimal(item.AverageWeightKg),
|
||||||
@@ -292,7 +291,6 @@ func marketingPdfRowValues(no int, item dto.RepportMarketingItemDTO) []string {
|
|||||||
formatMarketingPdfRupiah(item.SalesPricePerKg),
|
formatMarketingPdfRupiah(item.SalesPricePerKg),
|
||||||
formatMarketingPdfRupiah(item.HppPricePerKg),
|
formatMarketingPdfRupiah(item.HppPricePerKg),
|
||||||
formatMarketingPdfRupiah(item.SalesAmount),
|
formatMarketingPdfRupiah(item.SalesAmount),
|
||||||
formatMarketingPdfRupiah(item.HppAmount),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,30 +304,9 @@ func writeMarketingPdfTotal(pdf *fpdf.Fpdf, items []dto.RepportMarketingItemDTO)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rowH := 6.5
|
|
||||||
|
|
||||||
if pdf.GetY()+rowH > marketingPdfPageHeight(pdf)-12 {
|
|
||||||
pdf.AddPage()
|
|
||||||
writeMarketingPdfHeader(pdf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pdf.SetFont("Helvetica", "B", 6)
|
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()
|
lineH := 5.0
|
||||||
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
|
|
||||||
|
|
||||||
totals := []string{
|
totals := []string{
|
||||||
formatMarketingPdfNumber(float64(summary.TotalQty)),
|
formatMarketingPdfNumber(float64(summary.TotalQty)),
|
||||||
@@ -338,13 +315,58 @@ func writeMarketingPdfTotal(pdf *fpdf.Fpdf, items []dto.RepportMarketingItemDTO)
|
|||||||
formatMarketingPdfRupiah(summary.AverageSalesPrice),
|
formatMarketingPdfRupiah(summary.AverageSalesPrice),
|
||||||
formatMarketingPdfRupiah(summary.TotalHppPricePerKg),
|
formatMarketingPdfRupiah(summary.TotalHppPricePerKg),
|
||||||
formatMarketingPdfRupiah(float64(summary.TotalSalesAmount)),
|
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 {
|
for i, val := range totals {
|
||||||
col := marketingPdfColumns[11+i]
|
col := marketingPdfColumns[11+i]
|
||||||
|
pdf.SetFillColor(totalFillR, totalFillG, totalFillB)
|
||||||
|
pdf.Rect(x, y, col.width, rowH, "FD")
|
||||||
pdf.SetXY(x, y)
|
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
|
x += col.width
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,6 +532,27 @@ func marketingPdfPageHeight(pdf *fpdf.Fpdf) float64 {
|
|||||||
return h
|
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.
|
// formatMarketingPdfThousands inserts period every 3 digits.
|
||||||
func formatMarketingPdfThousands(v int64) string {
|
func formatMarketingPdfThousands(v int64) string {
|
||||||
negative := v < 0
|
negative := v < 0
|
||||||
|
|||||||
Reference in New Issue
Block a user