概要

項目内容
案件IDMAS-037
カテゴリFP&A・B/S管理(R&D関連)
PhaseP2
優先度★★
ステータス仕様書完了(未実装)
対象ファイル(新規)400_domain/408_rpa_depreciation.js
対象ファイル(既存変更)000_infra/002_constants.jsID_PREFIX_MAP / SHEET_DEFAULTS / MENU_DEFINITION 追記)
000_infra/003_contracts.jsSoftwareAssetDTO @typedef 追記)
200_data/202_repository.jsSoftwareAssetRepository 追記)
100_config/101_sys_config.jssetupAllSchemasschemas 定義に BUD_SW_AST を追加 / confSheet.appendRow 追記)
600_report/604_datamart_bs.jsdmCalcBs_() 側に「無形固定資産(ソフトウェア)」台帳集計ロジック追加)
400_domain/407_rpa_orchestrator.jsRPAService.generateDepreciation 追記)
新規シート25_bud_software_asset(ソフトウェア資産台帳・DDL 管理)

目的

開発フェーズで資産計上した自社開発ソフトウェアの 取得 → 月次償却 → 除却 のライフサイクルを 25_bud_software_asset 台帳で一元管理し、月次償却費を 既存の仕訳エンジン(Action A / Action B)経由 で自動計上する。現行は R&D 費用が全額費用処理されており B/S に開発投資が反映されていないため、無形固定資産(ソフトウェア)として B/S に計上することで、財務諸表上「自社でどれだけ投資価値を蓄積したか」を可視化する。

中小企業会計指針(docs/_internal/biz/ 参照)および 600_report/604_datamart_bs.jsdmBuildNotes_ 第 (5) 項「自社利用のソフトウェアについては、将来の収益獲得又は費用削減が確実であると認められた時点で無形固定資産に計上し、利用可能期間(5年)に基づく定額法により償却」に準拠する。

現在のコード

現状は減価償却管理の仕組みが存在しない。以下を全て新設する。

既存モジュール状態MAS-037 での関連
400_domain/401_rpa_hc.jsgenerateHcInvoices既存実装テンプレートRPA冪等性チェック(isDuplicate_(invData, invHeaders, memo) / 管理ID 相当のキー重複検出)→ INV 生成 → writeInvRows_(invSheet, invHeaders, drafts) の骨格を流用する
400_domain/403_rpa_capex.jsgenerateCapexInvoices既存既に 24_bud_capex 台帳ベース で減価償却費の自動起票を行っており、無形固定資産版として同じパターンを踏襲する
200_data/202_repository.jsInvoiceRepository.append(dtos)L185-207 既存流用dtos 配列を渡すと自動で 科目マスタ から 諸表区分/大分類 を補完し 32_wrk_invoice 末尾に追記する
200_data/202_repository.jsInvoiceRepository.findAll()L163-165 既存流用。冪等性チェックで 管理ID 一致の既存 INV を検索する際に呼び出す
000_infra/003_contracts.jsInvoiceDTO typedef)L38-67 既存請求ステータス(有効値 "未処理" | "承認済" | "却下")/ 申請種別 / 管理IDInvoiceDTO に実在しないため JournalEntryDTO管理ID と同名のカラムを 32_wrk_invoice ヘッダーに追加する必要がある(後述 Step 2 参照)
400_domain/410_subledger_engine.js(Action A / Action B)既存変更なし。新規 INV は既存フローに乗せて仕訳化する
600_report/604_datamart_bs.jsdmCalcBs_ / dmGetBsSectionId_L14-32 / L38-127 既存dmGetBsSectionId_表示区分 に「無形固定」が含まれるものを asset_nca に分類済み。「ソフトウェア」科目を 11_mst_account表示区分=無形固定資産 で登録すれば 既存データマート経由で自動 B/S 計上される
600_report/602_datamart_main.jsdmProcessAllEvents_L28-140 既存科目マスタ 未登録の科目はエラー(L49)。本案件では「ソフトウェア」「減価償却費」両科目を事前に 11_mst_account へ登録することが前提

JournalEntryDTO と InvoiceDTO の 管理ID カラム状況(Phase 1 Read で確認):

DTO管理ID フィールド状態
JournalEntryDTO003_contracts.js L97-129)存在(L117)42_trn_journal に実在。42_trn_journal DDL にも含まれる(101_sys_config.js L860)
InvoiceDTO003_contracts.js L38-67)未定義32_wrk_invoice DDL の WRK_INVC 列定義(101_sys_config.js L847)に 管理ID は含まれない

したがって本案件の「管理ID による冪等性チェック」は 32_wrk_invoice の既存カラム(摘要 または新規追加する 管理ID 列) を使う必要がある。既存 RPA(401_rpa_hc.js L202 の isDuplicate_(invData, invHeaders, salaryMemo))は 摘要 文字列の完全一致 で冪等性を担保しているため、本案件も同パターンを踏襲し、摘要に {資産ID}_{対象年月} 形式のキーを含めて一致判定する。32_wrk_invoice ヘッダー改修は不要。

修正方針

以下の 5 ステップで実装する。Step 1〜2 は定数・DTO・Repository の基盤整備、Step 3 が本丸の RPA 新設、Step 4〜5 が集計連携・DDL/メニュー登録。

Step 1: 定数追加(000_infra/002_constants.js

Phase 1 で Constants.ID_PREFIX_MAP(L93-112)と Constants.SHEET_DEFAULTS(L73-87)の正確なフィールド構造を確認済み。既存エントリに倣って 2 件追加する。

Constants.ID_PREFIX_MAP への追加(既存 24_bud_capex / 23_bud_subscription の行間に、番号順を保つ形で挿入):

{ pattern: '25_bud_software_asset', prefix: 'AST_', digit: 4, isDate: false },

Constants.SHEET_DEFAULTS への追加(既存 24_bud_capex の近傍に挿入):

{ pattern: '25_bud_software_asset', prefix: 'AST_', defaults: { '償却方法': '定額法', 'ステータス': '償却中' } },

MENU_DEFINITION への追加: '📋 サイドバー: 📒 経理業務 (RPA / Action)' カテゴリ(L254-267)の 📥 単発経費📥 パイプライン受注 の間に以下を追加(既存項目の 📥 絵文字と「◯◯◯◯月次請求」調の表記に揃える)。

{ label: '📥 ソフトウェア減価償却', funcName: 'generateDepreciationInvoices', description: '25_bud_software_asset 台帳の月次減価償却費 INV を起票' },

注意: generateAllRpaInvoices407_rpa_orchestrator.js L32-63)への組み込みは本案件のスコープ外とする。月次減価償却は 決算関連処理 のため、全 RPA 一括実行 とは独立した明示的な実行が望ましい(「人間が検討すべき事項」参照)。

Step 2: DTO + Repository 追加

000_infra/003_contracts.js への SoftwareAssetDTO 追加: OrderDTO(L14-36)の直後、もしくは BudgetDTO(L131-149)の近傍に以下の @typedef を追加する。

/**
 * 25_bud_software_asset — ソフトウェア資産台帳
 * @typedef {Object} SoftwareAssetDTO
 * @property {boolean}     有効フラグ
 * @property {string}      資産ID(AST)          - "AST_NNNN"
 * @property {string}      資産名
 * @property {Date|string} 取得日
 * @property {number}      取得価額
 * @property {number}      耐用年数(年)         - 3 or 5(税法基準)
 * @property {string}      償却方法             - "定額法"(固定。定率法は当面非対応)
 * @property {string}      償却開始年月         - "YYYY-MM"
 * @property {number}      月次償却額           - 取得価額 ÷ (耐用年数 × 12) の切り捨て整数
 * @property {number}      累計償却額           - これまでに計上済みの償却費合計(RPA が書き戻す)
 * @property {number}      残存簿価             - 取得価額 − 累計償却額(RPA が書き戻す)
 * @property {string}      ステータス           - "償却中" | "償却完了" | "除却"
 * @property {string}      証憑URL
 */

