|
|
|
@@ -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, |
|
|
|
|