線稿索引所有 spec最後更新 2026-07-07
specs/internal-external-ledger.md

內外帳與真實成本

一句話:同一筆成本同時承載「內帳真實額」與「外帳可申報額」,據以算真實淨利、並餵代收轉付 / 報稅。建構於 control-financedeparture_costs 之上,不另起第二套成本表

畫面(UI = wireframe):內外帳 / 淨利

1. 目標 / 問題

荒野(與台灣旅行社實務)有「內外帳」需求:實務上常有拿不到發票的支出(停車費、補貼、自然人嚮導 / 司機勞務…),但這些是真實成本,必須據實記錄才能算出真正利潤;同時對外申報只能列有合法憑證的部分。本檔讓系統一筆成本兩個金額並存,派生內帳(真實 / 淨利)與外帳(可申報 / 報稅)兩視圖。

範圍:成本的內外帳維度(含外幣成本 → 雙率派生台幣,§2.1.4)+ 支出證明單 + 淨利試算 + 對外申報邊界 + 成本登記 / 內外帳分析的後台 UI(獨立 nav)不做:正式毛利結算 / 總帳 / 分公司合併(control-finance 已劃界,未來會計模組)。營收側多幣別(orders / 收款一律 TWD);成本側多幣別的匯率 / 換匯 / 外幣帳戶機制在 currency-exchange,本檔只用其派生成本台幣。淨利是出團前後的毛估,不是帳務真相。收據實際開立見 travelinvoice-integration

2. 資料模型

2.1 departure_costs 內外帳維度(擴充欄)

SSOT 歸屬departure_costs 的基礎欄(payable_id / category / vendor_name / amount_twd 等)主檔在 control-finance §4已落地packages/core/src/schema/business.ts + packages/core/src/departure-costs/repo.ts)。本檔只擴充內外帳維度欄invoice_amount_twd / is_declarable / expense_proof_id,以及覆核維度 review_status + 覆核 actor 欄 created_by_user_id / reviewed_by_user_id / reviewed_at,見 §2.1.3),不重定義基礎欄、不另起第二套成本表。範本來源維度(template_line_id 等)另屬 cost-template

在 control-finance 的基礎 departure_costsamount_twd = 真實成本)上加:

欄位型別說明
invoice_amount_twdinteger NOT NULL default 0外帳可申報額:此筆取得合法憑證、可報稅的金額(無憑證填 0)。可上修可下修:預設 = amount_twd,但不限於 ≤ amount_twd——實務上有時拿到高於實際支出的發票,可上修(§3.3)。
is_declarableboolean NOT NULL default true是否取得合法憑證(發票 / 收據)。false 者須掛支出證明單(§2.2)。
expense_proof_idtext FK → expense_proofs.id nullable無發票支出時連到 §2.2 的支出證明單。

覆核維度(review_status + 覆核 actor 欄)見 §2.1.3;範本來源維度見 cost-template §2.4

內外帳一張表amount_twd(內帳真實)與 invoice_amount_twd(外帳可申報)並存於同一筆成本,不分裂成兩套帳。is_declarable=true 預設 invoice_amount_twd = amount_twd(可上修 / 下修);無發票支出 invoice_amount_twd = 0amount_twd 仍計入真實成本。

UI 命名(嚮導端與後台一致)amount_twd 在表單顯示為「代墊 / 實付額」(嚮導墊付、公司退還的錢,= GS 領隊薪資申請單「申請總額」);invoice_amount_twd 顯示為「憑證 / 發票額」(可報稅憑證面額,= GS「發票總金額」)。嚮導 guide-portal §3.2 現場填、後台 §4.1 成本登記頁,同一組欄位、同一組命名,兩 surface 寫同一份 departure_costs

2.1.3 嚮導申報覆核(review_status + 覆核 actor 欄)

嚮導 / 領隊在 guide-portal 現場填報的成本,不再「送出即生效」——先進 review_status='pending'(待覆核),不計入淨利 / 可申報 / 轉請款,待會計覆核 approve 後轉 approved(「代入帳表」)。線控 / op / admin / accountant 在後台或團控直接登記的成本 review_status='approved'(現場營運即生效,無額外 gate)。

departure_costs 為此再加覆核 actor 欄(責任分離需要 handler / approver 來源):

