|
|
|
@@ -414,7 +414,14 @@ open class JoPickOrderService( |
|
|
|
val uom = pol.uom |
|
|
|
val lineId = pol.id!! |
|
|
|
val lineSuggestedLots = suggestedPickLots.filter { it.pickOrderLine?.id == pol.id } |
|
|
|
|
|
|
|
val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } |
|
|
|
println("jpo: $jpo") |
|
|
|
val user = userService.find(jpo?.handledBy?:0L) |
|
|
|
println("user: $user") |
|
|
|
val handlerName = jpo?.handledBy?.let { uid -> |
|
|
|
userService.find(uid).orElse(null)?.name |
|
|
|
} |
|
|
|
println("handlerName: $handlerName") |
|
|
|
// 构建 lots 数据 |
|
|
|
val lots = lineSuggestedLots.mapNotNull { spl -> |
|
|
|
val ill = spl.suggestedLotLine |
|
|
|
@@ -428,7 +435,10 @@ open class JoPickOrderService( |
|
|
|
it.pickOrderLine?.id == pol.id && it.inventoryLotLine?.id == ill.id |
|
|
|
} |
|
|
|
val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } |
|
|
|
|
|
|
|
val handlerName = jpo?.handledBy?.let { uid -> |
|
|
|
userService.find(uid).orElse(null)?.name |
|
|
|
} |
|
|
|
println("handlerName: $handlerName") |
|
|
|
val availableQty = if (sol?.status == "rejected") { |
|
|
|
null |
|
|
|
} else { |
|
|
|
@@ -490,7 +500,8 @@ open class JoPickOrderService( |
|
|
|
uomCode = uom?.code, |
|
|
|
uomDesc = uom?.udfudesc, |
|
|
|
status = pol.status?.value, |
|
|
|
lots = lots |
|
|
|
lots = lots, |
|
|
|
handler = handlerName |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
@@ -536,273 +547,194 @@ open class JoPickOrderService( |
|
|
|
} |
|
|
|
// Get completed job order pick orders (for second tab) |
|
|
|
// Fix the getCompletedJobOrderLotsHierarchical method |
|
|
|
open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map<String, Any?> { |
|
|
|
println("=== Debug: getCompletedJobOrderLotsHierarchical ===") |
|
|
|
println("today: ${LocalDate.now()}") |
|
|
|
println("userId filter: $userId") |
|
|
|
open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map<String, Any?> { |
|
|
|
println("=== Debug: getCompletedJobOrderLotsHierarchical (repo version) ===") |
|
|
|
println("today: ${LocalDate.now()}") |
|
|
|
println("userId filter: $userId") |
|
|
|
|
|
|
|
// Get all COMPLETED pick orders assigned to the user with joId |
|
|
|
val user = userService.find(userId).orElse(null) |
|
|
|
if (user == null) { |
|
|
|
println("❌ User not found: $userId") |
|
|
|
return emptyMap() |
|
|
|
} |
|
|
|
val user = userService.find(userId).orElse(null) |
|
|
|
if (user == null) { |
|
|
|
println("❌ User not found: $userId") |
|
|
|
return mapOf("pickOrder" to null, "pickOrderLines" to emptyList<Map<String, Any?>>()) |
|
|
|
} |
|
|
|
|
|
|
|
// Get all COMPLETED pick orders assigned to user that have joId |
|
|
|
val completedPickOrders = pickOrderRepository.findAllByAssignToIdAndStatusIn( |
|
|
|
userId, |
|
|
|
listOf(PickOrderStatus.COMPLETED) |
|
|
|
).filter { it.jobOrder != null } // Only pick orders with joId |
|
|
|
|
|
|
|
println("🔍 DEBUG: Found ${completedPickOrders.size} completed job order pick orders assigned to user $userId") |
|
|
|
|
|
|
|
val visiblePickOrders = completedPickOrders |
|
|
|
// 1. 找出当前用户所有 COMPLETED 的 JO pick order |
|
|
|
val completedPickOrders = pickOrderRepository |
|
|
|
.findAllByAssignToIdAndStatusIn(userId, listOf(PickOrderStatus.COMPLETED)) |
|
|
|
.filter { it.jobOrder != null } |
|
|
|
|
|
|
|
if (visiblePickOrders.isEmpty()) { |
|
|
|
println("🔍 DEBUG: No visible completed job orders found") |
|
|
|
return mapOf( |
|
|
|
"pickOrder" to null as Any?, |
|
|
|
"pickOrderLines" to emptyList<Map<String, Any>>() as Any? |
|
|
|
) |
|
|
|
} |
|
|
|
println("🔍 DEBUG: Found ${completedPickOrders.size} completed job order pick orders assigned to user $userId") |
|
|
|
|
|
|
|
// For completed orders, show the latest one |
|
|
|
val latestCompletedOrder = visiblePickOrders.maxByOrNull { |
|
|
|
it.completeDate ?: it.modified ?: LocalDateTime.MIN |
|
|
|
} |
|
|
|
if (completedPickOrders.isEmpty()) { |
|
|
|
return mapOf("pickOrder" to null, "pickOrderLines" to emptyList<Map<String, Any?>>()) |
|
|
|
} |
|
|
|
|
|
|
|
if (latestCompletedOrder == null) { |
|
|
|
println("🔍 DEBUG: No latest completed order found") |
|
|
|
return mapOf( |
|
|
|
"pickOrder" to null as Any?, |
|
|
|
"pickOrderLines" to emptyList<Map<String, Any>>() as Any? |
|
|
|
) |
|
|
|
} |
|
|
|
// 2. 取最新的一张 |
|
|
|
val latestCompletedOrder = completedPickOrders.maxByOrNull { |
|
|
|
it.completeDate ?: it.modified ?: LocalDateTime.MIN |
|
|
|
} ?: return mapOf("pickOrder" to null, "pickOrderLines" to emptyList<Map<String, Any?>>()) |
|
|
|
|
|
|
|
println("🔍 DEBUG: Using latest completed order: ${latestCompletedOrder.code}") |
|
|
|
println("🔍 DEBUG: Using latest completed order: ${latestCompletedOrder.code}") |
|
|
|
|
|
|
|
// Use the same SQL query approach as getAllJobOrderLotsWithDetailsHierarchical |
|
|
|
val pickOrderIds = listOf(latestCompletedOrder.id!!) |
|
|
|
val pickOrderIdsStr = pickOrderIds.joinToString(",") |
|
|
|
val pickOrder = latestCompletedOrder |
|
|
|
val jobOrder = pickOrder.jobOrder!! |
|
|
|
|
|
|
|
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, |
|
|
|
'jo' 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 |
|
|
|
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)) |
|
|
|
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 |
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
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 = '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) |
|
|
|
AND (jpo.match_status = 'pending' OR jpo.match_status = 'scanned') |
|
|
|
ORDER BY |
|
|
|
CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, |
|
|
|
COALESCE(w.`order`, 999999) ASC, |
|
|
|
po.code ASC, |
|
|
|
i.code ASC, |
|
|
|
il.expiryDate ASC, |
|
|
|
il.lotNo ASC |
|
|
|
""".trimIndent() |
|
|
|
// 3. 组装 pickOrder 信息 |
|
|
|
val pickOrderInfo = mapOf( |
|
|
|
"id" to pickOrder.id, |
|
|
|
"code" to pickOrder.code, |
|
|
|
"consoCode" to pickOrder.consoCode, |
|
|
|
"targetDate" to pickOrder.targetDate?.let { |
|
|
|
"${it.year}-${"%02d".format(it.monthValue)}-${"%02d".format(it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
"type" to "jo", |
|
|
|
"status" to pickOrder.status?.value, |
|
|
|
"assignTo" to pickOrder.assignTo?.id, |
|
|
|
"jobOrder" to mapOf( |
|
|
|
"id" to jobOrder.id, |
|
|
|
"code" to jobOrder.code, |
|
|
|
"name" to "Job Order ${jobOrder.code}" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
println("🔍 Executing SQL for completed job order hierarchical structure: $sql") |
|
|
|
println("🔍 With parameters: userId = $userId, pickOrderIds = $pickOrderIdsStr") |
|
|
|
// 4. 找出所有 pick order line |
|
|
|
val pickOrderLines = pickOrderLineRepository |
|
|
|
.findAllByPickOrderId(pickOrder.id!!) |
|
|
|
.filter { it.deleted == false } |
|
|
|
|
|
|
|
// Execute SQL query and build hierarchical structure |
|
|
|
try { |
|
|
|
val results = jdbcDao.queryForList(sql, mapOf("userId" to userId)) |
|
|
|
|
|
|
|
if (results.isEmpty()) { |
|
|
|
return mapOf( |
|
|
|
"pickOrder" to null as Any?, |
|
|
|
"pickOrderLines" to emptyList<Map<String, Any>>() as Any? |
|
|
|
) |
|
|
|
if (pickOrderLines.isEmpty()) { |
|
|
|
return mapOf("pickOrder" to pickOrderInfo, "pickOrderLines" to emptyList<Map<String, Any?>>()) |
|
|
|
} |
|
|
|
|
|
|
|
// Build hierarchical structure |
|
|
|
val pickOrderInfo = results.firstOrNull()?.let { firstRow: Map<String, Any?> -> |
|
|
|
mapOf( |
|
|
|
"id" to firstRow["pickOrderId"], |
|
|
|
"code" to firstRow["pickOrderCode"], |
|
|
|
"consoCode" to firstRow["pickOrderConsoCode"], |
|
|
|
"targetDate" to firstRow["pickOrderTargetDate"], |
|
|
|
"type" to firstRow["pickOrderType"], |
|
|
|
"status" to firstRow["pickOrderStatus"], |
|
|
|
"assignTo" to firstRow["pickOrderAssignTo"], |
|
|
|
"jobOrder" to mapOf( |
|
|
|
"id" to firstRow["jobOrderId"], |
|
|
|
"code" to firstRow["jobOrderCode"], |
|
|
|
"name" to "Job Order ${firstRow["jobOrderCode"]}" |
|
|
|
|
|
|
|
val pickOrderLineIds = pickOrderLines.mapNotNull { it.id } |
|
|
|
|
|
|
|
// 5. 建议拣货 lot |
|
|
|
val suggestedPickLots = if (pickOrderLineIds.isNotEmpty()) { |
|
|
|
suggestPickLotRepository |
|
|
|
.findAllByPickOrderLineIdIn(pickOrderLineIds) |
|
|
|
.filter { it.deleted == false } |
|
|
|
} else emptyList() |
|
|
|
|
|
|
|
val inventoryLotLineIds = suggestedPickLots.mapNotNull { it.suggestedLotLine?.id } |
|
|
|
|
|
|
|
val inventoryLotLines = if (inventoryLotLineIds.isNotEmpty()) { |
|
|
|
inventoryLotLineRepository |
|
|
|
.findAllByIdIn(inventoryLotLineIds) |
|
|
|
.filter { it.deleted == false } |
|
|
|
} else emptyList() |
|
|
|
|
|
|
|
val inventoryLotIds = inventoryLotLines.mapNotNull { it.inventoryLot?.id }.distinct() |
|
|
|
val inventoryLots = if (inventoryLotIds.isNotEmpty()) { |
|
|
|
inventoryLotRepository |
|
|
|
.findAllByIdIn(inventoryLotIds) |
|
|
|
.filter { it.deleted == false } |
|
|
|
} else emptyList() |
|
|
|
|
|
|
|
// 6. stock_out_line(含所有状态) |
|
|
|
val stockOutLines = if (pickOrderLineIds.isNotEmpty() && inventoryLotLineIds.isNotEmpty()) { |
|
|
|
pickOrderLineIds.flatMap { polId -> |
|
|
|
inventoryLotLineIds.flatMap { illId -> |
|
|
|
stockOutLineRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) |
|
|
|
} |
|
|
|
} |
|
|
|
} else emptyList() |
|
|
|
|
|
|
|
// 7. 对应的 jo_pick_order(用于 match_* 和 handler) |
|
|
|
val joPickOrders = joPickOrderRepository.findByPickOrderId(pickOrder.id!!) |
|
|
|
|
|
|
|
// 8. 组装每一行 + lots |
|
|
|
val pickOrderLinesResult = pickOrderLines.map { pol -> |
|
|
|
val item = pol.item |
|
|
|
val uom = pol.uom |
|
|
|
val lineSuggestedLots = suggestedPickLots.filter { it.pickOrderLine?.id == pol.id } |
|
|
|
|
|
|
|
val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } |
|
|
|
val handlerName = jpo?.matchBy?.let { uid -> |
|
|
|
userService.find(uid).orElse(null)?.name |
|
|
|
} |
|
|
|
|
|
|
|
val lots = lineSuggestedLots.mapNotNull { spl -> |
|
|
|
val ill = spl.suggestedLotLine ?: return@mapNotNull null |
|
|
|
if (ill.deleted == true) return@mapNotNull null |
|
|
|
|
|
|
|
val il = ill.inventoryLot ?: return@mapNotNull null |
|
|
|
if (il.deleted == true) return@mapNotNull null |
|
|
|
|
|
|
|
val warehouse = ill.warehouse |
|
|
|
val sol = stockOutLines.firstOrNull { |
|
|
|
it.pickOrderLine?.id == pol.id && it.inventoryLotLine?.id == ill.id |
|
|
|
} |
|
|
|
|
|
|
|
val availableQty = if (sol?.status == "rejected") { |
|
|
|
null |
|
|
|
} else { |
|
|
|
(ill.inQty ?: BigDecimal.ZERO) - |
|
|
|
(ill.outQty ?: BigDecimal.ZERO) - |
|
|
|
(ill.holdQty ?: BigDecimal.ZERO) |
|
|
|
} |
|
|
|
|
|
|
|
val lotAvailability = when { |
|
|
|
il.expiryDate != null && il.expiryDate!!.isBefore(LocalDate.now()) -> "expired" |
|
|
|
sol?.status == "rejected" -> "rejected" |
|
|
|
availableQty != null && availableQty <= BigDecimal.ZERO -> "insufficient_stock" |
|
|
|
ill.status == InventoryLotLineStatus.UNAVAILABLE -> "status_unavailable" |
|
|
|
else -> "available" |
|
|
|
} |
|
|
|
|
|
|
|
val processingStatus = when (sol?.status) { |
|
|
|
"completed" -> "completed" |
|
|
|
"rejected" -> "rejected" |
|
|
|
"created" -> "pending" |
|
|
|
else -> "pending" |
|
|
|
} |
|
|
|
|
|
|
|
mapOf( |
|
|
|
"lotId" to ill.id, |
|
|
|
"lotNo" to il.lotNo, |
|
|
|
"expiryDate" to il.expiryDate?.let { |
|
|
|
"${it.year}-${"%02d".format(it.monthValue)}-${"%02d".format(it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
"location" to warehouse?.name, |
|
|
|
"availableQty" to availableQty?.toDouble(), |
|
|
|
"requiredQty" to (spl.qty?.toDouble() ?: 0.0), |
|
|
|
"actualPickQty" to (sol?.qty ?: 0.0), |
|
|
|
"processingStatus" to processingStatus, |
|
|
|
"lotAvailability" to lotAvailability, |
|
|
|
"pickOrderId" to pickOrder.id, |
|
|
|
"pickOrderCode" to pickOrder.code, |
|
|
|
"pickOrderConsoCode" to pickOrder.consoCode, |
|
|
|
"pickOrderLineId" to pol.id, |
|
|
|
"stockOutLineId" to sol?.id, |
|
|
|
"stockOutLineStatus" to sol?.status, |
|
|
|
"stockOutLineQty" to (sol?.qty ?: 0.0), |
|
|
|
"routerIndex" to warehouse?.order, |
|
|
|
"routerArea" to warehouse?.code, |
|
|
|
"routerRoute" to warehouse?.code, |
|
|
|
"uomShortDesc" to uom?.udfShortDesc, |
|
|
|
"matchStatus" to jpo?.matchStatus?.value, |
|
|
|
"matchBy" to jpo?.matchBy, |
|
|
|
"matchQty" to jpo?.matchQty, |
|
|
|
"handler" to handlerName |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// Group by pick order line |
|
|
|
val groupedByLine = results.groupBy { row: Map<String, Any?> -> row["pickOrderLineId"] } |
|
|
|
val pickOrderLines = groupedByLine.map { (lineId: Any?, lineRows: List<Map<String, Any?>>) -> |
|
|
|
val firstLineRow = lineRows.first() |
|
|
|
} |
|
|
|
|
|
|
|
mapOf( |
|
|
|
"id" to lineId, |
|
|
|
"itemId" to firstLineRow["itemId"], |
|
|
|
"itemCode" to firstLineRow["itemCode"], |
|
|
|
"itemName" to firstLineRow["itemName"], |
|
|
|
"requiredQty" to firstLineRow["pickOrderLineRequiredQty"], |
|
|
|
"uomCode" to firstLineRow["uomCode"], |
|
|
|
"uomDesc" to firstLineRow["uomDesc"], |
|
|
|
"lots" to lineRows.map { row: Map<String, Any?> -> |
|
|
|
mapOf( |
|
|
|
"lotId" to row["lotId"], |
|
|
|
"lotNo" to row["lotNo"], |
|
|
|
"expiryDate" to row["expiryDate"], |
|
|
|
"location" to row["location"], |
|
|
|
"availableQty" to row["availableQty"], |
|
|
|
"requiredQty" to row["requiredQty"], |
|
|
|
"actualPickQty" to row["actualPickQty"], |
|
|
|
"processingStatus" to row["processingStatus"], |
|
|
|
"lotAvailability" to row["lotAvailability"], |
|
|
|
"pickOrderId" to row["pickOrderId"], |
|
|
|
"pickOrderCode" to row["pickOrderCode"], |
|
|
|
"suggestedPickLotId" to row["suggestedPickLotId"], |
|
|
|
"stockOutLineQty" to row["stockOutLineQty"], |
|
|
|
"pickOrderConsoCode" to row["pickOrderConsoCode"], |
|
|
|
"pickOrderLineId" to row["pickOrderLineId"], |
|
|
|
"stockOutLineId" to row["stockOutLineId"], |
|
|
|
"stockOutLineStatus" to row["stockOutLineStatus"], |
|
|
|
"routerIndex" to row["routerIndex"], |
|
|
|
"routerArea" to row["routerArea"], |
|
|
|
"routerRoute" to row["routerRoute"], |
|
|
|
"uomShortDesc" to row["uomShortDesc"], |
|
|
|
"matchStatus" to row["match_status"], |
|
|
|
"matchBy" to row["match_by"], |
|
|
|
"matchQty" to row["match_qty"] |
|
|
|
) |
|
|
|
} |
|
|
|
"id" to pol.id, |
|
|
|
"itemId" to item?.id, |
|
|
|
"itemCode" to item?.code, |
|
|
|
"itemName" to item?.name, |
|
|
|
"requiredQty" to pol.qty?.toDouble(), |
|
|
|
"uomCode" to uom?.code, |
|
|
|
"uomDesc" to uom?.udfudesc, |
|
|
|
"handler" to handlerName, |
|
|
|
"lots" to lots |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
return mapOf( |
|
|
|
"pickOrder" to pickOrderInfo as Any?, |
|
|
|
"pickOrderLines" to pickOrderLines as Any? |
|
|
|
) |
|
|
|
|
|
|
|
} catch (e: Exception) { |
|
|
|
println("❌ Error executing completed Job Order SQL: ${e.message}") |
|
|
|
e.printStackTrace() |
|
|
|
|
|
|
|
return mapOf( |
|
|
|
"pickOrder" to null as Any?, |
|
|
|
"pickOrderLines" to emptyList<Map<String, Any>>() as Any? |
|
|
|
"pickOrder" to pickOrderInfo, |
|
|
|
"pickOrderLines" to pickOrderLinesResult |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Get completed job order pick order records (for third tab) |
|
|
|
@@ -1310,40 +1242,35 @@ private fun generateIssueNoForJo(): String { |
|
|
|
|
|
|
|
return "SKO-${yearMonth}-${nextSequence.toString().padStart(3, '0')}" |
|
|
|
} |
|
|
|
open fun getCompletedJobOrderPickOrdersWithCompletedSecondScan(userId: Long): List<Map<String, Any?>> { |
|
|
|
open fun getCompletedJobOrderPickOrdersWithCompletedSecondScan(): List<Map<String, Any?>> { |
|
|
|
println("=== getCompletedJobOrderPickOrdersWithCompletedSecondScan ===") |
|
|
|
println("userId: $userId") |
|
|
|
|
|
|
|
|
|
|
|
return try { |
|
|
|
// Get all completed pick orders assigned to user that have joId |
|
|
|
val completedPickOrders = pickOrderRepository.findAllByAssignToIdAndStatusIn( |
|
|
|
userId, |
|
|
|
listOf(PickOrderStatus.COMPLETED) |
|
|
|
).filter { it.jobOrder != null } // Only pick orders with joId |
|
|
|
// 1. 先找出所有 COMPLETED 的 JO pick order(不再依赖 assignTo / userId) |
|
|
|
val completedPickOrders = pickOrderRepository |
|
|
|
.findAllByStatusIn(listOf(PickOrderStatus.COMPLETED)) |
|
|
|
.filter { it.jobOrder != null } // 只要有 jobOrder 的 |
|
|
|
|
|
|
|
println("Found ${completedPickOrders.size} completed job order pick orders for user $userId") |
|
|
|
println("Found ${completedPickOrders.size} completed job order pick orders (all users)") |
|
|
|
|
|
|
|
// 2. 只保留「所有 item 的 second scan 都完成」的 pick order |
|
|
|
val completedJobOrderPickOrders = completedPickOrders.mapNotNull { pickOrder -> |
|
|
|
val jobOrder = pickOrder.jobOrder |
|
|
|
if (jobOrder != null) { |
|
|
|
// Check if all items in this pick order have completed second scan |
|
|
|
val joPickOrders = findByPickOrderId(pickOrder.id!!) |
|
|
|
val allSecondScanCompleted = joPickOrders.isNotEmpty() && |
|
|
|
joPickOrders.all { it.matchStatus == JoPickOrderStatus.completed } |
|
|
|
|
|
|
|
val allSecondScanCompleted = joPickOrders.isNotEmpty() && |
|
|
|
joPickOrders.all { it.matchStatus == JoPickOrderStatus.completed } |
|
|
|
|
|
|
|
if (allSecondScanCompleted) { |
|
|
|
mapOf( |
|
|
|
"id" to pickOrder.id, |
|
|
|
"pickOrderId" to pickOrder.id, |
|
|
|
"pickOrderCode" to pickOrder.code, |
|
|
|
"pickOrderConsoCode" to pickOrder.consoCode, |
|
|
|
"pickOrderTargetDate" to pickOrder.targetDate?.let { |
|
|
|
"${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
"pickOrderTargetDate" to pickOrder.targetDate, |
|
|
|
"pickOrderStatus" to pickOrder.status, |
|
|
|
"completedDate" to pickOrder.completeDate?.let { |
|
|
|
"${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
// ✅ 完成时间改用 jobOrder.planEnd |
|
|
|
"completedDate" to jobOrder.planEnd, |
|
|
|
"jobOrderId" to jobOrder.id, |
|
|
|
"jobOrderCode" to jobOrder.code, |
|
|
|
"jobOrderName" to jobOrder.bom?.name, |
|
|
|
@@ -1537,30 +1464,25 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List<Map<St |
|
|
|
} |
|
|
|
// ... existing code ... |
|
|
|
|
|
|
|
open fun getCompletedJobOrderPickOrders(userId: Long): List<Map<String, Any?>> { |
|
|
|
println("=== getCompletedJobOrderPickOrders ===") |
|
|
|
println("userId: $userId") |
|
|
|
open fun getCompletedJobOrderPickOrders(): List<Map<String, Any?>> { |
|
|
|
println("=== getCompletedJobOrderPickOrders (no user filter) ===") |
|
|
|
|
|
|
|
return try { |
|
|
|
// 修复:先查找所有 COMPLETED 状态的 job order pick orders(不限制 assignTo) |
|
|
|
val allCompletedPickOrders = pickOrderRepository.findAllByStatusIn( |
|
|
|
listOf(PickOrderStatus.COMPLETED) |
|
|
|
).filter { |
|
|
|
it.jobOrder != null && // 只查找有 job order 的 |
|
|
|
(it.assignTo?.id == userId || it.assignTo == null) // 分配给当前用户或未分配 |
|
|
|
} |
|
|
|
|
|
|
|
println("Found ${allCompletedPickOrders.size} completed job order pick orders (including unassigned)") |
|
|
|
// 1. 找出所有 COMPLETED 状态、且有关联 JobOrder 的 pick order(不再按 assignTo 过滤) |
|
|
|
val allCompletedPickOrders = pickOrderRepository |
|
|
|
.findAllByStatusIn(listOf(PickOrderStatus.COMPLETED)) |
|
|
|
.filter { it.jobOrder != null } |
|
|
|
|
|
|
|
println("Found ${allCompletedPickOrders.size} completed job order pick orders") |
|
|
|
|
|
|
|
// 2. 组装返回数据 |
|
|
|
val completedJobOrderPickOrders = allCompletedPickOrders.mapNotNull { pickOrder -> |
|
|
|
val jobOrder = pickOrder.jobOrder |
|
|
|
if (jobOrder != null) { |
|
|
|
// Get JoPickOrder records for this pick order |
|
|
|
// 对应的 JoPickOrder 记录(用于 second scan 状态统计) |
|
|
|
val joPickOrders = findByPickOrderId(pickOrder.id!!) |
|
|
|
|
|
|
|
println("Pick Order ${pickOrder.code}: joPickOrders.size=${joPickOrders.size}") |
|
|
|
|
|
|
|
// Calculate second scan completion status |
|
|
|
val secondScanCompleted = joPickOrders.isNotEmpty() && |
|
|
|
joPickOrders.all { it.matchStatus == JoPickOrderStatus.completed } |
|
|
|
|
|
|
|
@@ -1570,12 +1492,11 @@ open fun getCompletedJobOrderPickOrders(userId: Long): List<Map<String, Any?>> { |
|
|
|
"pickOrderCode" to pickOrder.code, |
|
|
|
"pickOrderConsoCode" to pickOrder.consoCode, |
|
|
|
"pickOrderTargetDate" to pickOrder.targetDate?.let { |
|
|
|
"${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" |
|
|
|
"${it.year}-${"%02d".format(it.monthValue)}-${"%02d".format(it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
"pickOrderStatus" to pickOrder.status, |
|
|
|
"completedDate" to pickOrder.completeDate?.let { |
|
|
|
"${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" |
|
|
|
}, |
|
|
|
// 完成时间:按你的需求用 jobOrder.planEnd |
|
|
|
"completedDate" to jobOrder.planEnd, |
|
|
|
"jobOrderId" to jobOrder.id, |
|
|
|
"jobOrderCode" to jobOrder.code, |
|
|
|
"jobOrderName" to jobOrder.bom?.name, |
|
|
|
@@ -1944,7 +1865,10 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo |
|
|
|
val uom = pol.uom |
|
|
|
val lineId = pol.id!! |
|
|
|
val lineSuggestedLots = suggestedPickLots.filter { it.pickOrderLine?.id == pol.id } |
|
|
|
|
|
|
|
val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } |
|
|
|
val handlerName = jpo?.handledBy?.let { uid -> |
|
|
|
userService.find(uid).orElse(null)?.name |
|
|
|
} |
|
|
|
// 构建 lots 数据 |
|
|
|
val lots = lineSuggestedLots.mapNotNull { spl -> |
|
|
|
val ill = spl.suggestedLotLine |
|
|
|
@@ -1958,7 +1882,10 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo |
|
|
|
it.pickOrderLine?.id == pol.id && it.inventoryLotLine?.id == ill.id |
|
|
|
} |
|
|
|
val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } |
|
|
|
|
|
|
|
val handlerName = jpo?.handledBy?.let { uid -> |
|
|
|
userService.find(uid).orElse(null)?.name |
|
|
|
} |
|
|
|
println("handlerName: $handlerName") |
|
|
|
val availableQty = if (sol?.status == "rejected") { |
|
|
|
null |
|
|
|
} else { |
|
|
|
@@ -2019,7 +1946,8 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo |
|
|
|
uomCode = uom?.code, |
|
|
|
uomDesc = uom?.udfudesc, |
|
|
|
status = pol.status?.value, |
|
|
|
lots = lots |
|
|
|
lots = lots, |
|
|
|
handler=handlerName |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|