瀏覽代碼

Liquibase 20260910:#1 stockUomId、#2–3 Option A trigger、#35 index

上線 app:#5 entity、#7 available = onHand − unavailable、#8 搜尋全 bucket、#34 Resolver(#10/#11 已接)
Admin 1.0:補 stockUomId、uomId=base(這就是 #1 的 data patch)
2.3 把 ledger 綁到該 bucket
2.7:先超發 remain→0(改 lot),再 miss;共用一張入倉單、一張出倉單
2.6 日結
fix負數倉
CANCERYS\kw093 6 天之前
父節點
當前提交
ca36da92f2
共有 2 個文件被更改,包括 28 次插入15 次删除
  1. +7
    -0
      src/app/api/stockLedgerFix/client.ts
  2. +21
    -15
      src/components/StockLedgerFix/StockLedgerFixPageClient.tsx

+ 7
- 0
src/app/api/stockLedgerFix/client.ts 查看文件

@@ -52,12 +52,15 @@ export type StockLedgerFixInventoryPreview = {
inventoryRows: number;
lotUomPairs: number;
missingUomPairs: number;
nullStockUomId: number;
};

export type StockLedgerFixInventoryResponse = {
inserted: number;
updated: number;
missingUomPairsAfter: number;
patchedStockUomId: number;
nullStockUomIdAfter: number;
};

export type StockLedgerFixSearchInventoryHit = {
@@ -101,6 +104,7 @@ export type StockLedgerFixAdjRow = {
ledgerOut: string;
missIn: string;
missOut: string;
overIssue: string;
};

export type StockLedgerFixAdjPreview = {
@@ -112,6 +116,8 @@ export type StockLedgerFixAdjPreview = {
sumMissIn: string;
sumMissOut: string;
skuNet: string;
overIssueCount: number;
sumOverIssue: string;
rows: StockLedgerFixAdjRow[];
};

@@ -119,6 +125,7 @@ export type StockLedgerFixAdjResponse = {
adjDate: string;
insertedIn: number;
insertedOut: number;
overIssuePatched: number;
filledLotQty: number;
filledBalance: number;
dayRowsWritten: number;


+ 21
- 15
src/components/StockLedgerFix/StockLedgerFixPageClient.tsx 查看文件

@@ -93,7 +93,7 @@ const EXPORT_PART_LABEL: Record<ExportPart, string> = {
"2.3": "2.3 inventoryId",
ledger: "ledger lot/uom/lotQty/balance",
"2.6": "2.6 日結",
"2.7": "2.7 ADJ INSERT",
"2.7": "2.7 ADJ+入出倉單",
};

function selectedExportParts(flags: Record<ExportPart, boolean>): ExportPart[] {
@@ -426,7 +426,7 @@ const StockLedgerFixPageClient: React.FC = () => {
const onInventory = async () => {
if (inventoryRunInFlight.current) return;
const ok = window.confirm(
"方案 A:保留現有 inventory.id,補缺 (itemId, uomId),並用 lot 的 in−out 重算全部數量。沒有 lot 的 UOM 會變成 0。不會改 inventory_lot_line。確定執行?",
"方案 A:保留現有 inventory.id;從 lot 回填 stockUomId(舊 uomId 是 stock 則改回 base);補缺 (itemId, stockUomId);用 lot 的 in−out 重算 onHand/unavailable。不寫 onHoldQty、不改 inventory_lot_line。確定執行?",
);
if (!ok) return;
inventoryRunInFlight.current = true;
@@ -436,7 +436,7 @@ const StockLedgerFixPageClient: React.FC = () => {
try {
const res = await runStockLedgerFixInventory();
setInventoryMessage(
`inventory 1.0 完成:新增 ${res.inserted} 列、重算 ${res.updated} 列、之後仍缺 UOM ${res.missingUomPairsAfter}`,
`inventory 1.0 完成:回填 stockUomId ${res.patchedStockUomId} 列、新增 ${res.inserted} 列、重算 ${res.updated} 列、之後仍缺 UOM ${res.missingUomPairsAfter}、仍 NULL stockUomId ${res.nullStockUomIdAfter}`,
);
await loadInventory();
} catch (e) {
@@ -456,7 +456,7 @@ const StockLedgerFixPageClient: React.FC = () => {
return;
}
const ok = window.confirm(
`會在 ${d} 新增 ADJ:入向 ${adjPreview?.adjInCount ?? 0} 筆、出向 ${adjPreview?.adjOutCount ?? 0} 筆(含反向調整)。缺入合計 ${adjPreview?.sumMissIn ?? "?"}、缺出合計 ${adjPreview?.sumMissOut ?? "?"}。目標:每 lot 最後 lotQtyAfter = line remain。已對齊的 lot 不會再動。確定?`,
`會在 ${d} 先修超發 remain→0(${adjPreview?.overIssueCount ?? 0} 條 lot,合計 ${adjPreview?.sumOverIssue ?? "?"},會改 lot inQty)。再補 miss ADJ:入向 ${adjPreview?.adjInCount ?? 0} 筆、出向 ${adjPreview?.adjOutCount ?? 0} 筆。入向全部掛同一張入倉單、出向全部掛同一張出倉單(miss 不改 lot 數量)。缺入合計 ${adjPreview?.sumMissIn ?? "?"}、缺出合計 ${adjPreview?.sumMissOut ?? "?"}。確定?`,
);
if (!ok) return;
adjRunInFlight.current = true;
@@ -466,7 +466,7 @@ const StockLedgerFixPageClient: React.FC = () => {
try {
const res = await runStockLedgerFixAdj(d);
setAdjMessage(
`ADJ ${res.adjDate}:入 ${res.insertedIn}、出 ${res.insertedOut}、lotQty ${res.filledLotQty}、balance ${res.filledBalance}、日結 ${res.dayRowsWritten}`,
`ADJ ${res.adjDate}:超發 remain→0 ${res.overIssuePatched}、入 ${res.insertedIn}、出 ${res.insertedOut}、lotQty ${res.filledLotQty}、balance ${res.filledBalance}、日結 ${res.dayRowsWritten}`,
);
await loadAdjPreview();
} catch (e) {
@@ -631,7 +631,7 @@ const StockLedgerFixPageClient: React.FC = () => {
const steps = stepsPayload(daySteps);
const stepLabel = steps?.join("、") ?? "全部 2.1–2.6";
const ok = window.confirm(
`一次修 ${from} → ${to}(步驟:${stepLabel})。2.1–2.5 整段一次算、2.6 仍依日寫日結。過程中無法中停。確定?`,
`一次修 ${from} → ${to}(步驟:${stepLabel})。改為逐日跑(每天 commit)。中途失敗時已跑完的天會留下。確定?`,
);
if (!ok) return;

@@ -724,7 +724,8 @@ const StockLedgerFixPageClient: React.FC = () => {
<Typography variant="body2">
現有 inventory {inventoryPreview.inventoryRows} 列;lot 的
item+UOM {inventoryPreview.lotUomPairs} 組;缺{" "}
{inventoryPreview.missingUomPairs} 組。
{inventoryPreview.missingUomPairs} 組;stockUomId 仍 NULL{" "}
{inventoryPreview.nullStockUomId} 列。
</Typography>
)}
<Box>
@@ -742,11 +743,13 @@ const StockLedgerFixPageClient: React.FC = () => {

<Paper sx={{ p: 2 }}>
<Stack spacing={1.5}>
<Typography variant="h6">2.7 ADJ:line in/out 對齊 ledger</Typography>
<Typography variant="h6">2.7 ADJ:超發 remain→0,再對齊 ledger</Typography>
<Typography variant="body2" color="text.secondary">
請先選 ADJ 日期再預覽。預設昨天;freeze dump 夜可選今天(例如 31/8 23:17 寫 ADJ 到
31/8)。比對每 lot 的 line in/out 與 ledger 加總;有差就 ADJ。目標:最後一筆
lotQtyAfter = line remain。明細最多 20 列。
31/8)。先處理超發(line 入少於出):把該 lot 的 inQty 補到等於 outQty(remain=0,trigger
重算 inventory)。再處理 miss:line 與 ledger 有差就 ADJ,掛既有 lot 的入/出倉行(不改 lot
數量)。一次 Apply 共用一張入倉單、一張出倉單,下面多行;同一 ADJ 日期再跑會沿用這兩張單。
明細最多 20 列。
</Typography>
<Stack direction="row" spacing={1} alignItems="center" flexWrap="wrap" useFlexGap>
<TextField
@@ -789,15 +792,16 @@ const StockLedgerFixPageClient: React.FC = () => {
{adjLoading && !adjPreview && <CircularProgress size={24} />}
{adjPreview && (
<Typography variant="body2">
ADJ 日期 {adjPreview.adjDate};可補 {adjPreview.lotCount} 條
lot(入 {adjPreview.adjInCount}、出 {adjPreview.adjOutCount});缺入合計{" "}
ADJ 日期 {adjPreview.adjDate};可處理 {adjPreview.lotCount} 條
lot(超發 remain→0 {adjPreview.overIssueCount}、合計 {adjPreview.sumOverIssue};miss 入{" "}
{adjPreview.adjInCount}、出 {adjPreview.adjOutCount});缺入合計{" "}
{adjPreview.sumMissIn}、缺出合計 {adjPreview.sumMissOut};SKU 淨額{" "}
{adjPreview.skuNet}
{adjPreview.skuNet !== "0" ? "(非 0 表示有缺入沒有對應缺出)" : ""}
{adjPreview.skippedNegCount > 0
? `;含反向 ADJ ${adjPreview.skippedNegCount} 條(ledger 多記)`
: ""}
。下列最多 20 列。
。下列最多 20 列(超發優先)
</Typography>
)}
{adjPreview && adjPreview.rows.length > 0 && (
@@ -810,6 +814,7 @@ const StockLedgerFixPageClient: React.FC = () => {
<TableCell align="right">ledger in/out</TableCell>
<TableCell align="right">缺入</TableCell>
<TableCell align="right">缺出</TableCell>
<TableCell align="right">超發</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -825,6 +830,7 @@ const StockLedgerFixPageClient: React.FC = () => {
</TableCell>
<TableCell align="right">{r.missIn}</TableCell>
<TableCell align="right">{r.missOut}</TableCell>
<TableCell align="right">{r.overIssue}</TableCell>
</TableRow>
))}
</TableBody>
@@ -949,7 +955,7 @@ const StockLedgerFixPageClient: React.FC = () => {
區間修(2.1–2.6 一次)
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
使用上面勾的步驟,整段日期一次 API。2.1–2.5 用同一視窗算完;2.6 日結仍依日寫入。可含今天(freeze dump 夜)。最長約 20 分鐘
使用上面勾的步驟,一次 API 但改為逐日(與單日修相同 SQL,每天 commit)。可含今天(freeze dump 夜)。前端最長約 20 分鐘;大區間仍建議匯出 SQL
</Typography>
<Stack direction="row" spacing={1} alignItems="center" flexWrap="wrap" useFlexGap>
<TextField
@@ -984,7 +990,7 @@ const StockLedgerFixPageClient: React.FC = () => {
匯出已修 SQL(新庫用)
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
勾選要匯出的段落(同日修步驟)。套檔順序:1.0 → ledger(±2.3)→ 2.7 INSERT →
勾選要匯出的段落(同日修步驟)。套檔順序:1.0 → ledger(±2.3)→ 2.7 入出倉單+ADJ INSERT →
2.6。完整檔(含 1.0+2.3)且正式庫 freeze/id 同源時,可跳過正式庫 1.0/2.3。預設只匯
ledger+日結(舊行為)。
</Typography>


Loading…
取消
儲存