From 9563d84c0bbf06e463fe4cb1829662c393d600df Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 9 Sep 2025 22:40:58 +0800 Subject: [PATCH] update --- .../pickOrder/service/PickOrderService.kt | 155 +++++++++++------- .../stock/service/SuggestedPickLotService.kt | 2 +- .../stock/web/SuggestedPickLotController.kt | 6 +- 3 files changed, 96 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt index ff76255..1512942 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt @@ -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") diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt index f9c47d9..6b7397b 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt @@ -123,7 +123,7 @@ open class SuggestedPickLotService( // ✅ 修复:在销售单位中计算分配数量 val assignQtyInSalesUnits = minOf(availableQtyInSalesUnits, remainingQty) remainingQty = remainingQty.minus(assignQtyInSalesUnits) - + val newHoldQtyInBaseUnits = holdQtyMap[lotLine.id] ?: zero // ✅ 修复:将销售单位转换为基础单位来更新 holdQty val assignQtyInBaseUnits = assignQtyInSalesUnits.multiply(ratio) holdQtyMap[lotLine.id] = (holdQtyMap[lotLine.id] ?: zero).plus(assignQtyInBaseUnits) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/SuggestedPickLotController.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/SuggestedPickLotController.kt index 80e7ee2..9fc3e2f 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/SuggestedPickLotController.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/SuggestedPickLotController.kt @@ -23,11 +23,7 @@ class SuggestedPickLotController( val pickOrderLineService: PurchaseOrderLineService, val pickOrderRepository: PickOrderRepository ) { -// @GetMapping("/test/{conso}") -// fun test(@PathVariable conso: String): Any { -// val test1 = pickOrderRepository.findAllByConsoCode(conso).flatMap { it.pickOrderLines } -// return suggestedPickLotService.suggestionForPickOrderLines(test1) -// } + @GetMapping("/test/{pickOrderId}") fun test(@PathVariable pickOrderId: Long): Any {