mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'fix/recording-validation' into 'development'
fix: allow editing sold egg weight on recording See merge request mbugroup/lti-api!499
This commit is contained in:
@@ -49,6 +49,7 @@ type RecordingRepository interface {
|
|||||||
DeleteEggs(tx *gorm.DB, recordingID uint) error
|
DeleteEggs(tx *gorm.DB, recordingID uint) error
|
||||||
ListEggs(tx *gorm.DB, recordingID uint) ([]entity.RecordingEgg, error)
|
ListEggs(tx *gorm.DB, recordingID uint) ([]entity.RecordingEgg, error)
|
||||||
UpdateEggTotalQty(tx *gorm.DB, eggID uint, totalQty float64) 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)
|
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)
|
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
|
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(
|
func (r *RecordingRepositoryImpl) GetRecordingEggByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
id uint,
|
id uint,
|
||||||
|
|||||||
@@ -799,6 +799,12 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
match := recordingutil.EggTotalsEqual(existingTotals, incomingTotals)
|
match := recordingutil.EggTotalsEqual(existingTotals, incomingTotals)
|
||||||
if match {
|
if match {
|
||||||
hasEggChanges = false
|
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 {
|
} else {
|
||||||
category := ""
|
category := ""
|
||||||
if recordingEntity.ProjectFlockKandang != nil && recordingEntity.ProjectFlockKandang.ProjectFlock.Id != 0 {
|
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 {
|
if err := s.ensureProductWarehousesByFlags(ctx, eggIDs, []string{"TELUR-UTUH", "TELUR-PECAH", "TELUR-PUTIH", "TELUR-RETAK", "TELUR"}, "egg"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ensureRecordingEggsUnused(existingEggs); err != nil {
|
if err := ensureRecordingEggQtyChangeSafe(existingEggs, req.Eggs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.logRecordingEggUsage(ctx, tx, existingEggs, note, actorID); err != nil {
|
if err := s.logRecordingEggUsage(ctx, tx, existingEggs, note, actorID); err != nil {
|
||||||
@@ -3779,6 +3785,44 @@ func ensureRecordingEggsUnused(eggs []entity.RecordingEgg) error {
|
|||||||
return nil
|
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 {
|
func (s *recordingService) recalculateFrom(ctx context.Context, tx *gorm.DB, projectFlockKandangId uint, from time.Time) error {
|
||||||
if tx == nil || projectFlockKandangId == 0 || from.IsZero() {
|
if tx == nil || projectFlockKandangId == 0 || from.IsZero() {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -148,6 +148,19 @@ func EggTotalsEqual(a, b map[uint]EggTotals) bool {
|
|||||||
return true
|
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 {
|
func DepletionRouteMapsEqual(a, b map[DepletionRoute]float64) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user