- 省時
財務月底對帳:進項發票在同一個網站匯入、查詢、算出總額
讓財務在同一個網站完成進項發票匯入、查詢與彙總,再同步到試算表的發票欄位。
背景與使用技術(4 項)
每月六千到八千筆進項發票,原本要逐筆下載、人工加總、比對作廢與折讓,再複製貼上到對帳表,大約要花掉一個人一週。這套內部網站把匯入、查詢、彙總與同步放在同一條流程裡:CSV 編碼自動辨識,同一份檔案重複匯入不會產生重複資料,整批總額由資料庫一次算完,同步到對帳表時保留財務自己加的公式欄。
誰在用
每月要對帳進項發票的財務團隊
原本怎麼做
月底對帳的痛點不在慢,而在加錯。進項發票的金額要逐張加總,作廢與折讓又不會寫在原本的發票上,得和另外幾份檔案兩邊對。錯誤要等到月底對帳不平才浮出來,然後得回頭一列一列找差額從哪來。
前後對比
量測:實測=有計時或有紀錄;估計=喜特先生推估;客戶自述=客戶回報;規格=設計上的固定條件;待補=尚未取得數字。
流程一眼看懂
發票金額逐張加總
作廢與折讓和其他檔案兩邊對
月底對帳不平才發現
一列一列找差額
匯入發票
查詢與跨頁彙總
明細
同步到試算表的發票欄
流程示意:依本案既有做法整理,非客戶實際畫面。
做了什麼
- 查詢與彙總共用同一套篩選:條件只寫一次,清單和總額不會分岔。
- 跨頁總額交給資料庫算,不必把幾千列撈出來相加。
- 以發票號碼匯入,只更新真的有變動的欄位,重複匯入不會出亂子。
- 同步只寫發票欄位,右側的公式欄一概不碰。
- 發票資料放在獨立區塊,只授權給伺服器端,再疊一層列級權限。
程式碼與實作細節收在頁面下方,需要時再展開。
你的情況像這樣嗎?
- 月底對帳,總額要靠逐張加總,錯了要等到對不平才知道。
- 清單的筆數和總額偶爾對不上,也說不出是哪一批。
- 對帳表右側有自己加的公式,不想被同步洗掉。
更多成果與運作條件
約 1 週 → 約 10 分鐘(客戶自述)
財務團隊自行回報的月度處理時間(每月 6,000 到 8,000 張),尚未用工時紀錄實測
6,000–8,000 張
每月處理量
1 條 SQL
整批篩選結果的三欄金額總和,在查詢時一起回傳
以上為本案既有成果與運作條件;估計值依原始資料標示,其他專案需另行評估,並非通用成效保證。
挑戰:原本遇到的困難
月底對帳的痛點不在慢,而在加錯。進項發票的金額要逐張加總,作廢與折讓又不會寫在原本的發票上,得和另外幾份檔案兩邊對。整套流程還有四個容易出事的地方:
- 清單與總額可能不是同一批:一頁只放得下幾十筆,但財務要的是整批總額。如果列清單和算總額是兩段各自寫的程式,改動之後會悄悄分岔,畫面上看不出異狀
- 中文編碼不固定:下載回來的 CSV 有時是一種編碼、有時是另一種,挑錯就是整片亂碼
- 對帳表不是空白的:發票欄位右側,財務自己加了幾欄公式。整列覆寫會連公式一起洗掉,而且要等同步完才會發現
- 資料是公司整年的採購憑證:安全標準不能停在「網址沒人知道」
人工做時,錯誤要等到月底對帳不平才會浮出來,然後得回頭一列一列找差額從哪來。
完整解決方案與設計取捨
財務用公司帳號登入後,月度作業沿著「匯入、查詢、明細、同步」一條線完成,不必在不同網站與檔案之間來回。
核心設計
- 查詢與彙總共用同一套篩選邏輯:條件只寫一次,列清單與算總額走的是同一份篩選,不會分岔
- 跨頁彙總交給資料庫:應稅金額、稅額、含稅總額用一條聚合查詢在資料庫端算完,不必把幾千列撈到應用層相加
- 差異式匯入:以發票號碼為主鍵,沒見過的就新增、已存在的只更新真的有變動的欄位,所以重複匯入結果相同
- 同步只寫發票欄位:同步範圍限定在發票欄位所在的區塊,右側公式欄一概不碰
- 兩道資料存取的牆:發票資料放在資料庫裡獨立的區塊(schema),只授權給伺服器端的角色,再疊一層列級權限(Row Level Security)
技術與實作細節
展開完整實作說明
這件事用人工做,會壞在哪裡?
有三個地方,而且每一個都不會自己舉手。
第一是算術。每張發票三個金額,一列一列加下去,按錯一列、跳過一列或同一列算了兩次,當天看起來都很正常,要到月底對帳不平才浮出來。
第二是狀態。作廢與折讓躺在另外幾份檔案裡,「把每張發票都當成還算數」的加總會錯得很有自信,光看發票本身看不出來。
第三是周邊事務。檔案編碼挑錯、對帳表靠複製貼上餵、想核對一張發票的原始掃描檔得在雲端硬碟裡逐層翻資料夾。每一件拆開看都不難,難的是每個月都要從頭做一次,而且每次都是幾千張。
兩道牆:獨立資料區加列級權限
前端用的匿名金鑰(anon key)會隨網頁送到使用者手上,任何人打開開發者工具都看得到。所以只要發票資料對這把金鑰開放,整年的進項憑證就等於掛在網路上。
因此發票資料放在獨立的 schema(資料庫裡獨立的資料區),只授權給伺服器端使用的角色,瀏覽器拿到的金鑰對這個 schema 沒有任何權限,讀寫一律經過伺服器端的 API。在這之上再疊一層 Row Level Security(列級權限,由資料庫逐列決定誰能讀寫)。理論上 schema 隔離已經足夠,但日後多加一個角色、改一次授權、開一個新的整合帳號,都可能不小心把 schema 打開;列級權限是第二道,兩道都過了才碰得到資料。
差異式匯入,與不寫無意義的歷史
「重複匯入結果相同」這件事寫在資料庫端的函式裡(技術上叫 upsert:有則更新、無則新增)。沒見過的發票直接新增;已存在的發票逐欄比對,只有真的變動才更新。完全沒變的那一列,連狀態歷史都不寫。
這條規則是特意加的,因為同一份 CSV 會被重複匯入。若每次都留下「其實什麼都沒改」的紀錄,之後要追一張發票的狀態變化時,就得從雜訊裡撈出真正的幾筆。每次狀態變動的歷史會保存變更前的完整快照,日後可以回頭查。
折讓拆成表頭與明細兩張表,就有明細存在、表頭卻找不到的可能。系統多做一道孤立檢測,把這類不一致抓出來,免得折讓資料半截掛著,等到對帳才發現。
同步範圍是寫死的欄位區塊。如果財務日後在對帳表中間插入或搬動發票欄位,同步範圍必須一起調整,否則會寫錯位置。這個限制要在交接時講清楚。
檔案編碼與掃描檔找尋
CSV 的編碼不讓使用者選。系統先以 UTF-8 解碼,若結果中出現解碼失敗的替代字元,就判定檔案其實是 Big5(舊式的繁體中文編碼),改用 Big5 重新解析。使用者只需要上傳。
發票掃描檔存在雲端硬碟,依日期歸檔,檔名依「日期加發票號碼」命名。明細頁直接依規則組出路徑去找,找不到時顯示「尚未上傳」,而不是報錯,因為不是每張發票都保證有掃描檔。
下載發票 CSV 的步驟後來另外接上了排程下載,但登入政府電子發票平台仍需人工輸入一次驗證碼,不是完全無人值守。CSV 進入系統之後,後面每一步都是自動的。