Bug #1416
是由 陳國瑋 於 約 2 個月 前更新
## 1. 問題摘要
A17 的月結算目前以 transaction 開始時間選取整筆交易,且完整交易會優先使用 `meterStart/meterStop` 搭配交易開始時間的單一費率。跨月份、跨尖峰/離峰或在每月 1 日 03:00 尚未完成的交易,可能發生月份歸屬錯誤、費率錯誤及剩餘用電漏帳。
本票修正月結算與所有電費預估入口,使其共用同一套以 MeterValue 計費區段為基礎的分月、分時計價規則。
## 2. 發生環境與 A17 證據
- 系統/模組:`ems_branch` 月結算、帳單與電費預估
- 環境:寶台 A17 production
- 查核日期:2026-08-07
- Transaction:`375`
- Connector:`CP003-005`
- 開始:2026-05-31 23:58:04
- 結束:2026-06-01 04:55:01
- 總用電量:16.160 kWh
- 5 月結算建立時間:2026-06-01 03:00:00
唯讀 DB 核對結果:
- 排除 transaction 375 後,該 connector/account 的 5 月交易總量為 498.750 kWh。
- 5 月正式帳單為 509.840 kWh、2,044.04 元且狀態為 paid。
- 可反推出 transaction 375 在 03:00 結算時只被納入 11.090 kWh、44.13 元。
- 交易完成後尚有 5.070 kWh 未結算;依當時離峰費率 3.98 元估算約 20.18 元。
- 6 月正式帳單為 513.500 kWh、2,147.27 元,等於所有「6 月開始」交易的總量,未包含上述 5.070 kWh/20.18 元。
## 3. 已確認的帳務期間
1. 排程仍於每月 1 日 03:00 執行上月結算。
2. 帳務期間固定為上月完整月份。
3. 程式內使用半開區間,例如 2026 年 7 月為:
- 起點:`2026-07-01 00:00:00`,包含。
- 終點:`2026-08-01 00:00:00`,不包含。
4. 上述區間等同 7/1 00:00 至 7/31 23:59:59,且可正確處理毫秒/微秒資料。
5. 8/1 00:00 至 03:00 的用電不得列入 7 月。
6. 時間判斷一律使用案場時區 `Asia/Taipei`。
## 4. 已確認的 MeterValue 計費區段規則
### 名詞定義
`MeterValue 計費區段` 是由相鄰兩筆累積能源讀數形成的最小計費單位。它不是整筆 Transaction,也不是 Tariff 的尖峰/離峰時段。
- 計費區段開始時間:前一筆 MeterValue 的 timestamp。
- 計費區段結束時間:後一筆 MeterValue 的 timestamp。
- 計費區段用電量:後一筆 MeterValue 減前一筆 MeterValue。
- 計費區段的月份與電價:均以前一筆 MeterValue 的 timestamp 判定。
例如累積讀值依序為 `7/31 23:59:30 = 10,000 Wh`、`8/1 00:00:00 = 10,050 Wh`、`8/1 00:00:30 = 10,110 Wh`:
- 第一個計費區段為 7/31 23:59:30~8/1 00:00:00,用電量 50 Wh;因開始時間在 7 月,整段計入 7 月。
- 第二個計費區段為 8/1 00:00:00~8/1 00:00:30,用電量 60 Wh;因開始時間在 8 月,整段計入 8 月。
- 若計費區段為 7/31 23:59:50~8/1 00:00:20,整段仍計入 7 月,不依秒數拆分。
### 計算規則
1. 交易只要與結算月份有時間重疊就必須納入,不再只依 `Transaction.startTimestamp` 所在月份選取。
2. 相鄰兩筆累積能源讀數形成一個MeterValue 計費區段: 相鄰兩筆累積能源讀數形成一個用電計費區段:
- 計費區段用電量=後一筆 MeterValue-前一筆 MeterValue。
- 前一筆 MeterValue 的 timestamp 為計費區段開始時間。
3. 以計費區段開始時間決定:
- 歸屬月份。
- 夏月/非夏月。
- 平日/週末假日。
- 尖峰/半尖峰/離峰。
- 當時有效的 Tariff 版本與單價。
4. 不做月份或費率邊界內插。
5. 若一個MeterValue 計費區段跨過月份或費率邊界,整段歸入計費區段開始時間所屬的月份與費率。 若一個採樣計費區段跨過月份或費率邊界,整段歸入計費區段開始時間所屬的月份與費率。
6. 允許月份/費率邊界最多有一個 MeterValue 採樣週期的偏差。
7. `meterStart` 與 transaction start timestamp 可作為交易起點讀數;`meterStop` 與 transaction stop timestamp 可作為交易終點讀數。
8. MeterValue 必須依 timestamp 排序並避免重複計算;負增量、重複/衝突讀數或無法解析的能源讀數視為資料異常,不得靜默計為 0 元。
## 5. 計價與彙總規則
1. 各 MeterValue 計費區段使用計費區段開始時間當時有效的歷史 Tariff 計價。
2. 月結算、未結算帳單、交易紀錄及後台預估金額必須共用同一套分段計價引擎,避免不同畫面產生不同結果。
3. 各計費區段以完整精度計算,月度金額加總完成後才四捨五入至小數點後 2 位。
4. 基本費規則維持不變。
5. 服務費率維持不變,但服務費須使用分月後的正確用電量計算。
6. Tariff 缺少對應日期/時段/費率版本時,不得以 0 元完成結算,必須列為資料異常。
7. 後端需保存足以稽核尖峰/半尖峰/離峰度數、單價及金額的計價明細;原始 MeterValue 後續清理後仍須能說明帳單如何計算。
## 6. 進行中交易與延遲資料
1. 月初 03:00 若交易仍在進行中,只計算「計費區段開始時間位於上月」的MeterValue 計費區段。 若交易仍在進行中,只計算「計費區段開始時間位於上月」的用電計費區段。
2. 若設備離線、OCPP 訊息尚未補送或 MeterValue 資料不完整:
- 只能產生未完成的草稿結算。
- 不得進入財務審核。
- 不得以 0 度、單一費率或時間比例猜測完成帳單。
- MeterValue 補齊後需自動、冪等重算。
- 若資料持續異常,維持待處理狀態並留下可查詢的錯誤與稽核紀錄。
3. 同一月份重跑結算不得重複計費,也不得遺漏已補齊的MeterValue 計費區段。 同一月份重跑結算不得重複計費,也不得遺漏已補齊的用電計費區段。
## 7. 帳單狀態與歷史資料
1. `DRAFT` 可自動重算。
2. 待財務審核的資料可由人工觸發重算;重算後必須重新審核。
3. `SETTLED`、已付款及已逾期帳單不得自動改寫。
4. A17 transaction 375 所屬的 5 月帳單已付款,本票不得直接修改該帳單。
5. 漏列的 5.070 kWh/約 20.18 元由財務另行決定是否以後續調整項補收,不納入自動資料修正。
## 8. API、FE 與相容性範圍
1. 本票包含後端計算、必要資料結構、稽核明細及既有電費查詢/預估入口的一致性修正。
2. 現有 API 的總用電量與總金額欄位必須保持相容。
3. 本票不修改住戶端或 Branch Admin FE。
4. 客戶帳單目前仍顯示總用電量與總金額。
5. 若未來要顯示尖峰/半尖峰/離峰分項,另開 FE 需求。
## 9. 驗收條件
- [ ] 8/1 03:00 執行 7 月結算時,只計入計費區段開始時間位於 `[7/1 00:00, 8/1 00:00)` 的用電。
- [ ] 8/1 00:00 至 03:00 的用電不會進入 7 月帳單。
- [ ] 交易開始於上月或更早,只要有MeterValue 計費區段開始於本月,就會正確進入本月帳單。 交易開始於上月或更早,只要有用電計費區段開始於本月,就會正確進入本月帳單。
- [ ] 交易結束於次月,只要有MeterValue 計費區段開始於本月,就會正確進入本月帳單。 交易結束於次月,只要有用電計費區段開始於本月,就會正確進入本月帳單。
- [ ] 跨月份、夏月/非夏月、平假日、尖峰/半尖峰/離峰及 Tariff 版本邊界時,皆以計費區段開始時間正確歸屬。
- [ ] 月結算、未結算帳單、交易紀錄與後台預估金額使用相同分段計價結果。
- [ ] 分段用電量合計與可用的 transaction 首尾讀數一致;若不一致則列為異常,不得靜默結算。
- [ ] MeterValue 延遲時只產生草稿,資料補齊後可自動且冪等重算。
- [ ] Tariff 缺漏、負增量、重複/衝突 MeterValue 等異常不會產生 0 元正式帳單。
- [ ] 重跑 DRAFT/待審核結算不會重複計費;已結算、已付款及已逾期帳單不會被自動改寫。
- [ ] 現有 API 總額欄位保持相容,現有 FE 不需修改。
- [ ] 後端保存可稽核的分時度數、單價與金額明細。
- [ ] 新增 production regression E2E case,優先級 P0,trigger:Billing/Tariff/Settlement/Release/Hotfix。
## 10. E2E Impact
- Classification:**Add**
- Domain:Billing/Tariff/Settlement
- Priority:**P0**
- Status:實作完成前為 Gap,通過正式回歸後轉 Active
- Trigger:Billing、Tariff、Settlement、Release、Hotfix
- Release pack:Hotfix 至少執行所有適用 P0;Standard 執行 P0+P1
## 11. 相關程式
- `service/SettlementService.java`
- `schedule/BillSettlingTask.java`
- `repository/TransactionRepository.java`
- `repository/MeterValueRepository.java`
- `util/TariffCalculationUtil.java`
- `service/HistoricalTariffService.java`
- `api/bill/BillHqService.java`
- `service/TransactionService.java`
返回