代表一個可存放庫存的地點 * rental_stock_reservations
預約訂單的數量提前管控表 * product_stock_reservations
商品訂單的數量提前管控表
order_items
└─ 1:N product_stock_reservations
└─ N:1 inventory_locations(inventory_domain = store)
booking_selected_rentals
└─ 1:N rental_stock_reservations
└─ N:1 inventory_locations(inventory_domain = rental)
inventory_locations
├─ 1:N product_stock_reservations
└─ 1:N rental_stock_reservations
(order_item_id, variant_id) 複合外鍵連至 order_items,確認保留的規格確實屬於該訂單明細。(booking_selected_rental_id, rental_sku_variant_id) 複合外鍵連至 booking_selected_rentals,確認保留的租借規格確實屬於該預約明細。(location_id, inventory_domain) 複合外鍵連至 inventory_locations,且 inventory_domain 固定為 store。(location_id, inventory_domain) 複合外鍵連至 inventory_locations,且 inventory_domain 固定為 rental。ON UPDATE CASCADE ON DELETE RESTRICT;已存在保留帳的訂單、預約或地點不可直接刪除。商城訂單保留:
order_items 後,依選取規格與出貨地點建立 product_stock_reservations。status = active 時,數量仍被暫時保留;可設定 expires_at 供逾時釋放。released 或 expired,並填入 released_at。fulfilled,並填入 fulfilled_at。租借預約保留:
booking_selected_rentals 後,依租借 SKU 規格、取用地點與入住區間建立 rental_stock_reservations。status = active 時,[check_in, check_out) 區間內的可用數量必須扣除該保留數量。released 並填入 released_at;完成租借時改為 fulfilled 並填入 fulfilled_at。expired 狀態;其有效性依預約業務流程決定。id 保留帳流水號
GENERATED BY DEFAULT AS IDENTITY。
order_item_id 訂單明細識別碼;
與 variant_id 複合外鍵指向 order_items。
idx_product_stock_reservations_order_item ON (order_item_id)
location_id 商城庫存地點;
與 inventory_domain 複合外鍵指向 inventory_locations。
0。active、released、fulfilled、expired;預設 active。now()。reserved_at。inventory_domain 固定為 store
idx_product_stock_reservations_active_lookup ON (variant_id、location_id),條件:status = active
idx_product_stock_reservations_expiry ON (expires_at),條件:status = active AND expires_at IS NOT NULL
id 保留帳流水號
GENERATED BY DEFAULT AS IDENTITY。
booking_selected_rental_id 預約租借明細識別碼;
與 rental_sku_variant_id 複合外鍵指向 booking_selected_rentals。
idx_rental_stock_reservations_booking_item ON (booking_selected_rental_id)
location_id 租借庫存地點;
與 inventory_domain 複合外鍵指向 inventory_locations。
check_in。0。active、released、fulfilled;預設 active。now()。inventory_domain 固定為 rental,預設 rental。
idx_rental_stock_reservations_active_range ON (rental_sku_variant_id、location_id、check_in、check_out),條件:status = active
inventory_domain 庫存類型,只允許 store 或 rental。
type 分類至store/rental 後的狀態
store 只允許 main、branch、inspection、repair、damaged。
rental 只允許 main、campground、inspection、repair、damaged。
branch_id 所屬門市,NULL;只有 type = branch 且 inventory_domain = store 時必填
type 非 branch 時必須為 NULL。
idx_inventory_locations_branch ON (branch_id)
true。now()。now();DDL 未定義自動更新 Trigger。CHECK:庫存領域、地點類型,以及門市類型與 branch_id 的相容性。
idx_inventory_locations_domain_type_active ON (inventory_domain、type、active)
product_stock_reservationsrental_stock_reservationsinventory_locationsactive 保留數量。active 保留數量。active,以避免庫存稽核鏈被覆寫。released、expired 代表數量已歸還可用池;fulfilled 代表該保留已完成業務履約。latest_schema.sql 沒有以 Trigger 實作保留帳生命週期;正式後端必須負責狀態轉換、期限與庫存一致性驗證。pages/checkout.html
↓
js/pages/checkout.js
↓
window.API.orders.create(orderData)
↓
js/api-mock.js
↓
localStorage.mockOrders
product_stock_reservations。rental_stock_reservations,並依 [check_in, check_out) 重疊條件計算可租量。released 並填入 released_at。tools/database-validation/validation/validate_inventory.sql 第 24–36 行檢查保留帳是否仍有對應實體庫存列。tools/database-validation/validation/p5-data.sql 第 204–207 行檢查兩張表的 inventory_domain 是否固定為正確領域。expires_at 為 NULL;服務層必須定義無到期時間的有效使用情境,避免永久 active 保留。[check_in, check_out) 語意,否則相鄰租期可能被錯誤判定為衝突。inventory_locations.active 不會自動阻止既有保留帳或新建保留帳;服務層應禁止對停用地點建立新的保留。