欄位型別說明
review_statustext NOT NULL default 'approved'pending(嚮導送出待覆核)/ approved(已覆核 / 直接登記)。
created_by_user_idtext FK → user(同庫)經手人(建此成本列者;嚮導送出時 = 嚮導本人)。覆核責任分離的 handler。
reviewed_by_user_idtext FK → user nullable覆核人approve 時寫入,強制 ≠ created_by_user_id
reviewed_attimestamptz nullable覆核時間。
  • 覆核 = ledger.approve(強制 reviewed_by_user_id ≠ created_by_user_id,比照支出證明單;嚮導 / op 經手,admin / accountant 覆核)。無發票成本另有 expense_proofspending → approved(§2.2);兩者語意對齊:覆核成本列時,若掛 pending 證明單一併核准(仍受 approver ≠ handler 與 append-only 約束)。
  • 不重複出款expense_proofs 是憑證文件、不自行產生 payable;轉請款的來源永遠是 departure_costs 成本列(一列至多一張 payable,payable_id 去重)。證明單只隨其 linked 成本列一起 approve,不另開第二筆出款。
  • approved 的嚮導代墊成本 → 轉請款給嚮導approve 後該列可一鍵 convertCostsToPayable(payee_type='guide')control-finance §5),進「請款管理」走出款核簽,把代墊款退還嚮導。詳見 guide-portal §3.2

2.1.4 外幣維度(成本以外幣登記,雙率派生台幣)

海外團的真實成本常以外幣發生(地接日幣、印尼盾、未來美金)。成本列可原生記外幣 + 匯率amount_twd(內帳)與 invoice_amount_twd(外帳)改由外幣派生——內帳用真實取得成本、外帳用台銀牌告。匯率機制(牌告表 / 換匯 / 外幣帳戶 WAC)見 currency-exchange,本檔只擁有成本列上的外幣欄與雙率換算。

departure_costs(與 expense_proofs)擴充:

欄位型別說明
currencytext NOT NULL default 'TWD'成本幣別(ISO 4217)。TWD = 現行行為(直接填 amount_twd,rate 欄留空)。
foreign_amountinteger nullable外幣金額(最小單位整數);currency='TWD' 時 NULL。
internal_rate_sourcetext nullable內帳匯率來源 fx_account / published / manualcurrency-exchange §3.3);TWD 列 NULL。
fx_account_idtext FK → receiving_accounts nullableinternal_rate_source='fx_account' 時連到支出的外幣帳戶(取其 WAC)。
internal_ratenumeric nullable內帳匯率快照(canonical twd_per_unit):登記當下依來源解析(帳戶 WAC / 台銀 / 手填)後快照,不漂移。
external_ratenumeric nullable外帳匯率快照:登記當下 resolveExchangeRate(currency, 成本日)(台銀牌告)。

amount_twd / invoice_amount_twd 仍是存量真相(SQL 直接 SUM,既有聚合全不動);外幣列只改「這兩個整數怎麼算出來」:

  • amount_twd = round(foreign_amount × internal_rate)(內帳真實成本)
  • invoice_amount_twd = is_declarable ? round(foreign_amount × external_rate) : 0(外帳可申報)

兩個整數台幣由同一筆外幣金額、各自的匯率派生——這正是 GS「內帳 254,511 / 外帳 168,942」黑箱的結構化還原(內外帳差異來自「憑證」與「匯率」兩個正交來源)。

2.1.1 保費成本(旅平 / 旅責二類,insurance 維度)

