CF精算表パイプラインの大幅拡張
朝、前日までのCF精算表パイプラインを動かすと、短期借入金が未対応のまま放置されていた。取引モジュールに科目を1つ追加するだけの話に見えたが、触り始めると集約シートの設計、未払費用の補助科目分解、符号エラーの修正、そしてテスト自動化まで芋づる式に課題が出てきた。気づけば夕方まで手が止まらなかった。
短期借入金を取引モジュールに追加
みずほ銀行からの短期借入金(100万、年利2%)を取引モジュールに追加した。返済予定表シートに月次の元本返済と利息支払いの行を並べ、年度ごとのCF調整額を計算する。長期借入金と同じ構造なので、既存の辞書にキーを足す形で対応できた。
シート命名規則の最終決定
シート名の接頭辞を TPL_ にするか漢字にするかで迷いがあった。TPL_返済予定表 という表記は、Pythonスクリプト側では分かりやすいが、Excelを開いたときにタブが英字と漢字の混在で読みにくい。
最終的に 取引_ 接頭辞に統一した。取引_返済予定表、取引_回収予定表 のように、シートタブだけ見て「これは取引モジュール由来のシートだ」と判別できる命名に落ち着いた。全スクリプトのシート名参照を一括置換した。
集約シートの設計 --- 配置場所をめぐる議論
問題: INDEX/MATCH足し算の限界
短期借入金が加わったことで、CFWSの各セルに書くINDEX/MATCH数式が膨らんだ。短期借入金の返済予定表と長期借入金の返済予定表を別々にMATCHして足し算する。貸付金が加われば3項になる。科目が増えるたびに数式が伸びていき、可読性が消える。
中間の集約シートを1枚噛ませて、各取引モジュールの値を1箇所にまとめる方針に切り替えた。
最初の案: CFWS側に集約シートを配置
最初はCFWS(Step c)のExcel内に集約シートを新設する案で進めた。CFWSが各取引モジュールのExcelを参照して集約する形だ。しかし、この構造だと外部ファイル参照が増え、パスが壊れたときのデバッグが面倒になる。
最終案: 取引モジュール側に集約シートを配置
議論を経て、集約シートは取引モジュール(Step a)側に配置することに決めた。各取引モジュールのExcel内に 集約 シートを追加し、そのExcel内の返済予定表・回収予定表から値を集める。CFWSはこの集約シートを値貼り付けで取り込む。
この構造にしたことで、取引モジュール単体で「この論点からCFWSに渡す値」が完結する。CFWSは集約シートの値を貼るだけなので、数式の依存関係が単純になった。
未払費用の補助科目分解
問題の発覚
CF精算表のBS科目に「未払費用」が1行で入っていた。しかし実際には未払利息と未払営業経費では調整先が異なる。未払利息はCF上「支払利息」の調整項目であり、未払営業経費は営業CFの調整項目だ。1行にまとめると、どちらのCF項目に紐づけるか決められない。
補助科目への分離
未払費用を 未払利息 と 未払営業経費 に分離した。年次推移表のBS階層に2行を追加し、それぞれのCF調整先を明示的に設定した。
未払利息の増減は「支払利息」の列で調整する。ここが少し直感に反する部分で、BS上は負債の増減なのに、CF上は支払利息の非資金調整として処理する。この仕訳形状について議論した結果、「利息の未払計上分はPLの支払利息からCFの実際支払額への橋渡しだ」という理解に落ち着いた。
CFWSのバグ修正
短期借入金返済の符号エラー
短期借入金の返済額がCFWSでプラスになっていた。返済はキャッシュアウトなのでマイナスが正しい。原因は取引モジュールからCFWSへ値を転記する際の *-1 が欠落していたこと。長期借入金では付いていたが、短期借入金の追加時にコピーし忘れていた。
PL計上額セクションの支払利息参照抜け
CFWSの「PL計上額」セクションに支払利息の参照が入っていなかった。年次推移表のPLには支払利息が計上されているのに、CFWSのPLセクションが読みに行っていない。支払利息の行を追加し、年次推移表の該当セルを参照するよう修正した。
COM経由のExcel自動検証
テスト方針の議論
テストコードの書き方で2つの案が出た。
案A: Pythonで数式を再実装して検証する。 openpyxlは数式を評価できないので、Pythonで同じ計算ロジックを書いて期待値を出し、Excelのセルと照合する。前日にこの方式で書いたが、ロジックの二重管理になる。Excelの数式を変更するたびにPython側も追従する必要がある。
案B: COM経由でExcelを開き、check=0をそのまま読む。 Excelの数式はExcel自身に評価させて、check行の値が0かどうかだけをPythonで確認する。数式の再実装が不要で、Excelが正ならテストも正。
議論の結果、案Bを採用した。「生成済みExcelのcheck=0をCOM経由で自動検証する薄いスクリプト」に落とし込むのが、保守コスト最小の選択だった。
verify_cfws_excel.py の作成
win32com.client でExcelアプリケーションを起動し、生成済みのExcelファイルを開く。各シートのcheck行を走査して、値が0でないセルがあればエラーとして報告する。
# 核心部分のみ
wb = excel.Workbooks.Open(abs_path)
for ws in wb.Worksheets:
for row in check_rows:
val = ws.Cells(row, col).Value
if val and abs(val) > 0.01:
errors.append(f"{ws.Name} Row{row}: {val}")
Excelを非表示モードで起動し、検証後にプロセスを閉じる。CIでは動かせないが、ローカルでの目視確認を自動化できた。
Codexレビューを経た設計修正
テスト計画をCodexにレビューさせたところ、「check行の位置をハードコードするとシート構造が変わったときに壊れる」と指摘が返ってきた。check行のセルに特定のラベル("check")が入っていることを前提に、ラベルで行位置を動的に検索するよう修正した。
全ステップの再生成と検証
短期借入金の追加、集約シートの新設、未払費用の分離、バグ修正を全て反映した上で、パイプライン全体を再実行した。
- 取引モジュール(Step a): 短期借入金+集約シート付きで再生成
- 年次推移表(Step b): BS/PLに未払利息・未払営業経費・支払利息を反映して再生成
- CFWS(Step c): 集約シートからの値貼り付けで再生成
verify_cfws_excel.py を実行して、全年度のcheck=0を確認した。符号エラーも参照抜けも解消されていた。
振り返り
集約シートの配置場所を決めるのに一番時間を使った。CFWS側に置く案で一度コードを書き始めてから、「取引モジュール側に置いたほうが依存が閉じる」と気づいて書き直した。手戻りは発生したが、この判断で数式の複雑度が目に見えて下がった。INDEX/MATCHの3項足し算が集約シートへの単一参照に変わり、セルの中身が一行で読めるようになった。
テスト方針の議論では、Python再実装とCOM経由検証の間で揺れた。前日までPythonで数式を再実装する方向で進めていたが、二重管理のコストに気づいてCOM経由に切り替えた。Excelが計算した結果をそのまま読む。当たり前のようで、openpyxlの世界にいると見えなくなる選択肢だった。