diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt index f2ee658..11cd703 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt @@ -87,6 +87,112 @@ class StockTakeRecordService( } } + /** + * 逗號分隔多個關鍵字,任一包含於 [StockTakeRecord.itemCode] 即保留(不分大小寫)。 + */ + private fun filterStockTakeRecordsByItemCode( + records: List, + itemCode: String? + ): List { + 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, + itemCode: String? + ): List { + 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, + sectionDescription: String? + ): List { + if (sectionDescription.isNullOrBlank() || sectionDescription == "All") return records + return records.filter { rec -> + rec.warehouse?.stockTakeSectionDescription?.equals(sectionDescription, ignoreCase = true) == true + } + } + + private fun filterStockTakeRecordsByStockTakeSections( + records: List, + stockTakeSections: String? + ): List { + 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, + itemName: String? + ): List { + 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, + sectionDescription: String? + ): List { + if (sectionDescription.isNullOrBlank() || sectionDescription == "All") return responses + return responses.filter { r -> + r.stockTakeSectionDescription?.equals(sectionDescription, ignoreCase = true) == true + } + } + + private fun filterInventoryLotDetailsByStockTakeSections( + responses: List, + stockTakeSections: String? + ): List { + 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, + itemName: String? + ): List { + 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 { // 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 { - 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() 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 { // Overall 卡:只取“最新一轮”,并且总数口径与 diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt index 76a0cdc..3317e20 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt @@ -56,38 +56,62 @@ class StockTakeRecordController( fun getApproverInventoryLotDetailsAll( @RequestParam(required = false) stockTakeId: Long?, // 可选:限定某个 stockTake @RequestParam(required = false, defaultValue = "0") pageNum: Int, // 分页页码(从 0 开始) - @RequestParam(required = false, defaultValue = "100") pageSize: Int // 每页多少条,测试时可调大 + @RequestParam(required = false, defaultValue = "100") pageSize: Int, // 每页多少条,测试时可调大 + @RequestParam(required = false) itemCode: String?, + @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) sectionDescription: String?, + @RequestParam(required = false) stockTakeSections: String? ): RecordsRes { return stockOutRecordService.getApproverInventoryLotDetailsAll( stockTakeId = stockTakeId, pageNum = pageNum, - pageSize = pageSize + pageSize = pageSize, + itemCode = itemCode, + itemName = itemName, + sectionDescription = sectionDescription, + stockTakeSections = stockTakeSections ) } @GetMapping("/approverInventoryLotDetailsAllPending") fun getApproverInventoryLotDetailsAllPending( @RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false, defaultValue = "0") pageNum: Int, - @RequestParam(required = false, defaultValue = "2147483647") pageSize: Int + @RequestParam(required = false, defaultValue = "2147483647") pageSize: Int, + @RequestParam(required = false) itemCode: String?, + @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) sectionDescription: String?, + @RequestParam(required = false) stockTakeSections: String? ): RecordsRes { return stockOutRecordService.getApproverInventoryLotDetailsAll( stockTakeId = stockTakeId, pageNum = pageNum, pageSize = pageSize, - approvalView = "pending" + approvalView = "pending", + itemCode = itemCode, + itemName = itemName, + sectionDescription = sectionDescription, + stockTakeSections = stockTakeSections ) } @GetMapping("/approverInventoryLotDetailsAllApproved") fun getApproverInventoryLotDetailsAllApproved( @RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false, defaultValue = "0") pageNum: Int, - @RequestParam(required = false, defaultValue = "50") pageSize: Int + @RequestParam(required = false, defaultValue = "50") pageSize: Int, + @RequestParam(required = false) itemCode: String?, + @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) sectionDescription: String?, + @RequestParam(required = false) stockTakeSections: String? ): RecordsRes { return stockOutRecordService.getApproverInventoryLotDetailsAll( stockTakeId = stockTakeId, pageNum = pageNum, pageSize = pageSize, - approvalView = "approved" + approvalView = "approved", + itemCode = itemCode, + itemName = itemName, + sectionDescription = sectionDescription, + stockTakeSections = stockTakeSections ) } @GetMapping("/AllApproverStockTakeList")