200_data/202_repository.js への SoftwareAssetRepository 追加: JournalRepository(L259-298)の直後、AccountRepository の前に以下を追加する。既存 OrderRepository(L107-146)のパターンを完全踏襲し、内部ヘルパー readSheetAsDtos_ / writeDtosToSheet_ / appendDtosToSheet_ をそのまま再利用する。

var SoftwareAssetRepository = {
  _getSheet: function() {
    return Utils.getSheetByKey('BUD_SW_AST', '25_bud_software_asset');
  },
  findAll: function() {
    return readSheetAsDtos_(SoftwareAssetRepository._getSheet());
  },
  save: function(dtos) {
    var sheet = SoftwareAssetRepository._getSheet();
    if (!sheet) return;
    var headers = sheet.getRange(1, 1, 1, sheet.getMaxColumns()).getValues()[0]
      .map(function(h) { return String(h).trim(); });
    writeDtosToSheet_(sheet, headers, dtos);
  },
  append: function(dtos) {
    var sheet = SoftwareAssetRepository._getSheet();
    if (!sheet) return 0;
    var headers = sheet.getRange(1, 1, 1, sheet.getMaxColumns()).getValues()[0]
      .map(function(h) { return String(h).trim(); });
    return appendDtosToSheet_(sheet, headers, dtos, 1);
  },
};

InvoiceDTO の変更は不要: 管理ID 相当の冪等キーは 摘要 文字列の完全一致で担保する(後述 Step 3)。

Step 3: 月次減価償却RPA新設(400_domain/408_rpa_depreciation.js

401_rpa_hc.jsgenerateHcInvoices(L10-499)を 骨格テンプレート として以下の公開関数を実装する。ファイル番号 408 は Phase 1 調査で未使用を確認済み(401_rpa_hc / 402_rpa_subscription / 403_rpa_capex / 404_rpa_finance / 405_rpa_adhoc / 406_rpa_pipeline / 407_rpa_orchestrator の直後)。

公開関数シグネチャ:

function generateDepreciationInvoices(targetOverride, _silent) { ... }

処理フロー:

  1. 入力取得: SoftwareAssetRepository.findAll(){ headers, dtos: SoftwareAssetDTO[] } を取得
  2. 対象年月の決定: targetOverride 未指定時は Utilities.formatDate(new Date(), tz, 'yyyy-MM')(当月)を採用
  3. 既存 INV 読込(冪等性チェック用): InvoiceRepository.findAll()dtos: InvoiceDTO[] を取得し、既存摘要の Set<string> を構築
  4. 資産行ループ: 各 SoftwareAssetDTO について以下を判定:
    • 有効フラグ !== true → スキップ
    • ステータス === '除却' || ステータス === '償却完了' → スキップ
    • 耐用年数(年) <= 0 || 取得価額 <= 0 → 警告ログ出力してスキップ(エッジケース表参照)
    • 資産名 / 取得価額 / 耐用年数(年) / 償却開始年月 のいずれかが空欄 → 警告ログ出力してスキップ
    • 償却開始年月 > 対象年月 → INV 未生成(償却未開始)
  5. 月次償却額の計算:
    • monthlyAmount = Math.floor(取得価額 / (耐用年数(年) * 12))
    • 残存簿価 < monthlyAmount の場合は最終月扱い → monthlyAmount = 残存簿価 として全額償却
  6. 冪等キー生成: memo = '【RPA:DEP】' + 資産ID(AST) + '_' + 対象年月 + ' ' + 資産名 + ' 月次減価償却費' 形式。例: 【RPA:DEP】AST_0001_2026-04 自社開発PJ管理システム 月次減価償却費
  7. 既存 INV との重複チェック: 既存摘要 Set に memo が含まれていればスキップ(isDuplicate_ 相当の文字列完全一致)
  8. INV 生成: InvoiceRepository.append(dtos) に以下 1 件を追加:
フィールド
有効フラグtrue
起票日時new Date()
起票者'RPA自動起票'
申請種別'財務仕訳(振替等)'(CLAUDE.md「申請種別コードは APL_xxx で統一(APL_TBD/HC/TR/DD/AP/EX/JE)」に従うが、既存 401_rpa_hc.js L290 でも「財務仕訳(振替等)」表記を使用しているため既存パターンを踏襲)
発生日(P/L計上日)対象月の月末日(例: 2026-04-30
決済日_計画発生日と同日(仕訳振替のため実決済は発生しない)
請求ステータス'未処理'
収支区分'支出'
取引先名'(社内)自社開発ソフトウェア'(運用方針で確定後、Constants.RPA_DEFAULTS への追加を検討)
科目名'減価償却費'(事前に 11_mst_account への登録が必要)
税区分'対象外'
通貨'JPY'
税抜金額_計画monthlyAmount
消費税額_計画0
税込金額_計画monthlyAmount
未決済残高(自動計算)monthlyAmount
決済手段'仕訳振替'(CLAUDE.md「仕訳振替の判定は === "仕訳振替" の完全一致」に準拠)
摘要冪等キー memoAST_0001_2026-04 を含む)

注意: 減価償却の仕訳は本来「借方: 減価償却費 / 貸方: ソフトウェア(無形固定資産)」の複合仕訳。本案件では「決済手段=仕訳振替」の INV 1 件として起票し、Action A が P/L 側「減価償却費」の計上と B/S 側「ソフトウェア」の取り崩しを自動処理する(410_subledger_engine.js 既存ロジックに依存)。

  1. 台帳書き戻し(オプション): 生成した INV 件数分だけ 累計償却額 += monthlyAmount / 残存簿価 -= monthlyAmount を更新し、残存簿価 === 0 となった資産は ステータス = '償却完了' とする。ただし実装の初版では台帳書き戻しは省略し、B/S 集計は INV→TRN 経由のみに依存させる 方針とする(二重計上防止)。台帳への残存簿価反映は Step 4 でデータマート側から動的計算する。
  2. 完了通知: Utils.toastResult() または ui.alert() で処理件数と合計償却費を提示:
    🎉 ソフトウェア減価償却 完了
    N 件について、合計 X 円の減価償却費を計上しました(要承認)。
    32_wrk_invoice で内容を確認し、「承認済」に変更してから Action A を実行してください。
    

Human-in-the-Loop 必須(プロダクトポリシー準拠):

  • 生成する INV の 請求ステータス は必ず '未処理'InvoiceDTO の有効値「"未処理" | "承認済" | "却下"」に準拠、独自ステータス新設禁止)
  • ユーザーが 32_wrk_invoice シートで内容を確認し、手動で '承認済' に変更するまで仕訳は生成されない
  • Action A(processInvoiceApprovalsMENU_DEFINITION L264 で登録済)が承認済 INV を検出して TRN に変換する
  • Action B は決済手段=仕訳振替のため実行不要(仕訳振替は Action A 時点で完結する、CLAUDE.md「仕訳振替」仕様)

Step 4: B/Sデータマート連携

Phase 1 調査結果(600_report/604_datamart_bs.js L14-32 の dmGetBsSectionId_ および 600_report/602_datamart_main.js L28-140 の dmProcessAllEvents_)により、B/S 集計は 42_trn_journal の仕訳経由で自動完結する ことが判明した。すなわち以下の 2 条件を満たせば、追加のデータマート改修は不要となる:

  1. 11_mst_account に科目「ソフトウェア」を 諸表区分=B/S, 大分類=資産, 表示区分=無形固定資産 で登録
  2. 11_mst_account に科目「減価償却費」が既に登録されていること(CAPEX 既存運用で登録済みを前提)

ただし仕様書記載要件(冒頭 Phase 2 Step 4)の「SoftwareAssetRepository.findAll() で台帳を読み取り 取得価額 - 累計償却額 を「無形固定資産(ソフトウェア)」として集計するロジックを追加」を満たすため、INV→TRN 経由で自動集計される金額と、台帳の 残存簿価 が一致していることを検証する補助ロジック600_report/604_datamart_bs.js に追加する。