GS 內外帳 / 玉山工作表把保險分二類:旅平險(per-head 旅遊平安險)/ 旅責險(per-梯次 旅行業責任險)。兩類保費都進 departure_costscategory='保險'),是真實成本、計入淨利;登山團另有登山險(per-head 山域意外險)同走 category='保險'

  • 資料源分工:保單營運資訊(保險公司 / 保單號 / 完成狀態 / 種類)在 departure-prepdeparture_insurancekind = travel_accident / liability不存金額);保費金額departure_costscategory='保險'vendor_name 記保險公司)。兩表以 departure_id + 種類對應,不在 departure_insurance 重存成本。
  • 淨利計入:保費屬真實成本,預估淨利 = 收入 − 真實成本(含保費)− 預估手續費 − 預估稅(§3.1)。第一版保費以 departure_costs 逐筆登記,不另在 departure_costsinsurance_type 維度欄(種類落 departure_insurance;成本表只需 category='保險')。
  • per-head × 人數自動換算(已定案):保費(旅平 / 登山險 per-head)等隨人頭變動的成本,內外帳頁登記時可選「單價 × 數量」計價(不必只填總額),沿用 cost-template §3.1 的同套數量模型——headcount(單價 × ceil(Σ選定人頭 / 組距))或 fixed(單價 × 固定數量)。Option B(存公式 + 動態重算):手動登記的 per-head 列持久化 quantity_mode / headcount_components / group_divisor / quantity / unit_price_twdtemplate_line_id 為 NULL 標記手動列),amount_twd = unit_price × resolveQuantity(headcounts);人頭變動由既有 recalculateDepartureTemplateCosts 自然重算(手動列天然納入其 quantity_mode='headcount' AND NOT is_manual_override AND payable_id IS NULL 過濾)。手改金額即設 is_manual_override 停止重算;手填總額路徑(不選公式)完全不變。第一版 TWD-only(per-head × 外幣互斥,repo 拒 PERHEAD_FOREIGN)。只放內外帳頁(團控 finance 頁維持唯讀、嚮導 portal 代墊實付語意不動)。

2.1.2 人力成本「每 8 人一組」(領隊 / 司機 / 嚮導)

GS 內外帳表的領隊 / 司機 / 嚮導人力成本算法:roundup((人數 + counta(...)) / 8, 0) × 單價 —— 每 8 人一組配一名(不足 8 仍進位一組),與席次 / 團號的 8 人分組同源。

  • 自動派生已落 cost-template:「每 8 人一組」改由成本範本的 headcount 公式 ceil(Σ人頭 / 組距) 表達(如領隊費 = headcount_components={leader}roundup((旅客+司機)/8)),套用後人數變動自動重算 amount_twd。仍可線控手填總額(手改 → is_manual_override);兩者寫同一 departure_costs.amount_twd(單一存量真相不變)。
  • 範本外的手動 ad-hoc 登記同享自動換算(§2.1.1):沒綁範本、或臨時新增的人力 / 保費成本,內外帳頁登記時可直接選「單價 × 數量」用同一數量模型即時換算(Option B 動態重算),不必先建範本。手動列與範本列共用 recalculateDepartureTemplateCosts(不靠 template_line_id),行為一致。
  • 派車人抽成(內部分潤)見 §3.2,走 payables(staff_commission),與此處的對外人力成本分開。

2.2 支出證明單 expense_proofs(新表)

無法取得發票的支出走支出證明單,是內帳真實成本的合法內部憑證、可列印。比照 payables 的責任分離與編號:

