MENU

【コピペで解決】GASエラーに悩むのはもう終わり!Claudeを使ったデバッグ術完全ガイド

「GASのエラーで1時間も溶かした…」

そんな経験ありませんか?実は、AIチャットツール「Claude」を使えば、複雑なGoogle Apps Script(GAS)のコードエラーもたった数分で解決できます。
この記事では、ChatGPTやGeminiで挫折した方でも、画面を見ながらマネするだけでGASのエラーを解消できる方法を、実際のスクリーンショット付きで徹底解説します。

目次

この記事で得られること

  • ✅ 1時間かかっていたGASのエラー修正が数分で終わる方法
  • ✅ ChatGPTやGeminiよりGAS対応が得意なAIがわかる
  • ✅ エラーが出ているコードをコピペで修正する具体的な手順

目次

  1. はじめに:なぜGASのエラー解消にClaudeが最適なのか?
  2. ステップ1:エラーが出ているGASコードを準備する
  3. ステップ2:Claudeにエラー解消を依頼する
  4. ステップ3:Claudeが提案したコードに差し替える
  5. 【特典】プロンプト&GASコードのプレゼント
  6. まとめ

はじめに:なぜGASのエラー解消にClaudeが最適なのか?

Google Apps Script(GAS)は、Googleの各種サービスを自動化できる非常に強力なツールですが、プログラミング初心者にとってはエラーの解消(デバッグ)が大きな壁となります。

ChatGPTやGeminiなど、多くのAIがコード作成を支援してくれますが、GASのような特定の分野では、AIによって得意・不得意があります。動画で解説されている通り、2026年3月現在、GASのコード生成やエラー修正においては「Claude」が圧倒的に高い性能を発揮します。

💡 ポイント
ChatGPTやGeminiでうまくいかなかったエラーも、Claudeに同じ質問をするだけで一発で解決することがよくあります。まずはClaudeを試してみるのが、エラー解消への一番の近道です。

この記事では、すでにあるGASコードのエラーをClaudeを使って解消する方法を3ステップで解説します。

ステップ1:エラーが出ているGASコードを準備する

まずは、エラーが発生しているGASのコードを用意します。今回は例として、請求書を自動で作成・送付するシステムのコードを使用します。

1-1. Apps Scriptを開く

Googleスプレッドシートの「拡張機能」メニューから「Apps Script」を選択し、GASエディタを開きます。

Apps Scriptを開く画面
▲ スプレッドシートの「拡張機能」>「Apps Script」をクリック

1-2. コードをすべてコピーする

GASエディタに表示されているコードを、すべて選択してコピーします。キーボードのCtrl + A(Macの場合は Cmd + A)で全選択し、Ctrl + C(Macの場合は Cmd + C)でコピーすると簡単です。

GASコードを全選択してコピーする画面
▲ コードエディタ内をクリックし、Ctrl+A (Cmd+A)ですべて選択してからコピーします

ステップ2:Claudeにエラー解消を依頼する

次に、コピーしたコードをClaudeに貼り付けて、エラーの解消を依頼します。

2-1. Claudeを開き、モデルを選択する

Claudeの公式サイトにアクセスします。無料プランで利用できる、高性能な「Sonnet 4.6」モデルが選択されていることを確認してください。有料プランに加入している場合は、さらに強力な「Opus 4.6」も利用できます。

Claudeのモデル選択画面
▲ 無料プランでも高性能な「Sonnet 4.6」が利用できます

2-2. プロンプトとコードを貼り付ける

以下のプロンプト(AIへの指示文)を入力し、その下に先ほどコピーしたGASコードを貼り付けて送信します。

このGASの内容を理解して

プロンプトとGASコードを貼り付けた画面
▲ 指示文に続けて、先ほどコピーしたコードを貼り付けて送信します

2-3. Claudeの分析結果を確認する

送信すると、Claudeがコードの全体像を分析し、どのような機能を持つGASなのかを解説してくれます。この時点で、Claudeはコードの構造を完全に理解しています。

