|
|
|
@@ -87,6 +87,112 @@ class StockTakeRecordService( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 逗號分隔多個關鍵字,任一包含於 [StockTakeRecord.itemCode] 即保留(不分大小寫)。 |
|
|
|
*/ |
|
|
|
private fun filterStockTakeRecordsByItemCode( |
|
|
|
records: List<StockTakeRecord>, |
|
|
|
itemCode: String? |
|
|
|
): List<StockTakeRecord> { |
|
|
|
if (itemCode.isNullOrBlank()) return records |
|
|
|
val parts = itemCode.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (parts.isEmpty()) return records |
|
|
|
return records.filter { rec -> |
|
|
|
val code = rec.itemCode ?: "" |
|
|
|
parts.any { part -> code.contains(part, ignoreCase = true) } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** 無 [stockTakeId] 時對已組裝明細依貨品編號篩選(仍可能較耗資源;建議帶 stockTakeId)。 */ |
|
|
|
private fun filterInventoryLotDetailsByItemCode( |
|
|
|
responses: List<InventoryLotDetailResponse>, |
|
|
|
itemCode: String? |
|
|
|
): List<InventoryLotDetailResponse> { |
|
|
|
if (itemCode.isNullOrBlank()) return responses |
|
|
|
val parts = itemCode.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (parts.isEmpty()) return responses |
|
|
|
return responses.filter { r -> |
|
|
|
val code = r.itemCode ?: "" |
|
|
|
parts.any { part -> code.contains(part, ignoreCase = true) } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterStockTakeRecordsBySectionDescription( |
|
|
|
records: List<StockTakeRecord>, |
|
|
|
sectionDescription: String? |
|
|
|
): List<StockTakeRecord> { |
|
|
|
if (sectionDescription.isNullOrBlank() || sectionDescription == "All") return records |
|
|
|
return records.filter { rec -> |
|
|
|
rec.warehouse?.stockTakeSectionDescription?.equals(sectionDescription, ignoreCase = true) == true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterStockTakeRecordsByStockTakeSections( |
|
|
|
records: List<StockTakeRecord>, |
|
|
|
stockTakeSections: String? |
|
|
|
): List<StockTakeRecord> { |
|
|
|
if (stockTakeSections.isNullOrBlank()) return records |
|
|
|
val sections = stockTakeSections.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (sections.isEmpty()) return records |
|
|
|
return records.filter { rec -> |
|
|
|
val sec = rec.stockTakeSection ?: "" |
|
|
|
sections.any { part -> |
|
|
|
sec.equals(part, ignoreCase = true) || sec.contains(part, ignoreCase = true) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterStockTakeRecordsByItemName( |
|
|
|
records: List<StockTakeRecord>, |
|
|
|
itemName: String? |
|
|
|
): List<StockTakeRecord> { |
|
|
|
if (itemName.isNullOrBlank()) return records |
|
|
|
val parts = itemName.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (parts.isEmpty()) return records |
|
|
|
return records.filter { rec -> |
|
|
|
val name = rec.itemName ?: "" |
|
|
|
parts.any { part -> name.contains(part, ignoreCase = true) } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterInventoryLotDetailsBySectionDescription( |
|
|
|
responses: List<InventoryLotDetailResponse>, |
|
|
|
sectionDescription: String? |
|
|
|
): List<InventoryLotDetailResponse> { |
|
|
|
if (sectionDescription.isNullOrBlank() || sectionDescription == "All") return responses |
|
|
|
return responses.filter { r -> |
|
|
|
r.stockTakeSectionDescription?.equals(sectionDescription, ignoreCase = true) == true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterInventoryLotDetailsByStockTakeSections( |
|
|
|
responses: List<InventoryLotDetailResponse>, |
|
|
|
stockTakeSections: String? |
|
|
|
): List<InventoryLotDetailResponse> { |
|
|
|
if (stockTakeSections.isNullOrBlank()) return responses |
|
|
|
val sections = stockTakeSections.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (sections.isEmpty()) return responses |
|
|
|
return responses.filter { r -> |
|
|
|
val sec = r.stockTakeSection ?: "" |
|
|
|
sections.any { part -> |
|
|
|
sec.equals(part, ignoreCase = true) || sec.contains(part, ignoreCase = true) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun filterInventoryLotDetailsByItemName( |
|
|
|
responses: List<InventoryLotDetailResponse>, |
|
|
|
itemName: String? |
|
|
|
): List<InventoryLotDetailResponse> { |
|
|
|
if (itemName.isNullOrBlank()) return responses |
|
|
|
val parts = itemName.split(",").map { it.trim() }.filter { it.isNotEmpty() } |
|
|
|
if (parts.isEmpty()) return responses |
|
|
|
return responses.filter { r -> |
|
|
|
val name = r.itemName ?: "" |
|
|
|
parts.any { part -> name.contains(part, ignoreCase = true) } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
open fun AllPickedStockTakeList(): List<AllPickedStockTakeListReponse> { |
|
|
|
// 1. 获取所有不同的 stockTakeSection(从 warehouse 表) |
|
|
|
val allWarehouses = warehouseRepository.findAllByDeletedIsFalse() |
|
|
|
@@ -226,15 +332,19 @@ class StockTakeRecordService( |
|
|
|
stockTakeId: Long? = null, |
|
|
|
pageNum: Int = 0, |
|
|
|
pageSize: Int = 100, |
|
|
|
approvalView: String? = null |
|
|
|
approvalView: String? = null, |
|
|
|
itemCode: String? = null, |
|
|
|
itemName: String? = null, |
|
|
|
sectionDescription: String? = null, |
|
|
|
stockTakeSections: String? = null |
|
|
|
): RecordsRes<InventoryLotDetailResponse> { |
|
|
|
|
|
|
|
println("getApproverInventoryLotDetailsAll called with stockTakeId: $stockTakeId, pageNum: $pageNum, pageSize: $pageSize") |
|
|
|
println("getApproverInventoryLotDetailsAll called with stockTakeId: $stockTakeId, pageNum: $pageNum, pageSize: $pageSize, itemCode: $itemCode, itemName: $itemName, sectionDescription: $sectionDescription, stockTakeSections: $stockTakeSections") |
|
|
|
|
|
|
|
// 3. 如果传了 stockTakeId,就把「同一轮」的所有 stockTake 找出来(stockTakeRoundId,舊資料則 planStart) |
|
|
|
// stockTakeId != null 时,优先用 stocktakerecord.stockTakeRoundId 取整轮记录(更快) |
|
|
|
// 如果该轮因为旧数据尚未写入 roundId 导致取不到,再 fallback 到旧逻辑(根据 stock_take 的 planStart / stockTakeRoundId 求 stockTakeId 列表) |
|
|
|
val (roundStockTakeIds, roundStockTakeRecords) = if (stockTakeId != null) { |
|
|
|
val (roundStockTakeIds, roundStockTakeRecordsRaw) = if (stockTakeId != null) { |
|
|
|
val baseStockTake = stockTakeRepository.findByIdAndDeletedIsFalse(stockTakeId) |
|
|
|
?: throw IllegalArgumentException("Stock take not found: $stockTakeId") |
|
|
|
|
|
|
|
@@ -252,6 +362,14 @@ class StockTakeRecordService( |
|
|
|
} else { |
|
|
|
emptySet<Long>() to emptyList() |
|
|
|
} |
|
|
|
var roundStockTakeRecords = roundStockTakeRecordsRaw |
|
|
|
roundStockTakeRecords = filterStockTakeRecordsBySectionDescription(roundStockTakeRecords, sectionDescription) |
|
|
|
roundStockTakeRecords = filterStockTakeRecordsByStockTakeSections(roundStockTakeRecords, stockTakeSections) |
|
|
|
roundStockTakeRecords = filterStockTakeRecordsByItemCode(roundStockTakeRecords, itemCode) |
|
|
|
roundStockTakeRecords = filterStockTakeRecordsByItemName(roundStockTakeRecords, itemName) |
|
|
|
if (stockTakeId != null && roundStockTakeRecords.isEmpty()) { |
|
|
|
return RecordsRes(emptyList(), 0) |
|
|
|
} |
|
|
|
val stockTakeRecordsMap = roundStockTakeRecords |
|
|
|
.groupBy { Pair(it.lotId ?: 0L, it.warehouse?.id ?: 0L) } |
|
|
|
.mapValues { (_, records) -> records.maxByOrNull { it.id ?: 0L }!! } |
|
|
|
@@ -394,19 +512,30 @@ class StockTakeRecordService( |
|
|
|
} |
|
|
|
else -> filteredResults |
|
|
|
} |
|
|
|
|
|
|
|
val approvalFilteredFinal = if (stockTakeId == null) { |
|
|
|
var list = approvalFilteredResults |
|
|
|
list = filterInventoryLotDetailsBySectionDescription(list, sectionDescription) |
|
|
|
list = filterInventoryLotDetailsByStockTakeSections(list, stockTakeSections) |
|
|
|
list = filterInventoryLotDetailsByItemCode(list, itemCode) |
|
|
|
list = filterInventoryLotDetailsByItemName(list, itemName) |
|
|
|
list |
|
|
|
} else { |
|
|
|
approvalFilteredResults |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 分页(和 section 版一模一样) |
|
|
|
val pageable = PageRequest.of(pageNum, pageSize) |
|
|
|
val startIndex = pageable.offset.toInt() |
|
|
|
val endIndex = minOf(startIndex + pageSize, approvalFilteredResults.size) |
|
|
|
val endIndex = minOf(startIndex + pageSize, approvalFilteredFinal.size) |
|
|
|
|
|
|
|
val paginatedResult = if (startIndex < approvalFilteredResults.size) { |
|
|
|
approvalFilteredResults.subList(startIndex, endIndex) |
|
|
|
val paginatedResult = if (startIndex < approvalFilteredFinal.size) { |
|
|
|
approvalFilteredFinal.subList(startIndex, endIndex) |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
return RecordsRes(paginatedResult, approvalFilteredResults.size) |
|
|
|
return RecordsRes(paginatedResult, approvalFilteredFinal.size) |
|
|
|
} |
|
|
|
open fun AllApproverStockTakeList(): List<AllPickedStockTakeListReponse> { |
|
|
|
// Overall 卡:只取“最新一轮”,并且总数口径与 |
|
|
|
|