欄位型別說明
idtext PK(ep_<ulid>主鍵。
proof_numbertext unique(EP-YYMMDD-NNN人類可讀單號,per-DB sequence(比照 payable_number)。
departure_idtext FK → departures屬於哪個梯次。
payee_nametext NOT NULL受款對象(自然人 / 廠商)。
amount_twdinteger NOT NULL金額;與所掛 departure_costs.amount_twd 對應。
reason_no_receipttext NOT NULL無法取得單據的原因(如「自然人」)。
summarytext支出內容及摘要。
handler_user_idtext FK → user(同庫)經手人(建單)。
approver_user_idtext FK → user nullable核准人;強制 ≠ handler_user_id(責任分離)。
statustext NOT NULL default 'pending'狀態機 pending(待核准)→ approved(已核准)。
approved_attimestamptz nullable核准時間。
created_at / updated_attimestamptz

狀態機pending → approved(單向)。

Append-onlypending 期間可編輯;核准後不可改、不可刪(DB-level trigger 阻擋 approved 列的 UPDATE/DELETE,比照 payment_transactions 的窄放寬模式 —— 一律擋,無例外欄)。更正走反向 / 重開(開一張新證明單沖正,不回改原單)。

2.3 tenant_settings 預估費率(新欄)

參考預估費率存租戶設定(每梯次權威數是毛利,§3.1;這三費率只供 per-trip「參考預估淨利」,公司真實淨利在 operating-expenses 月損益表用實際值)。單一平面費率,不分通路(預估是毛估,分刷卡 / ATM 不同費率的精度沒有意義)。以 basis points(萬分之一,整數) 存,沿用「金額不浮點」原則:

欄位型別說明
ecpay_fee_bpsinteger NOT NULL default 270預估綠界手續費率(270 = 2.70%)。
fongshou_fee_bpsinteger NOT NULL default 50預估豐收款手續費率(50 = 0.50%)。
profit_tax_bpsinteger NOT NULL default 500預估發票 / 營所稅率(500 = 5.00%,以本團收入毛估)。

3. 邏輯 / 存取層

3.1 兩視圖(只讀派生,不寫第二套金額)

  • 內帳(真實 / 毛利):真實成本 = 房費成本 + Σ departure_costs.amount_twd每梯次權威數=毛利 = 本團收入 − 真實成本(不扣手續費 / 稅)。手續費 / 稅 / overhead 是公司層級費用,移 operating-expenses 用實際值在月損益表扣一次(避免雙重計)。

    營收認列口徑(單一真相,避免現金 vs 出團月混淆):「本團收入」= 該梯次成交應收Σ 掛在此 departure 的訂單 order_charge_lines,即 order-money-modelgross_receivable),不是當期收到的現金(訂金 / 尾款常跨月分次收)。損益的期間歸屬 = 出團月(departure 出團日所屬月),與收款月、付款月皆無關——某梯 5 月出團、3 月收訂金、6 月收尾款,全額營收與毛利都落 5 月order-money-model §1 的「報表用收到現金」僅指訂單付款狀態報表,不涵蓋此處毛利 / 損益的營收認列。全退(receivable_reduction)使該單應收歸 0、自然退出毛利收入。 §2.3 三費率(綠界 / 豐收款 / 營所稅)保留但降為「參考預估」:團控 / 線控頁可顯示明確標示「預估」的 per-trip 淨利(毛利 − 預估費率)給現場快速感覺,非公司財務真相——公司淨利以 operating-expenses 月損益表為準。 取消梯次不入毛利(2026-07-03 已定案,選項 C):梯次列表 / 毛利彙整(listDepartureLedgers / computeRegionMargins)過濾 departures.status='cancelled'listDepartureLedgers 提供 includeCancelled opt-in,僅供掛帳台帳等現金 / 應付追蹤視圖與殘餘檢視用;單梯明細頁不受影響)——取消梯次沒有出團月,「0 收入 / 正成本」會污染區間毛利比較。其殘餘不可退成本(含房費)由內外帳頁「取消梯次待結轉」卡人工確認結轉公司層特殊損益(結轉 / 撤銷 / 反向守衛 / 編輯鎖見 operating-expenses §3.4)、留存行政手續費認列其他收入(§3.3)。

  • 外帳(可申報):可申報成本 = Σ departure_costs.invoice_amount_twd;對應 travelinvoice-integration 的開立與申報。
  • 只計已覆核:上述兩視圖的成本聚合只計 review_status='approved' 的列(§2.1.3);pending(嚮導待覆核)不入淨利 / 可申報 / 轉請款。
  • 無憑證真實成本(派生)逐列聚合 nonDeclarable = Σ max(0, amount_twd − invoice_amount_twd)(只計 approved 列)。逐列取差額是刻意的——避免某列上修發票(invoice > amount)跨列吃掉另一列的無憑證成本;上修列該項貢獻 0,整體不出現負數。(寫成 max(0, Σamount − Σinvoice),那會跨列淨額抵減。)
  • 外幣列(§2.1.4):上述聚合無感——amount_twd / invoice_amount_twd 已是登記當下由外幣 × 內 / 外帳匯率快照 round 出的整數台幣,照常進 SUM。內帳吃真實取得成本(WAC / 當日 / 手填),外帳吃台銀牌告;同一筆外幣可使「外帳 > 內帳」或「內帳 > 外帳」(匯率落差 + 憑證可上修),皆合法。

兩視圖經 helper 派生(比照 orders/money 不 inline 算式);團控成本登記頁與嚮導 portal 顯示該梯次成本明細+合計(內帳真實額),但淨利 / 收入 / 毛利不在團控 / 嚮導端顯示(敏感財務,見 §4)。

3.2 派車人抽成(複用既有欄位,不加 schema)