ClaudeがGASの概要を説明する画面
▲ まずはコードの概要を理解させます。シート構成や主な機能が整理されていればOKです

2-4. エラー内容を伝えて修正を依頼する

次に、実際に発生しているエラーの内容を伝えて、コードの修正を依頼します。もしエラーメッセージが出ている場合は、それをそのまま貼り付けるのが最も効果的です。

今回は、エラー修正だけでなく「複数社一括対応」という機能追加もあわせて依頼する例を見てみましょう。

エラーが出ているので修正したいです。

また、追加で「複数社一括対応」をやりたいです。

このように、やりたいことを具体的に伝えることで、Claudeは対話形式で必要な情報をヒアリングし、最適なコードを提案してくれます。

Claudeが追加機能についてヒアリングする画面
▲ 「複数社一括対応」という曖昧な依頼に対し、Claudeが具体的な仕様を確認してくれます

ユーザーが質問に答えると、Claudeは要件を整理し、実装する機能のリストを提示した上で、コード生成を開始します。

Claudeが要件を整理し実装を開始する画面
▲ ユーザーの回答をもとに、実装する機能を3点にまとめてくれました


ステップ3:Claudeが提案したコードに差し替える

最後に、Claudeが生成した修正済みのコードをコピーし、元のGASエディタに貼り付けます。

3-1. 生成されたコードをコピーする

Claudeが生成したコードブロックの右上にあるコピーボタンをクリックして、コード全体をコピーします。

Claudeが生成したコード
▲ Claudeが元のコードを修正し、新機能を追加したコードを生成してくれます

3-2. GASエディタに貼り付ける

元のGASエディタに戻り、既存のコードをすべて削除してから、コピーした新しいコードを貼り付けます。これでエラーの修正と機能追加は完了です。

修正後のコードをGASエディタに貼り付けた画面
▲ 元のコードをすべて削除し、Claudeが生成した新しいコードに差し替えます

⚠️ 注意
コードを差し替えた後は、必ず「保存」ボタン(フロッピーディスクのアイコン)をクリックしてください。保存しないと変更が反映されません。


【特典】プロンプト&GASコードのプレゼント

今回、動画内で使用されたプロンプトと、実際にClaudeが生成した修正後のGASコードをプレゼントします。

以下のリンクからダウンロードして、ご自身の環境で試してみてください。ただし、コピー&ペーストして動かすだけでなく、「なぜこのコードで動くのか?」を考えながら、答え合わせとして活用することが、スキルアップへの一番の近道です。

追加コード↓

// ============================================================
// 請求書自動発行 GAS【月次定期請求・ログ・リトライ拡張】
// NEXT INNOVAITION株式会社
// ============================================================
//
// 【既存コードに追記する内容】
// ① 定期請求マスタシート(新規追加)
// ② 送信ログシート(新規追加)
// ③ 月次定期請求データ自動生成
// ④ 毎月指定日に自動実行するトリガー設定
// ⑤ 送信失敗時リトライ機能
//
// 【追加シート】
// ・定期請求マスタ:毎月自動生成する請求先の雛形
// ・送信ログ:全送信結果の記録
// ============================================================

// ----- 追加定数 -----
const SHEET_RECURRING_MASTER = '定期請求マスタ';
const SHEET_SEND_LOG = '送信ログ';
const MAX_RETRY_COUNT = 3;          // 最大リトライ回数
const RETRY_INTERVAL_MINUTES = 10;  // リトライ間隔(分)

// ============================================================
// onOpen に追記するメニュー項目(既存の onOpen に追加してください)
// ============================================================
// 既存の onOpen() 内の createMenu チェーンに以下を追加:
//
//   .addSeparator()
//   .addItem('📅 定期請求マスタ初期化', 'initRecurringMaster')
//   .addItem('🔄 今月の定期請求データを生成', 'generateMonthlyInvoices')
//   .addItem('🚀 月次一括送信(生成+送信)', 'runMonthlyBatch')
//   .addItem('⚙️ 月次自動実行トリガーを設定', 'setupMonthlyTrigger')
//   .addItem('🗑️ 月次トリガーを削除', 'deleteMonthlyTrigger')
//   .addItem('🔁 失敗分をリトライ送信', 'retryFailedInvoices')

