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 5171164..79a4281 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 @@ -331,18 +331,24 @@ open class StockTakeRecordService( val selectedQty = resolvePickerQtyForVarianceFilter(response) val bookQty = response.bookQty ?: response.availableQty ?: BigDecimal.ZERO val difference = selectedQty.subtract(bookQty) - if (bookQty.compareTo(BigDecimal.ZERO) != 0) { - return difference + val raw = if (bookQty.compareTo(BigDecimal.ZERO) != 0) { + difference .divide(bookQty, 6, RoundingMode.HALF_UP) .multiply(BigDecimal("100")) + } else { + when { + difference.compareTo(BigDecimal.ZERO) == 0 -> BigDecimal.ZERO + difference.compareTo(BigDecimal.ZERO) > 0 -> BigDecimal("100") + else -> BigDecimal("-100") + } } - return when { - difference.compareTo(BigDecimal.ZERO) == 0 -> BigDecimal.ZERO - difference.compareTo(BigDecimal.ZERO) > 0 -> BigDecimal("100") - else -> BigDecimal("-100") - } + return roundDownVariancePercent(raw) } + /** 與前端顯示一致:差異% 小數向零方向捨去(-48.43 → -48,48.9 → 48) */ + private fun roundDownVariancePercent(vp: BigDecimal): BigDecimal = + vp.setScale(0, RoundingMode.DOWN) + /** * @param varianceFilterInclusive false:只保留區間外(vp ≤ -t 或 vp ≥ t); * true:只保留區間內(-t ≤ vp ≤ t) @@ -568,6 +574,35 @@ open class StockTakeRecordService( return result.sortedBy { it.stockTakeSession } } + + /** + * 全系統最新盤點輪次 id(MAX(stockTakeRoundId));舊資料無 roundId 時退回 planStart 最新一筆。 + */ + open fun resolveGlobalLatestStockTakeRoundKey(): Long? { + val maxRound = stockTakeRepository.findMaxStockTakeRoundId() + if (maxRound > 0L) { + return maxRound + } + val latest = stockTakeRepository.findAll() + .filter { !it.deleted } + .maxByOrNull { it.planStart ?: LocalDateTime.MIN } + return latest?.let { st -> st.stockTakeRoundId ?: st.id } + } + + open fun getGlobalLatestStockTakeRoundMeta(): LatestStockTakeRoundMetaResponse { + val roundKey = resolveGlobalLatestStockTakeRoundKey() + if (roundKey == null || roundKey <= 0L) { + return LatestStockTakeRoundMetaResponse(stockTakeRoundId = null, planStartDate = null) + } + val byRound = stockTakeRepository.findAllByStockTakeRoundIdAndDeletedIsFalse(roundKey) + val planStart = if (byRound.isNotEmpty()) { + byRound.mapNotNull { it.planStart }.maxOrNull()?.toLocalDate() + } else { + stockTakeRepository.findByIdAndDeletedIsFalse(roundKey)?.planStart?.toLocalDate() + } + return LatestStockTakeRoundMetaResponse(stockTakeRoundId = roundKey, planStartDate = planStart) + } + open fun getApproverInventoryLotDetailsAll( stockTakeId: Long? = null, pageNum: Int = 0, 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 6fc9864..fd2cf94 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 @@ -73,12 +73,8 @@ class StockTakeRecordController( } } if (onlyLatestRound) { - val latestRoundKey = all - .mapNotNull { item -> - item.stockTakeRoundId ?: item.stockTakeId.takeIf { it > 0 } - } - .maxOrNull() - all = if (latestRoundKey == null) { + val latestRoundKey = stockOutRecordService.resolveGlobalLatestStockTakeRoundKey() + all = if (latestRoundKey == null || latestRoundKey <= 0L) { emptyList() } else { all.filter { (it.stockTakeRoundId ?: it.stockTakeId) == latestRoundKey } @@ -90,6 +86,12 @@ class StockTakeRecordController( val pageList = if (fromIndex >= total) emptyList() else all.subList(fromIndex, toIndex) return RecordsRes(pageList, total) } + + @GetMapping("/latestStockTakeRoundMeta") + fun latestStockTakeRoundMeta(): LatestStockTakeRoundMetaResponse { + return stockOutRecordService.getGlobalLatestStockTakeRoundMeta() + } + @GetMapping("/approverInventoryLotDetailsAll") fun getApproverInventoryLotDetailsAll( @RequestParam(required = false) stockTakeId: Long?, // 可选:限定某个 stockTake