From e8c33f818b91c9fe11302fbc333c1a0415aab5bc Mon Sep 17 00:00:00 2001 From: giovanni Date: Thu, 9 Apr 2026 15:28:26 +0700 Subject: [PATCH] adjust dashboard uniformity and validation add uniformity --- .../dashboard_stats.repository.go | 4 +- .../dashboards/services/dashboard.service.go | 74 +++++++++++++++++++ .../services/uniformity.service.go | 6 +- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/internal/modules/dashboards/repositories/dashboard_stats.repository.go b/internal/modules/dashboards/repositories/dashboard_stats.repository.go index 363e6aa5..72f54185 100644 --- a/internal/modules/dashboards/repositories/dashboard_stats.repository.go +++ b/internal/modules/dashboards/repositories/dashboard_stats.repository.go @@ -35,6 +35,7 @@ type UniformityWeeklyMetric struct { Week int Uniformity float64 AverageWeight float64 + UniformDate time.Time } type StandardWeeklyMetric struct { @@ -144,7 +145,8 @@ func (r *DashboardRepositoryImpl) GetUniformityWeeklyMetrics(ctx context.Context Table("project_flock_kandang_uniformity AS u"). Select(`u.week AS week, COALESCE(AVG(u.uniformity), 0) AS uniformity, - COALESCE(AVG((u.chart_data->'statistics'->>'average_weight')::numeric), 0) AS average_weight`). + COALESCE(AVG((u.chart_data->'statistics'->>'average_weight')::numeric), 0) AS average_weight, + MAX(u.uniform_date) AS uniform_date`). Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = u.project_flock_kandang_id"). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). Where("u.uniform_date IS NOT NULL"). diff --git a/internal/modules/dashboards/services/dashboard.service.go b/internal/modules/dashboards/services/dashboard.service.go index 928205d2..454537f6 100644 --- a/internal/modules/dashboards/services/dashboard.service.go +++ b/internal/modules/dashboards/services/dashboard.service.go @@ -265,6 +265,7 @@ func (s dashboardService) buildPerformanceCharts(ctx context.Context, params *va } bodyWeightDataset := make([]map[string]interface{}, 0, len(weeks)) + bodyWeightDatasetIndexByWeek := make(map[int]int, len(weeks)) performanceDataset := make([]map[string]interface{}, 0, len(weeks)) fcrDataset := make([]map[string]interface{}, 0, len(weeks)) deplesiDataset := make([]map[string]interface{}, 0, len(weeks)) @@ -298,6 +299,7 @@ func (s dashboardService) buildPerformanceCharts(ctx context.Context, params *va "body_weight": roundTo(uni.AverageWeight, 2), "std_body_weight": roundTo(std.StdBodyWeight, 2), }) + bodyWeightDatasetIndexByWeek[week] = len(bodyWeightDataset) - 1 performanceDataset = append(performanceDataset, map[string]interface{}{ "week": week, @@ -326,6 +328,15 @@ func (s dashboardService) buildPerformanceCharts(ctx context.Context, params *va }) } + bodyWeightDataset = extendBodyWeightDatasetUntilEndDate( + bodyWeightDataset, + bodyWeightDatasetIndexByWeek, + uniformities, + uniformityMap, + standardMap, + params.PeriodEnd, + ) + qualityRows, err := s.Repository.GetEggQualityWeeklyMetrics(ctx, startDate, endExclusive, filter) if err != nil { return nil, err @@ -1049,6 +1060,69 @@ func (s dashboardService) avgSellingPrice(ctx context.Context, filter *validatio return result.TotalPrice / result.TotalWeight, nil } +func extendBodyWeightDatasetUntilEndDate( + dataset []map[string]interface{}, + indexByWeek map[int]int, + uniformities []repository.UniformityWeeklyMetric, + uniformityMap map[int]repository.UniformityWeeklyMetric, + standardMap map[int]repository.StandardWeeklyMetric, + periodEnd time.Time, +) []map[string]interface{} { + latestUniformityWeek := 0 + var latestUniformityDate time.Time + for _, row := range uniformities { + if row.Week <= 0 || row.UniformDate.IsZero() { + continue + } + if latestUniformityDate.IsZero() || row.UniformDate.After(latestUniformityDate) || (row.UniformDate.Equal(latestUniformityDate) && row.Week > latestUniformityWeek) { + latestUniformityDate = row.UniformDate + latestUniformityWeek = row.Week + } + } + + if latestUniformityWeek <= 0 || latestUniformityDate.IsZero() || periodEnd.IsZero() || !periodEnd.After(latestUniformityDate) { + return dataset + } + + additionalWeeks := int(math.Ceil(periodEnd.Sub(latestUniformityDate).Hours() / (24 * 7))) + if additionalWeeks <= 0 { + return dataset + } + + lastUniformity := uniformityMap[latestUniformityWeek] + lastStandard := standardMap[latestUniformityWeek] + latestBodyWeight := roundTo(lastUniformity.AverageWeight, 2) + latestStdBodyWeight := roundTo(lastStandard.StdBodyWeight, 2) + + targetWeek := latestUniformityWeek + additionalWeeks + for week := latestUniformityWeek + 1; week <= targetWeek; week++ { + row := map[string]interface{}{ + "week": week, + "body_weight": latestBodyWeight, + "std_body_weight": latestStdBodyWeight, + } + + if idx, ok := indexByWeek[week]; ok { + dataset[idx] = row + continue + } + + dataset = append(dataset, row) + indexByWeek[week] = len(dataset) - 1 + } + + sort.Slice(dataset, func(i, j int) bool { + return datasetWeek(dataset[i]) < datasetWeek(dataset[j]) + }) + + return dataset +} + +func datasetWeek(row map[string]interface{}) int { + week, _ := row["week"].(int) + return week +} + func feedUsageToGrams(rows []repository.FeedUsageByUom) float64 { total := 0.0 for _, row := range rows { diff --git a/internal/modules/production/uniformities/services/uniformity.service.go b/internal/modules/production/uniformities/services/uniformity.service.go index 7de39ef8..5c28ce78 100644 --- a/internal/modules/production/uniformities/services/uniformity.service.go +++ b/internal/modules/production/uniformities/services/uniformity.service.go @@ -406,9 +406,9 @@ func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file } return nil, fiber.NewError(fiber.StatusBadRequest, "week must start from 1 for growing projects") } - if latestWeek > 0 && req.Week > latestWeek+1 { - return nil, fiber.NewError(fiber.StatusBadRequest, "week must be sequential without skipping") - } + // if latestWeek > 0 && req.Week > latestWeek+1 { + // return nil, fiber.NewError(fiber.StatusBadRequest, "week must be sequential without skipping") + // } if err := s.ensureUniqueUniformity(c.Context(), 0, req.ProjectFlockKandangId, req.Week); err != nil { return nil, err