| @@ -1250,8 +1250,37 @@ open class PickOrderService( | |||||
| println("⚠️ WARNING: do_pick_order $doPickOrderId not found, skipping") | println("⚠️ WARNING: do_pick_order $doPickOrderId not found, skipping") | ||||
| return@forEach | return@forEach | ||||
| } | } | ||||
| println("🔍 Processing do_pick_order ID: ${dpo.id}, ticket: ${dpo.ticketNo}") | println("🔍 Processing do_pick_order ID: ${dpo.id}, ticket: ${dpo.ticketNo}") | ||||
| // ✅ 新增:检查这个 do_pick_order 下是否还有其他未完成的 pick orders | |||||
| val allDoPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!) | |||||
| val allPickOrderIdsInDpo = allDoPickOrderLines.mapNotNull { it.pickOrderId }.distinct() | |||||
| println("🔍 DEBUG: This do_pick_order has ${allPickOrderIdsInDpo.size} pick orders") | |||||
| // ✅ 检查每个 pick order 的状态 | |||||
| val pickOrderStatuses = allPickOrderIdsInDpo.map { poId -> | |||||
| val po = pickOrderRepository.findById(poId).orElse(null) | |||||
| poId to po?.status | |||||
| } | |||||
| pickOrderStatuses.forEach { (poId, status) -> | |||||
| println("🔍 DEBUG: Pick order $poId status: $status") | |||||
| } | |||||
| // ✅ 只有当所有 pick orders 都是 COMPLETED 状态时,才移动到 record 表 | |||||
| val allPickOrdersCompleted = pickOrderStatuses.all { (_, status) -> | |||||
| status == PickOrderStatus.COMPLETED | |||||
| } | |||||
| if (!allPickOrdersCompleted) { | |||||
| println("⏳ Not all pick orders in this do_pick_order are completed, keeping do_pick_order alive") | |||||
| println("🔍 DEBUG: Completed pick orders: ${pickOrderStatuses.count { it.second == PickOrderStatus.COMPLETED }}/${pickOrderStatuses.size}") | |||||
| return@forEach // ✅ 跳过这个 do_pick_order,不删除它 | |||||
| } | |||||
| println("✅ All pick orders in this do_pick_order are completed, moving to record table") | |||||
| // 2) 先复制 do_pick_order -> do_pick_order_record | // 2) 先复制 do_pick_order -> do_pick_order_record | ||||
| val dpoRecord = DoPickOrderRecord( | val dpoRecord = DoPickOrderRecord( | ||||
| @@ -3516,261 +3545,307 @@ ORDER BY | |||||
| val enrichedResults = filteredResults | val enrichedResults = filteredResults | ||||
| return enrichedResults | return enrichedResults | ||||
| } | } | ||||
| open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, Any?> { | |||||
| println("=== Debug: getAllPickOrderLotsWithDetailsHierarchical (NEW STRUCTURE) ===") | |||||
| println("userId filter: $userId") | |||||
| val user = userService.find(userId).orElse(null) | |||||
| if (user == null) { | |||||
| println("❌ User not found: $userId") | |||||
| return emptyMap() | |||||
| } | |||||
| // ✅ Step 1: 获取 do_pick_order 基本信息 | |||||
| val doPickOrderSql = """ | |||||
| SELECT DISTINCT | |||||
| dpo.id as do_pick_order_id, | |||||
| dpo.ticket_no, | |||||
| dpo.store_id, | |||||
| dpo.TruckLanceCode, | |||||
| dpo.truck_departure_time, | |||||
| dpo.ShopCode, | |||||
| dpo.ShopName | |||||
| FROM fpsmsdb.do_pick_order dpo | |||||
| INNER JOIN fpsmsdb.do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE po.assignTo = :userId | |||||
| AND po.type = 'do' | |||||
| AND po.status IN ('assigned', 'released', 'picking') | |||||
| AND po.deleted = false | |||||
| AND dpo.deleted = false | |||||
| LIMIT 1 | |||||
| """.trimIndent() | |||||
| val doPickOrderInfo = jdbcDao.queryForMap(doPickOrderSql, mapOf("userId" to userId)).orElse(null) | |||||
| if (doPickOrderInfo == null) { | |||||
| println("❌ No do_pick_order found for user $userId") | |||||
| return mapOf( | |||||
| "fgInfo" to null, | |||||
| "pickOrders" to emptyList<Any>() | |||||
| ) | |||||
| } | |||||
| val doPickOrderId = (doPickOrderInfo["do_pick_order_id"] as? Number)?.toLong() | |||||
| println("🔍 Found do_pick_order ID: $doPickOrderId") | |||||
| // ✅ Step 2: 获取该 do_pick_order 下的所有 pick orders | |||||
| val pickOrdersSql = """ | |||||
| SELECT DISTINCT | |||||
| dpol.pick_order_id, | |||||
| dpol.pick_order_code, | |||||
| dpol.do_order_id, | |||||
| dpol.delivery_order_code, | |||||
| po.consoCode, | |||||
| po.status, | |||||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate | |||||
| FROM fpsmsdb.do_pick_order_line dpol | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE dpol.do_pick_order_id = :doPickOrderId | |||||
| AND dpol.deleted = 0 | |||||
| AND po.deleted = false | |||||
| ORDER BY dpol.pick_order_id | |||||
| """.trimIndent() | |||||
| // ... existing code ... | |||||
| open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, Any?> { | |||||
| println("=== Debug: getAllPickOrderLotsWithDetailsHierarchical (NEW STRUCTURE) ===") | |||||
| println("userId filter: $userId") | |||||
| val user = userService.find(userId).orElse(null) | |||||
| if (user == null) { | |||||
| println("❌ User not found: $userId") | |||||
| return emptyMap() | |||||
| } | |||||
| // ✅ Step 1: 获取 do_pick_order 基本信息 | |||||
| val doPickOrderSql = """ | |||||
| SELECT DISTINCT | |||||
| dpo.id as do_pick_order_id, | |||||
| dpo.ticket_no, | |||||
| dpo.store_id, | |||||
| dpo.TruckLanceCode, | |||||
| dpo.truck_departure_time, | |||||
| dpo.ShopCode, | |||||
| dpo.ShopName | |||||
| FROM fpsmsdb.do_pick_order dpo | |||||
| INNER JOIN fpsmsdb.do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE po.assignTo = :userId | |||||
| AND po.type = 'do' | |||||
| AND EXISTS ( | |||||
| SELECT 1 | |||||
| FROM fpsmsdb.do_pick_order_line dpol2 | |||||
| INNER JOIN fpsmsdb.pick_order po2 ON po2.id = dpol2.pick_order_id | |||||
| WHERE dpol2.do_pick_order_id = dpo.id | |||||
| AND dpol2.deleted = 0 | |||||
| AND po2.status IN ('assigned', 'released', 'picking') | |||||
| AND po2.deleted = false | |||||
| ) | |||||
| AND po.deleted = false | |||||
| AND dpo.deleted = false | |||||
| LIMIT 1 | |||||
| """.trimIndent() | |||||
| val doPickOrderInfo = jdbcDao.queryForMap(doPickOrderSql, mapOf("userId" to userId)).orElse(null) | |||||
| if (doPickOrderInfo == null) { | |||||
| println("❌ No do_pick_order found for user $userId") | |||||
| return mapOf( | |||||
| "fgInfo" to null, | |||||
| "pickOrders" to emptyList<Any>() | |||||
| ) | |||||
| } | |||||
| val doPickOrderId = (doPickOrderInfo["do_pick_order_id"] as? Number)?.toLong() | |||||
| println("🔍 Found do_pick_order ID: $doPickOrderId") | |||||
| // ✅ Step 2: 获取该 do_pick_order 下的所有 pick orders | |||||
| val pickOrdersSql = """ | |||||
| SELECT DISTINCT | |||||
| dpol.pick_order_id, | |||||
| dpol.pick_order_code, | |||||
| dpol.do_order_id, | |||||
| dpol.delivery_order_code, | |||||
| po.consoCode, | |||||
| po.status, | |||||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate | |||||
| FROM fpsmsdb.do_pick_order_line dpol | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE dpol.do_pick_order_id = :doPickOrderId | |||||
| AND dpol.deleted = 0 | |||||
| AND po.deleted = false | |||||
| ORDER BY dpol.pick_order_id | |||||
| """.trimIndent() | |||||
| val pickOrdersInfo = jdbcDao.queryForList(pickOrdersSql, mapOf("doPickOrderId" to doPickOrderId)) | |||||
| println("🔍 Found ${pickOrdersInfo.size} pick orders") | |||||
| // ✅ Step 3: 为每个 pick order 获取 lines 和 lots | |||||
| val allPickOrderLines = mutableListOf<Map<String, Any?>>() | |||||
| val lineCountsPerPickOrder = mutableListOf<Int>() | |||||
| val pickOrderIds = mutableListOf<Long>() | |||||
| val pickOrderCodes = mutableListOf<String>() | |||||
| val doOrderIds = mutableListOf<Long>() | |||||
| val deliveryOrderCodes = mutableListOf<String>() | |||||
| pickOrdersInfo.forEach { poInfo -> | |||||
| val pickOrderId = (poInfo["pick_order_id"] as? Number)?.toLong() | |||||
| val pickOrderCode = poInfo["pick_order_code"] as? String | |||||
| val doOrderId = (poInfo["do_order_id"] as? Number)?.toLong() | |||||
| val deliveryOrderCode = poInfo["delivery_order_code"] as? String | |||||
| val pickOrdersInfo = jdbcDao.queryForList(pickOrdersSql, mapOf("doPickOrderId" to doPickOrderId)) | |||||
| println("🔍 Found ${pickOrdersInfo.size} pick orders") | |||||
| // 收集 IDs 和 codes | |||||
| pickOrderId?.let { pickOrderIds.add(it) } | |||||
| pickOrderCode?.let { pickOrderCodes.add(it) } | |||||
| doOrderId?.let { doOrderIds.add(it) } | |||||
| deliveryOrderCode?.let { deliveryOrderCodes.add(it) } | |||||
| // ✅ Step 3: 为每个 pick order 获取 lines 和 lots(包括 null stock 的) | |||||
| val pickOrders = pickOrdersInfo.map { poInfo -> | |||||
| val pickOrderId = (poInfo["pick_order_id"] as? Number)?.toLong() | |||||
| // ✅ 查询该 pick order 的所有 lines 和 lots | |||||
| val linesSql = """ | |||||
| SELECT | |||||
| 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, | |||||
| pol.id as pickOrderLineId, | |||||
| pol.qty as pickOrderLineRequiredQty, | |||||
| pol.status as pickOrderLineStatus, | |||||
| i.id as itemId, | |||||
| i.code as itemCode, | |||||
| i.name as itemName, | |||||
| uc.code as uomCode, | |||||
| uc.udfudesc as uomDesc, | |||||
| uc.udfShortDesc as uomShortDesc, | |||||
| 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, | |||||
| w.`order` as routerIndex, | |||||
| w.code as routerRoute, | |||||
| CASE | |||||
| WHEN sol.status = 'rejected' THEN NULL | |||||
| ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) | |||||
| END as availableQty, | |||||
| COALESCE(spl.qty, 0) as requiredQty, | |||||
| COALESCE(sol.qty, 0) as actualPickQty, | |||||
| spl.id as suggestedPickLotId, | |||||
| ill.status as lotStatus, | |||||
| sol.id as stockOutLineId, | |||||
| sol.status as stockOutLineStatus, | |||||
| COALESCE(sol.qty, 0) as stockOutLineQty, | |||||
| COALESCE(ill.inQty, 0) as inQty, | |||||
| COALESCE(ill.outQty, 0) as outQty, | |||||
| COALESCE(ill.holdQty, 0) as holdQty, | |||||
| 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, | |||||
| CASE | |||||
| WHEN sol.status = 'completed' THEN 'completed' | |||||
| WHEN sol.status = 'rejected' THEN 'rejected' | |||||
| WHEN sol.status = 'created' THEN 'pending' | |||||
| ELSE 'pending' | |||||
| END as processingStatus | |||||
| FROM fpsmsdb.pick_order po | |||||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||||
| JOIN fpsmsdb.items i ON i.id = pol.itemId | |||||
| LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId | |||||
| // ✅ 查询该 pick order 的所有 lines 和 lots | |||||
| val linesSql = """ | |||||
| SELECT | |||||
| 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, | |||||
| -- ✅ 关键修改:使用 LEFT JOIN 来包含没有 lot 的 pick order lines | |||||
| LEFT JOIN ( | |||||
| SELECT spl.pickOrderLineId, spl.suggestedLotLineId AS lotLineId | |||||
| FROM fpsmsdb.suggested_pick_lot spl | |||||
| UNION | |||||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId | |||||
| FROM fpsmsdb.stock_out_line sol | |||||
| WHERE sol.deleted = false | |||||
| ) ll ON ll.pickOrderLineId = pol.id | |||||
| pol.id as pickOrderLineId, | |||||
| pol.qty as pickOrderLineRequiredQty, | |||||
| pol.status as pickOrderLineStatus, | |||||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl | |||||
| ON spl.pickOrderLineId = pol.id AND spl.suggestedLotLineId = ll.lotLineId | |||||
| LEFT JOIN fpsmsdb.stock_out_line sol | |||||
| ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ll.lotLineId AND sol.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false | |||||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||||
| i.id as itemId, | |||||
| i.code as itemCode, | |||||
| i.name as itemName, | |||||
| uc.code as uomCode, | |||||
| uc.udfudesc as uomDesc, | |||||
| uc.udfShortDesc as uomShortDesc, | |||||
| WHERE po.id = :pickOrderId | |||||
| AND po.deleted = false | |||||
| ORDER BY | |||||
| COALESCE(w.`order`, 999999) ASC, | |||||
| pol.id ASC, | |||||
| il.lotNo ASC | |||||
| """.trimIndent() | |||||
| 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, | |||||
| w.`order` as routerIndex, | |||||
| w.code as routerRoute, | |||||
| CASE | |||||
| WHEN sol.status = 'rejected' THEN NULL | |||||
| ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) | |||||
| END as availableQty, | |||||
| COALESCE(spl.qty, 0) as requiredQty, | |||||
| COALESCE(sol.qty, 0) as actualPickQty, | |||||
| spl.id as suggestedPickLotId, | |||||
| ill.status as lotStatus, | |||||
| sol.id as stockOutLineId, | |||||
| sol.status as stockOutLineStatus, | |||||
| COALESCE(sol.qty, 0) as stockOutLineQty, | |||||
| COALESCE(ill.inQty, 0) as inQty, | |||||
| COALESCE(ill.outQty, 0) as outQty, | |||||
| COALESCE(ill.holdQty, 0) as holdQty, | |||||
| 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, | |||||
| CASE | |||||
| WHEN sol.status = 'completed' THEN 'completed' | |||||
| WHEN sol.status = 'rejected' THEN 'rejected' | |||||
| WHEN sol.status = 'created' THEN 'pending' | |||||
| ELSE 'pending' | |||||
| END as processingStatus | |||||
| FROM fpsmsdb.pick_order po | |||||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||||
| JOIN fpsmsdb.items i ON i.id = pol.itemId | |||||
| LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId | |||||
| val linesResults = jdbcDao.queryForList(linesSql, mapOf("pickOrderId" to pickOrderId)) | |||||
| println("🔍 Pick order $pickOrderId has ${linesResults.size} line-lot records") | |||||
| LEFT JOIN ( | |||||
| SELECT spl.pickOrderLineId, spl.suggestedLotLineId AS lotLineId | |||||
| FROM fpsmsdb.suggested_pick_lot spl | |||||
| UNION | |||||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId | |||||
| FROM fpsmsdb.stock_out_line sol | |||||
| WHERE sol.deleted = false | |||||
| ) ll ON ll.pickOrderLineId = pol.id | |||||
| // ✅ 按 pickOrderLineId 分组 | |||||
| val lineGroups = linesResults.groupBy { (it["pickOrderLineId"] as? Number)?.toLong() } | |||||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl | |||||
| ON spl.pickOrderLineId = pol.id AND spl.suggestedLotLineId = ll.lotLineId | |||||
| LEFT JOIN fpsmsdb.stock_out_line sol | |||||
| ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ll.lotLineId AND sol.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false | |||||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||||
| val pickOrderLines = lineGroups.map { (lineId, lineRows) -> | |||||
| val firstLineRow = lineRows.firstOrNull() | |||||
| if (firstLineRow == null) { | |||||
| null | |||||
| } else { | |||||
| // ✅ 构建 lots 列表(如果没有 lot,返回空数组) | |||||
| val lots = if (lineRows.any { it["lotId"] != null }) { | |||||
| lineRows.filter { it["lotId"] != null }.map { lotRow -> | |||||
| mapOf( | |||||
| "id" to lotRow["lotId"], | |||||
| "lotNo" to lotRow["lotNo"], | |||||
| "expiryDate" to lotRow["expiryDate"], | |||||
| "location" to lotRow["location"], | |||||
| "stockUnit" to lotRow["stockUnit"], | |||||
| "availableQty" to lotRow["availableQty"], | |||||
| "requiredQty" to lotRow["requiredQty"], | |||||
| "actualPickQty" to lotRow["actualPickQty"], | |||||
| "inQty" to lotRow["inQty"], | |||||
| "outQty" to lotRow["outQty"], | |||||
| "holdQty" to lotRow["holdQty"], | |||||
| "lotStatus" to lotRow["lotStatus"], | |||||
| "lotAvailability" to lotRow["lotAvailability"], | |||||
| "processingStatus" to lotRow["processingStatus"], | |||||
| "suggestedPickLotId" to lotRow["suggestedPickLotId"], | |||||
| "stockOutLineId" to lotRow["stockOutLineId"], | |||||
| "stockOutLineStatus" to lotRow["stockOutLineStatus"], | |||||
| "stockOutLineQty" to lotRow["stockOutLineQty"], | |||||
| "router" to mapOf( | |||||
| "id" to null, | |||||
| "index" to lotRow["routerIndex"], | |||||
| "route" to lotRow["routerRoute"], | |||||
| "area" to lotRow["routerRoute"], | |||||
| "itemCode" to lotRow["itemId"], | |||||
| "itemName" to lotRow["itemName"], | |||||
| "uomId" to lotRow["uomCode"], | |||||
| "noofCarton" to lotRow["requiredQty"] | |||||
| ) | |||||
| WHERE po.id = :pickOrderId | |||||
| AND po.deleted = false | |||||
| ORDER BY | |||||
| COALESCE(w.`order`, 999999) ASC, | |||||
| pol.id ASC, | |||||
| il.lotNo ASC | |||||
| """.trimIndent() | |||||
| val linesResults = jdbcDao.queryForList(linesSql, mapOf("pickOrderId" to pickOrderId)) | |||||
| println("🔍 Pick order $pickOrderId has ${linesResults.size} line-lot records") | |||||
| // ✅ 按 pickOrderLineId 分组 | |||||
| val lineGroups = linesResults.groupBy { (it["pickOrderLineId"] as? Number)?.toLong() } | |||||
| val pickOrderLines = lineGroups.map { (lineId, lineRows) -> | |||||
| val firstLineRow = lineRows.firstOrNull() | |||||
| if (firstLineRow == null) { | |||||
| null | |||||
| } else { | |||||
| // ✅ 构建 lots 列表 | |||||
| val lots = if (lineRows.any { it["lotId"] != null }) { | |||||
| lineRows.filter { it["lotId"] != null }.map { lotRow -> | |||||
| mapOf( | |||||
| "id" to lotRow["lotId"], | |||||
| "lotNo" to lotRow["lotNo"], | |||||
| "expiryDate" to lotRow["expiryDate"], | |||||
| "location" to lotRow["location"], | |||||
| "stockUnit" to lotRow["stockUnit"], | |||||
| "availableQty" to lotRow["availableQty"], | |||||
| "requiredQty" to lotRow["requiredQty"], | |||||
| "actualPickQty" to lotRow["actualPickQty"], | |||||
| "inQty" to lotRow["inQty"], | |||||
| "outQty" to lotRow["outQty"], | |||||
| "holdQty" to lotRow["holdQty"], | |||||
| "lotStatus" to lotRow["lotStatus"], | |||||
| "lotAvailability" to lotRow["lotAvailability"], | |||||
| "processingStatus" to lotRow["processingStatus"], | |||||
| "suggestedPickLotId" to lotRow["suggestedPickLotId"], | |||||
| "stockOutLineId" to lotRow["stockOutLineId"], | |||||
| "stockOutLineStatus" to lotRow["stockOutLineStatus"], | |||||
| "stockOutLineQty" to lotRow["stockOutLineQty"], | |||||
| "router" to mapOf( | |||||
| "id" to null, | |||||
| "index" to lotRow["routerIndex"], | |||||
| "route" to lotRow["routerRoute"], | |||||
| "area" to lotRow["routerRoute"], | |||||
| "itemCode" to lotRow["itemId"], | |||||
| "itemName" to lotRow["itemName"], | |||||
| "uomId" to lotRow["uomCode"], | |||||
| "noofCarton" to lotRow["requiredQty"] | |||||
| ) | ) | ||||
| } | |||||
| } else { | |||||
| emptyList() // ✅ 返回空数组而不是 null | |||||
| ) | |||||
| } | } | ||||
| mapOf( | |||||
| "id" to lineId, | |||||
| "requiredQty" to firstLineRow["pickOrderLineRequiredQty"], | |||||
| "status" to firstLineRow["pickOrderLineStatus"], | |||||
| "item" to mapOf( | |||||
| "id" to firstLineRow["itemId"], | |||||
| "code" to firstLineRow["itemCode"], | |||||
| "name" to firstLineRow["itemName"], | |||||
| "uomCode" to firstLineRow["uomCode"], | |||||
| "uomDesc" to firstLineRow["uomDesc"], | |||||
| "uomShortDesc" to firstLineRow["uomShortDesc"], | |||||
| ), | |||||
| "lots" to lots // ✅ 即使是空数组也返回 | |||||
| ) | |||||
| } else { | |||||
| emptyList() | |||||
| } | } | ||||
| }.filterNotNull() | |||||
| mapOf( | |||||
| "pickOrderId" to pickOrderId, | |||||
| "pickOrderCode" to poInfo["pick_order_code"], | |||||
| "doOrderId" to poInfo["do_order_id"], | |||||
| "deliveryOrderCode" to poInfo["delivery_order_code"], | |||||
| "consoCode" to poInfo["consoCode"], | |||||
| "status" to poInfo["status"], | |||||
| "targetDate" to poInfo["targetDate"], | |||||
| "pickOrderLines" to pickOrderLines | |||||
| ) | |||||
| } | |||||
| // ✅ 构建 FG 信息 | |||||
| val fgInfo = mapOf( | |||||
| "doPickOrderId" to doPickOrderId, | |||||
| "ticketNo" to doPickOrderInfo["ticket_no"], | |||||
| "storeId" to doPickOrderInfo["store_id"], | |||||
| "shopCode" to doPickOrderInfo["ShopCode"], | |||||
| "shopName" to doPickOrderInfo["ShopName"], | |||||
| "truckLanceCode" to doPickOrderInfo["TruckLanceCode"], | |||||
| "departureTime" to doPickOrderInfo["truck_departure_time"] | |||||
| ) | |||||
| mapOf( | |||||
| "id" to lineId, | |||||
| "requiredQty" to firstLineRow["pickOrderLineRequiredQty"], | |||||
| "status" to firstLineRow["pickOrderLineStatus"], | |||||
| "item" to mapOf( | |||||
| "id" to firstLineRow["itemId"], | |||||
| "code" to firstLineRow["itemCode"], | |||||
| "name" to firstLineRow["itemName"], | |||||
| "uomCode" to firstLineRow["uomCode"], | |||||
| "uomDesc" to firstLineRow["uomDesc"], | |||||
| "uomShortDesc" to firstLineRow["uomShortDesc"], | |||||
| ), | |||||
| "lots" to lots | |||||
| ) | |||||
| } | |||||
| }.filterNotNull() | |||||
| return mapOf( | |||||
| "fgInfo" to fgInfo, | |||||
| "pickOrders" to pickOrders | |||||
| // 记录该 pick order 的行数 | |||||
| lineCountsPerPickOrder.add(pickOrderLines.size) | |||||
| allPickOrderLines.addAll(pickOrderLines) | |||||
| } | |||||
| // 合并到总列表 | |||||
| allPickOrderLines.sortWith(compareBy( | |||||
| { line -> | |||||
| val lots = line["lots"] as? List<Map<String, Any?>> | |||||
| val firstLot = lots?.firstOrNull() | |||||
| val router = firstLot?.get("router") as? Map<String, Any?> | |||||
| (router?.get("index") as? Number)?.toInt() ?: 999999 | |||||
| } | |||||
| )) | |||||
| // ✅ 构建 FG 信息 | |||||
| val fgInfo = mapOf( | |||||
| "doPickOrderId" to doPickOrderId, | |||||
| "ticketNo" to doPickOrderInfo["ticket_no"], | |||||
| "storeId" to doPickOrderInfo["store_id"], | |||||
| "shopCode" to doPickOrderInfo["ShopCode"], | |||||
| "shopName" to doPickOrderInfo["ShopName"], | |||||
| "truckLanceCode" to doPickOrderInfo["TruckLanceCode"], | |||||
| "departureTime" to doPickOrderInfo["truck_departure_time"] | |||||
| ) | |||||
| // ✅ 构建合并后的 pick order 对象 | |||||
| val mergedPickOrder = if (pickOrdersInfo.isNotEmpty()) { | |||||
| val firstPickOrderInfo = pickOrdersInfo.first() | |||||
| mapOf( | |||||
| "pickOrderIds" to pickOrderIds, | |||||
| "pickOrderCodes" to pickOrderCodes, | |||||
| "doOrderIds" to doOrderIds, | |||||
| "deliveryOrderCodes" to deliveryOrderCodes, | |||||
| "lineCountsPerPickOrder" to lineCountsPerPickOrder, | |||||
| "consoCode" to firstPickOrderInfo["consoCode"], | |||||
| "status" to firstPickOrderInfo["status"], | |||||
| "targetDate" to firstPickOrderInfo["targetDate"], | |||||
| "pickOrderLines" to allPickOrderLines | |||||
| ) | ) | ||||
| } else { | |||||
| null | |||||
| } | } | ||||
| return mapOf( | |||||
| "fgInfo" to fgInfo, | |||||
| "pickOrders" to listOfNotNull(mergedPickOrder) | |||||
| ) | |||||
| } | |||||
| // Fix the type issues in the getPickOrdersByDateAndStore method | // Fix the type issues in the getPickOrdersByDateAndStore method | ||||
| open fun getPickOrdersByDateAndStore(storeId: String): Map<String, Any?> { | open fun getPickOrdersByDateAndStore(storeId: String): Map<String, Any?> { | ||||
| println("=== Debug: getPickOrdersByDateAndStore ===") | println("=== Debug: getPickOrdersByDateAndStore ===") | ||||