[{"data":1,"prerenderedAt":481},["ShallowReactive",2],{"content-/mf-journal-annual-table-generation":3,"all-pages-for-dir":479,"og-image-/mf-journal-annual-table-generation":480},{"id":4,"title":5,"body":6,"category":459,"description":460,"extension":461,"meta":462,"navigation":463,"path":464,"project_name":465,"published":466,"publishedAt":467,"seo":468,"stem":469,"tags":470,"todo":477,"updatedAt":477,"__hash__":478},"pages/2026-04/2026-04-02/mf-journal-annual-table-generation.md","会計ソフトの仕訳データから年次推移表を自動生成し、ExcelとGoogle Sheetsの両方に出力した",{"type":7,"value":8,"toc":443},"minimark",[9,13,17,22,27,30,42,49,52,55,59,62,66,69,72,90,93,97,108,119,123,126,130,137,370,376,379,382,393,396,399,402,430,433,436,439],[10,11,12],"h1",{"id":12},"会計ソフトの仕訳データから年次推移表を自動生成する",[14,15,16],"p",{},"朝、会計ソフトAのスプレッドシートに並ぶ仕訳データを眺めていた。このデータからBS+PLの年次推移表を毎回手で組むのをやめたい。gen-annual-tableスクリプトを書き始めたところから、気づけばExcel版とGoogle Sheets版の二系統が動くようになるまで丸一日が過ぎた。",[18,19,21],"h2",{"id":20},"gen-annual-table-excel版の開発","gen-annual-table: Excel版の開発",[23,24,26],"h3",{"id":25},"bsplの構造設計","BS+PLの構造設計",[14,28,29],{},"年次推移表の構造を固めるのに時間をかけた。ヘッダー行の下に個別科目が並び、小計・合計・チェック行が続く。2022年度から2028年度まで7年分を横に展開する。",[14,31,32,33,37,38,41],{},"合計行の数式で最初につまずいた。科目のpruning（ゼロ行の非表示化）を入れると、行番号がずれて ",[34,35,36],"code",{},"SUM(B10:B25)"," のような固定範囲指定が壊れる。",[34,39,40],{},"sum_named"," 方式に切り替えて、名前付き範囲で集計対象を指定するようにした。pruning後もインデックスが正しく動く。",[14,43,44,45,48],{},"PLの経常利益・税引前利益は単純なSUMでは出せない。営業利益に営業外損益を加減する計算式を ",[34,46,47],{},"pl_calc"," として定義し、合計行から参照する形にした。",[23,50,51],{"id":51},"チェック行で不整合を検知する",[14,53,54],{},"BSの末尾にチェック行を置いた。「資産合計 - 負債純資産合計 = 0」を数式で計算し、ゼロ以外の値が出たらセルが赤く光る。このチェック行のおかげで、後工程で科目の配置を変えたときに即座にずれを検知できた。",[23,56,58],{"id":57},"入力データをexcel内に同梱する","入力データをExcel内に同梱する",[14,60,61],{},"生成したExcelに「入力_MF仕訳」シートを追加し、元データをそのまま貼り付けた。インプットとアウトプットが1ファイルで完結するので、後から「この数字はどこから来たか」を追うときにファイルを行き来しなくて済む。",[18,63,65],{"id":64},"google-sheets版の新規開発","Google Sheets版の新規開発",[23,67,68],{"id":68},"共通コアモジュールの切り出し",[14,70,71],{},"Excel版が動いた後、同じロジックをGoogle Sheetsにも出したくなった。最初はExcel版のスクリプトをコピーして書き換え始めたが、科目構造の定義やpruningロジックが丸ごと重複していることに手が止まった。",[14,73,74,77,78,81,82,85,86,89],{},[34,75,76],{},"gen_annual_table_core.py"," として共通データモジュールを切り出すリファクタリングを実行した。BS・PLの科目構造、合計行の数式定義、pruningロジックをここに集約する。Excel版 (",[34,79,80],{},"gen_annual_table.py",") とSS版 (",[34,83,84],{},"gen_annual_table_ss.py",") は、このコアモジュールを ",[34,87,88],{},"import"," して、出力先だけを差し替える構造にした。",[14,91,92],{},"リファクタリング後、Excel版の出力結果が変わっていないことを確認してからSS版の開発に入った。",[23,94,96],{"id":95},"ss版-google-sheets-apiでの書き込み","SS版: Google Sheets APIでの書き込み",[14,98,99,100,103,104,107],{},"SS版では ",[34,101,102],{},"gws"," CLI経由でGoogle Sheets APIを叩く。シート作成、セル書き込み、IB書式適用の3ステップを1つのシェルスクリプト ",[34,105,106],{},"gen_annual_table_ss.sh"," にまとめた。",[14,109,110,111,114,115,118],{},"命名規則は ",[34,112,113],{},"CF_年次推移表_{ソースSS名}"," とした。",[34,116,117],{},"--title"," オプションで明示的にタイトルを指定できるが、未指定時はソーススプレッドシートのタイトルを自動取得して埋め込む。Google Sheetsにはバージョン履歴があるため、Excel版と違ってファイル名にタイムスタンプを入れる必要がない。",[23,120,122],{"id":121},"excel版とss版の値照合","Excel版とSS版の値照合",[14,124,125],{},"両方の出力が揃った時点で、全セルの値を突き合わせた。Pythonスクリプトで Excel の各セル値と Google Sheets の各セル値を比較し、差分があれば報告する仕組みを組んだ。最初の照合で数箇所の不一致が見つかり、SS版の数式変換ロジックにバグがあったことが判明した。修正後、全セル一致を確認。",[18,127,129],{"id":128},"勘定科目マスターのjson化","勘定科目マスターのJSON化",[14,131,132,133,136],{},"年次推移表の科目名をハードコードしていると、科目が増えたときに複数箇所を修正する必要が出る。会計ソフトAの勘定科目マスター（223件）をスプレッドシートから読み取り、",[34,134,135],{},"scripts/cf-materials/mf-account-master.json"," に書き出した。",[138,139,144],"pre",{"className":140,"code":141,"language":142,"meta":143,"style":143},"language-json shiki shiki-themes vitesse-light vitesse-light","{\n  \"accounts\": [\n    {\n      \"code\": \"110\",\n      \"name\": \"現金\",\n      \"category\": \"asset\",\n      \"parent\": null\n    },\n    {\n      \"code\": \"110-001\",\n      \"name\": \"小口現金\",\n      \"category\": \"asset\",\n      \"parent\": \"110\"\n    }\n  ]\n}\n","json","",[34,145,146,155,175,181,206,227,248,264,270,275,295,315,334,352,358,364],{"__ignoreMap":143},[147,148,151],"span",{"class":149,"line":150},"line",1,[147,152,154],{"class":153},"shFtX","{\n",[147,156,158,162,166,169,172],{"class":149,"line":157},2,[147,159,161],{"class":160},"sqvqQ","  \"",[147,163,165],{"class":164},"sz8Xr","accounts",[147,167,168],{"class":160},"\"",[147,170,171],{"class":153},":",[147,173,174],{"class":153}," [\n",[147,176,178],{"class":149,"line":177},3,[147,179,180],{"class":153},"    {\n",[147,182,184,187,189,191,193,197,201,203],{"class":149,"line":183},4,[147,185,186],{"class":160},"      \"",[147,188,34],{"class":164},[147,190,168],{"class":160},[147,192,171],{"class":153},[147,194,196],{"class":195},"sMJiu"," \"",[147,198,200],{"class":199},"sdGka","110",[147,202,168],{"class":195},[147,204,205],{"class":153},",\n",[147,207,209,211,214,216,218,220,223,225],{"class":149,"line":208},5,[147,210,186],{"class":160},[147,212,213],{"class":164},"name",[147,215,168],{"class":160},[147,217,171],{"class":153},[147,219,196],{"class":195},[147,221,222],{"class":199},"現金",[147,224,168],{"class":195},[147,226,205],{"class":153},[147,228,230,232,235,237,239,241,244,246],{"class":149,"line":229},6,[147,231,186],{"class":160},[147,233,234],{"class":164},"category",[147,236,168],{"class":160},[147,238,171],{"class":153},[147,240,196],{"class":195},[147,242,243],{"class":199},"asset",[147,245,168],{"class":195},[147,247,205],{"class":153},[147,249,251,253,256,258,260],{"class":149,"line":250},7,[147,252,186],{"class":160},[147,254,255],{"class":164},"parent",[147,257,168],{"class":160},[147,259,171],{"class":153},[147,261,263],{"class":262},"sHkkW"," null\n",[147,265,267],{"class":149,"line":266},8,[147,268,269],{"class":153},"    },\n",[147,271,273],{"class":149,"line":272},9,[147,274,180],{"class":153},[147,276,278,280,282,284,286,288,291,293],{"class":149,"line":277},10,[147,279,186],{"class":160},[147,281,34],{"class":164},[147,283,168],{"class":160},[147,285,171],{"class":153},[147,287,196],{"class":195},[147,289,290],{"class":199},"110-001",[147,292,168],{"class":195},[147,294,205],{"class":153},[147,296,298,300,302,304,306,308,311,313],{"class":149,"line":297},11,[147,299,186],{"class":160},[147,301,213],{"class":164},[147,303,168],{"class":160},[147,305,171],{"class":153},[147,307,196],{"class":195},[147,309,310],{"class":199},"小口現金",[147,312,168],{"class":195},[147,314,205],{"class":153},[147,316,318,320,322,324,326,328,330,332],{"class":149,"line":317},12,[147,319,186],{"class":160},[147,321,234],{"class":164},[147,323,168],{"class":160},[147,325,171],{"class":153},[147,327,196],{"class":195},[147,329,243],{"class":199},[147,331,168],{"class":195},[147,333,205],{"class":153},[147,335,337,339,341,343,345,347,349],{"class":149,"line":336},13,[147,338,186],{"class":160},[147,340,255],{"class":164},[147,342,168],{"class":160},[147,344,171],{"class":153},[147,346,196],{"class":195},[147,348,200],{"class":199},[147,350,351],{"class":195},"\"\n",[147,353,355],{"class":149,"line":354},14,[147,356,357],{"class":153},"    }\n",[147,359,361],{"class":149,"line":360},15,[147,362,363],{"class":153},"  ]\n",[147,365,367],{"class":149,"line":366},16,[147,368,369],{"class":153},"}\n",[14,371,372,373,375],{},"親子関係（勘定科目と補助科目）を ",[34,374,255],{}," フィールドで保持している。このJSONをコアモジュールから参照すれば、科目の追加・変更がJSON1箇所の編集で済む。",[18,377,378],{"id":378},"返済予定表の合計行バグ修正",[14,380,381],{},"年次推移表を眺めていて、支払利息の数字に違和感を覚えた。返済予定表の合計と突き合わせたところ、3,750円の差がある。",[14,383,384,385,388,389,392],{},"原因を追うと、TPL_返済予定表の合計行 ",[34,386,387],{},"=SUM(E20:E501)"," がRow 19を含んでいなかった。Row 19は初回返済時の据置期間利息3,750円が入っている行だ。",[34,390,391],{},"=SUM(E19:E501)"," に修正し、D・E・F列すべてで開始行を揃えた。利息合計が156,188円から159,938円に変わり、返済予定表の個別行合計と一致した。",[14,394,395],{},"3,750円のずれは合計額に対して小さいが、チェック行がなければ気づかなかった。",[18,397,398],{"id":398},"書式の仕上げ",[14,400,401],{},"数値の見た目を整える作業にも手を入れた。",[403,404,405,409,412,415],"ul",{},[406,407,408],"li",{},"数値カラムの列幅を18.125に統一し、スペーサー列は1.5に絞った",[406,410,411],{},"全セルに上下中央揃え（vertical center）を適用",[406,413,414],{},"チェック行のA列を右寄せにして、ラベルと数値の視線が揃うようにした",[406,416,417,418,421,422,425,426,429],{},"一部のセルで数値が ",[34,419,420],{},"stringValue"," として格納されていたのを ",[34,423,424],{},"numberValue"," / ",[34,427,428],{},"formulaValue"," に修正。文字列のままだとSUM関数が無視するため、これも照合時に発覚した",[18,431,432],{"id":432},"振り返り",[14,434,435],{},"一日で一番時間を使ったのは、共通コアモジュールの切り出しだった。Excel版が動いている状態でリファクタリングするのは勇気が要る。しかし、コピペで2つ目を作り始めた瞬間に「これは後で必ず片方だけ修正して不整合が出る」と手が止まった。結果的に、リファクタリングしてからSS版を作ったことで、照合時のバグ修正がコアモジュール1箇所の修正で両方に反映された。",[14,437,438],{},"返済予定表のバグは、年次推移表の数字を睨んでいて偶然見つけた。合計行のSUM範囲が1行ずれているだけで3,750円の差が出る。金額が小さいから放置してもよさそうだが、帳簿の信頼性は「全部合っている」前提で成り立つ。1円でもずれていたら他の数字も疑わなければならない。チェック行を入れておいてよかった。",[440,441,442],"style",{},"html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sqvqQ, html code.shiki .sqvqQ{--shiki-default:#99841877;--shiki-dark:#99841877}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}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":143,"searchDepth":157,"depth":157,"links":444},[445,450,455,456,457,458],{"id":20,"depth":157,"text":21,"children":446},[447,448,449],{"id":25,"depth":177,"text":26},{"id":51,"depth":177,"text":51},{"id":57,"depth":177,"text":58},{"id":64,"depth":157,"text":65,"children":451},[452,453,454],{"id":68,"depth":177,"text":68},{"id":95,"depth":177,"text":96},{"id":121,"depth":177,"text":122},{"id":128,"depth":157,"text":129},{"id":378,"depth":157,"text":378},{"id":398,"depth":157,"text":398},{"id":432,"depth":157,"text":432},"dev","会計ソフトAのMF仕訳データから年次推移表をExcelとGoogle Sheetsに自動生成するスクリプトを開発。共通コアモジュールの切り出し、勘定科目マスターJSON化、返済予定表バグ修正まで一日の記録","md",{},true,"/mf-journal-annual-table-generation","eurekapu-nuxt4",false,"2026-04-02T00:00:00.000Z",{"title":5,"description":460},"2026-04/2026-04-02/mf-journal-annual-table-generation",[471,472,473,474,475,476],"年次推移表","Excel自動化","Google Sheets API","Python","勘定科目マスター","会計データ",null,"j9EqWEsA8sO7HZAE4KXnhiaLHdwM1weoSxckYuu8lXY",[],"https://log.eurekapu.com/favicon.svg",1775338204044]