From 90fd8b37eed8a508cf8ac7a33eb42cc16b00156a Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 29 Sep 2026 16:10:12 +0800 Subject: [PATCH] 2.4,2.5 fix --- .../ledgerfix/StockLedgerFixAdjService.kt | 9 ++-- .../StockLedgerFixBackfillService.kt | 42 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixAdjService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixAdjService.kt index 6b97b641..6cd69bdb 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixAdjService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixAdjService.kt @@ -1,5 +1,6 @@ package com.ffii.fpsms.modules.master.service.ledgerfix +import com.ffii.fpsms.modules.common.SecurityUtils import com.ffii.fpsms.modules.master.web.models.StockLedgerFixAdjPreview import com.ffii.fpsms.modules.master.web.models.StockLedgerFixAdjResponse import com.ffii.fpsms.modules.master.web.models.StockLedgerFixAdjRow @@ -439,17 +440,19 @@ open class StockLedgerFixAdjService( ).orElse(null) if (existing != null) return support.toLong(existing["id"]) val at = adjDate.atTime(12, 0) + val handlerId = SecurityUtils.getUser().orElse(null)?.id + ?: throw IllegalStateException("stock-ledger-fix: login user required for stock_out.handlerId") return insertReturningId( """ INSERT INTO stock_out ( created, createdBy, version, modified, modifiedBy, deleted, - type, completeDate, status, remarks + type, completeDate, status, remarks, handlerId ) VALUES ( NOW(), 'stock-ledger-fix', 0, NOW(), 'stock-ledger-fix', 0, - 'ADJ', :at, 'completed', :remarks + 'ADJ', :at, 'completed', :remarks, :handlerId ) """.trimIndent(), - mapOf("at" to at, "remarks" to remarks), + mapOf("at" to at, "remarks" to remarks, "handlerId" to handlerId), ) } diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixBackfillService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixBackfillService.kt index e6ffce3b..2dbf3f02 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixBackfillService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ledgerfix/StockLedgerFixBackfillService.kt @@ -439,6 +439,8 @@ open class StockLedgerFixBackfillService( /** * 2.4 Opening = last lotQtyAfter before the window start (yesterday first, then lookback). + * Lookback: latest date before yesterday, then MAX(id) on that date. MAX(id) over all + * older rows picks a backdated insert (higher id, earlier date) and skips later receipts. * Idle days must not reset to 0. Window is :day .. :dayNext (one day or a range). */ private fun fillLotQty(args: Map): Int { @@ -529,12 +531,19 @@ open class StockLedgerFixBackfillService( INNER JOIN ( SELECT sl.inventoryLotLineId, MAX(sl.id) AS maxId FROM stock_ledger sl + INNER JOIN ( + SELECT s.inventoryLotLineId, MAX(s.date) AS maxDate + FROM stock_ledger s + INNER JOIN tmp_sl_fix_lot_miss m + ON m.inventoryLotLineId = s.inventoryLotLineId + WHERE s.deleted = 0 + AND s.date < :prevDay + AND s.lotQtyAfter IS NOT NULL + GROUP BY s.inventoryLotLineId + ) d ON d.inventoryLotLineId = sl.inventoryLotLineId + AND d.maxDate = sl.date WHERE sl.deleted = 0 - AND sl.date < :prevDay AND sl.lotQtyAfter IS NOT NULL - AND sl.inventoryLotLineId IN ( - SELECT inventoryLotLineId FROM tmp_sl_fix_lot_miss - ) GROUP BY sl.inventoryLotLineId ) x ON x.maxId = slp.id """.trimIndent(), @@ -593,6 +602,8 @@ open class StockLedgerFixBackfillService( * 2.5 Running balance per inventoryId. * Opening = last balance before the window. Fast path: day before :day. Lookback only for * inventoryIds that had no row that day (idle days must not reset to 0). + * Lookback: latest date before yesterday, then MAX(id) on that date. MAX(id) over all + * older rows picks a backdated insert and skips receipts dated after that row. * Window is :day .. :dayNext (one day or a range). */ private fun fillBalance(args: Map): Int { @@ -683,12 +694,19 @@ open class StockLedgerFixBackfillService( INNER JOIN ( SELECT sl.inventoryId, MAX(sl.id) AS maxId FROM stock_ledger sl + INNER JOIN ( + SELECT s.inventoryId, MAX(s.date) AS maxDate + FROM stock_ledger s + INNER JOIN tmp_stock_ledger_fix_miss m + ON m.inventoryId = s.inventoryId + WHERE s.deleted = 0 + AND s.date < :prevDay + AND s.balance IS NOT NULL + GROUP BY s.inventoryId + ) d ON d.inventoryId = sl.inventoryId + AND d.maxDate = sl.date WHERE sl.deleted = 0 - AND sl.date < :prevDay AND sl.balance IS NOT NULL - AND sl.inventoryId IN ( - SELECT inventoryId FROM tmp_stock_ledger_fix_miss - ) GROUP BY sl.inventoryId ) x ON x.maxId = slp.id """.trimIndent(), @@ -1131,7 +1149,7 @@ open class StockLedgerFixBackfillService( ).map { support.toLong(it["id"]) }.filter { it > 0 } } - internal fun dateRangeForFilter(filter: String, args: Map): Pair? { + open internal fun dateRangeForFilter(filter: String, args: Map): Pair? { val row = support.jdbcDao.queryForList( """ SELECT MIN(date) AS firstDate, MAX(date) AS lastDate @@ -1149,7 +1167,7 @@ open class StockLedgerFixBackfillService( return first to toExclusive } - internal fun upsertStockLotDayRange(lotIds: List, from: LocalDate, toExclusive: LocalDate): Int { + open internal fun upsertStockLotDayRange(lotIds: List, from: LocalDate, toExclusive: LocalDate): Int { if (lotIds.isEmpty()) return 0 return support.jdbcDao.executeUpdate( """ @@ -1259,7 +1277,7 @@ open class StockLedgerFixBackfillService( ) } - internal fun fillLotQtyForLotIds(lotIds: List, today: LocalDate): Int { + open internal fun fillLotQtyForLotIds(lotIds: List, today: LocalDate): Int { if (lotIds.isEmpty()) return 0 return support.withTempTx { support.jdbcDao.executeUpdate("DROP TEMPORARY TABLE IF EXISTS tmp_sl_fix_adj_lots") @@ -1313,7 +1331,7 @@ open class StockLedgerFixBackfillService( } /** Chain balance on new ADJ rows only; older rows for the same SKU are unchanged. */ - internal fun fillBalanceOnNewAdjRows(adjDate: LocalDate, today: LocalDate): Int { + open internal fun fillBalanceOnNewAdjRows(adjDate: LocalDate, today: LocalDate): Int { val rows = support.jdbcDao.queryForList( """ SELECT id, inventoryId,