From f9a847f61ee6d718fb3a9213f6770d02ce8fd3c7 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Wed, 1 Apr 2026 16:14:23 +0800 Subject: [PATCH] update --- .../modules/master/entity/ItemsRepository.kt | 12 ++ .../stock/service/StockTakeRecordService.kt | 104 ++++++++++++++++-- .../stock/web/StockTakeRecordController.kt | 31 +++--- .../stock/web/model/StockTakeRecordReponse.kt | 1 + 4 files changed, 120 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsRepository.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsRepository.kt index b655c4d..da77c0c 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsRepository.kt @@ -60,4 +60,16 @@ interface ItemsRepository : AbstractRepository { value = "SELECT * FROM items i WHERE i.code = :code AND i.deleted = false ORDER BY i.id LIMIT 1" ) fun findFirstByCodeAndDeletedFalse(code: String): Items? + + @Query( + nativeQuery = true, + value = """ + select i.id + from items i + where i.deleted = false + and (lower(i.code) like concat('%', lower(:kw), '%') + or lower(i.name) like concat('%', lower(:kw), '%')) + """ +) +fun findIdsByCodeOrNameContains(kw: String): List } \ No newline at end of file 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 11cd703..cc2bcd6 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 @@ -45,6 +45,7 @@ import java.time.LocalDate import com.ffii.fpsms.modules.stock.entity.InventoryLotLine import java.math.RoundingMode import com.ffii.fpsms.modules.stock.entity.StockTake +import com.ffii.fpsms.modules.master.entity.ItemsRepository @Service class StockTakeRecordService( val stockTakeRepository: StockTakeRepository, @@ -61,7 +62,8 @@ class StockTakeRecordService( val inventoryLotRepository: InventoryLotRepository, val stockLedgerRepository: StockLedgerRepository, val inventoryRepository: InventoryRepository, - val uomConversionRepository: UomConversionRepository + val uomConversionRepository: UomConversionRepository, + val itemsRepository: ItemsRepository ) { private val logger: Logger = LoggerFactory.getLogger(StockTakeRecordService::class.java) @@ -90,6 +92,18 @@ class StockTakeRecordService( /** * 逗號分隔多個關鍵字,任一包含於 [StockTakeRecord.itemCode] 即保留(不分大小寫)。 */ + private fun filterStockTakeRecordsByItemKeyword( + records: List, + itemKeyword: String? + ): List { + if (itemKeyword.isNullOrBlank()) return records + val parts = itemKeyword.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) } + } + } private fun filterStockTakeRecordsByItemCode( records: List, itemCode: String? @@ -154,7 +168,18 @@ class StockTakeRecordService( parts.any { part -> name.contains(part, ignoreCase = true) } } } - + private fun filterStockTakeRecordsByWarehouseCode( + records: List, + warehouseCodeKeyword: String? +): List { + if (warehouseCodeKeyword.isNullOrBlank()) return records + val parts = warehouseCodeKeyword.split(",").map { it.trim() }.filter { it.isNotEmpty() } + if (parts.isEmpty()) return records + return records.filter { rec -> + val code = rec.warehouse?.code ?: "" + parts.any { part -> code.contains(part, ignoreCase = true) } + } +} private fun filterInventoryLotDetailsBySectionDescription( responses: List, sectionDescription: String? @@ -164,7 +189,35 @@ class StockTakeRecordService( r.stockTakeSectionDescription?.equals(sectionDescription, ignoreCase = true) == true } } - + private fun filterInventoryLotDetailsByItemKeyword( + responses: List, + itemKeyword: String? + ): List { + if (itemKeyword.isNullOrBlank()) return responses + val parts = itemKeyword.split(",").map { it.trim() }.filter { it.isNotEmpty() } + if (parts.isEmpty()) return responses + + return responses.filter { r -> + val code = r.itemCode ?: "" + val name = r.itemName ?: "" + parts.any { part -> + code.contains(part, ignoreCase = true) || name.contains(part, ignoreCase = true) + } + } + } + private fun filterInventoryLotDetailsByWarehouseKeyword( + responses: List, + warehouseKeyword: String? +): List { + if (warehouseKeyword.isNullOrBlank()) return responses + val parts = warehouseKeyword.split(",").map { it.trim() }.filter { it.isNotEmpty() } + if (parts.isEmpty()) return responses + + return responses.filter { r -> + val code = r.warehouseCode ?: "" + parts.any { part -> code.contains(part, ignoreCase = true) } + } +} private fun filterInventoryLotDetailsByStockTakeSections( responses: List, stockTakeSections: String? @@ -333,13 +386,13 @@ class StockTakeRecordService( pageNum: Int = 0, pageSize: Int = 100, approvalView: String? = null, - itemCode: String? = null, - itemName: String? = null, + itemKeyword: String? = null, sectionDescription: String? = null, - stockTakeSections: String? = null + stockTakeSections: String? = null, + warehouseKeyword: String? = null ): RecordsRes { - println("getApproverInventoryLotDetailsAll called with stockTakeId: $stockTakeId, pageNum: $pageNum, pageSize: $pageSize, itemCode: $itemCode, itemName: $itemName, sectionDescription: $sectionDescription, stockTakeSections: $stockTakeSections") + println("getApproverInventoryLotDetailsAll called with stockTakeId: $stockTakeId, pageNum: $pageNum, pageSize: $pageSize, itemKeyword: $itemKeyword, sectionDescription: $sectionDescription, stockTakeSections: $stockTakeSections, warehouseKeyword: $warehouseKeyword") // 3. 如果传了 stockTakeId,就把「同一轮」的所有 stockTake 找出来(stockTakeRoundId,舊資料則 planStart) // stockTakeId != null 时,优先用 stocktakerecord.stockTakeRoundId 取整轮记录(更快) @@ -363,10 +416,30 @@ class StockTakeRecordService( emptySet() to emptyList() } var roundStockTakeRecords = roundStockTakeRecordsRaw + val parts = itemKeyword + ?.split(",") + ?.map { it.trim() } + ?.filter { it.isNotEmpty() } + .orEmpty() + if (parts.isNotEmpty()) { + val allowedItemIds = parts + .flatMap { kw -> itemsRepository.findIdsByCodeOrNameContains(kw) } + .distinct() + .toSet() + if (allowedItemIds.isEmpty()) { + return RecordsRes(emptyList(), 0) + } + roundStockTakeRecords = roundStockTakeRecords.filter { rec -> + val itemId = rec.itemId + itemId != null && allowedItemIds.contains(itemId) + } + } roundStockTakeRecords = filterStockTakeRecordsBySectionDescription(roundStockTakeRecords, sectionDescription) roundStockTakeRecords = filterStockTakeRecordsByStockTakeSections(roundStockTakeRecords, stockTakeSections) - roundStockTakeRecords = filterStockTakeRecordsByItemCode(roundStockTakeRecords, itemCode) - roundStockTakeRecords = filterStockTakeRecordsByItemName(roundStockTakeRecords, itemName) + // roundStockTakeRecords = filterStockTakeRecordsByItemCode(roundStockTakeRecords, itemCode) + //roundStockTakeRecords = filterStockTakeRecordsByItemName(roundStockTakeRecords, itemName) + //roundStockTakeRecords = filterStockTakeRecordsByItemKeyword(roundStockTakeRecords, itemKeyword) + roundStockTakeRecords = filterStockTakeRecordsByWarehouseCode(roundStockTakeRecords, warehouseKeyword) if (stockTakeId != null && roundStockTakeRecords.isEmpty()) { return RecordsRes(emptyList(), 0) } @@ -470,6 +543,7 @@ class StockTakeRecordService( warehouseSlot = warehouse?.slot, warehouseArea = warehouse?.area, warehouse = warehouse?.warehouse, + storeId = warehouse?.store_id, varianceQty = stockTakeRecord?.varianceQty, stockTakeRecordId = stockTakeRecord?.id, stockTakeRecordStatus = stockTakeRecord?.status, @@ -517,8 +591,10 @@ class StockTakeRecordService( var list = approvalFilteredResults list = filterInventoryLotDetailsBySectionDescription(list, sectionDescription) list = filterInventoryLotDetailsByStockTakeSections(list, stockTakeSections) - list = filterInventoryLotDetailsByItemCode(list, itemCode) - list = filterInventoryLotDetailsByItemName(list, itemName) + //list = filterInventoryLotDetailsByItemCode(list, itemCode) + //list = filterInventoryLotDetailsByItemName(list, itemName) + list = filterInventoryLotDetailsByItemKeyword(list, itemKeyword) + list = filterInventoryLotDetailsByWarehouseKeyword(list, warehouseKeyword) list } else { approvalFilteredResults @@ -707,6 +783,7 @@ class StockTakeRecordService( warehouseCode = warehouse?.code, warehouseName = warehouse?.name, status = ill.status?.name, + storeId = warehouse?.store_id, stockTakeRecordStatus = null, stockTakeRecordId = null, firstStockTakeQty = null, @@ -788,6 +865,7 @@ class StockTakeRecordService( itemName = item?.name, lotNo = inventoryLot?.lotNo, expiryDate = inventoryLot?.expiryDate, + storeId = warehouse?.store_id, productionDate = inventoryLot?.productionDate, stockInDate = inventoryLot?.stockInDate, inQty = ill.inQty, @@ -797,10 +875,11 @@ class StockTakeRecordService( availableQty = availableQty, uom = ill.stockUom?.uom?.udfudesc, warehouseCode = warehouse?.code, + warehouseArea = warehouse?.area, warehouseName = warehouse?.name, status = ill.status?.name, warehouseSlot = warehouse?.slot, - warehouseArea = warehouse?.area, + warehouse = warehouse?.warehouse, varianceQty = stockTakeRecord?.varianceQty, stockTakeRecordId = stockTakeRecord?.id, @@ -1810,6 +1889,7 @@ open fun getInventoryLotDetailsByStockTakeSectionNotMatch( warehouseSlot = warehouse?.slot, warehouseArea = warehouse?.area, warehouse = warehouse?.warehouse, + storeId = warehouse?.store_id, varianceQty = stockTakeRecord.varianceQty, stockTakeRecordId = stockTakeRecord.id, stockTakeRecordStatus = stockTakeRecord.status, 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 3317e20..cdef5d3 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 @@ -57,8 +57,7 @@ class StockTakeRecordController( @RequestParam(required = false) stockTakeId: Long?, // 可选:限定某个 stockTake @RequestParam(required = false, defaultValue = "0") pageNum: Int, // 分页页码(从 0 开始) @RequestParam(required = false, defaultValue = "100") pageSize: Int, // 每页多少条,测试时可调大 - @RequestParam(required = false) itemCode: String?, - @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) itemKeyword: String?, @RequestParam(required = false) sectionDescription: String?, @RequestParam(required = false) stockTakeSections: String? ): RecordsRes { @@ -66,8 +65,8 @@ class StockTakeRecordController( stockTakeId = stockTakeId, pageNum = pageNum, pageSize = pageSize, - itemCode = itemCode, - itemName = itemName, + + itemKeyword = itemKeyword, sectionDescription = sectionDescription, stockTakeSections = stockTakeSections ) @@ -77,20 +76,20 @@ class StockTakeRecordController( @RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false, defaultValue = "0") pageNum: Int, @RequestParam(required = false, defaultValue = "2147483647") pageSize: Int, - @RequestParam(required = false) itemCode: String?, - @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) itemKeyword: String?, @RequestParam(required = false) sectionDescription: String?, - @RequestParam(required = false) stockTakeSections: String? + @RequestParam(required = false) stockTakeSections: String?, + @RequestParam(required = false) warehouseKeyword: String? ): RecordsRes { return stockOutRecordService.getApproverInventoryLotDetailsAll( stockTakeId = stockTakeId, pageNum = pageNum, pageSize = pageSize, approvalView = "pending", - itemCode = itemCode, - itemName = itemName, + itemKeyword = itemKeyword, sectionDescription = sectionDescription, - stockTakeSections = stockTakeSections + stockTakeSections = stockTakeSections, + warehouseKeyword = warehouseKeyword ) } @GetMapping("/approverInventoryLotDetailsAllApproved") @@ -98,20 +97,20 @@ class StockTakeRecordController( @RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false, defaultValue = "0") pageNum: Int, @RequestParam(required = false, defaultValue = "50") pageSize: Int, - @RequestParam(required = false) itemCode: String?, - @RequestParam(required = false) itemName: String?, + @RequestParam(required = false) itemKeyword: String?, @RequestParam(required = false) sectionDescription: String?, - @RequestParam(required = false) stockTakeSections: String? + @RequestParam(required = false) stockTakeSections: String?, + @RequestParam(required = false) warehouseKeyword: String? ): RecordsRes { return stockOutRecordService.getApproverInventoryLotDetailsAll( stockTakeId = stockTakeId, pageNum = pageNum, pageSize = pageSize, approvalView = "approved", - itemCode = itemCode, - itemName = itemName, + itemKeyword = itemKeyword, sectionDescription = sectionDescription, - stockTakeSections = stockTakeSections + stockTakeSections = stockTakeSections, + warehouseKeyword = warehouseKeyword ) } @GetMapping("/AllApproverStockTakeList") diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockTakeRecordReponse.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockTakeRecordReponse.kt index 8bae859..6ca8588 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockTakeRecordReponse.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockTakeRecordReponse.kt @@ -48,6 +48,7 @@ data class InventoryLotDetailResponse( val warehouseSlot: String?, val warehouseArea: String?, val warehouseName: String?, + val storeId: String?, val varianceQty: BigDecimal? = null, val status: String?, val remarks: String?,