- 省時
- 一眼看到
集團財務月結:多家公司的報表一次產出,換匯規則寫進程式
選好期間與帳體,產出財務報表和儀表板用長表。目前正式上線的是其中一個帳體。
背景與使用技術(4 項)
集團底下每家公司(稱為帳體)各自記帳、各用各的幣別,每個月結都要逐一登入會計系統匯出,再到試算表對欄、查匯率、換成美金後手動合併,前後要兩到三天。改成部署在公司網域下的 Web App(Apps Script 發布成的網頁工具),選好粒度與期間按一次,就產出各帳體原幣別與集團統一美金的損益表與資產負債表,並自動歸檔到雲端硬碟。同一條管線也輸出六份長表,供管理儀表板使用。
誰在用
集團財務團隊:集團底下有多家各自記帳的公司,稱為帳體
原本怎麼做
月結本身不複雜:把各帳體這一期的分錄拉出來,按科目彙總,換成同一種幣別。麻煩在於每個帳體是獨立的線上帳號,匯出要登入好幾次,合併則靠人在試算表裡對欄位、查匯率、加總,整輪兩到三天。期間選錯、用到舊匯率,出來的仍是看起來正常的數字,只能一個帳體一個帳體重對。
前後對比
量測:實測=有計時或有紀錄;估計=喜特先生推估;客戶自述=客戶回報;規格=設計上的固定條件;待補=尚未取得數字。
流程一眼看懂
各帳體登入
匯出
人工對欄位、查匯率、加總
報表
選期間與帳體
拉取分錄並依科目彙總
依匯率表換算
報表歸檔,同時輸出 6 份長表
流程示意:依本案既有做法整理,非客戶實際畫面。
做了什麼
- 換匯規則寫進程式:匯率來自財務維護的匯率表,不抓當下的市場報價,同一期間重跑才會得到同一個數字。
- 單一帳體或集團合併由財務選,所有帳體走同一條程式路徑。
- 每月排程重跑當年度全部報表,單一步驟失敗不中斷,跑完發 Slack 摘要。
- 目前只有 1 個帳體正式上線,其餘尚未串接;管線已定義好連上之後怎麼處理,新增帳體不必重新設計。
程式碼與實作細節收在頁面下方,需要時再展開。
你的情況像這樣嗎?
- 你每個月要從好幾個獨立的帳號匯出資料,再手動合併。
- 重跑一次,數字有時會對不上,因為匯率或期間選得不一樣。
- 管理層想看跨月、跨單位的趨勢,卻沒有地方並排。
更多成果與運作條件
月結產出時間(實測)
人工循環約兩到三天,已串接的一個帳體現在約兩小時
每次 3,000 至 10,000 筆分錄
依科目彙總,所有帳體走同一條程式路徑
六份長表接上儀表板
管理層可自行切換國家與時間範圍,不必另外請人整理
以上為本案既有成果與運作條件;估計值依原始資料標示,其他專案需另行評估,並非通用成效保證。
同一批數字,兩種輸出
寬表讓財務並排閱讀,長表供儀表板切片分析。
畫面示意・範例資料,非客戶實際截圖。手機可左右滑動查看。
挑戰:原本遇到的困難
月結本身不複雜:把各帳體(集團底下各自記帳的公司)這一期的分錄拉出來,按科目彙總,換成同一種幣別。麻煩在於每個帳體是獨立的線上帳號,匯出要登入好幾次,合併則靠人在試算表裡對欄位、查匯率、加總。
- 人工循環長:每個帳體都要登入、匯出、關閉,整輪兩到三天
- 錯誤不會報錯:期間選錯、用到舊匯率,出來的仍是看起來正常的數字,只能一國一國重對
- 趨勢沒有地方看:現金流、帳齡、營收集中度跨帳體、跨月份無處並排
目標是同一期間重跑得到同一個數字,換匯規則寫進程式。
完整解決方案與設計取捨
把整段流程搬進一個部署在公司網域下的 Google Apps Script Web App,底層用共用的 Apps Script 函式庫。每個帳體第一次使用時完成一次 OAuth 授權(登入並同意工具讀取會計資料),之後 token(授權憑證)自動更新,不必每次重連。
財務選好報表粒度(月、季、年或自訂區間)與期間,再決定是單一帳體還是集團合併。工具拉取資料、依粒度彙整,集團範圍換算成美金,產出損益表與資產負債表,並依集團與各國歸檔到雲端硬碟的資料夾。同一次執行另外輸出六份長表,給 Looker Studio 儀表板使用。
客戶營收的月增月減是獨立入口,超過門檻的儲存格自動標色。每月排程會重跑當年度全部報表與長表,單一步驟失敗不中斷,跑完發一則 Slack 摘要。目前完成串接、正式上線的只有一個帳體,另有一個舊帳體待重新串接,其餘帳體尚未串接;管線已經定義好連上之後怎麼處理,新增帳體不必重新設計。
技術與實作細節
展開完整實作說明
月結第二天,總數為什麼兜不攏?
情境改寫:依月結常見的狀況整理,細節為示意。
月結第二天下午,財務傳來一句話:合併表的總數兜不攏。打開試算表從頭對一輪,對到第四家公司,才發現某一欄的期間選錯了,整個下午就這樣過去。沒有紅字,沒有警告,數字看起來完全正常,只是跟會計那邊的總額差了一截。
這種事每個月都可能發生,而且每次都是從頭來。
六家公司各自一個帳號,匯出會卡在哪裡?
集團底下的六家公司,在線上會計軟體裡是六個獨立的帳號,各記各的帳,各用各的幣別。所以「匯出」的意思是:登入其中一家的帳號,匯出這一期的數字,關掉;再登入下一家,再匯出一次。六輪下來,才開始真正吃時間的那一段。
那一段是在試算表裡一格一格對齊欄位、查當年的匯率、把外幣金額換成美金,最後手動加總出集團版本。換匯的意思是把某個幣別的金額乘上匯率,換成另一種幣別。一次月結要處理三千到一萬筆分錄,每一筆分錄是一筆進出帳的紀錄,最後被收斂成報表上幾十個科目。
慢還撐得住,撐不住的是手工合併出錯時沒有任何警告。
寬表與長表,為什麼同一次要出兩種?
給人看的損益表是寬表,一欄一個帳體,列是科目,方便從左到右讀。儀表板要的是長表,每列一筆觀測,欄位是期間、國家、科目與金額,才方便樞紐與切片。兩種形狀無法同時兼顧,所以同一次執行各出一份。
圖:同一批數字,寬表給人讀,長表給儀表板切片。
長表內部也不是同一種形狀。損益、資產負債、現金流這些期間類資料,列是國家乘期間乘科目。帳齡是某一天的快照,列是國家乘對象乘帳齡區間,用截止日而不是期間,因為帳齡只回答「現在拖了多久」。帳齡指應收(客戶欠我們的錢)與應付(我們欠別人的錢)各自拖了多久。營收則是國家乘期間乘客戶或產品。
硬把三種形狀塞進同一張表,就得挑一個共同分母,每種資料本來的維度就被丟掉。所以選擇多做幾個分頁,一共六份長表,讓每個領域都能用自己需要的維度切。
換匯時缺一筆匯率,整份報表要不要停?
集團報表換成美金時,匯率來自財務部維護的匯率表,不靠即時抓市場報價。原因是報表用的匯率必須跟會計那邊講好的一致,而且同一期間重跑,要得到同一個數字。
某個幣別在那一期缺匯率時,工具記一筆警告、略過該欄的美金換算,其餘能換的照常產出,整份報表不會因此失敗。下面是簡化過的示意寫法,並非原始程式:
function toUsd(amount, currency, fxTable) {
const rate = fxTable[currency]; // 財務部維護的匯率表,非即時報價
if (rate === undefined) {
log.warn(currency + ' 缺匯率,略過美金欄');
return null; // warn-skip:其餘能換的照常產出
}
return amount * rate;
}這樣做的代價是美金欄會空缺,要靠警告去補。結帳當下少一筆匯率,不應該讓整份集團報表產不出來。各國的原幣別報表完全不受匯率表影響,換算只發生在集團合併這一步。
版面改了,怎麼確定數字沒跑掉?
報表的核心拆成兩半。資料模型只負責數字,是一份與輸出格式無關的損益結構;渲染器只負責把模型畫成試算表的版面。中間還有一層解析器,把會計軟體回傳的原始結構轉成模型。
第一版把版面與計算寫在同一支函式裡。財務每次想加一列小計、換欄位順序,都得在算數字的程式旁邊動手。報表出錯最危險的地方是它不會報錯,只會給一個錯的數字,而這種寫法讓一個低風險的版面需求,有機會碰到高風險的計算。
拆開之後,改視覺只動渲染器,改彙整只動模型與彙整引擎。財務每個月來回調版面好幾次,底下的數字卻一次都沒變。
客戶營收的月增月減,怎麼抓出異常?
客戶營收的月增月減是獨立入口。財務選一個帳體,填起迄日期與門檻百分比,預設是 20%。工具保留會計軟體原生的客戶與子客戶階層,寫進試算表後用列群組收合展開,逐月比對每個客戶的營收。月增或月減超過門檻的儲存格自動標色,備註寫明變化百分比與前後金額。
比較邏輯有兩個邊界情況。父客戶有時會計軟體會給小計,有時不給,這時就用子列逐月加總頂上。前一個月金額為零時直接跳過,因為分母是零,任何成長率都會變成誤導性的暴增。示意如下:
function momFlag(prev, curr, threshold = 0.2) {
if (!prev) return null; // 前一月為 0 或沒資料:不比較
const pct = (curr - prev) / prev; // 例如 1200 → 1500,pct = 0.25
return Math.abs(pct) >= threshold ? pct : null;
}這支比較邏輯不碰試算表,也不碰會計系統,用一份寫死在程式裡的測試資料涵蓋四種情況:一般客戶、有會計軟體小計、無小計靠加總、前一月為零。在編輯器裡選函式執行,看 Log 就能驗證,改動之後一分鐘內可以重驗。
每次重跑,會不會留著上次的舊資料?
長表每次執行都整批清空重寫,沒有「只補新增月份」的邏輯。資料量是幾個帳體、幾個年度的月度彙總,重算成本很低;增量同步則要追蹤哪些列變了、哪些列該刪,在這個量級上不划算。每次從頭跑同一份邏輯,就不會有沒跑到的月份還留著舊值的情況。
每個資料源外面還包了一層防護。現金流、帳齡、營收任何一個資料源對某個帳體失敗,只記一筆警告並回傳空陣列,不讓單一來源拖垮整份六分頁的匯出。
哪些事情還要人來做?
最後一按留在人手上。要產哪一期、用哪個粒度、這個月的帳結完了沒有,都是財務的判斷。工具接手的是判斷之後的所有事。每月排程補的是「這個月沒有人剛好去按」的空檔,定時重跑當年度全部報表與長表,不取代手動一鍵。
還有幾件事沒有自動化。集團合併的定義是把各帳體並排彙整、統一換成美金,不含公司間交易的沖銷。沖銷是把集團內部互相買賣的金額扣掉,避免重複計算,那需要先盤清楚有多少關聯交易該沖,是會計面的判斷。架構上各帳體的資料在彙整前是分開的,之後要加入沖銷,不必重拆管線。
目前只有一個帳體完整上線。另有一個舊帳體待重新串接;其他國家尚未串接。切到正式環境時,要清掉各帳體殘留的測試 token,切換後到 Web App 重新授權,否則舊連線會混進正式環境的呼叫而失敗。
Looker Studio 的五頁儀表板無法用程式碼建置,圖表與計算欄位是照操作手冊在介面上一格一格組出來的。這條管線自動化的是資料怎麼變成長表,儀表板這一層仍是人工組裝。
月結時間與分錄量,改善了多少?
人工循環原本約兩到三天。已串接的那個帳體,現在選好粒度與期間按一次,約兩小時產出報表,並自動歸檔到 Drive 對應的資料夾。兩小時這個數字只適用於已串接的那一個帳體,其他帳體還沒有比較的基礎。
每次執行的分錄量是三千到一萬筆,全部依科目彙總,所有帳體走同一條程式路徑。同一次執行產出的六份長表接上 Looker Studio 後,管理層可以自己切國家、拉時間範圍看趨勢,不必再開一張報表需求。
以前合併出錯是靠總額兜不攏才發現,現在超過門檻的客戶營收會自動標色,財務看顏色就知道要追哪一家。