From ef985b5da59353b84d19bfec48661f6f270c32fc Mon Sep 17 00:00:00 2001 From: giovanni Date: Mon, 25 May 2026 14:50:01 +0700 Subject: [PATCH] fix list penjualan and export penjualan dengan qty --- .../controllers/deliveryorder.export.go | 248 +++++++++++------- .../marketing/dto/deliveryorder.dto.go | 19 ++ 2 files changed, 179 insertions(+), 88 deletions(-) diff --git a/internal/modules/marketing/controllers/deliveryorder.export.go b/internal/modules/marketing/controllers/deliveryorder.export.go index 7d26191a..06b3ab28 100644 --- a/internal/modules/marketing/controllers/deliveryorder.export.go +++ b/internal/modules/marketing/controllers/deliveryorder.export.go @@ -75,9 +75,18 @@ func setMarketingExportColumns(file *excelize.File, sheet string) error { "B": 14, "C": 18, "D": 20, - "E": 18, - "F": 60, - "G": 24, + "E": 14, + "F": 40, + "G": 10, + "H": 12, + "I": 12, + "J": 12, + "K": 16, + "L": 16, + "M": 18, + "N": 18, + "O": 18, + "P": 24, } for col, width := range columnWidths { @@ -95,13 +104,22 @@ func setMarketingExportColumns(file *excelize.File, sheet string) error { func setMarketingExportHeaders(file *excelize.File, sheet string) error { headers := []string{ - "No. Order", - "Tanggal", - "Status", - "Customer", - "Grand Total", - "Products", - "Notes", + "No. Order", // A + "Tanggal", // B + "Status", // C + "Customer", // D + "Tipe", // E + "Nama Produk", // F + "Week", // G + "Jumlah", // H + "Satuan", // I + "Qty Peti", // J + "Berat Rata-rata (kg)", // K + "Total Berat (kg)", // L + "Harga Satuan", // M + "Total Harga", // N + "Grand Total", // O + "Catatan", // P } for i, header := range headers { @@ -130,7 +148,7 @@ func setMarketingExportHeaders(file *excelize.File, sheet string) error { return err } - return file.SetCellStyle(sheet, "A1", "G1", headerStyle) + return file.SetCellStyle(sheet, "A1", "P1", headerStyle) } func setMarketingExportRows(file *excelize.File, sheet string, items []dto.MarketingListDTO) error { @@ -138,70 +156,154 @@ func setMarketingExportRows(file *excelize.File, sheet string, items []dto.Marke return nil } - for i, item := range items { - rowNumber := i + 2 - if err := file.SetCellValue(sheet, "A"+strconv.Itoa(rowNumber), safeMarketingExportText(item.SoNumber)); err != nil { - return err + row := 1 + for _, item := range items { + soNumber := safeMarketingExportText(item.SoNumber) + soDate := formatMarketingExportDate(item.SoDate) + status := formatMarketingExportStatus(item) + customer := safeMarketingExportText(item.Customer.Name) + grandTotal := sumMarketingGrandTotal(item.SalesOrder) + notes := safeMarketingExportText(item.Notes) + + if len(item.SalesOrder) == 0 { + row++ + r := strconv.Itoa(row) + vals := map[string]interface{}{ + "A": soNumber, "B": soDate, "C": status, "D": customer, + "E": "-", "F": "-", "G": "-", "H": "-", "I": "-", "J": "-", + "K": "-", "L": "-", "M": "-", "N": "-", + "O": grandTotal, "P": notes, + } + for col, val := range vals { + if err := file.SetCellValue(sheet, col+r, val); err != nil { + return err + } + } + continue } - if err := file.SetCellValue(sheet, "B"+strconv.Itoa(rowNumber), formatMarketingExportDate(item.SoDate)); err != nil { - return err - } - if err := file.SetCellValue(sheet, "C"+strconv.Itoa(rowNumber), formatMarketingExportStatus(item)); err != nil { - return err - } - if err := file.SetCellValue(sheet, "D"+strconv.Itoa(rowNumber), safeMarketingExportText(item.Customer.Name)); err != nil { - return err - } - if err := file.SetCellValue(sheet, "E"+strconv.Itoa(rowNumber), sumMarketingGrandTotal(item.SalesOrder)); err != nil { - return err - } - if err := file.SetCellValue(sheet, "F"+strconv.Itoa(rowNumber), formatMarketingProducts(item.SalesOrder)); err != nil { - return err - } - if err := file.SetCellValue(sheet, "G"+strconv.Itoa(rowNumber), safeMarketingExportText(item.Notes)); err != nil { - return err + + for _, prod := range item.SalesOrder { + row++ + r := strconv.Itoa(row) + + productName := "-" + if prod.ProductWarehouse != nil && prod.ProductWarehouse.Product != nil { + if n := strings.TrimSpace(prod.ProductWarehouse.Product.Name); n != "" { + productName = n + } + } + + week := "-" + if prod.Week != nil { + week = strconv.Itoa(*prod.Week) + } + + satuan := "-" + if prod.ConvertionUnit != nil && strings.TrimSpace(*prod.ConvertionUnit) != "" { + satuan = *prod.ConvertionUnit + } + + if err := file.SetCellValue(sheet, "A"+r, soNumber); err != nil { + return err + } + if err := file.SetCellValue(sheet, "B"+r, soDate); err != nil { + return err + } + if err := file.SetCellValue(sheet, "C"+r, status); err != nil { + return err + } + if err := file.SetCellValue(sheet, "D"+r, customer); err != nil { + return err + } + if err := file.SetCellValue(sheet, "E"+r, safeMarketingExportText(prod.MarketingType)); err != nil { + return err + } + if err := file.SetCellValue(sheet, "F"+r, productName); err != nil { + return err + } + if err := file.SetCellValue(sheet, "G"+r, week); err != nil { + return err + } + if err := file.SetCellValue(sheet, "H"+r, prod.Qty); err != nil { + return err + } + if err := file.SetCellValue(sheet, "I"+r, satuan); err != nil { + return err + } + if prod.TotalPeti != nil { + if err := file.SetCellValue(sheet, "J"+r, *prod.TotalPeti); err != nil { + return err + } + } else { + if err := file.SetCellValue(sheet, "J"+r, "-"); err != nil { + return err + } + } + if err := file.SetCellValue(sheet, "K"+r, prod.AvgWeight); err != nil { + return err + } + if err := file.SetCellValue(sheet, "L"+r, prod.TotalWeight); err != nil { + return err + } + if err := file.SetCellValue(sheet, "M"+r, prod.UnitPrice); err != nil { + return err + } + if err := file.SetCellValue(sheet, "N"+r, prod.TotalPrice); err != nil { + return err + } + if err := file.SetCellValue(sheet, "O"+r, grandTotal); err != nil { + return err + } + if err := file.SetCellValue(sheet, "P"+r, notes); err != nil { + return err + } } } - lastRow := len(items) + 1 + lastRow := row + lastRowStr := strconv.Itoa(lastRow) + 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}, + } + 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}, - }, + Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true}, + Border: border, }) if err != nil { return err } - - if err := file.SetCellStyle(sheet, "A2", "G"+strconv.Itoa(lastRow), dataStyle); err != nil { + if err := file.SetCellStyle(sheet, "A2", "P"+lastRowStr, dataStyle); err != nil { return err } - moneyStyle, 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}, - }, + numberStyle, err := file.NewStyle(&excelize.Style{ + Alignment: &excelize.Alignment{Horizontal: "right", Vertical: "center"}, + Border: border, }) if err != nil { return err } + if err := file.SetCellStyle(sheet, "K2", "O"+lastRowStr, numberStyle); err != nil { + return err + } - return file.SetCellStyle(sheet, "E2", "E"+strconv.Itoa(lastRow), moneyStyle) + centerStyle, err := file.NewStyle(&excelize.Style{ + Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"}, + Border: border, + }) + if err != nil { + return err + } + for _, col := range []string{"G", "H", "J"} { + if err := file.SetCellStyle(sheet, col+"2", col+lastRowStr, centerStyle); err != nil { + return err + } + } + return nil } func formatMarketingExportDate(value time.Time) string { @@ -225,36 +327,6 @@ func formatMarketingExportStatus(item dto.MarketingListDTO) string { return safeMarketingExportText(item.LatestApproval.StepName) } -func formatMarketingProducts(items []dto.DeliveryMarketingProductDTO) string { - if len(items) == 0 { - return "-" - } - - seen := make(map[string]struct{}) - names := make([]string, 0, len(items)) - for _, item := range items { - if item.ProductWarehouse == nil || item.ProductWarehouse.Product == nil { - continue - } - - name := strings.TrimSpace(item.ProductWarehouse.Product.Name) - if name == "" { - continue - } - - if _, exists := seen[name]; exists { - continue - } - seen[name] = struct{}{} - names = append(names, name) - } - - if len(names) == 0 { - return "-" - } - - return strings.Join(names, ", ") -} func sumMarketingGrandTotal(items []dto.DeliveryMarketingProductDTO) float64 { total := 0.0 diff --git a/internal/modules/marketing/dto/deliveryorder.dto.go b/internal/modules/marketing/dto/deliveryorder.dto.go index 0e21d534..915a183b 100644 --- a/internal/modules/marketing/dto/deliveryorder.dto.go +++ b/internal/modules/marketing/dto/deliveryorder.dto.go @@ -29,6 +29,7 @@ type MarketingListDTO struct { SalesPerson userDTO.UserRelationDTO `json:"sales_person"` SoDocs string `json:"so_docs"` SalesOrder []DeliveryMarketingProductDTO `json:"sales_order"` + DeliveryOrder []DeliveryGroupDTO `json:"delivery_order"` CreatedUser userDTO.UserRelationDTO `json:"created_user"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` @@ -203,6 +204,7 @@ func ToMarketingListDTO(marketing *entity.Marketing, deliveryProducts []entity.M SalesPerson: salesPerson, SoDocs: marketing.SoDocs, SalesOrder: salesOrderProducts, + DeliveryOrder: extractDeliveryGroupsFromProducts(marketing), CreatedUser: createdUser, CreatedAt: marketing.CreatedAt, UpdatedAt: marketing.UpdatedAt, @@ -376,6 +378,23 @@ func GenerateDeliveryOrderNumber(soNumber string, deliveryDate *time.Time, wareh return numberPrefix } +func extractDeliveryGroupsFromProducts(marketing *entity.Marketing) []DeliveryGroupDTO { + var dps []MarketingDeliveryProductDTO + for _, product := range marketing.Products { + if product.DeliveryProduct == nil || product.DeliveryProduct.DeliveryDate == nil { + continue + } + dp := ToMarketingDeliveryProductDTO(*product.DeliveryProduct) + if product.ProductWarehouse.Id != 0 { + mapped := productwarehouseDTO.ToProductWarehouseNestedDTO(product.ProductWarehouse) + dp.ProductWarehouse = &mapped + } + dp.ConvertionUnit = product.ConvertionUnit + dps = append(dps, dp) + } + return groupDeliveryProducts(dps, marketing.SoNumber) +} + func collectDoNumbers(marketing *entity.Marketing) []string { if marketing == nil || len(marketing.Products) == 0 { return nil