一句話:登山模組下「裝備品項 / 庫存 / 梯次裝備需求」的彙總與庫存警示資料模型;已落地(主檔 race-safe 庫存 + per-order 租借 + 跨梯次需求彙總),本檔描述現行 schema 與演算法。
🟩 登山模組 — 受 模組化 的「登山」開關 gate(裝備租借是登山模組專屬子集之一)。
裝備有兩條正交並存的線:per-order 租借(旅客實際借出,掛 order、走金流)與 per-departure 需求調查 + 跨梯次彙總(線控盤點哪梯次要借多少、會不會超收)。兩者共用同一份裝備主檔 equipment_items,庫存以主檔的 race-safe out_count 為唯一真相。
apps/wireframes/app/admin/equipment)· 團控分房(住宿與裝備在 GS 同「住宿裝備資料連動」模式)· 金流模型(租金 / 押金經 order_charge_lines 接金流)GS「裝備住宿-裝備」分頁把各行程的裝備需求以 睡墊*3 登山杖*2 字串記錄,跨日期窗用 SUMPRODUCT + REGEXEXTRACT 彙總各品項總需求,再比庫存上限:庫存 − 需求 < 0 → 超收(缺)、剩餘 ≤ 2 → 提示剩餘 N(庫存警示),另算現場付現金額(品項 × 每日價目表)。GS 7 類裝備、各有租借上限與每日價目(見 §2)。
ERP 把這個模型還原為兩條線:旅客真借的 per-order 租借單(race-safe 扣庫存 + 金流),以及線控盤梯次需求的 per-departure 需求調查 + 跨梯次彙總警示。庫存真相落在主檔 equipment_items 的 out_count(在租量),不再靠字串 parse。
equipment_items全站級品項主檔(DB per tenant,無 tenant_id)。關鍵欄位(精確型別看 packages/core/src/schema/business.ts):
name / category / spec:品名、分類、規格。GS 7 類 seed(scripts/seed.ts seedEquipmentItems,以 name 為自然鍵 idempotent):
| 品項 | 分類 | 庫存上限 total_count | 每日租金 rent_price_twd |
|---|---|---|---|
| 登山杖 | 行進 | 7 | 150 |
| 睡墊 | 睡眠 | 19 | 100 |
| 頭燈 | 照明 | 13 | 100 |
| 睡袋 | 睡眠 | 8 | 200 |
| 岩盔 | 雪攀 | 15 | 200 |
| 冰爪 | 雪攀 | 16 | 200 |
| 冰斧 | 雪攀 | 14 | 300 |
rent_price_twd / deposit_twd:每日租金 / 押金(整數 TWD)。
庫存三量:total_count(庫存上限)、out_count(在租,race-safe 扣減的真相,不可手改)、maintenance_count(維修中)。可租 = total − out − maintenance(派生)。
DB CHECK out_count + maintenance_count <= total_count 為最後兜底;建檔 out_count 一律從 0 起(在租量只由租借單扣減)。
equipment_rentals + equipment_rental_lines)旅客實際借出,掛 order、可選掛 departure。明細存成交租金 / 押金快照(改主檔不回寫單)。
UPDATE equipment_items SET out_count = out_count + N WHERE id = .. AND out_count + maintenance_count + N <= total_count;影響 0 列 → EquipmentStockError,整個 tx rollback。recalculateOrderRoomUpgrade):租金 append type='equipment_rental' charge line、押金 append type='equipment_deposit'(代收暫收)charge line,並為新增應收開 adjustment payment_schedule + intent,鎖 order 重算 payment_state / refund_state —— 全在 createRental 同一 tx。out_count、設 return_state='returned';有破損賠償 → recon_state='deposit_pending'。歸還不動 charge line、不自建出款 / 退款;押金退款一律走既有 refunds flow(會計事後手動發起,沖正 charge line + 出款);破損保留不退的部分 = 該 equipment_deposit charge 留著轉收入。markOverdueRentals(per-tenant cron)把過租期末日且仍 rented 的單轉 overdue(不動庫存)。線控在某梯次盤點要借多少(未必等於旅客已真借),並看同日期窗其他梯次會不會把庫存吃光。
departure_equipment_needs:每梯次每品項一筆需求(UNIQUE departure_id + equipment_item_id,再加同品項 = 覆寫數量非累加;quantity 正整數)。repo 在 packages/core/src/departure-prep/repo.ts(listEquipmentNeeds / upsertEquipmentNeed / deleteEquipmentNeed)。summarizeEquipmentDemand({ start, endExclusive }):把日期窗 [start, endExclusive) 內(依梯次 departure_date 落窗)各梯次對每個 item 的需求加總,對比主檔可租庫存:
totalDemand = Σ quantity(窗內各梯次該 item 需求)availableCount = total − out − maintenance(主檔可租)surplus = availableCount − totalDemandshortage = surplus < 0(需求 > 庫存 → 缺,還原 GS「超收」)lowStock(剩餘 ≤ 2):surplus >= 0 && surplus <= 2,還原 GS「剩餘 ≤2 才提示」的低水位警示(Alert 黃燈)。shortage(紅)與 lowStock(黃)互斥。departure_date ± N 天,或某月)。用途:某梯次調查需求時提醒同窗其他梯次也借同款導致超收 / 低水位。GS 有「現場付」偵測(品項 × 每日價目表)。GS 價目表以「晚數」計,不是含頭尾天數:1 日與 2 日同價(= base)、3 日 ×2、4 日 ×3,即
租金 =
rent_price_twd× max(1, 含頭尾天數 − 1) × 數量
(玉山 2/27–28 = 2 天 1 夜 → ×1 = base;雪季 3 天 2 夜 → ×2。原始 GS「裝備住宿-裝備」價目表佐證見 荒野旅人ERP溝通範本.xlsx。)
已落地(估算側):per-departure 裝備需求調查(出團前準備「裝備」tab)顯示每列 + 合計的現場付現估算 = 需求量 × max(1, 含頭尾天數 − 1) × rent_price_twd,其中含頭尾天數 = 梯次 departure_date → return_date。listEquipmentNeeds 帶 rentPriceTwd、日數於 page 由梯次日期算、估算在 UI 派生(不落 DB)。此為線控盤點用的現場付現參考。
per-order 租借側計價(決策:按天數計費,2026-07-01):旅客實際租金一律套本節 GS 規則 rent_price_twd × max(1, 含頭尾天數 − 1) × 數量,與估算側同公式。rent_price_twd_snapshot 語意 = 快照「成交每日單價 × 計價日數」的單位總價,使 rentTotalTwd = Σ snapshot × qty 維持成立,同步 rentTotalTwd / depositTotalTwd reducer 與測試。兩條線(估算 / 真借)並存不重複扣款。
已落地:
createRental按天數計費 —— 租金 =rent_price_twd × max(1, 含頭尾天數 − 1) × 數量(含頭尾天數 = 租期start_date → end_date),rent_price_twd_snapshot存快照後的單位總價使rentTotalTwd = Σ snapshot × qty成立;押金不乘天數(deposit_twd × 數量,一次性代收暫收)。與估算側同公式、兩條線並存不重複扣款。
apps/wireframes/app/admin/equipment 為 UI 真相)。/admin/control/[depId]/departure-prep)。requirePermission(resource.action);audit 由 action 層寫(比照 group-codes-repo / departure-costs)。equipment_rental / equipment_deposit charge line)| 版本 | 日期 | 變更 | Commit |
|---|---|---|---|
| 1 | 2026-05-30 | 初版 stub:登錄缺口 + 資料模型草圖(財務確認 GS 已有替代,佔位待排程) | — |
| 2 | 2026-06-23 | 從 stub 扶正到現行 schema:equipment_items(race-safe 庫存三量 + GS 7 類 seed + 庫存上限/每日價目)、per-order 租借(equipment_rentals,接 equipment_rental/equipment_deposit charge line)、per-departure 需求調查(departure_equipment_needs)+ 跨梯次彙總 summarizeEquipmentDemand(surplus/shortage + 剩餘≤2 lowStock 低水位)。現場付現逐日計價標 follow-up。 | — |
| 3 | 2026-06-24 | 現場付現估算落地(§5):listEquipmentNeeds 帶 rentPriceTwd、「裝備」tab 每列 + 合計顯示 需求量 × 行程日數 × 每日租金(行程日數 = 梯次日期含頭尾),UI 派生不落 DB;與 per-order 租金 charge line 並存。 | — |
| 4 | 2026-06-24 | 對齊原始 GS 價目表:計價以「晚數」計 max(1, 含頭尾天數 − 1)(1~2 天同價、3 天×2、4 天×3),修正現場付現估算原本誤用 × 含頭尾天數(1 夜團多收一倍)。createRental per-order 租金未乘計價日數的不一致記為 §5「待修齊」(動真實應收,待決策)。 | — |
| 5 | 2026-07-01 | §5 決策拍板:per-order 租借 createRental 按天數計費(同估算側 rent_price × max(1,含頭尾天數−1) × qty),解除「待決策」;現行 code 仍 flat,列為 code follow-up(三方對齊稽核 D3)。 | — |
| 6 | 2026-07-02 | §5 code 落地:createRental 改按天數計費(rent_price × max(1,含頭尾天數−1) × qty,含頭尾天數 = 租期 start→end),rent_price_twd_snapshot 存單位總價、押金不乘天數;rentTotalTwd reducer 與測試同步。解除 D3 code follow-up。 | — |