|
|
|
@@ -2,8 +2,13 @@ package com.ffii.fpsms.modules.stock.service |
|
|
|
|
|
|
|
import com.ffii.fpsms.modules.master.service.ItemUomService |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickOrder |
|
|
|
|
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickExecutionIssue // ✅ 添加 |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.IssueCategory |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.HandleStatus // ✅ 添加 |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickExecutionIssueRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.* |
|
|
|
import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus |
|
|
|
import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo |
|
|
|
@@ -15,6 +20,8 @@ import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotResponse |
|
|
|
import org.springframework.stereotype.Service |
|
|
|
import java.math.BigDecimal |
|
|
|
import java.time.LocalDate |
|
|
|
import java.time.LocalDateTime // ✅ 添加 |
|
|
|
import java.time.format.DateTimeFormatter // ✅ 添加 |
|
|
|
import kotlin.jvm.optionals.getOrDefault |
|
|
|
import kotlin.jvm.optionals.getOrNull |
|
|
|
import org.springframework.transaction.annotation.Transactional |
|
|
|
@@ -29,6 +36,7 @@ import com.ffii.fpsms.modules.stock.entity.FailInventoryLotLineRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutRepository |
|
|
|
import com.ffii.fpsms.modules.master.entity.ItemsRepository |
|
|
|
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus |
|
|
|
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo // ✅ 添加这行 |
|
|
|
@Service |
|
|
|
open class SuggestedPickLotService( |
|
|
|
val suggestedPickLotRepository: SuggestPickLotRepository, |
|
|
|
@@ -37,6 +45,7 @@ open class SuggestedPickLotService( |
|
|
|
val pickOrderLineRepository: PickOrderLineRepository, |
|
|
|
val inventoryLotLineService: InventoryLotLineService, |
|
|
|
val itemUomService: ItemUomService, |
|
|
|
val pickExecutionIssueRepository: PickExecutionIssueRepository, // ✅ 添加逗号 |
|
|
|
val pickOrderRepository: PickOrderRepository, |
|
|
|
val inventoryRepository: InventoryRepository, |
|
|
|
val failInventoryLotLineRepository: FailInventoryLotLineRepository, |
|
|
|
@@ -363,38 +372,49 @@ open class SuggestedPickLotService( |
|
|
|
val allSuggestions = suggestedPickLotRepository.findAllByPickOrderLineIdIn(allPickOrderLineIds) |
|
|
|
println("Found ${allSuggestions.size} existing suggestions") |
|
|
|
|
|
|
|
// ✅ FIX: Separate suggestions to keep (those with rejected stock out lines) and delete |
|
|
|
val suggestionsToKeep = allSuggestions.filter { suggestion -> |
|
|
|
val pickOrderLineId = suggestion.pickOrderLine?.id |
|
|
|
val suggestedLotLineId = suggestion.suggestedLotLine?.id |
|
|
|
|
|
|
|
println("Checking suggestion ${suggestion.id}: pickOrderLineId=$pickOrderLineId, suggestedLotLineId=$suggestedLotLineId") |
|
|
|
|
|
|
|
if (pickOrderLineId != null && suggestedLotLineId != null) { |
|
|
|
val stockOutLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( |
|
|
|
pickOrderLineId, |
|
|
|
suggestedLotLineId |
|
|
|
) |
|
|
|
val hasRejectedStockOutLine = stockOutLines.any { it.status == "rejected" } |
|
|
|
println(" Stock out lines: ${stockOutLines.map { "${it.id}(status=${it.status}, qty=${it.qty})" }}") |
|
|
|
println(" Has rejected stock out line: $hasRejectedStockOutLine") |
|
|
|
hasRejectedStockOutLine |
|
|
|
} else { |
|
|
|
println(" Missing pickOrderLineId or suggestedLotLineId") |
|
|
|
false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val suggestionsToDelete = allSuggestions.filter { suggestion -> |
|
|
|
!suggestionsToKeep.contains(suggestion) |
|
|
|
} |
|
|
|
// ✅ 删除第 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 { |
|
|
|
false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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 = suggestionsToKeep.mapNotNull { it.suggestedLotLine?.id }.distinct() |
|
|
|
println("Rejected lot IDs: $rejectedLotIds") |
|
|
|
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) |
|
|
|
@@ -407,29 +427,13 @@ open class SuggestedPickLotService( |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ NEW: Reduce holdQty for lots that are no longer suggested |
|
|
|
val deletedSuggestions = suggestionsToDelete |
|
|
|
val deletedLotIds = deletedSuggestions.mapNotNull { it.suggestedLotLine?.id }.distinct() |
|
|
|
println("Deleted lot IDs: $deletedLotIds") |
|
|
|
|
|
|
|
deletedLotIds.forEach { lotId -> |
|
|
|
val lot = inventoryLotLineRepository.findById(lotId).orElse(null) |
|
|
|
lot?.let { |
|
|
|
val originalHoldQty = it.holdQty ?: BigDecimal.ZERO |
|
|
|
val deletedQty = deletedSuggestions |
|
|
|
.filter { it.suggestedLotLine?.id == lotId } |
|
|
|
.sumOf { it.qty ?: BigDecimal.ZERO } |
|
|
|
|
|
|
|
val newHoldQty = originalHoldQty.minus(deletedQty) |
|
|
|
it.holdQty = if (newHoldQty < BigDecimal.ZERO) BigDecimal.ZERO else newHoldQty |
|
|
|
inventoryLotLineRepository.save(it) |
|
|
|
println("Reduced holdQty for deleted lot ${lot.id}: $originalHoldQty - $deletedQty = ${it.holdQty}") |
|
|
|
} |
|
|
|
} |
|
|
|
// ✅ FIX: Delete only the suggestions that should be deleted |
|
|
|
if (suggestionsToDelete.isNotEmpty()) { |
|
|
|
suggestedPickLotRepository.deleteAll(suggestionsToDelete) |
|
|
|
println("Deleted ${suggestionsToDelete.size} suggestions") |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ 不删除任何 suggestions - 保留 rejected suggestions 用于显示 |
|
|
|
// if (suggestionsToDelete.isNotEmpty()) { |
|
|
|
// suggestedPickLotRepository.deleteAll(suggestionsToDelete) |
|
|
|
// println("Deleted ${suggestionsToDelete.size} 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?>() |
|
|
|
@@ -462,61 +466,102 @@ open class SuggestedPickLotService( |
|
|
|
println("Final existing holdQtyMap: $existingHoldQtyMap") |
|
|
|
|
|
|
|
// ✅ FIX: Create new suggestions for all pick orders to resuggest |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToResuggest -> |
|
|
|
println("=== Creating new suggestions for pick order: ${pickOrderToResuggest.code} ===") |
|
|
|
|
|
|
|
val request = SuggestedPickLotForPolRequest( |
|
|
|
pickOrderLines = pickOrderToResuggest.pickOrderLines, |
|
|
|
holdQtyMap = existingHoldQtyMap.toMutableMap() // ✅ Use existing holdQty |
|
|
|
) |
|
|
|
val response = suggestionForPickOrderLines(request) |
|
|
|
|
|
|
|
println("Generated ${response.suggestedList.size} new suggestions") |
|
|
|
response.suggestedList.forEach { suggestion -> |
|
|
|
println(" - Suggestion: lotId=${suggestion.suggestedLotLine?.id}, qty=${suggestion.qty}") |
|
|
|
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" } |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ FIX: Save the suggestions to the database |
|
|
|
if (response.suggestedList.isNotEmpty()) { |
|
|
|
val savedSuggestions = suggestedPickLotRepository.saveAllAndFlush(response.suggestedList) |
|
|
|
println("Saved ${savedSuggestions.size} new suggestions for pick order: ${pickOrderToResuggest.code}") |
|
|
|
savedSuggestions.forEach { suggestion -> |
|
|
|
if (suggestion.suggestedLotLine != null) { |
|
|
|
val stockOutLine = createStockOutLineForSuggestion(suggestion, pickOrderToResuggest) |
|
|
|
if (stockOutLine != null) { |
|
|
|
println("✅ Created stock out line ${stockOutLine.id} for suggestion ${suggestion.id}") |
|
|
|
|
|
|
|
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}") |
|
|
|
} |
|
|
|
|
|
|
|
if (response.suggestedList.isNotEmpty()) { |
|
|
|
println("Saving ${response.suggestedList.size} new suggestions") |
|
|
|
|
|
|
|
// ✅ 保存所有新生成的 suggestions |
|
|
|
val savedSuggestions = suggestedPickLotRepository.saveAllAndFlush(response.suggestedList) |
|
|
|
println("Saved ${savedSuggestions.size} new suggestions") |
|
|
|
|
|
|
|
// ✅ 为每个新 suggestion 创建 stock out line 或 issue |
|
|
|
savedSuggestions.forEach { suggestion -> |
|
|
|
if (suggestion.suggestedLotLine != null) { |
|
|
|
val stockOutLine = createStockOutLineForSuggestion(suggestion, pickOrderToResuggest) |
|
|
|
if (stockOutLine != null) { |
|
|
|
println("✅ Created stock out line ${stockOutLine.id} for suggestion ${suggestion.id}") |
|
|
|
} |
|
|
|
} else { |
|
|
|
println("❌ Failed to create stock out line for suggestion ${suggestion.id}") |
|
|
|
// ✅ 如果 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" } |
|
|
|
|
|
|
|
rejectedStockOutLines.forEach { rejectedLine -> |
|
|
|
createResuggestFailureIssue( |
|
|
|
pickOrder = pickOrderToResuggest, |
|
|
|
pickOrderLine = pickOrderLine, |
|
|
|
rejectedStockOutLine = rejectedLine |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// ✅ FIX: Update holdQty for the lots that were suggested - CUMULATIVE |
|
|
|
response.holdQtyMap.forEach { (lotId, newHoldQty) -> |
|
|
|
if (lotId != null && newHoldQty != null && newHoldQty > BigDecimal.ZERO) { |
|
|
|
|
|
|
|
// ✅ 更新 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 |
|
|
|
|
|
|
|
// ✅ FIX: Calculate the additional holdQty needed |
|
|
|
val additionalHoldQty = newHoldQty.minus(existingHoldQty) |
|
|
|
val finalHoldQty = currentHoldQty.plus(additionalHoldQty) |
|
|
|
|
|
|
|
it.holdQty = finalHoldQty |
|
|
|
inventoryLotLineRepository.save(it) |
|
|
|
|
|
|
|
// ✅ Update the existingHoldQtyMap for next iteration |
|
|
|
existingHoldQtyMap[lotId] = newHoldQty |
|
|
|
|
|
|
|
println("Updated holdQty for lot $lotId: $currentHoldQty + $additionalHoldQty = $finalHoldQty") |
|
|
|
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 -> |
|
|
|
val rejectedStockOutLines = stockOutLIneRepository |
|
|
|
.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLine.id!!) |
|
|
|
.filter { it.status == "rejected" } |
|
|
|
|
|
|
|
if (rejectedStockOutLines.isNotEmpty()) { |
|
|
|
rejectedStockOutLines.forEach { rejectedLine -> |
|
|
|
createResuggestFailureIssue( |
|
|
|
pickOrder = pickOrderToResuggest, |
|
|
|
pickOrderLine = pickOrderLine, |
|
|
|
rejectedStockOutLine = rejectedLine |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
println("No suggestions generated for pick order: ${pickOrderToResuggest.code}") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ FIX: Update inventory table for each pick order |
|
|
|
allPickOrdersToResuggest.forEach { pickOrderToUpdate -> |
|
|
|
println("=== Updating inventory table for pick order: ${pickOrderToUpdate.code} ===") |
|
|
|
@@ -546,6 +591,88 @@ allPickOrdersToResuggest.forEach { pickOrderToResuggest -> |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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?.name, |
|
|
|
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 generateIssueNo(): String { |
|
|
|
val now = LocalDateTime.now() |
|
|
|
val yearMonth = now.format(DateTimeFormatter.ofPattern("yyMM")) |
|
|
|
|
|
|
|
// 查询当月最新的 issueNo |
|
|
|
val latestIssueNo = pickExecutionIssueRepository.findLatestIssueNoByYearMonth(yearMonth) |
|
|
|
|
|
|
|
// 计算下一个序列号 |
|
|
|
val nextSequence = if (latestIssueNo != null) { |
|
|
|
val parts = latestIssueNo.split("-") |
|
|
|
if (parts.size == 3) { |
|
|
|
val currentSequence = parts[2].toIntOrNull() ?: 0 |
|
|
|
currentSequence + 1 |
|
|
|
} else { |
|
|
|
1 |
|
|
|
} |
|
|
|
} else { |
|
|
|
1 |
|
|
|
} |
|
|
|
|
|
|
|
return "SKO-${yearMonth}-${nextSequence.toString().padStart(3, '0')}" |
|
|
|
} |
|
|
|
private fun findAllSuggestionsForPickOrders(pickOrderIds: List<Long>): List<SuggestedPickLot> { |
|
|
|
val allPickOrderLines = mutableListOf<PickOrderLine>() |
|
|
|
|
|
|
|
|