CANCERYS\kw093 11 часов назад
Родитель
Сommit
de310addd5
2 измененных файлов: 166 добавлений и 13 удалений
  1. +136
    -7
      src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt
  2. +30
    -6
      src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt

+ 136
- 7
src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt Просмотреть файл

@@ -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> { open fun AllPickedStockTakeList(): List<AllPickedStockTakeListReponse> {
// 1. 获取所有不同的 stockTakeSection(从 warehouse 表) // 1. 获取所有不同的 stockTakeSection(从 warehouse 表)
val allWarehouses = warehouseRepository.findAllByDeletedIsFalse() val allWarehouses = warehouseRepository.findAllByDeletedIsFalse()
@@ -226,15 +332,19 @@ class StockTakeRecordService(
stockTakeId: Long? = null, stockTakeId: Long? = null,
pageNum: Int = 0, pageNum: Int = 0,
pageSize: Int = 100, pageSize: Int = 100,
approvalView: String? = null
approvalView: String? = null,
itemCode: String? = null,
itemName: String? = null,
sectionDescription: String? = null,
stockTakeSections: String? = null
): RecordsRes<InventoryLotDetailResponse> { ): 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) // 3. 如果传了 stockTakeId,就把「同一轮」的所有 stockTake 找出来(stockTakeRoundId,舊資料則 planStart)
// stockTakeId != null 时,优先用 stocktakerecord.stockTakeRoundId 取整轮记录(更快) // stockTakeId != null 时,优先用 stocktakerecord.stockTakeRoundId 取整轮记录(更快)
// 如果该轮因为旧数据尚未写入 roundId 导致取不到,再 fallback 到旧逻辑(根据 stock_take 的 planStart / stockTakeRoundId 求 stockTakeId 列表) // 如果该轮因为旧数据尚未写入 roundId 导致取不到,再 fallback 到旧逻辑(根据 stock_take 的 planStart / stockTakeRoundId 求 stockTakeId 列表)
val (roundStockTakeIds, roundStockTakeRecords) = if (stockTakeId != null) {
val (roundStockTakeIds, roundStockTakeRecordsRaw) = if (stockTakeId != null) {
val baseStockTake = stockTakeRepository.findByIdAndDeletedIsFalse(stockTakeId) val baseStockTake = stockTakeRepository.findByIdAndDeletedIsFalse(stockTakeId)
?: throw IllegalArgumentException("Stock take not found: $stockTakeId") ?: throw IllegalArgumentException("Stock take not found: $stockTakeId")


@@ -252,6 +362,14 @@ class StockTakeRecordService(
} else { } else {
emptySet<Long>() to emptyList() 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 val stockTakeRecordsMap = roundStockTakeRecords
.groupBy { Pair(it.lotId ?: 0L, it.warehouse?.id ?: 0L) } .groupBy { Pair(it.lotId ?: 0L, it.warehouse?.id ?: 0L) }
.mapValues { (_, records) -> records.maxByOrNull { it.id ?: 0L }!! } .mapValues { (_, records) -> records.maxByOrNull { it.id ?: 0L }!! }
@@ -394,19 +512,30 @@ class StockTakeRecordService(
} }
else -> filteredResults 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 版一模一样) // 7. 分页(和 section 版一模一样)
val pageable = PageRequest.of(pageNum, pageSize) val pageable = PageRequest.of(pageNum, pageSize)
val startIndex = pageable.offset.toInt() 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 { } else {
emptyList() emptyList()
} }
return RecordsRes(paginatedResult, approvalFilteredResults.size)
return RecordsRes(paginatedResult, approvalFilteredFinal.size)
} }
open fun AllApproverStockTakeList(): List<AllPickedStockTakeListReponse> { open fun AllApproverStockTakeList(): List<AllPickedStockTakeListReponse> {
// Overall 卡:只取“最新一轮”,并且总数口径与 // Overall 卡:只取“最新一轮”,并且总数口径与


+ 30
- 6
src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt Просмотреть файл

@@ -56,38 +56,62 @@ class StockTakeRecordController(
fun getApproverInventoryLotDetailsAll( fun getApproverInventoryLotDetailsAll(
@RequestParam(required = false) stockTakeId: Long?, // 可选:限定某个 stockTake @RequestParam(required = false) stockTakeId: Long?, // 可选:限定某个 stockTake
@RequestParam(required = false, defaultValue = "0") pageNum: Int, // 分页页码(从 0 开始) @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<InventoryLotDetailResponse> { ): RecordsRes<InventoryLotDetailResponse> {
return stockOutRecordService.getApproverInventoryLotDetailsAll( return stockOutRecordService.getApproverInventoryLotDetailsAll(
stockTakeId = stockTakeId, stockTakeId = stockTakeId,
pageNum = pageNum, pageNum = pageNum,
pageSize = pageSize
pageSize = pageSize,
itemCode = itemCode,
itemName = itemName,
sectionDescription = sectionDescription,
stockTakeSections = stockTakeSections
) )
} }
@GetMapping("/approverInventoryLotDetailsAllPending") @GetMapping("/approverInventoryLotDetailsAllPending")
fun getApproverInventoryLotDetailsAllPending( fun getApproverInventoryLotDetailsAllPending(
@RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false) stockTakeId: Long?,
@RequestParam(required = false, defaultValue = "0") pageNum: Int, @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<InventoryLotDetailResponse> { ): RecordsRes<InventoryLotDetailResponse> {
return stockOutRecordService.getApproverInventoryLotDetailsAll( return stockOutRecordService.getApproverInventoryLotDetailsAll(
stockTakeId = stockTakeId, stockTakeId = stockTakeId,
pageNum = pageNum, pageNum = pageNum,
pageSize = pageSize, pageSize = pageSize,
approvalView = "pending"
approvalView = "pending",
itemCode = itemCode,
itemName = itemName,
sectionDescription = sectionDescription,
stockTakeSections = stockTakeSections
) )
} }
@GetMapping("/approverInventoryLotDetailsAllApproved") @GetMapping("/approverInventoryLotDetailsAllApproved")
fun getApproverInventoryLotDetailsAllApproved( fun getApproverInventoryLotDetailsAllApproved(
@RequestParam(required = false) stockTakeId: Long?, @RequestParam(required = false) stockTakeId: Long?,
@RequestParam(required = false, defaultValue = "0") pageNum: Int, @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<InventoryLotDetailResponse> { ): RecordsRes<InventoryLotDetailResponse> {
return stockOutRecordService.getApproverInventoryLotDetailsAll( return stockOutRecordService.getApproverInventoryLotDetailsAll(
stockTakeId = stockTakeId, stockTakeId = stockTakeId,
pageNum = pageNum, pageNum = pageNum,
pageSize = pageSize, pageSize = pageSize,
approvalView = "approved"
approvalView = "approved",
itemCode = itemCode,
itemName = itemName,
sectionDescription = sectionDescription,
stockTakeSections = stockTakeSections
) )
} }
@GetMapping("/AllApproverStockTakeList") @GetMapping("/AllApproverStockTakeList")


Загрузка…
Отмена
Сохранить