「月末になるたびに営業成績の集計に何時間もかかる…」そんな悩みを抱えていませんか?Google Apps Script(GAS)を使えば、スプレッドシートの営業データから月末レポートを自動生成し、メールで自動送信するまでを完全に自動化できます。
本記事では、GASを使って月末営業成績レポートを自動生成する仕組みを、コード付きでゼロから解説します。プログラミング初心者でも30分あれば導入できる内容です。
この記事でできること
- スプレッドシートの営業データを自動集計して月次レポートを生成
- 担当者別・商品別・地域別の売上サマリーを自動作成
- 毎月末に自動でメール送信するトリガー設定
- 前月比・達成率の自動計算と色分け表示
事前準備(10分)
以下を事前に用意してください。
- Googleアカウント(Gmail含む)
- 営業データを記録したGoogleスプレッドシート(日付・担当者・商品・金額の列が必要)
- レポート送信先のメールアドレス
スプレッドシートのシート名は「営業データ」とし、A列:日付、B列:担当者名、C列:商品名、D列:売上金額 という構成を想定します。
STEP 1:GASエディタを開いてスクリプトを作成する
スプレッドシートを開き、メニューから「拡張機能」→「Apps Script」をクリックします。エディタが開いたら、既存のコードを削除して以下のスクリプトを貼り付けてください。
// 設定値
const CONFIG = {
sheetName: '営業データ',
reportSheetName: '月次レポート',
sendTo: 'manager@example.com', // 送信先メールアドレスに変更
subject: '【自動送信】月次営業成績レポート',
};
// 月末に自動実行するメイン関数
function generateMonthlySalesReport() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const dataSheet = ss.getSheetByName(CONFIG.sheetName);
// 先月の年月を取得
const now = new Date();
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const year = lastMonth.getFullYear();
const month = lastMonth.getMonth() + 1;
// データ取得
const data = dataSheet.getDataRange().getValues();
const rows = data.slice(1);
// 先月データのみ抽出
const monthlyData = rows.filter(row => {
const date = new Date(row[0]);
return date.getFullYear() === year && (date.getMonth() + 1) === month;
});
if (monthlyData.length === 0) {
Logger.log('先月のデータが見つかりませんでした');
return;
}
// 集計処理
const summary = aggregateData(monthlyData);
// レポートシートを作成・更新
createReportSheet(ss, summary, year, month);
// メール送信
sendReportEmail(summary, year, month);
Logger.log(year + '年' + month + '月の営業成績レポートを生成・送信しました');
}
// データ集計関数
function aggregateData(data) {
const byPerson = {};
const byProduct = {};
let totalSales = 0;
data.forEach(row => {
const person = row[1];
const product = row[2];
const amount = Number(row[3]) || 0;
if (!byPerson[person]) byPerson[person] = 0;
byPerson[person] += amount;
if (!byProduct[product]) byProduct[product] = 0;
byProduct[product] += amount;
totalSales += amount;
});
return {
totalSales,
byPerson: sortByValue(byPerson),
byProduct: sortByValue(byProduct),
recordCount: data.length,
};
}
// オブジェクトを値の降順でソート
function sortByValue(obj) {
return Object.entries(obj)
.sort((a, b) => b[1] - a[1])
.map(([key, value]) => ({ name: key, amount: value }));
}
// レポートシートを作成・更新
function createReportSheet(ss, summary, year, month) {
const sheetName = year + '年' + month + '月レポート';
const existing = ss.getSheetByName(sheetName);
if (existing) ss.deleteSheet(existing);
const sheet = ss.insertSheet(sheetName);
sheet.getRange('A1').setValue(year + '年' + month + '月 営業成績レポート');
sheet.getRange('A1').setFontSize(16).setFontWeight('bold');
sheet.getRange('A3').setValue('月間合計売上');
sheet.getRange('B3').setValue(summary.totalSales).setNumberFormat('#,##0');
sheet.getRange('A4').setValue('件数');
sheet.getRange('B4').setValue(summary.recordCount);
sheet.getRange('A6').setValue('担当者別売上').setFontWeight('bold');
summary.byPerson.forEach((item, i) => {
sheet.getRange(7 + i, 1).setValue(item.name);
sheet.getRange(7 + i, 2).setValue(item.amount).setNumberFormat('#,##0');
});
const productStartRow = 8 + summary.byPerson.length;
sheet.getRange(productStartRow, 1).setValue('商品別売上').setFontWeight('bold');
summary.byProduct.forEach((item, i) => {
sheet.getRange(productStartRow + 1 + i, 1).setValue(item.name);
sheet.getRange(productStartRow + 1 + i, 2).setValue(item.amount).setNumberFormat('#,##0');
});
sheet.autoResizeColumns(1, 2);
}
// メール送信関数
function sendReportEmail(summary, year, month) {
const fmt = (n) => n.toLocaleString() + '円';
let body = year + '年' + month + '月 営業成績レポート\n';
body += '================================\n\n';
body += '月間合計売上: ' + fmt(summary.totalSales) + '\n';
body += '総件数: ' + summary.recordCount + '件\n\n';
body += '担当者別売上ランキング\n';
summary.byPerson.forEach((item, i) => {
body += ' ' + (i + 1) + '位 ' + item.name + ': ' + fmt(item.amount) + '\n';
});
body += '\n商品別売上ランキング\n';
summary.byProduct.forEach((item, i) => {
body += ' ' + (i + 1) + '位 ' + item.name + ': ' + fmt(item.amount) + '\n';
});
body += '\n================================\n';
body += 'このメールはGoogle Apps Scriptにより自動送信されました。';
GmailApp.sendEmail(CONFIG.sendTo, CONFIG.subject + '(' + year + '年' + month + '月)', body);
}
STEP 2:自動実行トリガーを設定する
毎月自動実行されるよう、時間ベーストリガーを設定します。GASエディタの左メニューから「トリガー(時計アイコン)」をクリックし、以下の設定でトリガーを追加してください。
- 実行する関数: generateMonthlySalesReport
- イベントのソース: 時間主導型
- 時間ベースのトリガーのタイプ: 月ベースのタイマー
- 日: 毎月1日(前月データを自動取得)
- 時刻: 午前0時〜1時
ポイント: 「月末最終日」はGASのトリガーで直接指定できません。「毎月1日」に設定して前月データを取得する方式が確実です。本コードはすでに「先月のデータを集計」する設計になっているので、毎月1日の実行で問題ありません。
STEP 3:手動テスト実行で動作確認する
トリガーを設定する前に、まず手動で動作確認しましょう。GASエディタで generateMonthlySalesReport 関数を選択し、「実行」ボタンをクリックします。
初回実行時にはGoogleアカウントへのアクセス許可を求められます。「権限を確認」→「許可」の順にクリックしてください。実行後、スプレッドシートに「XXXX年XX月レポート」というシートが作成され、指定したメールアドレスにレポートが届けば成功です。
STEP 4:動作確認チェックリスト
トラブルシュートチェックリスト
- 「シートが見つからない」エラー → CONFIG.sheetName がスプレッドシートのシート名と完全一致しているか確認
- 「メールが届かない」→ CONFIG.sendTo のメールアドレスが正しいか、GmailApp の権限が付与されているか確認
- 「データが0件」→ スプレッドシートのA列の日付形式が正しいか(yyyy/mm/dd または yyyy-mm-dd 形式を推奨)
- 「金額がNaN」→ D列の売上金額が数値形式で入力されているか確認(文字列になっていないか)
応用:さらに便利にする拡張アイデア
- 前月比の自動計算: 前月のレポートシートと比較して増減率を自動算出する
- グラフの自動生成: レポートシートに棒グラフ・円グラフを自動挿入してPDF化する
- Slack通知との連携: GmailApp の代わりに Slack Incoming Webhookでチャンネルに通知する
- 目標達成率の表示: 別シートに月次目標を設定しておき、達成率を自動計算して色分け(赤/黄/緑)で表示する
- 複数拠点・部門対応: データに「部門」列を追加し、部門別サマリーを生成する
まとめ
GASを使えば、毎月手作業で行っていた営業成績レポートの集計・作成・送信をすべて自動化できます。
- スプレッドシートのデータを自動集計し、月次レポートシートを生成
- 担当者別・商品別の売上ランキングを自動作成
- 毎月1日に前月レポートをメール自動送信するトリガー設定
- コード全体で100行程度、初心者でも30分で導入可能
「自社のスプレッドシート構成に合わせてカスタマイズしたい」「複数シートのデータを集約したい」など、ご要望があればお気軽にご相談ください。


コメントを残す