From da99bf142902d55213d1464c01ff4541de77c83a Mon Sep 17 00:00:00 2001 From: Adnan Zahir Date: Sat, 2 May 2026 17:03:57 +0700 Subject: [PATCH] fix: allow editing sold egg weight on recording --- .../repositories/recording.repository.go | 7 +++ .../recordings/services/recording.service.go | 46 ++++++++++++++++++- internal/utils/recording/util.recording.go | 13 ++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/internal/modules/production/recordings/repositories/recording.repository.go b/internal/modules/production/recordings/repositories/recording.repository.go index 8b58b8a3..ceb747ae 100644 --- a/internal/modules/production/recordings/repositories/recording.repository.go +++ b/internal/modules/production/recordings/repositories/recording.repository.go @@ -49,6 +49,7 @@ type RecordingRepository interface { DeleteEggs(tx *gorm.DB, recordingID uint) error ListEggs(tx *gorm.DB, recordingID uint) ([]entity.RecordingEgg, error) UpdateEggTotalQty(tx *gorm.DB, eggID uint, totalQty float64) error + UpdateEggWeight(tx *gorm.DB, eggID uint, weight *float64) error GetRecordingEggByID(ctx context.Context, id uint, modifier func(*gorm.DB) *gorm.DB) (*entity.RecordingEgg, error) ExistsOnDate(ctx context.Context, projectFlockKandangId uint, recordTime time.Time) (bool, error) @@ -543,6 +544,12 @@ func (r *RecordingRepositoryImpl) UpdateEggTotalQty(tx *gorm.DB, eggID uint, tot Update("total_qty", totalQty).Error } +func (r *RecordingRepositoryImpl) UpdateEggWeight(tx *gorm.DB, eggID uint, weight *float64) error { + return tx.Model(&entity.RecordingEgg{}). + Where("id = ?", eggID). + Update("weight", weight).Error +} + func (r *RecordingRepositoryImpl) GetRecordingEggByID( ctx context.Context, id uint, diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 5d24cf76..c7bfe648 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -799,6 +799,12 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin match := recordingutil.EggTotalsEqual(existingTotals, incomingTotals) if match { hasEggChanges = false + } else if recordingutil.EggQtyByWarehouseEqual(existingTotals, incomingTotals) { + // Weight-only change: update weight fields directly without touching FIFO + if err := s.updateEggWeightsOnly(tx, existingEggs, req.Eggs); err != nil { + return err + } + // hasEggChanges stays true so metrics are recomputed } else { category := "" if recordingEntity.ProjectFlockKandang != nil && recordingEntity.ProjectFlockKandang.ProjectFlock.Id != 0 { @@ -816,7 +822,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin if err := s.ensureProductWarehousesByFlags(ctx, eggIDs, []string{"TELUR-UTUH", "TELUR-PECAH", "TELUR-PUTIH", "TELUR-RETAK", "TELUR"}, "egg"); err != nil { return err } - if err := ensureRecordingEggsUnused(existingEggs); err != nil { + if err := ensureRecordingEggQtyChangeSafe(existingEggs, req.Eggs); err != nil { return err } if err := s.logRecordingEggUsage(ctx, tx, existingEggs, note, actorID); err != nil { @@ -3779,6 +3785,44 @@ func ensureRecordingEggsUnused(eggs []entity.RecordingEgg) error { return nil } +func ensureRecordingEggQtyChangeSafe(existingEggs []entity.RecordingEgg, reqEggs []validation.Egg) error { + usedByWarehouse := make(map[uint]float64) + for _, egg := range existingEggs { + usedByWarehouse[egg.ProductWarehouseId] += egg.TotalUsed + } + newQtyByWarehouse := make(map[uint]int) + for _, egg := range reqEggs { + newQtyByWarehouse[egg.ProductWarehouseId] += egg.Qty + } + for warehouseID, used := range usedByWarehouse { + if used <= 0 { + continue + } + if float64(newQtyByWarehouse[warehouseID]) < used { + return fiber.NewError(fiber.StatusBadRequest, + fmt.Sprintf("Jumlah telur tidak dapat dikurangi di bawah jumlah yang sudah terjual (%.0f butir)", used)) + } + } + return nil +} + +func (s *recordingService) updateEggWeightsOnly(tx *gorm.DB, existingEggs []entity.RecordingEgg, reqEggs []validation.Egg) error { + weightByWarehouse := make(map[uint]*float64) + for i := range reqEggs { + weightByWarehouse[reqEggs[i].ProductWarehouseId] = reqEggs[i].Weight + } + for _, egg := range existingEggs { + newWeight, ok := weightByWarehouse[egg.ProductWarehouseId] + if !ok { + continue + } + if err := s.Repository.UpdateEggWeight(tx, egg.Id, newWeight); err != nil { + return err + } + } + return nil +} + func (s *recordingService) recalculateFrom(ctx context.Context, tx *gorm.DB, projectFlockKandangId uint, from time.Time) error { if tx == nil || projectFlockKandangId == 0 || from.IsZero() { return nil diff --git a/internal/utils/recording/util.recording.go b/internal/utils/recording/util.recording.go index b6ff693b..f0a3d328 100644 --- a/internal/utils/recording/util.recording.go +++ b/internal/utils/recording/util.recording.go @@ -148,6 +148,19 @@ func EggTotalsEqual(a, b map[uint]EggTotals) bool { return true } +func EggQtyByWarehouseEqual(a, b map[uint]EggTotals) bool { + if len(a) != len(b) { + return false + } + for key, value := range a { + other, ok := b[key] + if !ok || value.Qty != other.Qty { + return false + } + } + return true +} + func DepletionRouteMapsEqual(a, b map[DepletionRoute]float64) bool { if len(a) != len(b) { return false