|
|
@@ -439,6 +439,8 @@ open class StockLedgerFixBackfillService( |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 2.4 Opening = last lotQtyAfter before the window start (yesterday first, then lookback). |
|
|
* 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). |
|
|
* Idle days must not reset to 0. Window is :day .. :dayNext (one day or a range). |
|
|
*/ |
|
|
*/ |
|
|
private fun fillLotQty(args: Map<String, Any>): Int { |
|
|
private fun fillLotQty(args: Map<String, Any>): Int { |
|
|
@@ -529,12 +531,19 @@ open class StockLedgerFixBackfillService( |
|
|
INNER JOIN ( |
|
|
INNER JOIN ( |
|
|
SELECT sl.inventoryLotLineId, MAX(sl.id) AS maxId |
|
|
SELECT sl.inventoryLotLineId, MAX(sl.id) AS maxId |
|
|
FROM stock_ledger sl |
|
|
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 |
|
|
WHERE sl.deleted = 0 |
|
|
AND sl.date < :prevDay |
|
|
|
|
|
AND sl.lotQtyAfter IS NOT NULL |
|
|
AND sl.lotQtyAfter IS NOT NULL |
|
|
AND sl.inventoryLotLineId IN ( |
|
|
|
|
|
SELECT inventoryLotLineId FROM tmp_sl_fix_lot_miss |
|
|
|
|
|
) |
|
|
|
|
|
GROUP BY sl.inventoryLotLineId |
|
|
GROUP BY sl.inventoryLotLineId |
|
|
) x ON x.maxId = slp.id |
|
|
) x ON x.maxId = slp.id |
|
|
""".trimIndent(), |
|
|
""".trimIndent(), |
|
|
@@ -593,6 +602,8 @@ open class StockLedgerFixBackfillService( |
|
|
* 2.5 Running balance per inventoryId. |
|
|
* 2.5 Running balance per inventoryId. |
|
|
* Opening = last balance before the window. Fast path: day before :day. Lookback only for |
|
|
* 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). |
|
|
* 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). |
|
|
* Window is :day .. :dayNext (one day or a range). |
|
|
*/ |
|
|
*/ |
|
|
private fun fillBalance(args: Map<String, Any>): Int { |
|
|
private fun fillBalance(args: Map<String, Any>): Int { |
|
|
@@ -683,12 +694,19 @@ open class StockLedgerFixBackfillService( |
|
|
INNER JOIN ( |
|
|
INNER JOIN ( |
|
|
SELECT sl.inventoryId, MAX(sl.id) AS maxId |
|
|
SELECT sl.inventoryId, MAX(sl.id) AS maxId |
|
|
FROM stock_ledger sl |
|
|
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 |
|
|
WHERE sl.deleted = 0 |
|
|
AND sl.date < :prevDay |
|
|
|
|
|
AND sl.balance IS NOT NULL |
|
|
AND sl.balance IS NOT NULL |
|
|
AND sl.inventoryId IN ( |
|
|
|
|
|
SELECT inventoryId FROM tmp_stock_ledger_fix_miss |
|
|
|
|
|
) |
|
|
|
|
|
GROUP BY sl.inventoryId |
|
|
GROUP BY sl.inventoryId |
|
|
) x ON x.maxId = slp.id |
|
|
) x ON x.maxId = slp.id |
|
|
""".trimIndent(), |
|
|
""".trimIndent(), |
|
|
@@ -1131,7 +1149,7 @@ open class StockLedgerFixBackfillService( |
|
|
).map { support.toLong(it["id"]) }.filter { it > 0 } |
|
|
).map { support.toLong(it["id"]) }.filter { it > 0 } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal fun dateRangeForFilter(filter: String, args: Map<String, Any>): Pair<LocalDate, LocalDate>? { |
|
|
|
|
|
|
|
|
open internal fun dateRangeForFilter(filter: String, args: Map<String, Any>): Pair<LocalDate, LocalDate>? { |
|
|
val row = support.jdbcDao.queryForList( |
|
|
val row = support.jdbcDao.queryForList( |
|
|
""" |
|
|
""" |
|
|
SELECT MIN(date) AS firstDate, MAX(date) AS lastDate |
|
|
SELECT MIN(date) AS firstDate, MAX(date) AS lastDate |
|
|
@@ -1149,7 +1167,7 @@ open class StockLedgerFixBackfillService( |
|
|
return first to toExclusive |
|
|
return first to toExclusive |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal fun upsertStockLotDayRange(lotIds: List<Long>, from: LocalDate, toExclusive: LocalDate): Int { |
|
|
|
|
|
|
|
|
open internal fun upsertStockLotDayRange(lotIds: List<Long>, from: LocalDate, toExclusive: LocalDate): Int { |
|
|
if (lotIds.isEmpty()) return 0 |
|
|
if (lotIds.isEmpty()) return 0 |
|
|
return support.jdbcDao.executeUpdate( |
|
|
return support.jdbcDao.executeUpdate( |
|
|
""" |
|
|
""" |
|
|
@@ -1259,7 +1277,7 @@ open class StockLedgerFixBackfillService( |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal fun fillLotQtyForLotIds(lotIds: List<Long>, today: LocalDate): Int { |
|
|
|
|
|
|
|
|
open internal fun fillLotQtyForLotIds(lotIds: List<Long>, today: LocalDate): Int { |
|
|
if (lotIds.isEmpty()) return 0 |
|
|
if (lotIds.isEmpty()) return 0 |
|
|
return support.withTempTx { |
|
|
return support.withTempTx { |
|
|
support.jdbcDao.executeUpdate("DROP TEMPORARY TABLE IF EXISTS tmp_sl_fix_adj_lots") |
|
|
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. */ |
|
|
/** 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( |
|
|
val rows = support.jdbcDao.queryForList( |
|
|
""" |
|
|
""" |
|
|
SELECT id, inventoryId, |
|
|
SELECT id, inventoryId, |
|
|
|