[{"data":1,"prerenderedAt":401},["ShallowReactive",2],{"content-/cf-working-capital-inventory":3,"all-pages-for-dir":399,"og-image-/cf-working-capital-inventory":400},{"id":4,"title":5,"body":6,"category":377,"description":378,"extension":379,"meta":380,"navigation":301,"path":381,"project_name":382,"published":383,"publishedAt":384,"seo":385,"stem":386,"tags":387,"todo":396,"updatedAt":397,"__hash__":398},"pages/2026-04/2026-04-05/cf-working-capital-inventory.md","CF精算表: 運転資本への在庫管理追加と全ステップ完了",{"type":7,"value":8,"toc":353},"minimark",[9,13,17,21,25,28,31,34,37,48,51,54,57,60,63,66,69,72,75,78,81,84,87,93,96,99,219,222,226,229,232,235,238,248,252,258,274,277,281,284,287,290,322,325,349],[10,11,5],"h1",{"id":12},"cf精算表-運転資本への在庫管理追加と全ステップ完了",[14,15,16],"p",{},"朝、運転資本（304）のStep Aを2022/01/01スタート・12月決算で再生成するところから始めた。タイトル行にFILL_MID_GRAY書式を適用し、MF仕訳シート・集約シート・資本政策シートを追加する。ここまでは前日の延長で手が動く。問題は在庫管理だった。「数量」という概念を取引モジュールに持ち込んだ瞬間、シート構造の前提が次々と崩れ、気づけば夕方まで列シフト・バグ修正・数式再設計に追われていた。",[18,19,20],"h2",{"id":20},"数量ベース生成モデルへの転換",[22,23,24],"h3",{"id":24},"商品パラメータの設計",[14,26,27],{},"在庫管理を組み込むにあたり、金額だけで取引を生成していたモデルを数量ベースに切り替えた。商品パラメータとしてリンゴを定義し、仕入単価からCOGS_RATEを逆算する構造にした。",[14,29,30],{},"NamedTupleに数量フィールドを追加し、売上データ・仕入データの各行が「何個売れたか」「何個仕入れたか」を持つようにした。",[22,32,33],{"id":33},"三分法の決算整理仕訳",[14,35,36],{},"期末の棚卸資産を正しく計上するため、三分法の決算整理仕訳を実装した。いわゆる「しーくりくりしー」の仕訳だ。",[38,39,44],"pre",{"className":40,"code":42,"language":43},[41],"language-text","期首: 仕入 / 繰越商品（期首繰越商品を仕入勘定に振替）\n期末: 繰越商品 / 仕入（期末繰越商品を資産計上）\n","text",[45,46,42],"code",{"__ignoreMap":47},"",[14,49,50],{},"期首と期末の棚卸高をパラメータから計算し、決算整理仕訳として自動挿入する処理を追加した。",[22,52,53],{"id":53},"新規シートの追加",[14,55,56],{},"商品台帳シートと在庫管理シートを新規に追加した。商品台帳は商品マスタとパラメータを一覧化し、在庫管理シートは月次の入出庫と残高を追跡する。",[18,58,59],{"id":59},"列シフト問題との格闘",[22,61,62],{"id":62},"何が起きたか",[14,64,65],{},"売上データシートと仕入データシートにB列として「数量」列を追加した。この1列の挿入が、下流のシート群を壊した。",[14,67,68],{},"売掛金管理・買掛金管理・クレカ決済シートがINDEX/MATCH数式で売上データ・仕入データを参照しているが、参照先の列番号がハードコードされていた。B列に数量が割り込んだことで、金額を取得しているつもりの列が1つずれ、数量の値を引いてしまう。",[22,70,71],{"id":71},"対応",[14,73,74],{},"INDEX/MATCHの列番号指定を全て洗い出し、数量列の挿入分だけオフセットを修正した。影響範囲は売掛金管理・買掛金管理・クレカ決済の3シート。列番号を定数化して、将来の列追加時にも1箇所の変更で済むようにした。",[18,76,77],{"id":77},"在庫が増え続けるバグ",[22,79,80],{"id":80},"症状",[14,82,83],{},"全シートを生成して在庫管理シートを開くと、月を追うごとに在庫残高が右肩上がりに膨れ上がっていた。4年目には在庫が初月の10倍近くまで積み上がり、明らかに実態と乖離している。",[22,85,86],{"id":86},"原因の特定",[14,88,89,92],{},[45,90,91],{},"generate_daily_purchases","関数のノイズ係数を確認すると、仕入数量に1.025を掛けていた。「売上より少し多めに仕入れる」意図だったが、販売実績と無関係に毎日一律で上乗せしているため、売れない分が毎月蓄積される。積み上がった在庫が消化される仕組みがどこにもない。",[22,94,95],{"id":95},"フィードバック制御への修正",[14,97,98],{},"仕入数量の決定ロジックを、販売実績に連動するフィードバック制御に書き換えた。",[38,100,104],{"className":101,"code":102,"language":103,"meta":47,"style":47},"language-python shiki shiki-themes vitesse-light vitesse-light","# 修正後: 販売数量ベースのフィードバック制御\nshortage = max(0, target_stock - current_stock)\npurchase_qty = daily_sales_qty + int(shortage * 0.2)\npurchase_qty = int(purchase_qty * random.uniform(0.95, 1.05))\n","python",[45,105,106,115,153,182],{"__ignoreMap":47},[107,108,111],"span",{"class":109,"line":110},"line",1,[107,112,114],{"class":113},"sxvE3","# 修正後: 販売数量ベースのフィードバック制御\n",[107,116,118,122,126,130,133,137,140,143,147,150],{"class":109,"line":117},2,[107,119,121],{"class":120},"sG7-3","shortage ",[107,123,125],{"class":124},"shFtX","=",[107,127,129],{"class":128},"sz8Xr"," max",[107,131,132],{"class":124},"(",[107,134,136],{"class":135},"sM54T","0",[107,138,139],{"class":124},",",[107,141,142],{"class":120}," target_stock ",[107,144,146],{"class":145},"stQ0i","-",[107,148,149],{"class":120}," current_stock",[107,151,152],{"class":124},")\n",[107,154,156,159,161,164,167,170,172,174,177,180],{"class":109,"line":155},3,[107,157,158],{"class":120},"purchase_qty ",[107,160,125],{"class":124},[107,162,163],{"class":120}," daily_sales_qty ",[107,165,166],{"class":145},"+",[107,168,169],{"class":128}," int",[107,171,132],{"class":124},[107,173,121],{"class":120},[107,175,176],{"class":145},"*",[107,178,179],{"class":135}," 0.2",[107,181,152],{"class":124},[107,183,185,187,189,191,193,195,197,200,203,206,208,211,213,216],{"class":109,"line":184},4,[107,186,158],{"class":120},[107,188,125],{"class":124},[107,190,169],{"class":128},[107,192,132],{"class":124},[107,194,158],{"class":120},[107,196,176],{"class":145},[107,198,199],{"class":120}," random",[107,201,202],{"class":124},".",[107,204,205],{"class":120},"uniform",[107,207,132],{"class":124},[107,209,210],{"class":135},"0.95",[107,212,139],{"class":124},[107,214,215],{"class":135}," 1.05",[107,217,218],{"class":124},"))\n",[14,220,221],{},"前日の販売数量をベースにし、目標在庫との差分（不足分）の20%を補充、そこに±5%のノイズを乗せる。在庫が十分あれば補充量は販売量とほぼ同じになり、不足していれば多めに仕入れる。このロジックに変えた瞬間、在庫残高が目標水準の前後で安定し始めた。",[18,223,225],{"id":224},"在庫管理シートのindexmatch化","在庫管理シートのINDEX/MATCH化",[14,227,228],{},"当初は在庫管理シートのデータをPythonで直接書き込んでいたが、売上データ・仕入データとの整合性を保証するため、INDEX/MATCHとSUMIFS数式ベースに変更した。",[14,230,231],{},"売上データシートの販売数量をSUMIFSで月次集計し、仕入データシートの仕入数量も同様に集計する。在庫管理シートはこの2つの集計結果を参照して入出庫と残高を計算する。Pythonが書き込むのはシート構造と数式だけで、値はExcelの計算エンジンに任せる方針に統一した。",[18,233,234],{"id":234},"openpyxl数式未計算問題の根本対策",[22,236,237],{"id":237},"問題",[14,239,240,243,244,247],{},[45,241,242],{},"gen_annual_table.py","（Step B: 年次推移表生成）は、Step Aで生成したExcelを読み取って年次推移表を組み立てる。しかしopenpyxlは数式の計算結果を持たない。",[45,245,246],{},"data_only=True","で開いても、一度もExcelで開いていないファイルはキャッシュ値がNoneになる。",[22,249,251],{"id":250},"from-excelオプションと-json-outputオプション","--from-excelオプションと--json-outputオプション",[14,253,254,255,257],{},"根本対策として、",[45,256,242],{},"に2つのオプションを追加した。",[259,260,261,268],"ul",{},[262,263,264,267],"li",{},[45,265,266],{},"--from-excel",": COM経由でExcelを起動し、数式を計算させてから値を読み取る",[262,269,270,273],{},[45,271,272],{},"--json-output",": 読み取った値をJSON形式で出力し、他スクリプトから参照可能にする",[14,275,276],{},"COM経由でExcelを開くと数式が全て計算された状態で値を取得できる。Windows環境限定だが、開発マシンでの生成パイプラインには十分だ。",[18,278,280],{"id":279},"全ステップ完了-4年度check0","全ステップ完了: 4年度check=0",[14,282,283],{},"Step A（取引モジュール）、Step B（年次推移表）、Step C（CFWS）の順に生成し、全4年度でcheck=0を確認した。checkセルはCFWSの各年度シートに埋め込んだ検証数式で、BS残高の整合性とCFの合計が期首期末の現金差額と一致するかを検証する。4年度分すべてゼロが並んだ画面を見て、ようやく肩の力が抜けた。",[18,285,286],{"id":286},"スキルファイルの整理",[14,288,289],{},"在庫管理の追加に伴い、関連するスキルファイルを作成・更新した。進捗管理の記述をチェックボックス形式に統一し、完了・未完了の状態が一目で分かるようにした。",[259,291,294,304,310,316],{"className":292},[293],"contains-task-list",[262,295,298,303],{"className":296},[297],"task-list-item",[299,300],"input",{"checked":301,"disabled":301,"type":302},true,"checkbox"," Step A: 取引モジュール生成（在庫管理込み）",[262,305,307,309],{"className":306},[297],[299,308],{"checked":301,"disabled":301,"type":302}," Step B: 年次推移表生成（--from-excelオプション対応）",[262,311,313,315],{"className":312},[297],[299,314],{"checked":301,"disabled":301,"type":302}," Step C: CFWS生成",[262,317,319,321],{"className":318},[297],[299,320],{"checked":301,"disabled":301,"type":302}," 全4年度 check=0 通過",[18,323,324],{"id":324},"学びメモ",[259,326,327,334,340],{},[262,328,329,333],{},[330,331,332],"strong",{},"1列追加したら3シートが壊れた",": B列に数量を挿入しただけでINDEX/MATCHの参照先がずれ、売掛金・買掛金・クレカ決済の3シートが間違った値を返し始めた。列番号を定数にまとめておけば、修正箇所は1行で済む",[262,335,336,339],{},[330,337,338],{},"ノイズ係数1.025が在庫を10倍に膨らませた",": フィードバックなしで毎日上乗せし続けると、売れ残りが積み上がる一方になる。販売数量に連動させた瞬間、グラフが目標水準の前後で横ばいに変わった",[262,341,342,348],{},[330,343,344,345,347],{},"openpyxlの",[45,346,246],{},"はNoneを返す",": 一度もExcelで開いていないファイルにはキャッシュ値がない。COM経由でExcelに計算させてから値を読み取ることで、Noneが消えた",[350,351,352],"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 .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 .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}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":47,"searchDepth":117,"depth":117,"links":354},[355,360,364,369,370,374,375,376],{"id":20,"depth":117,"text":20,"children":356},[357,358,359],{"id":24,"depth":155,"text":24},{"id":33,"depth":155,"text":33},{"id":53,"depth":155,"text":53},{"id":59,"depth":117,"text":59,"children":361},[362,363],{"id":62,"depth":155,"text":62},{"id":71,"depth":155,"text":71},{"id":77,"depth":117,"text":77,"children":365},[366,367,368],{"id":80,"depth":155,"text":80},{"id":86,"depth":155,"text":86},{"id":95,"depth":155,"text":95},{"id":224,"depth":117,"text":225},{"id":234,"depth":117,"text":234,"children":371},[372,373],{"id":237,"depth":155,"text":237},{"id":250,"depth":155,"text":251},{"id":279,"depth":117,"text":280},{"id":286,"depth":117,"text":286},{"id":324,"depth":117,"text":324},"dev","CF精算表パイプラインの運転資本（304）に在庫管理を追加。数量ベース生成モデルへの転換、三分法の決算整理仕訳、列シフト問題の解決、在庫増加バグのフィードバック制御修正、openpyxl数式未計算への根本対策まで、全4年度check=0を達成した記録","md",{},"/cf-working-capital-inventory","eurekapu-nuxt4",false,"2026-04-05T00:00:00.000Z",{"title":5,"description":378},"2026-04/2026-04-05/cf-working-capital-inventory",[388,389,390,391,392,393,394,395],"CF精算表","在庫管理","Python","Excel自動化","openpyxl","簿記","三分法","フィードバック制御","memo",null,"ALfY_Wb2J_CeBUIDMi3ieSzKkoW8XLwDVxsOEqA4Fyw",[],"https://log.eurekapu.com/favicon.svg",1775511574784]