內外帳表的「派車人(智傑 / 小御)+ 派車抽成」走既有結構、不開新表 / 新欄

  • 派車成本(車資 / 司機費)= departure_costs 一筆(category 交通 / 嚮導,vendor_name 記司機 / 派車人),同內外帳維度(有無發票)。
  • 派車人抽成(內部分潤)= control-finance §5 既有 payables(payee_type='staff_commission') 出款,payee_name 記派車人;走既有請款核簽狀態機與責任分離。

兩者各自落既有分類帳,不另建「派車」專屬模型。

3.3 不變式

  • 每筆 departure_costsinvoice_amount_twd ≥ 0,且 is_declarable=false ⟺ invoice_amount_twd=0 且必有 expense_proof_id
  • 可申報額可上修可下修is_declarable=trueinvoice_amount_twd 預設等於 amount_twd,使用者可下修或上修(無 ≤ amount_twd 上限——實務上可能拿到高於實際支出的發票);僅要求非負整數。「可申報 > 真實」不再視為錯誤,派生的無憑證真實成本夾到 0(§3.1)。is_declarable=false 時強制 0 且必同步開立一張 expense_proofs。B1 不另設審核覆寫。
  • 嚮導申報覆核:嚮導 portal 送出的成本 review_status='pending',不計入淨利 / 可申報 / 轉請款,待 ledger.approveapprover ≠ handler)後轉 approved(§2.1.3)。
  • 支出證明單責任分離approver_user_id ≠ handler_user_id;核准後 append-only。
  • 外幣列(§2.1.4)currency='TWD' ⟺ foreign_amount IS NULL 且 rate 欄全 NULL(TWD 列直接填台幣);currency≠'TWD' 時必有 foreign_amount ≥ 0internal_rate_sourceinternal_rateexternal_rate,且 amount_twd = round(foreign_amount × internal_rate)invoice_amount_twd = is_declarable ? round(foreign_amount × external_rate) : 0internal_rate_source='fx_account' 時必有 fx_account_id 且其帳戶 currency=本列 currency。匯率為登記快照(currency-exchange §3.2/§3.3),事後 WAC / 牌告變動不回改既有列(除非該列未鎖定且使用者明確重算)。

4. UI 與權限

決策(2026-06-24,覆寫 2026-06-23):把「成本登記(操作)」與「內外帳 / 淨利(敏感分析)」分成兩個 surface、按敏感度分權限 —— 成本+憑證登記是 per-departure 現場作業(GS「0501玉山」工作表由現場領隊本人逐筆填車資 / 餐費 / 接駁+發票繳回),跟對款 / 派車 / 訂餐同層,回到團控(線控的團控成本登記頁)與嚮導 portal(領隊現場填);此獨立 nav 保留收入 / 淨利 / 毛利派生、跨梯次損益、支出證明單核簽(敏感財務),僅 admin / accountant。三個 surface(團控 / 嚮導 portal / 此頁)寫同一份 departure_costs。2026-06-23 那版「成本登記只放此 nav、團控只讀」過度收斂(導致線控 / op / 嚮導無入口登記成本),已反轉。

4.1 版面(獨立 nav · 列表 → 下鑽)

  • 列表頁:各梯次損益一覽(本團收入 / 真實成本 / 可申報 / 預估淨利 / 毛利率 / 待核證明單),點一列下鑽。
  • 下鑽詳情三 tab
    • 內帳(成本登記 / 淨利):成本明細表,可新增 / 編輯 / 刪除 / 轉請款(已轉請款 payable_id 的列鎖定不可刪 / 改,更正走沖正);右側淨利試算卡(§3.1)。
    • 新增成本分叉:選「有合法憑證」→ 填可申報額(預設帶入真實額、可上修可下修,僅要求 invoice ≥ 0;上修時 UI 提示「可申報 > 真實」供覆核)+ 憑證類型;選「無發票」→ 可申報額強制 0,並同步內嵌開立一張支出證明單(受款 / 原因 / 摘要 / 經手)送核。
    • 幣別分叉(§2.1.4):成本可選幣別(預設 TWD)。選外幣 → 填外幣金額 + 內帳匯率來源(外幣帳戶 WAC / 當日台銀牌告(預設)/ 手填成交率),UI 即時顯示派生的內帳台幣 + 外帳台幣(台銀牌告);TWD 則同現行直接填台幣。匯率與外幣帳戶見 currency-exchange
    • 計價方式分叉(§2.1.1 / §2.1.2):TWD 成本可選「一次性總額」(現行直接填真實成本)或「單價 × 數量」(填單價 + 數量模式:依人頭多選 checkbox + 組距 / 固定值),UI 即時估算 單價 × ceil(Σ人頭 / 組距)(真相在 server 重算);選公式時可申報額 = 派生總額(不開手動覆寫欄)。外幣強制一次性總額(per-head TWD-only)。
    • 待覆核(嚮導申報):嚮導 portal 送出的 review_status='pending' 成本佇列,會計逐筆 / 批次 approve(經手 ≠ 核准)→ 代入帳表;approve 後可一鍵轉請款給嚮導(payee=guide,進請款管理)。
    • 外帳(可申報):唯讀派生明細 + 憑證涵蓋率(只計 approved)。
    • 支出證明單:列表 + 登記 + 核准(經手 ≠ 核准雙職,核准後 append-only) + 列印。
  • 列印:支出證明單 / 內外帳成本報表走 HTML @media print(比照請款單,見 control-finance §5.3)。

