From e0043544208300b401b5044916cc4fb6cd6e6f1a Mon Sep 17 00:00:00 2001 From: giovanni Date: Wed, 14 Jan 2026 16:20:59 +0700 Subject: [PATCH] adjust api production-result --- internal/modules/repports/module.go | 19 ++- .../production_result.repository.go | 23 ++++ .../repports/services/repport.service.go | 115 +++++++++++++++--- 3 files changed, 141 insertions(+), 16 deletions(-) diff --git a/internal/modules/repports/module.go b/internal/modules/repports/module.go index 61f37d4d..c6495a14 100644 --- a/internal/modules/repports/module.go +++ b/internal/modules/repports/module.go @@ -12,6 +12,7 @@ import ( expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories" marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories" + productionStandardRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories" chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories" recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories" purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories" @@ -34,10 +35,26 @@ func (RepportModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate * debtSupplierRepository := repportRepo.NewDebtSupplierRepository(db) hppPerKandangRepository := repportRepo.NewHppPerKandangRepository(db) productionResultRepository := repportRepo.NewProductionResultRepository(db) + standardGrowthDetailRepository := productionStandardRepo.NewStandardGrowthDetailRepository(db) + productionStandardDetailRepository := productionStandardRepo.NewProductionStandardDetailRepository(db) userRepository := rUser.NewUserRepository(db) approvalSvc := approvalService.NewApprovalService(approvalRepository) - repportService := sRepport.NewRepportService(validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc, purchaseSupplierRepository, debtSupplierRepository, hppPerKandangRepository, productionResultRepository) + repportService := sRepport.NewRepportService( + validate, + expenseRealizationRepository, + marketingDeliveryProductRepository, + purchaseRepository, + chickinRepository, + recordingRepository, + approvalSvc, + purchaseSupplierRepository, + debtSupplierRepository, + hppPerKandangRepository, + productionResultRepository, + standardGrowthDetailRepository, + productionStandardDetailRepository, + ) userService := sUser.NewUserService(userRepository, validate) RepportRoutes(router, userService, repportService) diff --git a/internal/modules/repports/repositories/production_result.repository.go b/internal/modules/repports/repositories/production_result.repository.go index 19007d0f..a8eccb91 100644 --- a/internal/modules/repports/repositories/production_result.repository.go +++ b/internal/modules/repports/repositories/production_result.repository.go @@ -11,6 +11,7 @@ import ( type ProductionResultRepository interface { GetRecordingsByProjectFlockKandang(ctx context.Context, projectFlockKandangID uint, offset, limit int) ([]entity.Recording, int64, error) + GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error) } type productionResultRepositoryImpl struct { @@ -76,3 +77,25 @@ func (r *productionResultRepositoryImpl) GetRecordingsByProjectFlockKandang( return recordings, total, nil } + +func (r *productionResultRepositoryImpl) GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error) { + if projectFlockKandangID == 0 { + return 0, nil + } + + var row struct { + ProductionStandardID uint `gorm:"column:production_standard_id"` + } + + err := r.db.WithContext(ctx). + Table("project_flock_kandangs pfk"). + Select("pf.production_standard_id"). + Joins("JOIN project_flocks pf ON pf.id = pfk.project_flock_id"). + Where("pfk.id = ?", projectFlockKandangID). + Take(&row).Error + if err != nil { + return 0, err + } + + return row.ProductionStandardID, nil +} diff --git a/internal/modules/repports/services/repport.service.go b/internal/modules/repports/services/repport.service.go index c4883b72..2577787a 100644 --- a/internal/modules/repports/services/repport.service.go +++ b/internal/modules/repports/services/repport.service.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "math" "sort" @@ -21,6 +22,7 @@ import ( areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto" supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto" warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto" + productionStandardRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories" chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories" recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories" purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories" @@ -55,6 +57,8 @@ type repportService struct { DebtSupplierRepo repportRepo.DebtSupplierRepository HppPerKandangRepo repportRepo.HppPerKandangRepository ProductionResultRepo repportRepo.ProductionResultRepository + StandardGrowthDetailRepo productionStandardRepository.StandardGrowthDetailRepository + ProductionStandardDetailRepo productionStandardRepository.ProductionStandardDetailRepository } type HppCostAggregate struct { @@ -78,6 +82,8 @@ func NewRepportService( debtSupplierRepo repportRepo.DebtSupplierRepository, hppPerKandangRepo repportRepo.HppPerKandangRepository, productionResultRepo repportRepo.ProductionResultRepository, + standardGrowthDetailRepo productionStandardRepository.StandardGrowthDetailRepository, + productionStandardDetailRepo productionStandardRepository.ProductionStandardDetailRepository, ) RepportService { return &repportService{ Log: utils.Log, @@ -92,6 +98,8 @@ func NewRepportService( DebtSupplierRepo: debtSupplierRepo, HppPerKandangRepo: hppPerKandangRepo, ProductionResultRepo: productionResultRepo, + StandardGrowthDetailRepo: standardGrowthDetailRepo, + ProductionStandardDetailRepo: productionStandardDetailRepo, } } @@ -285,6 +293,21 @@ func (s *repportService) GetProductionResult(ctx *fiber.Ctx, params *validation. weeklyResults := summarizeProductionResults(dailyResults, recordsPerWeek) + var productionStandardID uint + if s.ProductionResultRepo != nil { + standardID, err := s.ProductionResultRepo.GetProductionStandardIDByProjectFlockKandangID(ctx.Context(), params.ProjectFlockKandangID) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, 0, err + } + } else { + productionStandardID = standardID + } + } + + standardDetailCache := make(map[int]*entity.ProductionStandardDetail) + growthDetailCache := make(map[int]*entity.StandardGrowthDetail) + var cumulativeButir int64 var cumulativeKg float64 for i := range weeklyResults { @@ -300,6 +323,66 @@ func (s *repportService) GetProductionResult(ctx *fiber.Ctx, params *validation. cumulativeKg += weeklyResults[i].KgJumlah weeklyResults[i].TotalKg = cumulativeKg + + if productionStandardID == 0 { + continue + } + + week := int(weeklyResults[i].Woa) + if s.ProductionStandardDetailRepo != nil { + detail, ok := standardDetailCache[week] + if !ok { + fetched, fetchErr := s.ProductionStandardDetailRepo.GetByStandardIDAndWeek(ctx.Context(), productionStandardID, week) + if fetchErr != nil { + if !errors.Is(fetchErr, gorm.ErrRecordNotFound) { + return nil, 0, fetchErr + } + } else { + detail = fetched + } + standardDetailCache[week] = detail + } + + if detail != nil { + if detail.TargetHenDayProduction != nil { + weeklyResults[i].HdStd = *detail.TargetHenDayProduction + } + if detail.TargetHenHouseProduction != nil { + weeklyResults[i].HhStd = *detail.TargetHenHouseProduction + } + if detail.TargetEggWeight != nil { + weeklyResults[i].EwStd = *detail.TargetEggWeight + } + if detail.TargetEggMass != nil { + weeklyResults[i].EmStd = *detail.TargetEggMass + } + if detail.StandardFCR != nil { + weeklyResults[i].FcrStd = *detail.StandardFCR + } + } + } + + if s.StandardGrowthDetailRepo != nil { + detail, ok := growthDetailCache[week] + if !ok { + fetched, fetchErr := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(ctx.Context(), productionStandardID, week) + if fetchErr != nil { + if !errors.Is(fetchErr, gorm.ErrRecordNotFound) { + return nil, 0, fetchErr + } + } else { + detail = fetched + } + growthDetailCache[week] = detail + } + + if detail != nil && detail.FeedIntake != nil { + weeklyResults[i].FiStd = *detail.FeedIntake + } + if detail != nil && detail.TargetMeanBw != nil { + weeklyResults[i].StdBw = *detail.TargetMeanBw + } + } } totalWeeks := int64(math.Ceil(float64(totalRecordings) / float64(recordsPerWeek))) @@ -314,17 +397,17 @@ func mapRecordingToProductionResultDTO(record entity.Recording) dto.ProductionRe StdUniformity: "90% up", DepKum: valueOrZero(record.CumDepletionRate), DepStd: valueOrZero(record.TotalDepletionQty), + Hd: valueOrZero(record.HenDay), + Fi: valueOrZero(record.FeedIntake), Fcr: valueOrZero(record.FcrValue), - Hh: valueOrZero(record.TotalChickQty), + Hh: valueOrZero(record.HenHouse), + Em: valueOrZero(record.EggMass), + Ew: valueOrZero(record.EggWeight), } if record.Day != nil { result.Woa = float64(*record.Day) } - if record.CumIntake != nil { - result.Fi = float64(*record.CumIntake) - } - // avgWeight := calculateAverageBodyWeight(record.BodyWeights) avgWeight := 1.0 if avgWeight > 0 { @@ -351,8 +434,6 @@ func mapRecordingToProductionResultDTO(record entity.Recording) dto.ProductionRe result.PersenPutih = roundFloat((float64(result.ButiranPutih)/total)*100, 2) result.PersenRetak = roundFloat((float64(result.ButiranRetak)/total)*100, 2) result.PersenPecah = roundFloat((float64(result.ButiranPecah)/total)*100, 2) - result.Ew = (eggSummary.TotalKg * 1000) / total - result.Em = eggSummary.TotalKg } return result @@ -464,13 +545,13 @@ func summarizeProductionResults(daily []dto.ProductionResultDTO, groupSize int) if end > len(daily) { end = len(daily) } - result = append(result, aggregateProductionResultGroup(daily[i:end])) + result = append(result, aggregateProductionResultGroup(daily[i:end], groupSize)) } return result } -func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.ProductionResultDTO { +func aggregateProductionResultGroup(group []dto.ProductionResultDTO, groupSize int) dto.ProductionResultDTO { count := len(group) if count == 0 { return dto.ProductionResultDTO{} @@ -542,6 +623,10 @@ func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.Product if divider == 0 { divider = 1 } + weeklyDivider := float64(groupSize) + if weeklyDivider == 0 { + weeklyDivider = divider + } agg.Bw = sumBw / divider agg.StdBw = sumStdBw / divider @@ -570,17 +655,17 @@ func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.Product agg.PersenPecah = roundFloat(sumPersenPecah/percentDivider, 2) } - agg.Hd = sumHd / divider + agg.Hd = roundFloat(sumHd/weeklyDivider, 2) agg.HdStd = sumHdStd / divider - agg.Fi = sumFi / divider + agg.Fi = roundFloat(sumFi/weeklyDivider, 2) agg.FiStd = sumFiStd / divider - agg.Em = sumEm / divider + agg.Em = group[count-1].Em agg.EmStd = sumEmStd / divider - agg.Ew = sumEw / divider + agg.Ew = group[count-1].Ew agg.EwStd = sumEwStd / divider - agg.Fcr = sumFcr / divider + agg.Fcr = roundFloat(sumFcr/weeklyDivider, 2) agg.FcrStd = sumFcrStd / divider - agg.Hh = sumHh / divider + agg.Hh = roundFloat(sumHh/weeklyDivider, 2) agg.HhStd = sumHhStd / divider return agg