|
|
|
@@ -424,11 +424,7 @@ open class PickOrderService( |
|
|
|
// Mapping: PickOrder -> PickOrderInConso |
|
|
|
val finalPos = pos.map { po -> |
|
|
|
val pols = po.pickOrderLines |
|
|
|
// Suggestions for Pick Order Line |
|
|
|
// val suggestions = suggestedPickLotService.suggestionForPickOrderLines(pols) |
|
|
|
|
|
|
|
// Pick Order Lines |
|
|
|
// Mapping: PickOrderLine -> PickOrderLineInConso |
|
|
|
val finalPols = pols.map { pol -> |
|
|
|
val item = pol.item |
|
|
|
val uom = pol.uom |
|
|
|
@@ -808,70 +804,106 @@ open class PickOrderService( |
|
|
|
println("=== Debug: getPickOrderLineLotDetails ===") |
|
|
|
println("pickOrderLineId: $pickOrderLineId") |
|
|
|
println("today: $today") |
|
|
|
/* |
|
|
|
// ✅ 重新添加:首先检查是否需要 resuggest |
|
|
|
val needsResuggest = checkIfNeedsResuggest(pickOrderLineId) |
|
|
|
if (needsResuggest) { |
|
|
|
println("⚠️ NEEDS RESUGGEST: Auto-triggering resuggest for pick order line ID: $pickOrderLineId") |
|
|
|
try { |
|
|
|
// 获取 pick order ID |
|
|
|
val pickOrderId = getPickOrderIdFromPickOrderLineId(pickOrderLineId) |
|
|
|
if (pickOrderId != null) { |
|
|
|
suggestedPickLotService.resuggestPickOrder(pickOrderId) |
|
|
|
println("✅ Resuggest completed successfully for pick order ID: $pickOrderId") |
|
|
|
} else { |
|
|
|
println("❌ Could not find pick order ID for pick order line ID: $pickOrderLineId") |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
println("❌ Error during auto-resuggest: ${e.message}") |
|
|
|
} |
|
|
|
} else { |
|
|
|
println("✅ No resuggest needed for pick order line ID: $pickOrderLineId") |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
val sql = """ |
|
|
|
SELECT |
|
|
|
ill.id as lotId, |
|
|
|
il.lotNo, |
|
|
|
il.expiryDate, |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as availableQty, |
|
|
|
spl.qty as requiredQty, |
|
|
|
COALESCE(sol.qty, 0) as actualPickQty, |
|
|
|
spl.id as suggestedPickLotId, |
|
|
|
ill.status as lotStatus, |
|
|
|
sol.id as stockOutLineId, |
|
|
|
sol.status as stockOutLineStatus, |
|
|
|
sol.qty as stockOutLineQty, |
|
|
|
spl.suggestedLotLineId as debugSuggestedLotLineId, |
|
|
|
ill.inventoryLotId as debugInventoryLotId, |
|
|
|
CASE |
|
|
|
WHEN ill.status != 'available' THEN 'unavailable' |
|
|
|
WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' |
|
|
|
WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) < (spl.qty) |
|
|
|
AND COALESCE(ill.holdQty, 0) < (spl.qty) |
|
|
|
THEN 'insufficient_stock' |
|
|
|
ELSE 'available' |
|
|
|
END as lotAvailability |
|
|
|
FROM fpsmsdb.suggested_pick_lot spl |
|
|
|
JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId |
|
|
|
JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId |
|
|
|
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId |
|
|
|
LEFT JOIN fpsmsdb.item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false |
|
|
|
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = sales_iu.uomId |
|
|
|
LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = spl.pickOrderLineId AND sol.inventoryLotLineId = spl.suggestedLotLineId |
|
|
|
WHERE spl.pickOrderLineId = :pickOrderLineId |
|
|
|
ORDER BY il.expiryDate ASC, il.lotNo ASC |
|
|
|
""".trimIndent() |
|
|
|
SELECT |
|
|
|
ill.id as lotId, |
|
|
|
il.lotNo, |
|
|
|
il.expiryDate, |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as availableQty, |
|
|
|
spl.qty as requiredQty, |
|
|
|
COALESCE(ill.inQty, 0) as inQty, |
|
|
|
COALESCE(sol.qty, 0) as actualPickQty, |
|
|
|
spl.id as suggestedPickLotId, |
|
|
|
ill.status as lotStatus, |
|
|
|
sol.id as stockOutLineId, |
|
|
|
sol.status as stockOutLineStatus, |
|
|
|
sol.qty as stockOutLineQty, |
|
|
|
spl.suggestedLotLineId as debugSuggestedLotLineId, |
|
|
|
ill.inventoryLotId as debugInventoryLotId, |
|
|
|
-- ✅ Calculate total picked quantity by ALL pick orders for this lot |
|
|
|
COALESCE(( |
|
|
|
SELECT SUM(sol_all.qty) |
|
|
|
FROM fpsmsdb.stock_out_line sol_all |
|
|
|
WHERE sol_all.inventoryLotLineId = ill.id |
|
|
|
AND sol_all.deleted = false |
|
|
|
AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') |
|
|
|
), 0) as totalPickedByAllPickOrders, |
|
|
|
-- ✅ Calculate remaining available quantity after all pick orders |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0) - COALESCE(( |
|
|
|
SELECT SUM(sol_all.qty) |
|
|
|
FROM fpsmsdb.stock_out_line sol_all |
|
|
|
WHERE sol_all.inventoryLotLineId = ill.id |
|
|
|
AND sol_all.deleted = false |
|
|
|
AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') |
|
|
|
), 0)) as remainingAfterAllPickOrders, |
|
|
|
-- ✅ Add detailed debug fields for lotAvailability calculation |
|
|
|
ill.status as debug_ill_status, |
|
|
|
(il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) as debug_is_expired, |
|
|
|
sol.status as debug_sol_status, |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0) - COALESCE(( |
|
|
|
SELECT SUM(sol_all.qty) |
|
|
|
FROM fpsmsdb.stock_out_line sol_all |
|
|
|
WHERE sol_all.inventoryLotLineId = ill.id |
|
|
|
AND sol_all.deleted = false |
|
|
|
AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') |
|
|
|
), 0)) as debug_remaining_stock, |
|
|
|
(spl.qty - COALESCE(sol.qty, 0)) as debug_required_after_picked, |
|
|
|
CASE |
|
|
|
-- ✅ FIXED: Only check if lot is expired or rejected |
|
|
|
WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' |
|
|
|
WHEN sol.status = 'rejected' THEN 'rejected' |
|
|
|
-- ✅ FIXED: For this pick order, if it's suggested, it should be available |
|
|
|
-- The holdQty already reserves the stock for this pick order |
|
|
|
ELSE 'available' |
|
|
|
END as lotAvailability |
|
|
|
FROM fpsmsdb.suggested_pick_lot spl |
|
|
|
JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId |
|
|
|
JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId |
|
|
|
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId |
|
|
|
LEFT JOIN fpsmsdb.item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false |
|
|
|
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = sales_iu.uomId |
|
|
|
LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = spl.pickOrderLineId AND sol.inventoryLotLineId = spl.suggestedLotLineId |
|
|
|
WHERE spl.pickOrderLineId = :pickOrderLineId |
|
|
|
ORDER BY il.expiryDate ASC, il.lotNo ASC |
|
|
|
""".trimIndent() |
|
|
|
|
|
|
|
println("🔍 Executing SQL for lot details: $sql") |
|
|
|
println("🔍 With parameters: pickOrderLineId = $pickOrderLineId") |
|
|
|
|
|
|
|
val result = jdbcDao.queryForList(sql, mapOf("pickOrderLineId" to pickOrderLineId)) |
|
|
|
//val result = jdbcDao.queryForList(sql, mapOf("pickOrderLineId" to pickOrderLineId)) |
|
|
|
|
|
|
|
// ✅ Filter out completed lots |
|
|
|
// ✅ Add detailed debug output for each lot |
|
|
|
println("=== DETAILED LOT AVAILABILITY DEBUG ===") |
|
|
|
result.forEach { row -> |
|
|
|
val lotId = row["lotId"] |
|
|
|
val lotNo = row["lotNo"] |
|
|
|
val illStatus = row["debug_ill_status"] |
|
|
|
val isExpired = row["debug_is_expired"] |
|
|
|
val solStatus = row["debug_sol_status"] |
|
|
|
val lotAvailability = row["lotAvailability"] |
|
|
|
|
|
|
|
println("--- Lot: $lotNo (ID: $lotId) ---") |
|
|
|
println(" ill.status: $illStatus") |
|
|
|
println(" is_expired: $isExpired") |
|
|
|
println(" sol.status: $solStatus") |
|
|
|
println(" lotAvailability: $lotAvailability") |
|
|
|
|
|
|
|
// ✅ Check each condition step by step |
|
|
|
if (isExpired == true) { |
|
|
|
println(" ❌ FAILED: lot is expired") |
|
|
|
} else if (solStatus == "rejected") { |
|
|
|
println(" ❌ FAILED: sol.status = 'rejected'") |
|
|
|
} else { |
|
|
|
println(" ✅ PASSED: All conditions met, should be 'available'") |
|
|
|
} |
|
|
|
println(" ---") |
|
|
|
} |
|
|
|
println("=== END DETAILED DEBUG ===") |
|
|
|
|
|
|
|
// ✅ Filter out completed lots |
|
|
|
val filteredResult = result.filter { row -> |
|
|
|
val stockOutLineStatus = row["stockOutLineStatus"] as String? |
|
|
|
val stockOutLineQty = row["stockOutLineQty"] as Number? |
|
|
|
@@ -884,6 +916,7 @@ open class PickOrderService( |
|
|
|
stockOutLineStatus != "completed" || |
|
|
|
stockOutLineQty?.toDouble() != requiredQty?.toDouble() |
|
|
|
} |
|
|
|
|
|
|
|
println("Final result count: ${filteredResult.size}") |
|
|
|
filteredResult.forEach { row -> |
|
|
|
println("Final Row: $row") |
|
|
|
|