// ============================================================
// ① 定期請求マスタシートの初期化
// ============================================================
function initRecurringMaster() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(SHEET_RECURRING_MASTER);
  if (!sheet) {
    sheet = ss.insertSheet(SHEET_RECURRING_MASTER);
  }

  const headers = [
    '有効', '宛先会社名', '宛先敬称', '宛先代表者名', '宛先代表者敬称',
    '件名', '支払期限オフセット(日)',
    '摘要1', '数量1', '単位1', '単価1',
    '摘要2', '数量2', '単位2', '単価2',
    '摘要3', '数量3', '単位3', '単価3',
    '摘要4', '数量4', '単位4', '単価4',
    '摘要5', '数量5', '単位5', '単価5',
    '備考', '送信先メールアドレス'
  ];

  sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
  sheet.getRange(1, 1, 1, headers.length)
    .setFontWeight('bold').setBackground('#4472C4').setFontColor('white');
  sheet.setFrozenRows(1);
  sheet.setColumnWidth(1, 50);
  sheet.setColumnWidth(2, 200);
  sheet.setColumnWidth(7, 180);

  // サンプルデータ
  const sample = [
    true,
    'デジタルアスリート株式会社', '御中', '', '様',
    'AI顧問(コンサルティング)費用',
    30,  // 請求日から30日後を支払期限にする
    'AI顧問(コンサルティング)費用', 1, '式', 100000,
    '', '', '', '',
    '', '', '', '',
    '', '', '', '',
    '', '', '', '',
    '月次定期請求', 'example@example.com'
  ];
  sheet.getRange(2, 1, 1, sample.length).setValues([sample]);

  // 「有効」列にチェックボックス
  sheet.getRange(2, 1, 50, 1).insertCheckboxes();

  SpreadsheetApp.getUi().alert(
    '✅ 定期請求マスタを初期化しました\n\n' +
    '「有効」にチェックを入れた行が毎月自動生成されます。\n' +
    '支払期限オフセット(日):請求日から何日後を期限にするかを数値で入力してください。'
  );
}

// ============================================================
// ② 送信ログシートの初期化
// ============================================================
function initSendLog_() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(SHEET_SEND_LOG);
  if (!sheet) {
    sheet = ss.insertSheet(SHEET_SEND_LOG);
    const headers = [
      '送信日時', '請求No', '宛先会社名', '送信先メールアドレス',
      'ステータス', 'エラー内容', 'リトライ回数', 'PDFファイルURL'
    ];
    sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
    sheet.getRange(1, 1, 1, headers.length)
      .setFontWeight('bold').setBackground('#4472C4').setFontColor('white');
    sheet.setFrozenRows(1);
    sheet.setColumnWidth(1, 160);
    sheet.setColumnWidth(3, 200);
    sheet.setColumnWidth(4, 220);
    sheet.setColumnWidth(6, 300);
    sheet.setColumnWidth(8, 300);
  }
  return sheet;
}

// ============================================================
// ③ 送信ログに1件記録
// ============================================================
function writeSendLog_(invoiceNo, companyName, toEmail, status, errorMsg, retryCount, fileUrl) {
  const sheet = initSendLog_();
  const now = new Date();
  sheet.appendRow([
    now,
    invoiceNo || '',
    companyName || '',
    toEmail || '',
    status,          // '成功' or '失敗' or 'リトライ待ち'
    errorMsg || '',
    retryCount || 0,
    fileUrl || ''
  ]);

  // ステータスで色付け
  const lastRow = sheet.getLastRow();
  const statusCell = sheet.getRange(lastRow, 5);
  if (status === '成功') {
    statusCell.setBackground('#C6EFCE').setFontColor('#276221');
  } else if (status === '失敗') {
    statusCell.setBackground('#FFC7CE').setFontColor('#9C0006');
  } else if (status === 'リトライ待ち') {
    statusCell.setBackground('#FFEB9C').setFontColor('#9C6500');
  }
}