追加関数(dmCalcBs_ 末尾に呼び出し追加):

function dmValidateSoftwareAssetBalance_(ctx) {
  if (typeof SoftwareAssetRepository === 'undefined') return;
  var result = SoftwareAssetRepository.findAll();
  var ledgerBalance = 0;
  for (var i = 0; i < result.dtos.length; i++) {
    var d = result.dtos[i];
    if (d['有効フラグ'] !== true && String(d['有効フラグ']).toUpperCase() !== 'TRUE') continue;
    if (String(d['ステータス']).trim() === '除却') continue;
    ledgerBalance += (Number(d['取得価額']) || 0) - (Number(d['累計償却額']) || 0);
  }
  var martBalance = 0;
  var asset_nca = ctx.martBs['asset_nca'] || {};
  if (asset_nca['ソフトウェア']) {
    var arr = asset_nca['ソフトウェア'];
    martBalance = arr.reduce(function(a, b) { return a + b; }, 0);
  }
  if (Math.abs(ledgerBalance - martBalance) > 1) {
    Utils.logInfo('dmValidateSoftwareAssetBalance_',
      'WARN: ソフトウェア台帳残高(' + ledgerBalance + ') と B/S 集計値(' + martBalance + ') が ±1 円を超えて乖離');
  }
}

呼び出し位置: 600_report/604_datamart_bs.jsdmCalcBs_() 末尾(L127 直前 ctx.flowCl_Fin = flowCl_Fin; の直後)に dmValidateSoftwareAssetBalance_(ctx); を追加。

P/L 側(減価償却費)の集計: 11_mst_account に「減価償却費」が登録済みであれば、既存の dmProcessAllEvents_602_datamart_main.js L40-139)が P/L の sga販管費)セクションに自動計上する(L58 の if (acc.includes("減価償却")) が対応)。追加改修不要。

