From 89293a843e566d852938716790de14dd18994a27 Mon Sep 17 00:00:00 2001 From: giovanni Date: Thu, 15 Jan 2026 16:07:45 +0700 Subject: [PATCH] adjust api hpp kandang --- .../modules/repports/dto/repportHpp.dto.go | 58 +++---- .../hpp_per_kandang.repository.go | 160 +++++++++++++----- .../repports/services/repport.service.go | 108 +++++++++--- 3 files changed, 227 insertions(+), 99 deletions(-) diff --git a/internal/modules/repports/dto/repportHpp.dto.go b/internal/modules/repports/dto/repportHpp.dto.go index 63c5dce9..f790244c 100644 --- a/internal/modules/repports/dto/repportHpp.dto.go +++ b/internal/modules/repports/dto/repportHpp.dto.go @@ -25,14 +25,12 @@ type HppPerKandangResponseData struct { } type HppPerKandangRowDTO struct { - ID int `json:"id"` - Kandang HppPerKandangRowKandangDTO `json:"kandang"` - WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"` - RemainingChickenBirds int64 `json:"remaining_chicken_birds"` - RemainingChickenWeightKg float64 `json:"remaining_chicken_weight_kg"` - AvgWeightKg float64 `json:"avg_weight_kg"` - EggProductionPieces int64 `json:"egg_production_pieces"` - EggProductionKg float64 `json:"egg_production_kg"` + ID int `json:"id"` + Kandang HppPerKandangRowKandangDTO `json:"kandang"` + WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"` + AvgWeightKg float64 `json:"avg_weight_kg"` + EggProductionPieces int64 `json:"egg_production_pieces"` + EggProductionKg float64 `json:"egg_production_kg"` // FeedCostRp float64 `json:"feed_cost_rp"` // OvkCostRp float64 `json:"ovk_cost_rp"` EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"` @@ -80,34 +78,28 @@ type HppPerKandangSummaryDTO struct { } type HppPerKandangSummaryWeightRangeDTO struct { - ID int `json:"id"` - WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"` - Label string `json:"label"` - RemainingChickenBirds int64 `json:"remaining_chicken_birds"` - RemainingChickenWeightKg float64 `json:"remaining_chicken_weight_kg"` - AvgWeightKg float64 `json:"avg_weight_kg"` - EggProductionPieces int64 `json:"egg_production_pieces"` - EggProductionKg float64 `json:"egg_production_kg"` - EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"` - EggValueRp int64 `json:"egg_value_rp"` - FeedSuppliers []HppPerKandangSupplierDTO `json:"feed_suppliers"` - DocSuppliers []HppPerKandangSupplierDTO `json:"doc_suppliers"` - AverageDocPriceRp float64 `json:"average_doc_price_rp"` - HppRp float64 `json:"hpp_rp"` - RemainingValueRp int64 `json:"remaining_value_rp"` + ID int `json:"id"` + WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"` + Label string `json:"label"` + AvgWeightKg float64 `json:"avg_weight_kg"` + EggProductionPieces int64 `json:"egg_production_pieces"` + EggProductionKg float64 `json:"egg_production_kg"` + EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"` + EggValueRp int64 `json:"egg_value_rp"` + FeedSuppliers []HppPerKandangSupplierDTO `json:"feed_suppliers"` + DocSuppliers []HppPerKandangSupplierDTO `json:"doc_suppliers"` + AverageDocPriceRp float64 `json:"average_doc_price_rp"` + HppRp float64 `json:"hpp_rp"` + RemainingValueRp int64 `json:"remaining_value_rp"` } type HppPerKandangSummaryTotalDTO struct { - TotalRemainingChickenBirds int64 `json:"total_remaining_chicken_birds"` - TotalRemainingChickenWeightKg float64 `json:"total_remaining_chicken_weight_kg"` - AverageWeightKg float64 `json:"average_weight_kg"` - TotalRemainingValueRp int64 `json:"total_remaining_value_rp"` - TotalEggProductionPieces int64 `json:"total_egg_production_pieces"` - TotalEggProductionKg float64 `json:"total_egg_production_kg"` - AverageEggHppRpPerKg float64 `json:"average_egg_hpp_rp_per_kg"` - TotalEggValueRp int64 `json:"total_egg_value_rp"` - TotalHppRp float64 `json:"total_hpp_rp"` - TotalAverageDocPriceRp float64 `json:"total_average_doc_price_rp"` + AverageWeightKg float64 `json:"average_weight_kg"` + TotalEggProductionPieces int64 `json:"total_egg_production_pieces"` + TotalEggProductionKg float64 `json:"total_egg_production_kg"` + AverageEggHppRpPerKg float64 `json:"average_egg_hpp_rp_per_kg"` + TotalEggValueRp int64 `json:"total_egg_value_rp"` + TotalAverageDocPriceRp float64 `json:"total_average_doc_price_rp"` } func NewHppPerKandangFiltersDTO(area, location, kandang, weightMin, weightMax, period, showUnrecorded string) HppPerKandangFiltersDTO { diff --git a/internal/modules/repports/repositories/hpp_per_kandang.repository.go b/internal/modules/repports/repositories/hpp_per_kandang.repository.go index 4bd9aab4..64676ca8 100644 --- a/internal/modules/repports/repositories/hpp_per_kandang.repository.go +++ b/internal/modules/repports/repositories/hpp_per_kandang.repository.go @@ -11,6 +11,7 @@ import ( ) type HppPerKandangRow struct { + ProjectFlockKandangID uint KandangID uint KandangName string KandangStatus string @@ -18,6 +19,7 @@ type HppPerKandangRow struct { LocationName string PicID uint PicName string + RecordingCount int64 RemainingChickenBirds float64 RemainingChickenWeight float64 EggProductionWeightKg float64 @@ -44,7 +46,8 @@ type HppPerKandangSupplierRow struct { type HppPerKandangRepository interface { GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error) - GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) + GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) + GetEggProductionByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error) } type hppPerKandangRepository struct { @@ -58,9 +61,31 @@ func NewHppPerKandangRepository(db *gorm.DB) HppPerKandangRepository { func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error) { var rows []HppPerKandangRow - query := r.db.WithContext(ctx). + latestApproval := r.db.WithContext(ctx). + Table("approvals AS a"). + Select("a.approvable_id, a.action"). + Joins(` + JOIN ( + SELECT approvable_id, MAX(action_at) AS latest_action_at + FROM approvals + WHERE approvable_type = ? + GROUP BY approvable_id + ) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`, + string(utils.ApprovalWorkflowRecording), + ) + + validRecordings := r.db.WithContext(ctx). Table("recordings AS r"). + Select("r.id, r.project_flock_kandangs_id, r.total_chick_qty"). + Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval). + Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.deleted_at IS NULL"). + Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)) + + query := r.db.WithContext(ctx). + Table("project_flocks AS pf"). Select(` + pfk.id AS project_flock_kandang_id, k.id AS kandang_id, k.name AS kandang_name, k.status AS kandang_status, @@ -68,22 +93,21 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en loc.name AS location_name, pic.id AS pic_id, pic.name AS pic_name, - COALESCE(MAX(r.total_chick_qty), 0) AS remaining_chicken_birds, - COALESCE(SUM(rbw.total_weight), 0) AS remaining_chicken_weight, - COALESCE(SUM(re.weight), 0) AS egg_production_weight_kg, - COALESCE(SUM(re.qty), 0) AS egg_production_pieces`). - Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id"). + COALESCE(COUNT(vr.id), 0) AS recording_count, + COALESCE(MAX(vr.total_chick_qty), 0) AS remaining_chicken_birds, + 0 AS remaining_chicken_weight, + 0 AS egg_production_weight_kg, + 0 AS egg_production_pieces`). + Joins("JOIN project_flock_kandangs AS pfk ON pfk.project_flock_id = pf.id"). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). Joins("JOIN locations AS loc ON loc.id = k.location_id"). Joins("JOIN users AS pic ON pic.id = k.pic_id"). - Joins("LEFT JOIN recording_bws AS rbw ON rbw.recording_id = r.id"). - Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id"). - Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). - Where("r.deleted_at IS NULL") + Joins("LEFT JOIN (?) AS vr ON vr.project_flock_kandangs_id = pfk.id", validRecordings). + Where("pfk.closed_at IS NULL") query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs) - query = query.Group("k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name"). + query = query.Group("pfk.id, k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name"). Order("k.id ASC") if err := query.Scan(&rows).Error; err != nil { @@ -93,41 +117,44 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en return rows, nil } -func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) { +func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) { var rows []HppPerKandangCostRow - recordingPfk := r.db.WithContext(ctx). - Table("recordings AS r"). - Select("DISTINCT pfk.id"). - Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id"). - Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). - Joins("JOIN locations AS loc ON loc.id = k.location_id"). - Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). - Where("r.deleted_at IS NULL") - recordingPfk = applyLocationFilters(recordingPfk, areaIDs, locationIDs, kandangIDs) - purchaseStockableKey := fifo.StockableKeyPurchaseItems.String() transferStockableKey := fifo.StockableKeyStockTransferIn.String() + latestApproval := r.db.WithContext(ctx). + Table("approvals AS a"). + Select("a.approvable_id, a.action"). + Joins(` + JOIN ( + SELECT approvable_id, MAX(action_at) AS latest_action_at + FROM approvals + WHERE approvable_type = ? + GROUP BY approvable_id + ) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`, + string(utils.ApprovalWorkflowRecording), + ) + query := r.db.WithContext(ctx). Table("recordings AS r"). Select(` k.id AS kandang_id, COALESCE(SUM(CASE WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0) - WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0) + WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.total_qty, 0) * COALESCE(tpi.price, 0) ELSE 0 END), 0) AS feed_cost, COALESCE(SUM(CASE WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0) - WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0) + WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.total_qty, 0) * COALESCE(tpi.price, 0) ELSE 0 END), 0) AS ovk_cost`, utils.FlagPakan, transferStockableKey, utils.FlagPakan, utils.FlagOVK, transferStockableKey, utils.FlagOVK). Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id"). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). - Joins("JOIN locations AS loc ON loc.id = k.location_id"). + Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval). Joins("LEFT JOIN recording_stocks AS rs ON rs.recording_id = r.id"). Joins("LEFT JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.status = ?", fifo.UsableKeyRecordingStock.String(), entity.StockAllocationStatusActive). Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", purchaseStockableKey). @@ -136,11 +163,10 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, Joins("LEFT JOIN purchase_items AS tpi ON tpi.product_id = std.product_id AND tpi.warehouse_id = st.from_warehouse_id"). Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct). Joins("LEFT JOIN flags AS tf ON tf.flagable_id = std.product_id AND tf.flagable_type = ?", entity.FlagableTypeProduct). - Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})). - Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). - Where("r.deleted_at IS NULL") - - query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs) + Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs). + // Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.deleted_at IS NULL"). + Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)) query = query.Group("k.id").Order("k.id ASC") @@ -172,9 +198,8 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, Joins("LEFT JOIN purchase_items AS pi ON pi.product_warehouse_id = pc.product_warehouse_id"). Joins("LEFT JOIN purchases AS pur ON pur.id = pi.purchase_id"). Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id"). - Where("pc.project_flock_kandang_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})). + Where("pc.project_flock_kandang_id IN ?", projectFlockKandangIDs). Group("pfk.kandang_id, s.id, s.name, s.alias") - docQuery = applyLocationFilters(docQuery, areaIDs, locationIDs, kandangIDs) if err := docQuery.Scan(&docRows).Error; err != nil { return nil, nil, err @@ -254,9 +279,9 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, Joins("JOIN project_budgets AS pb ON pb.project_flock_id = pfk.project_flock_id"). Joins("LEFT JOIN (?) AS k_usage ON k_usage.project_flock_kandang_id = pfk.id", pfkUsageSub). Joins("LEFT JOIN (?) AS p_usage ON p_usage.project_flock_id = pfk.project_flock_id", projectUsageSub). - Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})). + Where("pfk.id IN (?)", projectFlockKandangIDs). Group("k.id") - budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs) + // budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs) if err := budgetQuery.Scan(&budgetRows).Error; err != nil { return nil, nil, err @@ -288,9 +313,9 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, Joins("JOIN locations AS loc ON loc.id = k.location_id"). Joins("JOIN expense_nonstocks AS en ON en.project_flock_kandang_id = pfk.id"). Joins("JOIN expense_realizations AS er ON er.expense_nonstock_id = en.id"). - Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})). + Where("pfk.id IN (?)", projectFlockKandangIDs). Group("k.id") - expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs) + // expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs) if err := expenseQuery.Scan(&expenseRows).Error; err != nil { return nil, nil, err @@ -323,10 +348,10 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id"). Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct). Where("f.name IN ?", []utils.FlagType{utils.FlagPakan, utils.FlagOVK}). - Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})). - Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs). + // Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). Where("r.deleted_at IS NULL") - feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs) + // feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs) if err := feedQuery.Scan(&feedSuppliers).Error; err != nil { return nil, nil, err @@ -347,6 +372,61 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, return rows, supplierRows, nil } +func (r *hppPerKandangRepository) GetEggProductionByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error) { + if len(projectFlockKandangIDs) == 0 { + return map[uint]HppPerKandangRow{}, nil + } + + latestApproval := r.db.WithContext(ctx). + Table("approvals AS a"). + Select("a.approvable_id, a.action"). + Joins(` + JOIN ( + SELECT approvable_id, MAX(action_at) AS latest_action_at + FROM approvals + WHERE approvable_type = ? + GROUP BY approvable_id + ) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`, + string(utils.ApprovalWorkflowRecording), + ) + + type eggRow struct { + ProjectFlockKandangID uint + EggProductionWeightKg float64 + EggProductionPieces float64 + } + + eggRows := make([]eggRow, 0) + query := r.db.WithContext(ctx). + Table("recordings AS r"). + Select(` + r.project_flock_kandangs_id AS project_flock_kandang_id, + COALESCE(SUM(re.weight), 0) AS egg_production_weight_kg, + COALESCE(SUM(re.qty), 0) AS egg_production_pieces`). + Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval). + Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id"). + Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs). + // Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.deleted_at IS NULL"). + Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)). + Group("r.project_flock_kandangs_id") + + if err := query.Scan(&eggRows).Error; err != nil { + return nil, err + } + + result := make(map[uint]HppPerKandangRow, len(eggRows)) + for _, row := range eggRows { + result[row.ProjectFlockKandangID] = HppPerKandangRow{ + ProjectFlockKandangID: row.ProjectFlockKandangID, + EggProductionWeightKg: row.EggProductionWeightKg, + EggProductionPieces: row.EggProductionPieces, + } + } + + return result, nil +} + func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int64) *gorm.DB { if len(areaIDs) > 0 { query = query.Where("loc.area_id IN ?", areaIDs) diff --git a/internal/modules/repports/services/repport.service.go b/internal/modules/repports/services/repport.service.go index c4883b72..9be8d8c4 100644 --- a/internal/modules/repports/services/repport.service.go +++ b/internal/modules/repports/services/repport.service.go @@ -972,10 +972,37 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes if err != nil { return nil, nil, err } - costRows, supplierRows, err := s.HppPerKandangRepo.GetFeedOvkDocCostByPeriod(ctx.Context(), startOfDay, endOfDay, params.AreaIDs, params.LocationIDs, params.KandangIDs) - if err != nil { - return nil, nil, err + + validPfkIDs := make([]uint, 0, len(repoRows)) + pfkIndex := make(map[uint]int, len(repoRows)) + for idx := range repoRows { + row := repoRows[idx] + pfkIndex[row.ProjectFlockKandangID] = idx + if row.RecordingCount > 0 { + validPfkIDs = append(validPfkIDs, row.ProjectFlockKandangID) + } } + + costRows := make([]repportRepo.HppPerKandangCostRow, 0) + supplierRows := make([]repportRepo.HppPerKandangSupplierRow, 0) + if len(validPfkIDs) > 0 { + costRows, supplierRows, err = s.HppPerKandangRepo.GetFeedOvkDocCostByPeriod(ctx.Context(), startOfDay, endOfDay, validPfkIDs) + if err != nil { + return nil, nil, err + } + + eggMap, err := s.HppPerKandangRepo.GetEggProductionByProjectFlockKandangIDs(ctx.Context(), startOfDay, endOfDay, validPfkIDs) + if err != nil { + return nil, nil, err + } + for pfkID, egg := range eggMap { + if rowIdx, ok := pfkIndex[pfkID]; ok { + repoRows[rowIdx].EggProductionWeightKg = egg.EggProductionWeightKg + repoRows[rowIdx].EggProductionPieces = egg.EggProductionPieces + } + } + } + costMap := make(map[uint]HppCostAggregate, len(costRows)) for _, row := range costRows { costMap[row.KandangID] = HppCostAggregate{ @@ -1028,9 +1055,13 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes Max float64 } type weightRangeAggregate struct { - Summary *dto.HppPerKandangSummaryWeightRangeDTO - EggHppSum float64 - EggHppCount int + Summary *dto.HppPerKandangSummaryWeightRangeDTO + RemainingBirds int64 + RemainingWeightKg float64 + EggHppSum float64 + EggHppCount int + FeedSuppliers map[int64]dto.HppPerKandangSupplierDTO + DocSuppliers map[int64]dto.HppPerKandangSupplierDTO } dataRows := make([]dto.HppPerKandangRowDTO, 0, len(repoRows)) @@ -1049,6 +1080,10 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes var totalEggHppCount int for _, row := range repoRows { + if !params.ShowUnrecorded && row.RecordingCount == 0 { + continue + } + birdsFloat := row.RemainingChickenBirds if math.IsNaN(birdsFloat) || math.IsInf(birdsFloat, 0) { birdsFloat = 0 @@ -1067,9 +1102,16 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes } avgWeight := 0.0 - if birdsFloat > 0 { - avgWeight = weightFloat / birdsFloat + if eggPiecesFloat > 0 { + avgWeight = eggWeightFloat / eggPiecesFloat } + if params.WeightMin != nil && avgWeight < *params.WeightMin { + continue + } + if params.WeightMax != nil && avgWeight > *params.WeightMax { + continue + } + weightMin := math.Floor(avgWeight*10) / 10 if weightMin < 0 { weightMin = 0 @@ -1116,9 +1158,7 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes WeightMin: weightMin, WeightMax: weightMax, }, - RemainingChickenBirds: rowBirds, - RemainingChickenWeightKg: weightFloat, - AvgWeightKg: avgWeight, + AvgWeightKg: avgWeight, // FeedCostRp: costEntry.FeedCost, // OvkCostRp: costEntry.OvkCost, DocSuppliers: docSupplierMap[row.KandangID], @@ -1126,10 +1166,10 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes EggProductionPieces: rowEggPieces, EggProductionKg: eggWeightFloat, AverageDocPriceRp: avgDocPrice, - HppRp: hppRp, - EggHppRpPerKg: eggHpp, - RemainingValueRp: rowRemainingValue, - EggValueRp: rowEggValue, + // HppRp: hppRp, + EggHppRpPerKg: eggHpp, + RemainingValueRp: rowRemainingValue, + EggValueRp: rowEggValue, }) totalBirds += rowBirds @@ -1161,13 +1201,25 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes }, Label: fmt.Sprintf("%.2f - %.2f", weightMin, weightMax), }, + FeedSuppliers: make(map[int64]dto.HppPerKandangSupplierDTO), + DocSuppliers: make(map[int64]dto.HppPerKandangSupplierDTO), } perRangeMap[rangeKey] = rangeAgg } rangeSummary := rangeAgg.Summary - rangeSummary.RemainingChickenBirds += rowBirds - rangeSummary.RemainingChickenWeightKg += row.RemainingChickenWeight + rangeAgg.RemainingBirds += rowBirds + rangeAgg.RemainingWeightKg += row.RemainingChickenWeight + for _, supplier := range feedSupplierMap[row.KandangID] { + if _, ok := rangeAgg.FeedSuppliers[supplier.ID]; !ok { + rangeAgg.FeedSuppliers[supplier.ID] = supplier + } + } + for _, supplier := range docSupplierMap[row.KandangID] { + if _, ok := rangeAgg.DocSuppliers[supplier.ID]; !ok { + rangeAgg.DocSuppliers[supplier.ID] = supplier + } + } rangeSummary.EggProductionPieces += rowEggPieces rangeSummary.EggProductionKg += eggWeightFloat rangeSummary.RemainingValueRp += rowRemainingValue @@ -1194,22 +1246,27 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes agg := perRangeMap[key] entry := agg.Summary entry.ID = idx + 1 - if entry.RemainingChickenBirds > 0 { - entry.AvgWeightKg = entry.RemainingChickenWeightKg / float64(entry.RemainingChickenBirds) + if agg.RemainingBirds > 0 { + entry.AvgWeightKg = agg.RemainingWeightKg / float64(agg.RemainingBirds) } if agg.EggHppCount > 0 { entry.EggHppRpPerKg = agg.EggHppSum / float64(agg.EggHppCount) } + entry.FeedSuppliers = make([]dto.HppPerKandangSupplierDTO, 0, len(agg.FeedSuppliers)) + for _, supplier := range agg.FeedSuppliers { + entry.FeedSuppliers = append(entry.FeedSuppliers, supplier) + } + entry.DocSuppliers = make([]dto.HppPerKandangSupplierDTO, 0, len(agg.DocSuppliers)) + for _, supplier := range agg.DocSuppliers { + entry.DocSuppliers = append(entry.DocSuppliers, supplier) + } perRangeSummary = append(perRangeSummary, *entry) } totalSummary := dto.HppPerKandangSummaryTotalDTO{ - TotalRemainingChickenBirds: totalBirds, - TotalRemainingChickenWeightKg: totalWeight, - TotalEggProductionPieces: totalEggPieces, - TotalEggProductionKg: totalEggKg, - TotalRemainingValueRp: totalRemainingValueRp, - TotalEggValueRp: totalEggValueRp, + TotalEggProductionPieces: totalEggPieces, + TotalEggProductionKg: totalEggKg, + TotalEggValueRp: totalEggValueRp, } if totalBirds > 0 { totalSummary.AverageWeightKg = totalWeight / float64(totalBirds) @@ -1218,7 +1275,6 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes totalSummary.AverageEggHppRpPerKg = totalEggHppSum / float64(totalEggHppCount) } if totalHppCount > 0 { - totalSummary.TotalHppRp = totalHppSum / float64(totalHppCount) } if totalDocPriceCount > 0 { totalSummary.TotalAverageDocPriceRp = totalDocPriceSum / float64(totalDocPriceCount)