Browse Source

update

master
CANCERYS\kw093 1 month ago
parent
commit
1cbf74dda4
4 changed files with 148 additions and 95 deletions
  1. +4
    -3
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt
  2. +2
    -4
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt
  3. +140
    -88
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  4. +2
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt

+ 4
- 3
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt View File

@@ -291,6 +291,7 @@ open class DoPickOrderService(
println("🔍 DEBUG: Found ${allRecords.size} records for date $targetDate")
// ✅ 过滤掉所有 do_pick_order_line 都是 "issue" 状态的 shop
/*
val filteredRecords = allRecords.filter { doPickOrder ->
val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!)
if (!hasNonIssueLines) {
@@ -298,11 +299,11 @@ open class DoPickOrderService(
}
hasNonIssueLines
}
println("🔍 DEBUG: After filtering, ${filteredRecords.size} records remain")
*/
// println("🔍 DEBUG: After filtering, ${filteredRecords.size} records remain")
// ✅ 使用过滤后的记录
val grouped = filteredRecords.groupBy { it.truckDepartureTime to it.truckLanceCode }
val grouped = allRecords.groupBy { it.truckDepartureTime to it.truckLanceCode }
.mapValues { (_, list) ->
LaneBtn(
truckLanceCode = list.first().truckLanceCode ?: "",


+ 2
- 4
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt View File

@@ -713,8 +713,6 @@ open fun createBatchReleaseIssue(
FROM fpsmsdb.delivery_order_line dol
INNER JOIN fpsmsdb.items i ON i.id = dol.itemId
WHERE dol.deliveryOrderId = :deliveryOrderId
INNER JOIN fpsmsdb.items i ON i.id = dol.itemId
WHERE dol.doId = :deliveryOrderId
AND dol.deleted = 0
""".trimIndent()
@@ -738,11 +736,11 @@ open fun createBatchReleaseIssue(
val issue = PickExecutionIssue(
id = null,
pickOrderId = 0L, // batch release 失败时可能还没有 pick order
pickOrderId = null, // batch release 失败时可能还没有 pick order
pickOrderCode = deliveryOrder["code"] as? String ?: "",
pickOrderCreateDate = LocalDate.now(),
pickExecutionDate = LocalDate.now(),
pickOrderLineId = 0L, // batch release 失败时可能还没有 pick order line
pickOrderLineId = null, // batch release 失败时可能还没有 pick order line
issueNo = issueNo,
joPickOrderId = null,
doPickOrderId = null,


+ 140
- 88
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt View File

@@ -3642,98 +3642,128 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A
// ✅ 查询该 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
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 (
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
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,

-- 新增:stockouts 专用字段(不依赖 ll)
sol_any.id as stockOutLineId_any,
sol_any.status as stockOutLineStatus_any,
COALESCE(sol_any.qty, 0) as stockOutLineQty_any,
sol_any.inventoryLotLineId as lotId_any,
il_any.lotNo as lotNo_any,
w_any.name as location_any,
-- 仅当有 lot 时可计算,没 lot 时为 NULL
CASE
WHEN ill_any.id IS NULL THEN NULL
ELSE (COALESCE(ill_any.inQty,0) - COALESCE(ill_any.outQty,0) - COALESCE(ill_any.holdQty,0))
END as availableQty_any
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

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

LEFT JOIN fpsmsdb.suggested_pick_lot spl
ON spl.pickOrderLineId = pol.id AND spl.suggestedLotLineId = ll.lotLineId

-- lots 用(保留原逻辑)
LEFT JOIN fpsmsdb.stock_out_line sol
ON sol.pickOrderLineId = pol.id
AND ( (sol.inventoryLotLineId = ll.lotLineId)
OR (sol.inventoryLotLineId IS NULL AND ll.lotLineId IS NULL) )
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

-- stockouts 用(不依赖 ll)
LEFT JOIN fpsmsdb.stock_out_line sol_any
ON sol_any.pickOrderLineId = pol.id
AND sol_any.deleted = false
LEFT JOIN fpsmsdb.inventory_lot_line ill_any
ON ill_any.id = sol_any.inventoryLotLineId AND ill_any.deleted = false
LEFT JOIN fpsmsdb.inventory_lot il_any
ON il_any.id = ill_any.inventoryLotId AND il_any.deleted = false
LEFT JOIN fpsmsdb.warehouse w_any
ON w_any.id = ill_any.warehouseId

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")
println("DEBUG polIds in linesResults: " + linesResults.map { it["pickOrderLineId"] }.distinct())
println("DEBUG sol polIds in linesResults: " + linesResults.mapNotNull { it["stockOutLineId"]?.let { _ -> it["pickOrderLineId"] } }.distinct())
// ✅ 按 pickOrderLineId 分组
val lineGroups = linesResults.groupBy { (it["pickOrderLineId"] as? Number)?.toLong() }
@@ -3743,7 +3773,7 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A
if (firstLineRow == null) {
null
} else {
// ✅ 构建 lots 列表
// ✅ lots:仍然是“有批次”的明细(保留你当前的逻辑)
val lots = if (lineRows.any { it["lotId"] != null }) {
lineRows.filter { it["lotId"] != null }.map { lotRow ->
mapOf(
@@ -3780,7 +3810,27 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A
} else {
emptyList()
}

// ✅ 新增:stockouts(包括 inventoryLotLineId 为 null 的出库行)
// stockouts:包含所有出库行(即使 lot 为空)
val stockouts = lineRows
.filter { it["stockOutLineId_any"] != null }
.map { row ->
val noLot = (row["lotId_any"] == null)
mapOf(
"id" to row["stockOutLineId_any"],
"status" to row["stockOutLineStatus_any"],
"qty" to row["stockOutLineQty_any"],
"lotId" to row["lotId_any"], // 可能为 null
"lotNo" to (row["lotNo_any"] ?: ""), // 用 *_any
"location" to (row["location_any"] ?: ""), // 用 *_any
"availableQty" to row["availableQty_any"], // 用 *_any
"noLot" to noLot
)
//println("DEBUG sol_any stockOutLineId: " + row["stockOutLineId_any"])
//println("DEBUG sol_any pickOrderLineId: " + row["pickOrderLineId"])
}

mapOf(
"id" to lineId,
"requiredQty" to firstLineRow["pickOrderLineRequiredQty"],
@@ -3793,7 +3843,9 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A
"uomDesc" to firstLineRow["uomDesc"],
"uomShortDesc" to firstLineRow["uomShortDesc"],
),
"lots" to lots
"lots" to lots,
// ✅ 新增字段
"stockouts" to stockouts
)
}
}.filterNotNull()


+ 2
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt View File

@@ -212,6 +212,7 @@ open class SuggestedPickLotService(
qty = remainingQtyToAllocate // ✅ 保存销售单位
}
try {
/*
val pickOrder = line.pickOrder
if (pickOrder != null) {
createInsufficientStockIssue(
@@ -220,6 +221,7 @@ open class SuggestedPickLotService(
insufficientQty = remainingQtyToAllocate
)
}
*/
} catch (e: Exception) {
println("❌ Error creating insufficient stock issue: ${e.message}")
e.printStackTrace()


Loading…
Cancel
Save