FIX[BE]Lock chickins, accumulate pending qty, use qty key

This commit is contained in:
aguhh18
2025-12-31 13:09:13 +07:00
parent 7d6573fabd
commit 1b5437bc01
3 changed files with 21 additions and 9 deletions
@@ -68,11 +68,17 @@ func (r *ChickinRepositoryImpl) GetByProjectFlockKandangID(ctx context.Context,
// GetByProjectFlockKandangIDForUpdate locks chickin rows to prevent race condition
func (r *ChickinRepositoryImpl) GetByProjectFlockKandangIDForUpdate(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error) {
var chickins []entity.ProjectChickin
// CRITICAL: Use FOR UPDATE to lock rows and prevent concurrent chickin requests
// This ensures that simultaneous requests wait for each other and read consistent pending_qty
err := r.db.WithContext(ctx).
Where("project_flock_kandang_id = ?", projectFlockKandangID).
Order("created_at DESC").
Find(&chickins).
Error
Raw(`
SELECT * FROM project_chickins
WHERE project_flock_kandang_id = ?
AND deleted_at IS NULL
ORDER BY created_at DESC
FOR UPDATE
`, projectFlockKandangID).
Scan(&chickins).Error
if err != nil {
return nil, err
}
@@ -196,6 +196,8 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
}
}
// CRITICAL: Validate chickins sequentially to prevent over-allocation within the same request
// pendingQtyMap is accumulated as we validate each chickin to ensure total pending doesn't exceed available stock
for idx, chickin := range newChikins {
pendingQty := pendingQtyMap[chickin.ProductWarehouseId]
desiredQty := chickinQtyMap[uint(idx)]
@@ -210,6 +212,10 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
}
chickinQtyMap[uint(idx)] = availableQty
// ACCUMULATE pending for this product warehouse so NEXT chickin in same request sees it
// This prevents multiple chickins in same request from over-allocating the same stock
pendingQtyMap[chickin.ProductWarehouseId] += availableQty
}
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))