[{"data":1,"prerenderedAt":495},["ShallowReactive",2],{"content-/cfws-pipeline-expansion-borrowing":3,"all-pages-for-dir":493,"og-image-/cfws-pipeline-expansion-borrowing":494},{"id":4,"title":5,"body":6,"category":471,"description":472,"extension":473,"meta":474,"navigation":475,"path":476,"project_name":477,"published":478,"publishedAt":479,"seo":480,"stem":481,"tags":482,"todo":490,"updatedAt":491,"__hash__":492},"pages/2026-04/2026-04-04/cfws-pipeline-expansion-borrowing.md","CF精算表パイプラインの大幅拡張 --- 短期借入金・集約シート・自動検証を一日で組み上げた",{"type":7,"value":8,"toc":447},"minimark",[9,14,18,22,25,28,40,55,59,64,67,70,74,77,81,88,91,94,97,100,103,114,117,121,124,131,135,138,142,145,148,155,161,164,168,174,390,393,397,400,403,406,428,434,437,440,443],[10,11,13],"h1",{"id":12},"cf精算表パイプラインの大幅拡張","CF精算表パイプラインの大幅拡張",[15,16,17],"p",{},"朝、前日までのCF精算表パイプラインを動かすと、短期借入金が未対応のまま放置されていた。取引モジュールに科目を1つ追加するだけの話に見えたが、触り始めると集約シートの設計、未払費用の補助科目分解、符号エラーの修正、そしてテスト自動化まで芋づる式に課題が出てきた。気づけば夕方まで手が止まらなかった。",[19,20,21],"h2",{"id":21},"短期借入金を取引モジュールに追加",[15,23,24],{},"みずほ銀行からの短期借入金（100万、年利2%）を取引モジュールに追加した。返済予定表シートに月次の元本返済と利息支払いの行を並べ、年度ごとのCF調整額を計算する。長期借入金と同じ構造なので、既存の辞書にキーを足す形で対応できた。",[19,26,27],{"id":27},"シート命名規則の最終決定",[15,29,30,31,35,36,39],{},"シート名の接頭辞を ",[32,33,34],"code",{},"TPL_"," にするか漢字にするかで迷いがあった。",[32,37,38],{},"TPL_返済予定表"," という表記は、Pythonスクリプト側では分かりやすいが、Excelを開いたときにタブが英字と漢字の混在で読みにくい。",[15,41,42,43,46,47,50,51,54],{},"最終的に ",[32,44,45],{},"取引_"," 接頭辞に統一した。",[32,48,49],{},"取引_返済予定表","、",[32,52,53],{},"取引_回収予定表"," のように、シートタブだけ見て「これは取引モジュール由来のシートだ」と判別できる命名に落ち着いた。全スクリプトのシート名参照を一括置換した。",[19,56,58],{"id":57},"集約シートの設計-配置場所をめぐる議論","集約シートの設計 --- 配置場所をめぐる議論",[60,61,63],"h3",{"id":62},"問題-indexmatch足し算の限界","問題: INDEX/MATCH足し算の限界",[15,65,66],{},"短期借入金が加わったことで、CFWSの各セルに書くINDEX/MATCH数式が膨らんだ。短期借入金の返済予定表と長期借入金の返済予定表を別々にMATCHして足し算する。貸付金が加われば3項になる。科目が増えるたびに数式が伸びていき、可読性が消える。",[15,68,69],{},"中間の集約シートを1枚噛ませて、各取引モジュールの値を1箇所にまとめる方針に切り替えた。",[60,71,73],{"id":72},"最初の案-cfws側に集約シートを配置","最初の案: CFWS側に集約シートを配置",[15,75,76],{},"最初はCFWS（Step c）のExcel内に集約シートを新設する案で進めた。CFWSが各取引モジュールのExcelを参照して集約する形だ。しかし、この構造だと外部ファイル参照が増え、パスが壊れたときのデバッグが面倒になる。",[60,78,80],{"id":79},"最終案-取引モジュール側に集約シートを配置","最終案: 取引モジュール側に集約シートを配置",[15,82,83,84,87],{},"議論を経て、集約シートは取引モジュール（Step a）側に配置することに決めた。各取引モジュールのExcel内に ",[32,85,86],{},"集約"," シートを追加し、そのExcel内の返済予定表・回収予定表から値を集める。CFWSはこの集約シートを値貼り付けで取り込む。",[15,89,90],{},"この構造にしたことで、取引モジュール単体で「この論点からCFWSに渡す値」が完結する。CFWSは集約シートの値を貼るだけなので、数式の依存関係が単純になった。",[19,92,93],{"id":93},"未払費用の補助科目分解",[60,95,96],{"id":96},"問題の発覚",[15,98,99],{},"CF精算表のBS科目に「未払費用」が1行で入っていた。しかし実際には未払利息と未払営業経費では調整先が異なる。未払利息はCF上「支払利息」の調整項目であり、未払営業経費は営業CFの調整項目だ。1行にまとめると、どちらのCF項目に紐づけるか決められない。",[60,101,102],{"id":102},"補助科目への分離",[15,104,105,106,109,110,113],{},"未払費用を ",[32,107,108],{},"未払利息"," と ",[32,111,112],{},"未払営業経費"," に分離した。年次推移表のBS階層に2行を追加し、それぞれのCF調整先を明示的に設定した。",[15,115,116],{},"未払利息の増減は「支払利息」の列で調整する。ここが少し直感に反する部分で、BS上は負債の増減なのに、CF上は支払利息の非資金調整として処理する。この仕訳形状について議論した結果、「利息の未払計上分はPLの支払利息からCFの実際支払額への橋渡しだ」という理解に落ち着いた。",[19,118,120],{"id":119},"cfwsのバグ修正","CFWSのバグ修正",[60,122,123],{"id":123},"短期借入金返済の符号エラー",[15,125,126,127,130],{},"短期借入金の返済額がCFWSでプラスになっていた。返済はキャッシュアウトなのでマイナスが正しい。原因は取引モジュールからCFWSへ値を転記する際の ",[32,128,129],{},"*-1"," が欠落していたこと。長期借入金では付いていたが、短期借入金の追加時にコピーし忘れていた。",[60,132,134],{"id":133},"pl計上額セクションの支払利息参照抜け","PL計上額セクションの支払利息参照抜け",[15,136,137],{},"CFWSの「PL計上額」セクションに支払利息の参照が入っていなかった。年次推移表のPLには支払利息が計上されているのに、CFWSのPLセクションが読みに行っていない。支払利息の行を追加し、年次推移表の該当セルを参照するよう修正した。",[19,139,141],{"id":140},"com経由のexcel自動検証","COM経由のExcel自動検証",[60,143,144],{"id":144},"テスト方針の議論",[15,146,147],{},"テストコードの書き方で2つの案が出た。",[15,149,150,154],{},[151,152,153],"strong",{},"案A: Pythonで数式を再実装して検証する。"," openpyxlは数式を評価できないので、Pythonで同じ計算ロジックを書いて期待値を出し、Excelのセルと照合する。前日にこの方式で書いたが、ロジックの二重管理になる。Excelの数式を変更するたびにPython側も追従する必要がある。",[15,156,157,160],{},[151,158,159],{},"案B: COM経由でExcelを開き、check=0をそのまま読む。"," Excelの数式はExcel自身に評価させて、check行の値が0かどうかだけをPythonで確認する。数式の再実装が不要で、Excelが正ならテストも正。",[15,162,163],{},"議論の結果、案Bを採用した。「生成済みExcelのcheck=0をCOM経由で自動検証する薄いスクリプト」に落とし込むのが、保守コスト最小の選択だった。",[60,165,167],{"id":166},"verify_cfws_excelpy-の作成","verify_cfws_excel.py の作成",[15,169,170,173],{},[32,171,172],{},"win32com.client"," でExcelアプリケーションを起動し、生成済みのExcelファイルを開く。各シートのcheck行を走査して、値が0でないセルがあればエラーとして報告する。",[175,176,181],"pre",{"className":177,"code":178,"language":179,"meta":180,"style":180},"language-python shiki shiki-themes vitesse-light vitesse-light","# 核心部分のみ\nwb = excel.Workbooks.Open(abs_path)\nfor ws in wb.Worksheets:\n    for row in check_rows:\n        val = ws.Cells(row, col).Value\n        if val and abs(val) > 0.01:\n            errors.append(f\"{ws.Name} Row{row}: {val}\")\n","python","",[32,182,183,192,226,250,266,299,333],{"__ignoreMap":180},[184,185,188],"span",{"class":186,"line":187},"line",1,[184,189,191],{"class":190},"sxvE3","# 核心部分のみ\n",[184,193,195,199,203,206,209,212,214,217,220,223],{"class":186,"line":194},2,[184,196,198],{"class":197},"sG7-3","wb ",[184,200,202],{"class":201},"shFtX","=",[184,204,205],{"class":197}," excel",[184,207,208],{"class":201},".",[184,210,211],{"class":197},"Workbooks",[184,213,208],{"class":201},[184,215,216],{"class":197},"Open",[184,218,219],{"class":201},"(",[184,221,222],{"class":197},"abs_path",[184,224,225],{"class":201},")\n",[184,227,229,233,236,239,242,244,247],{"class":186,"line":228},3,[184,230,232],{"class":231},"sHkkW","for",[184,234,235],{"class":197}," ws ",[184,237,238],{"class":231},"in",[184,240,241],{"class":197}," wb",[184,243,208],{"class":201},[184,245,246],{"class":197},"Worksheets",[184,248,249],{"class":201},":\n",[184,251,253,256,259,261,264],{"class":186,"line":252},4,[184,254,255],{"class":231},"    for",[184,257,258],{"class":197}," row ",[184,260,238],{"class":231},[184,262,263],{"class":197}," check_rows",[184,265,249],{"class":201},[184,267,269,272,274,277,279,282,284,287,290,293,296],{"class":186,"line":268},5,[184,270,271],{"class":197},"        val ",[184,273,202],{"class":201},[184,275,276],{"class":197}," ws",[184,278,208],{"class":201},[184,280,281],{"class":197},"Cells",[184,283,219],{"class":201},[184,285,286],{"class":197},"row",[184,288,289],{"class":201},",",[184,291,292],{"class":197}," col",[184,294,295],{"class":201},").",[184,297,298],{"class":197},"Value\n",[184,300,302,305,308,312,316,318,321,324,327,331],{"class":186,"line":301},6,[184,303,304],{"class":231},"        if",[184,306,307],{"class":197}," val ",[184,309,311],{"class":310},"stQ0i","and",[184,313,315],{"class":314},"sz8Xr"," abs",[184,317,219],{"class":201},[184,319,320],{"class":197},"val",[184,322,323],{"class":201},")",[184,325,326],{"class":310}," >",[184,328,330],{"class":329},"sM54T"," 0.01",[184,332,249],{"class":201},[184,334,336,339,341,344,346,349,353,357,360,362,365,368,371,373,375,377,380,382,384,386,388],{"class":186,"line":335},7,[184,337,338],{"class":197},"            errors",[184,340,208],{"class":201},[184,342,343],{"class":197},"append",[184,345,219],{"class":201},[184,347,348],{"class":310},"f",[184,350,352],{"class":351},"sdGka","\"",[184,354,356],{"class":355},"snbK4","{",[184,358,359],{"class":197},"ws",[184,361,208],{"class":201},[184,363,364],{"class":197},"Name",[184,366,367],{"class":355},"}",[184,369,370],{"class":351}," Row",[184,372,356],{"class":355},[184,374,286],{"class":197},[184,376,367],{"class":355},[184,378,379],{"class":351},": ",[184,381,356],{"class":355},[184,383,320],{"class":197},[184,385,367],{"class":355},[184,387,352],{"class":351},[184,389,225],{"class":201},[15,391,392],{},"Excelを非表示モードで起動し、検証後にプロセスを閉じる。CIでは動かせないが、ローカルでの目視確認を自動化できた。",[60,394,396],{"id":395},"codexレビューを経た設計修正","Codexレビューを経た設計修正",[15,398,399],{},"テスト計画をCodexにレビューさせたところ、「check行の位置をハードコードするとシート構造が変わったときに壊れる」と指摘が返ってきた。check行のセルに特定のラベル（\"check\"）が入っていることを前提に、ラベルで行位置を動的に検索するよう修正した。",[19,401,402],{"id":402},"全ステップの再生成と検証",[15,404,405],{},"短期借入金の追加、集約シートの新設、未払費用の分離、バグ修正を全て反映した上で、パイプライン全体を再実行した。",[407,408,409,416,422],"ol",{},[410,411,412,415],"li",{},[151,413,414],{},"取引モジュール（Step a）",": 短期借入金+集約シート付きで再生成",[410,417,418,421],{},[151,419,420],{},"年次推移表（Step b）",": BS/PLに未払利息・未払営業経費・支払利息を反映して再生成",[410,423,424,427],{},[151,425,426],{},"CFWS（Step c）",": 集約シートからの値貼り付けで再生成",[15,429,430,433],{},[32,431,432],{},"verify_cfws_excel.py"," を実行して、全年度のcheck=0を確認した。符号エラーも参照抜けも解消されていた。",[19,435,436],{"id":436},"振り返り",[15,438,439],{},"集約シートの配置場所を決めるのに一番時間を使った。CFWS側に置く案で一度コードを書き始めてから、「取引モジュール側に置いたほうが依存が閉じる」と気づいて書き直した。手戻りは発生したが、この判断で数式の複雑度が目に見えて下がった。INDEX/MATCHの3項足し算が集約シートへの単一参照に変わり、セルの中身が一行で読めるようになった。",[15,441,442],{},"テスト方針の議論では、Python再実装とCOM経由検証の間で揺れた。前日までPythonで数式を再実装する方向で進めていたが、二重管理のコストに気づいてCOM経由に切り替えた。Excelが計算した結果をそのまま読む。当たり前のようで、openpyxlの世界にいると見えなくなる選択肢だった。",[444,445,446],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":180,"searchDepth":194,"depth":194,"links":448},[449,450,451,456,460,464,469,470],{"id":21,"depth":194,"text":21},{"id":27,"depth":194,"text":27},{"id":57,"depth":194,"text":58,"children":452},[453,454,455],{"id":62,"depth":228,"text":63},{"id":72,"depth":228,"text":73},{"id":79,"depth":228,"text":80},{"id":93,"depth":194,"text":93,"children":457},[458,459],{"id":96,"depth":228,"text":96},{"id":102,"depth":228,"text":102},{"id":119,"depth":194,"text":120,"children":461},[462,463],{"id":123,"depth":228,"text":123},{"id":133,"depth":228,"text":134},{"id":140,"depth":194,"text":141,"children":465},[466,467,468],{"id":144,"depth":228,"text":144},{"id":166,"depth":228,"text":167},{"id":395,"depth":228,"text":396},{"id":402,"depth":194,"text":402},{"id":436,"depth":194,"text":436},"dev","短期借入金の取引モジュール追加、集約シートの設計議論、未払費用の補助科目分解、COM経由のExcel自動検証スクリプト作成まで、CF精算表パイプラインを一日で大幅に拡張した記録","md",{},true,"/cfws-pipeline-expansion-borrowing","eurekapu-nuxt4",false,"2026-04-04T00:00:00.000Z",{"title":5,"description":472},"2026-04/2026-04-04/cfws-pipeline-expansion-borrowing",[483,484,485,486,487,488,489],"CF精算表","Excel自動化","Python","短期借入金","COM自動検証","openpyxl","簿記","memo",null,"0x4-S69B_Msm9YKSl6DNbIJbE-xSYOK5B8kDC69CLJU",[],"https://log.eurekapu.com/favicon.svg",1775338204386]