[FEAT] B009 改為全量同步模式,硬刪除不在清單的貨道

1. 修改 MachineService@syncSlots 實作 B009 全量同步邏輯:同步完成後,找出資料庫中不在 B009 回報清單的舊貨道,先記流水帳再硬刪除,確保後台狀態與機台實體完全一致。
2. 新增 MachineStockMovement::TYPE_DECOMMISSION 常數,用於標識因 B009 全量同步而移除的貨道異動紀錄。
3. 新增多語系翻譯 key(zh_TW / en / ja):movement.note.slot_decommissioned_by_b009、movement.note.initial_sync_report、movement.note.product_changed_and_adjusted 與 movement.type.decommission。
This commit is contained in:
sky121113 2026-05-07 14:28:07 +08:00
parent e735e5a8c5
commit eb55a25ca8
5 changed files with 50 additions and 0 deletions

View File

@ -57,6 +57,7 @@ class MachineStockMovement extends Model
const TYPE_REMOTE_DISPENSE = 'remote_dispense'; // 遠端出貨 (B055 樂觀扣除)
const TYPE_ADJUSTMENT = 'adjustment'; // B009 回報 / 後台手動修改
const TYPE_ROLLBACK = 'rollback'; // B055 出貨失敗回退
const TYPE_DECOMMISSION = 'decommission'; // B009 全量同步時移除不在清單的貨道
// ─── 關聯 ───

View File

@ -265,6 +265,39 @@ class MachineService
}
}
}
// ─── B009 全量同步:移除不在清單中的貨道 ───
// 取得本次上報的所有貨道編號
$reportedSlotNos = collect($slotsData)
->pluck('slot_no')
->filter()
->map(fn($s) => (string) $s)
->values()
->toArray();
// 找出資料庫中屬於此機台但不在清單內的舊貨道
$orphanedSlots = $machine->slots()
->whereNotIn('slot_no', $reportedSlotNos)
->get();
foreach ($orphanedSlots as $orphan) {
$oldStock = (int) $orphan->stock;
// 先記流水帳(保留歷史可追溯性)
if ($oldStock > 0) {
$this->recordStockMovement(
$orphan,
-$oldStock,
MachineStockMovement::TYPE_DECOMMISSION,
null,
"movement.note.slot_decommissioned_by_b009",
['old' => $oldStock, 'new' => 0, 'slot_no' => $orphan->slot_no]
);
}
// 硬刪除貨道B009 全量同步,機台沒有就不該存在)
$orphan->delete();
}
});
}

View File

@ -1694,10 +1694,16 @@
"min": "min",
"mins ago": "mins ago",
"movement.type.adjustment": "Stock Adjustment",
"movement.type.decommission": "B009 Full Sync Removal",
"movement.type.pickup": "Pickup Code Consumed",
"movement.type.remote_dispense": "Remote Dispense",
"movement.type.replenishment": "Replenishment",
"movement.type.rollback": "Dispense Rollback",
"movement.note.initial_sync_report": "B009 initial sync: new slot :slot_no created with stock :new",
"movement.note.manual_adjustment": "Manual stock adjustment via admin (old: :old → new: :new)",
"movement.note.product_changed_and_adjusted": "B009 report: product changed and stock adjusted (:old → :new)",
"movement.note.replenishment_correction": "B009 inventory report correction (old: :old → new: :new)",
"movement.note.slot_decommissioned_by_b009": "B009 full sync: slot :slot_no not in report, stock :old cleared and slot removed",
"of": "of",
"of items": "of items",
"pending": "pending",

View File

@ -1680,10 +1680,16 @@
"min": "min",
"mins ago": "mins ago",
"movement.type.adjustment": "棚卸調整",
"movement.type.decommission": "B009 全量同期削除",
"movement.type.pickup": "受取コード消費",
"movement.type.remote_dispense": "リモート出庫",
"movement.type.replenishment": "補充入庫",
"movement.type.rollback": "出庫失敗ロールバック",
"movement.note.initial_sync_report": "B009 初回同期:新規レーン :slot_no を初期在庫 :new で登録",
"movement.note.manual_adjustment": "管理画面から手動在庫修正(旧: :old → 新: :new",
"movement.note.product_changed_and_adjusted": "B009 報告:商品変更と在庫調整 (:old → :new)",
"movement.note.replenishment_correction": "B009 棚卸報告修正(旧: :old → 新: :new",
"movement.note.slot_decommissioned_by_b009": "B009 全量同期:レーン :slot_no は報告リストにないため、在庫 :old をクリアして削除",
"of": "of",
"of items": "件のアイテム",
"pending": "pending",

View File

@ -1838,9 +1838,13 @@
"menu.warehouses.transfers": "調撥單",
"min": "分",
"mins ago": "分鐘前",
"movement.note.initial_sync_report": "B009 首次同步初始化貨道庫存(新增貨道: :slot_no初始庫存: :new",
"movement.note.manual_adjustment": "後台手動修改貨道庫存(舊: :old → 新: :new",
"movement.note.product_changed_and_adjusted": "B009 廢道商品變更並調整庫存(庫存 :old → :new",
"movement.note.replenishment_correction": "B009 盤點回報修正(舊: :old → 新: :new",
"movement.note.slot_decommissioned_by_b009": "B009 全量同步:貨道 :slot_no 不在回報清單中,庫存 :old 歸零並移除",
"movement.type.adjustment": "盤點調整",
"movement.type.decommission": "B009 全量同步移除",
"movement.type.pickup": "取貨碼消耗",
"movement.type.remote_dispense": "遠端出貨",
"movement.type.replenishment": "補貨入庫",