adjust api closing data produksi

This commit is contained in:
MacBook Air M1
2026-01-13 15:32:43 +07:00
parent 590df26a1f
commit 0f4cc6e379
2 changed files with 49 additions and 43 deletions
@@ -586,11 +586,21 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint
averageFeedIntake := targetAverages.FeedIntakeAvg averageFeedIntake := targetAverages.FeedIntakeAvg
feedIntakeStd := 0.0 feedIntakeStd := 0.0
var mortalityStdFromGrowth *float64
if project.ProductionStandardId > 0 && currentWeek > 0 && s.StandardGrowthDetailRepo != nil { if project.ProductionStandardId > 0 && currentWeek > 0 && s.StandardGrowthDetailRepo != nil {
feedIntakeStd, err = s.calculateFeedIntakeStd(c.Context(), project.ProductionStandardId, currentWeek) growthDetail, growthErr := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(c.Context(), project.ProductionStandardId, currentWeek)
if err != nil { if growthErr != nil {
s.Log.Errorf("Failed to compute feed intake std for project flock %d: %+v", projectFlockID, err) if !errors.Is(growthErr, gorm.ErrRecordNotFound) {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch feed intake standard data") s.Log.Errorf("Failed to fetch growth detail for project flock %d: %+v", projectFlockID, growthErr)
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch growth standard data")
}
} else if growthDetail != nil {
if growthDetail.FeedIntake != nil {
feedIntakeStd = *growthDetail.FeedIntake
}
if growthDetail.MaxDepletion != nil {
mortalityStdFromGrowth = growthDetail.MaxDepletion
}
} }
} }
@@ -754,6 +764,14 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint
} }
performance.FeedIntake = averageFeedIntake performance.FeedIntake = averageFeedIntake
performance.FeedIntakeStd = feedIntakeStd performance.FeedIntakeStd = feedIntakeStd
if targetAverages.CumDepletionRateCount > 0 {
performance.MortalityAct = targetAverages.CumDepletionRateAvg
performance.DeffMortality = performance.MortalityAct - performance.MortalityStd
}
if mortalityStdFromGrowth != nil {
performance.MortalityStd = *mortalityStdFromGrowth
performance.DeffMortality = performance.MortalityAct - performance.MortalityStd
}
if !isGrowing { if !isGrowing {
if targetAverages.HenDayCount > 0 { if targetAverages.HenDayCount > 0 {
henDayAct := targetAverages.HenDayAvg henDayAct := targetAverages.HenDayAvg
@@ -876,24 +894,6 @@ func (s closingService) determineProductionWeek(ctx context.Context, projectFloc
return week, nil return week, nil
} }
func (s closingService) calculateFeedIntakeStd(ctx context.Context, productionStandardID uint, week int) (float64, error) {
if productionStandardID == 0 || week <= 0 || s.StandardGrowthDetailRepo == nil {
return 0, nil
}
detail, err := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(ctx, productionStandardID, week)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return 0, nil
}
return 0, err
}
if detail == nil || detail.FeedIntake == nil {
return 0, nil
}
return *detail.FeedIntake, nil
}
func calculatePerformanceMetrics(averageWeight, totalWeight, feedUsed, basePopulation, depletion, age float64, standards []entity.FcrStandard) dto.ClosingPerformanceDTO { func calculatePerformanceMetrics(averageWeight, totalWeight, feedUsed, basePopulation, depletion, age float64, standards []entity.FcrStandard) dto.ClosingPerformanceDTO {
mortalityStd, fcrStd := closestFcrValues(standards, averageWeight) mortalityStd, fcrStd := closestFcrValues(standards, averageWeight)
@@ -56,18 +56,20 @@ type RecordingRepositoryImpl struct {
} }
type RecordingTargetAverages struct { type RecordingTargetAverages struct {
HenDayAvg float64 HenDayAvg float64
HenDayCount int64 HenDayCount int64
HenHouseAvg float64 HenHouseAvg float64
HenHouseCount int64 HenHouseCount int64
EggWeightAvg float64 EggWeightAvg float64
EggWeightCount int64 EggWeightCount int64
EggMassAvg float64 EggMassAvg float64
EggMassCount int64 EggMassCount int64
FeedIntakeAvg float64 FeedIntakeAvg float64
FeedIntakeCount int64 FeedIntakeCount int64
FcrAvg float64 FcrAvg float64
FcrCount int64 FcrCount int64
CumDepletionRateAvg float64
CumDepletionRateCount int64
} }
func NewRecordingRepository(db *gorm.DB) RecordingRepository { func NewRecordingRepository(db *gorm.DB) RecordingRepository {
@@ -451,18 +453,20 @@ func (r *RecordingRepositoryImpl) GetTotalEggProductionWeightByProjectFlockID(ct
func (r *RecordingRepositoryImpl) GetAverageTargetMetricsByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint, includeTargets bool) (RecordingTargetAverages, error) { func (r *RecordingRepositoryImpl) GetAverageTargetMetricsByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint, includeTargets bool) (RecordingTargetAverages, error) {
var row struct { var row struct {
HenDayTotal float64 HenDayTotal float64
HenHouseTotal float64 HenHouseTotal float64
EggWeightTotal float64 EggWeightTotal float64
EggMassTotal float64 EggMassTotal float64
FeedIntakeTotal float64 FeedIntakeTotal float64
FcrTotal float64 FcrTotal float64
TotalCount int64 CumDepletionRateTotal float64
TotalCount int64
} }
selectParts := []string{ selectParts := []string{
"COALESCE(SUM(feed_intake), 0) AS feed_intake_total", "COALESCE(SUM(feed_intake), 0) AS feed_intake_total",
"COALESCE(SUM(fcr_value), 0) AS fcr_total", "COALESCE(SUM(fcr_value), 0) AS fcr_total",
"COALESCE(SUM(cum_depletion_rate), 0) AS cum_depletion_rate_total",
"COUNT(*) AS total_count", "COUNT(*) AS total_count",
} }
if includeTargets { if includeTargets {
@@ -483,8 +487,9 @@ func (r *RecordingRepositoryImpl) GetAverageTargetMetricsByProjectFlockKandangID
} }
result := RecordingTargetAverages{ result := RecordingTargetAverages{
FeedIntakeCount: row.TotalCount, FeedIntakeCount: row.TotalCount,
FcrCount: row.TotalCount, FcrCount: row.TotalCount,
CumDepletionRateCount: row.TotalCount,
} }
if includeTargets { if includeTargets {
result.HenDayCount = row.TotalCount result.HenDayCount = row.TotalCount
@@ -501,6 +506,7 @@ func (r *RecordingRepositoryImpl) GetAverageTargetMetricsByProjectFlockKandangID
} }
result.FeedIntakeAvg = row.FeedIntakeTotal / float64(row.TotalCount) result.FeedIntakeAvg = row.FeedIntakeTotal / float64(row.TotalCount)
result.FcrAvg = row.FcrTotal / float64(row.TotalCount) result.FcrAvg = row.FcrTotal / float64(row.TotalCount)
result.CumDepletionRateAvg = row.CumDepletionRateTotal
} }
return result, nil return result, nil