|
|
|
@@ -523,249 +523,301 @@ open class SuggestedPickLotService( |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
@Transactional(rollbackFor = [Exception::class]) |
|
|
|
open fun resuggestPickOrder(pickOrderId: Long): MessageResponse { |
|
|
|
try { |
|
|
|
val pickOrder = pickOrderRepository.findById(pickOrderId).orElseThrow() |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG START ===") |
|
|
|
println("Pick Order ID: $pickOrderId") |
|
|
|
println("Pick Order Code: ${pickOrder.code}") |
|
|
|
println("Pick Order Status: ${pickOrder.status}") |
|
|
|
|
|
|
|
// NEW: Get ALL pick orders for the same items |
|
|
|
val itemIds = pickOrder.pickOrderLines.mapNotNull { it.item?.id }.distinct() |
|
|
|
println("Item IDs in current pick order: $itemIds") |
|
|
|
|
|
|
|
val allCompetingPickOrders = mutableListOf<PickOrder>() |
|
|
|
|
|
|
|
itemIds.forEach { itemId -> |
|
|
|
val competingOrders = pickOrderLineRepository.findAllPickOrdersByItemId(itemId) |
|
|
|
.filter { it.id != pickOrderId } // Exclude current pick order |
|
|
|
println("Found ${competingOrders.size} competing pick orders for item $itemId") |
|
|
|
competingOrders.forEach { order -> |
|
|
|
println(" - Competing Order: ${order.code} (ID: ${order.id}, Status: ${order.status})") |
|
|
|
} |
|
|
|
allCompetingPickOrders.addAll(competingOrders) |
|
|
|
@Transactional(rollbackFor = [Exception::class]) |
|
|
|
open fun resuggestPickOrder(pickOrderId: Long): MessageResponse { |
|
|
|
try { |
|
|
|
val pickOrder = pickOrderRepository.findById(pickOrderId).orElseThrow() |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG START ===") |
|
|
|
println("Pick Order ID: $pickOrderId") |
|
|
|
println("Pick Order Code: ${pickOrder.code}") |
|
|
|
println("Pick Order Status: ${pickOrder.status}") |
|
|
|
|
|
|
|
// NEW: Get ALL pick orders for the same items |
|
|
|
val itemIds = pickOrder.pickOrderLines.mapNotNull { it.item?.id }.distinct() |
|
|
|
println("Item IDs in current pick order: $itemIds") |
|
|
|
|
|
|
|
val allCompetingPickOrders = mutableListOf<PickOrder>() |
|
|
|
|
|
|
|
itemIds.forEach { itemId -> |
|
|
|
val competingOrders = pickOrderLineRepository.findAllPickOrdersByItemId(itemId) |
|
|
|
.filter { it.id != pickOrderId } // Exclude current pick order |
|
|
|
println("Found ${competingOrders.size} competing pick orders for item $itemId") |
|
|
|
competingOrders.forEach { order -> |
|
|
|
println(" - Competing Order: ${order.code} (ID: ${order.id}, Status: ${order.status})") |
|
|
|
} |
|
|
|
|
|
|
|
// FIX: Only resuggest pick orders that have rejected stock out lines |
|
|
|
val allPickOrdersToResuggest = (listOf(pickOrder) + allCompetingPickOrders) |
|
|
|
.filter { pickOrderToCheck -> |
|
|
|
// Only resuggest if the pick order has rejected stock out lines |
|
|
|
pickOrderToCheck.pickOrderLines.any { pol -> |
|
|
|
val stockOutLines = stockOutLIneRepository.findAllByPickOrderLineIdAndDeletedFalse(pol.id!!) |
|
|
|
val hasRejectedStockOutLine = stockOutLines.any { it.status.equals("rejected", ignoreCase = true)} |
|
|
|
|
|
|
|
if (hasRejectedStockOutLine) { |
|
|
|
println("Pick Order ${pickOrderToCheck.code} has rejected stock out lines - will resuggest") |
|
|
|
stockOutLines.filter { it.status == "rejected" }.forEach { sol -> |
|
|
|
println(" - Rejected stock out line: ${sol.id} (lot: ${sol.inventoryLotLineId}, qty: ${sol.qty})") |
|
|
|
} |
|
|
|
allCompetingPickOrders.addAll(competingOrders) |
|
|
|
} |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 批量收集所有需要检查的 pick order line IDs |
|
|
|
val allPickOrderLineIdsToCheck = (listOf(pickOrder) + allCompetingPickOrders) |
|
|
|
.flatMap { it.pickOrderLines } |
|
|
|
.mapNotNull { it.id } |
|
|
|
.distinct() |
|
|
|
|
|
|
|
println("Checking ${allPickOrderLineIdsToCheck.size} pick order lines for rejected stock out lines") |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 批量查询所有 stock out lines(一次查询代替 N*M 次查询) |
|
|
|
// 注意:findAllByPickOrderLineIdInAndDeletedFalse 返回 List<StockOutLine>(实体类) |
|
|
|
val allStockOutLines = if (allPickOrderLineIdsToCheck.isNotEmpty()) { |
|
|
|
stockOutLIneRepository.findAllByPickOrderLineIdInAndDeletedFalse(allPickOrderLineIdsToCheck) |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
println("Found ${allStockOutLines.size} stock out lines in batch query (1 query instead of ${allPickOrderLineIdsToCheck.size} queries)") |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 按 pickOrderLineId 分组,便于后续查找 |
|
|
|
// 注意:StockOutLine 实体使用 pickOrderLine?.id,不是 pickOrderLineId |
|
|
|
val stockOutLinesByPickOrderLineId = allStockOutLines |
|
|
|
.groupBy { it.pickOrderLine?.id } |
|
|
|
|
|
|
|
// FIX: Only resuggest pick orders that have rejected stock out lines |
|
|
|
val allPickOrdersToResuggest = (listOf(pickOrder) + allCompetingPickOrders) |
|
|
|
.filter { pickOrderToCheck -> |
|
|
|
// Only resuggest if the pick order has rejected stock out lines |
|
|
|
pickOrderToCheck.pickOrderLines.any { pol -> |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取,而不是查询数据库 |
|
|
|
val stockOutLines = stockOutLinesByPickOrderLineId[pol.id] ?: emptyList() |
|
|
|
val hasRejectedStockOutLine = stockOutLines.any { |
|
|
|
it.status?.equals("rejected", ignoreCase = true) == true |
|
|
|
} |
|
|
|
|
|
|
|
if (hasRejectedStockOutLine) { |
|
|
|
println("Pick Order ${pickOrderToCheck.code} has rejected stock out lines - will resuggest") |
|
|
|
stockOutLines.filter { it.status?.equals("rejected", ignoreCase = true) == true }.forEach { sol -> |
|
|
|
println(" - Rejected stock out line: ${sol.id} (lot: ${sol.inventoryLotLine?.id}, qty: ${sol.qty})") |
|
|
|
} |
|
|
|
|
|
|
|
hasRejectedStockOutLine |
|
|
|
} |
|
|
|
|
|
|
|
hasRejectedStockOutLine |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG ===") |
|
|
|
println("Original pick orders: ${(listOf(pickOrder) + allCompetingPickOrders).size}") |
|
|
|
println("Filtered pick orders to resuggest: ${allPickOrdersToResuggest.size}") |
|
|
|
println("Pick orders being resuggested: ${allPickOrdersToResuggest.map { "${it.code}(${it.status})" }}") |
|
|
|
|
|
|
|
// FIX: Only resuggest if there are actually pick orders with rejected lots |
|
|
|
if (allPickOrdersToResuggest.isEmpty()) { |
|
|
|
println("No pick orders need resuggesting - no rejected lots found") |
|
|
|
return MessageResponse( |
|
|
|
id = pickOrderId, |
|
|
|
name = "No resuggest needed", |
|
|
|
code = "SUCCESS", |
|
|
|
type = "resuggest", |
|
|
|
message = "No pick orders have rejected lots, no resuggest needed", |
|
|
|
errorPosition = null |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// FIX: Get all pick order line IDs for the orders to resuggest |
|
|
|
val allPickOrderLineIds = allPickOrdersToResuggest |
|
|
|
.flatMap { it.pickOrderLines } |
|
|
|
.mapNotNull { it.id } |
|
|
|
|
|
|
|
println("All pick order line IDs to resuggest: $allPickOrderLineIds") |
|
|
|
|
|
|
|
// FIX: Get all existing suggestions for these pick order lines |
|
|
|
val allSuggestions = suggestedPickLotRepository.findAllByPickOrderLineIdIn(allPickOrderLineIds) |
|
|
|
println("Found ${allSuggestions.size} existing suggestions") |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 批量查询所有相关的 stock out lines(用于检查 rejected 状态) |
|
|
|
val allSuggestionStockOutLines = if (allSuggestions.isNotEmpty()) { |
|
|
|
val suggestionLineIds = allSuggestions.mapNotNull { it.pickOrderLine?.id }.distinct() |
|
|
|
val suggestionLotIds = allSuggestions.mapNotNull { it.suggestedLotLine?.id }.distinct() |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG ===") |
|
|
|
println("Original pick orders: ${(listOf(pickOrder) + allCompetingPickOrders).size}") |
|
|
|
println("Filtered pick orders to resuggest: ${allPickOrdersToResuggest.size}") |
|
|
|
println("Pick orders being resuggested: ${allPickOrdersToResuggest.map { "${it.code}(${it.status})" }}") |
|
|
|
|
|
|
|
// FIX: Only resuggest if there are actually pick orders with rejected lots |
|
|
|
if (allPickOrdersToResuggest.isEmpty()) { |
|
|
|
println("No pick orders need resuggesting - no rejected lots found") |
|
|
|
return MessageResponse( |
|
|
|
id = pickOrderId, |
|
|
|
name = "No resuggest needed", |
|
|
|
code = "SUCCESS", |
|
|
|
type = "resuggest", |
|
|
|
message = "No pick orders have rejected lots, no resuggest needed", |
|
|
|
errorPosition = null |
|
|
|
// OPTIMIZATION 3: 使用批量查询方法(一次查询代替 N*M 次查询) |
|
|
|
// 注意:返回 List<StockOutLine>(实体类) |
|
|
|
if (suggestionLineIds.isNotEmpty() && suggestionLotIds.isNotEmpty()) { |
|
|
|
stockOutLIneRepository.findAllByPickOrderLineIdInAndInventoryLotLineIdInAndDeletedFalse( |
|
|
|
suggestionLineIds, |
|
|
|
suggestionLotIds |
|
|
|
) |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
// FIX: Get all pick order line IDs for the orders to resuggest |
|
|
|
val allPickOrderLineIds = allPickOrdersToResuggest |
|
|
|
.flatMap { it.pickOrderLines } |
|
|
|
.mapNotNull { it.id } |
|
|
|
|
|
|
|
println("All pick order line IDs to resuggest: $allPickOrderLineIds") |
|
|
|
|
|
|
|
// FIX: Get all existing suggestions for these pick order lines |
|
|
|
val allSuggestions = suggestedPickLotRepository.findAllByPickOrderLineIdIn(allPickOrderLineIds) |
|
|
|
println("Found ${allSuggestions.size} existing suggestions") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 删除第 376-395 行的旧代码,替换为: |
|
|
|
// FIX: Separate suggestions to keep (those WITHOUT rejected stock out lines) and delete |
|
|
|
val suggestionsToKeep = allSuggestions.filter { suggestion -> |
|
|
|
val pickOrderLineId = suggestion.pickOrderLine?.id |
|
|
|
val suggestedLotLineId = suggestion.suggestedLotLine?.id |
|
|
|
|
|
|
|
if (pickOrderLineId != null && suggestedLotLineId != null) { |
|
|
|
val stockOutLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( |
|
|
|
pickOrderLineId, |
|
|
|
suggestedLotLineId |
|
|
|
) |
|
|
|
// 保留没有 rejected stock out lines 的 suggestions |
|
|
|
!stockOutLines.any { it.status == "rejected" } |
|
|
|
} else { |
|
|
|
true // 保留有问题的 suggestions 用于调试 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 只删除有 rejected stock out lines 的 suggestions |
|
|
|
val suggestionsToDelete = allSuggestions.filter { suggestion -> |
|
|
|
val pickOrderLineId = suggestion.pickOrderLine?.id |
|
|
|
val suggestedLotLineId = suggestion.suggestedLotLine?.id |
|
|
|
|
|
|
|
if (pickOrderLineId != null && suggestedLotLineId != null) { |
|
|
|
val stockOutLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( |
|
|
|
pickOrderLineId, |
|
|
|
suggestedLotLineId |
|
|
|
) |
|
|
|
stockOutLines.any { it.status == "rejected" } // 只删除 rejected 的 |
|
|
|
} else { |
|
|
|
suggestedLotLineId == null |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
println("Found ${allSuggestionStockOutLines.size} stock out lines for suggestions in batch query (1 query instead of ${allSuggestions.size} queries)") |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 按 (pickOrderLineId, inventoryLotLineId) 分组 |
|
|
|
// 注意:StockOutLine 实体使用 pickOrderLine?.id 和 inventoryLotLine?.id |
|
|
|
val stockOutLinesByLineAndLot = allSuggestionStockOutLines |
|
|
|
.groupBy { |
|
|
|
val lineId = it.pickOrderLine?.id |
|
|
|
val lotId = it.inventoryLotLine?.id |
|
|
|
lineId to lotId |
|
|
|
} |
|
|
|
|
|
|
|
// FIX: Separate suggestions to keep (those WITHOUT rejected stock out lines) and delete |
|
|
|
val suggestionsToKeep = allSuggestions.filter { suggestion -> |
|
|
|
val pickOrderLineId = suggestion.pickOrderLine?.id |
|
|
|
val suggestedLotLineId = suggestion.suggestedLotLine?.id |
|
|
|
|
|
|
|
println("Suggestions to keep (with rejected stock out lines): ${suggestionsToKeep.size}") |
|
|
|
println("Suggestions to delete: ${suggestionsToDelete.size}") |
|
|
|
|
|
|
|
// FIX: Clear holdQty ONLY for lots that have rejected stock out lines |
|
|
|
val rejectedLotIds = suggestionsToDelete.mapNotNull { it.suggestedLotLine?.id }.distinct() |
|
|
|
println("Rejected lot IDs (clearing holdQty only): $rejectedLotIds") |
|
|
|
|
|
|
|
rejectedLotIds.forEach { lotId -> |
|
|
|
val lot = inventoryLotLineRepository.findById(lotId).orElse(null) |
|
|
|
lot?.let { |
|
|
|
val originalHoldQty = it.holdQty ?: BigDecimal.ZERO |
|
|
|
it.holdQty = BigDecimal.ZERO |
|
|
|
inventoryLotLineRepository.save(it) |
|
|
|
println("Cleared holdQty for rejected lot ${lot.id}: $originalHoldQty -> 0") |
|
|
|
} |
|
|
|
if (pickOrderLineId != null && suggestedLotLineId != null) { |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取 |
|
|
|
val stockOutLines = stockOutLinesByLineAndLot[pickOrderLineId to suggestedLotLineId] ?: emptyList() |
|
|
|
// 保留没有 rejected stock out lines 的 suggestions |
|
|
|
!stockOutLines.any { it.status?.equals("rejected", ignoreCase = true) == true } |
|
|
|
} else { |
|
|
|
true // 保留有问题的 suggestions 用于调试 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
println("Keeping all suggestions (including rejected ones for display)") |
|
|
|
|
|
|
|
// NEW: Build holdQtyMap with existing holdQty from other pick orders |
|
|
|
val existingHoldQtyMap = mutableMapOf<Long?, BigDecimal?>() |
|
|
|
// 只删除有 rejected stock out lines 的 suggestions |
|
|
|
val suggestionsToDelete = allSuggestions.filter { suggestion -> |
|
|
|
val pickOrderLineId = suggestion.pickOrderLine?.id |
|
|
|
val suggestedLotLineId = suggestion.suggestedLotLine?.id |
|
|
|
|
|
|
|
// Get all lots that are being used by other pick orders (including those NOT being resuggested) |
|
|
|
val allOtherPickOrderLineIds = allCompetingPickOrders |
|
|
|
.flatMap { it.pickOrderLines } |
|
|
|
.mapNotNull { it.id } |
|
|
|
|
|
|
|
println("Other pick order line IDs: $allOtherPickOrderLineIds") |
|
|
|
if (pickOrderLineId != null && suggestedLotLineId != null) { |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取 |
|
|
|
val stockOutLines = stockOutLinesByLineAndLot[pickOrderLineId to suggestedLotLineId] ?: emptyList() |
|
|
|
stockOutLines.any { it.status?.equals("rejected", ignoreCase = true) == true } // 只删除 rejected 的 |
|
|
|
} else { |
|
|
|
suggestedLotLineId == null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
println("Suggestions to keep: ${suggestionsToKeep.size}") |
|
|
|
println("Suggestions to delete: ${suggestionsToDelete.size}") |
|
|
|
|
|
|
|
// FIX: Clear holdQty ONLY for lots that have rejected stock out lines |
|
|
|
val rejectedLotIds = suggestionsToDelete.mapNotNull { it.suggestedLotLine?.id }.distinct() |
|
|
|
println("Rejected lot IDs (clearing holdQty only): $rejectedLotIds") |
|
|
|
|
|
|
|
// OPTIMIZATION 3: 批量加载和更新 lots |
|
|
|
val rejectedLots = if (rejectedLotIds.isNotEmpty()) { |
|
|
|
inventoryLotLineRepository.findAllById(rejectedLotIds) |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
rejectedLots.forEach { lot -> |
|
|
|
val originalHoldQty = lot.holdQty ?: BigDecimal.ZERO |
|
|
|
lot.holdQty = BigDecimal.ZERO |
|
|
|
println("Cleared holdQty for rejected lot ${lot.id}: $originalHoldQty -> 0") |
|
|
|
} |
|
|
|
|
|
|
|
if (rejectedLots.isNotEmpty()) { |
|
|
|
inventoryLotLineRepository.saveAll(rejectedLots) |
|
|
|
println("Batch cleared holdQty for ${rejectedLots.size} rejected lots") |
|
|
|
} |
|
|
|
|
|
|
|
println("Keeping all suggestions (including rejected ones for display)") |
|
|
|
|
|
|
|
// NEW: Build holdQtyMap with existing holdQty from other pick orders |
|
|
|
val existingHoldQtyMap = mutableMapOf<Long?, BigDecimal?>() |
|
|
|
|
|
|
|
// Get all lots that are being used by other pick orders (including those NOT being resuggested) |
|
|
|
val allOtherPickOrderLineIds = allCompetingPickOrders |
|
|
|
.flatMap { it.pickOrderLines } |
|
|
|
.mapNotNull { it.id } |
|
|
|
|
|
|
|
println("Other pick order line IDs: $allOtherPickOrderLineIds") |
|
|
|
|
|
|
|
if (allOtherPickOrderLineIds.isNotEmpty()) { |
|
|
|
val otherSuggestions = suggestedPickLotRepository.findAllByPickOrderLineIdIn(allOtherPickOrderLineIds) |
|
|
|
println("Found ${otherSuggestions.size} other suggestions") |
|
|
|
|
|
|
|
if (allOtherPickOrderLineIds.isNotEmpty()) { |
|
|
|
val otherSuggestions = suggestedPickLotRepository.findAllByPickOrderLineIdIn(allOtherPickOrderLineIds) |
|
|
|
println("Found ${otherSuggestions.size} other suggestions") |
|
|
|
otherSuggestions.forEach { suggestion -> |
|
|
|
val lotId = suggestion.suggestedLotLine?.id |
|
|
|
val qty = suggestion.qty |
|
|
|
|
|
|
|
otherSuggestions.forEach { suggestion -> |
|
|
|
val lotId = suggestion.suggestedLotLine?.id |
|
|
|
val qty = suggestion.qty |
|
|
|
println("Processing other suggestion ${suggestion.id}: lotId=$lotId, qty=$qty") |
|
|
|
|
|
|
|
if (lotId != null && qty != null) { |
|
|
|
val currentHoldQty = existingHoldQtyMap[lotId] ?: BigDecimal.ZERO |
|
|
|
val newHoldQty = currentHoldQty.plus(qty) |
|
|
|
existingHoldQtyMap[lotId] = newHoldQty |
|
|
|
println(" Updated holdQty for lot $lotId: $currentHoldQty + $qty = $newHoldQty") |
|
|
|
} |
|
|
|
if (lotId != null && qty != null) { |
|
|
|
val currentHoldQty = existingHoldQtyMap[lotId] ?: BigDecimal.ZERO |
|
|
|
val newHoldQty = currentHoldQty.plus(qty) |
|
|
|
existingHoldQtyMap[lotId] = newHoldQty |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
println("Final existing holdQtyMap: $existingHoldQtyMap") |
|
|
|
|
|
|
|
// FIX: Create new suggestions for all pick orders to resuggest |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToResuggest -> |
|
|
|
// 只获取有 rejected stock out lines 的 pick order lines |
|
|
|
// OPTIMIZATION 3: 使用预加载的 Map |
|
|
|
val problematicPickOrderLines = pickOrderToResuggest.pickOrderLines.filter { pol -> |
|
|
|
val stockOutLines = stockOutLinesByPickOrderLineId[pol.id] ?: emptyList() |
|
|
|
stockOutLines.any { it.status?.equals("rejected", ignoreCase = true) == true } |
|
|
|
} |
|
|
|
|
|
|
|
println("Final existing holdQtyMap: $existingHoldQtyMap") |
|
|
|
|
|
|
|
// FIX: Create new suggestions for all pick orders to resuggest |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToResuggest -> |
|
|
|
// 只获取有 rejected stock out lines 的 pick order lines |
|
|
|
val problematicPickOrderLines = pickOrderToResuggest.pickOrderLines.filter { pol -> |
|
|
|
val stockOutLines = stockOutLIneRepository.findAllByPickOrderLineIdAndDeletedFalse(pol.id!!) |
|
|
|
stockOutLines.any { it.status == "rejected" } |
|
|
|
} |
|
|
|
if (problematicPickOrderLines.isNotEmpty()) { |
|
|
|
println("=== Creating new suggestions for pick order: ${pickOrderToResuggest.code} ===") |
|
|
|
|
|
|
|
if (problematicPickOrderLines.isNotEmpty()) { |
|
|
|
println("=== Creating new suggestions for pick order: ${pickOrderToResuggest.code} ===") |
|
|
|
|
|
|
|
// 调用 suggestionForPickOrderLines 生成新的 suggestions |
|
|
|
val request = SuggestedPickLotForPolRequest( |
|
|
|
pickOrderLines = problematicPickOrderLines, |
|
|
|
holdQtyMap = existingHoldQtyMap.toMutableMap() |
|
|
|
) |
|
|
|
val response = suggestionForPickOrderLines(request) |
|
|
|
|
|
|
|
println("Generated ${response.suggestedList.size} new suggestions") |
|
|
|
response.suggestedList.forEach { suggestion -> |
|
|
|
println(" - Suggestion: lotId=${suggestion.suggestedLotLine?.id}, qty=${suggestion.qty}") |
|
|
|
} |
|
|
|
// 调用 suggestionForPickOrderLines 生成新的 suggestions |
|
|
|
val request = SuggestedPickLotForPolRequest( |
|
|
|
pickOrderLines = problematicPickOrderLines, |
|
|
|
holdQtyMap = existingHoldQtyMap.toMutableMap() |
|
|
|
) |
|
|
|
val response = suggestionForPickOrderLines(request) |
|
|
|
|
|
|
|
println("Generated ${response.suggestedList.size} new suggestions") |
|
|
|
|
|
|
|
if (response.suggestedList.isNotEmpty()) { |
|
|
|
println("Saving ${response.suggestedList.size} new suggestions") |
|
|
|
|
|
|
|
if (response.suggestedList.isNotEmpty()) { |
|
|
|
println("Saving ${response.suggestedList.size} new suggestions") |
|
|
|
|
|
|
|
// 获取现有的 pending/checked 状态的 suggestions(可以更新的) |
|
|
|
// 获取现有的 pending/checked 状态的 suggestions(可以更新的) |
|
|
|
val existingUpdatableSuggestions = suggestionsToKeep |
|
|
|
.filter { it.suggestedLotLine?.id != null } |
|
|
|
.groupBy { it.pickOrderLine?.id to it.suggestedLotLine?.id } |
|
|
|
.mapValues { it.value.first() } // 每个 (lineId, lotId) 只取第一个 |
|
|
|
.filter { it.suggestedLotLine?.id != null } |
|
|
|
.groupBy { it.pickOrderLine?.id to it.suggestedLotLine?.id } |
|
|
|
.mapValues { it.value.first() } // 每个 (lineId, lotId) 只取第一个 |
|
|
|
|
|
|
|
// 处理新的 suggestions:更新现有的或创建新的 |
|
|
|
val suggestionsToSave = response.suggestedList.mapNotNull { newSugg -> |
|
|
|
val key = newSugg.pickOrderLine?.id to newSugg.suggestedLotLine?.id |
|
|
|
val lineId = newSugg.pickOrderLine?.id |
|
|
|
val lotId = newSugg.suggestedLotLine?.id |
|
|
|
val key = newSugg.pickOrderLine?.id to newSugg.suggestedLotLine?.id |
|
|
|
val lineId = newSugg.pickOrderLine?.id |
|
|
|
val lotId = newSugg.suggestedLotLine?.id |
|
|
|
|
|
|
|
if (lineId != null && lotId != null) { |
|
|
|
// 检查这个 lot 是否已有 suggestion |
|
|
|
val existingSugg = existingUpdatableSuggestions[key] |
|
|
|
|
|
|
|
if (existingSugg != null) { |
|
|
|
// 检查现有 suggestion 的 stock_out_line 状态 |
|
|
|
val stockOutLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( |
|
|
|
lineId, lotId |
|
|
|
) |
|
|
|
if (lineId != null && lotId != null) { |
|
|
|
// 检查这个 lot 是否已有 suggestion |
|
|
|
val existingSugg = existingUpdatableSuggestions[key] |
|
|
|
|
|
|
|
val canUpdate = stockOutLines.isEmpty() || stockOutLines.all { |
|
|
|
it.status == "pending" || it.status == "checked" || it.status == "partially_completed" |
|
|
|
if (existingSugg != null) { |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取 |
|
|
|
val stockOutLines = stockOutLinesByLineAndLot[lineId to lotId] ?: emptyList() |
|
|
|
|
|
|
|
val canUpdate = stockOutLines.isEmpty() || stockOutLines.all { |
|
|
|
val status = it.status?.lowercase() |
|
|
|
status == "pending" || status == "checked" || status == "partially_completed" |
|
|
|
} |
|
|
|
|
|
|
|
if (canUpdate) { |
|
|
|
// Case 1: 更新现有的 suggestion |
|
|
|
existingSugg.qty = newSugg.qty |
|
|
|
existingSugg.modified = LocalDateTime.now() |
|
|
|
existingSugg.modifiedBy = "system" |
|
|
|
println("⚠️ Updated existing suggestion ${existingSugg.id} for lot $lotId: new qty=${newSugg.qty}") |
|
|
|
existingSugg |
|
|
|
} else { |
|
|
|
// Case 2: 已完成/拒绝,跳过(不更新,也不创建新的) |
|
|
|
val firstStatus = stockOutLines.firstOrNull()?.status ?: "unknown" |
|
|
|
println("⏭️ Skipping lot $lotId - already $firstStatus") |
|
|
|
null |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 没有现有的 suggestion,创建新的 |
|
|
|
newSugg |
|
|
|
} |
|
|
|
} else if (lotId == null) { |
|
|
|
// lotId=null:检查是否已有 resuggest_issue |
|
|
|
val existingResuggestIssues = pickExecutionIssueRepository |
|
|
|
.findByPickOrderLineIdAndDeletedFalse(lineId ?: 0L) |
|
|
|
.filter { it.issueCategory.name == "resuggest_issue" } |
|
|
|
|
|
|
|
if (canUpdate) { |
|
|
|
// Case 1: 更新现有的 suggestion |
|
|
|
existingSugg.qty = newSugg.qty |
|
|
|
existingSugg.modified = LocalDateTime.now() |
|
|
|
existingSugg.modifiedBy = "system" |
|
|
|
println("⚠️ Updated existing suggestion ${existingSugg.id} for lot $lotId: new qty=${newSugg.qty}") |
|
|
|
existingSugg |
|
|
|
if (existingResuggestIssues.isEmpty()) { |
|
|
|
newSugg // 创建新的 null suggestion(后续会创建 issue) |
|
|
|
} else { |
|
|
|
// Case 2: 已完成/拒绝,跳过(不更新,也不创建新的) |
|
|
|
println("⏭️ Skipping lot $lotId - already ${stockOutLines.first().status}") |
|
|
|
null |
|
|
|
println("⏭️ Resuggest issue already exists for line $lineId, skipping null suggestion") |
|
|
|
null // 跳过,避免创建重复的 resuggest_issue |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 没有现有的 suggestion,创建新的 |
|
|
|
newSugg |
|
|
|
} |
|
|
|
} else if (lotId == null) { |
|
|
|
// lotId=null:检查是否已有 resuggest_issue |
|
|
|
val existingResuggestIssues = pickExecutionIssueRepository |
|
|
|
.findByPickOrderLineIdAndDeletedFalse(lineId ?: 0L) |
|
|
|
.filter { it.issueCategory.name == "resuggest_issue" } |
|
|
|
|
|
|
|
if (existingResuggestIssues.isEmpty()) { |
|
|
|
newSugg // 创建新的 null suggestion(后续会创建 issue) |
|
|
|
} else { |
|
|
|
println("⏭️ Resuggest issue already exists for line $lineId, skipping null suggestion") |
|
|
|
null // 跳过,避免创建重复的 resuggest_issue |
|
|
|
} |
|
|
|
} else { |
|
|
|
newSugg |
|
|
|
} |
|
|
|
}.filterNotNull() |
|
|
|
|
|
|
|
val updatedSuggestions = suggestionsToSave.filter { it.id != null } // 有 id 的是更新的 |
|
|
|
@@ -789,175 +841,169 @@ println("Keeping all suggestions (including rejected ones for display)") |
|
|
|
|
|
|
|
val savedSuggestions = allSavedSuggestions |
|
|
|
println("Saved/Updated ${savedSuggestions.size} suggestions") |
|
|
|
|
|
|
|
// 为每个新 suggestion 创建 stock out line 或 issue |
|
|
|
savedSuggestions.forEach { suggestion -> |
|
|
|
if (suggestion.suggestedLotLine != null) { |
|
|
|
val isNewSuggestion = response.suggestedList.any { |
|
|
|
it.pickOrderLine?.id == suggestion.pickOrderLine?.id && |
|
|
|
it.suggestedLotLine?.id == suggestion.suggestedLotLine?.id && |
|
|
|
it.id == null // 新的 suggestion 还没有 id |
|
|
|
} |
|
|
|
val stockOutLine = createStockOutLineForSuggestion(suggestion, pickOrderToResuggest) |
|
|
|
if (stockOutLine != null) { |
|
|
|
println(" Created stock out line ${stockOutLine.id} for suggestion ${suggestion.id}") |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 如果 lot 是 null,表示没有可用的 lot,创建 resuggest_issue |
|
|
|
println("❌ No available lot for pick order line ${suggestion.pickOrderLine?.id}, creating resuggest_issue") |
|
|
|
|
|
|
|
val pickOrderLine = suggestion.pickOrderLine |
|
|
|
if (pickOrderLine != null) { |
|
|
|
// 获取这个 line 的 rejected stock out lines |
|
|
|
val rejectedStockOutLines = stockOutLIneRepository |
|
|
|
.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLine.id!!) |
|
|
|
.filter { it.status == "rejected" } |
|
|
|
println("Rejected stock out lines: ${rejectedStockOutLines.size}") |
|
|
|
// 修复:只创建一个 resuggest_issue(如果有 rejected lines) |
|
|
|
if (rejectedStockOutLines.isNotEmpty()) { |
|
|
|
println("Creating resuggest failure issue") |
|
|
|
createResuggestFailureIssue( |
|
|
|
pickOrder = pickOrderToResuggest, |
|
|
|
pickOrderLine = pickOrderLine, |
|
|
|
rejectedStockOutLine = rejectedStockOutLines.first() |
|
|
|
) |
|
|
|
} |
|
|
|
println("Creating stock out line for suggestion") |
|
|
|
//createStockOutLineForSuggestion(suggestion, pickOrderToResuggest) |
|
|
|
println("Stock out line created") |
|
|
|
} |
|
|
|
|
|
|
|
// 为每个新 suggestion 创建 stock out line 或 issue |
|
|
|
savedSuggestions.forEach { suggestion -> |
|
|
|
if (suggestion.suggestedLotLine != null) { |
|
|
|
val isNewSuggestion = response.suggestedList.any { |
|
|
|
it.pickOrderLine?.id == suggestion.pickOrderLine?.id && |
|
|
|
it.suggestedLotLine?.id == suggestion.suggestedLotLine?.id && |
|
|
|
it.id == null // 新的 suggestion 还没有 id |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新 holdQty |
|
|
|
response.holdQtyMap.forEach { (lotId, newHoldQty) -> |
|
|
|
if (lotId != null && newHoldQty != null && newHoldQty > BigDecimal.ZERO) { |
|
|
|
val lot = inventoryLotLineRepository.findById(lotId).orElse(null) |
|
|
|
lot?.let { |
|
|
|
val currentHoldQty = it.holdQty ?: BigDecimal.ZERO |
|
|
|
val existingHoldQty = existingHoldQtyMap[lotId] ?: BigDecimal.ZERO |
|
|
|
val additionalHoldQty = newHoldQty.minus(existingHoldQty) |
|
|
|
val finalHoldQty = currentHoldQty.plus(additionalHoldQty) |
|
|
|
it.holdQty = finalHoldQty |
|
|
|
inventoryLotLineRepository.save(it) |
|
|
|
existingHoldQtyMap[lotId] = newHoldQty |
|
|
|
println("Updated holdQty for lot $lotId: $currentHoldQty + $additionalHoldQty = $finalHoldQty") |
|
|
|
} |
|
|
|
val stockOutLine = createStockOutLineForSuggestion(suggestion, pickOrderToResuggest) |
|
|
|
if (stockOutLine != null) { |
|
|
|
println(" Created stock out line ${stockOutLine.id} for suggestion ${suggestion.id}") |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 如果完全没有生成任何 suggestions |
|
|
|
println("No suggestions generated at all for pick order: ${pickOrderToResuggest.code}") |
|
|
|
|
|
|
|
problematicPickOrderLines.forEach { pickOrderLine -> |
|
|
|
val rejectedStockOutLines = stockOutLIneRepository |
|
|
|
.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLine.id!!) |
|
|
|
.filter { it.status == "rejected" } |
|
|
|
} else { |
|
|
|
// 如果 lot 是 null,表示没有可用的 lot,创建 resuggest_issue |
|
|
|
println("❌ No available lot for pick order line ${suggestion.pickOrderLine?.id}, creating resuggest_issue") |
|
|
|
|
|
|
|
if (rejectedStockOutLines.isNotEmpty()) { |
|
|
|
rejectedStockOutLines.forEach { rejectedLine -> |
|
|
|
val pickOrderLine = suggestion.pickOrderLine |
|
|
|
if (pickOrderLine != null) { |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取 |
|
|
|
val rejectedStockOutLines = stockOutLinesByPickOrderLineId[pickOrderLine.id] |
|
|
|
?.filter { it.status?.equals("rejected", ignoreCase = true) == true } ?: emptyList() |
|
|
|
println("Rejected stock out lines: ${rejectedStockOutLines.size}") |
|
|
|
// 修复:只创建一个 resuggest_issue(如果有 rejected lines) |
|
|
|
if (rejectedStockOutLines.isNotEmpty()) { |
|
|
|
println("Creating resuggest failure issue") |
|
|
|
// 注意:rejectedStockOutLines 是 List<StockOutLine>,需要转换为合适的类型 |
|
|
|
val firstRejectedLine = rejectedStockOutLines.first() |
|
|
|
createResuggestFailureIssue( |
|
|
|
pickOrder = pickOrderToResuggest, |
|
|
|
pickOrderLine = pickOrderLine, |
|
|
|
rejectedStockOutLine = rejectedLine |
|
|
|
rejectedStockOutLine = firstRejectedLine |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新 holdQty |
|
|
|
response.holdQtyMap.forEach { (lotId, newHoldQty) -> |
|
|
|
if (lotId != null && newHoldQty != null && newHoldQty > BigDecimal.ZERO) { |
|
|
|
val lot = inventoryLotLineRepository.findById(lotId).orElse(null) |
|
|
|
lot?.let { |
|
|
|
val currentHoldQty = it.holdQty ?: BigDecimal.ZERO |
|
|
|
val existingHoldQty = existingHoldQtyMap[lotId] ?: BigDecimal.ZERO |
|
|
|
val additionalHoldQty = newHoldQty.minus(existingHoldQty) |
|
|
|
val finalHoldQty = currentHoldQty.plus(additionalHoldQty) |
|
|
|
it.holdQty = finalHoldQty |
|
|
|
inventoryLotLineRepository.save(it) |
|
|
|
existingHoldQtyMap[lotId] = newHoldQty |
|
|
|
println("Updated holdQty for lot $lotId: $currentHoldQty + $additionalHoldQty = $finalHoldQty") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 如果完全没有生成任何 suggestions |
|
|
|
println("No suggestions generated at all for pick order: ${pickOrderToResuggest.code}") |
|
|
|
|
|
|
|
problematicPickOrderLines.forEach { pickOrderLine -> |
|
|
|
// OPTIMIZATION 3: 从预加载的 Map 中获取 |
|
|
|
val rejectedStockOutLines = stockOutLinesByPickOrderLineId[pickOrderLine.id] |
|
|
|
?.filter { it.status?.equals("rejected", ignoreCase = true) == true } ?: emptyList() |
|
|
|
|
|
|
|
if (rejectedStockOutLines.isNotEmpty()) { |
|
|
|
rejectedStockOutLines.forEach { rejectedLine -> |
|
|
|
createResuggestFailureIssue( |
|
|
|
pickOrder = pickOrderToResuggest, |
|
|
|
pickOrderLine = pickOrderLine, |
|
|
|
rejectedStockOutLine = rejectedLine |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// FIX: Update inventory table for each pick order |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToUpdate -> |
|
|
|
println("=== Updating inventory table for pick order: ${pickOrderToUpdate.code} ===") |
|
|
|
updateInventoryTableAfterResuggest(pickOrderToUpdate) |
|
|
|
} |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG END ===") |
|
|
|
|
|
|
|
return MessageResponse( |
|
|
|
id = pickOrderId, |
|
|
|
name = "Pick order resuggested successfully", |
|
|
|
code = "SUCCESS", |
|
|
|
type = "resuggest", |
|
|
|
message = "Resuggested ${allPickOrdersToResuggest.size} pick orders", |
|
|
|
errorPosition = null |
|
|
|
) |
|
|
|
} catch (e: Exception) { |
|
|
|
println("Error in resuggestPickOrder: ${e.message}") |
|
|
|
e.printStackTrace() |
|
|
|
return MessageResponse( |
|
|
|
id = null, |
|
|
|
name = "Failed to resuggest pick order", |
|
|
|
code = "ERROR", |
|
|
|
type = "resuggest", |
|
|
|
message = "Error: ${e.message}", |
|
|
|
errorPosition = null |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// FIX: Update inventory table for each pick order |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToUpdate -> |
|
|
|
println("=== Updating inventory table for pick order: ${pickOrderToUpdate.code} ===") |
|
|
|
updateInventoryTableAfterResuggest(pickOrderToUpdate) |
|
|
|
} |
|
|
|
|
|
|
|
println("=== RESUGGEST DEBUG END ===") |
|
|
|
|
|
|
|
return MessageResponse( |
|
|
|
id = pickOrderId, |
|
|
|
name = "Pick order resuggested successfully", |
|
|
|
code = "SUCCESS", |
|
|
|
type = "resuggest", |
|
|
|
message = "Resuggested ${allPickOrdersToResuggest.size} pick orders", |
|
|
|
errorPosition = null |
|
|
|
) |
|
|
|
} catch (e: Exception) { |
|
|
|
println("Error in resuggestPickOrder: ${e.message}") |
|
|
|
e.printStackTrace() |
|
|
|
return MessageResponse( |
|
|
|
id = null, |
|
|
|
name = "Failed to resuggest pick order", |
|
|
|
code = "ERROR", |
|
|
|
type = "resuggest", |
|
|
|
message = "Error: ${e.message}", |
|
|
|
errorPosition = null |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun createResuggestFailureIssue( |
|
|
|
pickOrder: PickOrder, |
|
|
|
pickOrderLine: PickOrderLine, |
|
|
|
rejectedStockOutLine: StockOutLineInfo // 使用 StockOutLineInfo |
|
|
|
) { |
|
|
|
try { |
|
|
|
val item = pickOrderLine.item |
|
|
|
|
|
|
|
// 从 StockOutLineInfo 获取 inventoryLotLineId |
|
|
|
val inventoryLotLineId = rejectedStockOutLine.inventoryLotLineId |
|
|
|
val inventoryLotLine = if (inventoryLotLineId != null) { |
|
|
|
inventoryLotLineRepository.findById(inventoryLotLineId).orElse(null) |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
|
|
|
|
val issue = PickExecutionIssue( |
|
|
|
id = null, |
|
|
|
pickOrderId = pickOrder.id!!, |
|
|
|
pickOrderCode = pickOrder.code!!, |
|
|
|
pickOrderCreateDate = pickOrder.created?.toLocalDate(), |
|
|
|
pickExecutionDate = LocalDate.now(), |
|
|
|
pickOrderLineId = pickOrderLine.id!!, |
|
|
|
issueNo = generateIssueNo(), |
|
|
|
joPickOrderId=pickOrder.jobOrder?.id, |
|
|
|
doPickOrderId=pickOrder.deliveryOrder?.id, |
|
|
|
issueCategory = IssueCategory.resuggest_issue, |
|
|
|
itemId = item?.id!!, |
|
|
|
itemCode = item.code, |
|
|
|
itemDescription = item.name, |
|
|
|
lotId = inventoryLotLine?.id, |
|
|
|
lotNo = inventoryLotLine?.inventoryLot?.lotNo, |
|
|
|
storeLocation = inventoryLotLine?.warehouse?.code, |
|
|
|
requiredQty = pickOrderLine.qty, |
|
|
|
actualPickQty = rejectedStockOutLine.qty ?: BigDecimal.ZERO, // 直接使用,不需要 toBigDecimal() |
|
|
|
missQty = (pickOrderLine.qty ?: BigDecimal.ZERO).minus(rejectedStockOutLine.qty ?: BigDecimal.ZERO), // 直接使用 |
|
|
|
badItemQty = BigDecimal.ZERO, |
|
|
|
issueRemark = "Resuggest failed: No alternative lots available for rejected lot ${inventoryLotLine?.inventoryLot?.lotNo}", |
|
|
|
pickerName = null, |
|
|
|
handleStatus = HandleStatus.pending, |
|
|
|
handleDate = null, |
|
|
|
handledBy = null, |
|
|
|
created = LocalDateTime.now(), |
|
|
|
createdBy = "system", |
|
|
|
version = 0, |
|
|
|
modified = LocalDateTime.now(), |
|
|
|
modifiedBy = "system", |
|
|
|
deleted = false |
|
|
|
) |
|
|
|
|
|
|
|
pickExecutionIssueRepository.save(issue) |
|
|
|
println(" Created resuggest_issue: ${issue.issueNo} for pick order ${pickOrder.code}") |
|
|
|
|
|
|
|
} catch (e: Exception) { |
|
|
|
println("❌ Error creating resuggest_issue: ${e.message}") |
|
|
|
e.printStackTrace() |
|
|
|
} |
|
|
|
private fun createResuggestFailureIssue( |
|
|
|
pickOrder: PickOrder, |
|
|
|
pickOrderLine: PickOrderLine, |
|
|
|
rejectedStockOutLine: StockOutLine // 改为 StockOutLine |
|
|
|
) { |
|
|
|
try { |
|
|
|
val item = pickOrderLine.item |
|
|
|
|
|
|
|
// 从 StockOutLine 获取 inventoryLotLineId |
|
|
|
val inventoryLotLine = rejectedStockOutLine.inventoryLotLine |
|
|
|
val inventoryLotLineId = inventoryLotLine?.id |
|
|
|
|
|
|
|
val issue = PickExecutionIssue( |
|
|
|
id = null, |
|
|
|
pickOrderId = pickOrder.id!!, |
|
|
|
pickOrderCode = pickOrder.code!!, |
|
|
|
pickOrderCreateDate = pickOrder.created?.toLocalDate(), |
|
|
|
pickExecutionDate = LocalDate.now(), |
|
|
|
pickOrderLineId = pickOrderLine.id!!, |
|
|
|
issueNo = generateIssueNo(), |
|
|
|
joPickOrderId = pickOrder.jobOrder?.id, |
|
|
|
doPickOrderId = pickOrder.deliveryOrder?.id, |
|
|
|
issueCategory = IssueCategory.resuggest_issue, |
|
|
|
itemId = item?.id!!, |
|
|
|
itemCode = item.code, |
|
|
|
itemDescription = item.name, |
|
|
|
lotId = inventoryLotLineId, |
|
|
|
lotNo = inventoryLotLine?.inventoryLot?.lotNo, |
|
|
|
storeLocation = inventoryLotLine?.warehouse?.code, |
|
|
|
requiredQty = pickOrderLine.qty, |
|
|
|
actualPickQty = rejectedStockOutLine.qty?.let { BigDecimal.valueOf(it) } ?: BigDecimal.ZERO, |
|
|
|
missQty = (pickOrderLine.qty ?: BigDecimal.ZERO).minus( |
|
|
|
rejectedStockOutLine.qty?.let { BigDecimal.valueOf(it) } ?: BigDecimal.ZERO |
|
|
|
), |
|
|
|
badItemQty = BigDecimal.ZERO, |
|
|
|
issueRemark = "Resuggest failed: No alternative lots available for rejected lot ${inventoryLotLine?.inventoryLot?.lotNo}", |
|
|
|
pickerName = null, |
|
|
|
handleStatus = HandleStatus.pending, |
|
|
|
handleDate = null, |
|
|
|
handledBy = null, |
|
|
|
created = LocalDateTime.now(), |
|
|
|
createdBy = "system", |
|
|
|
version = 0, |
|
|
|
modified = LocalDateTime.now(), |
|
|
|
modifiedBy = "system", |
|
|
|
deleted = false |
|
|
|
) |
|
|
|
|
|
|
|
val savedIssue = pickExecutionIssueRepository.save(issue) |
|
|
|
println(" Created resuggest_issue: ${savedIssue.issueNo} for pick order ${pickOrder.code}") |
|
|
|
|
|
|
|
} catch (e: Exception) { |
|
|
|
println("❌ Error creating resuggest_issue: ${e.message}") |
|
|
|
e.printStackTrace() |
|
|
|
} |
|
|
|
} |
|
|
|
private fun generateIssueNo(): String { |
|
|
|
val now = LocalDateTime.now() |
|
|
|
val yearMonth = now.format(DateTimeFormatter.ofPattern("yyMM")) |
|
|
|
|