概要

項目内容
案件IDMAS-135
カテゴリDDL・マスタ
PhaseP2
優先度★★
所要時間6〜8 時間(5 Step)
実装ステータス📝 仕様書段階・実装未着手 (2026-04-28 監査時点)
対象ファイル100_config/101_sys_config.js(DDL / システムキー / メニュー), 200_data/202_repository.jsPaymentMethodRepository 新設), 000_infra/003_contracts.jsPaymentMethodDTO @typedef 追加), 400_domain/400_rpa_common.js(決済日計算ヘルパー集約先), 400_domain/402_rpa_subscription.js L206-222(決済日計算の呼び出し箇所), 400_domain/405_rpa_adhoc.js L94-101(同), 400_domain/406_rpa_pipeline.js L155-164(同), 300_ui/301_ui_assist.js(onEdit 補完拡張), 800_ops/812_migration_payment_method.js(新規マイグレーション)
前提案件MAS-120(実装完了 PR #215) — 取引先マスタ標準決済条件(12_mst_partner の 5 列拡張 + PartnerRepository.findPaymentTermsMap())が既に稼働中。本案件はその次段フォールバック層(取引先マスタ未登録の取引先向け)を提供する

目的

決済手段(JCB / 楽天カード / 口座振替 / 銀行振込 / 立替精算 / 現金 等)ごとにほぼ固定で決まる決済条件(決済ラグ(月) / 支払基準日 / 休日調整方向)を新規マスタ 18_mst_payment_method に集約し、以下 3 つの課題を同時に解決する:

  1. 手入力による設定不整合の解消 — 20 番台予算タブ・32_wrk_invoice の各行で「決済手段=JCB」を選んでも、「決済ラグ(月)」「支払基準日」が手入力のため JCB 13 日 / 25 日 / 月末等、表記ゆれや設定忘れが混在する。マスタ参照に統一することで 1 箇所更新で全行に反映される
  2. カード会社の締日改定への追従 — カード会社が締日を変更した場合、マスタ 1 行の書き換えで全取引先・全タブに即反映。現状は既存行の手修正が必要
  3. MAS-120(取引先マスタ)の補完 — 取引先マスタに標準決済条件が登録されていない取引先(スポット契約・新規取引先など)でも、決済手段を選ぶだけで妥当なデフォルトを得られる

本案件は (a) 取引先マスタ(MAS-120) → (b) 決済手段マスタ(本件) → (c) 個別手入力値 という 3 層のフォールバック優先順位を確立する中間層を担う。

現在のコード

決済日計算ロジックの所在(集約された共通ヘルパーは存在しない

調査の結果、決済日(決済日_計画)の算出ロジックは RPA 実装ファイルごとにインラインで記述されており、400_domain/400_rpa_common.js にも集約された共通ヘルパーは存在しない。各所の記述は概ね同一ロジックだが、フォールバック挙動が微妙に異なる。

402_rpa_subscription.js L206-222(SaaS サブスク):

// ラグ計算
let lagStr = idxLag !== -1 ? String(row[idxLag]) : '0';
lagStr = lagStr.replace(/[0-9]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 0xFEE0); }).replace(/[^\d.-]/g, '');
const lag = parseInt(lagStr, 10) || 0;

// 発生日: 対象年月末日
const occurDate = new Date(cY, cM, 0);

// 決済予定日
const payDay = idxPayDay !== -1 ? (parseInt(String(row[idxPayDay]), 10) || 0) : 0;
var settleDate;
if (payDay > 0) {
  const maxDay = new Date(cY, cM + lag, 0).getDate();
  settleDate = new Date(cY, cM - 1 + lag, Math.min(payDay, maxDay));
} else {
  settleDate = new Date(cY, cM + lag, 0);
}

405_rpa_adhoc.js L94-101(単発・アドホック予算):

var payDayRaw = col['支払基準日'] !== -1 ? (parseInt(String(row[col['支払基準日']]), 10) || 0) : 0;
var settleDate;
if (payDayRaw > 0) {
  const maxDay = new Date(sY, sM, 0).getDate();
  settleDate = new Date(sY, sM - 1, Math.min(payDayRaw, maxDay));
} else {
  settleDate = new Date(oParts[0], oParts[1] + lag, 0);
}

406_rpa_pipeline.js L155-164(売上パイプライン / 入金):

function calcSettleDate(curYm) {
  var sYm = Utils.addMonths(curYm, lag);
  var sp = sYm.split('-').map(Number);
  if (payDayRaw > 0) {
    var maxDay = new Date(sp[0], sp[1], 0).getDate();
    return new Date(sp[0], sp[1] - 1, Math.min(payDayRaw, maxDay));
  }
  return new Date(sp[0], sp[1], 0);
}

いずれも**「休日調整」を呼んでいない**。現状、Utils.adjustToBusinessDay(ymdStr, direction)000_infra/004_utils.js L430)は実装済みだが、RPA 内部での呼び出し実例はなく、20 番台予算タブの「休日調整」列の値(例: 前営業日 / 翌営業日 / 空)は事実上読まれていない可能性が高い。本案件 Step 3 の改修対象。

既存マスタ DDL のパターン(100_config/101_sys_config.js

L826-901 の schemas = { ... } 辞書で DDL を宣言的に定義。代表例:

'MST_ACCT': { headers: ["有効フラグ","主科目コード",...], color: "#666666" },
'MST_PART': { headers: [..., "標準決済手段","標準決済ラグ(月)","標準支払基準日","標準休日調整","標準CF計上区分"], color: "#666666",
  validations: {
    "標準決済ラグ(月)": { type: 'range', min: -1, max: 12 },
    "標準支払基準日":   { type: 'range', min: 1, max: 31 }
  }
},

L769-824 の confSheet.appendRow(['MST_XXX', '', 'NN_xxx', '論理名']) パターンで 01_sys_configConstants.CONFIG_SHEET)にシステムキーを登録する。本案件では MST_PMTM を同方式で追加する。

