|
|
|
@@ -250,140 +250,136 @@ open class JoPickOrderService( |
|
|
|
val pickOrderIdsStr = pickOrderIds.joinToString(",") |
|
|
|
|
|
|
|
val sql = """ |
|
|
|
SELECT |
|
|
|
-- Pick Order Information |
|
|
|
po.id as pickOrderId, |
|
|
|
po.code as pickOrderCode, |
|
|
|
po.consoCode as pickOrderConsoCode, |
|
|
|
DATE_FORMAT(po.targetDate, '%Y-%m-%d') as pickOrderTargetDate, |
|
|
|
po.type as pickOrderType, |
|
|
|
po.status as pickOrderStatus, |
|
|
|
po.assignTo as pickOrderAssignTo, |
|
|
|
|
|
|
|
-- Job Order Information |
|
|
|
jo.id as jobOrderId, |
|
|
|
jo.code as jobOrderCode, |
|
|
|
|
|
|
|
-- Pick Order Line Information |
|
|
|
pol.id as pickOrderLineId, |
|
|
|
pol.qty as pickOrderLineRequiredQty, |
|
|
|
pol.status as pickOrderLineStatus, |
|
|
|
|
|
|
|
-- Item Information |
|
|
|
i.id as itemId, |
|
|
|
i.code as itemCode, |
|
|
|
i.name as itemName, |
|
|
|
uc.code as uomCode, |
|
|
|
uc.udfudesc as uomDesc, |
|
|
|
uc.udfShortDesc as uomShortDesc, |
|
|
|
|
|
|
|
-- Lot Information |
|
|
|
ill.id as lotId, |
|
|
|
il.lotNo, |
|
|
|
DATE_FORMAT(il.expiryDate, '%Y-%m-%d') as expiryDate, |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
|
|
|
|
-- Router Information |
|
|
|
r.id as routerId, |
|
|
|
ro.`order` as routerIndex, |
|
|
|
CONCAT(COALESCE(ro.route_area, ''), COALESCE(r.route, '')) as routerRoute, |
|
|
|
ro.route_area as routerArea, |
|
|
|
|
|
|
|
-- Set quantities to NULL for rejected lots |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'rejected' THEN NULL |
|
|
|
ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) |
|
|
|
END as availableQty, |
|
|
|
|
|
|
|
-- Required quantity for this lot |
|
|
|
COALESCE(spl.qty, 0) as requiredQty, |
|
|
|
|
|
|
|
-- Actual picked quantity |
|
|
|
COALESCE(sol.qty, 0) as actualPickQty, |
|
|
|
|
|
|
|
-- Suggested pick lot information |
|
|
|
spl.id as suggestedPickLotId, |
|
|
|
ill.status as lotStatus, |
|
|
|
|
|
|
|
-- Stock out line information |
|
|
|
sol.id as stockOutLineId, |
|
|
|
sol.status as stockOutLineStatus, |
|
|
|
COALESCE(sol.qty, 0) as stockOutLineQty, |
|
|
|
|
|
|
|
-- Additional detailed fields |
|
|
|
COALESCE(ill.inQty, 0) as inQty, |
|
|
|
COALESCE(ill.outQty, 0) as outQty, |
|
|
|
COALESCE(ill.holdQty, 0) as holdQty, |
|
|
|
COALESCE(spl.suggestedLotLineId, ill.id) 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 correctly |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as remainingAfterAllPickOrders, |
|
|
|
|
|
|
|
-- Lot availability status |
|
|
|
CASE |
|
|
|
WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' |
|
|
|
WHEN sol.status = 'rejected' THEN 'rejected' |
|
|
|
WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) <= 0 THEN 'insufficient_stock' |
|
|
|
WHEN ill.status = 'unavailable' THEN 'status_unavailable' |
|
|
|
ELSE 'available' |
|
|
|
END as lotAvailability, |
|
|
|
|
|
|
|
-- Processing status |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'completed' THEN 'completed' |
|
|
|
WHEN sol.status = 'rejected' THEN 'rejected' |
|
|
|
WHEN sol.status = 'created' THEN 'pending' |
|
|
|
ELSE 'pending' |
|
|
|
END as processingStatus, |
|
|
|
|
|
|
|
-- JoPickOrder second scan status |
|
|
|
jpo.match_status as match_status, |
|
|
|
jpo.match_by as match_by, |
|
|
|
jpo.match_qty as match_qty, |
|
|
|
jpo.ticketReleaseTime as ticketReleaseTime, |
|
|
|
jpo.ticketCompleteTime as ticketCompleteTime |
|
|
|
|
|
|
|
FROM fpsmsdb.pick_order po |
|
|
|
JOIN fpsmsdb.job_order jo ON jo.id = po.joId |
|
|
|
JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id |
|
|
|
JOIN fpsmsdb.items i ON i.id = pol.itemId |
|
|
|
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId |
|
|
|
LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id |
|
|
|
LEFT JOIN fpsmsdb.router r ON r.inventoryLotId = ill.id AND r.deleted = false |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId |
|
|
|
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId |
|
|
|
LEFT JOIN fpsmsdb.router_order ro ON r.router_id = ro.id |
|
|
|
LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false |
|
|
|
LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId |
|
|
|
WHERE po.deleted = false |
|
|
|
AND po.id IN ($pickOrderIdsStr) |
|
|
|
AND pol.deleted = false |
|
|
|
AND po.status IN ('PENDING', 'RELEASED', 'COMPLETED') |
|
|
|
AND po.assignTo = :userId |
|
|
|
AND ill.deleted = false |
|
|
|
AND il.deleted = false |
|
|
|
AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL) |
|
|
|
ORDER BY |
|
|
|
CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, |
|
|
|
COALESCE(ro.`order`, 999999) ASC, |
|
|
|
COALESCE(r.route, 999999) ASC, |
|
|
|
po.code ASC, |
|
|
|
i.code ASC, |
|
|
|
il.expiryDate ASC, |
|
|
|
il.lotNo ASC |
|
|
|
""".trimIndent() |
|
|
|
SELECT |
|
|
|
-- Pick Order Information |
|
|
|
po.id as pickOrderId, |
|
|
|
po.code as pickOrderCode, |
|
|
|
po.consoCode as pickOrderConsoCode, |
|
|
|
DATE_FORMAT(po.targetDate, '%Y-%m-%d') as pickOrderTargetDate, |
|
|
|
po.type as pickOrderType, |
|
|
|
po.status as pickOrderStatus, |
|
|
|
po.assignTo as pickOrderAssignTo, |
|
|
|
|
|
|
|
-- Job Order Information |
|
|
|
jo.id as jobOrderId, |
|
|
|
jo.code as jobOrderCode, |
|
|
|
|
|
|
|
-- Pick Order Line Information |
|
|
|
pol.id as pickOrderLineId, |
|
|
|
pol.qty as pickOrderLineRequiredQty, |
|
|
|
pol.status as pickOrderLineStatus, |
|
|
|
|
|
|
|
-- Item Information |
|
|
|
i.id as itemId, |
|
|
|
i.code as itemCode, |
|
|
|
i.name as itemName, |
|
|
|
uc.code as uomCode, |
|
|
|
uc.udfudesc as uomDesc, |
|
|
|
uc.udfShortDesc as uomShortDesc, |
|
|
|
|
|
|
|
-- Lot Information |
|
|
|
ill.id as lotId, |
|
|
|
il.lotNo, |
|
|
|
DATE_FORMAT(il.expiryDate, '%Y-%m-%d') as expiryDate, |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
|
|
|
|
-- ✅ Simplified Router Information using warehouse |
|
|
|
w.`order` as routerIndex, |
|
|
|
w.code as routerRoute, |
|
|
|
w.code as routerArea, |
|
|
|
|
|
|
|
-- Set quantities to NULL for rejected lots |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'rejected' THEN NULL |
|
|
|
ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) |
|
|
|
END as availableQty, |
|
|
|
|
|
|
|
-- Required quantity for this lot |
|
|
|
COALESCE(spl.qty, 0) as requiredQty, |
|
|
|
|
|
|
|
-- Actual picked quantity |
|
|
|
COALESCE(sol.qty, 0) as actualPickQty, |
|
|
|
|
|
|
|
-- Suggested pick lot information |
|
|
|
spl.id as suggestedPickLotId, |
|
|
|
ill.status as lotStatus, |
|
|
|
|
|
|
|
-- Stock out line information |
|
|
|
sol.id as stockOutLineId, |
|
|
|
sol.status as stockOutLineStatus, |
|
|
|
COALESCE(sol.qty, 0) as stockOutLineQty, |
|
|
|
|
|
|
|
-- Additional detailed fields |
|
|
|
COALESCE(ill.inQty, 0) as inQty, |
|
|
|
COALESCE(ill.outQty, 0) as outQty, |
|
|
|
COALESCE(ill.holdQty, 0) as holdQty, |
|
|
|
COALESCE(spl.suggestedLotLineId, ill.id) 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 correctly |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as remainingAfterAllPickOrders, |
|
|
|
|
|
|
|
-- Lot availability status |
|
|
|
CASE |
|
|
|
WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' |
|
|
|
WHEN sol.status = 'rejected' THEN 'rejected' |
|
|
|
WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) <= 0 THEN 'insufficient_stock' |
|
|
|
WHEN ill.status = 'unavailable' THEN 'status_unavailable' |
|
|
|
ELSE 'available' |
|
|
|
END as lotAvailability, |
|
|
|
|
|
|
|
-- Processing status |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'completed' THEN 'completed' |
|
|
|
WHEN sol.status = 'rejected' THEN 'rejected' |
|
|
|
WHEN sol.status = 'created' THEN 'pending' |
|
|
|
ELSE 'pending' |
|
|
|
END as processingStatus, |
|
|
|
|
|
|
|
-- JoPickOrder second scan status |
|
|
|
jpo.match_status as match_status, |
|
|
|
jpo.match_by as match_by, |
|
|
|
jpo.match_qty as match_qty, |
|
|
|
jpo.ticketReleaseTime as ticketReleaseTime, |
|
|
|
jpo.ticketCompleteTime as ticketCompleteTime |
|
|
|
|
|
|
|
FROM fpsmsdb.pick_order po |
|
|
|
JOIN fpsmsdb.job_order jo ON jo.id = po.joId |
|
|
|
JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id |
|
|
|
JOIN fpsmsdb.items i ON i.id = pol.itemId |
|
|
|
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId |
|
|
|
LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId |
|
|
|
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId -- ✅ 直接关联 warehouse |
|
|
|
LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false |
|
|
|
LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId |
|
|
|
WHERE po.deleted = false |
|
|
|
AND po.id IN ($pickOrderIdsStr) |
|
|
|
AND pol.deleted = false |
|
|
|
AND po.status IN ('PENDING', 'RELEASED', 'COMPLETED') |
|
|
|
AND po.assignTo = :userId |
|
|
|
AND ill.deleted = false |
|
|
|
AND il.deleted = false |
|
|
|
AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL) |
|
|
|
ORDER BY |
|
|
|
CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, |
|
|
|
COALESCE(w.`order`, 999999) ASC, -- ✅ 使用 warehouse.order 排序 |
|
|
|
po.code ASC, |
|
|
|
i.code ASC, |
|
|
|
il.expiryDate ASC, |
|
|
|
il.lotNo ASC |
|
|
|
""".trimIndent() |
|
|
|
|
|
|
|
println("🔍 Executing SQL for job order hierarchical structure: $sql") |
|
|
|
println("🔍 With parameters: userId = $userId, pickOrderIds = $pickOrderIdsStr") |
|
|
|
@@ -562,11 +558,9 @@ open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map<String, Any?> { |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
|
|
|
|
-- Router Information |
|
|
|
r.id as routerId, |
|
|
|
ro.`order` as routerIndex, |
|
|
|
CONCAT(COALESCE(ro.route_area, ''), COALESCE(r.route, '')) as routerRoute, |
|
|
|
ro.route_area as routerArea, |
|
|
|
-- Set quantities to NULL for rejected lots |
|
|
|
w.`order` as routerIndex, |
|
|
|
w.code as routerRoute, |
|
|
|
w.code as routerArea, |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'rejected' THEN NULL |
|
|
|
ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) |
|
|
|
@@ -652,8 +646,7 @@ open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map<String, Any?> { |
|
|
|
AND (jpo.match_status = 'pending' OR jpo.match_status = 'scanned') |
|
|
|
ORDER BY |
|
|
|
CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, |
|
|
|
COALESCE(ro.`order`, 999999) ASC, |
|
|
|
COALESCE(r.route, 999999) ASC, |
|
|
|
COALESCE(w.`order`, 999999) ASC |
|
|
|
po.code ASC, |
|
|
|
i.code ASC, |
|
|
|
il.expiryDate ASC, |
|
|
|
|