MAS-048: 採用 TCO & BEP シミュレーター(Jr 採用 D-180 判断基盤・P1.5 ★★★)
概要
| 項目 | 内容 |
|---|---|
| 案件 ID | MAS-048 |
| カテゴリ | シミュレーション |
| 優先度 | P1.5 ★★★(Jr 採用 D-180 = 2026-10 入社想定の最優先案件) |
| 対象ファイル(変更あり) | 400_domain/412_hiring_tco_simulator.js(新規・namespace HiringTcoSimulator)100_config/101_sys_config.js(03_sys_params に法定福利費率等の初期値設定支援)000_infra/002_constants.js(MENU_DEFINITION の 📋 サイドバー: 📊 マート更新 カテゴリに 1 項目追加)301_ui_assist.js または新規サイドバー HTML(採用 TCO 入力フォーム) |
| 出力先シート | 69_report_hiring_tco(新規・DDL 管理外・動的上書き) |
| 前提案件 | MAS-044(テンプレートマスタ・入力源として使用)、MAS-012(目標売上 → 必要人員数逆算・相補関係) |
| 後続案件 | MAS-049(賃上げ促進税制シミュレーター・本案件の TCO を入力として受取)、MAS-042(Go/No-Go 判定・本案件の TCO/BEP を閾値照合に使用) |
「給与 600 万 → 実コスト 900 万」の可視化が本案件のコア価値。Jr 採用 D-180(2026-10 入社想定)に向けた採用可否の財務判断を TCO(Total Cost of Ownership) と BEP(損益分岐点売上) の 2 指標で定量化する。
入力(想定年収 / 雇用形態 / 採用チャネル費用)→ 計算(法定福利費 15.68% + 採用費 + 研修費 + 設備按分)→ 出力(年間 TCO + 月次 TCO + 採用者が稼ぐべき最低粗利月額 = BEP)を 1 画面で完結させる。
D.9「一人法人 1 人目採用 財務シミュレーション完全ガイド」§2 / §5 で整理された計算フレームを実装する位置付け。
目的
- 採用可否の財務判断を定量化: 「年収 X 万の採用に対し実コスト Y 万・BEP 月 Z 万円」という数字で Go/No-Go 議論を土台化
- Jr 採用 D-180(2026-10 入社想定)への準備: 業務委託 → 契約社員 → 正社員の段階ごとに TCO 比較可能にして実雇用タイミングを最適化
- MAS-012(目標売上 → 必要人員逆算)との相補: MAS-012 が「何人必要か」、MAS-048 が「1 人いくらかかるか」。両者を組み合わせて採用計画を構築
- MAS-042(Go/No-Go ラベル付与)の判断エンジン: MAS-042 は判定ラベル(Go / グレー / No-Go)、MAS-048 は判定に使う TCO/BEP の数値計算。両者で役割分担
現在のコード
400_domain/ の採番状況(2026-04-23 時点)
400/401/402/403/404/405/406/407/410/413/420/430 が使用中。空き番号は 408, 409, 411, 412, 414-419, 421-429, 431-439。本案件は 412_hiring_tco_simulator.js を採用(MAS-011 の 430 / MAS-042 予定の 431 とは別番号で、ドメイン分類上「採用関連」として 412 を確保)。
22_bud_headcount(BUD_HC schema、101_sys_config.js L943)
既存ヘッダー 41 列: 有効フラグ / 管理ID / 氏名・ポジション / 雇用形態 / 科目名 / 取引先名 / 適用年度 / 入社年月 / 退職年月 / 開始年月 / 終了年月 / 月額給与・報酬 / 決済手段 / ... / 採用エージェント費 / PC等初期費用 / ... / 売上貢献(MAS-012 / PR #337 で追加された boolean 列)/ ...
本案件は 月額給与・報酬 / 採用エージェント費 / PC等初期費用 / 社保料率群(健保料率 / 厚年料率 / 雇用保険料率 / 子ども・子育て拠出金率)を参照して既存採用者の実績平均を算出し、シミュレーション入力のプリロードに使う。loadActualAverages では 売上貢献 = FALSE 行を除外(MAS-012 と同じ判定ロジック): 顧問会計士・顧問社労士等の「コストではあるが売上を生まない」HC を採用 TCO の平均から外し、「今後採用する売上貢献型 HC」の想定コスト平均を算出する。
18_tmpl_hc_position(MST_HC_TMPL schema、MAS-044 / PR #339 で実装済)
MAS-044 実装済の HC テンプレートマスタ。14 列構成:
| 列 | 説明 | MAS-048 での使用 |
|---|---|---|
| 有効フラグ | Boolean | findAsMap でスキップ判定 |
| 管理ID | POS_001 等 | テンプレ ID(サイドバー dropdown のキー) |
| ポジション名 | 「Sr エンジニア」等 | UI 表示名・結果ラベル |
| 想定雇用形態 | 正社員/業務委託/副業/パート | TCO 計算時の法定福利費適用判定 |
| 標準月額給与 | 数値(円) | 年収 = × 12 でプリロード |
| 想定月次売上貢献 | 数値(円) | BEP 判定時の粗利貢献想定値 |
| 想定変動費比率 | 0〜1 | BEP 月次売上の粗利率計算 |
| 採用費デフォルト | 数値(円) | TCO 計算の採用費 |
| PC費デフォルト | 数値(円) | TCO 計算の設備按分 |
| 月次追加固定費 | 数値(円) | 本案件で新規反映: 席料・福利厚生等、1 人増加に伴う月次固定費増分 |
| 立ち上がり月数 | 0〜60 | 本案件で新規反映: 入社〜売上貢献開始までのオンボーディング期間 |
| 売上貢献 | Boolean | 本案件で新規反映: FALSE の場合は BEP 判定を「コスト回収のみ」モードに変更(売上貢献なし HC の扱い) |
| 稼働率 | 0〜1 | 本案件で新規反映: BEP 月次売上を稼働率で割り戻す拡張の入力源(MVP は考慮せず、Phase 2 拡張で対応) |
| 備考 | 任意 | — |
200_data/202_repository.js の PositionTemplateRepository.findAsMap()(MAS-044 / PR #339 実装済、L430-497)
戻り値は 11 フィールド:
map[id] = {
positionName, // ポジション名
employmentType, // 想定雇用形態
monthlySalary, // 標準月額給与
monthlyRevenue, // 想定月次売上貢献
variableCostRate, // 想定変動費比率
defaultRecruitFee, // 採用費デフォルト
defaultPcCost, // PC費デフォルト
monthlyFixedCost, // 月次追加固定費(F-44 新規)
rampUpMonths, // 立ち上がり月数(F-44 新規)
revenueContributing,// 売上貢献(F-44 新規、boolean)
utilization, // 稼働率(F-44 新規、0〜1)
note, // 備考
}
MAS-048 の入力 UI でテンプレ選択時、これら 11 フィールドを一括でフォームに反映する。
03_sys_params(Constants.getParam(key, defaultVal)、002_constants.js L147-167)
法定福利費率・採用費・研修費・設備按分の既定値を 03_sys_params で管理する(ハードコード禁止)。本案件で使うパラメータキー:
| キー | デフォルト | 根拠 |
|---|---|---|
TCO_STATUTORY_WELFARE_RATE | 0.1568 | 協会けんぽ福井・40 歳未満(健保 4.97% + 介護 0 + 厚年 9.15% + 子育て 0.36% + 雇用 0.90% + 労災 0.30% = 15.68%)。D.9 §2.1 準拠 |
TCO_STATUTORY_WELFARE_RATE_40PLUS | 0.16475 | 40 歳以上(介護 0.795% 追加) |
TCO_COMMUTE_COST_MONTHLY | 10000 | 通勤費月額 |
TCO_RETIREMENT_DEPOSIT_MONTHLY | 10000 | 中退共月 1 万円 |
TCO_WELFARE_ANNUAL | 30000 | 健診・慶弔年 3 万円 |
TCO_LABOR_MANAGEMENT_ANNUAL | 280000 | 社労士月 2 万 × 12 + 給与ソフト年 4 万 |
TCO_EQUIPMENT_TOTAL | 600000 | PC + モニター + チェア + デスク |
TCO_EQUIPMENT_AMORT_YEARS | 3 | 設備按分年数 |
TCO_OFFICE_COST_MONTHLY | 30000 | コワーキング月 3 万 |
TCO_TRAINING_ANNUAL | 80000 | 教育研修年 8 万(中央値) |
TCO_RECRUIT_FEE_RATE | 0.30 | 人材紹介料率(年収の 30%) |
TCO_RECRUIT_AMORT_YEARS | 3 | 採用コスト按分年数 |
TCO_TURNOVER_RATE_3Y | 0.527 | 3 年以内離職率(厚労省・小規模法人 5-29 人)。D.9 §2.6 準拠 |
000_infra/002_constants.js(MENU_DEFINITION)
📋 サイドバー: 📊 マート更新 カテゴリ(L231-241)の items 配列に追加する:
{ label: '💼 採用 TCO & BEP 試算', funcName: 'openHiringTcoSidebar', description: '想定年収から TCO(実コスト)と BEP(損益分岐点売上)を試算' },
69_report_hiring_tco(新規・DDL 管理外)
MAS-013 の 67_report_investment_analysis と同じく DDL 管理外・動的上書き方式。CLAUDE.md 末尾の「DDL (setupAllSchemas) で管理されないタブ」リストに 69_report_hiring_tco を追加する。
列構成(案):
- A: 試算 ID(タイムスタンプ + 想定年収)
- B: 実行日時
- C: 想定年収
- D: 雇用形態
- E: 年齢区分(40 歳未満 / 40 歳以上)
- F: 法定福利費(円/年)
- G: 採用費(円/年、按分後)
- H: 研修費(円/年)
- I: 設備按分(円/年)
- J: オフィス按分(円/年)
- K: 労務管理費(円/年)
- L: 退職金積立(円/年)
- M: 福利厚生(円/年)
- N: 通勤費(円/年)
- O: 年間 TCO 合計
- P: 月次 TCO
- Q: BEP 月次粗利(採用者が稼ぐべき最低粗利)
- R: BEP 月次売上(粗利率想定値で割戻し)
- S: 粗利率想定値(ユーザー入力、デフォルト 62%)
- T: 実効 Payback(離職率調整・D.9 §2.6 準拠、月数)
- U: 備考(MAS-042 判定ラベル候補 / MAS-012 必要人員との比較メモ)
修正方針
Step 1: DDL 外シート生成 + パラメータ整備
CLAUDE.md に 69_report_hiring_tco を DDL 管理外リストに追記。03_sys_params に 13 パラメータキーの初期値を手動投入(シート直接編集 or MCP add_rows)。
注意: 69_report_hiring_tco は setupAllSchemas で自動生成されない。400_domain/412_hiring_tco_simulator.js の run() 関数内で SpreadsheetApp.insertSheet('69_report_hiring_tco') を実行し、存在しなければ自動生成する設計。
Step 2: 計算エンジン実装(412_hiring_tco_simulator.js 新規)
namespace HiringTcoSimulator を IIFE で定義。公開 API:
var HiringTcoSimulator = (function() {
/**
* @param {Object} input
* @param {number} input.annualSalary 想定年収(円)
* @param {string} input.employmentType 'SEISHAIN' | 'KEIYAKU' | 'GYOUMU_ITAKU' | 'FUKUGYOU'
* @param {number} input.ageGroup 40 or 40 以上(介護保険料率の切替)
* @param {number} [input.recruitFeeRate] 採用費率(未指定で 0.30)
* @param {number} [input.grossMarginRate] 粗利率想定(未指定で 0.62)
* @returns {Object} { tco, bep, payback, breakdown }
*/
function simulate(input) { /* ... */ }
/**
* 22_bud_headcount の有効行から実績平均をプリロード
* **売上貢献 = FALSE 行を除外**(F-12 PR #337 で追加された列。顧問会計士・顧問社労士等のコスト型 HC を除外)
* @returns {{ avgAnnualSalary, avgRecruitFee, avgPcCost, employmentTypeMix, excludedCount }}
*/
function loadActualAverages() {
var result = HeadcountRepository.findAll();
var activeRows = result.dtos.filter(function(dto) {
var flag = dto['有効フラグ'];
if (flag === false || String(flag).toUpperCase() === 'FALSE') return false;
// 売上貢献 = FALSE を除外(F-12 と同じ判定)
var rev = dto['売上貢献'];
return !(rev === false || String(rev).toUpperCase() === 'FALSE');
});
// 平均年収・採用エージェント費・PC等初期費用・雇用形態割合を算出...
}
/**
* シミュレーション結果を 69_report_hiring_tco に追記
* @param {Object} result simulate() の戻り値
*/
function writeToReport(result) { /* ... */ }
/**
* サイドバーから呼ばれる統合関数(calc → write の 1 セット)
*/
function runHiringTcoSimulation(input) { /* ... */ }
return {
simulate: simulate,
loadActualAverages: loadActualAverages,
writeToReport: writeToReport,
runHiringTcoSimulation: runHiringTcoSimulation,
};
})();
function openHiringTcoSidebar() {
var html = HtmlService.createHtmlOutputFromFile('hiring_tco_sidebar')
.setTitle('💼 採用 TCO & BEP 試算');
SpreadsheetApp.getUi().showSidebar(html);
}
Step 3: 計算ロジック詳細
TCO 計算式(年間、円):
法定福利費 = 年収 × TCO_STATUTORY_WELFARE_RATE(40 歳以上は _40PLUS)
採用費 = 年収 × TCO_RECRUIT_FEE_RATE ÷ TCO_RECRUIT_AMORT_YEARS
研修費 = TCO_TRAINING_ANNUAL
設備按分 = TCO_EQUIPMENT_TOTAL ÷ TCO_EQUIPMENT_AMORT_YEARS
オフィス按分 = TCO_OFFICE_COST_MONTHLY × 12
労務管理費 = TCO_LABOR_MANAGEMENT_ANNUAL
退職金積立 = TCO_RETIREMENT_DEPOSIT_MONTHLY × 12
福利厚生 = TCO_WELFARE_ANNUAL
通勤費 = TCO_COMMUTE_COST_MONTHLY × 12
年間 TCO 合計 = 年収 + 上記合計
雇用形態別の補正:
GYOUMU_ITAKU(業務委託): 法定福利費 = 0、採用費率 = 0.15(エージェント経由なら、直接契約なら 0)、オフィス按分 = 0(在宅前提)FUKUGYOU(副業): 法定福利費 = 0、設備按分 = 0、研修費 = 0KEIYAKU(契約社員): 正社員と同じ(雇用保険は 1 年未満でも適用)SEISHAIN(正社員): 上記フル適用
BEP 計算式:
BEP 月次粗利 = 月次 TCO = 年間 TCO ÷ 12
BEP 月次売上 = BEP 月次粗利 ÷ 粗利率想定値(デフォルト 0.62 = 70% ライス + 30% バリュー ≒ D.9 §5.2 の 62%)
MAS-044 テンプレ連携時の BEP 補正(MVP はなし、Phase 2 拡張候補):
MAS-044 テンプレの 稼働率(0〜1、例: 80% = 0.8)を考慮する場合、BEP 月次売上を稼働率で割り戻す:
BEP 月次売上(稼働率考慮版)= BEP 月次粗利 ÷ 粗利率想定値 ÷ 稼働率
例: 稼働率 80% のポジションなら、BEP 売上必要額は 1 / 0.8 = 1.25 倍 に増加。MVP では稼働率を無視して「フル稼働前提」で計算するが、業務委託・副業等で稼働率が 1.0 未満のポジションを試算する場合は Phase 2 で対応。「人間が検討すべき事項 #11」に拡張候補として明記。
MAS-044 テンプレの 売上貢献 = FALSE ポジション扱い:
revenueContributing = false のテンプレ(顧問会計士・顧問社労士等の想定)が選択された場合、BEP 月次売上は計算せず、UI に「このポジションは売上貢献なし → BEP 判定は不可。TCO 回収はクライアント売上全体から行う」と表示。月次粗利ベースの判定は行わない。
実効 Payback(離職率調整):
理論 Payback(月)= 年間 TCO ÷ (月次粗利貢献想定 × 12) × 12
実効 Payback = 理論 Payback ÷ (1 - TCO_TURNOVER_RATE_3Y × (36 - 理論 Payback) / 36)
* 離職率調整: 3 年以内離職率 52.7% を線形に配分。Payback が 36 ヶ月より長ければ完全ロスト扱い(`Infinity` 返却)
Step 4: UI 実装(templates/hiring_tco_sidebar.html 新規)
入力フォーム:
- MAS-044 テンプレート選択(MAS-044 / PR #339 実装済、選択時に以下フィールドを自動入力)
- 想定年収(数値、プリセット: 400 万 / 500 万 / 600 万 / 800 万 / 1,000 万、テンプレ選択時は
monthlySalary × 12で自動入力) - 雇用形態(dropdown: 正社員 / 契約社員 / 業務委託 / 副業、テンプレ選択時は
employmentTypeで自動入力) - 年齢区分(40 歳未満 / 40 歳以上)
- 採用費率(デフォルト 30%、調整可、テンプレ選択時は
defaultRecruitFee ÷ monthlySalary ÷ 12で逆算) - PC・設備費(テンプレ選択時は
defaultPcCostで自動入力、従来のTCO_EQUIPMENT_TOTALデフォルトを上書き) - 月次追加固定費(テンプレ選択時は
monthlyFixedCostで自動入力、TCO 計算の「その他固定費」に加算) - 立ち上がり月数(テンプレ選択時は
rampUpMonthsで自動入力、実効 Payback 計算の「売上貢献開始までのオフセット」として減算) - 稼働率(テンプレ選択時は
utilizationで自動入力、MVP では表示のみで計算未反映・Phase 2 で BEP 補正対応) - 粗利率想定(デフォルト 62%、調整可、テンプレ選択時は
1 - variableCostRateで自動入力)
テンプレ選択の実装方針:
MAS-044 実装の getHcTemplateValues(templateId)(430_what_if_simulator.js に MAS-044 PR #339 で追加、同等機能)を MAS-048 でも呼び出す or MAS-048 専用に getHiringTcoTemplateValues(templateId) を新設するかを Step 2 実装時に判断。推奨: 共通 API PositionTemplateRepository.findAsMap() を MAS-048 の 412_hiring_tco_simulator.js から直接呼ぶ(MAS-044 依存を避け、Repository 層のみに依存)。
- 月次粗利貢献想定(任意、離職率調整 Payback 計算用)
出力表示:
- 年間 TCO 合計(強調表示)
- 月次 TCO(= BEP 月次粗利)
- BEP 月次売上
- 実効 Payback(月、警告色で 24 ヶ月超を赤表示)
- 内訳テーブル(13 項目)
- MAS-042 判定ヒント(Go: BEP < 月商の 30%、グレー: 30-50%、No-Go: 50% 超)
「シートに保存」ボタンで runHiringTcoSimulation 実行 → 69_report_hiring_tco に追記。
Step 5: MENU_DEFINITION 追記
📋 サイドバー: 📊 マート更新 カテゴリの items 末尾(MAS-011 What-if の直後)に追加:
{ label: '💼 採用 TCO & BEP 試算', funcName: 'openHiringTcoSidebar', description: '想定年収から TCO(実コスト)と BEP(損益分岐点売上)を試算' },
影響範囲
変更ファイル一覧
| ファイル | 変更種別 | 内容 |
|---|---|---|
400_domain/412_hiring_tco_simulator.js | 新規 | namespace HiringTcoSimulator + 計算 / 書込 / 統合関数(約 300 行) |
templates/hiring_tco_sidebar.html | 新規 | 入力フォーム + 結果表示(約 250 行) |
000_infra/002_constants.js | 追加のみ | MENU_DEFINITION に 1 エントリ追加 |
CLAUDE.md | 追加のみ | DDL 管理外リストに 69_report_hiring_tco 追記 |
03_sys_params | データ追加のみ | 13 パラメータキーの初期値投入 |
docs/_config.json | 追加のみ | nav 登録 |
既存動作への影響
- MAS-011 What-if MVP: 影響なし(別 namespace / 別サイドバー)
- MAS-012 人員計画: 仕様書段階、MAS-048 完成後に「MAS-012 逆算人員数 × MAS-048 単位 TCO = 採用総投資額」を計算する統合シミュレーションを検討
- MAS-042 Go/No-Go: 仕様書完了済(PR #319)。MAS-048 の TCO/BEP 出力を MAS-042 の採用スクリーニング判定に入力として接続する
運用・デプロイ手順
03_sys_paramsに 13 パラメータキーの初期値を手動投入CLAUDE.mdに69_report_hiring_tco追記 → PR マージnpm run push:dev→ サイドバー💼 採用 TCO & BEP 試算起動- テストケース実行: 年収 600 万 / 正社員 / 40 歳未満 → 年間 TCO ≒ 873 万円 / BEP ≒ 117 万 / 月(D.9 §2.2 と一致確認)
69_report_hiring_tcoシートが自動生成され結果が追記されるnpm run push:prod→ 本番同手順
注意事項
- ⚠️ failure_patterns #18-#20(命名造語禁止): namespace
HiringTcoSimulator/ ファイル名412_hiring_tco_simulator.js/ シート名69_report_hiring_tco/ パラメータキーTCO_*を記述前に再確認 - ⚠️ failure_patterns #3(DDL コード値 vs 実データ乖離): 法定福利費率は 2025 年度料率ベース。年次更新(毎年 4 月)必須。
03_sys_paramsで管理すれば年次更新はマスタ変更のみで対応可能 - ⚠️ failure_patterns #26(
oauthScopes): 本案件はSpreadsheetApp/HtmlServiceのみ使用。追加スコープ不要(該当なし) - ⚠️ 雇用形態コードの命名:
'SEISHAIN' | 'KEIYAKU' | 'GYOUMU_ITAKU' | 'FUKUGYOU'は独自列挙だが、15_mst_dictionaryのUI雇用形態カテゴリ値と文字列として一致させる必要あり。マッピングテーブルを412_hiring_tco_simulator.js冒頭に定数として定義 - ⚠️ 設備按分の共有: 複数人採用時に
TCO_EQUIPMENT_TOTALを 1 人に全額按分すると過大になる。シミュレーション時にユーザーが「共有 or 専用」を選択できるようにする(Phase 2 拡張余地) - ⚠️ 実効 Payback 計算の線形近似: D.9 §2.6 の離職率 52.7% を単純線形配分している。実務では最初 6 ヶ月での離職が多い指数分布に近いが、MVP は線形で簡略化
- ⚠️ MAS-044 連携: MAS-044 / PR #339 で既に実装完了。
PositionTemplateRepository.findAsMap()経由で 11 フィールド(monthlySalary/monthlyRevenue/variableCostRate/defaultRecruitFee/defaultPcCost/monthlyFixedCost/rampUpMonths/revenueContributing/utilization/employmentType/positionName)を取得してフォーム自動入力に使用 - ⚠️
売上貢献 = FALSE行の除外:loadActualAveragesで22_bud_headcountの売上貢献列がFALSEの行を除外(MAS-012 PR #337 と同じ判定)。顧問会計士・顧問社労士等のコスト型 HC を「今後採用する売上貢献型 HC」の想定コスト平均から外す - ⚠️ Human-in-the-Loop: TCO / BEP は判断補助であり、最終的な採用決定は人間が行う。仕様書・サイドバー UI にその旨を明記
エッジケース
| # | 条件 | 検知方法 | 期待される挙動 | ログ出力 |
|---|---|---|---|---|
| 1 | 想定年収 0 or 負値 | input.annualSalary <= 0 | 入力バリデーションエラー・計算中断 | Utils.persistLog('WARN', 'simulate', 'invalid salary', '') |
| 2 | 03_sys_params にパラメータ未投入 | Constants.getParam('TCO_STATUTORY_WELFARE_RATE') がデフォルト値(0.1568)返却 | デフォルト値で計算実行・結果にヒント表示「03_sys_params に初期値を投入してください」 | Utils.logInfo('simulate', 'using default params') |
| 3 | 雇用形態が定義外 | 定義外文字列(例: 'ALBAITO') | 入力バリデーションエラー・UI で dropdown 範囲外を拒否 | Utils.persistLog('WARN', 'simulate', 'invalid employmentType: ' + type) |
| 4 | 22_bud_headcount が空(実績平均プリロード不可) | loadActualAverages で有効行 0 | プリロードをスキップし MAS-044 テンプレート or 手動入力にフォールバック | Utils.logInfo('loadActualAverages', 'no active rows') |
| 5 | 粗利率想定値 0 or 負値 | input.grossMarginRate <= 0 | BEP 月次売上計算でゼロ除算 → Infinity 返却 → UI で「粗利率要確認」赤表示 | Utils.persistLog('WARN', ...) |
| 6 | 40 歳以上指定だが介護保険料率 03_sys_params 未定義 | Constants.getParam('TCO_STATUTORY_WELFARE_RATE_40PLUS') でフォールバック | デフォルト 0.16475 で計算 | Utils.logInfo(...) |
| 7 | 業務委託(GYOUMU_ITAKU)で法定福利費を計算しようとする | 雇用形態分岐で 0 強制 | 法定福利費 = 0 で計算継続 | ログ出力なし(正常系) |
| 8 | 実効 Payback が Infinity(離職率で完全ロスト扱い) | 理論 Payback ≥ 36 | UI で「3 年以内離職リスク大・採用見送り推奨」赤色警告 | Utils.persistLog('WARN', 'calcEffectivePayback', 'payback > 36 months') |
| 9 | 69_report_hiring_tco シート書き込み中に他処理が編集 | LockService.tryLock(5000) 失敗 | 「別の処理が実行中」Toast 表示 | Utils.persistLog('WARN', 'runHiringTcoSimulation', 'lock failed') |
| 10 | サイドバー起動中にマスタ (03_sys_params) 編集 | キャッシュ未更新 | 次回計算から反映(Constants._paramsCache は GAS 実行単位でリセット) | ログ出力なし(正常系) |
| 11 | MAS-044 未実装時にテンプレート選択を試行 | PositionTemplateRepository 存在チェック | dropdown 非表示または「MAS-044 未実装」メッセージ表示 | ログ出力なし |
| 12 | 年収が 3,000 万超の高額想定 | input.annualSalary > 30000000 | 警告表示「一人法人想定範囲外・計算は継続」 | Utils.persistLog('WARN', 'simulate', 'high salary', '') |
| 13 | 採用費率が 1.0 超(年収の 100% 超) | input.recruitFeeRate > 1.0 | 警告表示「採用費率が異常値」・計算は継続 | Utils.persistLog('WARN', ...) |
| 14 | 同時に複数ユーザーがサイドバー起動 | LockService で 1 ユーザーのみ計算実行 | 2 人目は「別処理実行中」Toast | Utils.persistLog('WARN', ...) |
| 15 | Web アプリ(doGet)から実行 | SpreadsheetApp.getUi() が throw | MAS-013 実装の _notifyUser_ パターンで alert → toast → console フォールバック | ログ出力なし |
冪等性・再実行の設計
Gemini レビュー 🟡 Major 指摘対応(MAS-045 との挙動統一): 69_report_hiring_tco への書き込みは 純粋な追記方式。同一条件で複数回実行すれば複数行が追加される(MAS-045 予算転記と同一方針)。
試算 IDはタイムスタンプベース(HTCO_YYYYMMDD_HHMMSS)で毎回一意- 過去試算との比較はユーザーがシート上で手動比較 or 将来の Phase 2 で「試算履歴ビューワー」を提供
- MVP で上書き方式を採用しない理由: MAS-045 予算転記と挙動が異なると「What-if 系の機能は追記だが、採用 TCO 系は上書き」とユーザーが混乱するリスク。類似機能は原則統一(追記方式)
Human-in-the-Loop
- TCO / BEP は判断補助であり、採用決定は人間が行う(仕様書・サイドバー UI に明記)
- MAS-042 との連携で「Go / グレー / No-Go」ラベルを表示するが、背景色のみの視覚警告(自動ブロックはしない)
テスト要件(900_test/901_test_runner.js)
| テスト関数 | 合格基準 |
|---|---|
test_HiringTcoSimulator_simulate_seishain_40under | 年収 600 万 / 正社員 / 40 歳未満 → 年間 TCO = 約 873 万(D.9 §2.2 一致誤差 1% 未満) |
test_HiringTcoSimulator_simulate_gyoumuItaku | 業務委託 → 法定福利費 = 0、TCO = 年収 + 諸費用のみ |
test_HiringTcoSimulator_calcEffectivePayback | 理論 Payback 12 ヶ月 × 離職率 52.7% → 実効 Payback の手計算一致 |
test_HiringTcoSimulator_loadActualAverages_emptyMaster | 22_bud_headcount 空 → avgAnnualSalary = null |
test_HiringTcoSimulator_writeToReport_newRow | 新規試算 → 最終行追加 |
test_HiringTcoSimulator_writeToReport_duplicateId | 同一試算 ID → 既存行上書き |
実データ検証
実装前に MCP で以下を確認:
22_bud_headcountの実ヘッダー行:BUD_HCschema(101_sys_config.jsL943)との一致確認、特に雇用形態/月額給与・報酬/採用エージェント費/PC等初期費用/健保料率等03_sys_paramsの既存キー一覧:TCO_*プレフィックスの 13 キーが未登録であること15_mst_dictionaryのUI雇用形態カテゴリ: 現行値域(正社員 / 契約社員 / 業務委託 / 副業 / パート 等)の確認69_report_hiring_tcoシートが未作成であることCLAUDE.mdの DDL 管理外リスト: 現状03_sys_params/75_ss_equity_changes/76_notes/77_pj_raw/78_pj_pl/91_fs_bs/92_fs_pl/93_kpi_dashboard/94_fs_longterm_forecast/90_test_resultsを列挙中。本案件で69_report_hiring_tco/ MAS-013 で67_report_investment_analysis追記済
関連ドキュメント
| 仕様書・ドキュメント | 関連箇所 |
|---|---|
| dev_mas-012_headcount_simulation.md | 目標売上 → 必要人員数逆算。MAS-048 の「1 人の TCO」と組み合わせて「X 人採用の総投資額」を計算 |
| dev_mas-042_investment_hurdle_rate.md | Go/No-Go 判定エンジン。MAS-048 の TCO/BEP 出力を採用スクリーニング判定に接続 |
| dev_mas-044_hc_template_master.md | MAS-048 の入力源。PositionTemplateRepository からテンプレート年収・雇用形態・初期費用を参照 |
| dev_mas-049_wage_increase_tax_credit_simulator.md | MAS-048 の TCO 計算結果を入力として、賃上げ促進税制の税額控除を試算 |
| ref_boutique_first_hire_simulation.md | D.9 調査レポート。§2 採用 TCO 完全分解・§5 BEP / Payback 計算フレーム・§7 Exit Cost が本案件の根拠 |
| CLAUDE.md | コーディング規約(ヘッダー名ベース列参照・Human-in-the-Loop・DDL 管理外タブリスト) |
人間が検討すべき事項
- 法定福利費率の年次更新フロー: 毎年 4 月料率改定への追従。
03_sys_paramsでの管理は良いが、更新忘れ防止のアラート(4 月になったら「料率更新を確認してください」Toast)を実装するか - 業務委託との比較モードの追加: 現案は単一雇用形態の試算。「正社員 vs 業務委託」の横並び比較モード(Phase 2 拡張)の優先度
- 定着率リスク(3 年以内離職率 52.7%)の感応度分析: 現案はパラメータ固定。職種別・年齢別の離職率を
03_sys_paramsで複数キーに分解するか - オンボーディング工数按分ルール: 現案は
TCO_TRAINING_ANNUAL年 8 万で固定。代表者の時間単価 × OJT 時間での動的計算も検討(D.9 §2.6 の「オンボーディングコスト年収の 20-30%」反映) - MAS-012 との統合シミュレーション: 「必要人員数 × 単位 TCO = 採用総投資額」を 1 画面で表示する統合 UI を MAS-048 内に作るか、別案件で起票するか
- MAS-042 Go/No-Go 連携の実装タイミング: MAS-042 実装時に MAS-048 API を呼ぶ形 or MAS-048 UI に MAS-042 判定ラベルを直接表示。UI 密結合は避けるべきだが、ユーザー体験は密結合の方が良い
- Web アプリ対応: MAS-013 と同様
_notifyUser_フォールバックを実装。スマホから採用検討中に試算できる価値は高い 69_report_hiring_tcoシートの保持期間: 過去の試算履歴は全件保持 or 100 件上限で古いものを自動削除するか- 税務・社労士との連携: 計算結果の年次監査(4 月料率改定後の整合確認)を顧問社労士にレビュー依頼する運用ルール
- D.9 §11 GO/WAIT/NO-GO 判定マトリクス: MAS-048 実装時に「WAIT 推奨ライン」(月商 300 万円未満は採用しない等)を計算結果画面に表示するか
- 稼働率(
utilization)の BEP 補正対応タイミング(Phase 2 拡張候補): MAS-044 テンプレのutilization(0〜1)を BEP 月次売上計算に反映する機能。MVP では表示のみで計算は未反映(フル稼働前提)。業務委託・副業・パートタイムの試算が増えた時点で Phase 2 対応。補正式:BEP 月次売上 ÷ utilization(稼働率 80% なら売上必要額が 1.25 倍に増加) - 立ち上がり月数(
rampUpMonths)の実効 Payback への反映: MAS-044 テンプレのrampUpMonths(入社〜売上貢献開始までの月数)を Payback 計算の「売上貢献開始までのオフセット」として減算する設計。例: 立ち上がり 3 ヶ月で理論 Payback 12 ヶ月 → 実質 15 ヶ月(入社から 15 ヶ月経過で回収完了)。離職率調整と組み合わせた最終 Payback 計算の優先順位を検討 - 売上貢献フラグ FALSE ポジションの TCO 試算モード:
revenueContributing = falseテンプレ(顧問会計士等)の場合、BEP 判定不可のまま TCO のみ表示する運用で良いか。あるいは「クライアント売上からの按分費用」として間接的に BEP を計算する拡張を入れるか
実装プロンプト(Claude Code 用)
あなたは GAS 会計システム (bizlp-gas-accounting) のシニア開発者です。
案件 MAS-048「採用 TCO & BEP シミュレーター」を以下の 5 Step で実装してください。
## 実行前タスク(必須・5 件)
1. `100_config/101_sys_config.js` の `BUD_HC` schema(L943)を Read し `22_bud_headcount` のヘッダー構成を確認
2. `000_infra/002_constants.js` の `Constants.getParam`(L147)と `MENU_DEFINITION`(L206 起点)を Read
3. `docs/arch/ref_boutique_first_hire_simulation.md`(D.9)の §2 / §5 を Read し計算式を確認
4. `docs/dev/dev_mas-013_investment_simulation.md` の `_notifyUser_` パターンを確認(Web アプリ対応)
5. MCP で `69_report_hiring_tco` シート未作成を確認、`03_sys_params` に `TCO_*` キー未登録を確認
## Step 1: `03_sys_params` パラメータ投入 + CLAUDE.md 更新(推奨モデル: Haiku)
- 13 パラメータキー(`TCO_STATUTORY_WELFARE_RATE` 等)を `03_sys_params` に MCP `update_cells` で投入
- `CLAUDE.md` の DDL 管理外リストに `69_report_hiring_tco` 追記
## Step 2: `412_hiring_tco_simulator.js` 新設(推奨モデル: Sonnet)
- namespace `HiringTcoSimulator` を IIFE で定義
- `simulate(input)` / `loadActualAverages()` / `writeToReport(result)` / `runHiringTcoSimulation(input)` の 4 公開関数
- `openHiringTcoSidebar()` グローバル関数(MENU_DEFINITION の funcName と一致)
- `LockService.tryLock(5000)` で排他制御、`_notifyUser_` で Web アプリ対応
- 離職率調整 Payback は D.9 §2.6 の線形近似で実装
## Step 3: サイドバー UI 実装(`templates/hiring_tco_sidebar.html` 新規、推奨モデル: Sonnet)
- 入力フォーム(想定年収プリセット / 雇用形態 dropdown / 年齢区分 / 採用費率 / 粗利率想定)
- 出力: 年間 TCO / 月次 TCO / BEP 月次売上 / 実効 Payback
- 内訳テーブル 13 項目
- MAS-044 テンプレ dropdown(MAS-044 完成前は非表示)
- 「シートに保存」ボタン → `runHiringTcoSimulation` 呼出
## Step 4: MENU_DEFINITION 追記(`002_constants.js`、推奨モデル: Haiku)
- `📋 サイドバー: 📊 マート更新` カテゴリに 1 エントリ追加
- `funcName: 'openHiringTcoSidebar'` と Step 2 のグローバル関数名一致確認
## Step 5: テスト追加(`900_test/901_test_runner.js`、推奨モデル: Sonnet)
- 6 テスト関数(正社員 40 歳未満 / 業務委託 / Payback / プリロード / 追記 / 重複 ID)
- 合格基準: D.9 §2.2 の年収 600 万 → 873 万円 TCO との誤差 1% 未満
## 制約
- `appsscript.json` の `oauthScopes` を変更しない
- 列番号ハードコード禁止(`headers.indexOf` で動的取得)
- 架空の関数名・シート名を使わない(failure_patterns #18-#20)
- MAS-044 未実装時も単体で動作する(テンプレ dropdown は非表示 or グレーアウト)
- 計算ロジックは純粋関数(`simulate` は入出力のみで副作用なし、`SpreadsheetApp` を呼ばない)
## 動作確認
1. サイドバー起動 → 想定年収 600 万 / 正社員 / 40 歳未満
2. 年間 TCO ≒ 873 万円(D.9 §2.2 一致)
3. BEP 月次売上 ≒ 117 万円(粗利率 62%)
4. 実効 Payback 表示
5. 「シートに保存」→ `69_report_hiring_tco` に追記される
6. Web アプリ URL からも実行可能(`_notifyUser_` フォールバック)
推奨実行モデル
| 工程 | 推奨モデル | 理由 |
|---|---|---|
| Step 1: パラメータ投入 + CLAUDE.md 更新 | Claude Haiku 4.5 | 定型作業、判断要素なし |
| Step 2: 計算エンジン実装 | Claude Sonnet 4.6 | D.9 計算式の忠実実装 + 雇用形態分岐の判断 |
| Step 3: サイドバー UI | Claude Sonnet 4.6 | HTML + JS + google.script.run 連携 |
| Step 4: MENU_DEFINITION 追記 | Claude Haiku 4.5 | 1 行追記、判断なし |
| Step 5: テスト追加 | Claude Sonnet 4.6 | 合格基準の D.9 §2.2 との数値一致検証 |
変更履歴
| 日付 | 変更内容 |
|---|---|
| 2026-04-23 | 初版作成。D.9「一人法人 1 人目採用 財務シミュレーション完全ガイド」§2 / §5 の計算フレームを実装する仕様。Jr 採用 D-180(2026-10 入社想定)向け P1.5 ★★★ 最優先案件。namespace HiringTcoSimulator(400_domain/412_hiring_tco_simulator.js 新規)で simulate(input) / loadActualAverages() / writeToReport(result) / runHiringTcoSimulation(input) の 4 公開関数。13 パラメータを 03_sys_params で管理(ハードコード禁止)。69_report_hiring_tco(DDL 管理外・動的上書き)に試算履歴を追記。MAS-044 テンプレ連携・MAS-042 Go/No-Go 連携・MAS-049 税制連携のフック点を確保。エッジケース 15 件・人間検討事項 10 件・推奨実行モデル 5 工程(Haiku×2 / Sonnet×3)を定義 |
| 2026-04-23 | Gemini レビュー(PR #335)指摘を反映。🟡 Major 対応: 冪等性設計を「同一 ID 上書き」から「純粋追記」に変更し、MAS-045 予算転記の挙動と統一。類似機能の挙動差異によるユーザー混乱を回避。試算 ID はタイムスタンプベース(HTCO_YYYYMMDD_HHMMSS)で毎回一意、過去比較は Phase 2 で「試算履歴ビューワー」として拡張予定 |
| 2026-04-23 | 不整合修正: (1) 出力シート番号 68 → 69 に変更(MAS-042 PR #336 で 68_report_investment_gonogo が使用中のため衝突回避、仕様書内 21 箇所を一括置換)、(2) MAS-044 実装(PR #339)で 18_tmpl_hc_position に追加された列(月次追加固定費 / 立ち上がり月数 / 売上貢献 / 稼働率)の MAS-048 での参照方法を明記。PositionTemplateRepository.findAsMap() の 11 フィールド戻り値(monthlyFixedCost / rampUpMonths / revenueContributing / utilization を含む)のフォーム自動反映設計を追加。loadActualAverages に売上貢献フラグ FALSE 除外ロジック(MAS-012 と同じ判定)を追記。人間検討事項 #11〜#13 を追加(稼働率 BEP 補正 / 立ち上がり月数 Payback 反映 / 売上貢献 FALSE ポジション試算モード) |