內外帳與損益
cairn 的財務分兩層:每梯次只算到「毛利」(收入 − 真實成本),公司層才把手續費、稅、辦公室費用扣一次算出「淨利」。同一筆成本同時帶「內帳真實額」與「外帳可申報額」兩個金額,據此派生真實利潤與報稅邊界。
理解這層分工,你才能正確解讀損益相關端點——每梯次的 grossProfit、公司的淨利,都是成本明細與費用台帳算出來的派生值。
這是進階會計模組
本篇的所有端點都屬進階會計模組(accounting)。租戶未啟用此模組時,內外帳、損益、結算相關端點會回 403 module_disabled——即使你的角色有對應權限。這與「權限不足」的 403 forbidden 是兩回事:module_disabled 要租戶在設定啟用模組,forbidden 要換有權限的 token。另外,內外帳與損益屬敏感全局財務,只有 admin / accountant 角色可讀(線控、嚮導端看不到淨利)。
內帳 vs 外帳:一筆成本兩個金額
每一筆成本同時承載兩個台幣金額,不分裂成兩套帳:
| 金額 | 是什麼 | 用途 |
|---|---|---|
| 內帳真實額 | 實際花掉的錢(含拿不到發票的支出) | 算真實毛利 / 淨利 |
| 外帳可申報額 | 取得合法憑證、可報稅的部分(無憑證為 0) | 對外申報 / 報稅 |
實務上常有拿不到發票的支出(停車費、補貼、自然人嚮導 / 司機勞務),這些是真實成本必須據實記錄,但對外申報只能列有合法憑證的部分——兩個金額的差就是「無憑證真實成本」。
可申報額可上修也可下修:通常等於真實額,但有時拿到高於實際支出的發票(可上修),或一筆完全無發票(為 0)。所以「外帳 > 內帳」不是錯誤,是合法的匯率 / 憑證落差。
無發票的支出會掛一張支出證明單作為內帳的合法內部憑證(記受款對象、原因、摘要),可列印、走經手與核准雙職分離。
成本要先覆核才入帳
不是所有成本都「送出即生效」。嚮導 / 領隊在現場填報的成本,先進「待覆核」狀態,不計入淨利、不可申報、不可轉請款,要等會計覆核通過才入帳;後台或團控直接登記的成本則直接視為已覆核。
對應 API:GET /internal-external-ledger/declarations/pending 取待覆核佇列,POST /internal-external-ledger/costs/{costId}/approve-declaration 覆核單筆(覆核人必須 ≠ 經手人)。覆核後的嚮導代墊成本可一鍵轉成請款(payable)退還嚮導。
外幣成本:雙率派生台幣
海外團的真實成本常以外幣發生(地接日幣、印尼盾)。成本可原生記外幣金額 + 匯率,兩個台幣金額由同一筆外幣各自派生:
- 內帳匯率取真實取得成本:外幣帳戶的加權平均成本、當日台銀牌告、或手填成交率(三選一,不寫死團型)。
- 外帳匯率一律台銀牌告。
- 兩個匯率都在登記當下快照進成本列,事後牌告變動不回改既有成本。
多幣別只進成本側。營收一律台幣——訂單、收款、退款都不收外幣,客人付的永遠是 TWD。
查匯率走 GET /exchange-rates(台銀牌告表,含現金 / 即期 × 買入 / 賣出四報價)與 GET /exchange-rates/resolve(解析某幣別某日的「1 外幣 = ? 台幣」)。resolve 的 fail-safe 約定:查無匯率回 200 帶 rate: null(不是 404),呼叫端請對 null 分支,不要靜默用 0 或 1。
每梯次只算到毛利
每一梯的權威數字是毛利 = 本團收入 − 真實成本,不扣手續費 / 稅:
本團收入 = 該梯次「成交應收」(不是當期收到的現金)
真實成本 = 已覆核成本的內帳真實額加總(含房費)
毛利 = 本團收入 − 真實成本
收入認列口徑要記牢:本團收入是該梯次的成交應收,不是當期收到的現金(訂金 / 尾款常跨月分次收)。期間歸屬一律看出團月——某梯 5 月出團、3 月收訂金、6 月收尾款,全額營收與毛利都落在 5 月。
讀每梯次內外帳走 GET /internal-external-ledger/departures(列表)與 .../departures/{departureId}(單梯派生:revenue / realCost / declarable / grossProfit / estimatedNetProfit)。estimatedNetProfit 只是給現場快速感覺的參考預估(毛利減預估費率),不是公司財務真相。
掛帳台帳的跨梯彙整走 GET /accrual-ledger(單期間四區塊)與 .../departure-summary(梯次彙總:收入 / 真實成本 / 毛利)。
取消梯次的成本認列
取消的梯次不入毛利——它沒有出團月,0 收入配上已發生的成本會讓各區毛利失真,所以內外帳列表與損益表的各區毛利一律排除取消梯次(掛帳台帳除外:欠廠商的錢照樣要追,台帳彙總仍含取消梯次)。退訂沖銷後殘餘不可退的成本(沒收的訂金、床位費等,含分房房費)由承辦人人工確認,一鍵結轉成一筆「特殊損益」費用,落在公司月損益表的特殊損益列——不會自動結轉,因為退訂協商還在進行時提早認列會把還拿得回來的錢記成損失。
| 端點 | 用途 |
|---|---|
GET /internal-external-ledger/cancelled-departures | 取消梯次待結轉清單(殘餘成本 / 是否已結轉) |
POST .../cancelled-departures/convert | 結轉殘餘成本為特殊損益(一梯次限一筆) |
POST .../cancelled-departures/revert | 撤銷結轉(可重新結轉) |
結轉後整個梯次進入凍結:不能改回銷售中、不能結團、成本與房費也不能再登記或修改——否則殘餘會同時(或都不)出現在毛利與特殊損益兩邊。結轉出來的特殊損益列同樣不能用一般費用編輯改動。要調整任何一項,一律走「撤銷結轉 → 修改 → 重新結轉」。
公司月損益
公司真實淨利在公司層算,把手續費 / 稅 / 辦公室費用用實際值扣一次(避免與每梯次重複計):
公司營業費用是與梯次無關的支出,逐筆登錄成台帳,按月歸屬;費用科目由租戶自訂。對應 API:
| 端點 | 用途 |
|---|---|
GET /pnl/statement | 公司月損益表(各區毛利 → 公司淨利) |
GET /pnl/expenses | 公司營業費用台帳(可依月 / 大類 / 科目篩選) |
GET /pnl/expense-categories | 費用科目目錄(租戶自訂) |
POST /pnl/expenses · PATCH /pnl/expenses/{id} | 登錄 / 更正費用 |
費用大類(kind)分 opex(一般營業費用)、tax(稅)、platform_fee(平台手續費實際月結)、special(一次性特殊損益)。損益表按大類 roll-up 成幾格,點開再 drill-down 到逐筆。「人事」這格只裝行政 / 內勤固定薪——領隊費屬每梯次直接成本,已算進該梯毛利,不要重算進公司人事。
月固定費用自動生成草稿
每月都會重複的公司費用(辦公室租金、行政固定薪、電信、網路…)不必每月手動重登。租戶可在設定建一份月固定費用範本(預設科目 / 金額 / 出帳帳戶),之後系統每月月底自動為每個範本生成下月的費用草稿——月中就能先過目、確認下個月的固定支出。
這對 API 消費者的意義,在 GET /pnl/expenses 的每一列回傳欄位上看得到:
| 欄位 | 值 | 意義 |
|---|---|---|
status | "draft" / "confirmed" | 草稿 = 待確認、不計入損益;已確認 = 入帳 |
origin | "manual" / "recurring" / "departure_conversion" | recurring = 月固定範本自動生成 |
sourceTemplateId | 範本 ID / null | origin 為 recurring 時指回生成它的範本 |
損益表只算已確認的費用。GET /pnl/statement 一律排除 status: "draft" 的列——自動生成的草稿在有人確認前不會進帳,這是「避免無人確認的鬼列」的安全前提。所以你在 pnl/expenses 台帳看到某筆 recurring 草稿,它還沒反映在當月損益表上,要等確認。確認是後台的人工步驟(確認時可順手改金額)。
經 POST /pnl/expenses 手動登錄的費用預設直接是已確認(status: "confirmed"),立即入帳——只有月固定範本自動生成的那批才會落在待確認草稿。自動生成同範本同月至多一列(冪等),所以月底排程重跑、或補算某個歷史月份,都不會產生重複列。
下一步
- 成本與範本:成本怎麼登記、行程綁範本自動帶成本行。
- 收款帳戶與結算:多帳戶分流、跨帳戶補款、月結互抵與換匯。
- 付款流程:客人收款、退款、出款(payables)的分界。
- internal-external-ledger API · pnl API。