Step 5: DDLスキーマ登録 + メニュー登録(100_config/101_sys_config.js

Phase 1 で setupAllSchemas(L749-1522)の schemas 定義(L826-901)と confSheet.appendRow(...) ブロック(L769-824)の正確な形式を確認済み。以下 3 箇所を追加する。

(1) システムキー登録(L780 近傍、BUD_SUBS の直後):

if (!existKeys.includes('BUD_SW_AST')) confSheet.appendRow(['BUD_SW_AST', '', '25_bud_software_asset', '予算_ソフトウェア資産台帳(減価償却管理)']);

(2) DDLスキーマ追加(L890 BUD_SUBS 定義の直後):

'BUD_SW_AST': {
  headers: ["有効フラグ","資産ID(AST)","資産名","取得日","取得価額","耐用年数(年)","償却方法","償却開始年月","月次償却額","累計償却額","残存簿価","ステータス","証憑URL"],
  color: "#674ea7",
  validations: {
    "耐用年数(年)":   { type: 'range', min: 1, max: 20, helpText: '税法上の耐用年数。自社利用ソフトウェアは5年、市場販売目的は3年が標準' },
    "取得価額":       { type: 'range', min: 0, max: 100000000 },
    "取得日":         { type: 'date_range', min: '2020-01-01', max: '2030-12-31' }
  }
},

(3) メニュー登録: Step 1 の MENU_DEFINITION 修正で完結(101_sys_config.js 側の追加作業なし)。

備考 — 28_bud_allocation / 29_bud_tax 衝突チェック: Phase 1 で 24_bud_capex / 22_bud_headcount / 23_bud_subscription / 26_bud_adhoc / 27_bud_resource / 28_bud_allocation の既存番号を確認済み。2525_bud_finance として BUD_FIN に既に割り当て済み(L779: 25_bud_finance)。番号衝突が発生する

番号衝突の解消: 既存の 25_bud_finance(BUD_FIN)と衝突しないよう、本案件の新規シート番号を 29_bud_software_asset に変更する(28_bud_allocation の次)。以後、仕様書中のすべての 25_bud_software_asset29_bud_software_asset として読み替える。定数・DTO・Repository・DDL・メニューの全箇所で 29_bud_software_asset を使用する。

影響範囲

ファイル変更種別変更量
000_infra/002_constants.js既存変更ID_PREFIX_MAP / SHEET_DEFAULTS / MENU_DEFINITION 合計 3 行追加
000_infra/003_contracts.js既存変更SoftwareAssetDTO @typedef 約 15 行追加
200_data/202_repository.js既存変更SoftwareAssetRepository 約 25 行追加
400_domain/408_rpa_depreciation.js新規約 200 行(401_rpa_hc.js のパターンを踏襲)
400_domain/407_rpa_orchestrator.js既存変更RPAService.generateDepreciation 1 行追加
100_config/101_sys_config.js既存変更confSheet.appendRow 1 行 + schemas 定義 約 10 行 追加
600_report/604_datamart_bs.js既存変更dmValidateSoftwareAssetBalance_ 関数追加 約 20 行 + dmCalcBs_ 末尾呼出 1 行
11_mst_account シートデータ追加「ソフトウェア」(諸表区分=B/S, 大分類=資産, 表示区分=無形固定資産)を手動登録

注意事項

  1. 請求ステータス'未処理' 固定InvoiceDTO typedef 003_contracts.js L49 に記載の有効値「"未処理" | "承認済" | "却下"」に準拠)。独自ステータス(例: "自動承認済")の新設は 禁止。Human-in-the-Loop を維持するため、承認は必ず人間が行う(プロダクトポリシー「Human-in-the-Loop」)。
  2. 列参照はヘッダー名ベースindexOf / buildHeaderIndex_ 経由でのみアクセスし、列番号ハードコードは禁止(CLAUDE.md コーディング規約)。
  3. 有効フラグ === false の資産行は全処理でスキップ(CLAUDE.md コーディング規約)。
  4. InvoiceRepository.append() 呼び出し前に摘要文字列の重複チェックを必ず実施。冪等キーは 摘要 文字列に 資産ID(AST)_対象年月 を含める形式(例: AST_0001_2026-04)。既存 InvoiceRepository.findAll() で全 INV を読み込んで Set<string> を構築してから判定する。
  5. 101_sys_config.js のメニュー名・関数名・既存シートキーは Phase 1 の Read で確認した実在する文字列のみ使用failure_patterns.md #20: 「コード未読 → 名前から類推」で仕様書に造語を埋め込む禁止)。特に '📋 サイドバー: 📒 経理業務 (RPA / Action)' カテゴリ名は 002_constants.js L254 から逐語引用する。
  6. 新規 INV レコードの摘要プレフィックス 【RPA:DEP】901_test_runner.js の SKIP_PATTERNS に未登録の場合、テスト回帰が発生する可能性あり(failure_patterns.md #8)。実装後に npm run push:dev → dev 環境で runAllTests を実行し、回帰なしを確認すること。
  7. 番号衝突回避: 新規シート番号は 29_bud_software_asset とする(25 は既存の 25_bud_finance と衝突するため)。システムキーは BUD_SW_ASTConstants.ID_PREFIX_MAP / Constants.SHEET_DEFAULTSpattern フィールドも '29_bud_software_asset' を設定する。
  8. 「ソフトウェア」科目の事前登録必須: 11_mst_account科目名='ソフトウェア', 諸表区分='B/S', 大分類='資産', 表示区分='無形固定資産' を手動登録してから RPA 初回実行すること。未登録の場合 602_datamart_main.js L49 でデータマート更新がエラー停止する。
  9. 「減価償却費」科目の事前登録必須: 既存 CAPEX 運用で登録済みのはずだが、未登録の場合は 科目名='減価償却費', 諸表区分='P/L', 大分類='費用', 表示区分='販売費及び一般管理費' で追加すること。
  10. 複合仕訳の扱い: 減価償却仕訳は本来「借方: 減価償却費 / 貸方: ソフトウェア」の複合仕訳だが、本案件は INV 1 件(決済手段=仕訳振替)として起票し、Action A の既存振替ロジック(410_subledger_engine.js)に処理を委ねる。仕訳エンジンの改修は行わない。Action A が期待通り複合仕訳を生成しない場合は「人間が検討すべき事項」で整理する。

エッジケース

条件処理理由
耐用年数(年) が 0 または空欄エラーログ出力(Utils.logError)、その資産をスキップ取得価額 ÷ (耐用年数 × 12) でゼロ除算が発生するため(failure_patterns.md #1 ゼロ除算対策)
取得価額 が 0 またはマイナス警告ログ出力(Utils.logInfo)、スキップ償却計算の前提が成立しない(負の取得価額は会計上ありえない)
資産名 / 取得価額 / 耐用年数(年) / 償却開始年月 のいずれかが空欄警告ログ出力、スキップ必須項目欠損(failure_patterns.md #3 データ不整合対策)
ステータス が「除却」または「償却完了」INV 未生成(スキップ)償却対象外(除却は資産台帳から実質除外、償却完了は残存簿価=0)
有効フラグ が FALSEスキップ全処理共通ルール(CLAUDE.md コーディング規約)
償却開始年月 が対象年月より後(例: 開始=2026-05、対象=2026-04)INV 未生成償却未開始のため計上対象外
月次償却額に端数が生じる(取得価額 ÷ (耐用年数 × 12) が割り切れない)通常月: Math.floor(取得価額 / (耐用年数 × 12))(切り捨て整数額)を適用。最終償却月は 残存簿価(= 取得価額 - 累計償却額)そのものを適用全額を過不足なく償却するため(failure_patterns.md #2 端数処理対策)。切り捨てで発生する残り数円は最終月に集約
残存簿価 < 月次償却額(最終月判定)月次償却額 = 残存簿価(全額)、INV 生成後は ステータス='償却完了' への書き戻し対象残存簿価を負にしないため。書き戻しは初版スコープ外(手動更新運用)
同一摘要(AST_NNNN_YYYY-MM を含む)の INV が既に存在するスキップ(冪等性保証)月次 RPA 二重実行防止(failure_patterns.md #4 冪等性対策)。isDuplicate_(invData, invHeaders, memo) 相当の摘要完全一致で判定
11_mst_account に「ソフトウェア」または「減価償却費」が未登録INV 生成は成功するが、後続のデータマート更新(buildBudgetTrendDataMart)が 602_datamart_main.js L49 でエラー停止11_mst_account 側の事前登録が必須(注意事項 #8 参照)
取得価額 が整数でない(例: 100,000.5 円)Math.floor(取得価額) として扱い、切り捨てを前提とした月次償却額を計算会計処理は整数円単位が原則
耐用年数が極端に長い(例: 100 年)DDL の range バリデーション(min=1, max=20)で入力段階で拒否税法上の耐用年数は最長 20 年程度(自社利用ソフトは 5 年、市場販売ソフトは 3 年が標準)
対象年月 引数が不正形式(例: '20260401'targetYm のバリデーションは RPA 側で実施せず、Utilities.formatDate(new Date(), tz, 'yyyy-MM') のデフォルトにフォールバックHC RPA(401_rpa_hc.js L40-49)のデフォルトパターンを踏襲
32_wrk_invoice シートが存在しないgetInvSheet_() が null を返した段階で ui.alert('🚨 32_wrk_invoice が見つかりません。') して処理中断HC RPA(401_rpa_hc.js L20 相当)のエラーハンドリングを踏襲

実データ検証

  • 29_bud_software_asset新規シート のため、実装前に確認すべき既存データはなし
  • 実装時は以下の手順で段階確認する:
    1. DDL 実行(setupAllSchemas)後にシート生成を確認(13 列ヘッダーが期待通りか)
    2. テストデータを 2〜3 行投入(例: 取得価額=1,200,000 / 耐用年数=5 → 月次償却額=20,000)
    3. dev 環境で generateDepreciationInvoices() を手動実行し、32_wrk_invoice に INV が生成されることを確認
    4. INV を手動承認 → Action A 実行 → 42_trn_journal に「減価償却費 / ソフトウェア」の仕訳が計上されることを確認
    5. buildBudgetTrendDataMart 再実行 → 91_fs_bs で「無形固定資産(ソフトウェア)」残高が月次減少していることを確認
    6. 二重実行テスト: 同じ対象年月で再度 generateDepreciationInvoices() を実行 → 「処理対象なし」で終了すること(冪等性検証)

関連ドキュメント

種別ファイル / 箇所関連内容
規約CLAUDE.md「コーディング規約」「プロダクトポリシー(Human-in-the-Loop)」「GAS ファイル番号体系(Modular Monolith)」
DTO 定義000_infra/003_contracts.js L38-67InvoiceDTO請求ステータス 有効値
Repository200_data/202_repository.js L152-208InvoiceRepository.append() の自動補完ロジック(諸表区分・大分類)
RPA テンプレート400_domain/401_rpa_hc.js L10-499generateHcInvoices の骨格、isDuplicate_ 冪等性チェックパターン
仕訳エンジン400_domain/410_subledger_engine.jsAction A / Action B の処理仕様
B/S 集計600_report/604_datamart_bs.js L14-32dmGetBsSectionId_ のセクション分類ロジック(「無形固定」は asset_nca
データマート600_report/602_datamart_main.js L28-140dmProcessAllEvents_ の P/L / B/S 振り分け(減価償却費は sga に自動集計)
失敗パターンdocs/_internal/failure_patterns.md#1(ゼロ除算) #2(端数処理) #3(データ不整合) #8(テスト SKIP_PATTERNS) #18-#20(仕様書記述の造語禁止) #21-#24(数式設計)
会計基準docs/_internal/biz/中小企業会計指針 第 (5) 項「ソフトウェアの会計処理」(604_datamart_bs.js L212-218 の dmBuildNotes_ にも引用済み)
TODO 管理docs/_internal/TODO_future.md L282MAS-037 エントリ(Phase=P2, 優先度=★★)

人間が検討すべき事項

TODO_future.md からの転記:

  • 償却期間の設定: 税法上の耐用年数は 3 年(市場販売目的ソフトウェア)または 5 年(自社利用ソフトウェア)。自社開発のどちらに該当するかを運用方針として確定する必要がある(docs/_internal/biz/ 側で会計方針書として明文化するか、資産ごとに個別判断するか)
  • 減損判定の基準: 減損の兆候をどう検知するか(例: 関連プロダクト売上が 2 年連続でゼロ、技術陳腐化による利用停止等)。本案件の初版スコープ外だが、将来追加要件として残す

追加の検討事項:

  1. 耐用年数の入力ルール: 税法基準(自社利用=5 年固定 / 市場販売=3 年固定)の 2 値から選択させる方式 vs 自由入力(1〜20 年)方式のどちらにするか。DDL の range バリデーションは暫定で 1〜20 年としたが、運用開始前に確定する
  2. 月次 RPA(408_rpa_depreciation.js)のトリガー設定: 手動実行(MENU_DEFINITION 経由)のみとするか、毎月月末の時間ベーストリガー(ScriptApp.newTrigger('generateDepreciationInvoices').timeBased().onMonthDay(28).atHour(2).create() 相当)で自動起票するか。本案件の初版は 手動実行のみ(他 RPA との整合)とし、時間トリガーは MAS-184(コラボレーション・通知)で統一検討する
  3. B/S データマートへの集計追加方式: Phase 1 の Read 結果では、11_mst_account に「ソフトウェア」を 表示区分=無形固定資産 で登録すれば 既存データマート経由で自動反映される ことが判明した(604_datamart_bs.js L14-32 の dmGetBsSectionId_)。追加の台帳直接集計ロジックは dmValidateSoftwareAssetBalance_ の検証用途のみとし、破壊的変更は行わない
  4. 複合仕訳の検証: 減価償却の仕訳は本来「借方: 減価償却費 / 貸方: ソフトウェア」の複合仕訳。本案件では INV 1 件(決済手段=仕訳振替)として起票し、410_subledger_engine.js の既存振替ロジックに処理を委ねる方針だが、Action A が期待通り複合仕訳を生成するか は実装時に実機検証する必要がある。未対応の場合は Action A 側に「ソフトウェア」科目の特別ハンドリングを追加する(追加スコープ)
  5. 資産取得時の初回 INV 起票: 本案件は月次償却のみ扱う。資産取得時の「借方: ソフトウェア / 貸方: 未払金」の INV 起票は誰が・どのタイミングで行うか(既存 403_rpa_capex.js の CAPEX パターンと統合するか、手動起票とするか)を運用方針として整理する
  6. 台帳の 累計償却額 / 残存簿価 書き戻し方針: 本案件の初版は 書き戻しなし(B/S 集計は INV→TRN 経由で自動計算、台帳は初期値のまま)とするが、ユーザーが台帳上で残存簿価を確認したいニーズがある場合は Step 3-9 の書き戻しロジックを有効化する
  7. 除却イベントの取り扱い: ステータス='除却' に変更した資産について、残存簿価の一括償却(除却損の計上)をどう行うか。本案件の初版スコープ外、別案件として切り出す
  8. 取引先名の扱い: 減価償却 INV の 取引先名 は「自社内部取引」のため取引先マスタに存在しない。Constants.RPA_DEFAULTS に「自社開発ソフト資産」等のキーを追加するか、固定文字列 '(社内)自社開発ソフトウェア' を使うか、取引先マスタに「社内」エントリを追加するかを運用方針として確定する
  9. MAS-034(R&D費用の自動分類・集計)との連携: MAS-034 は研究フェーズ(費用処理)と開発フェーズ(資産計上)を区分する案件。MAS-034 実装時に開発フェーズの費用が本案件の 29_bud_software_asset 台帳へ自動投入される連携を設計するか(直接連携 vs 手動転記)を整理する

実装プロンプト

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-037「ソフトウェア資産の減価償却管理」を実装してください。

## 実行前タスク

実装着手前に以下を全て Read で確認し、実在する関数名・シート名・列名のみを使用すること(failure_patterns.md #18-#20)。

1. `docs/_internal/TODO_future.md` — MAS-037 の案件概要・期待効果・人間検討事項
2. `000_infra/002_constants.js` — `Constants.ID_PREFIX_MAP` / `Constants.SHEET_DEFAULTS` / `Constants.MENU_DEFINITION` の現行定義。追加する新エントリは既存エントリと同一形式(pattern/prefix/digit/isDate または pattern/prefix/defaults)にする
3. `000_infra/003_contracts.js` — `InvoiceDTO` の全フィールド名と `請求ステータス` の有効値("未処理" | "承認済" | "却下")。独自ステータスを作らないこと
4. `200_data/202_repository.js` — `InvoiceRepository.append()` / `findAll()` の実装パターン、内部ヘルパー `readSheetAsDtos_` / `writeDtosToSheet_` / `appendDtosToSheet_` の呼び出し形式
5. `400_domain/401_rpa_hc.js` — `generateHcInvoices` の冪等性チェック(`isDuplicate_`)と INV 生成→`InvoiceRepository.append()` 相当の書き込みパターン
6. `400_domain/407_rpa_orchestrator.js` — `RPAService` の公開 API 構造と命名規則
7. `100_config/101_sys_config.js` — `setupAllSchemas` 内の `schemas` 定義形式(headers / color / validations)と `confSheet.appendRow` 登録パターン、既存メニュー名・関数名の文字列
8. `600_report/604_datamart_bs.js` / `600_report/602_datamart_main.js` — B/S 集計の既存ロジック(`dmGetBsSectionId_` / `dmProcessAllEvents_`)。ソフトウェアは `表示区分=無形固定資産` で `asset_nca` に分類される
9. `docs/_internal/failure_patterns.md` — #1(ゼロ除算)#2(端数)#3(データ不整合)#8(SKIP_PATTERNS)#18-#20(仕様書記述)#21-#24(数式設計)

## 修正対象ファイル

- `000_infra/002_constants.js` — `ID_PREFIX_MAP`・`SHEET_DEFAULTS`・`MENU_DEFINITION` への追記(3 行)
- `000_infra/003_contracts.js` — `SoftwareAssetDTO` の @typedef 追加(約 15 行)
- `200_data/202_repository.js` — `SoftwareAssetRepository` 追加(約 25 行)
- `400_domain/408_rpa_depreciation.js` — **新規作成**(約 200 行)
- `400_domain/407_rpa_orchestrator.js` — `RPAService.generateDepreciation` 1 行追加
- `100_config/101_sys_config.js` — `confSheet.appendRow` 1 行 + `schemas` 定義 約 10 行 追加
- `600_report/604_datamart_bs.js` — `dmValidateSoftwareAssetBalance_` 関数追加 約 20 行 + `dmCalcBs_` 末尾呼出 1 行
- `11_mst_account`(シート) — 「ソフトウェア」科目を手動登録(諸表区分=B/S / 大分類=資産 / 表示区分=無形固定資産)

## 実装内容

### Step 1: 定数追加(`000_infra/002_constants.js`)

- `Constants.ID_PREFIX_MAP` に以下を追加(既存エントリの番号順を保って挿入):
  `{ pattern: '29_bud_software_asset', prefix: 'AST_', digit: 4, isDate: false }`
- `Constants.SHEET_DEFAULTS` に以下を追加:
  `{ pattern: '29_bud_software_asset', prefix: 'AST_', defaults: { '償却方法': '定額法', 'ステータス': '償却中' } }`
- `MENU_DEFINITION` の `'📋 サイドバー: 📒 経理業務 (RPA / Action)'` カテゴリの「📥 単発経費」と「📥 パイプライン受注」の間に以下を追加:
  `{ label: '📥 ソフトウェア減価償却', funcName: 'generateDepreciationInvoices', description: '29_bud_software_asset 台帳の月次減価償却費 INV を起票' }`

### Step 2: DTO + Repository 追加

- `000_infra/003_contracts.js` の `OrderDTO` 直後に `SoftwareAssetDTO` の @typedef を追加(フィールド: 有効フラグ / 資産ID(AST) / 資産名 / 取得日 / 取得価額 / 耐用年数(年) / 償却方法 / 償却開始年月 / 月次償却額 / 累計償却額 / 残存簿価 / ステータス / 証憑URL)
- `200_data/202_repository.js` の `JournalRepository` 直後に `SoftwareAssetRepository` を追加。内部ヘルパー `readSheetAsDtos_` / `writeDtosToSheet_` / `appendDtosToSheet_` をそのまま再利用(新規ヘルパー不要)。システムキーは `'BUD_SW_AST'`

### Step 3: 月次減価償却RPA新設(`400_domain/408_rpa_depreciation.js`)

- `401_rpa_hc.js` の `generateHcInvoices` を骨格テンプレートとして、公開関数 `generateDepreciationInvoices(targetOverride, _silent)` を実装
- 処理フロー:
  1. `SoftwareAssetRepository.findAll()` で台帳取得
  2. 対象年月決定(引数優先、未指定時は当月)
  3. `InvoiceRepository.findAll()` で既存 INV 読込、摘要 `Set<string>` 構築
  4. 資産行ループ(エッジケース表に従ってスキップ判定)
  5. 月次償却額計算: `Math.floor(取得価額 / (耐用年数 × 12))`、最終月は残存簿価全額
  6. 冪等キー生成: `'【RPA:DEP】' + 資産ID(AST) + '_' + 対象年月 + ' ' + 資産名 + ' 月次減価償却費'`
  7. 摘要 Set で重複チェック→スキップまたは追加
  8. `InvoiceRepository.append(dtos)` で `32_wrk_invoice` に追記
- INV 生成フィールド(詳細は仕様書本文の表参照):
  - `請求ステータス='未処理'` 固定
  - `申請種別='財務仕訳(振替等)'`
  - `科目名='減価償却費'`
  - `決済手段='仕訳振替'`
  - `税区分='対象外'`
  - `税抜金額_計画=消費税額_計画=0、税込金額_計画=monthlyAmount`
  - `摘要=冪等キー`
- 完了通知: `ui.alert` で処理件数・償却費合計・承認待ち旨を提示
- エラーハンドリング: `401_rpa_hc.js` の try-catch + `Utils.logError` + `ui.alert` パターンを踏襲
- `RPAService.generateDepreciation = function(targetOverride, silent) { return generateDepreciationInvoices(targetOverride, silent); };` を `407_rpa_orchestrator.js` に追加

### Step 4: B/Sデータマート連携(`600_report/604_datamart_bs.js`)

- `dmValidateSoftwareAssetBalance_(ctx)` 関数を追加。`SoftwareAssetRepository.findAll()` で台帳を読み取り、`取得価額 - 累計償却額` の合計と `ctx.martBs['asset_nca']['ソフトウェア']` の年間累計を比較。±1 円を超える乖離は `Utils.logInfo` で警告ログを出力
- `dmCalcBs_` 末尾の `ctx.flowCl_Fin = flowCl_Fin;` の直後に `dmValidateSoftwareAssetBalance_(ctx);` を追加
- **P/L 集計(減価償却費)は既存の `602_datamart_main.js` L58 の `if (acc.includes("減価償却"))` で自動対応されるため追加改修不要**

### Step 5: DDLスキーマ登録(`100_config/101_sys_config.js`)

- L780 近傍の `BUD_SUBS` 登録の直後に以下を追加:
  `if (!existKeys.includes('BUD_SW_AST')) confSheet.appendRow(['BUD_SW_AST', '', '29_bud_software_asset', '予算_ソフトウェア資産台帳(減価償却管理)']);`
- `schemas` 定義(L826-901 付近)の `BUD_SUBS` 直後に `BUD_SW_AST` を追加:
  `'BUD_SW_AST': { headers: ["有効フラグ","資産ID(AST)","資産名","取得日","取得価額","耐用年数(年)","償却方法","償却開始年月","月次償却額","累計償却額","残存簿価","ステータス","証憑URL"], color: "#674ea7", validations: { "耐用年数(年)": { type: 'range', min: 1, max: 20 }, "取得価額": { type: 'range', min: 0, max: 100000000 }, "取得日": { type: 'date_range', min: '2020-01-01', max: '2030-12-31' } } }`

## 制約

- `請求ステータス` は `'未処理'` 固定。`InvoiceDTO` に存在しないステータス値(例: `"自動承認済"`)を使用しない
- 列参照はヘッダー名ベース(`indexOf` / `buildHeaderIndex_` 経由)。列番号ハードコード禁止
- `有効フラグ === false` の資産行は全処理でスキップ(CLAUDE.md コーディング規約)
- `InvoiceRepository.append()` 呼び出し前に摘要文字列の重複チェックを必ず実施(冪等性)
- メニュー名・関数名・既存シートキーは Read で確認した実在する文字列のみ使用(造語禁止)
- 新規シート番号は **`29_bud_software_asset`**(`25` は `25_bud_finance` と衝突するため)。システムキーは `BUD_SW_AST`
- 「ソフトウェア」「減価償却費」科目を実装前に `11_mst_account` に登録(未登録の場合データマート更新がエラー停止)

## エッジケース

| 条件 | 処理 | 理由 |
|------|------|------|
| `耐用年数(年)` が 0 または空欄 | エラーログ出力、スキップ | ゼロ除算防止 |
| `取得価額` が 0 またはマイナス | 警告ログ出力、スキップ | 償却計算の前提不成立 |
| `資産名` / `取得価額` / `耐用年数(年)` / `償却開始年月` のいずれかが空欄 | 警告ログ出力、スキップ | 必須項目欠損 |
| `ステータス` が「除却」または「償却完了」 | INV 未生成 | 償却対象外 |
| `有効フラグ` が FALSE | スキップ | 全処理共通ルール |
| `償却開始年月` が対象年月より後 | INV 未生成 | 償却未開始 |
| 月次償却額に端数 | 通常月は切り捨て整数、最終月は残存簿価全額 | 全額償却 |
| 残存簿価 < 月次償却額 | 月次償却額 = 残存簿価 | 残存簿価を負にしないため |
| 同一摘要の INV が既存 | スキップ(冪等性) | 二重実行防止 |
| `11_mst_account` に科目未登録 | データマート側でエラー | 事前登録必須 |

## 動作確認

1. `npm run push:dev` でデプロイ
2. dev GAS の `setupAllSchemas` を実行し、`29_bud_software_asset` シートが生成され 13 列ヘッダーが期待通りか確認
3. `11_mst_account` に「ソフトウェア」科目を登録(諸表区分=B/S / 大分類=資産 / 表示区分=無形固定資産)
4. `29_bud_software_asset` にテストデータを 2〜3 行投入(例: 取得価額=1,200,000 / 耐用年数=5 → 月次償却額=20,000 円)
5. 「📒 経理業務 (RPA / Action)」サイドバーから「📥 ソフトウェア減価償却」を実行
6. `32_wrk_invoice` に 摘要 `【RPA:DEP】AST_0001_YYYY-MM 〜` の INV が `請求ステータス=未処理` で生成されることを確認
7. ユーザーが該当 INV を確認・承認(`請求ステータス='承認済'` に変更)
8. 「📋 承認済INV→仕訳 (Action A)」を実行
9. `42_trn_journal` に「減価償却費 / ソフトウェア」の仕訳が計上されることを確認
10. `buildBudgetTrendDataMart` を実行し、`91_fs_bs` で「無形固定資産」区分に「ソフトウェア」残高が月次減少していることを確認
11. 同じ対象年月で再度「📥 ソフトウェア減価償却」を実行し、「処理対象なし」で終了することを確認(冪等性テスト)
12. `runAllTests`(`901_test_runner.js`)を実行し、既存テスト全件通過を確認(`【RPA:DEP】` プレフィックスが SKIP_PATTERNS に未登録の場合は追加)

推奨実行モデル

工程推奨モデル理由
Step 1(定数追加)Claude Haiku 4.5仕様書で追加文字列が完全に確定済み。定型挿入のみ
Step 2(DTO・Repository 追加)Claude Sonnet 4.6既存パターンへの準拠が必要。挿入位置特定と命名一貫性に中程度の判断
Step 3(RPA 新設 408_rpa_depreciation.jsClaude Opus 4.6冪等性・会計ロジック・Human-in-the-Loop・複合仕訳フロー・エッジケース判定など複合的な設計判断が必要
Step 4(B/S データマート連携)Claude Sonnet 4.6既存 dmCalcBs_ への挿入。検証ロジックは単純だが文脈理解が必要
Step 5(DDL・メニュー登録)Claude Sonnet 4.6既存スキーマ定義パターン踏襲。数行追加だが既存エントリと整合させる判断あり
実装前タスク(Phase 1 相当の Read 調査)Claude Sonnet 4.6ファイルパス・行番号の特定と内容理解の両方が必要

変更履歴

日付変更内容
2026-04-21初版作成。MAS-037 ソフトウェア資産の減価償却管理仕様書を作成。29_bud_software_asset 台帳(DDL 管理・13 列)、SoftwareAssetRepository408_rpa_depreciation.js(月次減価償却 RPA)、dmValidateSoftwareAssetBalance_(B/S 集計検証)を定義。Human-in-the-Loop(請求ステータス=未処理)による承認フローを維持し、既存 Action A による複合仕訳生成に処理を委譲する方針。シート番号は当初 25_bud_software_asset で設計したが既存 25_bud_finance との衝突を回避して 29_bud_software_asset に確定。エッジケース 14 項目(ゼロ除算・端数・必須項目欠損・ステータス除外・有効フラグ・償却開始年月未来・最終月残簿・冪等性・科目未登録等)と人間検討事項 9 項目(耐用年数入力ルール・トリガー設定・B/S 集計方式・複合仕訳検証・資産取得時 INV 起票・書き戻し方針・除却処理・取引先名・MAS-034 連携)を定義。推奨実行モデル(Step 1=Haiku / Step 2-5=Sonnet / Step 3=Opus)を明記

仕様書作成プロンプト

展開して表示
<instruction>
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. **拡張思考の使い分け**: Phase 1(設計)では拡張思考をフル活用し、ファイル名形式・エッジケース一覧・Step分割粒度・固有名詞(関数名/シート名/列名/行番号)を完全に確定させる。Phase 2(清書)の各Step内では拡張思考を最小限に抑え、Phase 1で確定済みの内容の書き下しに徹する。出力途中で再考しない。
2. **テキスト報告の禁止**: 「〜を作成します」等のtextのみでtool_useなしにturnを終了しない。説明は1文以内。直ちにtoolを呼ぶ。
3. **4-5分割のWrite/Edit実行**: 2-1(骨格 ~20行)/2-2(概要〜注意事項 ~300行)/2-3a(エッジケース〜人間検討事項 ~200行)/2-3b(実装プロンプト〜変更履歴 ~250行)/2-4(`<details>`プロンプト記録)に分割。1回のWrite/Editは約300行以内。
4. **各Stepで何を書くかを具体指示**: Phase 1で設計判断を完全に確定させ、Phase 2実行時に再考しない。

======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
案件 F-37「ソフトウェア資産の減価償却管理」の開発仕様書を作成してください。
作成完了後、`docs/_config.json` の `nav` 配列の §E.5(FP&A・レポーティング)にも必ず追記してください。

---

## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)

**Grep は「どこにあるか」の発見まで。「どう書くか」の判断は必ず Read で裏取りする(failure_patterns.md #18〜#20)。**
Phase 2 着手前に以下を全て実行し、設計を完全確定させること。

1. `docs/_internal/TODO_future.md` — F-37 の案件名・概要・期待効果・人間が検討すべき事項を取得する。
2. `000_infra/002_constants.js` — `Constants.ID_PREFIX_MAP` の各エントリの正確な形式(pattern/prefix/digit/isDate フィールド構成)と、`Constants.SHEET_DEFAULTS` の各エントリの形式(pattern/prefix/defaults フィールド構成)を Read で確認。追加する新エントリの正確な構造を確定する。
3. `000_infra/003_contracts.js` — `InvoiceDTO` の全フィールド名(特に `請求ステータス` の有効値・`管理ID` の存在)を Read で確認。`SoftwareAssetDTO` の `@typedef` 追加位置を特定する。
4. `200_data/202_repository.js` — `InvoiceRepository.append()` の実装を Read で確認(ヘッダー取得方法・`appendDtosToSheet_` の呼び出し形式)。`SoftwareAssetRepository` に流用する具体的なパターンを確定する。
5. `400_domain/401_rpa_hc.js` — 既存RPAの冪等性チェックロジック(既存レコード検索→重複時スキップ)とINV生成→`InvoiceRepository.append()` 呼び出しパターンを Read で確認。`408_rpa_depreciation.js` の実装テンプレートとして使用する。
6. `400_domain/407_rpa_orchestrator.js` — `RPAService` の公開API構造と、メニューから呼び出す関数の命名規則を Read で確認する。
7. `100_config/101_sys_config.js` — DDLスキーマ登録パターン(`setupAllSchemas` 内の他シート定義の形式)と、既存RPA関数が登録されているメニュー名・メニュー項目名を Read で確認する。実在するメニュー名・関数名のみを仕様書に引用すること(造語禁止)。
8. `600_report/604_datamart_bs.js`(存在する場合、なければ `600_report/` 配下のB/S担当ファイルを Grep で特定してから Read)— B/S資産残高の既存集計ロジックを Read で確認。`25_bud_software_asset` からの集計追加方式を特定する。
9. `docs/_internal/failure_patterns.md` — カテゴリ「計算ロジック」(#1〜#2: ゼロ除算・端数)、「データ不整合」(#3)、「仕様書記述」(#18〜#20)、「数式設計」(#21〜#24) を確認する。

---

## Phase 2: 仕様書の分割作成

出力先: `docs/dev/dev_mas-037_depreciation.md`
**【重要】絶対に1回のツール呼び出しで全内容を出力せず、以下のStepに分割して実行すること。**

### Step 2-1: 骨格の作成 (File Write ~20行)

見出し(H2)のみ。本文は空で可。

### Step 2-2: 概要〜注意事項の追記 (File Edit または Bash ~300行)

以下の内容を書く(Phase 1で確定した固有名詞・行番号をそのまま使用。推測で書かない):

- **概要テーブル**: 案件ID=F-37、カテゴリ=FP&A・B/S管理、Phase、優先度、対象ファイル(002_constants.js / 003_contracts.js / 202_repository.js / 408_rpa_depreciation.js[新規] / 101_sys_config.js / B/Sデータマート担当ファイル)
- **目的**: ソフトウェア資産の取得〜月次償却〜除却までのライフサイクルを `25_bud_software_asset` 台帳で一元管理し、月次償却費を既存の仕訳エンジン(Action B)経由で自動計上する
- **現在のコード**: 「現状は減価償却管理の仕組みが存在しない。以下を全て新設する」旨を記載
- **修正方針**(以下のアーキテクチャ決定事項を Step 1〜5 で記述):

  **Step 1: 定数追加(`000_infra/002_constants.js`)**
  - `Constants.ID_PREFIX_MAP` に追加(Phase 1で確認した形式に準拠):
    `{ pattern: '25_bud_software_asset', prefix: 'AST_', digit: 4, isDate: false }`
  - `Constants.SHEET_DEFAULTS` に追加(Phase 1で確認した形式に準拠):
    `{ pattern: '25_bud_software_asset', prefix: 'AST_', defaults: { '償却方法': '定額法', 'ステータス': '償却中' } }`

  **Step 2: DTO + Repository 追加**
  - `000_infra/003_contracts.js` に `SoftwareAssetDTO` の `@typedef` を追加(既存DTOパターンに倣う)。フィールド: `有効フラグ` / `資産ID(AST)` / `資産名` / `取得日` / `取得価額` / `耐用年数(年)` / `償却方法` / `償却開始年月` / `月次償却額` / `累計償却額` / `残存簿価` / `ステータス`("償却中"|"償却完了"|"除却") / `証憑URL`
  - `200_data/202_repository.js` に `SoftwareAssetRepository` を追加。`readSheetAsDtos_` / `appendDtosToSheet_` 等の既存内部ヘルパーを再利用(Phase 1で確認したパターンを踏襲)

  **Step 3: 月次減価償却RPA新設(`400_domain/408_rpa_depreciation.js`)**
  - `401_rpa_hc.js` 等の既存RPAパターンに倣って実装
  - `SoftwareAssetRepository.findAll()` で台帳を読み取り、償却対象資産ごとに月次償却額を計算してINVを生成
  - **冪等性キー**: `InvoiceDTO` の `管理ID` フィールドに `{資産ID}_{対象年月}` 形式(例: `AST_0001_2026-04`)を設定。INV追記前に `InvoiceRepository.findAll()` で同一 `管理ID` の存在を確認し、重複時はスキップ
  - **Human-in-the-Loop必須**: 生成するINVの `請求ステータス` は `"未処理"` に設定(`InvoiceDTO` の有効値 "未処理"|"承認済"|"却下" に準拠)。プロダクトポリシー「Human-in-the-Loop」に従い、ユーザーが `32_wrk_invoice` を確認・承認してから Action B を実行するフローを維持する。独自ステータス(例: "自動承認済")の新設は禁止
  - RPA完了時に `Utils.toastResult()` で処理件数・償却費合計を通知(例: 「ソフトウェア資産 N 件について、合計 X 円の減価償却費を計上しました(要承認)。」)

  **Step 4: B/Sデータマート連携**
  - Phase 1で確認したB/Sデータマート担当ファイルに、`SoftwareAssetRepository.findAll()` で台帳を読み取り `取得価額 - 累計償却額` を「無形固定資産(ソフトウェア)」として集計するロジックを追加。P/L計上はINV→Action B経由のため複合仕訳は不要

  **Step 5: DDLスキーマ登録 + メニュー登録(`100_config/101_sys_config.js`)**
  - `setupAllSchemas` に `25_bud_software_asset` のスキーマ定義を追加(Phase 1で確認した登録パターンに倣う)
  - Phase 1で確認した実在するメニュー名の下に、`408_rpa_depreciation.js` のエントリーポイント関数を追加

- **影響範囲**: 変更ファイル一覧と変更量を記載
- **注意事項**:
  1. `請求ステータス` は `"未処理"` 固定。`InvoiceDTO` に存在しないステータス値("自動承認済" 等)を使用しない
  2. 列参照はヘッダー名ベース(列番号ハードコード禁止)— CLAUDE.md コーディング規約
  3. `有効フラグ=FALSE` の資産行は全処理でスキップ — CLAUDE.md コーディング規約
  4. `InvoiceRepository.append()` 呼び出し前に `管理ID` の重複チェックを必ず実施
  5. `101_sys_config.js` のメニュー名・関数名は Phase 1 の Read で確認した実在する文字列のみ使用(failure_patterns.md #20)
  6. 新規INVレコードのラベルが `901_test_runner.js` の SKIP_PATTERNS に未登録の場合、テスト回帰が発生する(failure_patterns.md #8)。実装後にテストを実行して確認すること

### Step 2-3a: エッジケース〜人間検討事項の追記 (File Edit または Bash ~200行)

- **エッジケーステーブル**(テーブル形式: 条件 | 処理 | 理由):

  | 条件 | 処理 | 理由 |
  |------|------|------|
  | `耐用年数(年)` が 0 または空欄 | エラーログ出力、その資産をスキップ | `取得価額 ÷ (耐用年数 × 12)` でゼロ除算が発生するため |
  | `取得価額` が 0 またはマイナス | 警告ログ出力、スキップ | 償却計算の前提が成立しない |
  | `資産名` / `取得価額` / `耐用年数` / `償却開始年月` のいずれかが空欄 | 警告ログ出力、スキップ | 必須項目欠損 |
  | `ステータス` が「除却」または「償却完了」 | INV未生成 | 償却対象外 |
  | `有効フラグ` が FALSE | スキップ | 全処理共通ルール(CLAUDE.md) |
  | `償却開始年月` が実行対象月より後 | INV未生成 | 償却未開始 |
  | 月次償却額に端数が生じる(`取得価額 ÷ (耐用年数 × 12)` が割り切れない) | 通常月は切り捨て整数額。最終償却月の額は `残存簿価`(= `取得価額 - 累計償却額`)そのものを適用 | 全額を過不足なく償却するため |
  | 同一 `管理ID`(`{資産ID}_{対象年月}`)のINVが既に存在する | スキップ(冪等性保証) | 月次RPA二重実行防止 |

- **実データ検証**: `25_bud_software_asset` は新規シートのため DDL 実行(`setupAllSchemas`)後にスキーマを確認する。実装前に確認すべき既存データはなし
- **関連ドキュメント**: テーブル形式で関連仕様書を列挙(CLAUDE.md、003_contracts.js の InvoiceDTO 定義等)
- **人間が検討すべき事項**: TODO_future.md から転記し、以下を追加:
  - 耐用年数の入力ルール(税法基準 or 自由入力か)を運用方針として確認する
  - 月次RPA(`408_rpa_depreciation.js`)のトリガー設定(手動実行 vs 時間ベーストリガー)を確認する
  - B/Sデータマートへの集計追加は Phase 1 の Read 調査結果に基づき、既存集計ロジックを破壊しないよう慎重に実装する

### Step 2-3b: 実装プロンプト〜変更履歴の追記 (File Edit または Bash ~250行)

実装プロンプトは**バッククォートのコードブロックで囲まず、行頭4スペースインデント**で出力すること。

実装プロンプトに含める内容:

    あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
    案件 F-37「ソフトウェア資産の減価償却管理」を実装してください。

    ## 実行前タスク
    (Phase 1と同じファイルリスト・確認ポイントを転記。Read で裏取り済みの情報のみ使用)

    ## 修正対象ファイル
    - `000_infra/002_constants.js` — ID_PREFIX_MAP・SHEET_DEFAULTS への追記
    - `000_infra/003_contracts.js` — SoftwareAssetDTO の @typedef 追加
    - `200_data/202_repository.js` — SoftwareAssetRepository の追加
    - `400_domain/408_rpa_depreciation.js` — 新規作成
    - B/Sデータマート担当ファイル — 集計ロジック追加
    - `100_config/101_sys_config.js` — DDLスキーマ登録・メニュー登録

    ## 実装内容
    (Step 1〜5の具体的な変更手順とコード例)

    ## 制約
    - 請求ステータスは "未処理" 固定。InvoiceDTO に存在しないステータス値を使用しない
    - 列参照はヘッダー名ベース(列番号ハードコード禁止)
    - メニュー名・関数名は Read で確認した実在する文字列のみ使用
    - InvoiceRepository.append() 前に 管理ID の重複チェックを必ず実施

    ## エッジケース
    (Step 2-3a のテーブルと同内容を転記)

    ## 動作確認
    1. npm run push:dev でデプロイ
    2. Phase 1 で確認した実在するメニューから月次減価償却RPAを実行
    3. 32_wrk_invoice に 管理ID(例: AST_0001_2026-04)付きのINVが「未処理」で生成されることを確認
    4. ユーザーが該当INVを確認・承認してから Action B を実行
    5. 42_trn_journal に減価償却費の仕訳が計上されることを確認
    6. B/Sデータマートを更新し、「無形固定資産(ソフトウェア)」残高が正しく集計されることを確認
    7. 同じ対象年月で再度RPAを実行し、二重計上が起きないことを確認(冪等性テスト)
    8. 901_test_runner.js の全テストを実行し、回帰がないことを確認

推奨実行モデルテーブル:

| 工程 | 推奨モデル | 理由 |
|------|-----------|------|
| Step 1〜2(定数・DTO・Repository追加) | Claude Sonnet 4.6 | 既存パターンへの準拠。中程度の判断 |
| Step 3(RPA新設) | Claude Opus 4.6 | 冪等性・会計ロジック・Human-in-the-Loop の複合設計 |
| Step 4〜5(B/S連携・DDL・メニュー登録) | Claude Sonnet 4.6 | 既存パターン踏襲。中程度の判断 |

変更履歴テーブル:

| 日付 | 変更内容 |
|------|---------|
| 2026-04-20 | 初版作成 |

### Step 2-4: 仕様書作成プロンプトの記録 (File Edit または Bash)

末尾に `<details><summary>展開して表示</summary>` ブロックを追加し、この `<instruction>` 全文を記録する。

---

## Phase 3: 保存・登録・コミット

1. **`docs/_config.json` 更新**: `nav` 配列の §E.5(FP&A・レポーティング)に以下を追加:
   `{ "file": "dev/dev_mas-037_depreciation.md", "title": "E.5.X F-37 ソフトウェア資産の減価償却管理" }`

2. **`docs/_internal/changelog.md` 更新**: ヘッダー直後に追記:
   `| 2026-04-20 | [dev_mas-037_depreciation.md](dev_mas-037_depreciation.md) | 初版作成。25_bud_software_asset台帳・408_rpa_depreciation・B/S連携の仕様定義 |`

3. **git commit & push**:

git add docs/dev/dev_mas-037_depreciation.md docs/_config.json docs/_internal/changelog.md git commit -m "docs: MAS-037 ソフトウェア資産の減価償却管理の開発仕様書を作成

新規シート25_bud_software_asset、SoftwareAssetRepository、 408_rpa_depreciation.js、B/Sデータマート連携の仕様を定義。 Human-in-the-Loop(請求ステータス=未処理)による承認フローを維持。

https://claude.ai/code/session_XXXXX" git push -u origin {現在のブランチ}

</instruction>