4.2 權限(成本 entry 與 ledger 分析分離)

成本登記(操作)內外帳 / 淨利(敏感分析) 拆成不同 resource,前者開給現場營運角色、後者鎖 admin / accountant

action用途guide(自己梯次)opadminaccountantsales
departure_cost.create登記成本 + 開支出證明單(經手)✅(scoped)
departure_cost.manage編輯 / 刪除 / 轉請款(跨梯次)
ledger.read內外帳列表 / 淨利 / 內帳真實額 / 跨梯次損益
ledger.approve支出證明單核准(強制 approver ≠ handler
  • departure_cost.create:成本+憑證是 per-departure 現場作業,開給 op(團控成本頁)、guide(嚮導 portal,scoped 到自己帶的梯次,見 guide-portal)、admin / accountant
  • departure_cost.manage:跨梯次編輯 / 刪除 / 轉請款留 admin / accountant(2026-07-07 拍板 op 維持 create-only)。原 ledger.manage 已收斂改名於此(內外帳詳情頁與 api/v1 成本寫入閘同名;存量自訂角色 grants 由 migration 0052 映射)。
  • ledger.read:淨利 / 收入 / 毛利屬敏感財務,整個獨立 nav 經此 gate,僅 admin / accountant不顯示於團控 / 嚮導 portal
  • ledger.approve:支出證明單核准,強制 approver ≠ handler(嚮導 / op 經手,admin / accountant 核准)。
  • 轉請款(cost → payable)需 departure_cost.manage payable.create;建立後的 payable 仍走 control-finance §5payable.* 核簽狀態機。

5. 已裁決(原開放議題)

  • 手續費 / 稅率設定:存 tenant_settings單一平面費率(§2.3:ecpay_fee_bps / fongshou_fee_bps / profit_tax_bps,basis points 整數),不依通路(刷卡 vs ATM)分
  • 可申報額自動帶入:見 §3.3 不變式 —— is_declarable=true 預設 invoice=amount可上修可下修(無 ≤ amount 上限);is_declarable=false 強制 0 + 必掛證明單。B1 不設審核覆寫。
  • 嚮導申報覆核(2026-06-24):嚮導 portal 填報的成本走 review_status 覆核 gate(pending → approved),approve 後計入帳並可轉請款給嚮導(§2.1.3);後台 / 團控直接登記者直接 approved

Changelog

版本日期變更Commit
12026-06-20初版(草案):由 control-finance §4 抽出獨立。departure_costs 內外帳維度 + 支出證明單 + 內帳真實 / 外帳可申報雙視圖 + 淨利試算 + 不變式。未實作。
22026-06-20§2.1 明示 SSOT 歸屬:departure_costs 基礎欄主檔在 control-finance §4,本檔只擴充 invoice_amount_twd / is_declarable / expense_proof_id 三欄。
32026-06-23B1 設計定案(過夜 /loop brainstorming):(1) UI 決策 —— 成本登記 + 內外帳分析 + 證明單核簽全收進獨立 nav「內外帳 / 淨利」,不放團控,實作 control-finance §4 的成本登記 UI;(2) expense_proofs 補完整 schema(proof_number / status 狀態機 / 經手≠核准雙職 / 核准後 append-only trigger);(3) §2.3 tenant_settings 三個 bps 費率欄(單一平面、不分通路);(4) 新 permission resource ledger(read/manage/approve,僅 admin/accountant);(5) §5 開放議題裁決。wireframe 已對齊(/admin/internal-external-ledger 升級為登記+分析合一;/admin/control/costs 改轉導 stub;團控/出團準備/抽籤的成本快速動作移除/改指)。
42026-06-23列印面向補完設計:支出證明單與內外帳報表皆為 HTML 列印@media print + window.print(),比照 請款單列印 的 SSOT,非 server-side PDF)。證明單列印含受款/金額大寫/無單據原因/「經手 ≠ 核准」簽核格;報表列印含收入·成本摘要 / 內帳明細 / 淨利試算 / 外帳可申報 / 證明單列表。列印頁走 ledger.read 閘,且證明單列印須驗證該單屬路徑梯次(IDOR)。
52026-06-23對齊 GS 內外帳模型:§2.1.1 保費二類(旅平 per-head / 旅責 per-梯次,登山團另登山險)進 departure_costscategory='保險')計入淨利,種類落 departure-prep departure_insurance(不存金額),per-head 自動換算留 follow-up;§2.1.2 人力成本「每 8 人一組」roundup(人數/8)×單價 第一版為線控手填總額(不加 unit_count×unit_price schema,自動派生留 follow-up)。
62026-06-24反轉 2026-06-23 的成本登記收斂(§4):成本+憑證登記是 per-departure 現場作業,回到團控(團控成本登記頁,線控)與嚮導 portal(領隊現場填);此 nav 保留淨利 / 內外帳分析 + 證明單核簽(admin/accountant)。§4.2 權限拆分:departure_cost.create(guide scoped / op / admin / accountant 可登)與 ledger.read / ledger.approve(僅 admin/accountant)分離,取代舊「ledger.manage 全包、admin/accountant 限定」。§3.1 改「淨利不顯示於團控/嚮導端」。三 surface 寫同一份 departure_costs。wireframe 已對齊(團控成本頁 un-stub + 嚮導 portal)。spec 已改,apps/web 實作待 realign。
72026-06-24發票可上修(§2.1 / §3.1 / §3.3 / §4 / §5):invoice_amount_twd 移除 ≤ amount_twd 上限(實務上可拿到高於實際支出的發票),僅要求 ≥ 0;派生無憑證真實成本改逐列 nonDeclarable = Σ max(0, amount − invoice)(只計 approved;避免上修列跨列淨額抵減)。嚮導申報覆核(§2.1.3):新 departure_costs.review_statuspending/approved)+ 覆核 actor 欄 created_by_user_id / reviewed_by_user_id / reviewed_at(責任分離 reviewed_by ≠ created_by),嚮導 portal 送出 = pending 不計入帳,會計 ledger.approveapproved(代入帳表),approved 嚮導代墊可轉請款給嚮導(payee=guide)進請款管理;expense_proofs 不另產生 payable(出款來源永遠是成本列)。兩視圖成本聚合只計 approved。配合新 cost-template(系列團成本範本,套用列 review_status=approved)。未實作。
82026-06-24外幣維度 + 雙率派生(§1 / §2.1.4 / §3.1 / §3.3 / §4.1):departure_costs / expense_proofscurrency / foreign_amount / internal_rate_source / fx_account_id / internal_rate / external_rate;外幣列的 amount_twd(內帳)= round(foreign × internal_rate)invoice_amount_twd(外帳)= round(foreign × external_rate)(有憑證才 > 0),兩整數台幣由同筆外幣 + 內 / 外帳兩匯率派生(GS 內外帳黑箱的結構化還原)。內帳匯率來源通用三選一(外幣帳戶 WAC / 當日台銀牌告 / 手填,不寫死團型),外帳一律台銀牌告;皆登記快照不漂移。匯率 / 換匯 / 外幣帳戶機制獨立至新 currency-exchange;營收側鐵守 TWD。未實作。
102026-06-28金流→會計流程一致性修正 #2(§3.1):補「營收認列口徑」單一真相——本團收入 = 該梯次成交應收gross_receivable)非當期現金;損益期間歸屬 = 出團月(非收款 / 付款月);order-money-model §1「報表用現金」僅指訂單付款狀態、不涵蓋毛利 / 損益營收認列。
92026-06-25每梯次「淨利 → 毛利」降級(§2.3 / §3.1):每梯次權威數改為毛利 = 收入 − 真實成本(不扣手續費 / 稅);手續費 / 稅 / overhead 移公司層級operating-expenses 月損益表用實際值扣一次(避免雙重計,GS 0501 玉山鐵證每梯次已扣預估手續費 / 稅)。§2.3 三費率(ecpay_fee_bps / fongshou_fee_bps / profit_tax_bps)保留但降為 per-trip「參考預估」(現場快速感覺),公司真實淨利以月損益表為準。「人員成本」釐清:= 領隊費 = 每梯次直接成本(領隊經 guide-portal 自填),非公司人事。未實作。
112026-06-28L' 實作落地(§2.1.3 / §3.1 / §3.3):發票上修(invoice_amount_twd≤amount 上限)schema + 表單 + 逐列 nonDeclarable=Σmax(0,amount−invoice) 皆已落地。嚮導申報覆核落地:departure_costsreview_status(default 'approved',零回歸)/ created_by_user_id / reviewed_by_user_id / reviewed_at + DB CHECK 責任分離(reviewed_by≠created_by);approveDeclaration + listPendingDeclarations repo;4 處成本聚合(control-stats / getDepartureCostSummary / derive.listDepartureLedgers / company-pnl 各區毛利)一律 WHERE review_status='approved' → pending 不入淨利/可申報,approve 後才計;內外帳頁「待覆核成本」卡(ledger.approve)。嚮導端送出(pending)建在 G。e2e 40 + b1-ledger 整合測試(pending 不計入 / approve / SELF_REVIEW / 上修)。
152026-07-07§4.2 權限命名收斂落地:內外帳詳情頁成本 create/update/delete + 轉請款(server actions + api/v1)的閘由 ledger.manage 改名 departure_cost.manage,catalog 移除 ledger.manageledger 剩 read / approve);存量自訂角色 grants 由 migration 0052 映射(內建角色 seed 自 code 重同步)。拍板 op 維持 create-only(跨梯次編 / 刪 / 轉請款留 admin / accountant),§4.2 表 op 欄 ✅→❌ 修正——收斂為純改名,內建角色授權面零變化。
142026-07-03取消梯次過濾 + 待結轉卡實作落地(§3.1):listDepartureLedgers 預設排除 status='cancelled'includeCancelled opt-in;掛帳台帳彙總開此旗標保持與成本掛帳 / 應付清單對得上)+ computeRegionMargins 同步過濾;內外帳頁新「取消梯次待結轉」卡(殘餘成本=approved 成本+房費、結轉 / 撤銷 dialog,operating_expense.manage)。API cancelled-departures{,/convert,/revert} + CLI 鏡像。生命週期規則(反向守衛 / 編輯鎖)見 operating-expenses §3.4
132026-07-03取消梯次不入毛利(已定案,選項 C)(§3.1):梯次列表 / 毛利彙整過濾 departures.status='cancelled';殘餘不可退成本結轉公司層特殊損益(operating-expenses §3.4)。背景:房費成本接入後「0 收入 / 正成本」不對稱被 codex 對抗 review 揪出,經拍板選 C(對稱 §3.3 admin_fee 只認未出團 / 取消單)。引擎過濾與結轉流程待實作(狀態見 roadmap)。
122026-07-03手動 per-head 單價×人數自動換算落地(§2.1.1 / §2.1.2):把 cost-template 既有的單價×數量機制開放給內外帳頁的手動 ad-hoc 成本登記(不必先建範本)。DepartureCostInput 加選填 quantityMode / headcountComponents / groupDivisor / quantityFixed / unitPriceTwdcreateDepartureCost / updateDepartureCost per-head 路徑同 tx 取 getDepartureHeadcountsresolveQuantityamount = unit × quantity,持久化五欄(Option B 存公式,手動列 template_line_id=NULL),人頭變動由既有 recalculateDepartureTemplateCosts 自然重算。第一版 TWD-only(per-head × 外幣互斥,拒 PERHEAD_FOREIGN)。內外帳頁成本表單加「計價方式」分叉(一次性總額 vs 單價×數量)+ 人頭 checkbox / 組距 / 即時估算;/api/v1 鏡像同步。團控 finance 頁唯讀、嚮導 portal 不動;手填總額路徑零回歸。b1-ledger 整合測試 + e2e 47。