一句話:團控財務是每個梯次的營運財務工作台(訂單掛帳、梯次成本、梯次優惠價、供應商 / 嚮導 / 佣金請款核簽);金額與狀態計算以 order-money-model 為 SSOT,本檔只定義團控如何產生、審核與呈現這些金流事實。
畫面(UI = wireframe):
團控·請款列表·請款詳情·請款列印
團控財務包含四個彼此相關、但資料責任不同的功能:
| 功能 | 入口 | 資料責任 | SSOT |
|---|---|---|---|
| 訂單掛帳 / 折讓 / 加收 | /admin/control、訂單詳情 | 對特定訂單增減應收,保留原因與 actor | order_charge_lines(type='manual_adjustment'/'reversal') |
| 梯次成本 | /admin/control/[departureId]/costs | 登記房費以外的供應商成本,供彙總與轉請款 | departure_costs(設計表)+ room cost 來源 |
| 梯次優惠價 | /admin/control、梯次設定 | 主管對整梯設定促銷覆寫價;新單才套用 | departures promo 欄位 + resolveDeparturePrice |
| 請款核簽 | /admin/payments / payment-request UI | 線控建單、主管核准、會計依紙本付款並 mark paid | payables / payable_items |
不在本檔重做:
refunds;出款核簽不作為退款資料源。departure_costs 之上)。order_charge_lines;不改訂單外殼金額,也不另開第二套應收公式。type='reversal' 或相反 signed amount 表達。departure_costs 是成本簿;payables 是要交給主管 / 會計的付款核簽單。成本可轉成 payable,但兩者不是同一件事。/admin/control 進;跨梯次財務總覽才是獨立 nav。掛帳是主管對單筆訂單做一次性應收調整:
order_charge_lines。order_charge_lines。必要欄位語意:
| 欄位語意 | 說明 |
|---|---|
order_id / order_line_id | 可掛整單,也可掛某個商品 line。 |
amount_twd | signed integer TWD;負數減應收,正數增應收。 |
source_type / source_id | admin_manual、room_upgrade、discount_code 等來源;方便 audit 與報表分群。 |
description | 必填,說明調整原因;UI 不允許空白原因。 |
created_by_user_id | 同庫 user FK;保留責任歸屬。 |
掛帳後必須在同一交易中:
payment_schedules 到最新應收;payment_state / refund_state;assertOrderFinancialInvariants;audit_log。已落地:掛帳 / 折讓 / 沖正全套在
packages/core/src/orders/manual-charge.ts(applyManualAdjustment/reverseChargeLine,上述五步協定一個 tx,b2-finance 測試齊)。
order.adjust)權限 resource 為 order,action adjust(掛帳 / 折讓 / 加收 / 沖正,append order_charge_lines)。對齊 packages/core/src/permissions-ac.ts:
| 角色 | 掛帳 / 折讓 / 沖正(order.adjust) | 說明 |
|---|---|---|
admin | ✅ | 全權 |
op | ✅ | 線控可對單筆訂單掛帳 / 折讓 / 沖正 |
accountant | ❌(唯讀) | 只持 order.read;看得到 charge line,不能寫 |
sales | ❌ | 無 adjust(只 order.read/create/update) |
customer | ❌ | — |
梯次成本是線控在出團前後登記的供應商應付項目,例如山屋、旅宿、巴士、餐廳、保險、入山證、嚮導、地接與雜支。
成本彙總分兩個來源:
departure_costs 登記多筆成本明細,允許出團前修正;每次 create/update/delete 都寫 audit。departure_costs 的基礎設計語意:
| 欄位語意 | 說明 |
|---|---|
departure_id | 成本屬於哪個梯次。 |
category | 住宿、交通、餐飲、保險、門票、入山證、嚮導、地接、雜支、其他。 |
vendor_name | 供應商名稱,可帶入 payable payee。 |
description | 成本摘要。 |
amount_twd | 真實成本,整數 TWD(一律據實登記,含無發票支出)。 |
payable_id | 若已轉請款核簽,連到 payables.id,避免重複請款。 |
轉請款時,系統以成本列產生 payables(source_type='departure_cost') 與對應 payable_items;成本列只記 payable_id,不複製 payable 狀態。
內外帳維度另立:
departure_costs的「可申報額 / 是否有憑證 / 支出證明單 / 淨利試算 / 申報 / 嚮導申報覆核(review_status)/ 外幣維度(currency/foreign_amount/ 內外帳匯率快照)」屬內外帳層,移至 internal-external-ledger(外幣的匯率 / 換匯 / 外幣帳戶機制再下放 currency-exchange);「範本來源維度(template_line_id/quantity_mode/headcount_components/group_divisor/quantity/unit_price_twd/is_manual_override)」屬 cost-template(系列團成本範本,行程綁範本後梯次自動帶入成本行;數量=固定值或ceil(Σ人頭/組距),人頭含旅客 / 領隊 / 協作 / 司機,動態重算)。本檔只擁有梯次成本的資料 SSOT(基礎欄 + 轉請款)。amount_twd仍是真實成本存量真相(外幣列由外幣 × 內帳匯率快照 round 派生);團控顯示(§7)聚合amount_twd真實額成本明細,但淨利 / 收入 / 毛利不在團控顯示(敏感財務)。成本登記 UI 落點(2026-06-24 決策,覆寫 2026-06-23):成本+憑證登記是 per-departure 現場作業(§2「成本從
/admin/control進」原則),回到團控:線控走團控成本登記頁(/admin/control/[departureId]/costs,departure_cost.create),帶隊嚮導 / 領隊走嚮導 portal(scoped 到自己梯次)。獨立 nav「內外帳 / 淨利」保留淨利分析 + 證明單核簽(ledger.read/ledger.approve,僅admin/accountant)。三 surface 寫同一份departure_costs。2026-06-23「成本登記不在團控、團控只讀」已反轉(過度收斂使線控 / op / 嚮導無入口)。
UI 名稱可沿用「請款單」,資料層是 payables / payable_items。它代表旅行社要付款給第三方,不代表客戶退款本身。
payee_type | 用途 |
|---|---|
supplier | 旅宿、交通、餐飲、保險、地接等供應商。 |
guide | 嚮導費。 |
staff_commission | 業務 / 內部佣金。 |
other | 其他需走請款核簽的出款。 |
draft -> submitted -> approved -> paid
submitted -> rejected
draft/submitted/approved/rejected -> cancelled
paid is terminal
狀態轉換規則:
bank_reference。audit_log,target type 為 payable。@media print + window.print()。請款單、支出證明單、內外帳成本報表(見 internal-external-ledger)共用此列印路徑。pdf_generated_at / paper_printed_at 記錄列印動作;不寫永久 PDF URL。權限 resource 為 payable,格式為 payable.action。
| 角色 | read | create | submit | approve/reject | mark_paid | print/cancel |
|---|---|---|---|---|---|---|
admin | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
op | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
sales | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
accountant | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
customer | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
歸屬:§5.5 出款批次 / 批次轉帳匯款檔 / §5.6 廠商目錄屬進階會計模組(受
module_accountinggate);§5.1–5.4 的payables請款核簽留核心(掛帳台帳)。
現實裡同一收款對象的多筆 payable 常月結一次匯出(GS:嚮導每月 5 號前把當月各梯次領隊費彙整成一筆匯出,扣勞健保自付後實拿,並產批次轉帳清單)。本節在 payables 上加「出款批次」這層出納動作 —— 不是 HR / 算薪(薪資級距 / 勞健保投保 / 最低薪資 / 考勤一律不在此,由外部記帳 / payroll 提供數字)。
payout_batches(新表):
| 欄位 | 說明 |
|---|---|
id | 主鍵(pob_<ulid>)。 |
period | 出款歸屬月(YYYY-MM)。 |
payee_scope | 此批次涵蓋的對象(如 guide 全體 / 指定對象集)。 |
paid_from_account_id | 從哪個帳戶匯出(FK receiving_accounts,須 can_remit,如永豐)。 |
bank_reference | 批次轉帳參照號。 |
status | draft → confirmed(confirmed 即把納入的 payable 一併 mark paid)。 |
created_by_user_id / created_at | — |
payout_batch_lines(每對象一列):彙整一個收款對象(嚮導 / 員工 / 供應商)當月應付 → gross_twd = Σ 已核准 payable + Σ 直接外加(行政薪);減通用扣款項 deductions(JSON / 子表,每筆 {label, amount_twd},label 租戶自定:荒野填「勞健保自付」「借支」,系統不知道勞健保是什麼,零法規寫死)→ net_twd = gross − Σ deductions。確認時把該對象當月納入的 payables 全部 mark paid、連 payout_batch_id,並依 net_twd 在 account-settlement 記一筆出帳(接對帳)。
payout_batch_lines 補欄 | 說明 |
|---|---|
payee_type / payee_ref_id | 收款對象(guide / staff / supplier)+ 對應目錄列(取其收款銀行三欄,§5.6)。 |
confirmed_at / confirmed_by_user_id | 已對該對象確認(廠商走自助 token 頁確認,confirmed_by=null;出納亦可代勾)。僅 confirmed 列得進批次轉帳檔(§下)。嚮導 / 員工薪資視租戶政策可預設免確認。 |
confirm_token / supplier_confirm_note | 廠商自助確認頁的時效 token + 廠商回填文字(確認備註 / 異議)。 |
自動彙整明細(派生,重現 GS「廠商結帳」AG2:AH10):一列的 gross_twd 由其納入的已核准 payable 加總,每筆 payable 經 departure_costs → departures 派生「日期 + 團名 + 金額」明細列,UI 自動組出「0522奇萊主北 29,400 / 0530加羅湖 17,640 / 共 47,040」對廠商核對。明細是唯讀派生,不另存。
廠商結帳流程:當月各梯次的供應商成本 departure_costs(supplier) → 覆核 approved → convertCostsToPayable(payee_type='supplier')(同一供應商可跨梯次多筆)→ 出款批次依供應商 group 成一列 → 廠商自助確認(token URL) → 勾 confirmed → 納入批次轉帳檔。
廠商自助確認頁(tokenized URL,免登入,比照同意書 /consent/[orderId]):每個廠商月結列產一個 confirm_token,對外頁 /supplier-confirm/[token](綁 payout_batch_line_id、時效性)。廠商看到本月明細(日期 + 團名 + 金額 + 合計)→ 輸入文字(確認備註 / 異議)→ 按「確認」→ 回寫 confirmed_at / confirmed_by_user_id(=null,對外確認標記為廠商)/ supplier_confirm_note。出款端有「複製罐頭訊息 + 網址」鈕(罐頭文走 emails / message-templates,出納貼進 LINE 給廠商)。對外頁只露該列明細、不露其他廠商 / 帳務(比照 order-scoped 防 IDOR)。僅 confirmed 列進批次轉帳檔。
行政薪「直接外加」的輸入(GS 領隊薪資申請單底部「行政薪水(直接外加)」):純內勤 / 兼帶隊者的固定行政薪沒有 per-trip payable 來源,在出款批次頁手動加一筆「直接外加」(出納輸入、上月可帶入 placeholder),與通用扣款項一起 key。這是出納輸入、非 HR 固定薪主檔(不存薪資級距 / 不算勞健保 / 不管投保,守住不碰 HR)。領隊費則由已核准 payable 自動帶入、不在此手加。
operating_expenses(salary_admin)(payout_batch_line.operating_expense_id),毛額 = 損益費用列、淨額 = 批次匯出。行政薪不得在損益頁與批次頁各登一次(operating-expenses §2.2 型態④)。批次轉帳檔(標準銀行格式,per-tenant 出款帳戶,非寫死永豐):confirmed 列產可下載批次轉帳檔(CSV / 剪貼),台灣銀行批次匯款的通用四欄(對齊 GS 領隊薪資申請單 X60–AA60、永豐企業網銀 import 格式,但任何銀行批次匯款皆吃這四欄,不綁特定銀行):
| 欄 | 內容 | 寫入來源 | 長度 |
|---|---|---|---|
| (1) 收款人戶名 | payee 收款銀行三欄之戶名 | §5.6 目錄 | 1~65 |
| (2) 收款帳號 | payee 帳號 | §5.6 目錄 | 2~16 |
| (3) 收款銀行代號 | payee 銀行代號 | §5.6 目錄 | 7 |
| (4) 交易金額 | net_twd | 本列 | 整數 |
匯出帳戶 = 批次 paid_from_account_id(須 can_remit,荒野=永豐)。退款匯出(account-settlement §3.5)共用同一張四欄格式、各自清單。缺收款三欄者匯出前 UI 標紅擋下。亦保留 HTML print 對帳用。
與認列分離:領隊費的成本認列仍是 per-trip departure_costs(進毛利,internal-external-ledger);本批次只是把這些已核准 payable 的出款執行月結成一筆。雇主勞健保負擔(86,144 例)走 operating-expenses 辦公室 / 人事 opex 逐筆,與本批次的「自付扣款」連動但不耦合。
多租戶:純出納 + 通用扣款項,任何租戶可用(無 jurisdiction payroll)。HR 算薪 / 投保 / 考勤留外部或未來整合。
權限:沿用 payable(payable.mark_paid 才能 confirm 批次,admin / accountant)。
批次轉帳檔(§5.5)需收款人「戶名 / 帳號 / 銀行代號」。這是出款對象資料、非 HR 員工主檔(不存薪資級距 / 投保)。三類收款對象各自掛三欄收款銀行資訊:
| 收款對象 | 落點 | 收款銀行欄(皆 nullable) |
|---|---|---|
| 嚮導 / 領隊 | guides(guide-portal) | payee_account_name / payee_bank_code / payee_account_number |
| 員工(行政薪) | staff 出款資料 | 同三欄 |
| 供應商 / 廠商 | 新 suppliers 目錄 | 同三欄 |
suppliers(廠商目錄,新表)——廠商會跨月重複出現(阿凱登山企業社 / 協作包餐 / 儷萊春陽 / 接駁車外派…),建檔一次免月月重 key,收款銀行資料隨廠商走:
| 欄位 | 型別 | 說明 |
|---|---|---|
id | text PK(sup_<ulid>) | 主鍵。 |
name | text NOT NULL | 廠商名。 |
category_hint | text nullable | 慣用類別提示(協作 / 車 / 住宿 / 裝備…,租戶自定,非硬枚舉)。 |
payee_account_name / payee_bank_code / payee_account_number | text nullable | 收款銀行三欄(同上)。 |
status | text NOT NULL default 'active' | active / inactive(停用不刪)。 |
created_at / updated_at | timestamptz | — |
departure_costs.supplier_id(新欄,nullable,FK → suppliers):成本登記時可選已建檔廠商(自動帶名 + 收款資料),亦保留 vendor_name 自由文字(未建檔的一次性廠商)。月結 group 以 supplier_id(已建檔)優先、否則 fallback vendor_name。supplier.manage,admin / accountant / op);收款銀行資料 write 後遮罩顯示(比照其他收款資訊)。全 per-tenant 自填,不預載任何廠商 / 銀行。supplier(read / manage)。梯次優惠價是主管對整個 departure 設定的促銷覆寫價,只影響設定後的新訂單。
resolveDeparturePrice 擁有。團控頁的財務區塊應顯示:
order_charge_lines 聚合。payment_transactions(direction='in') 聚合,扣退款視報表語意決定。orders/money helper,不 inline 算式。departure_costs,成本合計只計 review_status='approved' 的列(internal-external-ledger §2.1.3);嚮導送出未覆核(pending)的成本另以「待覆核」計數 / 金額分列呈現,不混入合計。departure_costs.payable_id 與 payables.status 呈現。tour 視角的彙總必須經 order_lines → tour_booking_lines 篩出該梯次;customer 或跨產品視角不得用 tour-only join 排除訂房單。
| 版本 | 日期 | 變更 | Commit |
|---|---|---|---|
| 回填 | 2026-07-01 | 狀態回填:§5.5 出款批次(payout_batches/payout_batch_lines 月結彙整 + 廠商自動彙整 + 批次轉帳檔)+ §5.6 廠商目錄 suppliers(收款銀行三欄 + departure_costs.supplier_id)+ /supplier-confirm/[token] 廠商自助確認(免登入 tokenized 頁)已全鏈落地;v7–v9 條目的「未實作」註至此收斂(狀態以 roadmap 為準)。 | — |
| 4 | 2026-06-20 | 釐清邊界:departure_costs 維持基礎梯次成本(真實 amount_twd + 轉請款);內外帳維度(可申報額 / 支出證明單 / 淨利試算 / 申報)獨立至 internal-external-ledger,多收款帳戶分流獨立至 payment-accounts-reconciliation。 | — |
| 5 | 2026-06-23 | §3 補「掛帳 / 折讓 / 沖正已落地」(manual-charge.ts)+ §3.1 掛帳角色矩陣(order.adjust = admin / op;accountant 唯讀;sales 無),對齊 permissions-ac.ts。 | — |
| 6 | 2026-06-24 | §4 成本登記 UI 落點反轉(覆寫 2026-06-23):成本+憑證登記回團控(/admin/control/[departureId]/costs,departure_cost.create,線控)+嚮導 portal(領隊現場填,scoped);內外帳 nav 保留淨利分析 + 證明單核簽(admin/accountant)。呼應 §2「成本從 /admin/control 進」原則。詳見 internal-external-ledger §4。 | — |
| 7 | 2026-06-25 | §5.5 新增出款批次(月結匯出):payout_batches / payout_batch_lines 把同一收款對象當月已核准 payable 彙整成一筆匯出,減通用扣款項(label 租戶自定如「勞健保自付」,零法規寫死)→ net,confirm 時一併 mark paid + 記出帳進對帳 + 產批次轉帳清單(戶名/帳號/銀行代號/金額,對齊 GS 領隊薪資申請單批次轉帳區)。收款對象銀行資訊掛既有 guide/staff/供應商紀錄(出款對象資料、非 HR 員工主檔)。做出納面、不做 HR 算薪(薪資級距/勞健保投保/最低薪資/考勤留外部)。領隊費成本認列仍 per-trip departure_costs。未實作。 | — |
| 8 | 2026-06-28 | §5.5 / §5.6 匯款流程具體化(對齊 GS 202605記事「廠商結帳」AG2:AH10 + 領隊薪資申請單批次轉帳區):(1) payout_batch_lines 加 payee_type/payee_ref_id + confirmed_at/confirmed_by(僅 confirmed 列進批次檔,廠商月結走 LINE 重複確認後勾選)+ 自動彙整明細(payable→departure_costs→departures 派生「日期+團名+金額+合計」,重現 AG/AH 對廠商核對)+ 廠商結帳流程(成本→approve→convertToPayable(supplier)→group→confirm→匯出)。(2) 批次轉帳檔標準四欄(收款人戶名 1can_remit 帳戶匯出,缺收款資料擋下)。(3) 新 §5.6 廠商目錄 suppliers(跨月重複廠商建檔一次 + 收款銀行三欄)+ departure_costs.supplier_id(保留 vendor_name 自由填)+ guides/staff 收款銀行三欄 + 新 resource supplier。退款匯出(account-settlement §3.5)共用同一張四欄格式。未實作。 | — |
| 10 | 2026-06-28 | 金流→會計流程一致性修正 #3(§5.5):行政薪「直接外加」確認時生成 / 連結 operating_expenses(salary_admin)(payout_batch_line.operating_expense_id),明訂單一真相避免損益頁與批次頁重複出帳(對齊領隊費 departure_costs → payable → 批次 單鏈,補上行政薪缺的連結)。 | — |
| 9 | 2026-06-28 | 廠商自助確認(token URL)+ 模組歸屬:§5.5 廠商月結確認改對外 tokenized 頁 /supplier-confirm/[token](免登入、綁 payout_batch_line_id、廠商輸入文字按確認 → 回寫 confirmed_at / supplier_confirm_note,比照同意書 /consent/[orderId] + order-scoped 防 IDOR)+ 出款端「複製罐頭訊息 + 網址」鈕(貼 LINE);payout_batch_lines 加 confirm_token / supplier_confirm_note。標模組歸屬:§5.5 出款批次 / §5.6 廠商目錄屬進階會計模組(module_accounting gate),§5.1–5.4 payables 核簽留核心。未實作。 | — |
| 3 | 2026-06-05 | 整併請款核簽;改為 payables / payable_items 與金流分類帳現在式 SSOT,移除舊應收與請款表重複建模。 | — |
| 2 | 2026-05-30 | 補與 trip-pricing 的 promo 欄位邊界、權限與測試計畫。 | — |
| 1 | 2026-05-30 | 初版:掛帳、成本、優惠價三層團控財務設計。 | — |