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)
@@ -68,6 +68,8 @@ type RecordingTargetAverages struct {
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 {
@@ -457,12 +459,14 @@ func (r *RecordingRepositoryImpl) GetAverageTargetMetricsByProjectFlockKandangID
EggMassTotal float64 EggMassTotal float64
FeedIntakeTotal float64 FeedIntakeTotal float64
FcrTotal float64 FcrTotal float64
CumDepletionRateTotal float64
TotalCount int64 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 {
@@ -485,6 +489,7 @@ 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