既存シート番号の割り当て状況(マスタ系 11_mst_*19_mst_*

番号シート名ステータス
1111_mst_account実装済(MST_ACCT
1212_mst_partner実装済(MST_PART
1313_mst_organization実装済(MST_ORGN
1414_mst_project実装済(MST_PROJ
1515_mst_dictionary実装済(MST_DICT
1616_wrk_master実装済(WRK_MAST:マスタ登録申請ワークフロー)
1717_mst_intellectual未実装(MAS-035 仕様書で予約)
1818_mst_tax_rate未実装(MAS-119 仕様書で予約)
1919_mst_loan_pattern未実装(MAS-121 仕様書で予約)

シート番号の暫定割り当て: 本仕様書では 18_mst_payment_method を暫定案としているが、MAS-119(税率/保険料率マスタ)が同じ 18 番を予約済みのため番号衝突リスクあり。実装着手時に未着手仕様書との調整が必要(人間が検討すべき事項に記載)。候補は 17 / 18 / 19 / 20

onEdit ハンドラの所在

  • 100_config/101_sys_config.js L409 に唯一の function onEdit(e) が存在し、内部から handleUxAssist(e) を呼ぶ
  • 300_ui/301_ui_assist.js L70 handleUxAssist が実体(L75 の validSheets 配列にシート名を登録)
  • MAS-120 実装で既に applyPartnerPaymentTerms_ ヘルパー(L42-66)が導入済み。対象シート判定マップ PARTNER_TERMS_COL_MAP(L18-22)で 21_bud_pipeline / 23_bud_subscription / 26_bud_adhoc をカバー
  • 23_bud_subscription 分岐: L137-140(サービス名入力時の補完) + L158-161(取引先名後入力時の補完)
  • 21_bud_pipeline 分岐: L333-336 + L347-350
  • 26_bud_adhoc 分岐: L354-359

本案件では applyPartnerPaymentTerms_ 呼び出し後の残空欄に対して、同パターンで applyPaymentMethodTerms_ を呼ぶ 2 段フォールバック構造にする。

Repository パターン(200_data/202_repository.js

L304-350 の AccountRepository が読み取り専用マスタ Repository の標準パターン:

var AccountRepository = {
  _getSheet: function() { return Utils.getSheetByKey('MST_ACCT', '11_mst_account'); },
  findAll: function() { return readSheetAsDtos_(AccountRepository._getSheet()); },
  findAsMap: function() {
    if (AccountRepository._cache) return AccountRepository._cache;
    var result = AccountRepository.findAll();
    var map = {};
    for (var i = 0; i < result.dtos.length; i++) {
      var dto = result.dtos[i];
      var flag = dto['有効フラグ'];
      if (flag === false || String(flag).toUpperCase() === 'FALSE') continue;
      var name = String(dto['科目名'] || '').trim();
      if (name) map[name] = { stmt: ..., cat: ... };
    }
    AccountRepository._cache = map;
    return map;
  },
  _cache: null,
  resetCache: function() { AccountRepository._cache = null; },
};

L356-406 の PartnerRepository(MAS-120 実装済)も同一パターンで、findPaymentTermsMap() が本案件の findAsMap() の直接の参考になる。

既存マイグレーションスクリプト

800_ops/ ディレクトリの使用番号: 801-809, 810, 811810_migration_partner_payment_terms.js(MAS-120), 811_audit_checker.js)。次の空き番号は 812

MAS-120 マイグレーション(810_migration_partner_payment_terms.js)は本案件の直接の参考実装で、以下のパターンを踏襲できる:

  1. 冒頭で Repository.resetCache()
  2. 対象シート群から決済条件を集計(最頻値抽出 + 同点は先出現優先)
  3. Utils.auditLog('MIGRATE', ..., 'START'/'END') の監査ログ
  4. SpreadsheetApp.getUi().alert でサマリ表示
  5. 冪等性: 既存マスタ値が空欄の場合のみ setValue

修正方針

Step 1: DDL スキーマ追加(100_config/101_sys_config.js

confSheet.appendRow へのシステムキー登録(L818 付近、'SYS_TEST' の行の近傍に挿入):

if (!existKeys.includes('MST_PMTM')) confSheet.appendRow(['MST_PMTM', '', '18_mst_payment_method', 'マスタ_決済手段/決済条件']);

schemas 辞書にエントリ追加(L835 MST_ORGN の前後、マスタ系がまとまって並んでいる位置に挿入):

'MST_PMTM': {
  headers: ["有効フラグ","決済手段コード","決済手段名","標準決済ラグ(月)","標準支払基準日","標準休日調整","備考"],
  color: "#666666",
  validations: {
    "標準決済ラグ(月)": { type: 'range', min: -1, max: 12, helpText: '-1〜12 の整数で入力してください(-1 = 前払い / 0 = 当月 / 正値 = 後払い月数)' },
    "標準支払基準日":   { type: 'range', min: 1, max: 31, helpText: '1〜31 の整数。月末の場合は 31 を入力(動的に末日に丸める)' }
  }
},

inputCols マッピング追加(L1189 MST_ACCT / L1190 MST_PART の近傍):

if (key === 'MST_PMTM') { inputCols = [1,2,3,4,5,6,7]; }

④プルダウン検証setVali 群、L1485 の MST_PART の後に追加):

  • 列 6(標準休日調整)→ UI休日調整(MAS-140 で名前付き範囲化予定。未定義時は 前営業日 / 当日 / 翌営業日 のハードコード値リストで暫定)

列定義の根拠:

  • 決済手段コード: 英数 4 文字(例: JCB_, RKT_, BANK, CASH, DEPO)。将来マスタ間参照で使用
  • 決済手段名: 実データの表記に合わせる(JCB / 楽天カード / 口座振替 / 銀行振込 / 立替精算 / 現金 / 未定 等)。20 番台予算タブ・32_wrk_invoice の「決済手段」列の値と完全一致している必要あり(findAsMap() のキー)
  • 標準決済ラグ(月): MST_PART の 標準決済ラグ(月) と同じ範囲 -1〜12
  • 標準支払基準日: MST_PART の 標準支払基準日 と同じ範囲 1〜3131 は動的に末日へ丸める)
  • 標準休日調整: 前営業日 / 当日 / 翌営業日 / 空 の 4 値(Utils.adjustToBusinessDay の direction 引数との対応)

Step 2: PaymentMethodRepository / PaymentMethodDTO の新設

000_infra/003_contracts.js@typedef 追加(末尾、既存 PartnerDTO 等の後):

/**
 * 18_mst_payment_method — 決済手段マスタ
 * @typedef {Object} PaymentMethodDTO
 * @property {boolean} 有効フラグ
 * @property {string}  決済手段コード
 * @property {string}  決済手段名
 * @property {number}  標準決済ラグ(月)
 * @property {number}  標準支払基準日
 * @property {string}  標準休日調整
 * @property {string}  備考
 */

200_data/202_repository.jsPaymentMethodRepository を新設PartnerRepository の直後・ファイル末尾に追加、既存 Repository は一切変更しない):

// =====================================================================
// PaymentMethodRepository — 18_mst_payment_method (読み取り専用マスタ)
// =====================================================================

var PaymentMethodRepository = {

  /** @private */
  _getSheet: function() {
    return Utils.getSheetByKey('MST_PMTM', '18_mst_payment_method');
  },

  /**
   * 全決済手段マスタレコードを DTO 配列で取得する。
   * @returns {{ headers: string[], dtos: Object[] }}
   */
  findAll: function() {
    return readSheetAsDtos_(PaymentMethodRepository._getSheet());
  },

  /**
   * 決済手段名をキーとする決済条件マップを返す(キャッシュ付き)。
   * キー: 決済手段名(例: "JCB")
   * 値: { lagMonths, baseDay, holidayDir, code }
   * @returns {Object.<string, {lagMonths: number, baseDay: number, holidayDir: string, code: string}>}
   */
  findAsMap: function() {
    if (PaymentMethodRepository._cache) return PaymentMethodRepository._cache;
    var result = PaymentMethodRepository.findAll();
    var map = {};
    for (var i = 0; i < result.dtos.length; i++) {
      var dto = result.dtos[i];
      var flag = dto['有効フラグ'];
      if (flag === false || String(flag).toUpperCase() === 'FALSE') continue;
      var name = String(dto['決済手段名'] || '').trim();
      if (!name) continue;
      map[name] = {
        code:       String(dto['決済手段コード'] || '').trim(),
        lagMonths:  Number(dto['標準決済ラグ(月)']) || 0,
        baseDay:    Number(dto['標準支払基準日']) || 0,
        holidayDir: String(dto['標準休日調整'] || '').trim(),
      };
    }
    PaymentMethodRepository._cache = map;
    return map;
  },

  /** @private */
  _cache: null,

  /** キャッシュをリセットする */
  resetCache: function() {
    PaymentMethodRepository._cache = null;
  },
};

キャッシュ方針: AccountRepository / PartnerRepository と同一。GAS 実行単位でインメモリ保持。マイグレーション側では冒頭で resetCache() を呼ぶこと(MAS-003 失敗例回避)。

Step 3: 決済日計算ロジックの共通化 + フォールバック優先順位対応

400_domain/400_rpa_common.js に共通ヘルパー RpaCommon.resolveSettlementTermsRpaCommon.calcSettleDate を新設(ファイル末尾の resolveDefault の後に追加):

/**
 * 決済条件をフォールバック順 (a)→(b)→(c) で解決する。
 * @param {string} partnerName - 取引先名(UI用取引先名 or 取引先名_正式)
 * @param {string} paymentMethod - 決済手段名
 * @param {{lagMonths?: number, baseDay?: number, holidayDir?: string}} rowOverride - 行個別の手入力値
 * @returns {{lagMonths: number, baseDay: number, holidayDir: string, source: string}}
 *   source: 'partner' | 'method' | 'row' | 'default'(デバッグ用)
 */
resolveSettlementTerms: function(partnerName, paymentMethod, rowOverride) {
  var result = {
    lagMonths:  null,
    baseDay:    null,
    holidayDir: '',
    source:     'default',
  };
  var ov = rowOverride || {};

  // (a) 取引先マスタ(S-48) — 最上位
  var partnerKey = String(partnerName || '').trim();
  if (partnerKey) {
    try {
      var pMap = PartnerRepository.findPaymentTermsMap();
      var t = pMap[partnerKey];
      if (t) {
        if (result.lagMonths === null && t['決済ラグ月'] !== '' && t['決済ラグ月'] != null) {
          result.lagMonths = Number(t['決済ラグ月']);
          result.source = 'partner';
        }
        if (result.baseDay === null && t['支払基準日'] !== '' && t['支払基準日'] != null) {
          result.baseDay = Number(t['支払基準日']);
          result.source = 'partner';
        }
        if (!result.holidayDir && t['休日調整']) {
          result.holidayDir = t['休日調整'];
          result.source = 'partner';
        }
      }
    } catch (e) { /* マスタ未整備時はフォールスルー */ }
  }

  // (b) 決済手段マスタ(本案件)
  var methodKey = String(paymentMethod || '').trim();
  if (methodKey) {
    try {
      var mMap = PaymentMethodRepository.findAsMap();
      var m = mMap[methodKey];
      if (m) {
        if (result.lagMonths === null) { result.lagMonths = m.lagMonths; if (result.source === 'default') result.source = 'method'; }
        if (result.baseDay === null)   { result.baseDay = m.baseDay;     if (result.source === 'default') result.source = 'method'; }
        if (!result.holidayDir)        { result.holidayDir = m.holidayDir; if (result.source === 'default') result.source = 'method'; }
      }
    } catch (e) { /* マスタ未整備時はフォールスルー */ }
  }

  // (c) 行個別の手入力値
  if (result.lagMonths === null && ov.lagMonths !== undefined && ov.lagMonths !== '') {
    result.lagMonths = Number(ov.lagMonths);
    if (result.source === 'default') result.source = 'row';
  }
  if (result.baseDay === null && ov.baseDay !== undefined && ov.baseDay !== '') {
    result.baseDay = Number(ov.baseDay);
    if (result.source === 'default') result.source = 'row';
  }
  if (!result.holidayDir && ov.holidayDir) {
    result.holidayDir = ov.holidayDir;
    if (result.source === 'default') result.source = 'row';
  }

  // デフォルト (ラグ=0 / 末日 / 調整なし)
  if (result.lagMonths === null) result.lagMonths = 0;
  if (result.baseDay === null)   result.baseDay = 0;  // 0 = 月末指定
  return result;
},

/**
 * 発生年月・決済条件から決済予定日を計算する。
 * @param {string} occurYm - 発生年月 "YYYY-MM"
 * @param {{lagMonths: number, baseDay: number, holidayDir: string}} terms
 * @returns {Date}
 */
calcSettleDate: function(occurYm, terms) {
  if (!occurYm) return null;
  var targetYm = Utils.addMonths(occurYm, terms.lagMonths || 0);
  var parts = targetYm.split('-').map(Number);
  var y = parts[0], m = parts[1];
  var settle;
  if (terms.baseDay && terms.baseDay > 0) {
    var maxDay = new Date(y, m, 0).getDate();
    var day = Math.min(terms.baseDay, maxDay);
    settle = new Date(y, m - 1, day);
  } else {
    settle = new Date(y, m, 0); // 月末
  }
  // 休日調整
  if (terms.holidayDir === '前営業日' || terms.holidayDir === '翌営業日') {
    var dir = terms.holidayDir === '翌営業日' ? '後' : '前';
    var ymdStr = Utilities.formatDate(settle, Session.getScriptTimeZone(), 'yyyy-MM-dd');
    var adjusted = Utils.adjustToBusinessDay(ymdStr, dir);
    var ap = adjusted.split('-').map(Number);
    settle = new Date(ap[0], ap[1] - 1, ap[2]);
  }
  return settle;
},

②既存 RPA 3 ファイルの決済日計算箇所を共通ヘルパーに置き換え:

  • 400_domain/402_rpa_subscription.js L206-222 → RpaCommon.resolveSettlementTerms(ptnName, payMethodStr, { lagMonths: lag, baseDay: payDay, holidayDir: /* 該当列値 */ }) + RpaCommon.calcSettleDate(curYm, terms) に置き換え
  • 400_domain/405_rpa_adhoc.js L94-101 → 同様の置き換え
  • 400_domain/406_rpa_pipeline.js L155-164(calcSettleDate インライン関数)→ 共通ヘルパー呼び出しに置き換え

互換性維持の観点:

  • 既存 RPA のラグ計算に含まれる「全角数字→半角変換」「[^\d.-] 除去」は、文字列として入力された値を Number() で受けた場合の挙動差に注意。resolveSettlementTerms の行個別値受け取り時に同変換を適用するか、呼び出し側で数値化してから渡す
  • 既存の payMethodStr.includes('未定') で空文字化する分岐(402 L260)は本ヘルパー外部で引き続き適用

Step 4: onEdit 自動補完の追加(300_ui/301_ui_assist.js

MAS-120 の applyPartnerPaymentTerms_直後に 2 段目フォールバックとして applyPaymentMethodTerms_ を呼び出す。

①マッピング追加(L18-22 PARTNER_TERMS_COL_MAP の直後に PAYMENT_METHOD_TERMS_COL_MAP を新設。同じ列構成で使い回し可能):

// 決済手段マスタから引く列。マスタの「標準〜」から取得し、決済手段列が未編集でも補完対象とする
var PAYMENT_METHOD_TERMS_COL_MAP = {
  '21_bud_pipeline':     { 決済ラグ月: '入金ラグ(月)', 支払基準日: '入金日',   休日調整: '休日調整' },
  '23_bud_subscription': { 決済ラグ月: '決済ラグ(月)', 支払基準日: '支払基準日', 休日調整: '休日調整' },
  '26_bud_adhoc':        { 決済ラグ月: '決済ラグ(月)', 支払基準日: '支払基準日' }, // 休日調整 列なし
  '32_wrk_invoice':      { }, // INV には決済条件列なし(決済日_計画 のみ)→ 別処理
};

②ヘルパー関数新設applyPartnerPaymentTerms_ の直後、L66 直後):

/**
 * 決済手段マスタの標準決済条件を対象シートの空欄セルに転記する(S-48 補完の 2 段目)。
 * - S-48 `applyPartnerPaymentTerms_` 実行後に呼ばれる想定
 * - 「空欄のみ補完」原則。ユーザー手入力値は保護
 * - マスタ未登録の決済手段は何もしない
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet
 * @param {number} row
 * @param {string[]} headers
 * @param {string} paymentMethod - 決済手段名
 */
function applyPaymentMethodTerms_(sheet, row, headers, paymentMethod) {
  if (!paymentMethod) return;
  var sName = sheet.getName();
  var mapKeyName = Object.keys(PAYMENT_METHOD_TERMS_COL_MAP).find(function(k) { return sName.indexOf(k) !== -1; });
  if (!mapKeyName) return;
  var colMap = PAYMENT_METHOD_TERMS_COL_MAP[mapKeyName];
  var methodMap = PaymentMethodRepository.findAsMap();
  var terms = methodMap[String(paymentMethod).trim()];
  if (!terms) return;

  var valueByKey = {
    決済ラグ月: terms.lagMonths,
    支払基準日: terms.baseDay,
    休日調整:   terms.holidayDir,
  };
  Object.keys(colMap).forEach(function(termKey) {
    var colName = colMap[termKey];
    var cIdx = headers.indexOf(colName);
    if (cIdx === -1) return;
    var cell = sheet.getRange(row, cIdx + 1);
    if (!cell.isBlank()) return; // 既存値は保護(S-48 補完済を含む)
    var v = valueByKey[termKey];
    if (v === '' || v == null || v === 0) return; // マスタ値が空/0 は転記しない(意図的に無設定の可能性)
    cell.setValue(v);
  });
}

③呼び出し位置:

  • 21_bud_pipeline / 23_bud_subscription / 26_bud_adhoc の各「取引先名」入力ブロック内、applyPartnerPaymentTerms_(...)直後に:
    var pmIdx = headers.indexOf('決済手段');
    if (pmIdx !== -1) {
      applyPaymentMethodTerms_(sheet, row, headers, sheet.getRange(row, pmIdx + 1).getValue());
    }
    
  • さらに「決済手段列が直接編集された場合」の分岐を新設(colName === '決済手段' && val):
    if (colName === '決済手段' && val) {
      applyPaymentMethodTerms_(sheet, row, headers, val);
    }
    
  • 32_wrk_invoice では既存のマスタ補完ブロック(L269-281 付近)に準じて、「決済手段」編集時に 決済日_計画 が空欄であれば RpaCommon.calcSettleDate(発生日YM, terms) を使って補完するオプション追加(人間が検討すべき事項)

Step 5: マイグレーションスクリプト(800_ops/812_migration_payment_method.js 新規)

関数名: migrationS63PaymentMethod()

function migrationS63PaymentMethod() {
  var FUNC = 'migrationS63PaymentMethod';
  Utils.auditLog('MIGRATE', '', '', '', FUNC, '', '', 'START');
  try {
    if (PaymentMethodRepository.resetCache) PaymentMethodRepository.resetCache();

    // 1. 32_wrk_invoice / 21_bud_pipeline / 23_bud_subscription / 26_bud_adhoc の
    //    「決済手段」列から実在値を収集 + 各決済手段ごとに
    //    (決済ラグ, 支払基準日, 休日調整) の最頻値を抽出
    //    (26_bud_adhoc は休日調整列なし → スキップ)
    // 2. PaymentMethodRepository.findAll() で既存 18_mst_payment_method を取得
    // 3. 集計結果をプレビューダイアログで表示
    //    「以下 N 件の決済手段をマスタに登録します。よろしいですか?」
    //    (Human-in-the-Loop: 承認された場合のみ書き込み)
    // 4. 承認後、未登録の決済手段のみ appendRow で追加(冪等性:同名行があればスキップ)
    //    既存行の値は一切上書きしない
    // 5. Utils.logInfo + SpreadsheetApp.getUi().alert でサマリ表示
  } catch (e) {
    Utils.logError(FUNC, e);
    SpreadsheetApp.getUi().alert('エラー', e.message, SpreadsheetApp.getUi().ButtonSet.OK);
  }
}

メニュー登録000_infra/002_constants.js L298-309 の MENU_DEFINITION の「📋 サイドバー: 🔧 マイグレーション」カテゴリの items 配列に、MAS-120 のエントリの直後に追加。101_sys_config.jsonOpen はこの配列を動的ループして生成するため、002_constants.js のみの編集で反映される):

{ label: 'S-63: 決済手段マスタ化', funcName: 'migrationS63PaymentMethod', description: 'S-63 既存データから決済手段別の最頻値をマスタに冪等投入' },

影響範囲

変更ファイル変更量内容
100_config/101_sys_config.js約 10 行MST_PMTM スキーマ 1 ブロック追加、confSheet.appendRow 1 行、inputCols 1 行、setVali 1 行
000_infra/003_contracts.js約 15 行PaymentMethodDTO @typedef 追加のみ
200_data/202_repository.js約 50 行PaymentMethodRepository の新設(_getSheet / findAll / findAsMap / _cache / resetCache
400_domain/400_rpa_common.js約 100 行resolveSettlementTerms + calcSettleDate の 2 ヘルパー追加
400_domain/402_rpa_subscription.js約 15 行(差し引き)L206-222 のインライン計算を RpaCommon.resolveSettlementTerms + calcSettleDate 呼び出しに置き換え
400_domain/405_rpa_adhoc.js約 10 行(差し引き)L94-101 を同様に置き換え
400_domain/406_rpa_pipeline.js約 10 行(差し引き)L155-164 の calcSettleDate インライン関数を共通ヘルパーに置き換え
300_ui/301_ui_assist.js約 60 行PAYMENT_METHOD_TERMS_COL_MAP + applyPaymentMethodTerms_ + 3-4 シートでの呼び出し追加(MAS-120 補完の直後・colName === '決済手段' 分岐)
000_infra/002_constants.js1 行MENU_DEFINITION の「🔧 マイグレーション」カテゴリに 1 エントリ追加
800_ops/812_migration_payment_method.js約 150 行(新規)プレビュー付き冪等 INSERT マイグレーション

既存動作への影響:

  • setupAllSchemas 実行後に 18_mst_payment_method シートが新規作成される(既存シートには影響なし)
  • MAS-120 の applyPartnerPaymentTerms_ は一切変更せず、そのに本案件の補完が走るため MAS-120 の挙動は不変
  • RPA 3 ファイルの決済日計算結果は、マスタ未整備時は従来と同じ値を返す必要がある(互換性保持)。マスタ整備後は休日調整が新たに効くようになる(挙動変化あり)
  • 32_wrk_invoice の既存行は変更しない(マイグレーションは 18_mst_payment_method への INSERT のみ)

注意事項

  1. onEdit 補完は「空欄のみ」を厳守 — ユーザーが手動設定した値を上書きしない。MAS-120 の applyPartnerPaymentTerms_ と同じく cell.isBlank() チェック必須
  2. フォールバック優先順位 (a)→(b)→(c) を全処理で徹底resolveSettlementTerms を単一の参照点とし、RPA・onEdit の両方が同じ関数を呼ぶことで実装の一貫性を担保
  3. MAS-120 との協調 — 本案件は MAS-120 の次段フォールバック。MAS-120 で取引先マスタから補完済の列は空欄にならないため、applyPaymentMethodTerms_ は自動的にスキップされる(正しい挙動)
  4. マスタキーは「決済手段名」の完全一致findAsMap() のキーは String(dto['決済手段名']).trim()。20 番台予算タブ・32_wrk_invoice の「決済手段」列の表記(例: JCB / 楽天カード)と完全一致している必要あり。表記ゆれは MAS-139(セル単位バリデーション)で防止する前提
  5. 「標準支払基準日 = 31」で月末を表現 — 動的に月末へ丸める(Math.min(baseDay, maxDay) ロジック)。末日指定を意味するフラグは別途持たない
  6. 休日調整の値域前営業日 / 当日 / 翌営業日 / 空 の 4 値のみ。空欄(または 当日)の場合は Utils.adjustToBusinessDay を呼ばない
  7. マイグレーションは冪等 + Human-in-the-Loop — プレビューダイアログで承認された場合のみ書き込み。2 回目実行では既存行を全スキップ
  8. Repository キャッシュは GAS 実行単位 — マイグレーション冒頭で PaymentMethodRepository.resetCache() を呼ばないと、直前の onEdit で読み込まれた古いマップが残る可能性あり(MAS-003 失敗例 #18)
  9. MAS-120 未作成の場合の設計 — 本案件では MAS-120 は実装完了済として扱う。仕様書の前提案件テーブルにも記載の通り、PartnerRepository.findPaymentTermsMap は既に利用可能な状態である。万が一 MAS-120 が dev 環境でのみ未反映の場合は try/catch で優先順位 (a) をスキップし (b) から始める設計にしている
  10. シート番号衝突の確認18_mst_payment_method は MAS-119(税率マスタ)が同じ 18 番を予約済。実装直前に MAS-119 実装状況を再確認し、必要なら 20〜25 の未使用番号に変更する

エッジケース

条件挙動理由
決済手段名がマスタ未登録自動補完スキップ、手入力値をそのまま尊重。RPA は従来どおり行の手入力値で計算マスタ強制でユーザー入力を破壊しない
標準支払基準日 = 31(月末)Math.min(31, maxDay) で末日に動的に丸める(例: 2月は 28/29、4月は 30)月によって末日が異なるため
休日調整方向が空欄Utils.adjustToBusinessDay を呼ばず調整なし未設定はユーザーの意図として尊重
標準決済ラグ(月) = 0当月決済。Utils.addMonths(ym, 0) は同月を返す即時・当月決済の表現
標準決済ラグ(月) が負値(-1 等)前払い扱い。発生月より前の月を Utils.addMonths で算出(MST_PART の -1〜12 バリデーションに合わせる)前払金取引への対応
「現金」決済手段ラグ=0 / 支払基準日=0(= 発生日と同日扱い、new Date(y, m, 0) は末日になるため基準日 0 は別処理要件化)/ 休日調整=空 で登録即時決済の慣習
「未定」決済手段マスタ登録しない(マイグレーション時のフィルタで除外)。RPA 402 L260 既存の .includes('未定') 分岐で空文字化される確定前状態はマスタ管理外
onEdit 時に補完対象セルに既存値あり上書きしない(cell.isBlank() チェックを先行)Human-in-the-Loop:ユーザー設定値を保護
マイグレーションスクリプト 2 回目実行同一「決済手段名」行をスキップ(冪等性)。プレビューダイアログの登録候補 0 件重複挿入による不整合防止
優先順位 (a) と (b) が両方存在するresolveSettlementTerms が (a) 取引先マスタ設定を優先して採用。source: 'partner' を返す取引先個別設定が最上位
優先順位 (a) が取引先マスタの一部項目のみ設定(a) で埋まらなかった項目のみ (b) から補完。1 行内で source 混在可部分補完を許容(MAS-120 設計と整合)
マスタ名の表記ゆれ(半角スペース・全角/半角).trim() で前後空白のみ吸収。内部空白・全角半角は区別厳密一致のほうが安全。MAS-139 バリデーションで入力時点で防ぐ
Utils.adjustToBusinessDaydirection 引数'後' → 翌営業日、それ以外 → 前営業日。本仕様書では 翌営業日'後'前営業日'前' を渡す既存ヘルパーの仕様に整合
複数マスタに同じ「決済手段名」が有効=TRUE で 2 行存在後勝ち(for ループ最後の行で上書き)。マイグレーションは新規 INSERT のため発生しない運用上発生すべきでない。Utils.logWarn で警告を出す
onEdit で決済手段列のみ編集・取引先名未入力applyPaymentMethodTerms_ のみ発火(applyPartnerPaymentTerms_ はスキップ)、決済手段マスタからの補完のみ実行決済手段単独でも補完が効く
RPA 実行中にマスタ未整備resolveSettlementTermstry/catch で (b) をスキップ、行個別値 (c) にフォールバック。既存 RPA と同じ結果段階導入時の互換性保持
決済手段マスタの「標準支払基準日」が "15" (文字列)Number() で数値化。NaN の場合は 0 として扱い月末計算へDDL で range バリデーション済だが防御的に数値化

実データ検証(実装前に必須)

仕様書記述時および実装前に、以下を MCP / GAS エディタで確認すること(失敗パターン #18-#20 の轍を踏まないため):

  1. 32_wrk_invoice の「決済手段」列の実データ — ユニーク値一覧(初期マスタ候補)。=UNIQUE(W:W) 等で取得し、JCB / 楽天カード / 銀行振込 / 口座振替 / 立替精算 / 現金 / 未定 以外の表記ゆれの有無を確認
  2. 21_bud_pipeline / 23_bud_subscription / 26_bud_adhoc の「決済手段」列 — 同様にユニーク値確認。20 番台タブは数十件〜数百件程度の想定
  3. 01_sys_configConstants.CONFIG_SHEET)のシステムキー命名規則MST_ACCT / MST_PART / MST_ORGN / MST_PROJ / MST_DICT 等の 8 文字以内が既定パターン。本案件の MST_PMTM もこれに準拠
  4. シート番号 18_mst_payment_method の衝突確認 — 以下の未実装スペックとの競合確認:
    • MAS-119(18_mst_tax_rate)— docs/dev/dev_mas-119_headcount_rate_master.md
    • MAS-121(19_mst_loan_pattern)— docs/dev/dev_mas-121_capex_master_ref.md
    • MAS-035(17_mst_intellectual)— 仕様書未作成 いずれかが先行実装されている場合は番号を再割り当て
  5. 既存 RPA の決済日計算の現在値 — 改修前後で結果が一致することを dev で確認するためのベースライン。代表 5〜10 件の settleDate を改修前に記録
  6. 12_mst_partner の「標準〜」列のデータ充足率 — MAS-120 マイグレーションで埋まった件数。空欄が多ければ (b) 決済手段マスタの利用頻度が高くなる
  7. 18_dropdown シートの名前付き範囲UI休日調整 / UI決済手段 が存在するか(MAS-140 で追加予定)。存在しなければ本案件では「文字列リスト直指定」で暫定対応し、MAS-140 完了後に名前付き範囲参照に切替
  8. Utils.getSheetByKey('MST_PMTM', '18_mst_payment_method') のフォールバック01_sys_config に MST_PMTM キーが登録される前の呼び出しで、物理名 '18_mst_payment_method' で解決できることを dev で確認

関連ドキュメント

仕様書関連箇所
dev_mas-120_partner_payment_terms_autofill.md前提案件。取引先マスタ 5 列拡張・PartnerRepository.findPaymentTermsMap の実装。本案件のフォールバック優先順位 (a) を提供
dev_mas-116_migration_framework.mdマイグレーション設計基盤(冪等性・Utils.auditLog・メニュー登録の統一パターン)。本案件 Step 5 の参考
dev_mas-119_headcount_rate_master.md未実装だが 18_mst_tax_rate シート番号を予約済。番号衝突の確認対象
dev_mas-121_capex_master_ref.md未実装だが 19_mst_loan_pattern シート番号を予約済。同上
dev_mas-085_consistency_check.md整合性チェック系仕様書のフォーマット参考
dev_mas-139_data_validation.mdセル単位バリデーション。決済手段列の表記ゆれをマスタ参照プルダウンで防ぐ前提
dev_mas-140_partner_payment_terms_polish.mdMAS-120 の後追い整備。UI休日調整 等の名前付き範囲追加。本案件のプルダウンソースを共用する
CLAUDE.mdコーディング規約・マイグレーション運用ガイドライン・800_ops 番号付け(次は 812)

人間が検討すべき事項

以下は TODO_future.md L244 の MAS-135 エントリで「人間が検討すべき事項」として列挙された項目をそのまま転記し、本仕様書での推奨回答を添えたもの:

検討事項(TODO_future.md 原文)本仕様書での推奨対応未確定事項
MAS-120(取引先マスタ標準決済条件)との優先順位設計(a) 取引先マスタ → (b) 決済手段マスタ → (c) 個別入力、で確定。resolveSettlementTerms が単一参照点
カード会社の締日が月中改定された場合の扱い(発生日ベース or 決済予定日ベースで切替)発生日ベースを推奨。マスタ更新時点以降の発生分に新締日が適用、既存行は手動更新または個別マイグレーションで対応発生日ベースか決済予定日ベースかを関係者と合意
「未定」「現金」等の決済手段の扱い(マスタ登録の要否)「未定」は登録しない(RPA 側で空文字化される)。「現金」は登録する(ラグ=0 / 基準日=0(当日)/ 休日調整=空)「現金」の基準日表現方式(0 を当日扱いにするか別フラグを設けるか)
既存 INV のマイグレーション粒度(全 INV バックフィル or 新規分のみ)新規分のみ(既存 INV は一切触らない)。マスタ整備後の新規起票から新ロジックが効く段階導入方式既存 INV のうち 決済日_計画 が空の行にバックフィルするか否か
本案件のシート番号(18 or 他)暫定 18_mst_payment_method。MAS-119 / MAS-121 の実装順と調整。必要なら 20_mst_payment_method へ変更MAS-119 / MAS-121 / MAS-035 との番号調整の最終決定
マイグレーション実行フローの承認方式プレビューダイアログ方式(登録候補一覧を表示 → OK 押下で書き込み)。Human-in-the-Loop 必須承認 UI の詳細(HTML モーダル vs シンプル alert)
onEdit の対象シートに 32_wrk_invoice を含めるか含めるが、INV には 決済ラグ(月) 等の列がないため「決済手段 → 決済日_計画 自動算出」のみ適用(オプション。デフォルト OFF が安全)INV での onEdit 補完を本案件スコープに含めるか、別案件に切り出すか
休日調整の値域(前営業日 / 当日 / 翌営業日 以外の選択肢要否)現状 3 値で十分。将来 T+2 決済等が必要になった段階で拡張

その他、実装着手前に関係者合意が必要な事項:

  • RPA 改修の後方互換性テスト — 改修前後で同じ入力に対して同じ settleDate が返ることを dev で 10 件以上の代表ケースで検証(マスタ未整備状態での互換性)
  • キャッシュ失効タイミング — マスタを手動編集した直後の onEdit では古いキャッシュを返す可能性。運用で許容するか、resetCache をメニュー化するか

実装プロンプト(Claude Code 用)

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-135「決済手段マスタの新設(決済条件マスタ化)」を実装してください。
5 Step に段階実装し、各 Step 完了後に dev で動作確認してから次へ進むこと。

## 実行前タスク(必ず Read すること)

- `docs/dev/dev_mas-135_payment_method_master.md` — 本仕様書の全文
- `docs/dev/dev_mas-120_partner_payment_terms_autofill.md` — 前提案件(実装完了済)の全文。本案件は MAS-120 の直接的な拡張
- `docs/_internal/failure_patterns.md` — 特に #18-#20(固有名詞の Read 確認原則)
- `100_config/101_sys_config.js`
  - L769-824 `confSheet.appendRow` のシステムキー登録パターン
  - L826-901 `schemas = { ... }` 辞書(MST_PART の validations が参考)
  - L1189-1190 `inputCols` 分岐
  - L1485-1486 `setVali` プルダウン検証ブロック
- `000_infra/003_contracts.js` — 既存 `@typedef` 書式(ファイル末尾)
- `200_data/202_repository.js`
  - L304-350 `AccountRepository` — キャッシュ付き Repository の参考
  - L356-406 `PartnerRepository` — MAS-120 で追加された直接の参考(同パターンを踏襲)
- `400_domain/400_rpa_common.js` — 末尾 `resolveDefault` の後に新ヘルパーを追加する
- `400_domain/402_rpa_subscription.js` L206-222 — 決済日計算のインライン箇所
- `400_domain/405_rpa_adhoc.js` L94-101 — 同上
- `400_domain/406_rpa_pipeline.js` L155-164 — `calcSettleDate` インライン関数
- `300_ui/301_ui_assist.js`
  - L18-22 `PARTNER_TERMS_COL_MAP`(本案件で `PAYMENT_METHOD_TERMS_COL_MAP` を同パターンで追加)
  - L42-66 `applyPartnerPaymentTerms_`(直後に `applyPaymentMethodTerms_` を追加)
  - L75 `validSheets` 配列
  - L137-161 / L333-359 取引先名入力時の補完ブロック(直後に本案件の呼び出しを追加)
- `800_ops/810_migration_partner_payment_terms.js` — MAS-120 マイグレーションの完成形。本案件 Step 5 の直接のテンプレート
- `000_infra/002_constants.js` L298-309 — `MENU_DEFINITION` の「📋 サイドバー: 🔧 マイグレーション」カテゴリ(メニュー追加先)
- `000_infra/004_utils.js` L389 `addMonths` / L430 `adjustToBusinessDay` — 決済日計算で呼び出すユーティリティ

## 修正対象ファイル

1. `100_config/101_sys_config.js` — DDL 追加(既存コードへの追記のみ)
2. `000_infra/003_contracts.js` — `PaymentMethodDTO` `@typedef` 追加
3. `200_data/202_repository.js` — `PaymentMethodRepository` 新規追加(末尾)
4. `400_domain/400_rpa_common.js` — `resolveSettlementTerms` + `calcSettleDate` 新設
5. `400_domain/402_rpa_subscription.js` L206-222 — インライン計算を共通ヘルパー呼び出しに置換
6. `400_domain/405_rpa_adhoc.js` L94-101 — 同上
7. `400_domain/406_rpa_pipeline.js` L155-164 — 同上
8. `300_ui/301_ui_assist.js` — `PAYMENT_METHOD_TERMS_COL_MAP` + `applyPaymentMethodTerms_` + 呼び出し追加
9. `000_infra/002_constants.js` L298-309 — マイグレーションメニューに 1 項目追加
10. `800_ops/812_migration_payment_method.js` — 新規ファイル作成

## 実装内容

### Step 1: DDL スキーマ追加

実行前タスク:
- `100_config/101_sys_config.js` L826-901 の `schemas` 辞書を Read し、MST_ORGN / MST_PART の記述位置と書式を確認
- `000_infra/002_constants.js` の `CONFIG_SHEET` 値(`'01_sys_config'`)を Read で確認

実装内容:
- L818 付近に `if (!existKeys.includes('MST_PMTM')) confSheet.appendRow(['MST_PMTM', '', '18_mst_payment_method', 'マスタ_決済手段/決済条件']);` を追加
- `schemas` 辞書に `'MST_PMTM'` エントリを追加(本仕様書「修正方針 Step 1」の②の通り)
- L1189-1190 の inputCols 分岐に `if (key === 'MST_PMTM') { inputCols = [1,2,3,4,5,6,7]; }` を追加
- `setVali` でプルダウン検証を追加(標準休日調整 列 6 → `UI休日調整` 参照 or 文字列リスト暫定)

制約:
- 既存シートへの影響なし(新規シート作成のみ)
- 既存スキーマ定義(MST_ACCT / MST_PART 等)は触らない
- シート番号 `18` が MAS-119 と衝突する場合は関係者に確認してから別番号に変更

動作確認:
- `npm run push:dev` → GAS で `setupAllSchemas` を実行 → `18_mst_payment_method` シート新規作成
- `01_sys_config` に `MST_PMTM` 行が追加されている
- サンプル 2-3 行を手入力(JCB / 楽天カード / 銀行振込 等)し、バリデーションがかかること

### Step 2: PaymentMethodRepository / DTO 新設

実行前タスク:
- `200_data/202_repository.js` L304-406 を Read し、AccountRepository / PartnerRepository のパターンを完全理解
- `000_infra/003_contracts.js` の末尾 `@typedef` 群の書式を確認

実装内容:
- `003_contracts.js` 末尾に `PaymentMethodDTO` `@typedef` を追加
- `202_repository.js` 末尾(`PartnerRepository` L406 の直後)に `PaymentMethodRepository` を追加(本仕様書「修正方針 Step 2」の②の通り。5 メンバ: `_getSheet / findAll / findAsMap / _cache / resetCache`)
- `901_test_runner.js` に `PaymentMethodRepository.findAll().dtos.length >= 0` の簡易テストを追加

制約:
- `AccountRepository` / `PartnerRepository` のキャッシュパターンを忠実に踏襲
- `findAsMap` のキーは「決済手段名」を `.trim()` した文字列
- 有効フラグ=FALSE の行は除外

動作確認:
- GAS で `PaymentMethodRepository.findAll()` を実行 → Step 1 で手入力したサンプルが DTO 配列で返る
- `PaymentMethodRepository.findAsMap()['JCB']` が `{ code, lagMonths, baseDay, holidayDir }` を返す
- `901_test_runner.js` の新テストが合格

### Step 3: 決済日計算ロジックの共通化

実行前タスク:
- `400_domain/400_rpa_common.js` 全体を Read(既存 RpaCommon 名前空間の構造を把握)
- `400_domain/402_rpa_subscription.js` L200-230 を Read し、インライン計算の前後関係を把握
- `400_domain/405_rpa_adhoc.js` L85-110 / `400_domain/406_rpa_pipeline.js` L150-170 を同様に Read
- `000_infra/004_utils.js` L389 `addMonths` / L430 `adjustToBusinessDay` の引数仕様を再確認

実装内容:
- `400_rpa_common.js` の `RpaCommon` オブジェクト末尾に `resolveSettlementTerms` / `calcSettleDate` を追加(本仕様書「修正方針 Step 3」の①の通り)
- 402_rpa_subscription.js L206-222 を以下に置換:
  `var terms = RpaCommon.resolveSettlementTerms(ptnName, payMethodStr, { lagMonths: lag, baseDay: payDay, holidayDir: /* 列値 */ });`
  `var settleDate = RpaCommon.calcSettleDate(curYm, terms);`
- 405_rpa_adhoc.js / 406_rpa_pipeline.js も同様に置換
- 既存の「全角数字→半角変換」「`[^\d.-]` 除去」は呼び出し側に残すか、`resolveSettlementTerms` の受け取り時に吸収するかは、失敗テストがあれば呼び出し側維持を選択

制約:
- **互換性テスト必須**: 改修前後で同じ入力に対して同じ `settleDate` が返ることを dev で 10 件以上検証(マスタ未整備の状態で)
- マスタに該当エントリがない場合は `(c)` 行個別値にフォールバックするよう `try/catch` で防御
- `Utils.adjustToBusinessDay` の `direction` 引数は `'後'` or その他。本仕様書では `'翌営業日'` → `'後'`、`'前営業日'` → `'前'` にマッピング

動作確認:
- `runAllTests` で既存テストが回帰していないこと
- RPA 3 種(SaaS / Adhoc / Pipeline)を dev で実行 → 生成された `決済日_計画` が改修前と一致
- マスタに JCB を 15 日/前営業日 で登録 → 23_bud_subscription に JCB サブスクを追加 → 生成される `決済日_計画` が 15 日(土日祝日なら前営業日)になる

### Step 4: onEdit 自動補完の追加

実行前タスク:
- `300_ui/301_ui_assist.js` L18-22 / L42-66 / L137-161 / L333-359 を Read
- MAS-120 の `applyPartnerPaymentTerms_` の動作を完全理解(空欄判定・既定値上書き判定)

実装内容:
- L22 の `PARTNER_TERMS_COL_MAP` 直後に `PAYMENT_METHOD_TERMS_COL_MAP` を定義(本仕様書「修正方針 Step 4」の①の通り)
- L66 の `applyPartnerPaymentTerms_` 直後に `applyPaymentMethodTerms_` を新設(本仕様書「修正方針 Step 4」の②の通り)
- 各シートの取引先名入力ブロック(L139 / L335 / L356)に `applyPaymentMethodTerms_` の呼び出しを追加
- 各シートで新たに `colName === '決済手段' && val` 分岐を追加し、決済手段が直接編集された場合も補完

制約:
- **空欄のみ補完**(`cell.isBlank()` チェック必須)。MAS-120 で補完された値を上書きしない
- マスタ未登録の決済手段は何もしない(`return` 早期)
- `26_bud_adhoc` は休日調整列がないため `indexOf === -1` で自動スキップ
- `32_wrk_invoice` での onEdit 補完は、まず **OFF** でリリース(人間検討事項)

動作確認:
- マスタに JCB(ラグ=1 / 基準日=25 / 休日調整=前営業日)を登録
- 23_bud_subscription で新規行を作成 → 取引先名 "未マスタの取引先" を入力 → 決済手段 "JCB" を入力
- 決済ラグ(月)=1 / 支払基準日=25 / 休日調整=前営業日 が自動セット
- 既に決済ラグ(月)=2 が入っている行で決済手段を "JCB" に変更 → 2 が維持されること(上書きしない)
- MAS-120 登録済み取引先(標準決済手段=楽天カード)を入力 → applyPartnerPaymentTerms_ が先に発火 → applyPaymentMethodTerms_ は空欄がなくスキップされる

### Step 5: マイグレーションスクリプト

実行前タスク:
- `800_ops/810_migration_partner_payment_terms.js` 全体を Read(最頻値集計・冪等性保証の完成形)
- `000_infra/002_constants.js` L298-309 を Read(メニュー追加先の配列構造)

実装内容:
- `800_ops/812_migration_payment_method.js` を新規作成
- 関数名: `migrationS63PaymentMethod`
- 冒頭で `PaymentMethodRepository.resetCache()` + `Utils.auditLog('MIGRATE', ..., 'START')`
- 32_wrk_invoice / 21_bud_pipeline / 23_bud_subscription / 26_bud_adhoc の「決済手段」列から実値を収集
- 各決済手段ごとに (決済ラグ・支払基準日・休日調整) の最頻値を抽出(`810_migration_partner_payment_terms.js` の集計ロジックを流用)
- プレビュー文字列を組み立て → `SpreadsheetApp.getUi().alert(title, body, ButtonSet.YES_NO)` で承認
- 承認後、`PaymentMethodRepository.findAll()` の既存 `決済手段名` を取得して、**未登録の手段のみ appendRow**
- `Utils.logInfo` + サマリ alert + `Utils.auditLog('MIGRATE', ..., 'END')`
- `000_infra/002_constants.js` の `MENU_DEFINITION` の「🔧 マイグレーション」カテゴリ(L302-307 の items 配列)、MAS-120 エントリの直後に 1 行追加:
  `{ label: 'S-63: 決済手段マスタ化', funcName: 'migrationS63PaymentMethod', description: 'S-63 既存データから決済手段別の最頻値をマスタに冪等投入' },`

制約:
- **冪等性必須** — 2 回目実行で登録候補 0 件になること
- **Human-in-the-Loop** — 承認ダイアログで YES を押さない限り書き込まない
- 「未定」「選定中」を含む決済手段名はマイグレーション対象外(集計時点でフィルタ)
- `PaymentMethodRepository.resetCache()` は冒頭必須(MAS-003 失敗例回避)

動作確認:
- dev でマイグレーション実行 → プレビュー表示 → YES で書き込み → サマリ alert
- 再度実行 → 登録候補 0 件のサマリ
- `18_mst_payment_method` シートで登録された内容を目視確認 → 不適切な値があれば手動で修正または無効化

## 制約(全 Step 共通)

- 列参照はヘッダー名ベース(`indexOf`)。列番号ハードコード禁止
- 既存 Repository(OrderRepository / InvoiceRepository / AccountRepository / PartnerRepository 等)には触らない
- MAS-120 の既存ロジック(`applyPartnerPaymentTerms_` / `PartnerRepository.findPaymentTermsMap` / `810_migration_partner_payment_terms.js`)は一切変更しない(本案件は後続レイヤーとして追加のみ)
- `setupAllSchemas` で MST_PMTM の既存データがクリアされないことを dev で事前確認
- **onEdit での既存値上書き禁止**(`cell.isBlank()` 必須)
- **マイグレーションの冪等性必須**(2 回目で書き込み 0 件)

## 動作確認フロー(統合テスト)

1. `setupAllSchemas` 実行 → `18_mst_payment_method` 生成、`01_sys_config` に MST_PMTM 登録
2. マスタに 5 件サンプル登録(JCB / 楽天カード / 銀行振込 / 口座振替 / 現金)
3. 23_bud_subscription で新規行 → 決済手段="JCB" 入力 → 決済ラグ/支払基準日/休日調整が JCB マスタ値に
4. 既に決済ラグ=2 の行で決済手段=JCB に変更 → 上書きされない(手動値保護)
5. MAS-120 設定済み取引先(取引先マスタに標準決済手段=楽天カード あり)の取引先名を入力 → 優先順位 (a) が効いて楽天カード補完
6. マスタ未登録の決済手段("PayPay" 等)を入力 → 何も補完されない
7. RPA `generateSaasInvoices` を実行 → 生成された `決済日_計画` に休日調整が効いていること
8. `migrationS63PaymentMethod` を実行 → プレビュー → YES → サマリ
9. 再実行 → 0 件サマリ(冪等性確認)
10. `runAllTests` で全テスト PASS
11. prod 環境にデプロイ前: CLAUDE.md の「変更時の動作確認テスト」に従い RPA テスト・マート更新テストを実施

### 拡張思考の使用状況

| フェーズ | 拡張思考 | 備考 |
|---------|:--------:|------|
| Step 1 DDL 追加 | なし | 既存 schemas 辞書へのエントリ追記・inputCols・setVali の 1 行ずつ追加 |
| Step 2 Repository 新設 | なし | AccountRepository / PartnerRepository パターンのコピー改変 |
| Step 3 決済日計算改修 | あり | 3 ファイルのインライン計算の抽出、フォールバック優先順位設計、互換性テスト |
| Step 4 onEdit 拡張 | あり | MAS-120 との呼び出し順序、決済手段列編集分岐の追加位置 |
| Step 5 マイグレーション | あり | 冪等性保証・プレビュー UI・最頻値集計・未登録フィルタ |

推奨実行モデル

工程推奨モデル理由
Step 1: DDL スキーマ追加Claude Haiku 4.5既存 MST_PART / MST_ORGN の記述位置に 1 ブロック追記。判断要素少
Step 2: PaymentMethodRepository 新設Claude Haiku 4.5AccountRepository / PartnerRepository のコピー改変でコード完全定義可能
Step 3: 決済日計算改修Claude Opus 4.63 ファイル横断の抽出・優先順位フォールバック設計・互換性担保。設計判断が多い
Step 4: onEdit 拡張Claude Sonnet 4.6MAS-120 の直後パターンで機械的だが、呼び出し位置と colName === '決済手段' 分岐追加の判断あり
Step 5: マイグレーションClaude Sonnet 4.6810_migration_partner_payment_terms.js のテンプレート流用。プレビューダイアログ制御のみ新規設計

変更履歴

日付変更内容
2026-04-22初版作成。決済手段マスタ 18_mst_payment_method の DDL 設計・PaymentMethodRepository 新設・共通決済日計算ヘルパー RpaCommon.resolveSettlementTerms / calcSettleDate への集約・onEdit 補完の 2 段フォールバック拡張・冪等マイグレーションの 5 ステップ設計

仕様書作成プロンプト

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

======================================================================
あなたはGAS会計システムのシニア開発者兼仕様書ライターです。
案件 MAS-135「決済手段マスタの新設(決済条件マスタ化)」の開発仕様書を作成してください。
作成後は `docs/_config.json` の `nav` 配列の適切なセクションに必ず追記してください。

---

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

以下のファイルを順に Read/Grep し、Phase 2 で設計判断を再考しないよう全情報を確定させること。
**Grep は「どこにあるか」の発見まで。「どう書くか」の判断は必ず Read で裏取りしてから行う。推測で書かない。**

### 1-A: 案件要件の取得
- `docs/_internal/TODO_future.md` を Read し、MAS-135「決済手段マスタの新設」の概要・人間が検討すべき事項を取得する

### 1-B: プロジェクト規約の確認
- `CLAUDE.md` を Read し、マイグレーション番号ルール(804-808 使用済み・次は 809 から)・ファイル命名規則(`8XX_migration_*.js`)・コーディング規約を確認する

### 1-C: 仕様書テンプレートの参照
- `docs/dev/dev_mas-085_consistency_check.md` を Read し、整合性チェック系の仕様書フォーマットを把握(参考)
- `docs/dev/dev_mas-120_partner_payment_terms_autofill.md` について: まず `ls docs/dev/` で存在を確認してから Read する。ファイルが存在しない場合はスキップし、仕様書の注意事項に「MAS-120 仕様書未作成のため取引先マスタ連携設計は要確認」と記載する

### 1-D: 関連コードの調査(Grep → Read の順を守ること)

#### 1-D-1: 決済手段・決済日計算ロジックの特定
1. `Grep "決済手段" --include="*.js"` でヒットファイルと行番号を列挙する
2. `Grep "adjustToBusinessDay\|決済日\|calcPayment\|paymentDate" --include="*.js"` で決済日計算ヘルパー関数の所在を特定する
3. ヒットしたファイルを Read し、関数名・行番号・引数・呼び出し元を確定する
   - `Utils.adjustToBusinessDay(ymdStr, direction)` は `000_infra/004_utils.js` に実在。`direction='後'` → 翌営業日方向に丸め、それ以外 → 前営業日方向に丸め
   - `Utils.addMonths(ymStr, months)` は `000_infra/004_utils.js` に実在。戻り値は "YYYY-MM" 形式
   - 上記以外に決済日を計算するカスタムヘルパーが存在する場合はファイル名・関数名・行番号を確定する
   - 見つからない場合は「要調査: 決済日計算ヘルパーの所在未確定」として仕様書の注意事項に明記する

#### 1-D-2: DDL スキーマ定義パターンの把握
- `100_config/101_sys_config.js` を Read し、`setupAllSchemas` 内の既存マスタ(`11_mst_account` または `12_mst_partner`)の DDL 定義の実際の構造・列定義フォーマット・`Constants.CONFIG_SHEET`(値: `'01_sys_config'`)へのシステムキー登録方式を確認する
- 既存シート番号の一覧を確認し、`18_mst_payment_method` というシート番号が重複しないことを確かめる

#### 1-D-3: onEdit ハンドラの所在確認
1. `Grep "function onEdit\|onEdit_\|handleOnEdit" --include="*.js"` でハンドラの実在ファイル・行番号を特定する(`300_ui/301_ui_assist.js` または `100_config/101_sys_config.js` にある可能性が高いが、必ず Grep 結果で確認すること)
2. ヒットしたファイルを Read し、ハンドラ構造(シート名判定 → 列名判定 → 処理)を把握する
3. `21_bud_pipeline` / `23_bud_subscription` / `32_wrk_invoice` の「決済手段」列がハンドラの処理対象として既に扱われているか確認する(`000_infra/002_constants.js` の `SHEET_DEFAULTS` には `21_bud_pipeline` に `'決済手段': ''`、`23_bud_subscription` に `'決済手段': '未定'` が存在することは確認済みだが、実際の DDL 列定義も Read で確認すること)

#### 1-D-4: Repository パターンの把握
- `200_data/202_repository.js` を Read し、`AccountRepository` の実装(`findAll` / `findAsMap` / `_cache` / `resetCache`)を把握する。`PaymentMethodRepository` の設計ベースとして使用する
- `Utils.getSheetByKey(key, fallbackName)` の呼び出しパターンを確認する(key は `01_sys_config` に登録するシステムキー。例: `MST_ACCT` → `11_mst_account`)
- `readSheetAsDtos_` / `appendDtosToSheet_` 等のファイル内共通ヘルパーが存在することを確認する

#### 1-D-5: 既存マイグレーションスクリプトの確認
1. `ls 800_ops/` で使用済み番号の一覧を確認し、次の空き番号(CLAUDE.md では 809 から)を確定する
2. 最新番号のスクリプトを Read し、冪等性確保パターン(既存行チェック → スキップ)・`Utils.logInfo` と `SpreadsheetApp.getUi().alert` / `showModalDialog` の使い方を把握する
3. `docs/dev/dev_mas-116_migration_framework.md` を Read し、マイグレーション設計基盤の制約を把握する

### 1-E: Phase 2 着手前の確定チェックリスト(全て確定してから Phase 2 へ進むこと)
- [ ] 新マスタシート名: `18_mst_payment_method`(番号重複なし確認済み)
- [ ] 新マスタ列定義: 決済手段コード / 決済手段名 / 標準決済ラグ(月) / 標準支払基準日 / 休日調整方向 / 備考
- [ ] 新システムキー: 1-D-2 で命名規則を確認して決定(暫定案: `MST_PMTM`)
- [ ] `PaymentMethodRepository` 追加先: `200_data/202_repository.js`
- [ ] 決済日計算ヘルパーの関数名・ファイル名・行番号: 1-D-1 で確定
- [ ] onEdit ハンドラのファイル名・行番号: 1-D-3 で確定
- [ ] onEdit 拡張対象シート: `21_bud_pipeline` / `23_bud_subscription` / `32_wrk_invoice`(1-D-3 で実在確認済みのもの)
- [ ] マイグレーションスクリプトのファイル番号: 1-D-5 で確定(809〜次の空き番号)
- [ ] 取引先連携の優先順位: (a) 取引先マスタ(MAS-120 設定) → (b) 決済手段マスタ(本件) → (c) 個別手入力値

---

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

出力先: `docs/dev/dev_mas-135_payment_method_master.md`
**1 回の Write/Edit で全内容を出力しない。以下 5 Step に厳密に分割実行すること。**

### Step 2-1: 骨格の作成(Write, ~20行)
以下の見出しのみを書く。本文は空でよい:

    # MAS-135: 決済手段マスタの新設(決済条件マスタ化)
    ## 概要
    ## 目的
    ## 現在のコード
    ## 修正方針
    ## 影響範囲
    ## 注意事項
    ## エッジケース
    ## 実データ検証
    ## 関連ドキュメント
    ## 人間が検討すべき事項
    ## 実装プロンプト(Claude Code 用)
    ## 推奨実行モデル
    ## 変更履歴
    ## 仕様書作成プロンプト

### Step 2-2: 概要〜注意事項の追記(Edit または Bash heredoc, ~300行)
**Phase 1 で確定した実在の関数名・行番号・ファイルパスのみ使うこと。推測で書かない。**

書く内容:
- **概要テーブル**: 案件ID=MAS-135, カテゴリ=マスタ整備, 対象ファイル=(Phase 1 で特定した全ファイル), 前提案件=MAS-120(未作成の場合はその旨を記載)
- **目的**: 決済手段ごとの決済条件(ラグ・支払基準日・休日調整)をマスタ管理し、手入力による設定不整合を解消する
- **現在のコード**: 1-D-1 で特定した決済日計算ロジックのコードスニペット(ファイル名 + 行番号を明記)。特定できなかった場合は「現状: 決済日計算ヘルパーの所在が未確定(要調査)」と記載する
- **修正方針**(5 Step に分割して記述):
  - **Step 1: DDL スキーマ追加** — `100_config/101_sys_config.js` の `setupAllSchemas` に `18_mst_payment_method` のスキーマを追加(1-D-2 で確認した実際のフォーマットに準拠)。`Constants.CONFIG_SHEET`(値: `'01_sys_config'`)へのシステムキー登録(キー名: 1-E で確定した値)も含む
  - **Step 2: PaymentMethodRepository の新設** — `200_data/202_repository.js` に `AccountRepository` の構造(`findAll / findAsMap / _cache / resetCache`)を踏襲して追加。内部ヘルパー `readSheetAsDtos_` を再利用。`findAsMap()` のキーは「決済手段名」、値は `{ lag: number, baseDay: string, holidayDir: string }`。`Utils.getSheetByKey(システムキー, '18_mst_payment_method')` で取得
  - **Step 3: 決済日計算ロジックの改修** — 1-D-1 で特定したヘルパー関数(ファイル名・行番号を明記)に優先順位フォールバック `(a) 取引先マスタ(S-48) → (b) PaymentMethodRepository.findAsMap()[決済手段名] → (c) 個別手入力値` を追加。`Utils.addMonths(ymStr, months)` と `Utils.adjustToBusinessDay(ymdStr, direction)` を再利用(既存の呼び出し箇所との互換性を維持すること)
  - **Step 4: onEdit 自動補完の追加** — 1-D-3 で特定したハンドラ(ファイル名・行番号を明記)に、「決済手段」列選択 かつ 対象セルが空 の場合のみ `PaymentMethodRepository.findAsMap()` から補完するロジックを追加。対象シート: `21_bud_pipeline` / `23_bud_subscription` / `32_wrk_invoice`(1-D-3 で実在確認済みのもの)。取引先マスタ(MAS-120)に設定がある場合は補完をスキップ
  - **Step 5: マイグレーションスクリプト** — `800_ops/{次の空き番号}_migration_s63_payment_method.js` を新規作成。冪等性必須(同一「決済手段名」が `18_mst_payment_method` に既存行として存在する場合はスキップ)。`32_wrk_invoice` 等の「決済手段」列から最頻値を集計 → `SpreadsheetApp.getUi().alert` でプレビューをダイアログ表示 → 人間が確認・承認した場合のみシートへ書き込む
- **影響範囲**: 変更ファイルと各ファイルの追加行数見積もり
- **注意事項**:
  - onEdit での自動補完は対象セルが空の場合のみ実行し、ユーザーが手動設定した値を上書きしない
  - フォールバック優先順位 (a)→(b)→(c) を全処理で徹底すること
  - MAS-120 が未作成の場合、優先順位 (a) の取引先マスタ連携は本案件スコープ外とする(人間が検討すべき事項で確認)
  - `18_mst_payment_method` への直接書き込みは `setupAllSchemas` 実行後のみ有効

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

**エッジケーステーブル**(| 条件 | 挙動 | 理由 | 形式で全観点を網羅):

| 条件 | 挙動 | 理由 |
|------|------|------|
| 決済手段名がマスタ未登録 | 自動補完スキップ、手入力値をそのまま尊重 | マスタ強制でユーザー入力を破壊しない |
| 標準支払基準日 = "月末" | `new Date(y, m, 0).getDate()` で末日を動的計算 | 月によって末日が異なるため |
| 休日調整方向が空欄 | `Utils.adjustToBusinessDay` を呼ばず調整なし | 未設定はユーザーの意図として尊重 |
| 標準決済ラグ(月) = 0 | 当月決済(`Utils.addMonths(ym, 0)` は同月を返す) | 即時・当月決済の表現 |
| 標準決済ラグ(月) が負値 | DDL バリデーションでエラー。マスタ登録時に弾く | 遡及決済は仕様外の異常系 |
| 「現金」決済手段 | ラグ=0・支払基準日="当日"・休日調整方向=空でマスタ登録 | 即時決済の慣習 |
| 「未定」決済手段 | マスタ登録しない。ユーザー手入力に委ねる | 確定前状態はマスタ管理外 |
| onEdit 時に補完対象セルに既存値あり | 上書きしない(空セル判定を先行) | Human-in-the-Loop。ユーザー設定値を保護 |
| マイグレーションスクリプト 2 回目実行 | 同一「決済手段名」行をスキップ(冪等性) | 重複挿入による不整合防止 |
| 優先順位 (a) と (b) が両方存在する | (a) 取引先マスタ設定を優先して適用 | 取引先個別設定が最上位 |

**実データ検証**(実装前に MCP またはシート直読みで確認すべき項目):
- `32_wrk_invoice` の「決済手段」列に存在する実データのユニーク値(初期マスタデータの候補)
- `21_bud_pipeline` / `23_bud_subscription` の「決済手段」列の実在確認とユニーク値
- `01_sys_config`(`Constants.CONFIG_SHEET`)のシステムキー命名規則(`MST_ACCT` / `MST_PART` 等の形式から本件キー名を最終決定)
- `18_mst_payment_method` というシート番号が既存シートと重複しないことの最終確認

**関連ドキュメント**(テーブル形式):
- `docs/dev/dev_mas-120_partner_payment_terms_autofill.md`(存在する場合) — 取引先への決済条件自動補完(優先順位 (a) の前提)
- `docs/dev/dev_mas-116_migration_framework.md` — マイグレーション設計基盤

**人間が検討すべき事項**:
- TODO_future.md の MAS-135 記載事項をそのまま転記する
- マイグレーション実行フローの承認方式: プレビューダイアログ → 人間が「OK」を押した場合のみ書き込みを実行(Human-in-the-Loop 必須)
- `18` というシート番号が既存シートと衝突しないか(1-D-2 で調査済みの場合は結果を記載)
- MAS-120 が未実装の場合、優先順位 (a) の取引先マスタ連携を本案件スコープに含めるかどうかの判断

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

書く内容:

- **実装プロンプト(Claude Code 用)**: 行頭 4 スペースインデント形式(バッククォートで囲まない)で、Step 1〜5 それぞれの実装プロンプトを記載する。各 Step に「実行前タスク」(読むべきファイルと確認ポイント)・「修正対象ファイル」・「実装内容」・「制約」・「動作確認」を含める。「制約」に「onEdit での既存値上書き禁止」「マイグレーションの冪等性必須」を再掲する

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

| 工程 | 推奨モデル | 理由 |
|------|-----------|------|
| Step 1: DDL スキーマ追加 | Claude Haiku 4.5 | 既存パターンの横展開。判断要素少 |
| Step 2: Repository 新設 | Claude Haiku 4.5 | AccountRepository パターンのコピー改変。コード完全定義可 |
| Step 3: 決済日計算改修 | Claude Sonnet 4.6 | 既存ヘルパーの特定と優先順位フォールバック追加 |
| Step 4: onEdit 拡張 | Claude Sonnet 4.6 | 複数シートへの条件分岐追加。既存ハンドラ構造の理解が必要 |
| Step 5: マイグレーション | Claude Sonnet 4.6 | 冪等性・最頻値集計・ダイアログ制御の設計判断 |

- **変更履歴**テーブル:

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

### Step 2-4: 仕様書作成プロンプトの記録(Edit または Bash)
最重量工程のため必ず独立した Step で実行すること。仕様書末尾の `## 仕様書作成プロンプト` セクションに以下を追記する:

    <details><summary>展開して表示</summary>

    (この <instruction> タグの全文をそのまま記録)

    </details>

---

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

### 3-A: `docs/_config.json` への登録(必須)
`nav` 配列の §E.2(バグ修正・バリデーション・マスタ整備)に追記:
```json
{ "file": "dev/dev_mas-135_payment_method_master.md", "title": "E.2.XX S-63 決済手段マスタの新設" }
```
追記後に JSON 構文チェックを実行する:
```bash
node -e "require('./docs/_config.json')" && echo "OK"
```

### 3-B: `docs/_internal/changelog.md` への追記
ヘッダー直後の先頭行に追記:
```
| 2026-04-20 | [dev_mas-135_payment_method_master.md](dev_mas-135_payment_method_master.md) | 初版作成。決済手段マスタ新設(S-63)の開発仕様書 |
```

### 3-C: コミット&プッシュ
```bash
git add docs/dev/dev_mas-135_payment_method_master.md docs/_internal/changelog.md docs/_config.json
git commit -m "docs: S-63 決済手段マスタ新設の開発仕様書を作成

18_mst_payment_method の DDL設計・PaymentMethodRepository 新設・
決済日計算改修・onEdit 拡張・マイグレーション方針を定義。

https://claude.ai/code/session_XXXXX"
git push -u origin $(git rev-parse --abbrev-ref HEAD)
```
</instruction>