From 9b6637066ef3afc4513f435451f9c37781a018da Mon Sep 17 00:00:00 2001 From: giovanni Date: Fri, 30 Jan 2026 10:46:54 +0700 Subject: [PATCH] fix calculate age at closing data production --- .../closings/dto/closingMarketing.dto.go | 20 +++++++++ .../closings/services/closing.service.go | 42 +++++++------------ .../salesorder_delivery_product.repository.go | 41 ++++++++++++++++++ 3 files changed, 75 insertions(+), 28 deletions(-) diff --git a/internal/modules/closings/dto/closingMarketing.dto.go b/internal/modules/closings/dto/closingMarketing.dto.go index a4bb5cb0..189ef7cb 100644 --- a/internal/modules/closings/dto/closingMarketing.dto.go +++ b/internal/modules/closings/dto/closingMarketing.dto.go @@ -101,6 +101,26 @@ func ToSalesDTO(e entity.MarketingDeliveryProduct) SalesDTO { } } +func ToSalesAgeDTO(e entity.MarketingDeliveryProduct) SalesDTO { + + productFlags := make([]string, len(e.MarketingProduct.ProductWarehouse.Product.Flags)) + for i, f := range e.MarketingProduct.ProductWarehouse.Product.Flags { + productFlags[i] = f.Name + } + + var category string + if e.MarketingProduct.ProductWarehouse.ProjectFlockKandang != nil { + category = e.MarketingProduct.ProductWarehouse.ProjectFlockKandang.ProjectFlock.Category + } + + ageInDay, _ := calculateAgeFromChickin(e.MarketingProduct.ProductWarehouse.ProjectFlockKandang, e.DeliveryDate, productFlags, category) + + return SalesDTO{ + Age: ageInDay, + Qty: e.UsageQty, + } +} + func ToSummaryDto(e []entity.MarketingDeliveryProduct) SummaryDTO { var totalSalesPrice, totalActualPrice, sumSales, sumActual float64 diff --git a/internal/modules/closings/services/closing.service.go b/internal/modules/closings/services/closing.service.go index bd068843..a3cfb2cc 100644 --- a/internal/modules/closings/services/closing.service.go +++ b/internal/modules/closings/services/closing.service.go @@ -841,7 +841,7 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch FCR standard data") } } - age, err := s.calculateAverageSalesAge(c.Context(), projectFlockID) + age, err := s.calculateAverageSalesAge(c.Context(), projectFlockID, kandangID) if err != nil { s.Log.Errorf("Failed to calculate sales age for project flock %d: %+v", projectFlockID, err) return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch sales age data") @@ -1028,38 +1028,24 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint return &result, nil } -func (s closingService) calculateAverageSalesAge(ctx context.Context, projectFlockID uint) (float64, error) { - deliveryProducts, err := s.MarketingDeliveryProductRepo.GetDeliveryProductsByProjectFlockID(ctx, projectFlockID, func(db *gorm.DB) *gorm.DB { - return db. - Preload("MarketingProduct"). - Preload("MarketingProduct.ProductWarehouse"). - Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang"). - Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins") - }) +func (s closingService) calculateAverageSalesAge(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) (float64, error) { + penjualan, err := s.MarketingDeliveryProductRepo.GetClosingPenjualanForAgeChickDataProduction(ctx, projectFlockID, projectFlockKandangID) if err != nil { return 0, err } - - var ( - totalQty float64 - totalAgeWeeks float64 - ) - - for _, product := range deliveryProducts { - if product.UsageQty == 0 { - continue - } - projectFlockKandang := product.MarketingProduct.ProductWarehouse.ProjectFlockKandang - ageWeeks := dto.CalculateAgeFromChickinDataProduksi(projectFlockKandang, product.DeliveryDate) - totalAgeWeeks += float64(ageWeeks) * product.UsageQty - totalQty += product.UsageQty + acumulateAgeQty := 0.0 + totalQty := 0.0 + for _, v := range penjualan { + sale := dto.ToSalesAgeDTO(v) + acumulateAgeQty += float64(sale.Age) * sale.Qty + totalQty += sale.Qty + } + if totalQty > 0 { + averageAge := acumulateAgeQty / totalQty + return averageAge, nil } - if totalQty == 0 { - return 0, nil - } - - return totalAgeWeeks / totalQty, nil + return 0, err } func (s closingService) determineProductionWeek(ctx context.Context, projectFlockKandangIDs []uint) (int, error) { diff --git a/internal/modules/marketing/repositories/salesorder_delivery_product.repository.go b/internal/modules/marketing/repositories/salesorder_delivery_product.repository.go index 231c00d4..17394b80 100644 --- a/internal/modules/marketing/repositories/salesorder_delivery_product.repository.go +++ b/internal/modules/marketing/repositories/salesorder_delivery_product.repository.go @@ -22,6 +22,7 @@ type MarketingDeliveryProductRepository interface { UpdateFifoFields(ctx context.Context, id uint, usageQty, pendingQty float64) error GetUsageQty(ctx context.Context, id uint) (float64, error) ResetFifoFields(ctx context.Context, id uint) error + GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error) } type MarketingDeliveryProductRepositoryImpl struct { @@ -93,6 +94,46 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualan(ctx context return deliveryProducts, nil } +func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error) { + var deliveryProducts []entity.MarketingDeliveryProduct + + db := r.DB().WithContext(ctx). + Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id"). + Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id"). + Joins("JOIN products ON products.id = product_warehouses.product_id"). + Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = 'products'"). + Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id"). + Where("project_flock_kandangs.project_flock_id = ?", projectFlockID). + Where("flags.name IN (?)", []string{ + string(utils.FlagAyamAfkir), + string(utils.FlagAyamCulling), + string(utils.FlagPullet), + string(utils.FlagLayer), + }). + Where("marketing_delivery_products.delivery_date IS NOT NULL"). + Distinct("marketing_delivery_products.*") + + if projectFlockKandangID != nil { + db = db.Where("product_warehouses.project_flock_kandang_id = ?", *projectFlockKandangID) + } + + db = db. + Preload("MarketingProduct"). + Preload("MarketingProduct.ProductWarehouse"). + Preload("MarketingProduct.ProductWarehouse.Product"). + Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory"). + Preload("MarketingProduct.ProductWarehouse.Product.Flags"). + Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang"). + Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins"). + Order("marketing_delivery_products.delivery_date DESC") + + if err := db.Find(&deliveryProducts).Error; err != nil { + return nil, err + } + + return deliveryProducts, nil +} + func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanByCategory(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint, category string) ([]entity.MarketingDeliveryProduct, error) { var deliveryProducts []entity.MarketingDeliveryProduct