// ============================================================
// ④ 今月の定期請求データを生成(請求データシートに追記)
// ============================================================
function generateMonthlyInvoices() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const masterSheet = ss.getSheetByName(SHEET_RECURRING_MASTER);

  if (!masterSheet) {
    SpreadsheetApp.getUi().alert('❌ 定期請求マスタが見つかりません。\n先に「定期請求マスタ初期化」を実行してください。');
    return [];
  }

  const masterData = masterSheet.getDataRange().getValues();
  const masterHeaders = masterData[0];
  const today = new Date();
  const dateStr = Utilities.formatDate(today, 'Asia/Tokyo', 'yyyy/MM/dd');

  // 請求データシート
  const dataSheet = ss.getSheetByName(SHEET_INVOICE_DATA);
  const dataHeaders = dataSheet.getRange(1, 1, 1, dataSheet.getLastColumn()).getValues()[0];

  const generatedRows = [];

  for (let i = 1; i < masterData.length; i++) {
    const row = masterData[i];
    const isActive = row[masterHeaders.indexOf('有効')];
    if (!isActive) continue;

    const companyName = row[masterHeaders.indexOf('宛先会社名')];
    if (!companyName) continue;

    // 今月すでに生成済みか確認(同会社・同月の請求Noが存在するか)
    const existingData = dataSheet.getDataRange().getValues();
    const thisMonth = Utilities.formatDate(today, 'Asia/Tokyo', 'yyyyMM');
    const alreadyExists = existingData.slice(1).some(r => {
      const no = String(r[0]);
      const company = String(r[2]);
      return no.startsWith(thisMonth) && company === companyName;
    });

    if (alreadyExists) {
      Logger.log(`スキップ(既存): ${companyName}`);
      continue;
    }

    // 支払期限の計算
    const offsetDays = parseInt(row[masterHeaders.indexOf('支払期限オフセット(日)')]) || 30;
    const dueDate = new Date(today.getTime() + offsetDays * 24 * 60 * 60 * 1000);
    const dueDateStr = Utilities.formatDate(dueDate, 'Asia/Tokyo', 'yyyy年M月d日');

    // 請求番号採番
    const invoiceNo = getNextInvoiceNumber();

    // 明細データ取得
    const newRow = new Array(dataHeaders.length).fill('');
    const setVal = (colName, val) => {
      const idx = dataHeaders.indexOf(colName);
      if (idx >= 0) newRow[idx] = val;
    };

    setVal('請求No', invoiceNo);
    setVal('請求日', dateStr);
    setVal('宛先会社名', row[masterHeaders.indexOf('宛先会社名')]);
    setVal('宛先敬称', row[masterHeaders.indexOf('宛先敬称')]);
    setVal('宛先代表者名', row[masterHeaders.indexOf('宛先代表者名')]);
    setVal('宛先代表者敬称', row[masterHeaders.indexOf('宛先代表者敬称')]);
    setVal('件名', row[masterHeaders.indexOf('件名')]);
    setVal('支払期限', dueDateStr);
    setVal('備考', row[masterHeaders.indexOf('備考')]);
    setVal('送信先メールアドレス', row[masterHeaders.indexOf('送信先メールアドレス')]);

    for (let n = 1; n <= 5; n++) {
      setVal(`摘要${n}`, row[masterHeaders.indexOf(`摘要${n}`)]);
      setVal(`数量${n}`, row[masterHeaders.indexOf(`数量${n}`)]);
      setVal(`単位${n}`, row[masterHeaders.indexOf(`単位${n}`)]);
      setVal(`単価${n}`, row[masterHeaders.indexOf(`単価${n}`)]);
    }

    dataSheet.appendRow(newRow);
    generatedRows.push({ invoiceNo, companyName });
    Logger.log(`生成: ${invoiceNo} - ${companyName}`);

    // 採番がかぶらないよう少し待つ
    Utilities.sleep(200);
  }

  if (generatedRows.length > 0) {
    const list = generatedRows.map(r => `  ${r.invoiceNo}  ${r.companyName}`).join('\n');
    SpreadsheetApp.getUi().alert(
      `✅ 今月の定期請求データを生成しました(${generatedRows.length}件)\n\n${list}`
    );
  } else {
    SpreadsheetApp.getUi().alert('ℹ️ 今月分の定期請求データはすでに生成済みです(または有効なマスタがありません)');
  }

  return generatedRows;
}

