|
|
@@ -366,6 +366,8 @@ class StockTakeRecordService( |
|
|
stockTakeSection = stockTakeRecord?.stockTakeSection ?: warehouse?.stockTakeSection, |
|
|
stockTakeSection = stockTakeRecord?.stockTakeSection ?: warehouse?.stockTakeSection, |
|
|
stockTakeSectionDescription = warehouse?.stockTakeSectionDescription, |
|
|
stockTakeSectionDescription = warehouse?.stockTakeSectionDescription, |
|
|
stockTakerName = stockTakeRecord?.stockTakerName, |
|
|
stockTakerName = stockTakeRecord?.stockTakerName, |
|
|
|
|
|
stockTakeEndTime = stockTakeRecord?.stockTakeEndTime, |
|
|
|
|
|
approverTime = stockTakeRecord?.approverTime, |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -380,16 +382,14 @@ class StockTakeRecordService( |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Pending / Approved 只看「審核是否完成」,不要用 stockTakeRecord.status == "completed": |
|
|
|
|
|
// picker 在 inQty==outQty 時也會寫 status=completed,會被誤判成已審核而只出現在 Approved 分頁。 |
|
|
val approvalFilteredResults = when (approvalView?.lowercase()) { |
|
|
val approvalFilteredResults = when (approvalView?.lowercase()) { |
|
|
"approved" -> filteredResults.filter { response -> |
|
|
"approved" -> filteredResults.filter { response -> |
|
|
response.stockTakeRecordStatus == "completed" || |
|
|
|
|
|
response.approverQty != null || |
|
|
|
|
|
response.finalQty != null |
|
|
|
|
|
|
|
|
response.approverQty != null || response.finalQty != null |
|
|
} |
|
|
} |
|
|
"pending" -> filteredResults.filter { response -> |
|
|
"pending" -> filteredResults.filter { response -> |
|
|
!(response.stockTakeRecordStatus == "completed" || |
|
|
|
|
|
response.approverQty != null || |
|
|
|
|
|
response.finalQty != null) |
|
|
|
|
|
|
|
|
response.approverQty == null && response.finalQty == null |
|
|
} |
|
|
} |
|
|
else -> filteredResults |
|
|
else -> filteredResults |
|
|
} |
|
|
} |
|
|
@@ -683,6 +683,11 @@ class StockTakeRecordService( |
|
|
approverBadQty = stockTakeRecord?.approverBadQty, |
|
|
approverBadQty = stockTakeRecord?.approverBadQty, |
|
|
finalQty = stockTakeLine?.finalQty, |
|
|
finalQty = stockTakeLine?.finalQty, |
|
|
bookQty = stockTakeRecord?.bookQty, |
|
|
bookQty = stockTakeRecord?.bookQty, |
|
|
|
|
|
stockTakeSection = stockTakeRecord?.stockTakeSection ?: warehouse?.stockTakeSection, |
|
|
|
|
|
stockTakeSectionDescription = warehouse?.stockTakeSectionDescription, |
|
|
|
|
|
stockTakerName = stockTakeRecord?.stockTakerName, |
|
|
|
|
|
stockTakeEndTime = stockTakeRecord?.stockTakeEndTime, |
|
|
|
|
|
approverTime = stockTakeRecord?.approverTime, |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -1099,14 +1104,18 @@ return RecordsRes(paginatedResult, filteredResults.size) |
|
|
this.approverBadQty = finalBadQty |
|
|
this.approverBadQty = finalBadQty |
|
|
this.varianceQty = varianceQty |
|
|
this.varianceQty = varianceQty |
|
|
this.status = "completed" |
|
|
this.status = "completed" |
|
|
|
|
|
this.approverTime = java.time.LocalDateTime.now() |
|
|
|
|
|
// stockTakeEndTime 目前只在 saveStockTakeRecord「第二次盤點」時寫入;只做第一次盤點時會一直是 null。 |
|
|
|
|
|
// 審核通過時若仍為空,補上時間,讓列表「審核/完成時間」有值(不覆寫已有第二次盤點結束時間)。 |
|
|
|
|
|
if (this.stockTakeEndTime == null) { |
|
|
|
|
|
this.stockTakeEndTime = java.time.LocalDateTime.now() |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
val savedRecord = stockTakeRecordRepository.save(stockTakeRecord) |
|
|
val savedRecord = stockTakeRecordRepository.save(stockTakeRecord) |
|
|
|
|
|
|
|
|
// ------- 取当前库存行 / 库存信息 ------- |
|
|
|
|
|
val inventoryLotLine = inventoryLotLineRepository.findByIdAndDeletedIsFalse( |
|
|
|
|
|
stockTakeRecord.inventoryLotId ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
|
|
|
) ?: throw IllegalArgumentException("Inventory lot line not found") |
|
|
|
|
|
|
|
|
// stockTakeRecord.inventoryLotId 是 inventory_lot 主鍵,不是 inventory_lot_line 主鍵;必須用倉庫+批次定位庫存行 |
|
|
|
|
|
val inventoryLotLine = resolveInventoryLotLineForStockTakeRecord(savedRecord) |
|
|
|
|
|
|
|
|
val inventoryLot = inventoryLotRepository.findByIdAndDeletedFalse( |
|
|
val inventoryLot = inventoryLotRepository.findByIdAndDeletedFalse( |
|
|
inventoryLotLine.inventoryLot?.id ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
inventoryLotLine.inventoryLot?.id ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
@@ -1209,6 +1218,10 @@ open fun batchSaveApproverStockTakeRecords( |
|
|
this.approverBadQty = badQty |
|
|
this.approverBadQty = badQty |
|
|
this.varianceQty = varianceQty |
|
|
this.varianceQty = varianceQty |
|
|
this.status = "completed" |
|
|
this.status = "completed" |
|
|
|
|
|
this.approverTime = java.time.LocalDateTime.now() |
|
|
|
|
|
if (this.stockTakeEndTime == null) { |
|
|
|
|
|
this.stockTakeEndTime = java.time.LocalDateTime.now() |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
stockTakeRecordRepository.save(record) |
|
|
stockTakeRecordRepository.save(record) |
|
|
@@ -1321,6 +1334,10 @@ open fun batchSaveApproverStockTakeRecordsAll( |
|
|
this.approverBadQty = badQty |
|
|
this.approverBadQty = badQty |
|
|
this.varianceQty = varianceQty |
|
|
this.varianceQty = varianceQty |
|
|
this.status = "completed" |
|
|
this.status = "completed" |
|
|
|
|
|
this.approverTime = java.time.LocalDateTime.now() |
|
|
|
|
|
if (this.stockTakeEndTime == null) { |
|
|
|
|
|
this.stockTakeEndTime = java.time.LocalDateTime.now() |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
stockTakeRecordRepository.save(record) |
|
|
stockTakeRecordRepository.save(record) |
|
|
@@ -1362,6 +1379,26 @@ open fun batchSaveApproverStockTakeRecordsAll( |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* stockTakeRecord 上存的是 inventory_lot.id(批次),不是 inventory_lot_line.id;用倉庫 + 批次找唯一庫存行。 |
|
|
|
|
|
*/ |
|
|
|
|
|
private fun resolveInventoryLotLineForStockTakeRecord(record: StockTakeRecord): InventoryLotLine { |
|
|
|
|
|
val warehouseId = record.warehouse?.id |
|
|
|
|
|
?: throw IllegalArgumentException("Warehouse not found on stock take record") |
|
|
|
|
|
val lotId = record.inventoryLotId ?: record.lotId |
|
|
|
|
|
?: throw IllegalArgumentException("Inventory lot ID not found on stock take record") |
|
|
|
|
|
val lines = inventoryLotLineRepository.findAllByWarehouseIdInAndInventoryLotIdInAndDeletedIsFalse( |
|
|
|
|
|
listOf(warehouseId), |
|
|
|
|
|
listOf(lotId) |
|
|
|
|
|
) |
|
|
|
|
|
if (lines.isEmpty()) { |
|
|
|
|
|
throw IllegalArgumentException( |
|
|
|
|
|
"Inventory lot line not found for warehouseId=$warehouseId inventoryLotId=$lotId" |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
return lines.maxByOrNull { it.id ?: 0L }!! |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 根据 variance 调整库存并创建 Stock Ledger。 |
|
|
* 根据 variance 调整库存并创建 Stock Ledger。 |
|
|
* 当 variance != 0 时:创建 StockTakeLine,并根据 variance 正负创建 StockIn/StockOut 及 Ledger。 |
|
|
* 当 variance != 0 时:创建 StockTakeLine,并根据 variance 正负创建 StockIn/StockOut 及 Ledger。 |
|
|
@@ -1375,9 +1412,7 @@ private fun applyVarianceAdjustment( |
|
|
) { |
|
|
) { |
|
|
if (varianceQty == BigDecimal.ZERO) return |
|
|
if (varianceQty == BigDecimal.ZERO) return |
|
|
|
|
|
|
|
|
val inventoryLotLine = inventoryLotLineRepository.findByIdAndDeletedIsFalse( |
|
|
|
|
|
stockTakeRecord.inventoryLotId ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
|
|
|
) ?: throw IllegalArgumentException("Inventory lot line not found") |
|
|
|
|
|
|
|
|
val inventoryLotLine = resolveInventoryLotLineForStockTakeRecord(stockTakeRecord) |
|
|
|
|
|
|
|
|
val inventoryLot = inventoryLotRepository.findByIdAndDeletedFalse( |
|
|
val inventoryLot = inventoryLotRepository.findByIdAndDeletedFalse( |
|
|
inventoryLotLine.inventoryLot?.id ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
inventoryLotLine.inventoryLot?.id ?: throw IllegalArgumentException("Inventory lot ID not found") |
|
|
@@ -1625,6 +1660,11 @@ open fun getInventoryLotDetailsByStockTakeSectionNotMatch( |
|
|
approverBadQty = stockTakeRecord.approverBadQty, |
|
|
approverBadQty = stockTakeRecord.approverBadQty, |
|
|
finalQty = stockTakeLine?.finalQty, |
|
|
finalQty = stockTakeLine?.finalQty, |
|
|
bookQty = stockTakeRecord.bookQty, |
|
|
bookQty = stockTakeRecord.bookQty, |
|
|
|
|
|
stockTakeSection = stockTakeRecord.stockTakeSection ?: warehouse?.stockTakeSection, |
|
|
|
|
|
stockTakeSectionDescription = warehouse?.stockTakeSectionDescription, |
|
|
|
|
|
stockTakerName = stockTakeRecord.stockTakerName, |
|
|
|
|
|
stockTakeEndTime = stockTakeRecord.stockTakeEndTime, |
|
|
|
|
|
approverTime = stockTakeRecord.approverTime, |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|