/** * 経営ダッシュボード デバッグ版 * * このファイルには、エラーの原因を特定するための診断機能が含まれています。 * * 使い方: * 1. Google Apps Script エディタで Code.gs の内容を全て削除 * 2. このファイルの内容を全てコピー&ペースト * 3. 保存して「診断」メニューを実行 */ // ============================================ // デバッグ用メニュー // ============================================ function onOpen() { const ui = SpreadsheetApp.getUi(); ui.createMenu('🔷 GemEgg予実管理 (DEBUG)') .addItem('🔍 診断を実行', 'runDiagnostics') .addItem('📈 経営ダッシュボードを更新 (DEBUG)', 'updateDashboardDebug') .addItem('🔄 全て更新(予実+ダッシュボード)', 'updateAll') .addSeparator() .addItem('📋 実行ログを表示', 'showLogs') .addToUi(); } // ============================================ // 診断機能 // ============================================ /** * システム全体の診断を実行 */ function runDiagnostics() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const ui = SpreadsheetApp.getUi(); let report = '=== 診断レポート ===\n\n'; let errors = []; // 1. シート存在チェック report += '【1. シート存在チェック】\n'; const requiredSheets = ['予算入力', '実績入力', '予実出力', '経営ダッシュボード']; requiredSheets.forEach(name => { const sheet = ss.getSheetByName(name); if (sheet) { report += `✅ ${name}: 存在\n`; } else { report += `❌ ${name}: 見つかりません\n`; errors.push(`${name}シートが見つかりません`); } }); // 2. 経営ダッシュボードの基本設定チェック const dashboard = ss.getSheetByName('経営ダッシュボード'); if (dashboard) { report += '\n【2. 経営ダッシュボード設定チェック】\n'; try { const startMonth = dashboard.getRange('C4').getValue(); const endMonth = dashboard.getRange('C5').getValue(); const cashBalance = dashboard.getRange('C29').getValue(); report += `期首月 (C4): ${startMonth}\n`; report += `締月 (C5): ${endMonth}\n`; report += `現金残高 (C29): ${cashBalance}\n`; // 月数計算テスト try { const monthsElapsed = getMonthsElapsed(startMonth, endMonth); report += `計算された月数: ${monthsElapsed}ヶ月\n`; if (monthsElapsed < 1 || monthsElapsed > 12) { errors.push(`月数が異常です: ${monthsElapsed}ヶ月`); report += `⚠️ 月数が異常です: ${monthsElapsed}ヶ月\n`; } } catch (e) { errors.push(`月数計算エラー: ${e.message}`); report += `❌ 月数計算エラー: ${e.message}\n`; } } catch (e) { errors.push(`ダッシュボード設定読み取りエラー: ${e.message}`); report += `❌ 設定読み取りエラー: ${e.message}\n`; } } // 3. 予算入力シートチェック const budgetSheet = ss.getSheetByName('予算入力'); if (budgetSheet) { report += '\n【3. 予算入力シート構造チェック】\n'; try { // O6セル(年間予算売上) const annualRevenue = budgetSheet.getRange('O6').getValue(); report += `年間予算売上 (O6): ${annualRevenue}\n`; if (typeof annualRevenue !== 'number' || annualRevenue === 0) { errors.push('予算入力シートのO6に年間予算売上がありません'); report += '⚠️ O6に年間予算売上がありません\n'; } // 販管費計の検索 const sgaExpense = getBudgetSgaExpense(budgetSheet); report += `販管費計の年間予算: ${sgaExpense}\n`; if (sgaExpense === 0) { errors.push('予算入力シートで「販売管理費 計」が見つかりません'); report += '⚠️ 「販売管理費 計」が見つかりません\n'; } } catch (e) { errors.push(`予算入力シートエラー: ${e.message}`); report += `❌ エラー: ${e.message}\n`; } } // 4. 実績入力シートチェック const actualSheet = ss.getSheetByName('実績入力'); if (actualSheet) { report += '\n【4. 実績入力シート構造チェック】\n'; try { // 主要行のチェック const rows = [ { row: 9, name: '売上高' }, { row: 18, name: '売上総損益金額' }, { row: 20, name: '役員報酬' }, { row: 21, name: '給料手当' }, { row: 22, name: '法定福利費' }, { row: 31, name: '販売管理費 計' }, { row: 32, name: '営業損益金額' }, { row: 35, name: '経常損益金額' } ]; rows.forEach(item => { const value = actualSheet.getRange(item.row, 7).getValue(); // G列 const label = actualSheet.getRange(item.row, 2).getValue(); // B列 report += `${item.name} (${item.row}行): B列="${label}", 値=${value}\n`; }); } catch (e) { errors.push(`実績入力シートエラー: ${e.message}`); report += `❌ エラー: ${e.message}\n`; } } // 5. 総合判定 report += '\n【5. 総合判定】\n'; if (errors.length === 0) { report += '✅ エラーなし - ダッシュボード更新を実行できます\n'; } else { report += `❌ ${errors.length}個の問題が見つかりました:\n`; errors.forEach((err, i) => { report += ` ${i + 1}. ${err}\n`; }); } // ログに出力 console.log(report); // ダイアログで表示 ui.alert('診断結果', report, ui.ButtonSet.OK); } /** * 実行ログを表示 */ function showLogs() { const ui = SpreadsheetApp.getUi(); ui.alert( 'ログの確認方法', '1. Apps Script エディタで「実行」タブを開く\n' + '2. 関数を選択して「実行」をクリック\n' + '3. 下部の「実行ログ」パネルを確認\n\n' + 'または、「表示」→「ログ」(Ctrl+Enter) でログを表示できます。', ui.ButtonSet.OK ); } // ============================================ // デバッグ版ダッシュボード更新 // ============================================ /** * デバッグ版: 経営ダッシュボードを更新(詳細ログ付き) */ function updateDashboardDebug() { console.log('=== 経営ダッシュボード更新開始 ==='); const ss = SpreadsheetApp.getActiveSpreadsheet(); const dashboard = ss.getSheetByName('経営ダッシュボード'); if (!dashboard) { console.error('エラー: 経営ダッシュボードシートが見つかりません'); SpreadsheetApp.getUi().alert('エラー', '経営ダッシュボードシートが見つかりません。', SpreadsheetApp.getUi().ButtonSet.OK); return; } console.log('✓ 経営ダッシュボードシート: 見つかりました'); try { updateDashboardInternalDebug(dashboard); console.log('=== 更新完了 ==='); SpreadsheetApp.getUi().alert('✅ 完了', '経営ダッシュボードを更新しました。', SpreadsheetApp.getUi().ButtonSet.OK); } catch (error) { console.error('=== エラー発生 ==='); console.error(`エラーメッセージ: ${error.message}`); console.error(`スタックトレース:\n${error.stack}`); SpreadsheetApp.getUi().alert( 'エラー', `ダッシュボード更新中にエラーが発生しました:\n\n${error.message}\n\nスタックトレース:\n${error.stack}`, SpreadsheetApp.getUi().ButtonSet.OK ); } } /** * 経営ダッシュボードを内部的に更新(デバッグ版) */ function updateDashboardInternalDebug(dashboard) { const ss = SpreadsheetApp.getActiveSpreadsheet(); const budgetSheet = ss.getSheetByName('予算入力'); const actualSheet = ss.getSheetByName('実績入力'); if (!budgetSheet || !actualSheet) { throw new Error('予算入力または実績入力シートが見つかりません'); } console.log('✓ 予算入力シート: 見つかりました'); console.log('✓ 実績入力シート: 見つかりました'); // 期首月と締月を取得 console.log('\n--- 設定値の読み込み ---'); const startMonth = dashboard.getRange('C4').getValue(); const endMonth = dashboard.getRange('C5').getValue(); console.log(`期首月 (C4): ${startMonth}`); console.log(`締月 (C5): ${endMonth}`); // 月数を計算 console.log('\n--- 月数計算 ---'); console.log(`期首月の型: ${typeof startMonth}, 値: "${startMonth}"`); console.log(`締月の型: ${typeof endMonth}, 値: "${endMonth}"`); const monthsElapsed = getMonthsElapsed(startMonth, endMonth); console.log(`計算された月数: ${monthsElapsed}ヶ月`); // 月数の妥当性チェック if (monthsElapsed < 1 || monthsElapsed > 12) { throw new Error( `月数が異常です: ${monthsElapsed}ヶ月\n\n` + `期首月 (C4): "${startMonth}"\n` + `締月 (C5): "${endMonth}"\n\n` + `期首月と締月を以下の形式で設定してください:\n` + `- 形式: "2025/4" または "2025/04"\n` + `- 期首月 < 締月 である必要があります\n` + `- 月数は 1〜12 の範囲である必要があります` ); } // セクション1: 年間予算 vs 締月地点実績 console.log('\n--- セクション1: 年間予算 vs 締月地点実績 ---'); try { updateAnnualBudgetVsActualDebug(dashboard, budgetSheet, actualSheet, monthsElapsed); console.log('✓ セクション1: 完了'); } catch (e) { console.error(`❌ セクション1でエラー: ${e.message}`); throw new Error(`セクション1でエラー: ${e.message}\n${e.stack}`); } // セクション2: 締月地点予算 vs 実績 console.log('\n--- セクション2: 締月地点予算 vs 実績 ---'); try { updateMonthlyBudgetVsActualDebug(dashboard, budgetSheet, actualSheet, monthsElapsed); console.log('✓ セクション2: 完了'); } catch (e) { console.error(`❌ セクション2でエラー: ${e.message}`); throw new Error(`セクション2でエラー: ${e.message}\n${e.stack}`); } // セクション3: 収益性指標 console.log('\n--- セクション3: 収益性指標 ---'); try { updateProfitabilityIndicators(dashboard); console.log('✓ セクション3: 完了'); } catch (e) { console.error(`❌ セクション3でエラー: ${e.message}`); throw new Error(`セクション3でエラー: ${e.message}\n${e.stack}`); } // セクション4: 効率性指標 console.log('\n--- セクション4: 効率性指標 ---'); try { updateEfficiencyIndicatorsDebug(dashboard, actualSheet, monthsElapsed); console.log('✓ セクション4: 完了'); } catch (e) { console.error(`❌ セクション4でエラー: ${e.message}`); throw new Error(`セクション4でエラー: ${e.message}\n${e.stack}`); } // セクション5: キャッシュフロー関連 console.log('\n--- セクション5: キャッシュフロー関連 ---'); try { updateCashFlowMetrics(dashboard, monthsElapsed); console.log('✓ セクション5: 完了'); } catch (e) { console.error(`❌ セクション5でエラー: ${e.message}`); throw new Error(`セクション5でエラー: ${e.message}\n${e.stack}`); } // セクション6: その他指標 console.log('\n--- セクション6: その他指標 ---'); try { updateOtherMetrics(dashboard); console.log('✓ セクション6: 完了'); } catch (e) { console.error(`❌ セクション6でエラー: ${e.message}`); throw new Error(`セクション6でエラー: ${e.message}\n${e.stack}`); } } // ============================================ // セクション更新関数(デバッグ版) // ============================================ /** * セクション1: 年間予算 vs 締月地点実績(デバッグ版) */ function updateAnnualBudgetVsActualDebug(dashboard, budgetSheet, actualSheet, monthsElapsed) { const startCol = 7; // G列 const endCol = startCol + monthsElapsed - 1; console.log(` 対象列: ${startCol}列目(G)〜${endCol}列目`); // 年間予算 console.log(' 年間予算を読み込み中...'); const annualBudgetRevenue = budgetSheet.getRange('O6').getValue(); console.log(` 年間予算売上 (O6): ${annualBudgetRevenue}`); // 締月地点実績を計算 console.log(' 締月地点実績を計算中...'); const actualRevenue = sumRangeDebug(actualSheet, 9, startCol, endCol, '売上高'); const actualGrossProfit = sumRangeDebug(actualSheet, 18, startCol, endCol, '売上総損益金額'); const actualOperatingProfit = sumRangeDebug(actualSheet, 32, startCol, endCol, '営業損益金額'); const actualOrdinaryProfit = sumRangeDebug(actualSheet, 35, startCol, endCol, '経常損益金額'); // 販管費の年間予算を取得 console.log(' 販管費の年間予算を取得中...'); const annualSgaExpense = getBudgetSgaExpenseDebug(budgetSheet); console.log(` 販管費年間予算: ${annualSgaExpense}`); // 年間予算を計算 const annualGrossProfit = annualBudgetRevenue; const annualOperatingProfit = annualGrossProfit - annualSgaExpense; const annualOrdinaryProfit = annualOperatingProfit; console.log(` 年間売上総利益: ${annualGrossProfit}`); console.log(` 年間営業利益: ${annualOperatingProfit}`); console.log(` 年間経常利益: ${annualOrdinaryProfit}`); // ダッシュボードに書き込み console.log(' ダッシュボードに書き込み中...'); dashboard.getRange('C8').setValue(annualBudgetRevenue).setNumberFormat('#,##0'); dashboard.getRange('C9').setValue(annualGrossProfit).setNumberFormat('#,##0'); dashboard.getRange('C10').setValue(annualOperatingProfit).setNumberFormat('#,##0'); dashboard.getRange('C11').setValue(annualOrdinaryProfit).setNumberFormat('#,##0'); dashboard.getRange('D8').setValue(actualRevenue).setNumberFormat('#,##0'); dashboard.getRange('D9').setValue(actualGrossProfit).setNumberFormat('#,##0'); dashboard.getRange('D10').setValue(actualOperatingProfit).setNumberFormat('#,##0'); dashboard.getRange('D11').setValue(actualOrdinaryProfit).setNumberFormat('#,##0'); dashboard.getRange('E8').setFormula('=IFERROR(D8/C8, 0)').setNumberFormat('0%'); dashboard.getRange('E9').setFormula('=IFERROR(D9/C9, 0)').setNumberFormat('0%'); dashboard.getRange('E10').setFormula('=IFERROR(D10/C10, 0)').setNumberFormat('0%'); dashboard.getRange('E11').setFormula('=IFERROR(D11/C11, 0)').setNumberFormat('0%'); } /** * セクション2: 締月地点予算 vs 実績(デバッグ版) */ function updateMonthlyBudgetVsActualDebug(dashboard, budgetSheet, actualSheet, monthsElapsed) { const budgetStartCol = 3; // C列 const budgetEndCol = budgetStartCol + monthsElapsed - 1; console.log(` 予算対象列: ${budgetStartCol}列目(C)〜${budgetEndCol}列目`); const budgetRevenue = sumRangeDebug(budgetSheet, 6, budgetStartCol, budgetEndCol, '予算売上高'); const budgetSgaExpense = sumRangeForSgaDebug(budgetSheet, budgetStartCol, budgetEndCol); const budgetGrossProfit = budgetRevenue; const budgetOperatingProfit = budgetGrossProfit - budgetSgaExpense; const budgetOrdinaryProfit = budgetOperatingProfit; console.log(` 締月地点予算売上: ${budgetRevenue}`); console.log(` 締月地点予算販管費: ${budgetSgaExpense}`); console.log(` 締月地点予算営業利益: ${budgetOperatingProfit}`); dashboard.getRange('C14').setValue(budgetRevenue).setNumberFormat('#,##0'); dashboard.getRange('C15').setValue(budgetGrossProfit).setNumberFormat('#,##0'); dashboard.getRange('C16').setValue(budgetOperatingProfit).setNumberFormat('#,##0'); dashboard.getRange('C17').setValue(budgetOrdinaryProfit).setNumberFormat('#,##0'); dashboard.getRange('D14').setFormula('=D8'); dashboard.getRange('D15').setFormula('=D9'); dashboard.getRange('D16').setFormula('=D10'); dashboard.getRange('D17').setFormula('=D11'); dashboard.getRange('E14').setFormula('=D14-C14').setNumberFormat('#,##0'); dashboard.getRange('E15').setFormula('=D15-C15').setNumberFormat('#,##0'); dashboard.getRange('E16').setFormula('=D16-C16').setNumberFormat('#,##0'); dashboard.getRange('E17').setFormula('=D17-C17').setNumberFormat('#,##0'); dashboard.getRange('F14').setFormula('=IFERROR(D14/C14, 0)').setNumberFormat('0%'); dashboard.getRange('F15').setFormula('=IFERROR(D15/C15, 0)').setNumberFormat('0%'); dashboard.getRange('F16').setFormula('=IFERROR(D16/C16, 0)').setNumberFormat('0%'); dashboard.getRange('F17').setFormula('=IFERROR(D17/C17, 0)').setNumberFormat('0%'); } /** * セクション4: 効率性指標(デバッグ版) */ function updateEfficiencyIndicatorsDebug(dashboard, actualSheet, monthsElapsed) { const startCol = 7; // G列 const endCol = startCol + monthsElapsed - 1; console.log(` 対象列: ${startCol}列目(G)〜${endCol}列目`); const sgaExpense = sumRangeDebug(actualSheet, 31, startCol, endCol, '販管費計'); const executiveComp = sumRangeDebug(actualSheet, 20, startCol, endCol, '役員報酬'); const salaries = sumRangeDebug(actualSheet, 21, startCol, endCol, '給料手当'); const welfare = sumRangeDebug(actualSheet, 22, startCol, endCol, '法定福利費'); const laborCost = executiveComp + salaries + welfare; console.log(` 人件費内訳: 役員報酬=${executiveComp}, 給料手当=${salaries}, 法定福利費=${welfare}`); console.log(` 人件費合計: ${laborCost}`); dashboard.getRange('D25').setValue(sgaExpense).setNumberFormat('#,##0'); dashboard.getRange('C25').setFormula('=IFERROR(D25/D8, 0)').setNumberFormat('0.0%'); dashboard.getRange('D26').setValue(laborCost).setNumberFormat('#,##0'); dashboard.getRange('C26').setFormula('=IFERROR(D26/D8, 0)').setNumberFormat('0.0%'); } // ============================================ // ヘルパー関数(デバッグ版) // ============================================ /** * 指定範囲の合計を取得(デバッグ版) */ function sumRangeDebug(sheet, row, startCol, endCol, label) { console.log(` ${label}: ${row}行, ${startCol}〜${endCol}列を集計中...`); const rangeWidth = endCol - startCol + 1; // 範囲の妥当性チェック if (rangeWidth < 1) { throw new Error( `列範囲が不正です。\n` + `項目: ${label}\n` + `行: ${row}\n` + `開始列: ${startCol}\n` + `終了列: ${endCol}\n` + `計算された列数: ${rangeWidth}\n\n` + `これは期首月と締月の設定に問題がある可能性があります。` ); } const range = sheet.getRange(row, startCol, 1, rangeWidth); const values = range.getValues()[0]; console.log(` 取得した値: [${values.join(', ')}]`); const sum = values.reduce((sum, val) => { const num = typeof val === 'number' ? val : parseFloat(String(val).replace(/,/g, '')); return sum + (isNaN(num) ? 0 : num); }, 0); console.log(` ${label}合計: ${sum}`); return sum; } /** * 予算入力シートから販管費の年間予算を取得(デバッグ版) */ function getBudgetSgaExpenseDebug(budgetSheet) { console.log(' 販売管理費 計を検索中...'); const data = budgetSheet.getRange('B5:B50').getValues(); let sgaRow = -1; for (let i = 0; i < data.length; i++) { const cellValue = String(data[i][0]).trim(); if (cellValue.includes('販売管理費') && cellValue.includes('計')) { sgaRow = i + 5; console.log(` 見つかりました: ${sgaRow}行目 (${cellValue})`); break; } } if (sgaRow === -1) { console.log(' ⚠️ 販売管理費 計が見つかりませんでした'); return 0; } const value = budgetSheet.getRange(sgaRow, 15).getValue() || 0; // O列 console.log(` 販管費年間予算 (${sgaRow}行, O列): ${value}`); return value; } /** * 予算入力シートから販管費の締月地点予算を取得(デバッグ版) */ function sumRangeForSgaDebug(budgetSheet, startCol, endCol) { console.log(' 販売管理費 計を検索中...'); const data = budgetSheet.getRange('B5:B50').getValues(); let sgaRow = -1; for (let i = 0; i < data.length; i++) { const cellValue = String(data[i][0]).trim(); if (cellValue.includes('販売管理費') && cellValue.includes('計')) { sgaRow = i + 5; console.log(` 見つかりました: ${sgaRow}行目 (${cellValue})`); break; } } if (sgaRow === -1) { console.log(' ⚠️ 販売管理費 計が見つかりませんでした'); return 0; } return sumRangeDebug(budgetSheet, sgaRow, startCol, endCol, '販管費予算'); } // ============================================ // 共通ヘルパー関数 // ============================================ /** * 期首から締月までの月数を計算 */ function getMonthsElapsed(startMonth, endMonth) { // 値の検証 if (!startMonth || !endMonth) { throw new Error( `期首月または締月が設定されていません。\n` + `期首月 (C4): "${startMonth}"\n` + `締月 (C5): "${endMonth}"` ); } console.log(` 期首月の型: ${typeof startMonth}`); console.log(` 締月の型: ${typeof endMonth}`); let startYear, startMonthNum, endYear, endMonthNum; // Dateオブジェクトの場合 if (startMonth instanceof Date) { console.log(` 期首月はDateオブジェクトです: ${startMonth}`); startYear = startMonth.getFullYear(); startMonthNum = startMonth.getMonth() + 1; // getMonth()は0始まり } else { // 文字列の場合 const startStr = String(startMonth); console.log(` 期首月は文字列です: "${startStr}"`); if (!startStr.includes('/')) { throw new Error( `期首月の形式が正しくありません。\n` + `期首月 (C4): "${startStr}"\n\n` + `正しい形式: "2025/4" または "2025/04"\n` + `※現在、セルが日付型になっている可能性があります。` ); } const startParts = startStr.split('/').map(Number); startYear = startParts[0]; startMonthNum = startParts[1]; } // Dateオブジェクトの場合 if (endMonth instanceof Date) { console.log(` 締月はDateオブジェクトです: ${endMonth}`); endYear = endMonth.getFullYear(); endMonthNum = endMonth.getMonth() + 1; // getMonth()は0始まり } else { // 文字列の場合 const endStr = String(endMonth); console.log(` 締月は文字列です: "${endStr}"`); if (!endStr.includes('/')) { throw new Error( `締月の形式が正しくありません。\n` + `締月 (C5): "${endStr}"\n\n` + `正しい形式: "2025/4" または "2025/04"\n` + `※現在、セルが日付型になっている可能性があります。` ); } const endParts = endStr.split('/').map(Number); endYear = endParts[0]; endMonthNum = endParts[1]; } console.log(` 期首: ${startYear}年${startMonthNum}月`); console.log(` 締月: ${endYear}年${endMonthNum}月`); // 数値の検証 if (isNaN(startYear) || isNaN(startMonthNum) || isNaN(endYear) || isNaN(endMonthNum)) { throw new Error( `期首月または締月に数値以外が含まれています。\n` + `期首: ${startYear}年${startMonthNum}月\n` + `締月: ${endYear}年${endMonthNum}月` ); } const months = (endYear - startYear) * 12 + (endMonthNum - startMonthNum) + 1; console.log(` 計算: (${endYear} - ${startYear}) * 12 + (${endMonthNum} - ${startMonthNum}) + 1 = ${months}`); return months; } /** * セクション3: 収益性指標 */ function updateProfitabilityIndicators(dashboard) { dashboard.getRange('C20').setFormula('=IFERROR(D9/D8, 0)').setNumberFormat('0.0%'); dashboard.getRange('C21').setFormula('=IFERROR(D10/D8, 0)').setNumberFormat('0.0%'); dashboard.getRange('C22').setFormula('=IFERROR(D11/D8, 0)').setNumberFormat('0.0%'); } /** * セクション5: キャッシュフロー関連 */ function updateCashFlowMetrics(dashboard, monthsElapsed) { dashboard.getRange('E30').setValue(monthsElapsed + 'ヶ月'); dashboard.getRange('C30').setFormula(`=IFERROR(D25/${monthsElapsed}, 0)`).setNumberFormat('#,##0'); dashboard.getRange('C31').setFormula('=IFERROR(C29/C30, 0)').setNumberFormat('0.0'); dashboard.getRange('C32').setFormula(`=IFERROR(D11/${monthsElapsed}, 0)`).setNumberFormat('#,##0'); dashboard.getRange('C33').setFormula('=IF(C32<0, C29/ABS(C32), "∞")'); } /** * セクション6: その他指標 */ function updateOtherMetrics(dashboard) { dashboard.getRange('C36').setFormula('=D25').setNumberFormat('#,##0'); dashboard.getRange('C37').setFormula('=IFERROR(C36/D8, 0)').setNumberFormat('0.0%'); } /** * 全て更新 */ function updateAll() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const dashboard = ss.getSheetByName('経営ダッシュボード'); const ui = SpreadsheetApp.getUi(); try { // ダッシュボードを更新 if (dashboard) { updateDashboardInternalDebug(dashboard); } ui.alert('✅ 完了', '全ての更新が完了しました。', ui.ButtonSet.OK); } catch (error) { ui.alert('エラー', `更新中にエラーが発生しました:\n${error.message}`, ui.ButtonSet.OK); } }