// ============================================================
// ⑤ 月次一括バッチ(生成 → PDF → 送信)
// ============================================================
function runMonthlyBatch() {
  Logger.log('=== 月次一括バッチ 開始 ===');

  // Step1: 今月の定期請求データを生成
  generateMonthlyInvoices();
  Utilities.sleep(1000);

  // Step2: 未送信分を一括送信(ログ付き)
  batchSendWithLog_();

  Logger.log('=== 月次一括バッチ 完了 ===');
}

// ============================================================
// ⑥ ログ付き一括送信(内部共通処理)
// ============================================================
function batchSendWithLog_() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const dataSheet = ss.getSheetByName(SHEET_INVOICE_DATA);

  const lastRow = dataSheet.getLastRow();
  if (lastRow < 2) {
    Logger.log('送信対象データなし');
    return;
  }

  const headers = dataSheet.getRange(1, 1, 1, dataSheet.getLastColumn()).getValues()[0];
  const sentColIndex = headers.indexOf('送信済み') + 1;
  const emailColIndex = headers.indexOf('送信先メールアドレス') + 1;

  let successCount = 0;
  let failCount = 0;

  for (let r = 2; r <= lastRow; r++) {
    const rowData = dataSheet.getRange(r, 1, 1, dataSheet.getLastColumn()).getValues()[0];
    const sent = rowData[sentColIndex - 1];
    const email = rowData[emailColIndex - 1];
    const invoiceNo = rowData[0];

    if (sent || !email || !invoiceNo) continue;

    let retryCount = 0;
    let lastError = '';
    let success = false;
    let fileUrl = '';

    // リトライループ
    while (retryCount < MAX_RETRY_COUNT && !success) {
      try {
        const result = generateInvoicePDF(r);
        if (!result) throw new Error('PDF生成失敗');

        fileUrl = result.file.getUrl();
        sendInvoiceEmail_(result, r);
        success = true;
        successCount++;

        writeSendLog_(
          invoiceNo,
          rowData[headers.indexOf('宛先会社名')],
          email,
          '成功',
          '',
          retryCount,
          fileUrl
        );
        Logger.log(`✅ 送信成功: ${invoiceNo} (リトライ: ${retryCount}回)`);

      } catch (e) {
        retryCount++;
        lastError = e.message;
        Logger.log(`❌ 送信失敗 (${retryCount}回目): ${invoiceNo} - ${e.message}`);

        if (retryCount < MAX_RETRY_COUNT) {
          Logger.log(`⏳ ${RETRY_INTERVAL_MINUTES}分後にリトライします`);
          Utilities.sleep(RETRY_INTERVAL_MINUTES * 60 * 1000);
        }
      }
    }

    if (!success) {
      failCount++;
      writeSendLog_(
        invoiceNo,
        rowData[headers.indexOf('宛先会社名')],
        email,
        '失敗',
        lastError,
        retryCount,
        fileUrl
      );

      // 失敗フラグをデータシートに記録
      if (sentColIndex > 0) {
        dataSheet.getRange(r, sentColIndex).setValue('❌失敗');
      }
    }
  }

  // 実行後サマリーをログに残す
  const summary = `送信完了: ${successCount}件 成功 / ${failCount}件 失敗`;
  Logger.log(summary);

  // 管理者にサマリーメールを送信
  const settings = getSettingsMap_();
  const adminEmail = settings['メールアドレス'] || Session.getActiveUser().getEmail();
  if (adminEmail) {
    GmailApp.sendEmail(
      adminEmail,
      `【請求書】月次一括送信 完了レポート`,
      `月次一括送信が完了しました。\n\n` +
      `成功: ${successCount}件\n` +
      `失敗: ${failCount}件\n\n` +
      `詳細は「送信ログ」シートをご確認ください。`,
      { name: 'GAS 請求書システム' }
    );
  }

  return { successCount, failCount };
}

