From 644896edfa8bab01eef86ab81f3ed9183c622ec0 Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 00:21:26 +0700 Subject: [PATCH 01/18] feat(BE-281): unfinished uniformity and create project flock triger productwarehouse and add new filtering lookup --- .DS_Store | Bin 6148 -> 6148 bytes go.mod | 7 + go.sum | 22 +- ..._project_flock_kandang_uniformity.down.sql | 6 + ...te_project_flock_kandang_uniformity.up.sql | 58 ++ .../project_flock_kandang_uniformity.go | 33 + internal/entities/uniformity.go | 18 + .../product_warehouse.repository.go | 26 + .../controllers/projectflock.controller.go | 8 + .../dto/projectflock_kandang.dto.go | 1 + .../production/project_flocks/module.go | 5 +- .../project_flock_population_repository.go | 18 + .../projectflock_kandang.repository.go | 15 + .../services/projectflock.service.go | 129 +++ .../repositories/recording.repository.go | 22 + internal/modules/production/route.go | 6 +- .../controllers/uniformity.controller.go | 246 ++++++ .../uniformities/dto/uniformity.dto.go | 208 +++++ .../modules/production/uniformities/module.go | 43 + .../repositories/uniformity.repository.go | 21 + .../modules/production/uniformities/route.go | 30 + .../services/uniformity.body_weight_excel.go | 195 +++++ .../services/uniformity.service.go | 738 ++++++++++++++++++ .../validations/uniformity.validation.go | 173 ++++ internal/utils/constant.go | 23 +- 25 files changed, 2043 insertions(+), 8 deletions(-) create mode 100644 internal/database/migrations/20251227234328_create_project_flock_kandang_uniformity.down.sql create mode 100644 internal/database/migrations/20251227234328_create_project_flock_kandang_uniformity.up.sql create mode 100644 internal/entities/project_flock_kandang_uniformity.go create mode 100644 internal/entities/uniformity.go create mode 100644 internal/modules/production/uniformities/controllers/uniformity.controller.go create mode 100644 internal/modules/production/uniformities/dto/uniformity.dto.go create mode 100644 internal/modules/production/uniformities/module.go create mode 100644 internal/modules/production/uniformities/repositories/uniformity.repository.go create mode 100644 internal/modules/production/uniformities/route.go create mode 100644 internal/modules/production/uniformities/services/uniformity.body_weight_excel.go create mode 100644 internal/modules/production/uniformities/services/uniformity.service.go create mode 100644 internal/modules/production/uniformities/validations/uniformity.validation.go diff --git a/.DS_Store b/.DS_Store index 4c14efd89e4d913a63e6242a245ab626c5fffe6d..e39247fdff6549a6304ce8065c332c38da11c1a4 100644 GIT binary patch delta 31 ncmZoMXfc@J&nU4mU^g?P#AF_p{LPzLLYOBuSZrqJ_{$Ffpo$73 delta 70 zcmZoMXfc@J&nUSuU^g?P 0 { + return *latest.TotalChickQty, nil + } + } + + total, err := s.PopulationRepo.GetAvailableQtyByProjectFlockKandangID(ctx.Context(), projectFlockKandangID) + if err != nil { + s.Log.Errorf("Failed to fetch project flock kandang population %d: %+v", projectFlockKandangID, err) + return 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang population") + } + + return total, nil +} + func (s projectflockService) GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, float64, error) { idStr = strings.TrimSpace(idStr) projectFlockIdStr = strings.TrimSpace(projectFlockIdStr) @@ -793,6 +830,9 @@ func (s projectflockService) attachKandangs(ctx context.Context, dbTransaction * } return fiber.NewError(fiber.StatusInternalServerError, "Failed to persist project flock history") } + if err := s.ensureProjectFlockKandangProductWarehouses(ctx, dbTransaction, records); err != nil { + return err + } return nil } @@ -818,6 +858,23 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction * return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Tidak dapat melepas kandang karena sudah memiliki recording: %s", strings.Join(names, ", "))) } + pfkIDs, err := s.pivotRepoWithTx(dbTransaction).ListIDsByProjectAndKandang(ctx, projectFlockID, kandangIDs) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to load project flock kandang ids") + } + + if len(pfkIDs) > 0 { + pwRepo := s.ProductWarehouseRepo + if dbTransaction != nil { + pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction) + } else if pwRepo == nil { + pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB()) + } + if err := pwRepo.DeleteByProjectFlockKandangIDs(ctx, pfkIDs); err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove product warehouses for project flock kandang") + } + } + if resetStatus { if err := s.kandangRepoWithTx(dbTransaction).UpdateStatusByIDs(ctx, kandangIDs, utils.KandangStatusNonActive); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs status") @@ -854,6 +911,78 @@ func (s projectflockService) kandangRepoWithTx(tx *gorm.DB) kandangRepository.Ka return kandangRepository.NewKandangRepository(s.Repository.DB()) } +func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx context.Context, dbTransaction *gorm.DB, records []*entity.ProjectFlockKandang) error { + if len(records) == 0 { + return nil + } + + pwRepo := s.ProductWarehouseRepo + if dbTransaction != nil { + pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction) + } else if pwRepo == nil { + pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB()) + } + + warehouseRepo := s.WarehouseRepo + if dbTransaction != nil { + warehouseRepo = warehouseRepository.NewWarehouseRepository(dbTransaction) + } else if warehouseRepo == nil { + warehouseRepo = warehouseRepository.NewWarehouseRepository(s.Repository.DB()) + } + + flags := []utils.FlagType{ + utils.FlagAyamAfkir, + utils.FlagAyamCulling, + utils.FlagAyamMati, + utils.FlagTelurPecah, + utils.FlagTelurUtuh, + } + + productIDs := make(map[utils.FlagType]uint, len(flags)) + for _, flag := range flags { + product, err := pwRepo.GetFirstProductByFlag(ctx, string(flag)) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product untuk flag %s tidak ditemukan", flag)) + } + return err + } + productIDs[flag] = product.Id + } + + for _, record := range records { + if record == nil || record.Id == 0 { + continue + } + + warehouse, err := warehouseRepo.GetByKandangID(ctx, record.KandangId) + if err != nil { + return err + } + + for _, flag := range flags { + productID := productIDs[flag] + if _, err := pwRepo.GetByProductWarehouseAndProjectFlockKandang(ctx, productID, warehouse.Id, record.Id); err == nil { + continue + } else if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + + newPW := entity.ProductWarehouse{ + ProductId: productID, + WarehouseId: warehouse.Id, + ProjectFlockKandangId: &record.Id, + Quantity: 0, + } + if err := pwRepo.CreateOne(ctx, &newPW, nil); err != nil { + return err + } + } + } + + return nil +} + func (s projectflockService) Resubmit(c *fiber.Ctx, req *validation.Resubmit, id uint) (*entity.ProjectFlock, error) { if err := s.Validate.Struct(req); err != nil { return nil, err diff --git a/internal/modules/production/recordings/repositories/recording.repository.go b/internal/modules/production/recordings/repositories/recording.repository.go index 6e362ba7..a615692f 100644 --- a/internal/modules/production/recordings/repositories/recording.repository.go +++ b/internal/modules/production/recordings/repositories/recording.repository.go @@ -17,6 +17,7 @@ type RecordingRepository interface { repository.BaseRepository[entity.Recording] WithRelations(db *gorm.DB) *gorm.DB + GetLatestByProjectFlockKandangID(ctx context.Context, projectFlockKandangId uint) (*entity.Recording, error) GenerateNextDay(tx *gorm.DB, projectFlockKandangId uint) (int, error) CreateBodyWeights(tx *gorm.DB, bodyWeights []entity.RecordingBW) error @@ -81,6 +82,27 @@ func (r *RecordingRepositoryImpl) WithRelations(db *gorm.DB) *gorm.DB { Preload("Eggs.ProductWarehouse.Warehouse") } +func (r *RecordingRepositoryImpl) GetLatestByProjectFlockKandangID(ctx context.Context, projectFlockKandangId uint) (*entity.Recording, error) { + if projectFlockKandangId == 0 { + return nil, errors.New("project_flock_kandang_id is required") + } + + var record entity.Recording + err := r.DB().WithContext(ctx). + Where("project_flock_kandangs_id = ?", projectFlockKandangId). + Order("record_datetime DESC"). + Order("created_at DESC"). + Limit(1). + Find(&record).Error + if errors.Is(err, gorm.ErrRecordNotFound) || record.Id == 0 { + return nil, nil + } + if err != nil { + return nil, err + } + return &record, nil +} + func (r *RecordingRepositoryImpl) GenerateNextDay(tx *gorm.DB, projectFlockKandangId uint) (int, error) { var days []int if err := tx.Model(&entity.Recording{}). diff --git a/internal/modules/production/route.go b/internal/modules/production/route.go index d1425b7c..4066121a 100644 --- a/internal/modules/production/route.go +++ b/internal/modules/production/route.go @@ -8,10 +8,11 @@ import ( "gorm.io/gorm" chickins "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins" + projectFlockKandangs "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs" projectflocks "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks" recordings "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings" transferLayings "gitlab.com/mbugroup/lti-api.git/internal/modules/production/transfer_layings" - projectFlockKandangs "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs" + uniformitys "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities" // MODULE IMPORTS ) @@ -24,8 +25,9 @@ func RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Valida chickins.ChickinModule{}, transferLayings.TransferLayingModule{}, projectFlockKandangs.ProjectFlockKandangModule{}, + uniformitys.UniformityModule{}, // MODULE REGISTRY -} + } for _, m := range allModules { m.RegisterRoutes(group, db, validate) diff --git a/internal/modules/production/uniformities/controllers/uniformity.controller.go b/internal/modules/production/uniformities/controllers/uniformity.controller.go new file mode 100644 index 00000000..b6874ba4 --- /dev/null +++ b/internal/modules/production/uniformities/controllers/uniformity.controller.go @@ -0,0 +1,246 @@ +package controller + +import ( + "math" + + "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/dto" + service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" + validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/validations" + "gitlab.com/mbugroup/lti-api.git/internal/response" + + "github.com/gofiber/fiber/v2" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" +) + +type UniformityController struct { + UniformityService service.UniformityService +} + +func NewUniformityController(uniformityService service.UniformityService) *UniformityController { + return &UniformityController{ + UniformityService: uniformityService, + } +} + +func (u *UniformityController) GetAll(c *fiber.Ctx) error { + query, err := validation.ParseQuery(c) + if err != nil { + return err + } + + result, totalResults, err := u.UniformityService.GetAll(c, query) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.SuccessWithPaginate[dto.UniformityListDTO]{ + Code: fiber.StatusOK, + Status: "success", + Message: "Get all production uniformities successfully", + Meta: response.Meta{ + Page: query.Page, + Limit: query.Limit, + TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))), + TotalResults: totalResults, + Filters: fiber.Map{ + "location_id": "", + "project_flock_id": "", + "status": "Pengajuan", + }, + }, + Data: dto.ToUniformityListDTOs(result), + }) +} + +func (u *UniformityController) GetOne(c *fiber.Ctx) error { + id, err := validation.ParseIDParam(c, "id") + if err != nil { + return err + } + + result, err := u.UniformityService.GetOne(c, id) + if err != nil { + return err + } + + withDetails := c.QueryBool("with_details", false) + calculation := service.UniformityCalculation{} + var document *entity.Document + var meanWeight float64 + if result.MeanUp > 0 { + meanWeight = math.Round(result.MeanUp / 1.10) + } + if withDetails { + var err error + calculation, document, err = u.UniformityService.CalculateUniformityFromDocument(c, id) + if err != nil { + return err + } + } else { + calculation = service.UniformityCalculation{ + ChickQtyOfWeight: result.ChickQtyOfWeight, + MeanWeight: meanWeight, + MeanDown: result.MeanDown, + MeanUp: result.MeanUp, + UniformQty: result.UniformQty, + OutsideQty: result.NotUniformQty, + Uniformity: result.Uniformity, + Cv: result.Cv, + } + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Get production uniformity successfully", + Data: dto.ToUniformityDetailDTO(*result, calculation, document), + }) +} + +func (u *UniformityController) CreateOne(c *fiber.Ctx) error { + req, file, err := validation.ParseCreate(c) + if err != nil { + return err + } + + rows, err := u.UniformityService.ParseBodyWeightExcel(c, file) + if err != nil { + return err + } + + calculation, err := u.UniformityService.ComputeUniformity(rows) + if err != nil { + return err + } + + result, err := u.UniformityService.CreateOne(c, req, file, rows) + if err != nil { + return err + } + + document := dto.NewDocumentForResponse(file.Filename) + + return c.Status(fiber.StatusCreated). + JSON(response.Success{ + Code: fiber.StatusCreated, + Status: "success", + Message: "Create uniformity successfully", + Data: dto.ToUniformityDetailDTO(*result, calculation, document), + }) +} + +func (u *UniformityController) UploadBodyWeightExcel(c *fiber.Ctx) error { + files, err := validation.ParseUploadFiles(c) + if err != nil { + return err + } + + rows, err := u.UniformityService.ParseBodyWeightExcel(c, files[0]) + if err != nil { + return err + } + + calculation, err := u.UniformityService.ComputeUniformity(rows) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Uniformity verified successfully", + Data: dto.ToUniformityVerificationDTO(calculation), + }) +} + +func (u *UniformityController) UpdateOne(c *fiber.Ctx) error { + id, err := validation.ParseIDParam(c, "id") + if err != nil { + return err + } + + req, file, err := validation.ParseUpdate(c) + if err != nil { + return err + } + + var rows []service.BodyWeightExcelRow + if file != nil { + parsed, err := u.UniformityService.ParseBodyWeightExcel(c, file) + if err != nil { + return err + } + rows = parsed + } + + result, err := u.UniformityService.UpdateOne(c, req, id, file, rows) + if err != nil { + return err + } + + calculation, document, err := u.UniformityService.CalculateUniformityFromDocument(c, id) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Update uniformity successfully", + Data: dto.ToUniformityDetailDTO(*result, calculation, document), + }) +} + +func (u *UniformityController) DeleteOne(c *fiber.Ctx) error { + id, err := validation.ParseIDParam(c, "id") + if err != nil { + return err + } + + if err := u.UniformityService.DeleteOne(c, id); err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Common{ + Code: fiber.StatusOK, + Status: "success", + Message: "Delete uniformity successfully", + }) +} + +func (u *UniformityController) Approve(c *fiber.Ctx) error { + req, err := validation.ParseApprove(c) + if err != nil { + return err + } + + results, err := u.UniformityService.Approval(c, req) + if err != nil { + return err + } + + var ( + data interface{} + message = "Submit uniformity approvals successfully" + ) + + if len(results) == 1 { + message = "Submit uniformity approval successfully" + data = dto.ToUniformityListDTOs(results)[0] + } else { + data = dto.ToUniformityListDTOs(results) + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: message, + Data: data, + }) +} diff --git a/internal/modules/production/uniformities/dto/uniformity.dto.go b/internal/modules/production/uniformities/dto/uniformity.dto.go new file mode 100644 index 00000000..1c9f4c4d --- /dev/null +++ b/internal/modules/production/uniformities/dto/uniformity.dto.go @@ -0,0 +1,208 @@ +package dto + +import ( + "time" + + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto" + service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" +) + +type UniformitySamplingDTO struct { + ChickQtyOfWeight float64 `json:"chick_qty_of_weight"` + MeanWeight float64 `json:"mean_weight"` + MeanDown float64 `json:"mean_down"` + MeanUp float64 `json:"mean_up"` +} + +type UniformityResultDTO struct { + UniformQty float64 `json:"uniform_qty"` + OutsideQty float64 `json:"outside_qty"` + Uniformity float64 `json:"uniformity"` + Cv float64 `json:"cv"` +} + +type UniformityDetailItemDTO struct { + Id int `json:"id"` + Weight float64 `json:"weight"` + Range string `json:"range"` +} + +type UniformityVerificationDTO struct { + Sampling UniformitySamplingDTO `json:"sampling"` + Result UniformityResultDTO `json:"result"` + UniformityDetails []UniformityDetailItemDTO `json:"uniformity_details"` +} + +type UniformityInfoDTO struct { + Tanggal string `json:"tanggal"` + LokasiFarm string `json:"lokasi_farm"` + ProjectFlock string `json:"project_flock"` + Kandang string `json:"kandang"` + FileName string `json:"file_name"` +} + +type UniformityDetailDTO struct { + Id uint `json:"id"` + InfoUmum UniformityInfoDTO `json:"info_umum"` + Sampling UniformitySamplingDTO `json:"sampling"` + Result UniformityResultDTO `json:"result"` + UniformityDetails []UniformityDetailItemDTO `json:"uniformity_details"` +} + +type UniformityListDTO struct { + Id uint `json:"id"` + ProjectFlockKandangId uint `json:"project_flock_kandang_id"` + LocationName string `json:"location_name"` + FlockName string `json:"flock_name"` + KandangName string `json:"kandang_name"` + AppliedAt *time.Time `json:"applied_at"` + Week int `json:"week"` + Status string `json:"status"` + Uniformity float64 `json:"uniformity"` + Cv float64 `json:"cv"` + ChickQtyOfWeight float64 `json:"chick_qty_of_weight"` + UniformQty float64 `json:"uniform_qty"` + MeanUp float64 `json:"mean_up"` + MeanDown float64 `json:"mean_down"` + CreatedAt time.Time `json:"created_at"` + CreatedBy uint `json:"created_by"` + LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"` +} + +func NewDocumentForResponse(name string) *entity.Document { + if name == "" { + return nil + } + return &entity.Document{Name: name} +} + +func ToUniformityVerificationDTO(calc service.UniformityCalculation) UniformityVerificationDTO { + return UniformityVerificationDTO{ + Sampling: toUniformitySamplingDTO(calc), + Result: toUniformityResultDTO(calc), + UniformityDetails: toUniformityDetailItemsDTO(calc), + } +} + +func ToUniformityDetailDTO( + entityData entity.ProjectFlockKandangUniformity, + calc service.UniformityCalculation, + document *entity.Document, +) UniformityDetailDTO { + info := UniformityInfoDTO{ + Tanggal: formatUniformityDate(entityData.UniformDate), + LokasiFarm: resolveLocationName(entityData.ProjectFlockKandang), + ProjectFlock: resolveProjectFlockName(entityData.ProjectFlockKandang), + Kandang: resolveKandangName(entityData.ProjectFlockKandang), + FileName: "", + } + if document != nil { + info.FileName = document.Name + } + + return UniformityDetailDTO{ + Id: entityData.Id, + InfoUmum: info, + Sampling: toUniformitySamplingDTO(calc), + Result: toUniformityResultDTO(calc), + UniformityDetails: toUniformityDetailItemsDTO(calc), + } +} + +func ToUniformityListDTOs(items []entity.ProjectFlockKandangUniformity) []UniformityListDTO { + result := make([]UniformityListDTO, len(items)) + for i, item := range items { + var latestApproval *approvalDTO.ApprovalRelationDTO + status := "Pengajuan" + if item.LatestApproval != nil { + mapped := approvalDTO.ToApprovalDTO(*item.LatestApproval) + latestApproval = &mapped + if mapped.StepName != "" { + status = mapped.StepName + } + } + + result[i] = UniformityListDTO{ + Id: item.Id, + ProjectFlockKandangId: item.ProjectFlockKandangId, + LocationName: resolveLocationName(item.ProjectFlockKandang), + FlockName: resolveProjectFlockName(item.ProjectFlockKandang), + KandangName: resolveKandangName(item.ProjectFlockKandang), + AppliedAt: item.UniformDate, + Week: item.Week, + Status: status, + Uniformity: item.Uniformity, + Cv: item.Cv, + ChickQtyOfWeight: item.ChickQtyOfWeight, + UniformQty: item.UniformQty, + MeanUp: item.MeanUp, + MeanDown: item.MeanDown, + CreatedAt: item.CreatedAt, + CreatedBy: item.CreatedBy, + LatestApproval: latestApproval, + } + } + return result +} + +func toUniformitySamplingDTO(calc service.UniformityCalculation) UniformitySamplingDTO { + return UniformitySamplingDTO{ + ChickQtyOfWeight: calc.ChickQtyOfWeight, + MeanWeight: calc.MeanWeight, + MeanDown: calc.MeanDown, + MeanUp: calc.MeanUp, + } +} + +func toUniformityResultDTO(calc service.UniformityCalculation) UniformityResultDTO { + return UniformityResultDTO{ + UniformQty: calc.UniformQty, + OutsideQty: calc.OutsideQty, + Uniformity: calc.Uniformity, + Cv: calc.Cv, + } +} + +func toUniformityDetailItemsDTO(calc service.UniformityCalculation) []UniformityDetailItemDTO { + result := make([]UniformityDetailItemDTO, len(calc.Details)) + for i, item := range calc.Details { + result[i] = UniformityDetailItemDTO{ + Id: item.Id, + Weight: item.Weight, + Range: item.Range, + } + } + return result +} + +func resolveLocationName(pfk entity.ProjectFlockKandang) string { + if pfk.Kandang.Id != 0 && pfk.Kandang.Location.Id != 0 { + return pfk.Kandang.Location.Name + } + if pfk.ProjectFlock.Id != 0 && pfk.ProjectFlock.Location.Id != 0 { + return pfk.ProjectFlock.Location.Name + } + return "" +} + +func resolveProjectFlockName(pfk entity.ProjectFlockKandang) string { + if pfk.ProjectFlock.Id != 0 { + return pfk.ProjectFlock.FlockName + } + return "" +} + +func resolveKandangName(pfk entity.ProjectFlockKandang) string { + if pfk.Kandang.Id != 0 { + return pfk.Kandang.Name + } + return "" +} + +func formatUniformityDate(date *time.Time) string { + if date == nil || date.IsZero() { + return "" + } + return date.Format("2006-01-02") +} diff --git a/internal/modules/production/uniformities/module.go b/internal/modules/production/uniformities/module.go new file mode 100644 index 00000000..1032cdcf --- /dev/null +++ b/internal/modules/production/uniformities/module.go @@ -0,0 +1,43 @@ +package uniformitys + +import ( + "context" + "fmt" + + "github.com/go-playground/validator/v10" + "github.com/gofiber/fiber/v2" + "gorm.io/gorm" + + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" + rUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" + sUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" + + rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" + sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" + "gitlab.com/mbugroup/lti-api.git/internal/utils" +) + +type UniformityModule struct{} + +func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) { + uniformityRepo := rUniformity.NewUniformityRepository(db) + documentRepo := commonRepo.NewDocumentRepository(db) + approvalRepo := commonRepo.NewApprovalRepository(db) + userRepo := rUser.NewUserRepository(db) + + documentSvc, err := commonSvc.NewDocumentServiceFromConfig(context.Background(), documentRepo) + if err != nil { + panic(fmt.Sprintf("failed to create document service: %v", err)) + } + + approvalSvc := commonSvc.NewApprovalService(approvalRepo) + if err := approvalSvc.RegisterWorkflowSteps(utils.ApprovalWorkflowUniformity, utils.UniformityApprovalSteps); err != nil { + panic(fmt.Sprintf("failed to register uniformity approval workflow: %v", err)) + } + + uniformityService := sUniformity.NewUniformityService(uniformityRepo, documentSvc, approvalRepo, approvalSvc, validate) + userService := sUser.NewUserService(userRepo, validate) + + UniformityRoutes(router, userService, uniformityService) +} diff --git a/internal/modules/production/uniformities/repositories/uniformity.repository.go b/internal/modules/production/uniformities/repositories/uniformity.repository.go new file mode 100644 index 00000000..3bc66f4f --- /dev/null +++ b/internal/modules/production/uniformities/repositories/uniformity.repository.go @@ -0,0 +1,21 @@ +package repository + +import ( + "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + "gorm.io/gorm" +) + +type UniformityRepository interface { + repository.BaseRepository[entity.ProjectFlockKandangUniformity] +} + +type UniformityRepositoryImpl struct { + *repository.BaseRepositoryImpl[entity.ProjectFlockKandangUniformity] +} + +func NewUniformityRepository(db *gorm.DB) UniformityRepository { + return &UniformityRepositoryImpl{ + BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectFlockKandangUniformity](db), + } +} diff --git a/internal/modules/production/uniformities/route.go b/internal/modules/production/uniformities/route.go new file mode 100644 index 00000000..d22e8761 --- /dev/null +++ b/internal/modules/production/uniformities/route.go @@ -0,0 +1,30 @@ +package uniformitys + +import ( + // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + controller "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/controllers" + uniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" + user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" + + "github.com/gofiber/fiber/v2" +) + +func UniformityRoutes(v1 fiber.Router, u user.UserService, s uniformity.UniformityService) { + ctrl := controller.NewUniformityController(s) + + route := v1.Group("/uniformities") + + // route.Get("/", m.Auth(u), ctrl.GetAll) + // route.Post("/", m.Auth(u), ctrl.CreateOne) + // route.Get("/:id", m.Auth(u), ctrl.GetOne) + // route.Patch("/:id", m.Auth(u), ctrl.UpdateOne) + // route.Delete("/:id", m.Auth(u), ctrl.DeleteOne) + + route.Get("/", ctrl.GetAll) + route.Post("/", ctrl.CreateOne) + route.Post("/verify", ctrl.UploadBodyWeightExcel) + route.Post("/approvals", ctrl.Approve) + route.Get("/:id", ctrl.GetOne) + route.Patch("/:id", ctrl.UpdateOne) + route.Delete("/:id", ctrl.DeleteOne) +} diff --git a/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go b/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go new file mode 100644 index 00000000..97155a3b --- /dev/null +++ b/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go @@ -0,0 +1,195 @@ +package service + +import ( + "io" + "mime/multipart" + "strconv" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/xuri/excelize/v2" +) + +type BodyWeightExcelRow struct { + No int `json:"no"` + Weight float64 `json:"weight"` + Range string `json:"range,omitempty"` +} + +func (s uniformityService) ParseBodyWeightExcel(_ *fiber.Ctx, file *multipart.FileHeader) ([]BodyWeightExcelRow, error) { + if file == nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "file is required") + } + + reader, err := file.Open() + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "failed to open file") + } + defer reader.Close() + + rows, err := parseBodyWeightExcelReader(reader) + if err != nil { + return nil, err + } + + return rows, nil +} + +func parseBodyWeightExcelReader(reader io.Reader) ([]BodyWeightExcelRow, error) { + xlsx, err := excelize.OpenReader(reader) + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "failed to read excel file") + } + defer func() { + _ = xlsx.Close() + }() + + sheets := xlsx.GetSheetList() + if len(sheets) == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "no sheets found in file") + } + + rows, err := xlsx.GetRows(sheets[0], excelize.Options{RawCellValue: true}) + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "failed to read sheet rows") + } + + return parseBodyWeightRows(rows) +} + +func parseBodyWeightRows(rows [][]string) ([]BodyWeightExcelRow, error) { + headerRowIdx, noCol, bwCol, rangeCol := findBodyWeightHeader(rows) + if headerRowIdx < 0 || bwCol < 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "header BW not found") + } + + result := make([]BodyWeightExcelRow, 0) + lastNo := 0 + + for i := headerRowIdx + 1; i < len(rows); i++ { + row := rows[i] + weightStr := cellAt(row, bwCol) + weightVal, ok := parseNumber(weightStr) + if !ok { + continue + } + + noVal := 0 + if noCol >= 0 { + if parsed, ok := parseNumber(cellAt(row, noCol)); ok { + noVal = int(parsed) + } + } + if noVal <= 0 { + noVal = lastNo + 1 + } + if noVal > lastNo { + lastNo = noVal + } + + rangeVal := "" + if rangeCol >= 0 { + rangeVal = strings.TrimSpace(cellAt(row, rangeCol)) + } + + rowPayload := BodyWeightExcelRow{ + No: noVal, + Weight: weightVal, + Range: rangeVal, + } + if rowPayload.No <= 0 || rowPayload.Weight <= 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "invalid body weight row data") + } + + result = append(result, rowPayload) + } + + if len(result) == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "no body weight data found") + } + + return result, nil +} + +func findBodyWeightHeader(rows [][]string) (rowIdx int, noCol int, bwCol int, rangeCol int) { + rowIdx = -1 + noCol = -1 + bwCol = -1 + rangeCol = -1 + + for i, row := range rows { + tempNo := -1 + tempBW := -1 + tempRange := -1 + for j, cell := range row { + label := normalizeHeader(cell) + switch label { + case "no": + tempNo = j + case "bw": + tempBW = j + case "outsiderange": + tempRange = j + default: + if strings.HasPrefix(label, "bw") { + tempBW = j + } else if strings.HasPrefix(label, "no") { + tempNo = j + } else if strings.Contains(label, "range") { + tempRange = j + } + } + } + if tempBW >= 0 { + rowIdx = i + bwCol = tempBW + noCol = tempNo + rangeCol = tempRange + break + } + } + + return rowIdx, noCol, bwCol, rangeCol +} + +func cellAt(row []string, idx int) string { + if idx < 0 || idx >= len(row) { + return "" + } + return strings.TrimSpace(row[idx]) +} + +func normalizeHeader(value string) string { + trimmed := strings.ToLower(strings.TrimSpace(value)) + if trimmed == "" { + return "" + } + var b strings.Builder + for _, r := range trimmed { + if r >= 'a' && r <= 'z' { + b.WriteRune(r) + } + } + return b.String() +} + +func parseNumber(value string) (float64, bool) { + trimmed := strings.TrimSpace(value) + if trimmed == "" { + return 0, false + } + + if strings.Contains(trimmed, ",") { + if strings.Contains(trimmed, ".") { + trimmed = strings.ReplaceAll(trimmed, ",", "") + } else { + trimmed = strings.ReplaceAll(trimmed, ",", ".") + } + } + + parsed, err := strconv.ParseFloat(trimmed, 64) + if err != nil { + return 0, false + } + return parsed, true +} diff --git a/internal/modules/production/uniformities/services/uniformity.service.go b/internal/modules/production/uniformities/services/uniformity.service.go new file mode 100644 index 00000000..786d3662 --- /dev/null +++ b/internal/modules/production/uniformities/services/uniformity.service.go @@ -0,0 +1,738 @@ +package service + +import ( + "context" + "errors" + "fmt" + "math" + "mime/multipart" + "net/http" + "strings" + "time" + + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" + validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/validations" + "gitlab.com/mbugroup/lti-api.git/internal/utils" + approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" + + "github.com/go-playground/validator/v10" + "github.com/gofiber/fiber/v2" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +type UniformityService interface { + GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandangUniformity, int64, error) + GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) + GetSummary(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) + CreateOne(ctx *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) + UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) + DeleteOne(ctx *fiber.Ctx, id uint) error + Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlockKandangUniformity, error) + ParseBodyWeightExcel(ctx *fiber.Ctx, file *multipart.FileHeader) ([]BodyWeightExcelRow, error) + ComputeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) + CalculateUniformityFromDocument(ctx *fiber.Ctx, uniformityID uint) (UniformityCalculation, *entity.Document, error) +} + +type uniformityService struct { + Log *logrus.Logger + Validate *validator.Validate + Repository repository.UniformityRepository + DocumentSvc commonSvc.DocumentService + ApprovalRepo commonRepo.ApprovalRepository + ApprovalSvc commonSvc.ApprovalService +} + +func NewUniformityService( + repo repository.UniformityRepository, + documentSvc commonSvc.DocumentService, + approvalRepo commonRepo.ApprovalRepository, + approvalSvc commonSvc.ApprovalService, + validate *validator.Validate, +) UniformityService { + return &uniformityService{ + Log: utils.Log, + Validate: validate, + Repository: repo, + DocumentSvc: documentSvc, + ApprovalRepo: approvalRepo, + ApprovalSvc: approvalSvc, + } +} + +func (s uniformityService) withRelations(db *gorm.DB) *gorm.DB { + return db. + Preload("ProjectFlockKandang.ProjectFlock.Location"). + Preload("ProjectFlockKandang.Kandang.Location") +} + +func (s uniformityService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandangUniformity, int64, error) { + if err := s.Validate.Struct(params); err != nil { + return nil, 0, err + } + + offset := (params.Page - 1) * params.Limit + + uniformitys, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB { + db = s.withRelations(db) + if params.ProjectFlockKandangId != 0 { + db = db.Where("project_flock_kandang_id = ?", params.ProjectFlockKandangId) + } + if params.Week != 0 { + db = db.Where("week = ?", params.Week) + } + return db.Order("uniform_date DESC").Order("created_at DESC") + }) + + if err != nil { + s.Log.Errorf("Failed to get uniformitys: %+v", err) + return nil, 0, err + } + if err := s.attachLatestApprovals(c.Context(), uniformitys); err != nil { + return nil, 0, err + } + return uniformitys, total, nil +} + +func (s uniformityService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) { + uniformity, err := s.Repository.GetByID(c.Context(), id, s.withRelations) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Uniformity not found") + } + if err != nil { + s.Log.Errorf("Failed get uniformity by id: %+v", err) + return nil, err + } + if err := s.attachLatestApproval(c.Context(), uniformity); err != nil { + return nil, err + } + return uniformity, nil +} + +func (s uniformityService) GetSummary(c *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) { + return s.GetOne(c, id) +} + +func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + if file == nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "document is required") + } + + uniformDate, err := time.Parse("2006-01-02", req.Date) + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "date must be in YYYY-MM-DD format") + } + + if len(rows) == 0 { + parsedRows, err := s.ParseBodyWeightExcel(c, file) + if err != nil { + return nil, err + } + rows = parsedRows + } + + calculation, err := s.ComputeUniformity(rows) + if err != nil { + return nil, err + } + actorID, err := m.ActorIDFromContext(c) + if err != nil { + return nil, err + } + + createBody := &entity.ProjectFlockKandangUniformity{ + Uniformity: calculation.Uniformity, + Week: req.Week, + Cv: calculation.Cv, + ChickQtyOfWeight: calculation.ChickQtyOfWeight, + MeanUp: calculation.MeanUp, + MeanDown: calculation.MeanDown, + ProjectFlockKandangId: req.ProjectFlockKandangId, + UniformQty: calculation.UniformQty, + NotUniformQty: calculation.OutsideQty, + UniformDate: &uniformDate, + CreatedBy: actorID, + } + + if err := s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error { + repoTx := s.Repository.WithTx(tx) + if err := repoTx.CreateOne(c.Context(), createBody, nil); err != nil { + return err + } + if err := s.createUniformityApproval( + c.Context(), + tx, + createBody.Id, + utils.UniformityStepPengajuan, + entity.ApprovalActionCreated, + actorID, + nil, + ); err != nil { + return err + } + return nil + }); err != nil { + s.Log.Errorf("Failed to create uniformity: %+v", err) + return nil, err + } + + if s.DocumentSvc != nil { + actorIDCopy := actorID + _, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{ + DocumentableType: "UNIFORMITY", + DocumentableID: uint64(createBody.Id), + CreatedBy: &actorIDCopy, + Files: []commonSvc.DocumentFile{ + { + File: file, + Type: "UNIFORMITY", + }, + }, + }) + if err != nil { + s.rollbackUniformityCreate(c.Context(), createBody.Id) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to upload uniformity document") + } + } + + return s.GetOne(c, createBody.Id) +} + +func (s uniformityService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + updateBody := make(map[string]any) + + if req.Date != nil { + parsed, err := time.Parse("2006-01-02", *req.Date) + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "date must be in YYYY-MM-DD format") + } + updateBody["uniform_date"] = parsed + } + if req.ProjectFlockKandangId != nil { + updateBody["project_flock_kandang_id"] = *req.ProjectFlockKandangId + } + if req.Week != nil { + updateBody["week"] = *req.Week + } + + if file != nil { + if s.DocumentSvc == nil { + return nil, fiber.NewError(fiber.StatusInternalServerError, "Document service not available") + } + + if len(rows) == 0 { + parsedRows, err := s.ParseBodyWeightExcel(c, file) + if err != nil { + return nil, err + } + rows = parsedRows + } + + calculation, err := s.ComputeUniformity(rows) + if err != nil { + return nil, err + } + + updateBody["uniformity"] = calculation.Uniformity + updateBody["cv"] = calculation.Cv + updateBody["chick_qty_of_weight"] = calculation.ChickQtyOfWeight + updateBody["mean_up"] = calculation.MeanUp + updateBody["mean_down"] = calculation.MeanDown + updateBody["uniform_qty"] = calculation.UniformQty + updateBody["not_uniform_qty"] = calculation.OutsideQty + } + + if len(updateBody) == 0 { + return s.GetOne(c, id) + } + + if file == nil { + if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Uniformity not found") + } + s.Log.Errorf("Failed to update uniformity: %+v", err) + return nil, err + } + + return s.GetOne(c, id) + } + + existingDocs, err := s.DocumentSvc.ListByTarget(c.Context(), "UNIFORMITY", uint64(id)) + if err != nil { + return nil, err + } + + actorID, err := m.ActorIDFromContext(c) + if err != nil { + return nil, err + } + + actorIDCopy := actorID + uploadResults, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{ + DocumentableType: "UNIFORMITY", + DocumentableID: uint64(id), + CreatedBy: &actorIDCopy, + Files: []commonSvc.DocumentFile{ + { + File: file, + Type: "UNIFORMITY", + }, + }, + }) + if err != nil { + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to upload uniformity document") + } + + if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil { + if len(uploadResults) > 0 { + ids := make([]uint, 0, len(uploadResults)) + for _, result := range uploadResults { + if result.Document.Id != 0 { + ids = append(ids, result.Document.Id) + } + } + if len(ids) > 0 { + _ = s.DocumentSvc.DeleteDocuments(c.Context(), ids, true) + } + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Uniformity not found") + } + s.Log.Errorf("Failed to update uniformity: %+v", err) + return nil, err + } + + if len(existingDocs) > 0 { + oldIDs := make([]uint, 0, len(existingDocs)) + for _, doc := range existingDocs { + if doc.Id != 0 { + oldIDs = append(oldIDs, doc.Id) + } + } + if len(oldIDs) > 0 { + _ = s.DocumentSvc.DeleteDocuments(c.Context(), oldIDs, true) + } + } + + return s.GetOne(c, id) +} + +func (s uniformityService) DeleteOne(c *fiber.Ctx, id uint) error { + if err := s.Repository.DeleteOne(c.Context(), id); err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusNotFound, "Uniformity not found") + } + s.Log.Errorf("Failed to delete uniformity: %+v", err) + return err + } + return nil +} + +func (s uniformityService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlockKandangUniformity, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + actionValue := strings.ToUpper(strings.TrimSpace(req.Action)) + var action entity.ApprovalAction + switch actionValue { + case string(entity.ApprovalActionApproved): + action = entity.ApprovalActionApproved + case string(entity.ApprovalActionRejected): + action = entity.ApprovalActionRejected + default: + return nil, fiber.NewError(fiber.StatusBadRequest, "action must be APPROVED or REJECTED") + } + + ids := uniqueUintSlice(req.ApprovableIds) + if len(ids) == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "approvable_ids must contain at least one id") + } + + step := utils.UniformityStepPengajuan + if action == entity.ApprovalActionApproved { + step = utils.UniformityStepDisetujui + } + + actorID, err := m.ActorIDFromContext(c) + if err != nil { + return nil, err + } + + ctx := c.Context() + transactionErr := s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { + repoTx := s.Repository.WithTx(tx) + approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(tx)) + + for _, id := range ids { + if _, err := repoTx.GetByID(ctx, id, nil); err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Uniformity %d not found", id)) + } + return err + } + + if _, err := approvalSvc.CreateApproval( + ctx, + utils.ApprovalWorkflowUniformity, + id, + step, + &action, + actorID, + req.Notes, + ); err != nil { + return err + } + } + + return nil + }) + if transactionErr != nil { + if fiberErr, ok := transactionErr.(*fiber.Error); ok { + return nil, fiberErr + } + s.Log.Errorf("Failed to record approvals for uniformities %+v: %+v", ids, transactionErr) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to submit uniformity approval") + } + + results := make([]entity.ProjectFlockKandangUniformity, 0, len(ids)) + for _, id := range ids { + loaded, err := s.GetOne(c, id) + if err != nil { + return nil, err + } + results = append(results, *loaded) + } + + return results, nil +} + +type UniformityDetailItem struct { + Id int + Weight float64 + Range string +} + +type UniformityCalculation struct { + ChickQtyOfWeight float64 + MeanWeight float64 + MeanDown float64 + MeanUp float64 + UniformQty float64 + OutsideQty float64 + Uniformity float64 + Cv float64 + Details []UniformityDetailItem +} + +func (s uniformityService) ComputeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) { + return computeUniformity(rows) +} + +func (s uniformityService) CalculateUniformityFromDocument(c *fiber.Ctx, uniformityID uint) (UniformityCalculation, *entity.Document, error) { + if s.DocumentSvc == nil { + return UniformityCalculation{}, nil, fiber.NewError(fiber.StatusInternalServerError, "Document service not available") + } + + documents, err := s.DocumentSvc.ListByTarget(c.Context(), "UNIFORMITY", uint64(uniformityID)) + if err != nil { + return UniformityCalculation{}, nil, err + } + if len(documents) == 0 { + return UniformityCalculation{}, nil, fiber.NewError(fiber.StatusNotFound, "Uniformity document not found") + } + + document := documents[0] + url := s.DocumentSvc.PublicURL(document) + if url == "" { + return UniformityCalculation{}, nil, fiber.NewError(fiber.StatusBadRequest, "Uniformity document URL not available") + } + + req, err := http.NewRequestWithContext(c.Context(), http.MethodGet, url, nil) + if err != nil { + return UniformityCalculation{}, nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return UniformityCalculation{}, nil, err + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return UniformityCalculation{}, nil, fiber.NewError(fiber.StatusBadRequest, "Failed to download uniformity document") + } + + rows, err := parseBodyWeightExcelReader(resp.Body) + if err != nil { + return UniformityCalculation{}, nil, err + } + + calculation, err := computeUniformity(rows) + if err != nil { + return UniformityCalculation{}, nil, err + } + + return calculation, &document, nil +} + +func (s *uniformityService) createUniformityApproval( + ctx context.Context, + db *gorm.DB, + uniformityID uint, + step approvalutils.ApprovalStep, + action entity.ApprovalAction, + actorID uint, + notes *string, +) error { + if uniformityID == 0 { + return fiber.NewError(fiber.StatusBadRequest, "Uniformity tidak valid untuk approval") + } + if actorID == 0 { + return fiber.NewError(fiber.StatusBadRequest, "Actor Id tidak valid untuk approval") + } + + var svc commonSvc.ApprovalService + if db != nil { + svc = commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(db)) + } else if s.ApprovalSvc != nil { + svc = s.ApprovalSvc + } else { + svc = commonSvc.NewApprovalService(s.ApprovalRepo) + } + + _, err := svc.CreateApproval(ctx, utils.ApprovalWorkflowUniformity, uniformityID, step, &action, actorID, notes) + return err +} + +func (s *uniformityService) attachLatestApprovals(ctx context.Context, items []entity.ProjectFlockKandangUniformity) error { + if len(items) == 0 || s.ApprovalSvc == nil { + return nil + } + + ids := make([]uint, 0, len(items)) + visited := make(map[uint]struct{}, len(items)) + for _, item := range items { + if item.Id == 0 { + continue + } + if _, ok := visited[item.Id]; ok { + continue + } + visited[item.Id] = struct{}{} + ids = append(ids, item.Id) + } + + if len(ids) == 0 { + return nil + } + + latestMap, err := s.ApprovalSvc.LatestByTargets(ctx, utils.ApprovalWorkflowUniformity, ids, func(db *gorm.DB) *gorm.DB { + return db.Preload("ActionUser") + }) + if err != nil { + s.Log.Warnf("Unable to load latest approvals for uniformities: %+v", err) + return nil + } + + if len(latestMap) == 0 { + return nil + } + + for i := range items { + if items[i].Id == 0 { + continue + } + if approval, ok := latestMap[items[i].Id]; ok { + items[i].LatestApproval = approval + } + } + + return nil +} + +func (s *uniformityService) attachLatestApproval(ctx context.Context, item *entity.ProjectFlockKandangUniformity) error { + if item == nil || item.Id == 0 || s.ApprovalSvc == nil { + return nil + } + + approvals, err := s.ApprovalSvc.ListByTarget(ctx, utils.ApprovalWorkflowUniformity, item.Id, func(db *gorm.DB) *gorm.DB { + return db.Preload("ActionUser") + }) + if err != nil { + s.Log.Warnf("Unable to load approvals for uniformity %d: %+v", item.Id, err) + return nil + } + + if len(approvals) == 0 { + item.LatestApproval = nil + return nil + } + + latest := approvals[len(approvals)-1] + item.LatestApproval = &latest + return nil +} + +func (s *uniformityService) rollbackUniformityCreate(ctx context.Context, uniformityID uint) { + if uniformityID == 0 { + return + } + + if s.ApprovalRepo != nil { + if err := s.ApprovalRepo.DeleteByTarget(ctx, utils.ApprovalWorkflowUniformity.String(), uniformityID); err != nil { + s.Log.WithError(err).Warnf("Failed to rollback uniformity approvals for %d", uniformityID) + } + } + + if err := s.Repository.DeleteOne(ctx, uniformityID); err != nil { + s.Log.WithError(err).Warnf("Failed to rollback uniformity %d", uniformityID) + } +} + +func uniqueUintSlice(values []uint) []uint { + if len(values) == 0 { + return nil + } + + seen := make(map[uint]struct{}, len(values)) + result := make([]uint, 0, len(values)) + for _, v := range values { + if v == 0 { + continue + } + if _, ok := seen[v]; ok { + continue + } + seen[v] = struct{}{} + result = append(result, v) + } + return result +} + +func computeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) { + weights := make([]float64, 0, len(rows)) + details := make([]UniformityDetailItem, 0, len(rows)) + hasRangeLabels := false + for idx, row := range rows { + if row.Weight <= 0 { + continue + } + id := row.No + if id <= 0 { + id = idx + 1 + } + weights = append(weights, row.Weight) + rangeLabel := strings.TrimSpace(row.Range) + if rangeLabel != "" { + upper := strings.ToUpper(rangeLabel) + if upper == "HIGH" || upper == "LOW" { + hasRangeLabels = true + } + rangeLabel = upper + } + details = append(details, UniformityDetailItem{ + Id: id, + Weight: row.Weight, + Range: rangeLabel, + }) + } + + total := float64(len(weights)) + if total == 0 { + return UniformityCalculation{}, fiber.NewError(fiber.StatusBadRequest, "no body weight data found") + } + + var sum float64 + for _, w := range weights { + sum += w + } + mean := sum / total + meanUpThreshold := roundToPrecision(mean*1.10, 3) + meanDownThreshold := roundToPrecision(mean*0.90, 3) + + var uniformCount float64 + for i := range details { + if hasRangeLabels { + if details[i].Range == "HIGH" || details[i].Range == "LOW" { + details[i].Range = "Outside" + continue + } + details[i].Range = "Ideal" + uniformCount++ + continue + } + + w := details[i].Weight + if w > meanUpThreshold || w < meanDownThreshold { + details[i].Range = "Outside" + continue + } + details[i].Range = "Ideal" + uniformCount++ + } + outsideCount := total - uniformCount + + var cv float64 + if mean > 0 && total > 1 { + stddevWeights := weights + if len(stddevWeights) > 100 { + stddevWeights = stddevWeights[:100] + } + stddevCount := float64(len(stddevWeights)) + if stddevCount > 1 { + var stddevSum float64 + for _, w := range stddevWeights { + stddevSum += w + } + stddevMean := stddevSum / stddevCount + var sumSquares float64 + for _, w := range stddevWeights { + diff := w - stddevMean + sumSquares += diff * diff + } + stddev := math.Sqrt(sumSquares / (stddevCount - 1)) + cv = (stddev / mean) * 100 + } + } + + uniformity := (uniformCount / total) * 100 + + return UniformityCalculation{ + ChickQtyOfWeight: total, + MeanWeight: roundToPrecision(mean, 0), + MeanDown: roundToPrecision(mean*0.90, 0), + MeanUp: roundToPrecision(mean*1.10, 0), + UniformQty: uniformCount, + OutsideQty: outsideCount, + Uniformity: roundToPrecision(uniformity, 0), + Cv: roundToPrecision(cv, 1), + Details: details, + }, nil +} + +func roundToPrecision(value float64, precision int) float64 { + if precision < 0 { + return value + } + scale := math.Pow10(precision) + scaled := value * scale + fraction := scaled - math.Floor(scaled) + if fraction >= 0.5 { + return math.Ceil(scaled) / scale + } + return math.Floor(scaled) / scale +} diff --git a/internal/modules/production/uniformities/validations/uniformity.validation.go b/internal/modules/production/uniformities/validations/uniformity.validation.go new file mode 100644 index 00000000..d27ed287 --- /dev/null +++ b/internal/modules/production/uniformities/validations/uniformity.validation.go @@ -0,0 +1,173 @@ +package validation + +import ( + "mime/multipart" + "strconv" + "strings" + + "github.com/gofiber/fiber/v2" +) + +type Create struct { + Date string `form:"date" validate:"required"` + ProjectFlockKandangId uint `form:"project_flock_kandang_id" validate:"required,number,min=1"` + Week int `form:"week" validate:"required,min=1"` +} + +type Update struct { + Date *string `json:"date,omitempty" form:"date" validate:"omitempty"` + ProjectFlockKandangId *uint `json:"project_flock_kandang_id,omitempty" form:"project_flock_kandang_id" validate:"omitempty,number,min=1"` + Week *int `json:"week,omitempty" form:"week" validate:"omitempty,min=1"` +} + +type Query struct { + Page int `query:"page" validate:"omitempty,number,min=1,gt=0"` + Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"` + ProjectFlockKandangId uint `query:"project_flock_kandang_id" validate:"omitempty,number,min=1"` + Week int `query:"week" validate:"omitempty,min=1"` +} + +type UploadExcelRequest struct { + Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"` +} + +type Approve struct { + Action string `json:"action" validate:"required_strict"` + ApprovableIds []uint `json:"approvable_ids" validate:"required_strict,min=1,dive,gt=0"` + Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"` +} + +func ParseIDParam(c *fiber.Ctx, name string) (uint, error) { + raw := strings.TrimSpace(c.Params(name)) + if raw == "" { + return 0, fiber.NewError(fiber.StatusBadRequest, "Invalid Id") + } + id, err := strconv.Atoi(raw) + if err != nil || id <= 0 { + return 0, fiber.NewError(fiber.StatusBadRequest, "Invalid Id") + } + return uint(id), nil +} + +func ParseQuery(c *fiber.Ctx) (*Query, error) { + query := &Query{ + Page: c.QueryInt("page", 1), + Limit: c.QueryInt("limit", 10), + ProjectFlockKandangId: uint(c.QueryInt("project_flock_kandang_id", 0)), + Week: c.QueryInt("week", 0), + } + + if query.Page < 1 || query.Limit < 1 { + return nil, fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0") + } + + return query, nil +} + +func ParseCreate(c *fiber.Ctx) (*Create, *multipart.FileHeader, error) { + date := strings.TrimSpace(c.FormValue("date")) + if date == "" { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "date is required") + } + + projectFlockKandangIDStr := strings.TrimSpace(c.FormValue("project_flock_kandang_id")) + if projectFlockKandangIDStr == "" { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "project_flock_kandang_id is required") + } + + projectFlockKandangID, err := strconv.Atoi(projectFlockKandangIDStr) + if err != nil || projectFlockKandangID <= 0 { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "project_flock_kandang_id is required") + } + + weekStr := strings.TrimSpace(c.FormValue("week")) + if weekStr == "" { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "week is required") + } + + week, err := strconv.Atoi(weekStr) + if err != nil || week <= 0 { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "week is required") + } + + file, err := c.FormFile("document") + if err != nil { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "document is required") + } + + return &Create{ + Date: date, + ProjectFlockKandangId: uint(projectFlockKandangID), + Week: week, + }, file, nil +} + +func ParseUpdate(c *fiber.Ctx) (*Update, *multipart.FileHeader, error) { + contentType := strings.ToLower(c.Get("Content-Type")) + if strings.Contains(contentType, "multipart/form-data") { + req := &Update{} + + date := strings.TrimSpace(c.FormValue("date")) + if date != "" { + req.Date = &date + } + + projectFlockKandangIDStr := strings.TrimSpace(c.FormValue("project_flock_kandang_id")) + if projectFlockKandangIDStr != "" { + projectFlockKandangID, err := strconv.Atoi(projectFlockKandangIDStr) + if err != nil || projectFlockKandangID <= 0 { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "project_flock_kandang_id is invalid") + } + idCopy := uint(projectFlockKandangID) + req.ProjectFlockKandangId = &idCopy + } + + weekStr := strings.TrimSpace(c.FormValue("week")) + if weekStr != "" { + week, err := strconv.Atoi(weekStr) + if err != nil || week <= 0 { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "week is invalid") + } + req.Week = &week + } + + file, err := c.FormFile("document") + if err != nil { + file = nil + } + + return req, file, nil + } + + req := new(Update) + if err := c.BodyParser(req); err != nil { + return nil, nil, fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + } + return req, nil, nil +} + +func ParseUploadFiles(c *fiber.Ctx) ([]*multipart.FileHeader, error) { + form, err := c.MultipartForm() + if err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") + } + + files := form.File["documents"] + if len(files) == 0 { + if file, err := c.FormFile("document"); err == nil && file != nil { + files = []*multipart.FileHeader{file} + } else { + return nil, fiber.NewError(fiber.StatusBadRequest, "documents is required") + } + } + + return files, nil +} + +func ParseApprove(c *fiber.Ctx) (*Approve, error) { + req := new(Approve) + if err := c.BodyParser(req); err != nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + } + return req, nil +} diff --git a/internal/utils/constant.go b/internal/utils/constant.go index 354c9042..d003d996 100644 --- a/internal/utils/constant.go +++ b/internal/utils/constant.go @@ -250,6 +250,21 @@ var RecordingApprovalSteps = map[approvalutils.ApprovalStep]string{ RecordingStepDisetujui: "Disetujui", } +// ------------------------------------------------------------------- +// Uniformity Approval +// ------------------------------------------------------------------- + +const ( + ApprovalWorkflowUniformity approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("UNIFORMITIES") + UniformityStepPengajuan approvalutils.ApprovalStep = 1 + UniformityStepDisetujui approvalutils.ApprovalStep = 2 +) + +var UniformityApprovalSteps = map[approvalutils.ApprovalStep]string{ + UniformityStepPengajuan: "Pengajuan", + UniformityStepDisetujui: "Disetujui", +} + // ------------------------------------------------------------------- // Purchase Approval // ------------------------------------------------------------------- @@ -324,12 +339,12 @@ type DocumentType string type DocumentableType string const ( - DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT" - DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT" + DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT" + DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT" DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT" - DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER" - DocumentableTypeExpense DocumentableType = "EXPENSE" + DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER" + DocumentableTypeExpense DocumentableType = "EXPENSE" DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION" ) From 411d6fe6a91fe7dda64e32fbc1d60ef87f706362 Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 09:38:49 +0700 Subject: [PATCH 02/18] feat(BE-281): deleting bw in recording --- ...ng_egg_and_deleting_recording_bws.down.sql | 55 ++++++++++++++ ...ding_egg_and_deleting_recording_bws.up.sql | 46 ++++++++++++ internal/entities/recording.go | 1 - .../recordings/dto/recording.dto.go | 20 ----- .../repositories/recording.repository.go | 1 - .../recordings/services/recording.service.go | 73 +++---------------- .../validations/recording.validation.go | 8 -- internal/utils/recording/util.recording.go | 42 ----------- 8 files changed, 110 insertions(+), 136 deletions(-) create mode 100644 internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql create mode 100644 internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql diff --git a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql new file mode 100644 index 00000000..a52551bc --- /dev/null +++ b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql @@ -0,0 +1,55 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS recording_bws ( + id BIGSERIAL PRIMARY KEY, + recording_id BIGINT NOT NULL, + avg_weight NUMERIC(8,2) NOT NULL, + qty NUMERIC(15,3) NOT NULL DEFAULT 1, + total_weight NUMERIC(10,3) NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + + CONSTRAINT fk_recording_bws_recording + FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE, + + CONSTRAINT chk_recording_bws_nonneg + CHECK (avg_weight >= 0 AND qty >= 0 AND total_weight >= 0) +); + +CREATE INDEX IF NOT EXISTS idx_recording_bws_recording + ON recording_bws (recording_id); + +ALTER TABLE recordings + DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives_v3; + +ALTER TABLE recordings + DROP COLUMN IF EXISTS hand_day, + DROP COLUMN IF EXISTS hand_house, + DROP COLUMN IF EXISTS feed_intake, + DROP COLUMN IF EXISTS egg_mesh, + DROP COLUMN IF EXISTS egg_weight; + +ALTER TABLE recordings + ADD CONSTRAINT chk_recordings_nonnegatives_v2 CHECK ( + (total_depletion_qty IS NULL OR total_depletion_qty >= 0) AND + (cum_depletion_rate IS NULL OR cum_depletion_rate >= 0) AND + (daily_gain IS NULL OR daily_gain >= 0) AND + (avg_daily_gain IS NULL OR avg_daily_gain >= 0) AND + (cum_intake IS NULL OR cum_intake >= 0) AND + (fcr_value IS NULL OR fcr_value >= 0) AND + (total_chick_qty IS NULL OR total_chick_qty >= 0) + ); + +ALTER TABLE recording_eggs + DROP CONSTRAINT IF EXISTS chk_recording_eggs_qty; + +ALTER TABLE recording_eggs + DROP COLUMN IF EXISTS fcr_value, + ALTER COLUMN weight TYPE NUMERIC(10,3) USING weight::NUMERIC(10,3); + +ALTER TABLE recording_eggs + ADD CONSTRAINT chk_recording_eggs_qty CHECK ( + qty >= 0 AND (weight IS NULL OR weight >= 0) + ); + +COMMIT; diff --git a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql new file mode 100644 index 00000000..3617a71b --- /dev/null +++ b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql @@ -0,0 +1,46 @@ +BEGIN; + +ALTER TABLE recordings + DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives_v2; + +ALTER TABLE recordings + ADD COLUMN IF NOT EXISTS hand_day NUMERIC(15,3), + ADD COLUMN IF NOT EXISTS hand_house NUMERIC(15,3), + ADD COLUMN IF NOT EXISTS feed_intake NUMERIC(15,3), + ADD COLUMN IF NOT EXISTS egg_mesh NUMERIC(15,3), + ADD COLUMN IF NOT EXISTS egg_weight NUMERIC(15,3); + +ALTER TABLE recordings + ADD CONSTRAINT chk_recordings_nonnegatives_v3 CHECK ( + (total_depletion_qty IS NULL OR total_depletion_qty >= 0) AND + (cum_depletion_rate IS NULL OR cum_depletion_rate >= 0) AND + (daily_gain IS NULL OR daily_gain >= 0) AND + (avg_daily_gain IS NULL OR avg_daily_gain >= 0) AND + (cum_intake IS NULL OR cum_intake >= 0) AND + (fcr_value IS NULL OR fcr_value >= 0) AND + (total_chick_qty IS NULL OR total_chick_qty >= 0) AND + (hand_day IS NULL OR hand_day >= 0) AND + (hand_house IS NULL OR hand_house >= 0) AND + (feed_intake IS NULL OR feed_intake >= 0) AND + (egg_mesh IS NULL OR egg_mesh >= 0) AND + (egg_weight IS NULL OR egg_weight >= 0) + ); + +ALTER TABLE recording_eggs + ADD COLUMN IF NOT EXISTS fcr_value NUMERIC(15,3), + ALTER COLUMN weight TYPE NUMERIC(15,3) USING weight::NUMERIC(15,3); + +ALTER TABLE recording_eggs + DROP CONSTRAINT IF EXISTS chk_recording_eggs_qty; + +ALTER TABLE recording_eggs + ADD CONSTRAINT chk_recording_eggs_qty CHECK ( + qty >= 0 AND + (weight IS NULL OR weight >= 0) AND + (fcr_value IS NULL OR fcr_value >= 0) + ); + +DROP INDEX IF EXISTS idx_recording_bws_recording; +DROP TABLE IF EXISTS recording_bws; + +COMMIT; diff --git a/internal/entities/recording.go b/internal/entities/recording.go index 42535365..7b4497e3 100644 --- a/internal/entities/recording.go +++ b/internal/entities/recording.go @@ -25,7 +25,6 @@ type Recording struct { ProjectFlockKandang *ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"` - BodyWeights []RecordingBW `gorm:"foreignKey:RecordingId;references:Id"` Depletions []RecordingDepletion `gorm:"foreignKey:RecordingId;references:Id"` Stocks []RecordingStock `gorm:"foreignKey:RecordingId;references:Id"` Eggs []RecordingEgg `gorm:"foreignKey:RecordingId;references:Id"` diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index 51fba8a4..53106d84 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -39,18 +39,11 @@ type RecordingListDTO struct { type RecordingDetailDTO struct { RecordingListDTO - BodyWeights []RecordingBodyWeightDTO `json:"body_weights"` Depletions []RecordingDepletionDTO `json:"depletions"` Stocks []RecordingStockDTO `json:"stocks"` Eggs []RecordingEggDTO `json:"eggs"` } -type RecordingBodyWeightDTO struct { - AvgWeight float64 `json:"avg_weight"` - Qty float64 `json:"qty"` - TotalWeight float64 `json:"total_weight"` -} - type RecordingDepletionDTO struct { ProductWarehouseId uint `json:"product_warehouse_id"` Qty float64 `json:"qty"` @@ -183,25 +176,12 @@ func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO { return RecordingDetailDTO{ RecordingListDTO: listDTO, - BodyWeights: ToRecordingBodyWeightDTOs(e.BodyWeights), Depletions: ToRecordingDepletionDTOs(e.Depletions), Stocks: ToRecordingStockDTOs(e.Stocks), Eggs: eggs, } } -func ToRecordingBodyWeightDTOs(bodyWeights []entity.RecordingBW) []RecordingBodyWeightDTO { - result := make([]RecordingBodyWeightDTO, len(bodyWeights)) - for i, bw := range bodyWeights { - result[i] = RecordingBodyWeightDTO{ - AvgWeight: bw.AvgWeight, - Qty: bw.Qty, - TotalWeight: bw.TotalWeight, - } - } - return result -} - func ToRecordingDepletionDTOs(depletions []entity.RecordingDepletion) []RecordingDepletionDTO { result := make([]RecordingDepletionDTO, len(depletions)) for i, d := range depletions { diff --git a/internal/modules/production/recordings/repositories/recording.repository.go b/internal/modules/production/recordings/repositories/recording.repository.go index 6e362ba7..a273d88c 100644 --- a/internal/modules/production/recordings/repositories/recording.repository.go +++ b/internal/modules/production/recordings/repositories/recording.repository.go @@ -66,7 +66,6 @@ func (r *RecordingRepositoryImpl) WithRelations(db *gorm.DB) *gorm.DB { Preload("CreatedUser"). Preload("ProjectFlockKandang"). Preload("ProjectFlockKandang.ProjectFlock"). - Preload("BodyWeights"). Preload("Depletions"). Preload("Depletions.ProductWarehouse"). Preload("Depletions.ProductWarehouse.Product"). diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index a83c1128..d7f2c3e0 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -233,12 +233,6 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent return err } - mappedBodyWeights := recordingutil.MapBodyWeights(createdRecording.Id, req.BodyWeights) - if err := s.Repository.CreateBodyWeights(tx, mappedBodyWeights); err != nil { - s.Log.Errorf("Failed to persist body weights: %+v", err) - return err - } - mappedStocks := recordingutil.MapStocks(createdRecording.Id, req.Stocks) if err := s.Repository.CreateStocks(tx, mappedStocks); err != nil { s.Log.Errorf("Failed to persist stocks: %+v", err) @@ -291,7 +285,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin return nil, err } - if req.BodyWeights == nil && req.Stocks == nil && req.Depletions == nil && req.Eggs == nil { + if req.Stocks == nil && req.Depletions == nil && req.Eggs == nil { return s.GetOne(c, id) } @@ -311,12 +305,11 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin } recordingEntity = recording - hasBodyChanges := req.BodyWeights != nil hasStockChanges := req.Stocks != nil hasDepletionChanges := req.Depletions != nil hasEggChanges := req.Eggs != nil - if !hasBodyChanges && !hasStockChanges && !hasDepletionChanges && !hasEggChanges { + if !hasStockChanges && !hasDepletionChanges && !hasEggChanges { return nil } @@ -346,17 +339,6 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin } } - if hasBodyChanges { - if err := s.Repository.DeleteBodyWeights(tx, recordingEntity.Id); err != nil { - s.Log.Errorf("Failed to clear body weights: %+v", err) - return err - } - if err := s.Repository.CreateBodyWeights(tx, recordingutil.MapBodyWeights(recordingEntity.Id, req.BodyWeights)); err != nil { - s.Log.Errorf("Failed to update body weights: %+v", err) - return err - } - } - if hasStockChanges { existingStocks, err := s.Repository.ListStocks(tx, recordingEntity.Id) if err != nil { @@ -432,7 +414,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin } } - if hasBodyChanges || hasStockChanges || hasDepletionChanges { + if hasStockChanges || hasDepletionChanges { if err := s.computeAndUpdateMetrics(ctx, tx, recordingEntity); err != nil { s.Log.Errorf("Failed to recompute recording metrics: %+v", err) return err @@ -775,7 +757,6 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm var prevCumDepletionQty float64 var prevCumIntake float64 - var prevAvgWeight float64 if prevRecording != nil { if prevRecording.TotalDepletionQty != nil { prevCumDepletionQty = *prevRecording.TotalDepletionQty @@ -783,10 +764,6 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm if prevRecording.CumIntake != nil { prevCumIntake = float64(*prevRecording.CumIntake) } - prevAvgWeight, err = s.Repository.GetAverageBodyWeight(tx, prevRecording.Id) - if err != nil { - return fmt.Errorf("getAverageBodyWeight(prev): %w", err) - } } totalChick, err := s.Repository.GetTotalChick(tx, recording.ProjectFlockKandangId) @@ -794,21 +771,11 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm return fmt.Errorf("getTotalChick: %w", err) } - currentAvgWeight, err := s.Repository.GetAverageBodyWeight(tx, recording.Id) - if err != nil { - return fmt.Errorf("getAverageBodyWeight(current): %w", err) - } - usageInGrams, err := s.Repository.GetFeedUsageInGrams(tx, recording.Id) if err != nil { return fmt.Errorf("getFeedUsageInGrams: %w", err) } - currentAvgGrams := recordingutil.ToGrams(currentAvgWeight) - currentAvgKg := recordingutil.GramsToKg(currentAvgGrams) - prevAvgGrams := recordingutil.ToGrams(prevAvgWeight) - prevAvgKg := recordingutil.GramsToKg(prevAvgGrams) - currentDepletion := float64(totalDepletionQty) cumDepletionQty := prevCumDepletionQty + currentDepletion @@ -840,25 +807,10 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm recording.CumDepletionRate = nil } - if currentAvgGrams > 0 && prevAvgGrams > 0 { - dailyGainKg := (currentAvgGrams - prevAvgGrams) / 1000 - updates["daily_gain"] = dailyGainKg - recording.DailyGain = &dailyGainKg - } else { - dailyGainKg := 0.0 - updates["daily_gain"] = dailyGainKg - recording.DailyGain = &dailyGainKg - } - - if currentAvgKg > 0 && remainingChick > 0 { - avgDailyGain := (currentAvgKg - prevAvgKg) / remainingChick - updates["avg_daily_gain"] = avgDailyGain - recording.AvgDailyGain = &avgDailyGain - } else { - avgDailyGain := 0.0 - updates["avg_daily_gain"] = avgDailyGain - recording.AvgDailyGain = &avgDailyGain - } + updates["daily_gain"] = gorm.Expr("NULL") + updates["avg_daily_gain"] = gorm.Expr("NULL") + recording.DailyGain = nil + recording.AvgDailyGain = nil if usageInGrams > 0 && totalChick > 0 { var cumIntakeValue float64 @@ -882,15 +834,8 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm recording.CumIntake = nil } - if usageInGrams > 0 && currentAvgKg > 0 { - feedUsageKg := usageInGrams / 1000 - fcrValue := feedUsageKg / currentAvgKg - updates["fcr_value"] = fcrValue - recording.FcrValue = &fcrValue - } else { - updates["fcr_value"] = gorm.Expr("NULL") - recording.FcrValue = nil - } + updates["fcr_value"] = gorm.Expr("NULL") + recording.FcrValue = nil if err := s.Repository.WithTx(tx).PatchOne(ctx, recording.Id, updates, nil); err != nil { return err diff --git a/internal/modules/production/recordings/validations/recording.validation.go b/internal/modules/production/recordings/validations/recording.validation.go index 28c38ff5..a1d6aaf7 100644 --- a/internal/modules/production/recordings/validations/recording.validation.go +++ b/internal/modules/production/recordings/validations/recording.validation.go @@ -1,12 +1,6 @@ package validation type ( - BodyWeight struct { - AvgWeight float64 `json:"avg_weight" validate:"required"` - Qty float64 `json:"qty" validate:"required,gt=0"` - TotalWeight *float64 `json:"total_weight,omitempty" validate:"omitempty,gte=0"` - } - Stock struct { ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"` Qty float64 `json:"qty" validate:"required,gte=0"` @@ -27,14 +21,12 @@ type ( type Create struct { ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"` - BodyWeights []BodyWeight `json:"body_weights" validate:"dive"` Stocks []Stock `json:"stocks" validate:"dive"` Depletions []Depletion `json:"depletions" validate:"dive"` Eggs []Egg `json:"eggs" validate:"omitempty,dive"` } type Update struct { - BodyWeights []BodyWeight `json:"body_weights,omitempty" validate:"omitempty,dive"` Stocks []Stock `json:"stocks,omitempty" validate:"omitempty,dive"` Depletions []Depletion `json:"depletions,omitempty" validate:"omitempty,dive"` Eggs []Egg `json:"eggs,omitempty" validate:"omitempty,dive"` diff --git a/internal/utils/recording/util.recording.go b/internal/utils/recording/util.recording.go index f10926dc..91c9cc4b 100644 --- a/internal/utils/recording/util.recording.go +++ b/internal/utils/recording/util.recording.go @@ -5,31 +5,6 @@ import ( validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/validations" ) -func MapBodyWeights(recordingID uint, items []validation.BodyWeight) []entity.RecordingBW { - if len(items) == 0 { - return nil - } - - result := make([]entity.RecordingBW, 0, len(items)) - for _, item := range items { - var totalWeight float64 - if item.TotalWeight != nil { - totalWeight = *item.TotalWeight - } - if totalWeight <= 0 { - totalWeight = item.AvgWeight * item.Qty - } - - result = append(result, entity.RecordingBW{ - RecordingId: recordingID, - AvgWeight: item.AvgWeight, - Qty: item.Qty, - TotalWeight: totalWeight, - }) - } - return result -} - func MapStocks(recordingID uint, items []validation.Stock) []entity.RecordingStock { if len(items) == 0 { return nil @@ -86,20 +61,3 @@ func MapEggs(recordingID uint, createdBy uint, items []validation.Egg) []entity. } return result } - -func ToGrams(weight float64) float64 { - if weight <= 0 { - return 0 - } - if weight < 10 { - return weight * 1000 - } - return weight -} - -func GramsToKg(grams float64) float64 { - if grams <= 0 { - return 0 - } - return grams / 1000 -} From 8dfb2246142d6fa745063e179fb4b9e22f2301a0 Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 10:13:29 +0700 Subject: [PATCH 03/18] feat(BE-281): changes std deviasi first 100 data to all --- .../production/uniformities/services/uniformity.service.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/modules/production/uniformities/services/uniformity.service.go b/internal/modules/production/uniformities/services/uniformity.service.go index 786d3662..871f4816 100644 --- a/internal/modules/production/uniformities/services/uniformity.service.go +++ b/internal/modules/production/uniformities/services/uniformity.service.go @@ -689,9 +689,6 @@ func computeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) var cv float64 if mean > 0 && total > 1 { stddevWeights := weights - if len(stddevWeights) > 100 { - stddevWeights = stddevWeights[:100] - } stddevCount := float64(len(stddevWeights)) if stddevCount > 1 { var stddevSum float64 From 8e7e97694603f298f02989b9a9c85719cde5a5f6 Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 16:25:08 +0700 Subject: [PATCH 04/18] feat(BE-281): adjustment recording table with handhouse and deleting weight unfinished dto:standart fcr,hand house and others --- ...ng_egg_and_deleting_recording_bws.down.sql | 1 - ...ding_egg_and_deleting_recording_bws.up.sql | 4 +- internal/entities/recording.go | 7 +- internal/entities/recording_bw.go | 15 -- .../recordings/dto/recording.dto.go | 48 ++++-- .../repositories/recording.repository.go | 158 ++++++------------ .../recordings/services/recording.service.go | 90 ++++++++-- 7 files changed, 165 insertions(+), 158 deletions(-) delete mode 100644 internal/entities/recording_bw.go diff --git a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql index a52551bc..c42fd7d6 100644 --- a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql +++ b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.down.sql @@ -44,7 +44,6 @@ ALTER TABLE recording_eggs DROP CONSTRAINT IF EXISTS chk_recording_eggs_qty; ALTER TABLE recording_eggs - DROP COLUMN IF EXISTS fcr_value, ALTER COLUMN weight TYPE NUMERIC(10,3) USING weight::NUMERIC(10,3); ALTER TABLE recording_eggs diff --git a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql index 3617a71b..032d77b5 100644 --- a/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql +++ b/internal/database/migrations/20251228173112_adjustment_recording_egg_and_deleting_recording_bws.up.sql @@ -27,7 +27,6 @@ ALTER TABLE recordings ); ALTER TABLE recording_eggs - ADD COLUMN IF NOT EXISTS fcr_value NUMERIC(15,3), ALTER COLUMN weight TYPE NUMERIC(15,3) USING weight::NUMERIC(15,3); ALTER TABLE recording_eggs @@ -36,8 +35,7 @@ ALTER TABLE recording_eggs ALTER TABLE recording_eggs ADD CONSTRAINT chk_recording_eggs_qty CHECK ( qty >= 0 AND - (weight IS NULL OR weight >= 0) AND - (fcr_value IS NULL OR fcr_value >= 0) + (weight IS NULL OR weight >= 0) ); DROP INDEX IF EXISTS idx_recording_bws_recording; diff --git a/internal/entities/recording.go b/internal/entities/recording.go index 7b4497e3..404c4986 100644 --- a/internal/entities/recording.go +++ b/internal/entities/recording.go @@ -13,11 +13,14 @@ type Recording struct { Day *int `gorm:"column:day"` TotalDepletionQty *float64 `gorm:"column:total_depletion_qty"` CumDepletionRate *float64 `gorm:"column:cum_depletion_rate"` - DailyGain *float64 `gorm:"column:daily_gain"` - AvgDailyGain *float64 `gorm:"column:avg_daily_gain"` CumIntake *int `gorm:"column:cum_intake"` FcrValue *float64 `gorm:"column:fcr_value"` TotalChickQty *float64 `gorm:"column:total_chick_qty"` + HandDay *float64 `gorm:"column:hand_day"` + HandHouse *float64 `gorm:"column:hand_house"` + FeedIntake *float64 `gorm:"column:feed_intake"` + EggMesh *float64 `gorm:"column:egg_mesh"` + EggWeight *float64 `gorm:"column:egg_weight"` CreatedBy uint `gorm:"column:created_by"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` diff --git a/internal/entities/recording_bw.go b/internal/entities/recording_bw.go deleted file mode 100644 index 041df0f6..00000000 --- a/internal/entities/recording_bw.go +++ /dev/null @@ -1,15 +0,0 @@ -package entities - -import "time" - -type RecordingBW struct { - Id uint `gorm:"primaryKey"` - RecordingId uint `gorm:"column:recording_id;not null;index"` - AvgWeight float64 `gorm:"column:avg_weight;not null"` - Qty float64 `gorm:"column:qty;not null"` - TotalWeight float64 `gorm:"column:total_weight;not null"` - CreatedAt time.Time `gorm:"autoCreateTime"` - UpdatedAt time.Time `gorm:"autoUpdateTime"` - - Recording Recording `gorm:"foreignKey:RecordingId;references:Id"` -} diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index 53106d84..d38642b9 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -22,11 +22,14 @@ type RecordingRelationDTO struct { ProjectFlockCategory string `json:"project_flock_category"` TotalDepletionQty float64 `json:"total_depletion_qty"` CumDepletionRate float64 `json:"cum_depletion_rate"` - DailyGain float64 `json:"daily_gain"` - AvgDailyGain float64 `json:"avg_daily_gain"` CumIntake int `json:"cum_intake"` FcrValue float64 `json:"fcr_value"` TotalChickQty float64 `json:"total_chick_qty"` + HandDay float64 `json:"hand_day"` + HandHouse float64 `json:"hand_house"` + FeedIntake float64 `json:"feed_intake"` + EggMesh float64 `json:"egg_mesh"` + EggWeight float64 `json:"egg_weight"` Approval approvalDTO.ApprovalRelationDTO `json:"approval"` } @@ -39,9 +42,9 @@ type RecordingListDTO struct { type RecordingDetailDTO struct { RecordingListDTO - Depletions []RecordingDepletionDTO `json:"depletions"` - Stocks []RecordingStockDTO `json:"stocks"` - Eggs []RecordingEggDTO `json:"eggs"` + Depletions []RecordingDepletionDTO `json:"depletions"` + Stocks []RecordingStockDTO `json:"stocks"` + Eggs []RecordingEggDTO `json:"eggs"` } type RecordingDepletionDTO struct { @@ -81,11 +84,14 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { day int totalDepletionQty float64 cumDepletionRate float64 - dailyGain float64 - avgDailyGain float64 cumIntake int fcrValue float64 totalChickQty float64 + handDay float64 + handHouse float64 + feedIntake float64 + eggMesh float64 + eggWeight float64 ) if e.Day != nil { @@ -97,12 +103,6 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { if e.CumDepletionRate != nil { cumDepletionRate = *e.CumDepletionRate } - if e.DailyGain != nil { - dailyGain = *e.DailyGain - } - if e.AvgDailyGain != nil { - avgDailyGain = *e.AvgDailyGain - } if e.CumIntake != nil { cumIntake = *e.CumIntake } @@ -112,6 +112,21 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { if e.TotalChickQty != nil { totalChickQty = *e.TotalChickQty } + if e.HandDay != nil { + handDay = *e.HandDay + } + if e.HandHouse != nil { + handHouse = *e.HandHouse + } + if e.FeedIntake != nil { + feedIntake = *e.FeedIntake + } + if e.EggMesh != nil { + eggMesh = *e.EggMesh + } + if e.EggWeight != nil { + eggWeight = *e.EggWeight + } if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.ProjectFlock.Id != 0 { category := e.ProjectFlockKandang.ProjectFlock.Category @@ -132,11 +147,14 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { ProjectFlockCategory: projectFlockCategory, TotalDepletionQty: totalDepletionQty, CumDepletionRate: cumDepletionRate, - DailyGain: dailyGain, - AvgDailyGain: avgDailyGain, CumIntake: cumIntake, FcrValue: fcrValue, TotalChickQty: totalChickQty, + HandDay: handDay, + HandHouse: handHouse, + FeedIntake: feedIntake, + EggMesh: eggMesh, + EggWeight: eggWeight, Approval: latestApproval, } } diff --git a/internal/modules/production/recordings/repositories/recording.repository.go b/internal/modules/production/recordings/repositories/recording.repository.go index a273d88c..8642ed08 100644 --- a/internal/modules/production/recordings/repositories/recording.repository.go +++ b/internal/modules/production/recordings/repositories/recording.repository.go @@ -19,9 +19,6 @@ type RecordingRepository interface { WithRelations(db *gorm.DB) *gorm.DB GenerateNextDay(tx *gorm.DB, projectFlockKandangId uint) (int, error) - CreateBodyWeights(tx *gorm.DB, bodyWeights []entity.RecordingBW) error - DeleteBodyWeights(tx *gorm.DB, recordingID uint) error - CreateStocks(tx *gorm.DB, stocks []entity.RecordingStock) error DeleteStocks(tx *gorm.DB, recordingID uint) error ListStocks(tx *gorm.DB, recordingID uint) ([]entity.RecordingStock, error) @@ -41,10 +38,10 @@ type RecordingRepository interface { SumRecordingDepletions(tx *gorm.DB, recordingID uint) (float64, error) FindPreviousRecording(tx *gorm.DB, projectFlockKandangId uint, currentDay int) (*entity.Recording, error) GetTotalChick(tx *gorm.DB, projectFlockKandangId uint) (int64, error) - GetAverageBodyWeight(tx *gorm.DB, recordingID uint) (float64, error) + GetTotalChickinByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint) (float64, error) GetFeedUsageInGrams(tx *gorm.DB, recordingID uint) (float64, error) - GetFcrID(tx *gorm.DB, projectFlockKandangId uint) (uint, error) - GetFcrStandardWeightKg(tx *gorm.DB, fcrId uint, currentWeightKg float64) (float64, bool, error) + GetEggSummaryByRecording(tx *gorm.DB, recordingID uint) (totalQty float64, totalWeightGrams float64, err error) + GetCumulativeEggQtyByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint, recordTime time.Time) (float64, error) GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error) GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (totalDepletion float64, err error) GetLatestAvgWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (avgWeight float64, err error) @@ -91,17 +88,6 @@ func (r *RecordingRepositoryImpl) GenerateNextDay(tx *gorm.DB, projectFlockKanda return nextRecordingDay(days), nil } -func (r *RecordingRepositoryImpl) CreateBodyWeights(tx *gorm.DB, bodyWeights []entity.RecordingBW) error { - if len(bodyWeights) == 0 { - return nil - } - return tx.Create(&bodyWeights).Error -} - -func (r *RecordingRepositoryImpl) DeleteBodyWeights(tx *gorm.DB, recordingID uint) error { - return tx.Where("recording_id = ?", recordingID).Delete(&entity.RecordingBW{}).Error -} - func (r *RecordingRepositoryImpl) CreateStocks(tx *gorm.DB, stocks []entity.RecordingStock) error { if len(stocks) == 0 { return nil @@ -270,21 +256,18 @@ func (r *RecordingRepositoryImpl) GetTotalChick(tx *gorm.DB, projectFlockKandang return int64(math.Round(total)), nil } -func (r *RecordingRepositoryImpl) GetAverageBodyWeight(tx *gorm.DB, recordingID uint) (float64, error) { - var result struct { - TotalWeight float64 - TotalQty float64 - } - if err := tx.Model(&entity.RecordingBW{}). - Select("COALESCE(SUM(total_weight), 0) AS total_weight, COALESCE(SUM(qty), 0) AS total_qty"). - Where("recording_id = ?", recordingID). - Scan(&result).Error; err != nil { - return 0, err - } - if result.TotalQty == 0 { +func (r *RecordingRepositoryImpl) GetTotalChickinByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint) (float64, error) { + if projectFlockKandangId == 0 { return 0, nil } - return result.TotalWeight / result.TotalQty, nil + + var result float64 + err := tx. + Table("project_chickins"). + Select("COALESCE(SUM(project_chickins.usage_qty), 0)"). + Where("project_chickins.project_flock_kandang_id = ?", projectFlockKandangId). + Scan(&result).Error + return result, err } func (r *RecordingRepositoryImpl) GetFeedUsageInGrams(tx *gorm.DB, recordingID uint) (float64, error) { @@ -321,89 +304,52 @@ func (r *RecordingRepositoryImpl) GetFeedUsageInGrams(tx *gorm.DB, recordingID u return total, nil } -func (r *RecordingRepositoryImpl) GetFcrID(tx *gorm.DB, projectFlockKandangId uint) (uint, error) { - var result struct { - FcrID uint - } - if err := tx.Table("project_flock_kandangs"). - Select("project_flocks.fcr_id AS fcr_id"). - Joins("JOIN project_flocks ON project_flocks.id = project_flock_kandangs.project_flock_id"). - Where("project_flock_kandangs.id = ?", projectFlockKandangId). - Scan(&result).Error; err != nil { - return 0, err - } - return result.FcrID, nil -} - -func (r *RecordingRepositoryImpl) GetFcrStandardWeightKg(tx *gorm.DB, fcrId uint, currentWeightKg float64) (float64, bool, error) { - if fcrId == 0 { - return 0, false, nil - } - - var standard entity.FcrStandard - err := tx. - Where("fcr_id = ? AND weight >= ?", fcrId, currentWeightKg). - Order("weight ASC"). - First(&standard).Error - - if errors.Is(err, gorm.ErrRecordNotFound) { - err = tx. - Where("fcr_id = ?", fcrId). - Order("weight DESC"). - First(&standard).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return 0, false, nil - } - } - if err != nil { - return 0, false, err - } - - weight := standard.Weight - if weight > 10 { - return weight / 1000, true, nil - } - return weight, true, nil -} - -func (r *RecordingRepositoryImpl) GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error) { - if projectFlockID == 0 { +func (r *RecordingRepositoryImpl) GetEggSummaryByRecording(tx *gorm.DB, recordingID uint) (totalQty float64, totalWeightGrams float64, err error) { + if recordingID == 0 { return 0, 0, nil } - totalChickinQty, err := r.getTotalChickinQtyByProjectFlockID(ctx, projectFlockID) + var result struct { + TotalQty float64 + TotalWeightGrams float64 + } + err = tx. + Table("recording_eggs"). + Select("COALESCE(SUM(recording_eggs.qty), 0) AS total_qty, COALESCE(SUM(recording_eggs.qty * COALESCE(recording_eggs.weight, 0)), 0) AS total_weight_grams"). + Where("recording_eggs.recording_id = ?", recordingID). + Scan(&result).Error if err != nil { return 0, 0, err } - - totalDepletion, err := r.GetTotalDepletionByProjectFlockID(ctx, projectFlockID) - if err != nil { - return 0, 0, err - } - - actualQty := totalChickinQty - totalDepletion - - avgWeight, err := r.GetLatestAvgWeightByProjectFlockID(ctx, projectFlockID) - if err != nil { - return 0, 0, err - } - - totalWeight = actualQty * avgWeight - - return totalWeight, actualQty, nil + return result.TotalQty, result.TotalWeightGrams, nil } -func (r *RecordingRepositoryImpl) getTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) { +func (r *RecordingRepositoryImpl) GetCumulativeEggQtyByProjectFlockKandang( + tx *gorm.DB, + projectFlockKandangId uint, + recordTime time.Time, +) (float64, error) { + if projectFlockKandangId == 0 { + return 0, nil + } + var result float64 - err := r.DB().WithContext(ctx). - Table("project_chickins"). - Select("COALESCE(SUM(project_chickins.usage_qty), 0)"). - Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = project_chickins.project_flock_kandang_id"). - Where("project_flock_kandangs.project_flock_id = ?", projectFlockID). + err := tx. + Table("recording_eggs"). + Select("COALESCE(SUM(recording_eggs.qty), 0)"). + Joins("JOIN recordings ON recordings.id = recording_eggs.recording_id"). + Where("recordings.project_flock_kandangs_id = ?", projectFlockKandangId). + Where("recordings.record_datetime <= ?", recordTime). Scan(&result).Error return result, err } +func (r *RecordingRepositoryImpl) GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error) { + // Body-weight tracking is removed; keep stub for report compatibility. + return 0, 0, nil +} + + func (r *RecordingRepositoryImpl) GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) { var result float64 err := r.DB().WithContext(ctx). @@ -417,16 +363,8 @@ func (r *RecordingRepositoryImpl) GetTotalDepletionByProjectFlockID(ctx context. } func (r *RecordingRepositoryImpl) GetLatestAvgWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) { - var result float64 - err := r.DB().WithContext(ctx). - Table("recording_bws"). - Select("COALESCE(AVG(recording_bws.avg_weight), 0)"). - Joins("JOIN recordings ON recordings.id = recording_bws.recording_id"). - Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = recordings.project_flock_kandangs_id"). - Where("project_flock_kandangs.project_flock_id = ?", projectFlockID). - Where("recordings.record_datetime = (SELECT MAX(record_datetime) FROM recordings r2 WHERE r2.project_flock_kandangs_id IN (SELECT id FROM project_flock_kandangs WHERE project_flock_id = ?))", projectFlockID). - Scan(&result).Error - return result, err + // Body-weight tracking is removed; keep stub for report compatibility. + return 0, nil } func (r *RecordingRepositoryImpl) GetTotalEggProductionWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) { diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index d7f2c3e0..2098aad6 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -255,7 +255,7 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, nil, nil, mappedEggs)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedEggs)); err != nil { s.Log.Errorf("Failed to adjust product warehouses: %+v", err) return err } @@ -384,7 +384,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil, nil, nil)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil)); err != nil { s.Log.Errorf("Failed to adjust product warehouses for depletions: %+v", err) return err } @@ -408,7 +408,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, nil, nil, existingEggs, mappedEggs)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, mappedEggs)); err != nil { s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err) return err } @@ -578,7 +578,7 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, nil, nil, oldEggs, nil)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, oldEggs, nil)); err != nil { return err } @@ -706,7 +706,6 @@ func (s *recordingService) ReleaseRecordingStocks(ctx context.Context, tx *gorm. func buildWarehouseDeltas( oldDepletions, newDepletions []entity.RecordingDepletion, - oldStocks, newStocks []entity.RecordingStock, oldEggs, newEggs []entity.RecordingEgg, ) map[uint]float64 { deltas := make(map[uint]float64) @@ -776,6 +775,21 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm return fmt.Errorf("getFeedUsageInGrams: %w", err) } + totalEggQty, totalEggWeightGrams, err := s.Repository.GetEggSummaryByRecording(tx, recording.Id) + if err != nil { + return fmt.Errorf("getEggSummaryByRecording: %w", err) + } + + cumulativeEggQty, err := s.Repository.GetCumulativeEggQtyByProjectFlockKandang(tx, recording.ProjectFlockKandangId, recording.RecordDatetime) + if err != nil { + return fmt.Errorf("getCumulativeEggQtyByProjectFlockKandang: %w", err) + } + + initialChickin, err := s.Repository.GetTotalChickinByProjectFlockKandang(tx, recording.ProjectFlockKandangId) + if err != nil { + return fmt.Errorf("getTotalChickinByProjectFlockKandang: %w", err) + } + currentDepletion := float64(totalDepletionQty) cumDepletionQty := prevCumDepletionQty + currentDepletion @@ -807,10 +821,65 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm recording.CumDepletionRate = nil } - updates["daily_gain"] = gorm.Expr("NULL") - updates["avg_daily_gain"] = gorm.Expr("NULL") - recording.DailyGain = nil - recording.AvgDailyGain = nil + var feedIntake float64 + if remainingChick > 0 && usageInGrams > 0 { + feedIntake = (usageInGrams / remainingChick) * 1000 + updates["feed_intake"] = feedIntake + recording.FeedIntake = &feedIntake + } else { + updates["feed_intake"] = gorm.Expr("NULL") + recording.FeedIntake = nil + } + + var handDay float64 + if remainingChick > 0 && totalEggQty >= 0 { + handDay = (totalEggQty / remainingChick) * 100 + updates["hand_day"] = handDay + recording.HandDay = &handDay + } else { + updates["hand_day"] = gorm.Expr("NULL") + recording.HandDay = nil + } + + var handHouse float64 + if initialChickin > 0 && cumulativeEggQty >= 0 { + handHouse = cumulativeEggQty / initialChickin + updates["hand_house"] = handHouse + recording.HandHouse = &handHouse + } else { + updates["hand_house"] = gorm.Expr("NULL") + recording.HandHouse = nil + } + + var eggMesh float64 + if remainingChick > 0 && totalEggWeightGrams > 0 { + eggMesh = (totalEggWeightGrams / remainingChick) * 1000 + updates["egg_mesh"] = eggMesh + recording.EggMesh = &eggMesh + } else { + updates["egg_mesh"] = gorm.Expr("NULL") + recording.EggMesh = nil + } + + var eggWeight float64 + if totalEggQty > 0 && totalEggWeightGrams > 0 { + eggWeight = (totalEggWeightGrams / totalEggQty) * 1000 + updates["egg_weight"] = eggWeight + recording.EggWeight = &eggWeight + } else { + updates["egg_weight"] = gorm.Expr("NULL") + recording.EggWeight = nil + } + + var fcrValue float64 + if usageInGrams > 0 && totalEggWeightGrams > 0 { + fcrValue = totalEggWeightGrams / usageInGrams + updates["fcr_value"] = fcrValue + recording.FcrValue = &fcrValue + } else { + updates["fcr_value"] = gorm.Expr("NULL") + recording.FcrValue = nil + } if usageInGrams > 0 && totalChick > 0 { var cumIntakeValue float64 @@ -834,9 +903,6 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm recording.CumIntake = nil } - updates["fcr_value"] = gorm.Expr("NULL") - recording.FcrValue = nil - if err := s.Repository.WithTx(tx).PatchOne(ctx, recording.Id, updates, nil); err != nil { return err } From a2066979c1af83b9ed1c244e4ab1f569c2fe24cd Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 19:04:10 +0700 Subject: [PATCH 05/18] feat(BE-281): adjustment uniformity for make unique for week,projectflockandang, and date --- .../modules/production/uniformities/module.go | 4 +- .../services/uniformity.service.go | 101 +++++++++++++++--- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/internal/modules/production/uniformities/module.go b/internal/modules/production/uniformities/module.go index 1032cdcf..27a73fbc 100644 --- a/internal/modules/production/uniformities/module.go +++ b/internal/modules/production/uniformities/module.go @@ -10,6 +10,7 @@ import ( commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" + rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" rUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" sUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" @@ -24,6 +25,7 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat uniformityRepo := rUniformity.NewUniformityRepository(db) documentRepo := commonRepo.NewDocumentRepository(db) approvalRepo := commonRepo.NewApprovalRepository(db) + projectFlockKandangRepo := rProjectFlock.NewProjectFlockKandangRepository(db) userRepo := rUser.NewUserRepository(db) documentSvc, err := commonSvc.NewDocumentServiceFromConfig(context.Background(), documentRepo) @@ -36,7 +38,7 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat panic(fmt.Sprintf("failed to register uniformity approval workflow: %v", err)) } - uniformityService := sUniformity.NewUniformityService(uniformityRepo, documentSvc, approvalRepo, approvalSvc, validate) + uniformityService := sUniformity.NewUniformityService(uniformityRepo, documentSvc, approvalRepo, approvalSvc, projectFlockKandangRepo, validate) userService := sUser.NewUserService(userRepo, validate) UniformityRoutes(router, userService, uniformityService) diff --git a/internal/modules/production/uniformities/services/uniformity.service.go b/internal/modules/production/uniformities/services/uniformity.service.go index 871f4816..6f8ba6ac 100644 --- a/internal/modules/production/uniformities/services/uniformity.service.go +++ b/internal/modules/production/uniformities/services/uniformity.service.go @@ -14,6 +14,7 @@ import ( commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/validations" "gitlab.com/mbugroup/lti-api.git/internal/utils" @@ -39,12 +40,13 @@ type UniformityService interface { } type uniformityService struct { - Log *logrus.Logger - Validate *validator.Validate - Repository repository.UniformityRepository - DocumentSvc commonSvc.DocumentService - ApprovalRepo commonRepo.ApprovalRepository - ApprovalSvc commonSvc.ApprovalService + Log *logrus.Logger + Validate *validator.Validate + Repository repository.UniformityRepository + DocumentSvc commonSvc.DocumentService + ApprovalRepo commonRepo.ApprovalRepository + ApprovalSvc commonSvc.ApprovalService + ProjectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository } func NewUniformityService( @@ -52,15 +54,17 @@ func NewUniformityService( documentSvc commonSvc.DocumentService, approvalRepo commonRepo.ApprovalRepository, approvalSvc commonSvc.ApprovalService, + projectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository, validate *validator.Validate, ) UniformityService { return &uniformityService{ - Log: utils.Log, - Validate: validate, - Repository: repo, - DocumentSvc: documentSvc, - ApprovalRepo: approvalRepo, - ApprovalSvc: approvalSvc, + Log: utils.Log, + Validate: validate, + Repository: repo, + DocumentSvc: documentSvc, + ApprovalRepo: approvalRepo, + ApprovalSvc: approvalSvc, + ProjectFlockKandangRepo: projectFlockKandangRepo, } } @@ -121,6 +125,9 @@ func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file if err := s.Validate.Struct(req); err != nil { return nil, err } + if s.ProjectFlockKandangRepo == nil { + return nil, fiber.NewError(fiber.StatusInternalServerError, "Project flock kandang repository not available") + } if file == nil { return nil, fiber.NewError(fiber.StatusBadRequest, "document is required") @@ -131,6 +138,16 @@ func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file return nil, fiber.NewError(fiber.StatusBadRequest, "date must be in YYYY-MM-DD format") } + if err := commonSvc.EnsureRelations( + c.Context(), + commonSvc.RelationCheck{Name: "Project Flock Kandang", ID: &req.ProjectFlockKandangId, Exists: s.ProjectFlockKandangRepo.IdExists}, + ); err != nil { + return nil, err + } + if err := s.ensureUniqueUniformity(c.Context(), 0, req.ProjectFlockKandangId, req.Week, &uniformDate); err != nil { + return nil, err + } + if len(rows) == 0 { parsedRows, err := s.ParseBodyWeightExcel(c, file) if err != nil { @@ -212,6 +229,7 @@ func (s uniformityService) UpdateOne(c *fiber.Ctx, req *validation.Update, id ui } updateBody := make(map[string]any) + var uniformDate *time.Time if req.Date != nil { parsed, err := time.Parse("2006-01-02", *req.Date) @@ -219,14 +237,51 @@ func (s uniformityService) UpdateOne(c *fiber.Ctx, req *validation.Update, id ui return nil, fiber.NewError(fiber.StatusBadRequest, "date must be in YYYY-MM-DD format") } updateBody["uniform_date"] = parsed + uniformDate = &parsed } if req.ProjectFlockKandangId != nil { + if s.ProjectFlockKandangRepo == nil { + return nil, fiber.NewError(fiber.StatusInternalServerError, "Project flock kandang repository not available") + } + if err := commonSvc.EnsureRelations( + c.Context(), + commonSvc.RelationCheck{Name: "Project Flock Kandang", ID: req.ProjectFlockKandangId, Exists: s.ProjectFlockKandangRepo.IdExists}, + ); err != nil { + return nil, err + } updateBody["project_flock_kandang_id"] = *req.ProjectFlockKandangId } if req.Week != nil { updateBody["week"] = *req.Week } + if req.Date != nil || req.ProjectFlockKandangId != nil || req.Week != nil { + current, err := s.Repository.GetByID(c.Context(), id, nil) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Uniformity not found") + } + return nil, err + } + targetDate := uniformDate + if targetDate == nil { + targetDate = current.UniformDate + } + targetWeek := current.Week + if req.Week != nil { + targetWeek = *req.Week + } + targetPFKID := current.ProjectFlockKandangId + if req.ProjectFlockKandangId != nil { + targetPFKID = *req.ProjectFlockKandangId + } + if targetDate != nil { + if err := s.ensureUniqueUniformity(c.Context(), id, targetPFKID, targetWeek, targetDate); err != nil { + return nil, err + } + } + } + if file != nil { if s.DocumentSvc == nil { return nil, fiber.NewError(fiber.StatusInternalServerError, "Document service not available") @@ -331,6 +386,28 @@ func (s uniformityService) UpdateOne(c *fiber.Ctx, req *validation.Update, id ui return s.GetOne(c, id) } +func (s *uniformityService) ensureUniqueUniformity(ctx context.Context, id uint, projectFlockKandangID uint, week int, uniformDate *time.Time) error { + if projectFlockKandangID == 0 || week == 0 || uniformDate == nil || uniformDate.IsZero() { + return nil + } + + query := s.Repository.DB().WithContext(ctx). + Model(&entity.ProjectFlockKandangUniformity{}). + Where("project_flock_kandang_id = ? AND week = ? AND uniform_date = ?", projectFlockKandangID, week, *uniformDate) + if id != 0 { + query = query.Where("id <> ?", id) + } + + var count int64 + if err := query.Count(&count).Error; err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate uniformity uniqueness") + } + if count > 0 { + return fiber.NewError(fiber.StatusConflict, "Uniformity already exists for the same project flock kandang, week, and date") + } + return nil +} + func (s uniformityService) DeleteOne(c *fiber.Ctx, id uint) error { if err := s.Repository.DeleteOne(c.Context(), id); err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { From 6523290aaf44f62ed1875dbb219120e3377ce066 Mon Sep 17 00:00:00 2001 From: ragilap Date: Mon, 29 Dec 2025 19:44:10 +0700 Subject: [PATCH 06/18] feat(BE-281): change template excel --- Tamplate-Uniformity.xlsx | Bin 0 -> 123855 bytes .../services/uniformity.body_weight_excel.go | 7 ++++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Tamplate-Uniformity.xlsx diff --git a/Tamplate-Uniformity.xlsx b/Tamplate-Uniformity.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bb24c303ef9e441d65d7ae1ee72a9286ecf9dbf7 GIT binary patch literal 123855 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

