package dto import ( "encoding/json" "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" marketingDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/dto" customerDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/dto" productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto" productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto" supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto" uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto" warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" "gitlab.com/mbugroup/lti-api.git/internal/utils" ) type RepportMarketingItemDTO struct { ID int `json:"id"` SoDate time.Time `json:"so_date"` RealizationDate time.Time `json:"realization_date"` AgingDays int `json:"aging_days"` Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"` Customer *customerDTO.CustomerRelationDTO `json:"customer,omitempty"` DoNumber string `json:"do_number"` Sales *userDTO.UserRelationDTO `json:"sales,omitempty"` VehicleNumber string `json:"vehicle_number"` Product *ProductRelationDTOFixed `json:"product,omitempty"` MarketingType string `json:"marketing_type"` Qty float64 `json:"qty"` AverageWeightKg float64 `json:"average_weight_kg"` TotalWeightKg float64 `json:"total_weight_kg"` SalesPricePerKg float64 `json:"sales_price_per_kg"` HppPricePerKg float64 `json:"hpp_price_per_kg"` SalesAmount float64 `json:"sales_amount"` HppAmount float64 `json:"hpp_amount"` } type Summary struct { TotalQty int `json:"total_qty"` TotalWeightKg float64 `json:"total_weight_kg"` AverageWeightKg float64 `json:"average_weight_kg"` AverageSalesPrice float64 `json:"average_sales_price"` TotalSalesAmount int64 `json:"total_sales_amount"` TotalHppAmount int64 `json:"total_hpp_amount"` TotalHppPricePerKg float64 `json:"total_hpp_price_per_kg"` } type ProductRelationDTOFixed struct { productDTO.ProductRelationDTO ProductPrice float64 `json:"product_price"` SellingPrice *float64 `json:"selling_price,omitempty"` } func ToMarketingReportItems(mdps []entity.MarketingDeliveryProduct, hppMap map[uint]float64, agingMap map[int]int) []RepportMarketingItemDTO { items := make([]RepportMarketingItemDTO, 0, len(mdps)) for _, mdp := range mdps { hppPerKg := float64(0) category := "" if projectFlockKandang := mdp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil { if hpp, exists := hppMap[projectFlockKandang.ProjectFlockId]; exists { hppPerKg = hpp } category = projectFlockKandang.ProjectFlock.Category } soDate := time.Time{} agingDays := 0 if mdp.MarketingProduct.Marketing.SoDate.Year() > 1 { soDate = mdp.MarketingProduct.Marketing.SoDate if ag, exists := agingMap[int(mdp.Id)]; exists { agingDays = ag } else { agingDays = int(time.Since(soDate).Hours() / 24) } } realizationDate := time.Time{} if mdp.DeliveryDate != nil { realizationDate = *mdp.DeliveryDate } totalWeightKg := mdp.UsageQty * mdp.AvgWeight salesAmount := totalWeightKg * mdp.UnitPrice var hpp float64 var hppAmount float64 var hasAyam, hasTelur, hasTrading bool for _, flag := range mdp.MarketingProduct.ProductWarehouse.Product.Flags { ft := utils.FlagType(flag.Name) if ft == utils.FlagAyamAfkir || ft == utils.FlagAyamCulling || ft == utils.FlagAyamMati || ft == utils.FlagDOC || ft == utils.FlagPullet || ft == utils.FlagLayer { hasAyam = true } if ft == utils.FlagTelur || ft == utils.FlagTelurUtuh || ft == utils.FlagTelurPecah || ft == utils.FlagTelurPutih || ft == utils.FlagTelurRetak { hasTelur = true } if ft == utils.FlagOVK || ft == utils.FlagObat || ft == utils.FlagVitamin || ft == utils.FlagKimia || ft == utils.FlagPakan || ft == utils.FlagPreStarter || ft == utils.FlagStarter || ft == utils.FlagFinisher { hasTrading = true } } marketingType := "trading" if hasTrading { marketingType = "trading" } else if hasTelur { marketingType = "telur" } else if hasAyam { marketingType = "ayam" } eligibleForHpp := false if utils.ProjectFlockCategory(category) == utils.ProjectFlockCategoryGrowing { eligibleForHpp = hasAyam } else { eligibleForHpp = hasAyam || hasTelur } if eligibleForHpp { hpp = hppPerKg hppAmount = totalWeightKg * hppPerKg } item := RepportMarketingItemDTO{ ID: int(mdp.Id), SoDate: soDate, RealizationDate: realizationDate, AgingDays: agingDays, DoNumber: marketingDTO.GenerateDeliveryOrderNumber(mdp.MarketingProduct.Marketing.SoNumber, mdp.DeliveryDate, mdp.MarketingProduct.ProductWarehouse.WarehouseId), MarketingType: marketingType, Qty: mdp.UsageQty, AverageWeightKg: mdp.AvgWeight, TotalWeightKg: totalWeightKg, SalesPricePerKg: mdp.UnitPrice, HppPricePerKg: hpp, SalesAmount: salesAmount, HppAmount: hppAmount, VehicleNumber: mdp.VehicleNumber, } if mdp.MarketingProduct.ProductWarehouse.WarehouseId != 0 { mapped := warehouseDTO.ToWarehouseRelationDTO(mdp.MarketingProduct.ProductWarehouse.Warehouse) item.Warehouse = &mapped } if mdp.MarketingProduct.Marketing.CustomerId != 0 { mapped := customerDTO.ToCustomerRelationDTO(mdp.MarketingProduct.Marketing.Customer) item.Customer = &mapped } if mdp.MarketingProduct.Marketing.SalesPersonId != 0 { mapped := userDTO.ToUserRelationDTO(mdp.MarketingProduct.Marketing.SalesPerson) item.Sales = &mapped } if mdp.MarketingProduct.ProductWarehouse.ProductId != 0 { mapped := productDTO.ToProductRelationDTO(mdp.MarketingProduct.ProductWarehouse.Product) item.Product = newProductRelationDTOFixedPtr(&mapped) } items = append(items, item) } return items } func ToSummaryFromDTOItems(items []RepportMarketingItemDTO) *Summary { if len(items) == 0 { return nil } totalQty := 0 totalWeightKg := 0.0 avgSalesPrice := 0.0 avgWeightKg := 0.0 totalSalesAmount := int64(0) totalHppAmount := int64(0) for _, item := range items { totalQty += int(item.Qty) totalWeightKg += item.TotalWeightKg totalSalesAmount += int64(item.SalesAmount) totalHppAmount += int64(item.HppAmount) avgSalesPrice += item.SalesPricePerKg } totalHppPricePerKg := float64(0) if totalWeightKg > 0 { totalHppPricePerKg = float64(totalHppAmount) / totalWeightKg } if len(items) > 0 { avgSalesPrice = avgSalesPrice / float64(len(items)) } if totalQty > 0 { avgWeightKg = totalWeightKg / float64(totalQty) } return &Summary{ TotalQty: totalQty, TotalWeightKg: totalWeightKg, AverageWeightKg: avgWeightKg, AverageSalesPrice: avgSalesPrice, TotalSalesAmount: totalSalesAmount, TotalHppAmount: totalHppAmount, TotalHppPricePerKg: totalHppPricePerKg, } } func newProductRelationDTOFixedPtr(original *productDTO.ProductRelationDTO) *ProductRelationDTOFixed { if original == nil { return nil } fixed := ProductRelationDTOFixed{ ProductRelationDTO: *original, ProductPrice: original.ProductPrice, SellingPrice: original.SellingPrice, } return &fixed } func (p ProductRelationDTOFixed) MarshalJSON() ([]byte, error) { type Alias struct { Id uint `json:"id"` Name string `json:"name"` ProductPrice float64 `json:"product_price"` SellingPrice *float64 `json:"selling_price"` Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"` Flags *[]string `json:"flags,omitempty"` ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"` Suppliers []supplierDTO.SupplierRelationDTO `json:"suppliers"` } suppliers := make([]supplierDTO.SupplierRelationDTO, len(p.ProductRelationDTO.Suppliers)) for i, ps := range p.ProductRelationDTO.Suppliers { suppliers[i] = supplierDTO.SupplierRelationDTO{ Id: ps.Id, Name: ps.Name, Alias: ps.Alias, Category: ps.Category, } } return json.Marshal(&Alias{ Id: p.ProductRelationDTO.Id, Name: p.ProductRelationDTO.Name, ProductPrice: p.ProductPrice, SellingPrice: p.SellingPrice, Uom: p.ProductRelationDTO.Uom, Flags: p.ProductRelationDTO.Flags, ProductCategory: p.ProductRelationDTO.ProductCategory, Suppliers: suppliers, }) }