// ============================================================
// ⑦ 失敗分のリトライ送信(手動実行用)
// ============================================================
function retryFailedInvoices() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const dataSheet = ss.getSheetByName(SHEET_INVOICE_DATA);
  const ui = SpreadsheetApp.getUi();

  const headers = dataSheet.getRange(1, 1, 1, dataSheet.getLastColumn()).getValues()[0];
  const sentColIndex = headers.indexOf('送信済み') + 1;
  const emailColIndex = headers.indexOf('送信先メールアドレス') + 1;
  const lastRow = dataSheet.getLastRow();

  const failedRows = [];
  for (let r = 2; r <= lastRow; r++) {
    const sent = dataSheet.getRange(r, sentColIndex).getValue();
    const email = dataSheet.getRange(r, emailColIndex).getValue();
    const invoiceNo = dataSheet.getRange(r, 1).getValue();
    if (String(sent).includes('失敗') && email && invoiceNo) {
      failedRows.push({ row: r, invoiceNo, email });
    }
  }

  if (failedRows.length === 0) {
    ui.alert('ℹ️ リトライ対象の失敗行がありません');
    return;
  }

  const list = failedRows.map(f => `  ${f.invoiceNo} → ${f.email}`).join('\n');
  const response = ui.alert(
    '🔁 失敗分リトライ確認',
    `以下の ${failedRows.length} 件を再送信します:\n\n${list}\n\n実行しますか?`,
    ui.ButtonSet.YES_NO
  );
  if (response !== ui.Button.YES) return;

  let successCount = 0;
  let failCount = 0;

  failedRows.forEach(item => {
    try {
      // 失敗フラグをクリア
      dataSheet.getRange(item.row, sentColIndex).setValue('');

      const result = generateInvoicePDF(item.row);
      if (!result) throw new Error('PDF生成失敗');
      sendInvoiceEmail_(result, item.row);
      successCount++;

      writeSendLog_(
        item.invoiceNo,
        dataSheet.getRange(item.row, headers.indexOf('宛先会社名') + 1).getValue(),
        item.email,
        '成功(リトライ)',
        '',
        1,
        result.file.getUrl()
      );
    } catch (e) {
      failCount++;
      dataSheet.getRange(item.row, sentColIndex).setValue('❌失敗');
      writeSendLog_(
        item.invoiceNo,
        dataSheet.getRange(item.row, headers.indexOf('宛先会社名') + 1).getValue(),
        item.email,
        '失敗',
        e.message,
        1,
        ''
      );
    }
  });

  ui.alert(`🔁 リトライ完了\n\n✅ 成功: ${successCount}件\n❌ 失敗: ${failCount}件`);
}

// ============================================================
// ⑧ 月次自動実行トリガーの設定
// ============================================================
function setupMonthlyTrigger() {
  const ui = SpreadsheetApp.getUi();

  // 既存の月次トリガーを削除
  deleteMonthlyTrigger(true); // サイレント削除

  // 毎月何日に実行するか確認
  const result = ui.prompt(
    '⚙️ 月次トリガー設定',
    '毎月何日に自動実行しますか?(1〜28 の数字を入力)',
    ui.ButtonSet.OK_CANCEL
  );
  if (result.getSelectedButton() !== ui.Button.OK) return;

  const day = parseInt(result.getResponseText().trim());
  if (isNaN(day) || day < 1 || day > 28) {
    ui.alert('❌ 1〜28 の数字を入力してください');
    return;
  }

  // 時刻確認
  const timeResult = ui.prompt(
    '⚙️ 実行時刻',
    '何時に実行しますか?(0〜23 の数字を入力、例:9 → 9:00〜10:00の間に実行)',
    ui.ButtonSet.OK_CANCEL
  );
  if (timeResult.getSelectedButton() !== ui.Button.OK) return;

  const hour = parseInt(timeResult.getResponseText().trim());
  if (isNaN(hour) || hour < 0 || hour > 23) {
    ui.alert('❌ 0〜23 の数字を入力してください');
    return;
  }

  // トリガー作成
  ScriptApp.newTrigger('runMonthlyBatchByTrigger')
    .timeBased()
    .onMonthDay(day)
    .atHour(hour)
    .create();

  // 設定値をPropertiesに保存(確認用)
  PropertiesService.getScriptProperties().setProperties({
    'MONTHLY_TRIGGER_DAY': String(day),
    'MONTHLY_TRIGGER_HOUR': String(hour)
  });

  ui.alert(
    `✅ 月次トリガーを設定しました\n\n` +
    `毎月 ${day} 日 ${hour}時頃に「月次一括バッチ」が自動実行されます。`
  );
}