beG<&g&;kXK%L9Vc0Dk;fl@6ib6O3_j{FYs1F# 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 literal 0 HcmV?d00001 diff --git a/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go b/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go index 97155a3b..4e87f0cc 100644 --- a/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go +++ b/internal/modules/production/uniformities/services/uniformity.body_weight_excel.go @@ -49,7 +49,12 @@ func parseBodyWeightExcelReader(reader io.Reader) ([]BodyWeightExcelRow, error) return nil, fiber.NewError(fiber.StatusBadRequest, "no sheets found in file") } - rows, err := xlsx.GetRows(sheets[0], excelize.Options{RawCellValue: true}) + sheetName := sheets[0] + if len(sheets) > 1 { + sheetName = sheets[1] + } + + rows, err := xlsx.GetRows(sheetName, excelize.Options{RawCellValue: true}) if err != nil { return nil, fiber.NewError(fiber.StatusBadRequest, "failed to read sheet rows") } From 9a094b8bfed3ee3a0644dcca6d3f7ccb02a04fd8 Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 09:56:48 +0700 Subject: [PATCH 07/18] feat(BE-281):fix document payload --- .../validations/uniformity.validation.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/internal/modules/production/uniformities/validations/uniformity.validation.go b/internal/modules/production/uniformities/validations/uniformity.validation.go index d27ed287..b2aeaf26 100644 --- a/internal/modules/production/uniformities/validations/uniformity.validation.go +++ b/internal/modules/production/uniformities/validations/uniformity.validation.go @@ -147,21 +147,12 @@ func ParseUpdate(c *fiber.Ctx) (*Update, *multipart.FileHeader, error) { } func ParseUploadFiles(c *fiber.Ctx) ([]*multipart.FileHeader, error) { - form, err := c.MultipartForm() - if err != nil { - return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") + file, err := c.FormFile("document") + if err != nil || file == nil { + return nil, fiber.NewError(fiber.StatusBadRequest, "document is required") } - files := form.File["documents"] - if len(files) == 0 { - if file, err := c.FormFile("document"); err == nil && file != nil { - files = []*multipart.FileHeader{file} - } else { - return nil, fiber.NewError(fiber.StatusBadRequest, "documents is required") - } - } - - return files, nil + return []*multipart.FileHeader{file}, nil } func ParseApprove(c *fiber.Ctx) (*Approve, error) { From 90125ffe1a2717f95ea368be019b88fe2da06b89 Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 12:07:28 +0700 Subject: [PATCH 08/18] feat(BE-281):add dto standart mean bw and uniformity --- .../controllers/uniformity.controller.go | 56 +++++- .../uniformities/dto/uniformity.dto.go | 28 +++ .../modules/production/uniformities/module.go | 14 +- .../services/uniformity.service.go | 175 ++++++++++++++++-- 4 files changed, 253 insertions(+), 20 deletions(-) diff --git a/internal/modules/production/uniformities/controllers/uniformity.controller.go b/internal/modules/production/uniformities/controllers/uniformity.controller.go index b6874ba4..12cc3739 100644 --- a/internal/modules/production/uniformities/controllers/uniformity.controller.go +++ b/internal/modules/production/uniformities/controllers/uniformity.controller.go @@ -32,6 +32,10 @@ func (u *UniformityController) GetAll(c *fiber.Ctx) error { if err != nil { return err } + standards, err := u.UniformityService.MapStandards(c, result) + if err != nil { + return err + } return c.Status(fiber.StatusOK). JSON(response.SuccessWithPaginate[dto.UniformityListDTO]{ @@ -49,7 +53,7 @@ func (u *UniformityController) GetAll(c *fiber.Ctx) error { "status": "Pengajuan", }, }, - Data: dto.ToUniformityListDTOs(result), + Data: dto.ToUniformityListDTOsWithStandard(result, standards), }) } @@ -90,12 +94,24 @@ func (u *UniformityController) GetOne(c *fiber.Ctx) error { } } + standard, err := u.UniformityService.GetStandard(c, result) + if err != nil { + return err + } + var standardDTO *dto.UniformityStandardDTO + if standard != nil { + standardDTO = &dto.UniformityStandardDTO{ + MeanWeight: standard.MeanWeight, + Uniformity: standard.Uniformity, + } + } + return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Get production uniformity successfully", - Data: dto.ToUniformityDetailDTO(*result, calculation, document), + Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO), }) } @@ -121,13 +137,24 @@ func (u *UniformityController) CreateOne(c *fiber.Ctx) error { } document := dto.NewDocumentForResponse(file.Filename) + standard, err := u.UniformityService.GetStandard(c, result) + if err != nil { + return err + } + var standardDTO *dto.UniformityStandardDTO + if standard != nil { + standardDTO = &dto.UniformityStandardDTO{ + MeanWeight: standard.MeanWeight, + Uniformity: standard.Uniformity, + } + } return c.Status(fiber.StatusCreated). JSON(response.Success{ Code: fiber.StatusCreated, Status: "success", Message: "Create uniformity successfully", - Data: dto.ToUniformityDetailDTO(*result, calculation, document), + Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO), }) } @@ -181,17 +208,36 @@ func (u *UniformityController) UpdateOne(c *fiber.Ctx) error { return err } - calculation, document, err := u.UniformityService.CalculateUniformityFromDocument(c, id) + standard, err := u.UniformityService.GetStandard(c, result) if err != nil { return err } + var standardDTO *dto.UniformityStandardDTO + if standard != nil { + standardDTO = &dto.UniformityStandardDTO{ + MeanWeight: standard.MeanWeight, + Uniformity: standard.Uniformity, + } + } + + calculation := service.UniformityCalculation{ + ChickQtyOfWeight: result.ChickQtyOfWeight, + MeanWeight: math.Round(result.MeanUp / 1.10), + MeanDown: result.MeanDown, + MeanUp: result.MeanUp, + UniformQty: result.UniformQty, + OutsideQty: result.NotUniformQty, + Uniformity: result.Uniformity, + Cv: result.Cv, + } + var document *entity.Document return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Update uniformity successfully", - Data: dto.ToUniformityDetailDTO(*result, calculation, document), + Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO), }) } diff --git a/internal/modules/production/uniformities/dto/uniformity.dto.go b/internal/modules/production/uniformities/dto/uniformity.dto.go index 1c9f4c4d..1324d805 100644 --- a/internal/modules/production/uniformities/dto/uniformity.dto.go +++ b/internal/modules/production/uniformities/dto/uniformity.dto.go @@ -22,6 +22,11 @@ type UniformityResultDTO struct { Cv float64 `json:"cv"` } +type UniformityStandardDTO struct { + MeanWeight *float64 `json:"mean_weight"` + Uniformity *float64 `json:"uniformity"` +} + type UniformityDetailItemDTO struct { Id int `json:"id"` Weight float64 `json:"weight"` @@ -47,6 +52,7 @@ type UniformityDetailDTO struct { InfoUmum UniformityInfoDTO `json:"info_umum"` Sampling UniformitySamplingDTO `json:"sampling"` Result UniformityResultDTO `json:"result"` + Standard *UniformityStandardDTO `json:"standard"` UniformityDetails []UniformityDetailItemDTO `json:"uniformity_details"` } @@ -65,6 +71,8 @@ type UniformityListDTO struct { UniformQty float64 `json:"uniform_qty"` MeanUp float64 `json:"mean_up"` MeanDown float64 `json:"mean_down"` + StandardMeanWeight *float64 `json:"standard_mean_weight"` + StandardUniformity *float64 `json:"standard_uniformity"` CreatedAt time.Time `json:"created_at"` CreatedBy uint `json:"created_by"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"` @@ -89,6 +97,7 @@ func ToUniformityDetailDTO( entityData entity.ProjectFlockKandangUniformity, calc service.UniformityCalculation, document *entity.Document, + standard *UniformityStandardDTO, ) UniformityDetailDTO { info := UniformityInfoDTO{ Tanggal: formatUniformityDate(entityData.UniformDate), @@ -106,6 +115,7 @@ func ToUniformityDetailDTO( InfoUmum: info, Sampling: toUniformitySamplingDTO(calc), Result: toUniformityResultDTO(calc), + Standard: standard, UniformityDetails: toUniformityDetailItemsDTO(calc), } } @@ -146,6 +156,24 @@ func ToUniformityListDTOs(items []entity.ProjectFlockKandangUniformity) []Unifor return result } +func ToUniformityListDTOsWithStandard( + items []entity.ProjectFlockKandangUniformity, + standards map[uint]service.UniformityStandard, +) []UniformityListDTO { + result := ToUniformityListDTOs(items) + if len(result) == 0 || len(standards) == 0 { + return result + } + + for i := range result { + if std, ok := standards[result[i].Id]; ok { + result[i].StandardMeanWeight = std.MeanWeight + result[i].StandardUniformity = std.Uniformity + } + } + return result +} + func toUniformitySamplingDTO(calc service.UniformityCalculation) UniformitySamplingDTO { return UniformitySamplingDTO{ ChickQtyOfWeight: calc.ChickQtyOfWeight, diff --git a/internal/modules/production/uniformities/module.go b/internal/modules/production/uniformities/module.go index 27a73fbc..b3162940 100644 --- a/internal/modules/production/uniformities/module.go +++ b/internal/modules/production/uniformities/module.go @@ -10,6 +10,7 @@ import ( commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" + rProductionStandard "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories" rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" rUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" sUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" @@ -26,6 +27,8 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat documentRepo := commonRepo.NewDocumentRepository(db) approvalRepo := commonRepo.NewApprovalRepository(db) projectFlockKandangRepo := rProjectFlock.NewProjectFlockKandangRepository(db) + productionStandardRepo := rProductionStandard.NewProductionStandardRepository(db) + standardGrowthDetailRepo := rProductionStandard.NewStandardGrowthDetailRepository(db) userRepo := rUser.NewUserRepository(db) documentSvc, err := commonSvc.NewDocumentServiceFromConfig(context.Background(), documentRepo) @@ -38,7 +41,16 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat panic(fmt.Sprintf("failed to register uniformity approval workflow: %v", err)) } - uniformityService := sUniformity.NewUniformityService(uniformityRepo, documentSvc, approvalRepo, approvalSvc, projectFlockKandangRepo, validate) + uniformityService := sUniformity.NewUniformityService( + uniformityRepo, + documentSvc, + approvalRepo, + approvalSvc, + projectFlockKandangRepo, + productionStandardRepo, + standardGrowthDetailRepo, + validate, + ) userService := sUser.NewUserService(userRepo, validate) UniformityRoutes(router, userService, uniformityService) diff --git a/internal/modules/production/uniformities/services/uniformity.service.go b/internal/modules/production/uniformities/services/uniformity.service.go index 6f8ba6ac..2e76e48f 100644 --- a/internal/modules/production/uniformities/services/uniformity.service.go +++ b/internal/modules/production/uniformities/services/uniformity.service.go @@ -14,6 +14,7 @@ import ( commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + rProductionStandard "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories" rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/validations" @@ -30,6 +31,8 @@ type UniformityService interface { GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandangUniformity, int64, error) GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) GetSummary(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error) + GetStandard(ctx *fiber.Ctx, uniformity *entity.ProjectFlockKandangUniformity) (*UniformityStandard, error) + MapStandards(ctx *fiber.Ctx, items []entity.ProjectFlockKandangUniformity) (map[uint]UniformityStandard, error) CreateOne(ctx *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) DeleteOne(ctx *fiber.Ctx, id uint) error @@ -40,13 +43,15 @@ type UniformityService interface { } type uniformityService struct { - Log *logrus.Logger - Validate *validator.Validate - Repository repository.UniformityRepository - DocumentSvc commonSvc.DocumentService - ApprovalRepo commonRepo.ApprovalRepository - ApprovalSvc commonSvc.ApprovalService - ProjectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository + Log *logrus.Logger + Validate *validator.Validate + Repository repository.UniformityRepository + DocumentSvc commonSvc.DocumentService + ApprovalRepo commonRepo.ApprovalRepository + ApprovalSvc commonSvc.ApprovalService + ProjectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository + ProductionStandardRepo rProductionStandard.ProductionStandardRepository + StandardGrowthDetailRepo rProductionStandard.StandardGrowthDetailRepository } func NewUniformityService( @@ -55,16 +60,20 @@ func NewUniformityService( approvalRepo commonRepo.ApprovalRepository, approvalSvc commonSvc.ApprovalService, projectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository, + productionStandardRepo rProductionStandard.ProductionStandardRepository, + standardGrowthDetailRepo rProductionStandard.StandardGrowthDetailRepository, validate *validator.Validate, ) UniformityService { return &uniformityService{ - Log: utils.Log, - Validate: validate, - Repository: repo, - DocumentSvc: documentSvc, - ApprovalRepo: approvalRepo, - ApprovalSvc: approvalSvc, - ProjectFlockKandangRepo: projectFlockKandangRepo, + Log: utils.Log, + Validate: validate, + Repository: repo, + DocumentSvc: documentSvc, + ApprovalRepo: approvalRepo, + ApprovalSvc: approvalSvc, + ProjectFlockKandangRepo: projectFlockKandangRepo, + ProductionStandardRepo: productionStandardRepo, + StandardGrowthDetailRepo: standardGrowthDetailRepo, } } @@ -121,6 +130,64 @@ func (s uniformityService) GetSummary(c *fiber.Ctx, id uint) (*entity.ProjectFlo return s.GetOne(c, id) } +func (s uniformityService) GetStandard(c *fiber.Ctx, uniformity *entity.ProjectFlockKandangUniformity) (*UniformityStandard, error) { + if uniformity == nil { + return nil, nil + } + return s.resolveUniformityStandard(c.Context(), *uniformity) +} + +func (s uniformityService) MapStandards(c *fiber.Ctx, items []entity.ProjectFlockKandangUniformity) (map[uint]UniformityStandard, error) { + if len(items) == 0 { + return nil, nil + } + if s.ProductionStandardRepo == nil || s.StandardGrowthDetailRepo == nil { + return nil, nil + } + + categoryStandard := make(map[string]*entity.ProductionStandard) + detailCache := make(map[uint]map[int]entity.StandardGrowthDetail) + result := make(map[uint]UniformityStandard, len(items)) + + for _, item := range items { + if item.Id == 0 { + continue + } + standard, err := s.resolveCategoryStandard(c.Context(), item.ProjectFlockKandang.ProjectFlock.Category, categoryStandard) + if err != nil { + return nil, err + } + if standard == nil { + continue + } + + weekMap, ok := detailCache[standard.Id] + if !ok { + details, err := s.StandardGrowthDetailRepo.GetByProductionStandardID(c.Context(), standard.Id) + if err != nil { + return nil, err + } + weekMap = make(map[int]entity.StandardGrowthDetail, len(details)) + for _, detail := range details { + weekMap[detail.Week] = detail + } + detailCache[standard.Id] = weekMap + } + + detail, ok := weekMap[item.Week] + if !ok { + continue + } + standardDTO := UniformityStandard{ + MeanWeight: cloneFloat64(detail.TargetMeanBw), + Uniformity: float64Ptr(detail.MinUniformity), + } + result[item.Id] = standardDTO + } + + return result, nil +} + func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) { if err := s.Validate.Struct(req); err != nil { return nil, err @@ -516,6 +583,11 @@ type UniformityCalculation struct { Details []UniformityDetailItem } +type UniformityStandard struct { + MeanWeight *float64 + Uniformity *float64 +} + func (s uniformityService) ComputeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) { return computeUniformity(rows) } @@ -664,6 +736,81 @@ func (s *uniformityService) attachLatestApproval(ctx context.Context, item *enti return nil } +func (s *uniformityService) resolveUniformityStandard(ctx context.Context, item entity.ProjectFlockKandangUniformity) (*UniformityStandard, error) { + if s.ProductionStandardRepo == nil || s.StandardGrowthDetailRepo == nil { + return nil, nil + } + + standard, err := s.resolveCategoryStandard(ctx, item.ProjectFlockKandang.ProjectFlock.Category, nil) + if err != nil || standard == nil { + return nil, err + } + + detail, err := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(ctx, standard.Id, item.Week) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, err + } + + return &UniformityStandard{ + MeanWeight: cloneFloat64(detail.TargetMeanBw), + Uniformity: float64Ptr(detail.MinUniformity), + }, nil +} + +func (s *uniformityService) resolveCategoryStandard( + ctx context.Context, + category string, + cache map[string]*entity.ProductionStandard, +) (*entity.ProductionStandard, error) { + category = strings.TrimSpace(category) + if category == "" { + return nil, nil + } + if cache != nil { + if cached, ok := cache[category]; ok { + return cached, nil + } + } + + var standard entity.ProductionStandard + err := s.ProductionStandardRepo.DB().WithContext(ctx). + Where("project_category = ?", category). + Where("deleted_at IS NULL"). + Order("created_at DESC"). + First(&standard).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + if cache != nil { + cache[category] = nil + } + return nil, nil + } + return nil, err + } + + standardCopy := standard + if cache != nil { + cache[category] = &standardCopy + } + return &standardCopy, nil +} + +func cloneFloat64(value *float64) *float64 { + if value == nil { + return nil + } + copy := *value + return © +} + +func float64Ptr(value float64) *float64 { + copy := value + return © +} + func (s *uniformityService) rollbackUniformityCreate(ctx context.Context, uniformityID uint) { if uniformityID == 0 { return From 0c776e83328f1e7dc630282af3fd15ee7af4c71b Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 12:08:49 +0700 Subject: [PATCH 09/18] feat(BE-281): uncoment auth --- Tamplate-Uniformity.xlsx | Bin 123855 -> 0 bytes internal/middleware/auth.go | 11 +++++------ 2 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 Tamplate-Uniformity.xlsx diff --git a/Tamplate-Uniformity.xlsx b/Tamplate-Uniformity.xlsx deleted file mode 100644 index bb24c303ef9e441d65d7ae1ee72a9286ecf9dbf7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123855 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

beG<&g&;kXK%L9Vc0Dk;fl@6ib6O3_j{FYs1F# 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 diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index a08d431b..a831c25b 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -104,12 +104,11 @@ func AuthenticatedUser(c *fiber.Ctx) (*entity.User, bool) { } func ActorIDFromContext(c *fiber.Ctx) (uint, error) { - // user, ok := AuthenticatedUser(c) - // if !ok || user == nil || user.Id == 0 { - // return 0, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") - // } - // return user.Id, nil - return 1, nil + user, ok := AuthenticatedUser(c) + if !ok || user == nil || user.Id == 0 { + return 0, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") + } + return user.Id, nil } // AuthDetails returns the full authentication context (token, claims, user). From 756ba223edbef6e0630b36ee0b6b0c2ce51fa47f Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 13:17:01 +0700 Subject: [PATCH 10/18] feat(BE-281):add standart production into response recording get one --- internal/entities/recording.go | 6 ++ .../recordings/dto/recording.dto.go | 10 ++ .../recordings/services/recording.service.go | 93 ++++++++++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/internal/entities/recording.go b/internal/entities/recording.go index 404c4986..e07a0a6b 100644 --- a/internal/entities/recording.go +++ b/internal/entities/recording.go @@ -33,4 +33,10 @@ type Recording struct { Eggs []RecordingEgg `gorm:"foreignKey:RecordingId;references:Id"` LatestApproval *Approval `gorm:"-" json:"-"` + + StandardHandDay *float64 `gorm:"-"` + StandardHandHouse *float64 `gorm:"-"` + StandardFeedIntake *float64 `gorm:"-"` + StandardEggMesh *float64 `gorm:"-"` + StandardEggWeight *float64 `gorm:"-"` } diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index d38642b9..12222b97 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -30,6 +30,11 @@ type RecordingRelationDTO struct { FeedIntake float64 `json:"feed_intake"` EggMesh float64 `json:"egg_mesh"` EggWeight float64 `json:"egg_weight"` + StandardHandDay *float64 `json:"hand_day_std,omitempty"` + StandardHandHouse *float64 `json:"hand_house_std,omitempty"` + StandardFeedIntake *float64 `json:"feed_intake_std,omitempty"` + StandardEggMesh *float64 `json:"egg_mesh_std,omitempty"` + StandardEggWeight *float64 `json:"egg_weight_std,omitempty"` Approval approvalDTO.ApprovalRelationDTO `json:"approval"` } @@ -155,6 +160,11 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { FeedIntake: feedIntake, EggMesh: eggMesh, EggWeight: eggWeight, + StandardHandDay: e.StandardHandDay, + StandardHandHouse: e.StandardHandHouse, + StandardFeedIntake: e.StandardFeedIntake, + StandardEggMesh: e.StandardEggMesh, + StandardEggWeight: e.StandardEggWeight, Approval: latestApproval, } } diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 2098aad6..a3756adf 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -9,6 +9,7 @@ import ( entity "gitlab.com/mbugroup/lti-api.git/internal/entities" m "gitlab.com/mbugroup/lti-api.git/internal/middleware" rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" + rProductionStandard "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories" rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/validations" @@ -121,6 +122,9 @@ func (s recordingService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti if err := s.attachLatestApprovals(c.Context(), recordings); err != nil { return nil, 0, err } + if err := s.attachProductionStandards(c.Context(), recordings); err != nil { + return nil, 0, err + } return recordings, total, nil } @@ -138,6 +142,9 @@ func (s recordingService) GetOne(c *fiber.Ctx, id uint) (*entity.Recording, erro if err := s.attachLatestApproval(c.Context(), recording); err != nil { return nil, err } + if err := s.attachProductionStandard(c.Context(), recording); err != nil { + return nil, err + } return recording, nil } @@ -255,7 +262,7 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedEggs)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedEggs)); err != nil { s.Log.Errorf("Failed to adjust product warehouses: %+v", err) return err } @@ -384,7 +391,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil)); err != nil { s.Log.Errorf("Failed to adjust product warehouses for depletions: %+v", err) return err } @@ -408,7 +415,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, mappedEggs)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, mappedEggs)); err != nil { s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err) return err } @@ -578,7 +585,7 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { return err } - if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, oldEggs, nil)); err != nil { + if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, oldEggs, nil)); err != nil { return err } @@ -1008,6 +1015,84 @@ func (s *recordingService) attachLatestApproval(ctx context.Context, item *entit return nil } +type productionStandardValues struct { + HandDay *float64 + HandHouse *float64 + FeedIntake *float64 + EggMesh *float64 + EggWeight *float64 +} + +func (s *recordingService) attachProductionStandards(ctx context.Context, items []entity.Recording) error { + if len(items) == 0 { + return nil + } + + for i := range items { + if err := s.attachProductionStandard(ctx, &items[i]); err != nil { + s.Log.Warnf("Unable to load production standard for recording %d: %+v", items[i].Id, err) + } + } + return nil +} + +func (s *recordingService) attachProductionStandard(ctx context.Context, item *entity.Recording) error { + if item == nil || item.Id == 0 { + return nil + } + if item.Day == nil || *item.Day <= 0 { + return nil + } + if item.ProjectFlockKandang == nil || item.ProjectFlockKandang.ProjectFlock.Id == 0 { + return nil + } + + standardID := item.ProjectFlockKandang.ProjectFlock.ProductionStandardId + if standardID == 0 { + return nil + } + + week := ((int(*item.Day) - 1) / 7) + 1 + if week <= 0 { + return nil + } + + category := strings.ToUpper(item.ProjectFlockKandang.ProjectFlock.Category) + db := s.Repository.DB() + standardDetailRepo := rProductionStandard.NewProductionStandardDetailRepository(db) + growthDetailRepo := rProductionStandard.NewStandardGrowthDetailRepository(db) + + var standard productionStandardValues + if category == string(utils.ProjectFlockCategoryLaying) { + detail, err := standardDetailRepo.GetByStandardIDAndWeek(ctx, standardID, week) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + if detail != nil { + standard.HandDay = detail.TargetHenDayProduction + standard.HandHouse = detail.TargetHenHouseProduction + standard.EggWeight = detail.TargetEggWeight + standard.EggMesh = detail.TargetEggMass + } + } + + growthDetail, err := growthDetailRepo.GetByStandardIDAndWeek(ctx, standardID, week) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + if growthDetail != nil { + standard.FeedIntake = growthDetail.FeedIntake + } + + item.StandardHandDay = standard.HandDay + item.StandardHandHouse = standard.HandHouse + item.StandardFeedIntake = standard.FeedIntake + item.StandardEggMesh = standard.EggMesh + item.StandardEggWeight = standard.EggWeight + + return nil +} + func uniqueUintSlice(values []uint) []uint { if len(values) == 0 { return nil From 0396aa02554624fd89f45b3ea3a9d42a71bae93e Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 14:27:50 +0700 Subject: [PATCH 11/18] feat(BE-287):adjustment purchase restrict unfinished --- .../purchases/services/expense_bridge.go | 44 +++++++++++-------- .../purchases/services/purchase.service.go | 31 +++++++------ 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/internal/modules/purchases/services/expense_bridge.go b/internal/modules/purchases/services/expense_bridge.go index 146f04f2..70a06c92 100644 --- a/internal/modules/purchases/services/expense_bridge.go +++ b/internal/modules/purchases/services/expense_bridge.go @@ -310,9 +310,6 @@ func (b *expenseBridge) OnItemsReceived(c *fiber.Ctx, purchaseID uint, updates [ return err } if cnt == 1 { - if item.Warehouse == nil || item.Warehouse.KandangId == nil || *item.Warehouse.KandangId == 0 { - return fiber.NewError(fiber.StatusBadRequest, "Warehouse not connect to kandangs") - } newNonstockID, err := b.findExpeditionNonstockID(ctx, supplierID) if err != nil { return err @@ -332,7 +329,9 @@ func (b *expenseBridge) OnItemsReceived(c *fiber.Ctx, purchaseID uint, updates [ "price": pricePerItem, "notes": note, "nonstock_id": newNonstockID, - "kandang_id": uint64(*item.Warehouse.KandangId), + } + if item.Warehouse != nil && item.Warehouse.KandangId != nil && *item.Warehouse.KandangId != 0 { + updateBody["kandang_id"] = uint64(*item.Warehouse.KandangId) } if err := b.db.WithContext(ctx). Model(&entity.ExpenseNonstock{}). @@ -550,18 +549,27 @@ func (b *expenseBridge) createExpenseViaService( } kandangID := items[0].kandangID - if kandangID == nil || *kandangID == 0 { - return nil, fiber.NewError(fiber.StatusBadRequest, "Warehouse not connect to kandangs") - } - - kandang, err := b.kandangRepo.GetByID(ctx, *kandangID, func(db *gorm.DB) *gorm.DB { - return db.Select("id, location_id") - }) - if err != nil { - return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Kandang not found: %d", *kandangID)) - } - if kandang == nil { - return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Kandang not found: %d", *kandangID)) + var locationID uint64 + var expenseKandangID *uint64 + if kandangID != nil && *kandangID != 0 { + kandang, err := b.kandangRepo.GetByID(ctx, *kandangID, func(db *gorm.DB) *gorm.DB { + return db.Select("id, location_id") + }) + if err != nil { + return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Kandang not found: %d", *kandangID)) + } + if kandang == nil { + return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Kandang not found: %d", *kandangID)) + } + locationID = uint64(kandang.LocationId) + id := uint64(*kandangID) + expenseKandangID = &id + } else { + warehouse := items[0].item.Warehouse + if warehouse == nil || warehouse.LocationId == nil || *warehouse.LocationId == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "Warehouse location is required for expense") + } + locationID = uint64(*warehouse.LocationId) } costItems := make([]expenseValidation.CostItem, 0, len(items)) @@ -584,9 +592,9 @@ func (b *expenseBridge) createExpenseViaService( TransactionDate: utils.FormatDate(expenseDate), Category: "BOP", SupplierID: uint64(supplierID), - LocationID: uint64(kandang.LocationId), + LocationID: locationID, ExpenseNonstocks: []expenseValidation.ExpenseNonstock{{ - KandangID: func() *uint64 { id := uint64(*kandangID); return &id }(), + KandangID: expenseKandangID, CostItems: costItems, }}, } diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 366a8c0e..43c2bdc7 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -246,22 +246,25 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase s.Log.Errorf("Failed to get warehouse %d: %+v", id, err) return nil, nil, utils.Internal("Failed to get warehouse") } - if warehouse.KandangId == nil || *warehouse.KandangId == 0 { - return nil, nil, utils.BadRequest(fmt.Sprintf("%s is not linked to a kandang", warehouse.Name)) - } var pfkID *uint - if s.ProjectFlockKandangRepo != nil { - if pfk, err := s.ProjectFlockKandangRepo.GetActiveByKandangID(c.Context(), uint(*warehouse.KandangId)); err == nil && pfk != nil { - if pfk.ClosedAt != nil { - return nil, nil, utils.BadRequest("Project sudah closing") + isKandang := strings.EqualFold(strings.TrimSpace(warehouse.Type), "KANDANG") + if isKandang { + if warehouse.KandangId == nil || *warehouse.KandangId == 0 { + return nil, nil, utils.BadRequest(fmt.Sprintf("%s is not linked to a kandang", warehouse.Name)) + } + if s.ProjectFlockKandangRepo != nil { + if pfk, err := s.ProjectFlockKandangRepo.GetActiveByKandangID(c.Context(), uint(*warehouse.KandangId)); err == nil && pfk != nil { + if pfk.ClosedAt != nil { + return nil, nil, utils.BadRequest("Project sudah closing") + } + idCopy := uint(pfk.Id) + pfkID = &idCopy + } else if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil, utils.BadRequest(fmt.Sprintf("%s has no active project flock", warehouse.Name)) + } else if err != nil { + s.Log.Errorf("Failed to validate project flock for warehouse %d: %+v", id, err) + return nil, nil, utils.Internal("Failed to validate project flock") } - idCopy := uint(pfk.Id) - pfkID = &idCopy - } else if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil, utils.BadRequest(fmt.Sprintf("%s has no active project flock", warehouse.Name)) - } else if err != nil { - s.Log.Errorf("Failed to validate project flock for warehouse %d: %+v", id, err) - return nil, nil, utils.Internal("Failed to validate project flock") } } From 4e5caa8cbafa5bc32c48b0bd17a3e3061008f526 Mon Sep 17 00:00:00 2001 From: ragilap Date: Tue, 30 Dec 2025 15:23:34 +0700 Subject: [PATCH 12/18] feat(BE-281): add rbac for uniformity --- internal/middleware/permissions.go | 10 ++++++++ .../modules/production/uniformities/route.go | 23 ++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/internal/middleware/permissions.go b/internal/middleware/permissions.go index d384fee7..32ee5ecb 100644 --- a/internal/middleware/permissions.go +++ b/internal/middleware/permissions.go @@ -193,6 +193,16 @@ const ( P_PurchaseApprovalManager = "lti.Purchase.approve.manager" ) +const ( + P_Uniformities_GetAll = "lti.production.uniformity.list" + P_Uniformities_GetOne = "lti.production.uniformity.detail" + P_Uniformities_Verify = "lti.production.uniformity.verify" + P_Uniformities_CreateOne = "lti.production.uniformity.create" + P_Uniformities_UpdateOne = "lti.production.uniformity.update" + P_Uniformities_DeleteOne = "lti.production.uniformity.delete" + P_Uniformities_Approval = "lti.production.uniformity.approve" +) + const ( P_UserGetAll = "lti.users.list" P_UserGetOne = "lti.users.detail" diff --git a/internal/modules/production/uniformities/route.go b/internal/modules/production/uniformities/route.go index d22e8761..ff2b1805 100644 --- a/internal/modules/production/uniformities/route.go +++ b/internal/modules/production/uniformities/route.go @@ -1,7 +1,7 @@ package uniformitys import ( - // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/controllers" uniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,18 +13,13 @@ func UniformityRoutes(v1 fiber.Router, u user.UserService, s uniformity.Uniformi ctrl := controller.NewUniformityController(s) route := v1.Group("/uniformities") + route.Use(m.Auth(u)) - // route.Get("/", m.Auth(u), ctrl.GetAll) - // route.Post("/", m.Auth(u), ctrl.CreateOne) - // route.Get("/:id", m.Auth(u), ctrl.GetOne) - // route.Patch("/:id", m.Auth(u), ctrl.UpdateOne) - // route.Delete("/:id", m.Auth(u), ctrl.DeleteOne) - - route.Get("/", ctrl.GetAll) - route.Post("/", ctrl.CreateOne) - route.Post("/verify", ctrl.UploadBodyWeightExcel) - route.Post("/approvals", ctrl.Approve) - route.Get("/:id", ctrl.GetOne) - route.Patch("/:id", ctrl.UpdateOne) - route.Delete("/:id", ctrl.DeleteOne) + route.Get("/", m.RequirePermissions(m.P_Uniformities_GetAll), ctrl.GetAll) + route.Post("/", m.RequirePermissions(m.P_Uniformities_CreateOne), ctrl.CreateOne) + route.Post("/verify", m.RequirePermissions(m.P_Uniformities_Verify), ctrl.UploadBodyWeightExcel) + route.Post("/approvals", m.RequirePermissions(m.P_Uniformities_Approval), ctrl.Approve) + route.Get("/:id", m.RequirePermissions(m.P_Uniformities_GetOne), ctrl.GetOne) + route.Patch("/:id", m.RequirePermissions(m.P_Uniformities_UpdateOne), ctrl.UpdateOne) + route.Delete("/:id", m.RequirePermissions(m.P_Uniformities_DeleteOne), ctrl.DeleteOne) } From fd5f83ca58cc1c140a6e6977bee98f6f73b5031c Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 03:50:58 +0700 Subject: [PATCH 13/18] feat(BE-278): unrestrict feat warehouse purchase,adding purchase upload document --- internal/middleware/permissions.go | 1 + .../expenses/services/expense.service.go | 24 +++-- .../product_warehouse.repository.go | 25 +++++ .../controllers/purchase.controller.go | 36 +++++-- internal/modules/purchases/module.go | 1 + .../purchases/services/expense_bridge.go | 4 + .../purchases/services/purchase.service.go | 98 ++++++++++++++----- .../validations/purchase.validation.go | 29 +++--- internal/modules/repports/route.go | 2 +- internal/utils/constant.go | 2 + 10 files changed, 159 insertions(+), 63 deletions(-) diff --git a/internal/middleware/permissions.go b/internal/middleware/permissions.go index f0056149..1d308787 100644 --- a/internal/middleware/permissions.go +++ b/internal/middleware/permissions.go @@ -44,6 +44,7 @@ const ( P_ReportExpenseGetAll = "lti.repport.expense.list" P_ReportDeliveryGetAll = "lti.repport.delivery.list" P_ReportPurchaseSupplierGetAll = "lti.repport.purchasesupplier.list" + P_ReportHppPerKandangGetAll = "lti.repport.gethppperkandang.list" ) const ( diff --git a/internal/modules/expenses/services/expense.service.go b/internal/modules/expenses/services/expense.service.go index b4753451..37d4cec0 100644 --- a/internal/modules/expenses/services/expense.service.go +++ b/internal/modules/expenses/services/expense.service.go @@ -214,21 +214,19 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen return fiber.NewError(fiber.StatusInternalServerError, "Failed to get active project flocks for location") } - if len(activeProjectFlocks) == 0 { - return fiber.NewError(fiber.StatusBadRequest, "No active project flocks found for this location") - } + if len(activeProjectFlocks) > 0 { + projectFlockIDs := make([]uint64, len(activeProjectFlocks)) + for i, pf := range activeProjectFlocks { + projectFlockIDs[i] = uint64(pf.Id) + } - projectFlockIDs := make([]uint64, len(activeProjectFlocks)) - for i, pf := range activeProjectFlocks { - projectFlockIDs[i] = uint64(pf.Id) + projectFlockIdsJSON, err := json.Marshal(projectFlockIDs) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal project_flock_ids") + } + jsonStr := string(projectFlockIdsJSON) + projectFlockIdJSON = &jsonStr } - - projectFlockIdsJSON, err := json.Marshal(projectFlockIDs) - if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal project_flock_ids") - } - jsonStr := string(projectFlockIdsJSON) - projectFlockIdJSON = &jsonStr } expense = &entity.Expense{ diff --git a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go index e759138e..3cb22851 100644 --- a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go +++ b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go @@ -199,6 +199,31 @@ func (r *ProductWarehouseRepositoryImpl) CleanupEmpty(ctx context.Context, affec return nil } + var inUseIDs []uint + if err := r.DB().WithContext(ctx). + Model(&entity.PurchaseItem{}). + Where("product_warehouse_id IN ?", emptyIDs). + Distinct(). + Pluck("product_warehouse_id", &inUseIDs).Error; err != nil { + return err + } + if len(inUseIDs) > 0 { + inUse := make(map[uint]struct{}, len(inUseIDs)) + for _, id := range inUseIDs { + inUse[id] = struct{}{} + } + filtered := make([]uint, 0, len(emptyIDs)) + for _, id := range emptyIDs { + if _, exists := inUse[id]; !exists { + filtered = append(filtered, id) + } + } + emptyIDs = filtered + } + if len(emptyIDs) == 0 { + return nil + } + if err := r.DB().WithContext(ctx). Model(&entity.PurchaseItem{}). Where("product_warehouse_id IN ?", emptyIDs). diff --git a/internal/modules/purchases/controllers/purchase.controller.go b/internal/modules/purchases/controllers/purchase.controller.go index b4cf5660..d9b32cd1 100644 --- a/internal/modules/purchases/controllers/purchase.controller.go +++ b/internal/modules/purchases/controllers/purchase.controller.go @@ -1,6 +1,7 @@ package controller import ( + "encoding/json" "fmt" "math" "strconv" @@ -24,13 +25,13 @@ func NewPurchaseController(s service.PurchaseService) *PurchaseController { func (ctrl *PurchaseController) GetAll(c *fiber.Ctx) error { query := &validation.Query{ - Page: c.QueryInt("page", 1), - Limit: c.QueryInt("limit", 10), - CreatedFrom: strings.TrimSpace(c.Query("created_from")), - CreatedTo: strings.TrimSpace(c.Query("created_to")), - SupplierID: uint(c.QueryInt("supplier_id", 0)), - AreaID: uint(c.QueryInt("area_id", 0)), - LocationID: uint(c.QueryInt("location_id", 0)), + Page: c.QueryInt("page", 1), + Limit: c.QueryInt("limit", 10), + CreatedFrom: strings.TrimSpace(c.Query("created_from")), + CreatedTo: strings.TrimSpace(c.Query("created_to")), + SupplierID: uint(c.QueryInt("supplier_id", 0)), + AreaID: uint(c.QueryInt("area_id", 0)), + LocationID: uint(c.QueryInt("location_id", 0)), ProductCategoryID: uint(c.QueryInt("product_category_id", 0)), } @@ -86,7 +87,6 @@ func (ctrl *PurchaseController) CreateOne(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - result, err := ctrl.service.CreateOne(c, req) if err != nil { return err @@ -161,10 +161,26 @@ func (ctrl *PurchaseController) ReceiveProducts(c *fiber.Ctx) error { } req := new(validation.ReceivePurchaseRequest) - if err := c.BodyParser(req); err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + form, err := c.MultipartForm() + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") + } + req.Action = c.FormValue("action") + if notes := strings.TrimSpace(c.FormValue("notes")); notes != "" { + req.Notes = ¬es } + itemsJSON := c.FormValue("items") + if strings.TrimSpace(itemsJSON) != "" { + if err := json.Unmarshal([]byte(itemsJSON), &req.Items); err != nil { + var singleItem validation.ReceivePurchaseItemRequest + if err := json.Unmarshal([]byte(itemsJSON), &singleItem); err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid items JSON") + } + req.Items = []validation.ReceivePurchaseItemRequest{singleItem} + } + } + req.TravelDocuments = form.File["documents"] result, err := ctrl.service.ReceiveProducts(c, uint(id), req) if err != nil { return err diff --git a/internal/modules/purchases/module.go b/internal/modules/purchases/module.go index fa10559d..7e80de38 100644 --- a/internal/modules/purchases/module.go +++ b/internal/modules/purchases/module.go @@ -98,6 +98,7 @@ func (PurchaseModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate approvalService, expenseBridge, fifoService, + documentSvc, ) userRepo := rUser.NewUserRepository(db) diff --git a/internal/modules/purchases/services/expense_bridge.go b/internal/modules/purchases/services/expense_bridge.go index 70a06c92..6c74a1fc 100644 --- a/internal/modules/purchases/services/expense_bridge.go +++ b/internal/modules/purchases/services/expense_bridge.go @@ -394,9 +394,13 @@ func (b *expenseBridge) OnItemsReceived(c *fiber.Ctx, purchaseID uint, updates [ } if kandangID != nil { updateBody["kandang_id"] = uint64(*kandangID) + } else { + updateBody["kandang_id"] = nil } if projectFK != nil { updateBody["project_flock_kandang_id"] = uint64(*projectFK) + } else { + updateBody["project_flock_kandang_id"] = nil } if err := b.db.WithContext(ctx). diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 43c2bdc7..813fbd6f 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math" + "mime/multipart" "strings" "time" @@ -57,6 +58,7 @@ type purchaseService struct { ApprovalSvc commonSvc.ApprovalService ExpenseBridge PurchaseExpenseBridge FifoSvc commonSvc.FifoService + DocumentSvc commonSvc.DocumentService approvalWorkflow approvalutils.ApprovalWorkflowKey } @@ -76,6 +78,7 @@ func NewPurchaseService( approvalSvc commonSvc.ApprovalService, expenseBridge PurchaseExpenseBridge, fifoSvc commonSvc.FifoService, + documentSvc commonSvc.DocumentService, ) PurchaseService { return &purchaseService{ Log: utils.Log, @@ -89,6 +92,7 @@ func NewPurchaseService( ApprovalSvc: approvalSvc, ExpenseBridge: expenseBridge, FifoSvc: fifoSvc, + DocumentSvc: documentSvc, approvalWorkflow: utils.ApprovalWorkflowPurchase, } } @@ -615,9 +619,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation if err := s.Validate.Struct(req); err != nil { return nil, err } - ctx := c.Context() - action, err := parseApprovalActionInput(req.Action) if err != nil { return nil, err @@ -664,6 +666,30 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation return updated, nil } + if action == entity.ApprovalActionApproved && len(req.TravelDocuments) > 0 { + if len(req.TravelDocuments) > len(req.Items) { + return nil, utils.BadRequest("Travel documents exceed total receiving items") + } + for idx, file := range req.TravelDocuments { + if file == nil { + continue + } + if idx >= len(req.Items) { + break + } + itemID := req.Items[idx].PurchaseItemID + if itemID == 0 { + return nil, utils.BadRequest("Purchase item id is required for travel document upload") + } + uploadedURL, err := s.uploadTravelDocument(ctx, actorID, itemID, file) + if err != nil { + s.Log.Errorf("Failed to upload travel document for item %d: %+v", itemID, err) + return nil, utils.Internal("Failed to upload travel document") + } + req.Items[idx].TravelDocumentPath = &uploadedURL + } + } + itemMap := make(map[uint]*entity.PurchaseItem, len(purchase.Items)) for i := range purchase.Items { itemMap[purchase.Items[i].Id] = &purchase.Items[i] @@ -807,32 +833,20 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation for _, prep := range prepared { item := prep.item - var oldPWID *uint - if item.ProductWarehouseId != nil { - idCopy := uint(*item.ProductWarehouseId) - oldPWID = &idCopy - } - var newPWID *uint - clearPW := false - // Always ensure PW when qty > 0 so stockable has target. - if prep.receivedQty > 0 { - pwID, err := pwRepoTx.EnsureProductWarehouse( - c.Context(), - uint(item.ProductId), - prep.warehouseID, - item.ProjectFlockKandangId, - purchase.CreatedBy, - ) - if err != nil { - return err - } - newPWID = &pwID - } else if oldPWID != nil { - newPWID = oldPWID - clearPW = true + // Always ensure PW after receiving so linkage stays stable. + pwID, err := pwRepoTx.EnsureProductWarehouse( + c.Context(), + uint(item.ProductId), + prep.warehouseID, + item.ProjectFlockKandangId, + purchase.CreatedBy, + ) + if err != nil { + return err } + newPWID = &pwID deltaQty := prep.receivedQty - item.TotalQty switch { @@ -857,7 +871,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation VehicleNumber: prep.payload.VehicleNumber, ReceivedQty: &qtyCopy, ProductWarehouseID: newPWID, - ClearProductWarehouse: clearPW, + ClearProductWarehouse: false, } if prep.overrideWarehouse || uint(item.WarehouseId) != prep.warehouseID { @@ -972,6 +986,38 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation return updated, nil } +func (s *purchaseService) uploadTravelDocument( + ctx context.Context, + actorID uint, + itemID uint, + file *multipart.FileHeader, +) (string, error) { + if file == nil { + return "", errors.New("travel document file is required") + } + if s.DocumentSvc == nil { + return "", errors.New("document service not available") + } + + documentFiles := []commonSvc.DocumentFile{{ + File: file, + Type: string(utils.DocumentTypePurchaseTravel), + }} + results, err := s.DocumentSvc.UploadDocuments(ctx, commonSvc.DocumentUploadRequest{ + DocumentableType: string(utils.DocumentableTypePurchaseItem), + DocumentableID: uint64(itemID), + CreatedBy: &actorID, + Files: documentFiles, + }) + if err != nil { + return "", err + } + if len(results) == 0 { + return "", errors.New("upload result is empty") + } + return results[0].URL, nil +} + func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) { if err := s.Validate.Struct(req); err != nil { return nil, err diff --git a/internal/modules/purchases/validations/purchase.validation.go b/internal/modules/purchases/validations/purchase.validation.go index 1637ccaf..564cc96f 100644 --- a/internal/modules/purchases/validations/purchase.validation.go +++ b/internal/modules/purchases/validations/purchase.validation.go @@ -1,5 +1,7 @@ package validation +import "mime/multipart" + type PurchaseItemPayload struct { WarehouseID uint `json:"warehouse_id" validate:"required,gt=0"` ProductID uint `json:"product_id" validate:"required,gt=0"` @@ -26,7 +28,7 @@ type StaffPurchaseApprovalItem struct { type ApproveStaffPurchaseRequest struct { Action string `json:"action" validate:"required,oneof=APPROVED REJECTED"` - Items []StaffPurchaseApprovalItem `json:"items,omitempty" validate:"omitempty,min=1,dive"` + Items []StaffPurchaseApprovalItem `json:"items" validate:"omitempty,min=1,dive"` Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"` } @@ -36,21 +38,22 @@ type ApproveManagerPurchaseRequest struct { } type ReceivePurchaseItemRequest struct { - PurchaseItemID uint `json:"purchase_item_id" validate:"required,gt=0"` - WarehouseID *uint `json:"warehouse_id" validate:"omitempty,gt=0"` - ReceivedDate string `json:"received_date" validate:"required,datetime=2006-01-02"` - ExpeditionVendorID *uint `json:"expedition_vendor_id,omitempty" validate:"omitempty,gt=0"` - TransportPerItem *float64 `json:"transport_per_item,omitempty" validate:"omitempty,gte=0"` - TravelNumber *string `json:"travel_number" validate:"omitempty,max=100"` - TravelDocumentPath *string `json:"travel_document_path" validate:"omitempty,max=255"` - VehicleNumber *string `json:"vehicle_number" validate:"omitempty,max=100"` - ReceivedQty *float64 `json:"received_qty" validate:"omitempty,gte=0"` + PurchaseItemID uint `form:"purchase_item_id" json:"purchase_item_id" validate:"required,gt=0"` + WarehouseID *uint `form:"warehouse_id" json:"warehouse_id" validate:"omitempty,gt=0"` + ReceivedDate string `form:"received_date" json:"received_date" validate:"required,datetime=2006-01-02"` + ExpeditionVendorID *uint `form:"expedition_vendor_id" json:"expedition_vendor_id,omitempty" validate:"omitempty,gt=0"` + TransportPerItem *float64 `form:"transport_per_item" json:"transport_per_item,omitempty" validate:"omitempty,gte=0"` + TravelNumber *string `form:"travel_number" json:"travel_number" validate:"omitempty,max=100"` + TravelDocumentPath *string `form:"travel_document_path" json:"travel_document_path" validate:"omitempty,max=1024"` + VehicleNumber *string `form:"vehicle_number" json:"vehicle_number" validate:"omitempty,max=100"` + ReceivedQty *float64 `form:"received_qty" json:"received_qty" validate:"omitempty,gte=0"` } type ReceivePurchaseRequest struct { - Action string `json:"action" validate:"required,oneof=APPROVED REJECTED"` - Items []ReceivePurchaseItemRequest `json:"items,omitempty" validate:"omitempty,min=1,dive"` - Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"` + Action string `form:"action" json:"action" validate:"required,oneof=APPROVED REJECTED"` + Items []ReceivePurchaseItemRequest `form:"items" json:"items" validate:"min=1,dive"` + TravelDocuments []*multipart.FileHeader `form:"travel_documents" json:"-" validate:"omitempty,dive"` + Notes *string `form:"notes" json:"notes,omitempty" validate:"omitempty,max=500"` } type DeletePurchaseItemsRequest struct { diff --git a/internal/modules/repports/route.go b/internal/modules/repports/route.go index 707ef878..83f133af 100644 --- a/internal/modules/repports/route.go +++ b/internal/modules/repports/route.go @@ -18,6 +18,6 @@ func RepportRoutes(v1 fiber.Router, u user.UserService, s repport.RepportService route.Get("/expense", m.RequirePermissions(m.P_ReportExpenseGetAll), ctrl.GetExpense) route.Get("/marketing", m.RequirePermissions(m.P_ReportDeliveryGetAll), ctrl.GetMarketing) route.Get("/purchase-supplier", m.RequirePermissions(m.P_ReportPurchaseSupplierGetAll), ctrl.GetPurchaseSupplier) - route.Get("/hpp-per-kandang", ctrl.GetHppPerKandang) + route.Get("/hpp-per-kandang", m.RequirePermissions(m.P_ReportHppPerKandangGetAll),ctrl.GetHppPerKandang) } diff --git a/internal/utils/constant.go b/internal/utils/constant.go index 85b0cc91..b7875605 100644 --- a/internal/utils/constant.go +++ b/internal/utils/constant.go @@ -411,10 +411,12 @@ const ( DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT" DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT" DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT" + DocumentTypePurchaseTravel DocumentType = "PURCHASE_TRAVEL_DOCUMENT" DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER" DocumentableTypeExpense DocumentableType = "EXPENSE" DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION" + DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM" ) // ------------------------------------------------------------------- From bc03c469f24d4c0249e22701d3fea2efc8932928 Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 04:00:41 +0700 Subject: [PATCH 14/18] feat(BE-278): add delete document s3 --- .../purchases/services/purchase.service.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 813fbd6f..31e55b86 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -1097,6 +1097,10 @@ func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.Del return nil, utils.Internal("Failed to delete purchase items") } + if err := s.deletePurchaseItemDocuments(ctx, itemsToDelete); err != nil { + return nil, utils.Internal("Failed to delete purchase documents") + } + if len(itemsToDelete) > 0 { if err := s.notifyExpenseItemsDeleted(ctx, purchase.Id, itemsToDelete); err != nil { s.Log.Errorf("Failed to sync expense deletion for purchase %d: %+v", purchase.Id, err) @@ -1156,6 +1160,10 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error { return utils.Internal("Failed to delete purchase") } + if err := s.deletePurchaseItemDocuments(ctx, itemsToDelete); err != nil { + return utils.Internal("Failed to delete purchase documents") + } + if len(itemsToDelete) > 0 { if err := s.notifyExpenseItemsDeleted(ctx, uint(id), itemsToDelete); err != nil { s.Log.Errorf("Failed to sync expense deletion for purchase %d: %+v", id, err) @@ -1239,6 +1247,21 @@ func (s *purchaseService) notifyExpenseItemsDeleted(ctx context.Context, purchas } +func (s *purchaseService) deletePurchaseItemDocuments(ctx context.Context, items []entity.PurchaseItem) error { + if s.DocumentSvc == nil || len(items) == 0 { + return nil + } + for _, item := range items { + if item.Id == 0 { + continue + } + if err := s.DocumentSvc.DeleteByTarget(ctx, string(utils.DocumentableTypePurchaseItem), uint64(item.Id), true); err != nil { + return err + } + } + return nil +} + func (s *purchaseService) buildStaffAdjustmentPayload( ctx context.Context, purchase *entity.Purchase, From 709e304f7ff47d0b6f264e62a4a309cedd934891 Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 07:39:20 +0700 Subject: [PATCH 15/18] feat(BE-281): adjustment bug erorr 500 if 404 record projectflock --- .../production/project_flocks/services/projectflock.service.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/modules/production/project_flocks/services/projectflock.service.go b/internal/modules/production/project_flocks/services/projectflock.service.go index 75c89c8e..1e859e47 100644 --- a/internal/modules/production/project_flocks/services/projectflock.service.go +++ b/internal/modules/production/project_flocks/services/projectflock.service.go @@ -959,6 +959,9 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont warehouse, err := warehouseRepo.GetByKandangID(ctx, record.KandangId) if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Warehouse untuk kandang %d belum tersedia", record.KandangId)) + } return err } From dbaee7313455b8f237bf03f9698d41adb56ef38e Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 07:50:13 +0700 Subject: [PATCH 16/18] feat(BE-278): fix error purchase product warehouse --- internal/modules/purchases/services/purchase.service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 31e55b86..7dac0e19 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -1534,5 +1534,5 @@ func (s *purchaseService) ensureProjectFlockNotClosedForPurchase( return utils.Internal("DB not available for project flock validation") } - return commonSvc.EnsureProjectFlockNotClosedForProductWarehouses(ctx, db, pfkIDs) + return commonSvc.EnsureProjectFlockNotClosedByProjectFlockKandangID(ctx, db, pfkIDs) } From d9afd2913e90d1c93e8806a1f7b69fa8cfdaef7a Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 09:13:55 +0700 Subject: [PATCH 17/18] feat(BE-278): adjustment_recording dto --- internal/entities/recording.go | 1 + .../recordings/dto/recording.dto.go | 2 ++ .../repositories/recording.repository.go | 29 ++++++++++++++++++- .../recordings/services/recording.service.go | 17 +++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/internal/entities/recording.go b/internal/entities/recording.go index e07a0a6b..03388ef2 100644 --- a/internal/entities/recording.go +++ b/internal/entities/recording.go @@ -39,4 +39,5 @@ type Recording struct { StandardFeedIntake *float64 `gorm:"-"` StandardEggMesh *float64 `gorm:"-"` StandardEggWeight *float64 `gorm:"-"` + StandardFcr *float64 `gorm:"-"` } diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index 12222b97..736eeaa7 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -35,6 +35,7 @@ type RecordingRelationDTO struct { StandardFeedIntake *float64 `json:"feed_intake_std,omitempty"` StandardEggMesh *float64 `json:"egg_mesh_std,omitempty"` StandardEggWeight *float64 `json:"egg_weight_std,omitempty"` + StandardFcr *float64 `json:"fcr_std,omitempty"` Approval approvalDTO.ApprovalRelationDTO `json:"approval"` } @@ -165,6 +166,7 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { StandardFeedIntake: e.StandardFeedIntake, StandardEggMesh: e.StandardEggMesh, StandardEggWeight: e.StandardEggWeight, + StandardFcr: e.StandardFcr, Approval: latestApproval, } } diff --git a/internal/modules/production/recordings/repositories/recording.repository.go b/internal/modules/production/recordings/repositories/recording.repository.go index 8642ed08..d9e0bc0b 100644 --- a/internal/modules/production/recordings/repositories/recording.repository.go +++ b/internal/modules/production/recordings/repositories/recording.repository.go @@ -42,6 +42,7 @@ type RecordingRepository interface { GetFeedUsageInGrams(tx *gorm.DB, recordingID uint) (float64, error) GetEggSummaryByRecording(tx *gorm.DB, recordingID uint) (totalQty float64, totalWeightGrams float64, err error) GetCumulativeEggQtyByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint, recordTime time.Time) (float64, error) + GetFcrStandardNumber(tx *gorm.DB, fcrId uint, currentWeightKg float64) (float64, bool, error) GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error) GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (totalDepletion float64, err error) GetLatestAvgWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (avgWeight float64, err error) @@ -344,12 +345,38 @@ func (r *RecordingRepositoryImpl) GetCumulativeEggQtyByProjectFlockKandang( return result, err } +func (r *RecordingRepositoryImpl) GetFcrStandardNumber(tx *gorm.DB, fcrId uint, currentWeightKg float64) (float64, bool, error) { + if fcrId == 0 || currentWeightKg <= 0 { + return 0, false, nil + } + + var standard entity.FcrStandard + err := tx. + Where("fcr_id = ? AND weight >= ?", fcrId, currentWeightKg). + Order("weight ASC"). + First(&standard).Error + + if errors.Is(err, gorm.ErrRecordNotFound) { + err = tx. + Where("fcr_id = ?", fcrId). + Order("weight DESC"). + First(&standard).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return 0, false, nil + } + } + if err != nil { + return 0, false, err + } + + return standard.FcrNumber, true, nil +} + func (r *RecordingRepositoryImpl) GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error) { // Body-weight tracking is removed; keep stub for report compatibility. return 0, 0, nil } - func (r *RecordingRepositoryImpl) GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) { var result float64 err := r.DB().WithContext(ctx). diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index a3756adf..1a63ad96 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -1063,6 +1063,7 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e growthDetailRepo := rProductionStandard.NewStandardGrowthDetailRepository(db) var standard productionStandardValues + var standardFcr *float64 if category == string(utils.ProjectFlockCategoryLaying) { detail, err := standardDetailRepo.GetByStandardIDAndWeek(ctx, standardID, week) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { @@ -1082,6 +1083,21 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e } if growthDetail != nil { standard.FeedIntake = growthDetail.FeedIntake + if category == string(utils.ProjectFlockCategoryLaying) && growthDetail.TargetMeanBw != nil && item.ProjectFlockKandang.ProjectFlock.FcrId > 0 { + targetWeight := *growthDetail.TargetMeanBw + if targetWeight > 10 { + targetWeight = targetWeight / 1000 + } + if targetWeight > 0 { + fcrStd, ok, err := s.Repository.GetFcrStandardNumber(db, item.ProjectFlockKandang.ProjectFlock.FcrId, targetWeight) + if err != nil { + return err + } + if ok { + standardFcr = &fcrStd + } + } + } } item.StandardHandDay = standard.HandDay @@ -1089,6 +1105,7 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e item.StandardFeedIntake = standard.FeedIntake item.StandardEggMesh = standard.EggMesh item.StandardEggWeight = standard.EggWeight + item.StandardFcr = standardFcr return nil } From b8c0b0c37d9c5cf242786e3f30db5cb669054c19 Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 31 Dec 2025 09:44:20 +0700 Subject: [PATCH 18/18] feat(BE-278): add std for max_depletion --- internal/entities/recording.go | 13 +++++++------ .../production/recordings/dto/recording.dto.go | 2 ++ .../recordings/services/recording.service.go | 13 ++++++++----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/internal/entities/recording.go b/internal/entities/recording.go index 03388ef2..7f952a62 100644 --- a/internal/entities/recording.go +++ b/internal/entities/recording.go @@ -34,10 +34,11 @@ type Recording struct { LatestApproval *Approval `gorm:"-" json:"-"` - StandardHandDay *float64 `gorm:"-"` - StandardHandHouse *float64 `gorm:"-"` - StandardFeedIntake *float64 `gorm:"-"` - StandardEggMesh *float64 `gorm:"-"` - StandardEggWeight *float64 `gorm:"-"` - StandardFcr *float64 `gorm:"-"` + StandardHandDay *float64 `gorm:"-"` + StandardHandHouse *float64 `gorm:"-"` + StandardFeedIntake *float64 `gorm:"-"` + StandardMaxDepletion *float64 `gorm:"-"` + StandardEggMesh *float64 `gorm:"-"` + StandardEggWeight *float64 `gorm:"-"` + StandardFcr *float64 `gorm:"-"` } diff --git a/internal/modules/production/recordings/dto/recording.dto.go b/internal/modules/production/recordings/dto/recording.dto.go index 736eeaa7..c34651ba 100644 --- a/internal/modules/production/recordings/dto/recording.dto.go +++ b/internal/modules/production/recordings/dto/recording.dto.go @@ -33,6 +33,7 @@ type RecordingRelationDTO struct { StandardHandDay *float64 `json:"hand_day_std,omitempty"` StandardHandHouse *float64 `json:"hand_house_std,omitempty"` StandardFeedIntake *float64 `json:"feed_intake_std,omitempty"` + StandardMaxDepletion *float64 `json:"max_depletion_std,omitempty"` StandardEggMesh *float64 `json:"egg_mesh_std,omitempty"` StandardEggWeight *float64 `json:"egg_weight_std,omitempty"` StandardFcr *float64 `json:"fcr_std,omitempty"` @@ -164,6 +165,7 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO { StandardHandDay: e.StandardHandDay, StandardHandHouse: e.StandardHandHouse, StandardFeedIntake: e.StandardFeedIntake, + StandardMaxDepletion: e.StandardMaxDepletion, StandardEggMesh: e.StandardEggMesh, StandardEggWeight: e.StandardEggWeight, StandardFcr: e.StandardFcr, diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 1a63ad96..5b09d003 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -1016,11 +1016,12 @@ func (s *recordingService) attachLatestApproval(ctx context.Context, item *entit } type productionStandardValues struct { - HandDay *float64 - HandHouse *float64 - FeedIntake *float64 - EggMesh *float64 - EggWeight *float64 + HandDay *float64 + HandHouse *float64 + FeedIntake *float64 + MaxDepletion *float64 + EggMesh *float64 + EggWeight *float64 } func (s *recordingService) attachProductionStandards(ctx context.Context, items []entity.Recording) error { @@ -1083,6 +1084,7 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e } if growthDetail != nil { standard.FeedIntake = growthDetail.FeedIntake + standard.MaxDepletion = growthDetail.MaxDepletion if category == string(utils.ProjectFlockCategoryLaying) && growthDetail.TargetMeanBw != nil && item.ProjectFlockKandang.ProjectFlock.FcrId > 0 { targetWeight := *growthDetail.TargetMeanBw if targetWeight > 10 { @@ -1103,6 +1105,7 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e item.StandardHandDay = standard.HandDay item.StandardHandHouse = standard.HandHouse item.StandardFeedIntake = standard.FeedIntake + item.StandardMaxDepletion = standard.MaxDepletion item.StandardEggMesh = standard.EggMesh item.StandardEggWeight = standard.EggWeight item.StandardFcr = standardFcr