経費表の集計ミスを月末前に発見|GASで日付・金額・重複をdry-run監査
ツールおじ|GoogleアカウントをAIエージェント化
月末に経費表を集計しようとしてから、日付の形式違い、金額の文字混入、同じ管理IDの二重登録に気づくと、元の記録まで戻って確認することになります。
この記事では、スプレッドシートを更新せず、問題がある行番号とエラー種別だけをGASで確認します。支払先やメモの内容はログへ出さないため、まずコピー環境で安全に試せます。
この無料コードでできること
- 日付が `YYYY-MM-DD` 形式か確認する
- 金額が0より大きい数値か確認する
- 管理IDの空欄と重複候補を確認する
- 確認状態が許可した3種類のいずれかを確認する
- 問題のある行番号とエラー種別だけをログへ出す
このコードは集計、税区分の判定、領収書のOCR、会計ソフトへの登録を行いません。税務・会計上の扱いは、必要に応じて専門家や利用中サービスの案内を確認してください。
準備するシート
シート名を `経費確認` にし、1行目へ次の見出しを左から並べます。
- A列: 管理ID
- B列: 発生日
- C列: 金額
- D列: 確認状態
- E列: メモ
確認状態は `未確認`、`確認済み`、`対象外` のいずれかにそろえます。管理IDには、外部へ公開しない社内用の番号を使ってください。カード番号、口座番号、認証情報は入力しないでください。
コピーして使える最小コード
function auditExpenseSheetInputFree() {
const CONFIG = {
SHEET_NAME: '経費確認',
HEADER_ROWS: 1,
MAX_ROWS: 500,
DRY_RUN: true,
ALLOWED_STATUS: ['未確認', '確認済み', '対象外']
};
if (CONFIG.DRY_RUN !== true) {
throw new Error('安全のためDRY_RUNはtrueのまま実行してください。');
}
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName(CONFIG.SHEET_NAME);
if (!sheet) {
throw new Error('シート「経費確認」が見つかりません。');
}
const lastRow = sheet.getLastRow();
if (lastRow <= CONFIG.HEADER_ROWS) {
console.log(JSON.stringify({ checkedRows: 0, issues: [] }));
return;
}
const rowCount = lastRow - CONFIG.HEADER_ROWS;
if (rowCount > CONFIG.MAX_ROWS) {
throw new Error('確認行が500件を超えています。範囲を分けてください。');
}
const rows = sheet
.getRange(CONFIG.HEADER_ROWS + 1, 1, rowCount, 5)
.getDisplayValues();
const seenIds = new Set();
const issues = [];
rows.forEach((row, index) => {
const sheetRow = index + CONFIG.HEADER_ROWS + 1;
const [managementId, dateText, amountText, status] = row
.map((value) => String(value).trim());
if (!managementId) {
issues.push({ row: sheetRow, code: 'MISSING_ID' });
} else if (seenIds.has(managementId)) {
issues.push({ row: sheetRow, code: 'DUPLICATE_ID' });
} else {
seenIds.add(managementId);
}
if (!/^\d{4}-\d{2}-\d{2}$/.test(dateText)) {
issues.push({ row: sheetRow, code: 'INVALID_DATE_FORMAT' });
} else {
const [year, month, day] = dateText.split('-').map(Number);
const parsed = new Date(year, month - 1, day);
if (
parsed.getFullYear() !== year ||
parsed.getMonth() !== month - 1 ||
parsed.getDate() !== day
) {
issues.push({ row: sheetRow, code: 'INVALID_DATE_VALUE' });
}
}
const normalizedAmount = amountText.replace(/[,,円\s]/g, '');
const amount = Number(normalizedAmount);
if (!normalizedAmount || !Number.isFinite(amount) || amount <= 0) {
issues.push({ row: sheetRow, code: 'INVALID_AMOUNT' });
}
if (!CONFIG.ALLOWED_STATUS.includes(status)) {
issues.push({ row: sheetRow, code: 'INVALID_STATUS' });
}
});
console.log(JSON.stringify({
dryRun: CONFIG.DRY_RUN,
checkedRows: rows.length,
issueCount: issues.length,
issues: issues
}));
}実行前の準備
1. 元のスプレッドシートをコピーします。
2. コピー側に `経費確認` シートと見出し5列を作ります。
3. テスト用の数行だけを入力します。
4. 拡張機能からApps Scriptを開き、コードを貼り付けます。
5. `auditExpenseSheetInputFree` を選び、実行します。
6. 実行ログで `issueCount` と行番号を確認します。
初回実行時は、対象スプレッドシートを読む権限の確認が表示されることがあります。内容を確認し、目的に合わない権限が表示された場合は中止してください。
エラーコードの見方
- `MISSING_ID`: 管理IDが空欄
- `DUPLICATE_ID`: 同じ管理IDが複数行にある
- `INVALID_DATE_FORMAT`: 日付が `YYYY-MM-DD` 形式ではない
- `INVALID_DATE_VALUE`: 2月30日など、実在しない日付
- `INVALID_AMOUNT`: 金額が空欄、数値以外、または0以下
- `INVALID_STATUS`: 確認状態が許可値と一致しない
ログへ支払先、メモ、金額そのものは出しません。行番号を確認して、修正はスプレッドシート上で手動で行います。
制限と安全上の注意・停止条件
- シート名や列順が違う場合は、コードを実行する前に合わせる
- 500行を超える場合は、コピーを分けて少量ずつ確認する
- カード番号、口座番号、APIキーなどが含まれる表では実行しない
- 経費に該当するか、どの区分にするかをこのコードだけで判断しない
- ログ結果だけで削除、送信、会計登録を自動実行しない
Apps Scriptには実行時間やサービス利用量の上限があります。組織アカウントでは管理者設定により実行できない場合があります。
公開前チェックリスト
- 元データではなくコピー環境で試した
- `DRY_RUN` が `true` になっている
- シート名、列順、確認状態の候補を確認した
- ログに支払先やメモ本文が出ていない
- エラー行を人が確認してから修正する
まとめ
経費表は、集計式より前に入力の形をそろえると確認作業を減らしやすくなります。まずは日付、金額、管理ID、確認状態の4点だけを読み取り専用で監査し、問題のある行を人が確認してください。
注文・入金・発送側もまとめて管理したい方へ
個人販売の注文・発送管理GAS Proを見る

GasおじのTips商品一覧を見る
GasおじのTips商品一覧を見る

※本記事は学習・検証用の例です。実データへ適用する前にコピー環境で確認してください。
※Google公式・Google公認の商品ではありません。
