package dto import ( "fmt" "sort" "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto" productwarehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/dto" customerDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" ) type MarketingRelationDTO struct { Id uint `json:"id"` SoNumber string `json:"so_number"` SoDate time.Time `json:"so_date"` Notes string `json:"notes,omitempty"` } type MarketingListDTO struct { MarketingRelationDTO Customer customerDTO.CustomerRelationDTO `json:"customer"` SalesPerson userDTO.UserRelationDTO `json:"sales_person"` SoDocs string `json:"so_docs"` SalesOrder []DeliveryMarketingProductDTO `json:"sales_order"` CreatedUser userDTO.UserRelationDTO `json:"created_user"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` LatestApproval approvalDTO.ApprovalRelationDTO `json:"latest_approval"` } type MarketingDetailDTO struct { MarketingRelationDTO Customer customerDTO.CustomerRelationDTO `json:"customer"` 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"` LatestApproval approvalDTO.ApprovalRelationDTO `json:"latest_approval"` } type MarketingDeliveryProductDTO struct { Id uint `json:"id"` MarketingProductId uint `json:"marketing_product_id"` Qty float64 `json:"qty"` UnitPrice float64 `json:"unit_price"` TotalWeight float64 `json:"total_weight"` AvgWeight float64 `json:"avg_weight"` TotalPrice float64 `json:"total_price"` DeliveryDate *time.Time `json:"delivery_date"` VehicleNumber string `json:"vehicle_number"` ProductWarehouse *productwarehouseDTO.ProductWarehousNestedDTO `json:"product_warehouse,omitempty"` } type DeliveryItemDTO struct { ProductWarehouse *productwarehouseDTO.ProductWarehousNestedDTO `json:"product_warehouse"` Qty float64 `json:"qty"` UnitPrice float64 `json:"unit_price"` TotalWeight float64 `json:"total_weight"` AvgWeight float64 `json:"avg_weight"` TotalPrice float64 `json:"total_price"` VehicleNumber string `json:"vehicle_number"` } type DeliveryGroupDTO struct { DoNumber string `json:"do_number"` DeliveryDate *time.Time `json:"delivery_date"` Warehouse *productwarehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"` Deliveries []DeliveryItemDTO `json:"deliveries"` } type DeliveryMarketingProductDTO struct { Id uint `json:"id"` MarketingId uint `json:"marketing_id"` ProductWarehouseId uint `json:"product_warehouse_id"` Qty float64 `json:"qty"` UnitPrice float64 `json:"unit_price"` AvgWeight float64 `json:"avg_weight"` TotalWeight float64 `json:"total_weight"` TotalPrice float64 `json:"total_price"` ProductWarehouse *productwarehouseDTO.ProductWarehousNestedDTO `json:"product_warehouse,omitempty"` VehicleNumber string `json:"vehicle_number,omitempty"` } func ToMarketingRelationDTO(marketing *entity.Marketing) MarketingRelationDTO { return MarketingRelationDTO{ Id: marketing.Id, SoNumber: marketing.SoNumber, SoDate: marketing.SoDate, Notes: marketing.Notes, } } func ToDeliveryMarketingProductDTO(e entity.MarketingProduct) DeliveryMarketingProductDTO { var productWarehouse *productwarehouseDTO.ProductWarehousNestedDTO if e.ProductWarehouse.Id != 0 { mapped := productwarehouseDTO.ToProductWarehouseNestedDTO(e.ProductWarehouse) productWarehouse = &mapped } return DeliveryMarketingProductDTO{ Id: e.Id, MarketingId: e.MarketingId, ProductWarehouseId: e.ProductWarehouseId, Qty: e.Qty, UnitPrice: e.UnitPrice, AvgWeight: e.AvgWeight, TotalWeight: e.TotalWeight, TotalPrice: e.TotalPrice, ProductWarehouse: productWarehouse, VehicleNumber: getVehicleNumber(e), } } func ToMarketingDeliveryProductDTO(e entity.MarketingDeliveryProduct) MarketingDeliveryProductDTO { return MarketingDeliveryProductDTO{ Id: e.Id, MarketingProductId: e.MarketingProductId, Qty: e.UsageQty, UnitPrice: e.UnitPrice, TotalWeight: e.TotalWeight, AvgWeight: e.AvgWeight, TotalPrice: e.TotalPrice, DeliveryDate: e.DeliveryDate, VehicleNumber: e.VehicleNumber, } } func ToMarketingListDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingListDTO { var createdUser userDTO.UserRelationDTO if marketing.CreatedUser.Id != 0 { mapped := userDTO.ToUserRelationDTO(marketing.CreatedUser) createdUser = mapped } var customer customerDTO.CustomerRelationDTO if marketing.Customer.Id != 0 { mapped := customerDTO.ToCustomerRelationDTO(marketing.Customer) customer = mapped } var salesPerson userDTO.UserRelationDTO if marketing.SalesPerson.Id != 0 { mapped := userDTO.ToUserRelationDTO(marketing.SalesPerson) salesPerson = mapped } var latestApproval approvalDTO.ApprovalRelationDTO if marketing.LatestApproval != nil { mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval) latestApproval = mapped } var salesOrderProducts []DeliveryMarketingProductDTO if len(marketing.Products) > 0 { salesOrderProducts = make([]DeliveryMarketingProductDTO, len(marketing.Products)) for i, product := range marketing.Products { salesOrderProducts[i] = ToDeliveryMarketingProductDTO(product) } } return MarketingListDTO{ MarketingRelationDTO: ToMarketingRelationDTO(marketing), Customer: customer, SalesPerson: salesPerson, SoDocs: marketing.SoDocs, SalesOrder: salesOrderProducts, CreatedUser: createdUser, CreatedAt: marketing.CreatedAt, UpdatedAt: marketing.UpdatedAt, LatestApproval: latestApproval, } } func ToMarketingDetailDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingDetailDTO { var createdUser userDTO.UserRelationDTO if marketing.CreatedUser.Id != 0 { mapped := userDTO.ToUserRelationDTO(marketing.CreatedUser) createdUser = mapped } var customer customerDTO.CustomerRelationDTO if marketing.Customer.Id != 0 { mapped := customerDTO.ToCustomerRelationDTO(marketing.Customer) customer = mapped } var salesPerson userDTO.UserRelationDTO if marketing.SalesPerson.Id != 0 { mapped := userDTO.ToUserRelationDTO(marketing.SalesPerson) salesPerson = mapped } var salesOrderProducts []DeliveryMarketingProductDTO if len(marketing.Products) > 0 { salesOrderProducts = make([]DeliveryMarketingProductDTO, len(marketing.Products)) for i, product := range marketing.Products { salesOrderProducts[i] = ToDeliveryMarketingProductDTO(product) } } var deliveryProductsDTOs []MarketingDeliveryProductDTO if len(deliveryProducts) > 0 { deliveryProductsDTOs = make([]MarketingDeliveryProductDTO, len(deliveryProducts)) for i, dp := range deliveryProducts { deliveryProductsDTOs[i] = ToMarketingDeliveryProductDTO(dp) } deliveryProductsDTOs = enrichDeliveryProductDTOsWithWarehouse(deliveryProductsDTOs, marketing) } deliveryGroups := groupDeliveryProducts(deliveryProductsDTOs, marketing.SoNumber) var latestApproval approvalDTO.ApprovalRelationDTO if marketing.LatestApproval != nil { mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval) latestApproval = mapped } return MarketingDetailDTO{ MarketingRelationDTO: ToMarketingRelationDTO(marketing), SoDocs: marketing.SoDocs, Customer: customer, SalesPerson: salesPerson, SalesOrder: salesOrderProducts, DeliveryOrder: deliveryGroups, CreatedUser: createdUser, CreatedAt: marketing.CreatedAt, UpdatedAt: marketing.UpdatedAt, LatestApproval: latestApproval, } } func ToMarketingListDTOs(marketings []entity.Marketing) []MarketingListDTO { result := make([]MarketingListDTO, len(marketings)) for i, m := range marketings { result[i] = ToMarketingListDTO(&m, []entity.MarketingDeliveryProduct{}) } return result } func enrichDeliveryProductDTOsWithWarehouse(deliveryProductDTOs []MarketingDeliveryProductDTO, marketing *entity.Marketing) []MarketingDeliveryProductDTO { if len(deliveryProductDTOs) == 0 || marketing == nil || len(marketing.Products) == 0 { return deliveryProductDTOs } productMap := make(map[uint]*entity.MarketingProduct) for i := range marketing.Products { productMap[marketing.Products[i].Id] = &marketing.Products[i] } for i := range deliveryProductDTOs { if product, exists := productMap[deliveryProductDTOs[i].MarketingProductId]; exists { if product.ProductWarehouse.Id != 0 { mapped := productwarehouseDTO.ToProductWarehouseNestedDTO(product.ProductWarehouse) deliveryProductDTOs[i].ProductWarehouse = &mapped } } } return deliveryProductDTOs } func groupDeliveryProducts(products []MarketingDeliveryProductDTO, soNumber string) []DeliveryGroupDTO { groupMap := make(map[string]*DeliveryGroupDTO) for _, product := range products { if product.DeliveryDate == nil { continue } var warehouseId uint var warehouseName string if product.ProductWarehouse != nil { warehouseId = product.ProductWarehouse.Warehouse.Id warehouseName = product.ProductWarehouse.Warehouse.Name } key := fmt.Sprintf("%d_%s", warehouseId, product.DeliveryDate.Format("2006-01-02")) group, exists := groupMap[key] if !exists { group = &DeliveryGroupDTO{ DeliveryDate: product.DeliveryDate, Warehouse: &productwarehouseDTO.WarehouseRelationDTO{ Id: warehouseId, Name: warehouseName, }, Deliveries: []DeliveryItemDTO{}, } groupMap[key] = group } deliveryItem := DeliveryItemDTO{ ProductWarehouse: product.ProductWarehouse, Qty: product.Qty, UnitPrice: product.UnitPrice, TotalWeight: product.TotalWeight, AvgWeight: product.AvgWeight, TotalPrice: product.TotalPrice, VehicleNumber: product.VehicleNumber, } group.Deliveries = append(group.Deliveries, deliveryItem) } var groups []DeliveryGroupDTO for _, group := range groupMap { groups = append(groups, *group) } sort.Slice(groups, func(i, j int) bool { if groups[i].DeliveryDate == nil || groups[j].DeliveryDate == nil { return false } return groups[i].DeliveryDate.Before(*groups[j].DeliveryDate) }) for i := range groups { groups[i].DoNumber = GenerateDeliveryOrderNumber(soNumber, groups[i].DeliveryDate, groups[i].Warehouse.Id) } return groups } func GenerateDeliveryOrderNumber(soNumber string, deliveryDate *time.Time, warehouseId uint) string { dateStr := "" if deliveryDate != nil { dateStr = deliveryDate.Format("20060102") } return fmt.Sprintf("%s-%s-%d", soNumber, dateStr, warehouseId) } func getVehicleNumber(e entity.MarketingProduct) string { if e.DeliveryProduct != nil && e.DeliveryProduct.VehicleNumber != "" { return e.DeliveryProduct.VehicleNumber } return "" }