CANCERYS\kw093 10 часов назад
Родитель
Сommit
9ff66b0d88
2 измененных файлов: 78 добавлений и 23 удалений
  1. +1
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt
  2. +77
    -23
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt

+ 1
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt Просмотреть файл

@@ -57,4 +57,5 @@ interface StockLedgerRepository: AbstractRepository<StockLedger, Long> {
ORDER BY sl.date DESC, sl.id DESC
""")
fun findLatestByItemId(@Param("itemId") itemId: Long): List<StockLedger>
fun findFirstByItemIdAndDeletedFalseOrderByDateDescIdDesc(itemId: Long): StockLedger?
}

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

@@ -868,6 +868,13 @@ open class StockInLineService(
@Throws(IOException::class)
@Transactional
open fun update(request: SaveStockInLineRequest): MessageResponse {
val _t0 = System.nanoTime()
fun _msSince(t: Long): Double = (System.nanoTime() - t) / 1_000_000.0
fun _logStep(name: String, t: Long) {
logger.info("[SIL.update timing] $name took ${String.format("%.3f", _msSince(t))} ms")
}

val _tFind = System.nanoTime()
val stockInLine = if (request.id != null) stockInLineRepository.findById(request.id!!).orElseThrow()
else return MessageResponse(
id = null,
@@ -877,6 +884,7 @@ open class StockInLineService(
message = "stock in line id is null",
errorPosition = null,
)
_logStep("stockInLineRepository.findById", _tFind)
// val allStockInLine = stockInLineRepository.findAllStockInLineInfoByStockInIdAndDeletedFalse(stockInLine!!.stockIn!!.id!!)

if (stockInLine.expiryDate != null && request.expiryDate == null) {
@@ -887,6 +895,7 @@ open class StockInLineService(
// TODO: check all status to prevent reverting progress due to multiple users access to the same po?
// return list of stock in line, update data grid with the list

val _tApplyFields = System.nanoTime()
stockInLine.apply {
this.productionDate = request.productionDate?.atStartOfDay() ?: this.productionDate
this.productLotNo = request.productLotNo ?: this.productLotNo
@@ -941,15 +950,23 @@ open class StockInLineService(
this.expiryDate = stockInLine.expiryDate ?: request.expiryDate
this.remarks = stockInLine.remarks ?: request.remarks
}
_logStep("apply_fields", _tApplyFields)
if (request.status == StockInLineStatus.RECEIVED.status) {
val _tPutAwayTotal = System.nanoTime()
// Putaway
var savedInventoryLotLine: InventoryLotLine? = null

// savedInventoryLotLine = saveInventoryLotLineWhenStockIn(request = request, stockInLine = stockInLine)
val _tSaveLotLines = System.nanoTime()
val savedInventoryLotLines = saveInventoryLotLineWhenStockIn(request = request, stockInLine = stockInLine)
_logStep("saveInventoryLotLineWhenStockIn", _tSaveLotLines)

val _tFindAllLotLines = System.nanoTime()
val inventoryLotLines = stockInLine.inventoryLot?.let { it.id?.let { _id -> inventoryLotLineRepository.findAllByInventoryLotId(_id) } } ?: listOf()
_logStep("inventoryLotLineRepository.findAllByInventoryLotId", _tFindAllLotLines)

// ✅ 每次上架都寫一筆 stock_ledger(inQty = 本次上架的庫存數量)
val _tDeltaCompute = System.nanoTime()
val putAwayDeltaStockQty = (request.inventoryLotLines ?: listOf()).sumOf { line ->
val stockItemUom = itemUomRepository.findBaseUnitByItemIdAndStockUnitIsTrueAndDeletedIsFalse(
itemId = request.itemId
@@ -967,10 +984,14 @@ open class StockInLineService(
}
convertedBaseQty
}
_logStep("compute_putAwayDeltaStockQty(+uom lookups per line)", _tDeltaCompute)
if (putAwayDeltaStockQty > BigDecimal.ZERO) {
val _tLedger = System.nanoTime()
createStockLedgerForStockIn(stockInLine, putAwayDeltaStockQty.toDouble())
_logStep("createStockLedgerForStockIn(includes findLatestByItemId)", _tLedger)
}

val _tQtyCalc = System.nanoTime()
val putAwayStockQty = inventoryLotLines.sumOf { it.inQty ?: BigDecimal.ZERO }

// PO-origin: acceptedQty is already STOCK qty; Non-PO: keep legacy rule (acceptQty is purchase qty)
@@ -986,8 +1007,10 @@ open class StockInLineService(
}
(request.acceptQty ?: request.acceptedQty)?.times(ratio) ?: BigDecimal.ZERO
}
_logStep("compute_putAwayStockQty_and_requiredStockQty(+uom lookups)", _tQtyCalc)

if (putAwayStockQty >= requiredStockQty) {
val _tStatus = System.nanoTime()
stockInLine.apply {
val isWipJobOrder = stockInLine.jobOrder?.bom?.description == "WIP"
this.status = if (isWipJobOrder) {
@@ -1009,7 +1032,9 @@ open class StockInLineService(
}
jobOrderRepository.save(jo!!)
}
_logStep("update_status_and_jobOrder_save", _tStatus)
}
_logStep("putaway_total", _tPutAwayTotal)
} else if (request.status == StockInLineStatus.PENDING.status || request.status == StockInLineStatus.ESCALATED.status) {
var escLogId : Long? = 0L;
// Escalation
@@ -1065,17 +1090,27 @@ open class StockInLineService(

saveQcResultWhenStockIn(request, stockInLine, escLogId)
}
val _tSaveFlush = System.nanoTime()
val savedStockInLine = saveAndFlush(stockInLine)
_logStep("saveAndFlush(stockInLine)", _tSaveFlush)
// check if all line completed
if (savedStockInLine.purchaseOrderLine != null) {
val pol = savedStockInLine.purchaseOrderLine
if (pol != null) {
val _tPol = System.nanoTime()
updatePurchaseOrderLineStatus(pol)
_logStep("updatePurchaseOrderLineStatus", _tPol)
val _tPo = System.nanoTime()
updatePurchaseOrderStatus(pol.purchaseOrder!!)
_logStep("updatePurchaseOrderStatus", _tPo)
}
}

val _tLineInfo = System.nanoTime()
val lineInfo = stockInLineRepository.findStockInLineInfoByIdAndDeletedFalse(savedStockInLine.id!!)
_logStep("findStockInLineInfoByIdAndDeletedFalse", _tLineInfo)

logger.info("[SIL.update timing] TOTAL took ${String.format("%.3f", (System.nanoTime() - _t0) / 1_000_000.0)} ms")

return MessageResponse(
id = savedStockInLine.id,
@@ -1263,32 +1298,51 @@ open class StockInLineService(
@Transactional

private fun createStockLedgerForStockIn(stockInLine: StockInLine, inQty: Double) {
val _t0 = System.nanoTime()
fun _msSince(t: Long): Double = (System.nanoTime() - t) / 1_000_000.0
fun _logStep(name: String, t: Long) {
logger.info("[SIL.ledger timing] $name took ${String.format("%.3f", _msSince(t))} ms")
}

val item = stockInLine.item ?: return

val _tInv = System.nanoTime()
val inventory = inventoryRepository.findFirstByItemIdAndDeletedIsFalseOrderByIdAsc(item.id!!) ?: return
// ✅ 修复:查询最新的 stock_ledger 记录,基于前一笔 balance 计算
val latestLedger = stockLedgerRepository.findLatestByItemId(item.id!!).firstOrNull()
// ✅ 修复:如果 latestLedger 为 null(第一次 stock in),previousBalance 应该是 0
// 因为 inventory.onHandQty 已经被触发器更新为包含本次 stock in 的数量
val previousBalance = latestLedger?.balance ?: 0.0
val newBalance = previousBalance + inQty

val stockLedger = StockLedger().apply {
this.stockInLine = stockInLine
this.inventory = inventory
this.inQty = inQty
this.outQty = null
this.balance = newBalance
this.type = stockInLine.type
this.itemId = item.id
this.itemCode = item.code
this.uomId = itemUomService.findStockUnitByItemId(item.id!!)?.uom?.id ?: inventory.uom?.id
this.date = LocalDate.now()
}
_logStep("inventoryRepository.findFirstByItemIdAndDeletedIsFalseOrderByIdAsc", _tInv)

// ✅ 修复:查询最新的 stock_ledger 记录,基于前一笔 balance 计算
val _tLatest = System.nanoTime()
val latestLedger = stockLedgerRepository.findFirstByItemIdAndDeletedFalseOrderByDateDescIdDesc(item.id!!)
_logStep("stockLedgerRepository.findLatestByItemId", _tLatest)

// ✅ 修复:如果 latestLedger 为 null(第一次 stock in),previousBalance 应该是 0
// 因为 inventory.onHandQty 已经被触发器更新为包含本次 stock in 的数量
val previousBalance = latestLedger?.balance ?: 0.0

val newBalance = previousBalance + inQty

val _tUom = System.nanoTime()
val stockUomId = itemUomService.findStockUnitByItemId(item.id!!)?.uom?.id ?: inventory.uom?.id
_logStep("itemUomService.findStockUnitByItemId", _tUom)

val stockLedger = StockLedger().apply {
this.stockInLine = stockInLine
this.inventory = inventory
this.inQty = inQty
this.outQty = null
this.balance = newBalance
this.type = stockInLine.type
this.itemId = item.id
this.itemCode = item.code
this.uomId = stockUomId
this.date = LocalDate.now()
}

val _tSave = System.nanoTime()
stockLedgerRepository.saveAndFlush(stockLedger)
_logStep("stockLedgerRepository.saveAndFlush", _tSave)

stockLedgerRepository.saveAndFlush(stockLedger)
logger.info("[SIL.ledger timing] TOTAL took ${String.format("%.3f", (System.nanoTime() - _t0) / 1_000_000.0)} ms")
}

@Transactional


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