|
|
|
@@ -691,52 +691,74 @@ open class PickOrderService( |
|
|
|
} else { |
|
|
|
emptyMap() |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Pick Orders |
|
|
|
val releasePickOrderInfos = pos |
|
|
|
.map { po -> |
|
|
|
val releasePickOrderLineInfos = po.pickOrderLines.map { pol -> |
|
|
|
val inventory = pol.item?.id?.let { inventories[it] } |
|
|
|
val itemUom = pol.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } |
|
|
|
|
|
|
|
|
|
|
|
// ✅ Move stockOutLines declaration inside the pol loop |
|
|
|
val stockOutLines = stockOutLinesByPickOrderLineId[pol.id] ?: emptyList() |
|
|
|
|
|
|
|
// ✅ Fix: Convert availableQty from base units to sales units |
|
|
|
val convertedAvailableQty = inventory?.sumOf { i -> |
|
|
|
val inQty = i.inQty ?: zero |
|
|
|
val outQty = i.outQty ?: zero |
|
|
|
val holdQty = i.holdQty ?: zero |
|
|
|
val baseQty = inQty.minus(outQty).minus(holdQty) |
|
|
|
println("Item ID: ${i.item?.id}, InQty: $inQty, OutQty: $outQty, HoldQty: $holdQty, BaseQty: $baseQty") |
|
|
|
|
|
|
|
// ✅ NEW: Subtract completed picked quantities for this specific inventory lot line |
|
|
|
val completedPickedQty = stockOutLines |
|
|
|
.filter { it.status == "completed" || it.status == "COMPLETE" } |
|
|
|
.filter { stockOutLine -> |
|
|
|
// ✅ Check if this stock out line is for the current inventory lot line |
|
|
|
stockOutLine.inventoryLotLineId == i.id |
|
|
|
} |
|
|
|
.sumOf { it.qty ?: zero } |
|
|
|
|
|
|
|
val adjustedBaseQty = baseQty.minus(completedPickedQty) |
|
|
|
|
|
|
|
println("Item ID: ${i.item?.id}, BaseQty: $baseQty, CompletedPicked: $completedPickedQty, Adjusted: $adjustedBaseQty") |
|
|
|
|
|
|
|
// Apply unit conversion if needed |
|
|
|
val itemUom = pol.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } |
|
|
|
val ratioN = itemUom?.ratioN |
|
|
|
val ratioD = itemUom?.ratioD |
|
|
|
println("Item ID: ${pol.item?.id}, RatioN: $ratioN, RatioD: $ratioD") |
|
|
|
val convertedQty: BigDecimal = if (ratioN != null && ratioD != null && ratioD != zero) { |
|
|
|
baseQty.divide(ratioN.divide(ratioD, 10, java.math.RoundingMode.HALF_UP), 2, java.math.RoundingMode.HALF_UP) |
|
|
|
} else { |
|
|
|
baseQty |
|
|
|
} |
|
|
|
|
|
|
|
// Ensure the lambda returns BigDecimal |
|
|
|
convertedQty |
|
|
|
//val itemUom = pol.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } |
|
|
|
// val ratioN = itemUom?.ratioN |
|
|
|
// val ratioD = itemUom?.ratioD |
|
|
|
|
|
|
|
// val convertedQty: BigDecimal = if (ratioN != null && ratioD != null && ratioD != zero) { |
|
|
|
// adjustedBaseQty.divide(ratioN.divide(ratioD, 10, java.math.RoundingMode.HALF_UP), 2, java.math.RoundingMode.HALF_UP) |
|
|
|
// } else { |
|
|
|
// adjustedBaseQty |
|
|
|
//} |
|
|
|
|
|
|
|
adjustedBaseQty |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ✅ Calculate total picked quantity from stock out lines |
|
|
|
val stockOutLines = stockOutLinesByPickOrderLineId[pol.id] ?: emptyList() |
|
|
|
val totalPickedQty = stockOutLines.sumOf { it.qty ?: zero } |
|
|
|
|
|
|
|
println("=== PICKED QTY DEBUG: Line ${pol.id} ===") |
|
|
|
println("Stock Out Lines: ${stockOutLines.map { "${it.id}(status=${it.status}, qty=${it.qty})" }}") |
|
|
|
|
|
|
|
val totalPickedQty = stockOutLines |
|
|
|
.filter { it.status == "completed" || it.status == "COMPLETE" } // Only completed lines |
|
|
|
.filter { (it.qty ?: zero) > BigDecimal.ZERO } // Only lines with actual quantities |
|
|
|
.sumOf { it.qty ?: zero } |
|
|
|
|
|
|
|
println("Total Picked Qty: $totalPickedQty") |
|
|
|
println("=== END DEBUG ===") |
|
|
|
|
|
|
|
// Return |
|
|
|
GetPickOrderLineInfo( |
|
|
|
id = pol.id, |
|
|
|
itemId = pol.item?.id, |
|
|
|
itemCode = pol.item?.code, |
|
|
|
itemName = pol.item?.name, |
|
|
|
availableQty = convertedAvailableQty, // ✅ Use converted quantity |
|
|
|
availableQty = convertedAvailableQty, // ✅ Use adjusted available quantity |
|
|
|
requiredQty = pol.qty, |
|
|
|
uomCode = pol.uom?.code, |
|
|
|
uomDesc = pol.uom?.udfudesc, |
|
|
|
suggestedList = suggestions.suggestedList.filter { it.pickOrderLine?.id == pol.id }, |
|
|
|
// ✅ Add picked quantity data |
|
|
|
pickedQty = totalPickedQty |
|
|
|
) |
|
|
|
} |
|
|
|
@@ -764,14 +786,8 @@ open class PickOrderService( |
|
|
|
item.second.let { |
|
|
|
val convertedAvailableQty = inventory?.sumOf { i -> |
|
|
|
val baseQty = (i.availableQty ?: zero) |
|
|
|
val ratioN = itemUom?.ratioN |
|
|
|
val ratioD = itemUom?.ratioD |
|
|
|
|
|
|
|
if (ratioN != null && ratioD != null && ratioD != zero) { |
|
|
|
baseQty.divide(ratioN.divide(ratioD, 10, java.math.RoundingMode.HALF_UP), 2, java.math.RoundingMode.HALF_UP) |
|
|
|
} else { |
|
|
|
baseQty |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
it.availableQty = convertedAvailableQty |
|
|
|
@@ -841,15 +857,8 @@ open class PickOrderService( |
|
|
|
il.lotNo, |
|
|
|
il.expiryDate, |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
-- ✅ 修复:availableQty 应该显示实际可用数量(保持小数) |
|
|
|
CASE |
|
|
|
WHEN sales_iu.ratioN IS NOT NULL AND sales_iu.ratioD IS NOT NULL AND sales_iu.ratioD != 0 THEN |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) / (sales_iu.ratioN / sales_iu.ratioD) |
|
|
|
ELSE |
|
|
|
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) |
|
|
|
END as availableQty, |
|
|
|
-- ✅ 修复:requiredQty 直接使用 spl.qty,因为它已经是销售单位 |
|
|
|
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, |
|
|
|
@@ -880,13 +889,27 @@ open class PickOrderService( |
|
|
|
println("🔍 With parameters: pickOrderLineId = $pickOrderLineId") |
|
|
|
|
|
|
|
val result = jdbcDao.queryForList(sql, mapOf("pickOrderLineId" to pickOrderLineId)) |
|
|
|
//val result = jdbcDao.queryForList(sql, mapOf("pickOrderLineId" to pickOrderLineId)) |
|
|
|
|
|
|
|
println("Final result count: ${result.size}") |
|
|
|
result.forEach { row -> |
|
|
|
// ✅ Filter out completed lots |
|
|
|
val filteredResult = result.filter { row -> |
|
|
|
val stockOutLineStatus = row["stockOutLineStatus"] as String? |
|
|
|
val stockOutLineQty = row["stockOutLineQty"] as Number? |
|
|
|
val requiredQty = row["requiredQty"] as Number? |
|
|
|
|
|
|
|
// Show lot if: |
|
|
|
// 1. No stock out line exists, OR |
|
|
|
// 2. Stock out line is not completed, OR |
|
|
|
// 3. Stock out line qty doesn't equal required qty |
|
|
|
stockOutLineStatus != "completed" || |
|
|
|
stockOutLineQty?.toDouble() != requiredQty?.toDouble() |
|
|
|
} |
|
|
|
println("Final result count: ${filteredResult.size}") |
|
|
|
filteredResult.forEach { row -> |
|
|
|
println("Final Row: $row") |
|
|
|
} |
|
|
|
|
|
|
|
return result |
|
|
|
return filteredResult |
|
|
|
} |
|
|
|
|
|
|
|
@Transactional(rollbackFor = [java.lang.Exception::class]) |
|
|
|
|