// ============================================================
// ⑨ トリガーから呼ばれる実行関数(直接は呼ばない)
// ============================================================
function runMonthlyBatchByTrigger() {
  Logger.log('=== トリガー起動: 月次一括バッチ ===');
  try {
    runMonthlyBatch();
  } catch (e) {
    // 失敗時に管理者へエラーメール
    const settings = getSettingsMap_();
    const adminEmail = settings['メールアドレス'] || Session.getActiveUser().getEmail();
    if (adminEmail) {
      GmailApp.sendEmail(
        adminEmail,
        '【緊急】請求書月次バッチ 実行エラー',
        `月次一括バッチ実行中にエラーが発生しました。\n\nエラー内容:\n${e.message}\n\n` +
        `スタック:\n${e.stack || '不明'}\n\n` +
        `Google Apps Script の実行ログを確認してください。`,
        { name: 'GAS 請求書システム' }
      );
    }
    throw e; // GASのエラーログにも残す
  }
}

// ============================================================
// ⑩ 月次トリガーの削除
// ============================================================
function deleteMonthlyTrigger(silent) {
  const triggers = ScriptApp.getProjectTriggers();
  let deleted = 0;
  triggers.forEach(trigger => {
    if (trigger.getHandlerFunction() === 'runMonthlyBatchByTrigger') {
      ScriptApp.deleteTrigger(trigger);
      deleted++;
    }
  });

  if (!silent) {
    SpreadsheetApp.getUi().alert(
      deleted > 0
        ? `✅ 月次トリガーを削除しました(${deleted}件)`
        : 'ℹ️ 削除対象の月次トリガーはありませんでした'
    );
  }
}

// ============================================================
// ⑪ 現在のトリガー設定を確認
// ============================================================
function checkTriggerStatus() {
  const triggers = ScriptApp.getProjectTriggers();
  const monthly = triggers.filter(t => t.getHandlerFunction() === 'runMonthlyBatchByTrigger');

  const props = PropertiesService.getScriptProperties().getProperties();
  const day = props['MONTHLY_TRIGGER_DAY'] || '未設定';
  const hour = props['MONTHLY_TRIGGER_HOUR'] || '未設定';

  const msg = monthly.length > 0
    ? `✅ 月次トリガー 設定済み\n\n毎月 ${day} 日 ${hour}時頃に自動実行されます`
    : '❌ 月次トリガーは設定されていません';

  SpreadsheetApp.getUi().alert(msg);
}

まとめ {#まとめ}

この記事では、AIツール「Claude」を使ってGASのエラーを効率的に解消する方法を解説しました。

今日のポイント

  1. GASのエラー修正にはClaudeが最適:ChatGPTやGeminiで解決しないエラーは、まずClaudeに相談してみましょう。
  2. まずはコード全体を理解させる:「このGASの内容を理解して」とプロンプトを送り、コードの全体像を把握させることが重要です。
  3. 対話形式で要件を伝える:エラーメッセージや追加したい機能を具体的に伝えることで、Claudeが最適なコードを提案してくれます。

この方法を使えば、今まで何時間もかかっていたエラーとの格闘から解放され、より本質的な業務に集中できるようになります。ぜひ、今日から試してみてください。

📌 この記事が役に立ったら
ぜひ実際に試してみてください。質問があればコメントでお知らせください!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次