mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-06-09 15:07:49 +00:00
Merge branch 'fix/migration-do' into 'development'
fix over consume by code, revert migration overconsume sell See merge request mbugroup/lti-api!600
This commit is contained in:
@@ -195,9 +195,12 @@ func (s *fifoStockV2Service) allocateInternal(ctx context.Context, tx *gorm.DB,
|
||||
|
||||
if remaining > 0 {
|
||||
if !allowOverConsume {
|
||||
return nil, fmt.Errorf("%w: requested %.3f, allocated %.3f", ErrInsufficientStock, req.NeedQty, result.AllocatedQty)
|
||||
s.logger.Warnf("FIFO v2: clearing historical pending (%.3f) for %s/%d at PW=%d — over-consume is blocked by rule",
|
||||
remaining, req.Usable.LegacyTypeKey, req.Usable.ID, req.ProductWarehouseID)
|
||||
result.PendingQty = 0
|
||||
} else {
|
||||
result.PendingQty = remaining
|
||||
}
|
||||
result.PendingQty = remaining
|
||||
}
|
||||
|
||||
if err := s.applyUsableDeltas(tx, *usableRule, req.Usable.ID, result.AllocatedQty, result.PendingQty); err != nil {
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
BEGIN;
|
||||
|
||||
-- Rollback: re-insert TELUR/TELUR_GRADE block rules yang dihapus oleh migration ini.
|
||||
|
||||
INSERT INTO fifo_stock_v2_overconsume_rules(flag_group_code, function_code, lane, allow_overconsume, priority, reason, is_active)
|
||||
SELECT 'TELUR', 'MARKETING_OUT', 'USABLE', FALSE, 20, 'fifo_v2_exception_marketing_block_telur', TRUE
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM fifo_stock_v2_overconsume_rules
|
||||
WHERE lane = 'USABLE'
|
||||
AND function_code = 'MARKETING_OUT'
|
||||
AND flag_group_code = 'TELUR'
|
||||
AND reason = 'fifo_v2_exception_marketing_block_telur'
|
||||
);
|
||||
|
||||
INSERT INTO fifo_stock_v2_overconsume_rules(flag_group_code, function_code, lane, allow_overconsume, priority, reason, is_active)
|
||||
SELECT 'TELUR_GRADE', 'MARKETING_OUT', 'USABLE', FALSE, 20, 'fifo_v2_exception_marketing_block_telur_grade', TRUE
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM fifo_stock_v2_overconsume_rules
|
||||
WHERE lane = 'USABLE'
|
||||
AND function_code = 'MARKETING_OUT'
|
||||
AND flag_group_code = 'TELUR_GRADE'
|
||||
AND reason = 'fifo_v2_exception_marketing_block_telur_grade'
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
BEGIN;
|
||||
|
||||
-- Revert rules yang ditambahkan oleh migration 20260603031237_block_marketing_overconsume_telur.
|
||||
-- TELUR/TELUR_GRADE kembali fallback ke default allow rule (allow_overconsume=TRUE)
|
||||
-- karena validasi stok sekarang ditangani di service layer (code validation) bukan lewat
|
||||
-- config overconsume FIFO v2.
|
||||
|
||||
DELETE FROM fifo_stock_v2_overconsume_rules
|
||||
WHERE lane = 'USABLE'
|
||||
AND function_code = 'MARKETING_OUT'
|
||||
AND flag_group_code IN ('TELUR', 'TELUR_GRADE')
|
||||
AND reason IN (
|
||||
'fifo_v2_exception_marketing_block_telur',
|
||||
'fifo_v2_exception_marketing_block_telur_grade'
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
@@ -972,6 +972,19 @@ func (s deliveryOrdersService) consumeDeliveryStock(ctx context.Context, tx *gor
|
||||
if err := deliveryProductRepo.UpdateOne(ctx, deliveryProduct.Id, deliveryProduct, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product")
|
||||
}
|
||||
if requestedQty > 0 {
|
||||
available, err := s.checkAvailableStockQty(ctx, tx, marketingProduct.ProductWarehouseId)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memeriksa ketersediaan stok")
|
||||
}
|
||||
if requestedQty > available {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf(
|
||||
"Stok tidak mencukupi: dibutuhkan %g, tersedia %g",
|
||||
requestedQty, available,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
if err := reflowMarketingScope(
|
||||
ctx,
|
||||
s.FifoStockV2Svc,
|
||||
@@ -1505,3 +1518,28 @@ func uniqueUintIDs(ids []uint) []uint {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// checkAvailableStockQty returns the net available qty for a product warehouse:
|
||||
// gross qty (product_warehouses.qty) minus the sum of active CONSUME allocations
|
||||
// in stock_allocations. This gives the true available stock accounting for all
|
||||
// other delivery orders that have already consumed from the same warehouse.
|
||||
func (s deliveryOrdersService) checkAvailableStockQty(ctx context.Context, tx *gorm.DB, productWarehouseId uint) (float64, error) {
|
||||
var pw entity.ProductWarehouse
|
||||
if err := tx.WithContext(ctx).Select("qty").First(&pw, productWarehouseId).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var usedQty float64
|
||||
if err := tx.WithContext(ctx).Raw(`
|
||||
SELECT COALESCE(SUM(qty), 0)
|
||||
FROM stock_allocations
|
||||
WHERE stockable_type = 'product_warehouses'
|
||||
AND stockable_id = ?
|
||||
AND status = 'ACTIVE'
|
||||
AND allocation_purpose = 'CONSUME'
|
||||
`, productWarehouseId).Scan(&usedQty).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return pw.Quantity - usedQty, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user