From 71c62c5e0235a5d05792f0d318036c5f2f2c0c9e Mon Sep 17 00:00:00 2001 From: giovanni Date: Mon, 19 Jan 2026 16:19:47 +0700 Subject: [PATCH 1/2] [FIX][BE]: LSS390 --- .../dto/project_flock_kandang.dto.go | 14 +++ .../modules/repports/dto/repportHpp.dto.go | 6 +- .../hpp_per_kandang.repository.go | 71 +++++++----- .../repports/services/repport.service.go | 103 ++++++++++-------- 4 files changed, 121 insertions(+), 73 deletions(-) diff --git a/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go b/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go index 452cc7b3..c8faf761 100644 --- a/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go +++ b/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go @@ -1,6 +1,7 @@ package dto import ( + "strconv" "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" @@ -53,6 +54,7 @@ type ProjectFlockKandangListDTO struct { ProjectFlockKandangRelationDTO ProjectFlock *ProjectFlockDTO `json:"project_flock,omitempty"` Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"` + NameWithPeriod string `json:"name_with_period"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` CreatedAt time.Time `json:"created_at"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"` @@ -104,6 +106,7 @@ func ToProjectFlockKandangDetailDTOWithAvailableQty(e entity.ProjectFlockKandang ProjectFlockKandangRelationDTO: ToProjectFlockKandangRelationDTO(e), ProjectFlock: toProjectFlockDTO(projectFlockSummary), Kandang: toKandangRelation(e.Kandang), + NameWithPeriod: toNameWithPeriod(e.Kandang, e.Period), CreatedAt: e.CreatedAt, CreatedUser: toCreatedUserDTO(e.ProjectFlock), Approval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestProjectFlockApproval }), @@ -126,6 +129,16 @@ func toKandangRelation(kandang entity.Kandang) *kandangDTO.KandangRelationDTO { return &mapped } +func toNameWithPeriod(kandang entity.Kandang, period int) string { + if kandang.Name == "" { + return "" + } + if period == 0 { + return kandang.Name + } + return kandang.Name + " Period " + strconv.Itoa(period) +} + func toApprovalDTOSelector( e entity.ProjectFlockKandang, selector func(entity.ProjectFlockKandang) *entity.Approval) *approvalDTO.ApprovalRelationDTO { approval := selector(e) @@ -147,6 +160,7 @@ func ToProjectFlockKandangListDTO(e entity.ProjectFlockKandang) ProjectFlockKand ProjectFlockKandangRelationDTO: ToProjectFlockKandangRelationDTO(e), ProjectFlock: toProjectFlockDTO(projectFlockSummary), Kandang: toKandangRelation(e.Kandang), + NameWithPeriod: toNameWithPeriod(e.Kandang, e.Period), CreatedAt: e.CreatedAt, CreatedUser: toCreatedUserDTO(e.ProjectFlock), Approval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestProjectFlockApproval }), diff --git a/internal/modules/repports/dto/repportHpp.dto.go b/internal/modules/repports/dto/repportHpp.dto.go index f790244c..15b6d51b 100644 --- a/internal/modules/repports/dto/repportHpp.dto.go +++ b/internal/modules/repports/dto/repportHpp.dto.go @@ -31,6 +31,8 @@ type HppPerKandangRowDTO struct { AvgWeightKg float64 `json:"avg_weight_kg"` EggProductionPieces int64 `json:"egg_production_pieces"` EggProductionKg float64 `json:"egg_production_kg"` + // EggProductionTotalWeightKg float64 `json:"egg_production_total_weight_kg"` + // EggProductionTotalPieces int64 `json:"egg_production_total_pieces"` // FeedCostRp float64 `json:"feed_cost_rp"` // OvkCostRp float64 `json:"ovk_cost_rp"` EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"` @@ -38,8 +40,8 @@ type HppPerKandangRowDTO struct { FeedSuppliers []HppPerKandangSupplierDTO `json:"feed_suppliers"` DocSuppliers []HppPerKandangSupplierDTO `json:"doc_suppliers"` AverageDocPriceRp int64 `json:"average_doc_price_rp"` - HppRp float64 `json:"hpp_rp"` - RemainingValueRp int64 `json:"remaining_value_rp"` + // HppRp float64 `json:"hpp_rp"` + // RemainingValueRp int64 `json:"remaining_value_rp"` } type HppPerKandangRowKandangDTO struct { diff --git a/internal/modules/repports/repositories/hpp_per_kandang.repository.go b/internal/modules/repports/repositories/hpp_per_kandang.repository.go index 64676ca8..37a37d45 100644 --- a/internal/modules/repports/repositories/hpp_per_kandang.repository.go +++ b/internal/modules/repports/repositories/hpp_per_kandang.repository.go @@ -11,19 +11,21 @@ import ( ) type HppPerKandangRow struct { - ProjectFlockKandangID uint - KandangID uint - KandangName string - KandangStatus string - LocationID uint - LocationName string - PicID uint - PicName string - RecordingCount int64 - RemainingChickenBirds float64 - RemainingChickenWeight float64 - EggProductionWeightKg float64 - EggProductionPieces float64 + ProjectFlockKandangID uint + KandangID uint + KandangName string + KandangStatus string + LocationID uint + LocationName string + PicID uint + PicName string + RecordingCount int64 + // RemainingChickenBirds float64 + // RemainingChickenWeight float64 + EggProductionWeightKgRemaining float64 + EggProductionPiecesRemaining float64 + EggProductionTotalWeightKg float64 + EggProductionTotalPieces float64 } type HppPerKandangCostRow struct { @@ -97,13 +99,22 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en 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`). + 0 AS egg_production_pieces, + 0 AS egg_production_total_weight_kg, + 0 AS egg_production_total_pieces`). Joins("JOIN project_flock_kandangs AS pfk ON pfk.project_flock_id = pf.id"). + Joins(` + LEFT JOIN ( + SELECT project_flock_kandang_id, MIN(chick_in_date) AS chick_in_date + FROM project_chickins + GROUP BY project_flock_kandang_id + ) AS pc ON pc.project_flock_kandang_id = pfk.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 (?) AS vr ON vr.project_flock_kandangs_id = pfk.id", validRecordings). - Where("pfk.closed_at IS NULL") + Where("pf.category = ?", utils.ProjectFlockCategoryLaying). + Where("(pfk.closed_at IS NULL OR ? BETWEEN pc.chick_in_date AND pfk.closed_at)", start) query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs) @@ -164,7 +175,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, 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 ?", projectFlockKandangIDs). - // Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.record_datetime < ?", end). Where("r.deleted_at IS NULL"). Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)) @@ -349,7 +360,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, 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 (?)", projectFlockKandangIDs). - // Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end). + Where("r.record_datetime < ?", end). Where("r.deleted_at IS NULL") // feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs) @@ -391,9 +402,11 @@ func (r *hppPerKandangRepository) GetEggProductionByProjectFlockKandangIDs(ctx c ) type eggRow struct { - ProjectFlockKandangID uint - EggProductionWeightKg float64 - EggProductionPieces float64 + ProjectFlockKandangID uint + EggProductionWeightKgRemaining float64 + EggProductionPiecesRemaining float64 + EggProductionTotalWeightKg float64 + EggProductionTotalPieces float64 } eggRows := make([]eggRow, 0) @@ -401,12 +414,14 @@ func (r *hppPerKandangRepository) GetEggProductionByProjectFlockKandangIDs(ctx c 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`). + COALESCE(SUM((re.total_qty - re.total_used) * re.weight / 1000), 0) AS egg_production_weight_kg_remaining, + COALESCE(SUM(re.total_qty - re.total_used), 0) AS egg_production_pieces_remaining, + COALESCE(SUM(re.weight / 1000), 0) AS egg_production_total_weight_kg, + COALESCE(SUM(re.total_qty), 0) AS egg_production_total_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.record_datetime < ?", end). Where("r.deleted_at IS NULL"). Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)). Group("r.project_flock_kandangs_id") @@ -418,9 +433,11 @@ func (r *hppPerKandangRepository) GetEggProductionByProjectFlockKandangIDs(ctx c result := make(map[uint]HppPerKandangRow, len(eggRows)) for _, row := range eggRows { result[row.ProjectFlockKandangID] = HppPerKandangRow{ - ProjectFlockKandangID: row.ProjectFlockKandangID, - EggProductionWeightKg: row.EggProductionWeightKg, - EggProductionPieces: row.EggProductionPieces, + ProjectFlockKandangID: row.ProjectFlockKandangID, + EggProductionWeightKgRemaining: row.EggProductionWeightKgRemaining, + EggProductionPiecesRemaining: row.EggProductionPiecesRemaining, + EggProductionTotalWeightKg: row.EggProductionTotalWeightKg, + EggProductionTotalPieces: row.EggProductionTotalPieces, } } @@ -435,7 +452,7 @@ func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int query = query.Where("k.location_id IN ?", locationIDs) } if len(kandangIDs) > 0 { - query = query.Where("k.id IN ?", kandangIDs) + query = query.Where("pfk.id IN ?", kandangIDs) } return query } diff --git a/internal/modules/repports/services/repport.service.go b/internal/modules/repports/services/repport.service.go index 2e07e212..9c0c600f 100644 --- a/internal/modules/repports/services/repport.service.go +++ b/internal/modules/repports/services/repport.service.go @@ -1370,8 +1370,10 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes } for pfkID, egg := range eggMap { if rowIdx, ok := pfkIndex[pfkID]; ok { - repoRows[rowIdx].EggProductionWeightKg = egg.EggProductionWeightKg - repoRows[rowIdx].EggProductionPieces = egg.EggProductionPieces + repoRows[rowIdx].EggProductionWeightKgRemaining = egg.EggProductionWeightKgRemaining + repoRows[rowIdx].EggProductionPiecesRemaining = egg.EggProductionPiecesRemaining + repoRows[rowIdx].EggProductionTotalWeightKg = egg.EggProductionTotalWeightKg + repoRows[rowIdx].EggProductionTotalPieces = egg.EggProductionTotalPieces } } } @@ -1442,12 +1444,12 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes dataRows := make([]dto.HppPerKandangRowDTO, 0, len(repoRows)) perRangeMap := make(map[weightRangeKey]*weightRangeAggregate) var totalBirds int64 - var totalWeight float64 + // var totalWeight float64 var totalEggPieces int64 var totalEggKg float64 - var totalRemainingValueRp int64 + // var totalRemainingValueRp int64 var totalEggValueRp int64 - var totalHppSum float64 + // var totalHppSum float64 var totalHppCount int var totalDocPriceSum float64 var totalDocPriceCount int @@ -1461,26 +1463,34 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes continue } - birdsFloat := row.RemainingChickenBirds - if math.IsNaN(birdsFloat) || math.IsInf(birdsFloat, 0) { - birdsFloat = 0 + // birdsFloat := row.RemainingChickenBirds + // if math.IsNaN(birdsFloat) || math.IsInf(birdsFloat, 0) { + // birdsFloat = 0 + // } + // weightFloat := row.RemainingChickenWeight + // if math.IsNaN(weightFloat) || math.IsInf(weightFloat, 0) { + // weightFloat = 0 + // } + eggPiecesFloatRemaining := row.EggProductionPiecesRemaining + if math.IsNaN(eggPiecesFloatRemaining) || math.IsInf(eggPiecesFloatRemaining, 0) { + eggPiecesFloatRemaining = 0 } - weightFloat := row.RemainingChickenWeight - if math.IsNaN(weightFloat) || math.IsInf(weightFloat, 0) { - weightFloat = 0 + eggTotalPiecesFloat := row.EggProductionTotalPieces + if math.IsNaN(eggTotalPiecesFloat) || math.IsInf(eggTotalPiecesFloat, 0) { + eggTotalPiecesFloat = 0 } - eggPiecesFloat := row.EggProductionPieces - if math.IsNaN(eggPiecesFloat) || math.IsInf(eggPiecesFloat, 0) { - eggPiecesFloat = 0 + eggRemainingWeightFloatRemaining := row.EggProductionWeightKgRemaining + if math.IsNaN(eggRemainingWeightFloatRemaining) || math.IsInf(eggRemainingWeightFloatRemaining, 0) { + eggRemainingWeightFloatRemaining = 0 } - eggWeightFloat := row.EggProductionWeightKg + eggWeightFloat := row.EggProductionTotalWeightKg if math.IsNaN(eggWeightFloat) || math.IsInf(eggWeightFloat, 0) { eggWeightFloat = 0 } avgWeight := 0.0 - if eggPiecesFloat > 0 { - avgWeight = eggWeightFloat / eggPiecesFloat + if eggTotalPiecesFloat > 0 { + avgWeight = eggWeightFloat / eggTotalPiecesFloat } if params.WeightMin != nil && avgWeight < *params.WeightMin { continue @@ -1496,21 +1506,21 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes weightMax := weightMin + 0.09 rangeKey := weightRangeKey{Min: weightMin, Max: weightMax} - rowBirds := int64(math.Round(birdsFloat)) + // rowBirds := int64(math.Round(birdsFloat)) costEntry := costMap[row.KandangID] totalCost := costEntry.FeedCost + costEntry.OvkCost + costEntry.DocCost + costEntry.BudgetCost + costEntry.ExpenseCost - hppRp := 0.0 - if weightFloat > 0 { - hppRp = totalCost / weightFloat - } + // hppRp := 0.0 + // if weightFloat > 0 { + // hppRp = totalCost / weightFloat + // } eggHpp := 0.0 if eggWeightFloat > 0 { - eggHpp = totalCost / eggWeightFloat + eggHpp = (totalCost / eggWeightFloat) / 1000 } - rowEggPieces := int64(math.Round(eggPiecesFloat)) - rowEggValue := int64(eggHpp * eggWeightFloat) - rowRemainingValue := int64(hppRp * weightFloat) + rowEggPieces := int64(math.Round(eggPiecesFloatRemaining)) + rowEggValue := int64(eggHpp * eggRemainingWeightFloatRemaining) + // rowRemainingValue := int64(hppRp * weightFloat) avgDocPrice := int64(0) if costEntry.DocQty > 0 { avgDocPrice = int64(math.Round(costEntry.DocCost / costEntry.DocQty)) @@ -1540,27 +1550,29 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes // OvkCostRp: costEntry.OvkCost, DocSuppliers: docSupplierMap[row.KandangID], FeedSuppliers: feedSupplierMap[row.KandangID], - EggProductionPieces: rowEggPieces, - EggProductionKg: eggWeightFloat, - AverageDocPriceRp: avgDocPrice, + EggProductionPieces: int64(math.Round(eggPiecesFloatRemaining)), + EggProductionKg: eggRemainingWeightFloatRemaining, + // EggProductionTotalWeightKg: eggWeightFloat, + // EggProductionTotalPieces: int64(math.Round(eggTotalPiecesFloat)), + AverageDocPriceRp: avgDocPrice, // HppRp: hppRp, - EggHppRpPerKg: eggHpp, - RemainingValueRp: rowRemainingValue, - EggValueRp: rowEggValue, + EggHppRpPerKg: eggHpp, + // RemainingValueRp: rowRemainingValue, + EggValueRp: rowEggValue, }) - totalBirds += rowBirds - totalWeight += weightFloat + // totalBirds += rowBirds + // totalWeight += weightFloat totalEggPieces += rowEggPieces - totalEggKg += eggWeightFloat - totalRemainingValueRp += rowRemainingValue + totalEggKg += eggRemainingWeightFloatRemaining + // totalRemainingValueRp += rowRemainingValue totalEggValueRp += rowEggValue totalAvgWeightSum += avgWeight totalAvgWeightCount++ - if weightFloat > 0 { - totalHppSum += hppRp - totalHppCount++ - } + // if weightFloat > 0 { + // totalHppSum += hppRp + // totalHppCount++ + // } if avgDocPrice > 0 { totalDocPriceSum += float64(avgDocPrice) totalDocPriceCount++ @@ -1587,8 +1599,8 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes } rangeSummary := rangeAgg.Summary - rangeAgg.RemainingBirds += rowBirds - rangeAgg.RemainingWeightKg += row.RemainingChickenWeight + // rangeAgg.RemainingBirds += rowBirds + // rangeAgg.RemainingWeightKg += row.RemainingChickenWeight rangeAgg.AvgWeightSum += avgWeight rangeAgg.AvgWeightCount++ for _, supplier := range feedSupplierMap[row.KandangID] { @@ -1602,8 +1614,8 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes } } rangeSummary.EggProductionPieces += rowEggPieces - rangeSummary.EggProductionKg += eggWeightFloat - rangeSummary.RemainingValueRp += rowRemainingValue + rangeSummary.EggProductionKg += eggRemainingWeightFloatRemaining + // rangeSummary.RemainingValueRp += rowRemainingValue rangeSummary.EggValueRp += rowEggValue if eggWeightFloat > 0 { rangeAgg.EggHppSum += eggHpp @@ -1750,6 +1762,9 @@ func (s *repportService) parseHppPerKandangQuery(ctx *fiber.Ctx) (*validation.Hp if err != nil { return nil, dto.HppPerKandangFiltersDTO{}, fiber.NewError(fiber.StatusBadRequest, err.Error()) } + if weightMin != nil && weightMax != nil && *weightMin > *weightMax { + return nil, dto.HppPerKandangFiltersDTO{}, fiber.NewError(fiber.StatusBadRequest, "weight_min must be less than or equal to weight_max") + } params := &validation.HppPerKandangQuery{ Page: page, From 3052497fc0538c17123c599d32bb6ad2471b07b0 Mon Sep 17 00:00:00 2001 From: giovanni Date: Mon, 19 Jan 2026 17:05:43 +0700 Subject: [PATCH 2/2] adjust grouping by project flock kandang --- .../modules/repports/dto/repportHpp.dto.go | 1 + .../hpp_per_kandang.repository.go | 112 +++++++++--------- .../repports/services/repport.service.go | 29 +++-- 3 files changed, 74 insertions(+), 68 deletions(-) diff --git a/internal/modules/repports/dto/repportHpp.dto.go b/internal/modules/repports/dto/repportHpp.dto.go index 15b6d51b..dc0b81d4 100644 --- a/internal/modules/repports/dto/repportHpp.dto.go +++ b/internal/modules/repports/dto/repportHpp.dto.go @@ -27,6 +27,7 @@ type HppPerKandangResponseData struct { type HppPerKandangRowDTO struct { ID int `json:"id"` Kandang HppPerKandangRowKandangDTO `json:"kandang"` + NameWithPeriode string `json:"name_with_periode"` WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"` AvgWeightKg float64 `json:"avg_weight_kg"` EggProductionPieces int64 `json:"egg_production_pieces"` diff --git a/internal/modules/repports/repositories/hpp_per_kandang.repository.go b/internal/modules/repports/repositories/hpp_per_kandang.repository.go index 37a37d45..1135efbf 100644 --- a/internal/modules/repports/repositories/hpp_per_kandang.repository.go +++ b/internal/modules/repports/repositories/hpp_per_kandang.repository.go @@ -12,6 +12,7 @@ import ( type HppPerKandangRow struct { ProjectFlockKandangID uint + ProjectFlockPeriod int KandangID uint KandangName string KandangStatus string @@ -29,21 +30,21 @@ type HppPerKandangRow struct { } type HppPerKandangCostRow struct { - KandangID uint - FeedCost float64 - OvkCost float64 - DocCost float64 - DocQty float64 - BudgetCost float64 - ExpenseCost float64 + ProjectFlockKandangID uint + FeedCost float64 + OvkCost float64 + DocCost float64 + DocQty float64 + BudgetCost float64 + ExpenseCost float64 } type HppPerKandangSupplierRow struct { - KandangID uint - SupplierID uint - SupplierName string - SupplierAlias string - Category string + ProjectFlockKandangID uint + SupplierID uint + SupplierName string + SupplierAlias string + Category string } type HppPerKandangRepository interface { @@ -88,6 +89,7 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en Table("project_flocks AS pf"). Select(` pfk.id AS project_flock_kandang_id, + pfk.period AS project_flock_period, k.id AS kandang_id, k.name AS kandang_name, k.status AS kandang_status, @@ -118,8 +120,8 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs) - query = query.Group("pfk.id, k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name"). - Order("k.id ASC") + query = query.Group("pfk.id, pfk.period, k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name"). + Order("pfk.id ASC") if err := query.Scan(&rows).Error; err != nil { return nil, err @@ -150,7 +152,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, query := r.db.WithContext(ctx). Table("recordings AS r"). Select(` - k.id AS kandang_id, + pfk.id AS project_flock_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.total_qty, 0) * COALESCE(tpi.price, 0) @@ -179,25 +181,25 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, 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") + query = query.Group("pfk.id").Order("pfk.id ASC") if err := query.Scan(&rows).Error; err != nil { return nil, nil, err } docRows := make([]struct { - KandangID uint - DocCost float64 - DocQty float64 - SupplierID *uint - SupplierName *string - SupplierAlias *string + ProjectFlockKandangID uint + DocCost float64 + DocQty float64 + SupplierID *uint + SupplierName *string + SupplierAlias *string }, 0) docQuery := r.db.WithContext(ctx). Table("project_chickins AS pc"). Select(` - pfk.kandang_id AS kandang_id, + pfk.id AS project_flock_kandang_id, COALESCE(SUM(pc.usage_qty * COALESCE(pi.price, 0)), 0) AS doc_cost, COALESCE(SUM(pc.usage_qty), 0) AS doc_qty, s.id AS supplier_id, @@ -210,7 +212,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, 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 ?", projectFlockKandangIDs). - Group("pfk.kandang_id, s.id, s.name, s.alias") + Group("pfk.id, s.id, s.name, s.alias") if err := docQuery.Scan(&docRows).Error; err != nil { return nil, nil, err @@ -219,28 +221,28 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, costMap := make(map[uint]*HppPerKandangCostRow, len(rows)) for i := range rows { row := rows[i] - costMap[row.KandangID] = &rows[i] + costMap[row.ProjectFlockKandangID] = &rows[i] } docSuppliers := make([]HppPerKandangSupplierRow, 0) docSeen := make(map[uint]map[uint]bool) for _, doc := range docRows { - entry, ok := costMap[doc.KandangID] + entry, ok := costMap[doc.ProjectFlockKandangID] if !ok { rows = append(rows, HppPerKandangCostRow{ - KandangID: doc.KandangID, + ProjectFlockKandangID: doc.ProjectFlockKandangID, }) entry = &rows[len(rows)-1] - costMap[doc.KandangID] = entry + costMap[doc.ProjectFlockKandangID] = entry } entry.DocCost += doc.DocCost entry.DocQty += doc.DocQty if doc.SupplierID != nil { - if docSeen[doc.KandangID] == nil { - docSeen[doc.KandangID] = make(map[uint]bool) + if docSeen[doc.ProjectFlockKandangID] == nil { + docSeen[doc.ProjectFlockKandangID] = make(map[uint]bool) } - if !docSeen[doc.KandangID][*doc.SupplierID] { - docSeen[doc.KandangID][*doc.SupplierID] = true + if !docSeen[doc.ProjectFlockKandangID][*doc.SupplierID] { + docSeen[doc.ProjectFlockKandangID][*doc.SupplierID] = true supplierName := "" if doc.SupplierName != nil { supplierName = *doc.SupplierName @@ -250,19 +252,19 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, supplierAlias = *doc.SupplierAlias } docSuppliers = append(docSuppliers, HppPerKandangSupplierRow{ - KandangID: doc.KandangID, - SupplierID: *doc.SupplierID, - SupplierName: supplierName, - SupplierAlias: supplierAlias, - Category: "DOC", + ProjectFlockKandangID: doc.ProjectFlockKandangID, + SupplierID: *doc.SupplierID, + SupplierName: supplierName, + SupplierAlias: supplierAlias, + Category: "DOC", }) } } } budgetRows := make([]struct { - KandangID uint - BudgetCost float64 + ProjectFlockKandangID uint + BudgetCost float64 }, 0) pfkUsageSub := r.db. @@ -283,7 +285,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, budgetQuery := r.db.WithContext(ctx). Table("project_flock_kandangs AS pfk"). Select(` - k.id AS kandang_id, + pfk.id AS project_flock_kandang_id, COALESCE(SUM((pb.qty * pb.price) * COALESCE(k_usage.kandang_usage_qty, 0) / NULLIF(p_usage.project_usage_qty, 0)), 0) AS budget_cost`). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). Joins("JOIN locations AS loc ON loc.id = k.location_id"). @@ -291,7 +293,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, 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 (?)", projectFlockKandangIDs). - Group("k.id") + Group("pfk.id") // budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs) if err := budgetQuery.Scan(&budgetRows).Error; err != nil { @@ -299,33 +301,33 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, } for _, budget := range budgetRows { - entry, ok := costMap[budget.KandangID] + entry, ok := costMap[budget.ProjectFlockKandangID] if !ok { rows = append(rows, HppPerKandangCostRow{ - KandangID: budget.KandangID, + ProjectFlockKandangID: budget.ProjectFlockKandangID, }) entry = &rows[len(rows)-1] - costMap[budget.KandangID] = entry + costMap[budget.ProjectFlockKandangID] = entry } entry.BudgetCost += budget.BudgetCost } expenseRows := make([]struct { - KandangID uint - ExpenseCost float64 + ProjectFlockKandangID uint + ExpenseCost float64 }, 0) expenseQuery := r.db.WithContext(ctx). Table("project_flock_kandangs AS pfk"). Select(` - k.id AS kandang_id, + pfk.id AS project_flock_kandang_id, COALESCE(SUM(er.qty * er.price), 0) AS expense_cost`). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). 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 (?)", projectFlockKandangIDs). - Group("k.id") + Group("pfk.id") // expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs) if err := expenseQuery.Scan(&expenseRows).Error; err != nil { @@ -333,13 +335,13 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, } for _, exp := range expenseRows { - entry, ok := costMap[exp.KandangID] + entry, ok := costMap[exp.ProjectFlockKandangID] if !ok { rows = append(rows, HppPerKandangCostRow{ - KandangID: exp.KandangID, + ProjectFlockKandangID: exp.ProjectFlockKandangID, }) entry = &rows[len(rows)-1] - costMap[exp.KandangID] = entry + costMap[exp.ProjectFlockKandangID] = entry } entry.ExpenseCost += exp.ExpenseCost } @@ -348,7 +350,7 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, feedQuery := r.db.WithContext(ctx). Table("recordings AS r"). - Select("DISTINCT k.id AS kandang_id, s.id AS supplier_id, s.name AS supplier_name, s.alias AS supplier_alias"). + Select("DISTINCT pfk.id AS project_flock_kandang_id, s.id AS supplier_id, s.name AS supplier_name, s.alias AS supplier_alias"). 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"). @@ -369,11 +371,11 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, } for i := range feedSuppliers { - if _, exists := costMap[feedSuppliers[i].KandangID]; !exists { + if _, exists := costMap[feedSuppliers[i].ProjectFlockKandangID]; !exists { rows = append(rows, HppPerKandangCostRow{ - KandangID: feedSuppliers[i].KandangID, + ProjectFlockKandangID: feedSuppliers[i].ProjectFlockKandangID, }) - costMap[feedSuppliers[i].KandangID] = &rows[len(rows)-1] + costMap[feedSuppliers[i].ProjectFlockKandangID] = &rows[len(rows)-1] } feedSuppliers[i].Category = "FEED" } diff --git a/internal/modules/repports/services/repport.service.go b/internal/modules/repports/services/repport.service.go index 9c0c600f..452d46b6 100644 --- a/internal/modules/repports/services/repport.service.go +++ b/internal/modules/repports/services/repport.service.go @@ -1380,7 +1380,7 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes costMap := make(map[uint]HppCostAggregate, len(costRows)) for _, row := range costRows { - costMap[row.KandangID] = HppCostAggregate{ + costMap[row.ProjectFlockKandangID] = HppCostAggregate{ FeedCost: row.FeedCost, OvkCost: row.OvkCost, DocCost: row.DocCost, @@ -1409,15 +1409,15 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes category = "DOC" } - if seen[sup.KandangID] == nil { - seen[sup.KandangID] = make(map[uint]bool) + if seen[sup.ProjectFlockKandangID] == nil { + seen[sup.ProjectFlockKandangID] = make(map[uint]bool) } - if seen[sup.KandangID][sup.SupplierID] { + if seen[sup.ProjectFlockKandangID][sup.SupplierID] { continue } - seen[sup.KandangID][sup.SupplierID] = true + seen[sup.ProjectFlockKandangID][sup.SupplierID] = true - targetMap[sup.KandangID] = append(targetMap[sup.KandangID], dto.HppPerKandangSupplierDTO{ + targetMap[sup.ProjectFlockKandangID] = append(targetMap[sup.ProjectFlockKandangID], dto.HppPerKandangSupplierDTO{ ID: int64(sup.SupplierID), Name: sup.SupplierName, Alias: sup.SupplierAlias, @@ -1507,7 +1507,7 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes rangeKey := weightRangeKey{Min: weightMin, Max: weightMax} // rowBirds := int64(math.Round(birdsFloat)) - costEntry := costMap[row.KandangID] + costEntry := costMap[row.ProjectFlockKandangID] totalCost := costEntry.FeedCost + costEntry.OvkCost + costEntry.DocCost + costEntry.BudgetCost + costEntry.ExpenseCost // hppRp := 0.0 // if weightFloat > 0 { @@ -1526,8 +1526,10 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes avgDocPrice = int64(math.Round(costEntry.DocCost / costEntry.DocQty)) } + nameWithPeriod := fmt.Sprintf("%s Period %d", row.KandangName, row.ProjectFlockPeriod) + dataRows = append(dataRows, dto.HppPerKandangRowDTO{ - ID: int(row.KandangID), + ID: int(row.ProjectFlockKandangID), Kandang: dto.HppPerKandangRowKandangDTO{ ID: int64(row.KandangID), Name: row.KandangName, @@ -1545,11 +1547,12 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes WeightMin: weightMin, WeightMax: weightMax, }, - AvgWeightKg: avgWeight, + AvgWeightKg: avgWeight, + NameWithPeriode: nameWithPeriod, // FeedCostRp: costEntry.FeedCost, // OvkCostRp: costEntry.OvkCost, - DocSuppliers: docSupplierMap[row.KandangID], - FeedSuppliers: feedSupplierMap[row.KandangID], + DocSuppliers: docSupplierMap[row.ProjectFlockKandangID], + FeedSuppliers: feedSupplierMap[row.ProjectFlockKandangID], EggProductionPieces: int64(math.Round(eggPiecesFloatRemaining)), EggProductionKg: eggRemainingWeightFloatRemaining, // EggProductionTotalWeightKg: eggWeightFloat, @@ -1603,12 +1606,12 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes // rangeAgg.RemainingWeightKg += row.RemainingChickenWeight rangeAgg.AvgWeightSum += avgWeight rangeAgg.AvgWeightCount++ - for _, supplier := range feedSupplierMap[row.KandangID] { + for _, supplier := range feedSupplierMap[row.ProjectFlockKandangID] { if _, ok := rangeAgg.FeedSuppliers[supplier.ID]; !ok { rangeAgg.FeedSuppliers[supplier.ID] = supplier } } - for _, supplier := range docSupplierMap[row.KandangID] { + for _, supplier := range docSupplierMap[row.ProjectFlockKandangID] { if _, ok := rangeAgg.DocSuppliers[supplier.ID]; !ok { rangeAgg.DocSuppliers[supplier.ID] = supplier }