Googleスプレッドシートでつくる現金出納帳

がいの部屋

作成手順

ステップ1:スプレッドシートの準備

まず、スプレッドシートに必要な項目を設定します。新しいGoogleスプレッドシートを開き、シート名を「現金出納帳」などわかりやすい名前に変更してください。

A列B列C列D列E列F列
日付摘要収入支出残高備考
(入力)(入力)(入力)(入力)(自動計算)(任意)

A列(日付): 取引が行われた日付を入力します。

B列(摘要): 何の取引だったかを具体的に入力します(例:交通費、ランチ代、給料など)。

C列(収入): お金が入ってきた場合に入力します。

D列(支出): お金が出て行った場合に入力します。

E列(残高): GASで自動計算するようにします。

F列(備考): 必要に応じて補足情報を入力します。

ステップ2:GAS(Google Apps Script)の作成

次に、GASを記述していきます。

  1. スプレッドシートのメニューから「拡張機能」>「Apps Script」を選択します。新しいGASプロジェクトが開きます。
  2. コード.gsというファイルが開かれるので、既存のコードを全て削除し、以下のコードを貼り付けてください。
  3. コードを貼り付けたら、フロッピーディスクのアイコン(プロジェクトを保存)をクリックして保存します。プロジェクト名の入力を求められたら「現金出納帳スクリプト」など、わかりやすい名前を付けてください。
function onEdit(e) {
  const sheet = e.source.getActiveSheet();
  const range = e.range;

  // 「現金出納帳」シートでのみ動作
  if (sheet.getName() !== '現金出納帳') {
    return;
  }

  // 収入(C列)または支出(D列)が編集された場合
  if (range.getColumn() === 3 || range.getColumn() === 4) {
    const row = range.getRow();

    // 2行目以降のデータ行に対して処理
    if (row >= 2) {
      updateBalance(sheet, row);
    }
  }
}

function updateBalance(sheet, currentRow) {
  // 残高列のインデックス (E列はインデックス4)
  const balanceColumn = 5;

  // 現在の行の収入と支出を取得
  const income = sheet.getRange(currentRow, 3).getValue(); // C列
  const expense = sheet.getRange(currentRow, 4).getValue(); // D列

  let previousBalance = 0;

  // 最初のデータ行(2行目)の場合、初期残高は0とみなす
  if (currentRow === 2) {
    previousBalance = 0;
  } else {
    // 前の行の残高を取得 (E列)
    previousBalance = sheet.getRange(currentRow - 1, balanceColumn).getValue();
  }

  // 新しい残高を計算
  const newBalance = previousBalance + income - expense;

  // 残高をE列に設定
  sheet.getRange(currentRow, balanceColumn).setValue(newBalance);

  // 以下、残りのデータ行の残高を再計算(修正された行以降)
  const lastRow = sheet.getLastRow();
  for (let i = currentRow + 1; i <= lastRow; i++) {
    const prevRowBalance = sheet.getRange(i - 1, balanceColumn).getValue();
    const currentIncome = sheet.getRange(i, 3).getValue();
    const currentExpense = sheet.getRange(i, 4).getValue();
    sheet.getRange(i, balanceColumn).setValue(prevRowBalance + currentIncome - currentExpense);
  }
}

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('現金出納帳')
      .addItem('残高を全て更新', 'recalculateAllBalances')
      .addToUi();
}

function recalculateAllBalances() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // 「現金出納帳」シートでのみ動作
  if (sheet.getName() !== '現金出納帳') {
    SpreadsheetApp.getUi().alert('「現金出納帳」シートを開いてから実行してください。');
    return;
  }

  const lastRow = sheet.getLastRow();
  if (lastRow < 2) { // ヘッダー行のみの場合
    return;
  }

  // 2行目から最終行までループして残高を再計算
  for (let i = 2; i <= lastRow; i++) {
    updateBalance(sheet, i);
  }
  SpreadsheetApp.getUi().alert('残高が全て更新されました。');
}

ステップ3:GASの権限承認

初めてこのスクリプトを実行する際、Googleアカウントの権限承認が必要です。

  1. GASエディタで、関数選択ドロップダウンからonEdit関数を選び、実行ボタン(▶︎)をクリックします。
  2. 「承認が必要です」というポップアップが表示されるので、「権限を確認」をクリックします。
  3. ご自身のGoogleアカウントを選択し、警告が表示された場合は「詳細」>「現金出納帳スクリプトに移動」をクリックし、「許可」をクリックします。
    • onEdit関数は特別なトリガーなので、この承認作業は手動で一度だけ行えば、あとはシートの編集時に自動で実行されます。
    • onOpen関数も同様に、スプレッドシートを開いた時に自動でメニューが追加されます。

4. アプリの使い方

これで簡単な現金出納帳アプリの完成です!

  1. データの入力:
    • A列に日付、B列に摘要、C列に収入、D列に支出を入力します。
    • E列(残高)は手入力せず、空欄にしておいてください。 GASが自動で計算してくれます。
  2. 残高の自動計算:
    • C列(収入)またはD列(支出)に金額を入力すると、自動的にE列の残高が計算・更新されます。
    • 途中の行を修正した場合でも、それ以降の行の残高も自動的に再計算されます。
  3. メニューからの残高更新:
    • スプレッドシートを開くと、メニューバーに**「現金出納帳」**という項目が追加されます。
    • データが大量になった場合や、何らかの理由で残高がずれたと感じた場合は、「現金出納帳」>「残高を全て更新」を選択すると、最初から最後まで残高を再計算し直すことができます。

詳しい解説

1. onEdit(e) 関数 – 編集時に自動実行される核となる関数

function onEdit(e) {
  const sheet = e.source.getActiveSheet();
  const range = e.range;

  // 「現金出納帳」シートでのみ動作
  if (sheet.getName() !== '現金出納帳') {
    return;
  }

  // 収入(C列)または支出(D列)が編集された場合
  if (range.getColumn() === 3 || range.getColumn() === 4) {
    const row = range.getRow();

    // 2行目以降のデータ行に対して処理
    if (row >= 2) {
      updateBalance(sheet, row);
    }
  }
}

この onEdit(e) 関数は、Googleスプレッドシートの特別なトリガーです。スプレッドシートのセルが編集されるたびに、Googleによって自動的に呼び出されます

  • e (イベントオブジェクト):
    • この e は、編集イベントに関する情報が詰まった重要なオブジェクトです。
    • e.source: 編集が発生したスプレッドシート全体を表します。
    • e.source.getActiveSheet(): 編集が発生したアクティブなシートを取得します。これを sheet 変数に格納しています。
    • e.range: 編集されたセルまたはセル範囲を表します。これを range 変数に格納しています。
  • if (sheet.getName() !== '現金出納帳') { return; }:
    • この行は、スクリプトが特定のシートでのみ動作するよう制限するためのものです。もし別のシート(例えば「設定」シートなど)で編集が行われても、このスクリプトは何もせずに終了します。これにより、意図しないシートで残高計算が行われるのを防ぎます。
  • if (range.getColumn() === 3 || range.getColumn() === 4):
    • range.getColumn() は、編集されたセルの列番号を取得します。(A列が1、B列が2… C列が3、D列が4となります)。
    • この条件は、「C列(収入)またはD列(支出)が編集された場合のみ」というチェックを行っています。日付や摘要の列が編集されても、残高計算は行いません。
  • const row = range.getRow();:
    • 編集されたセルの行番号を取得します。
  • if (row >= 2) { updateBalance(sheet, row); }:
    • row >= 2 は、ヘッダー行(1行目)を除外するための条件です。データ入力は2行目から始まるため、2行目以降で編集があった場合にのみ処理を続行します。
    • updateBalance(sheet, row);: 実際に残高を計算・更新する**updateBalance 関数を呼び出しています**。引数として、編集されたシートと編集された行番号を渡しています。

2. updateBalance(sheet, currentRow) 関数 – 残高を計算・更新する関数

function updateBalance(sheet, currentRow) {
  // 残高列のインデックス (E列はインデックス4)
  const balanceColumn = 5; // E列は5番目の列

  // 現在の行の収入と支出を取得
  const income = sheet.getRange(currentRow, 3).getValue(); // C列
  const expense = sheet.getRange(currentRow, 4).getValue(); // D列

  let previousBalance = 0;

  // 最初のデータ行(2行目)の場合、初期残高は0とみなす
  if (currentRow === 2) {
    previousBalance = 0;
  } else {
    // 前の行の残高を取得 (E列)
    previousBalance = sheet.getRange(currentRow - 1, balanceColumn).getValue();
  }

  // 新しい残高を計算
  const newBalance = previousBalance + income - expense;

  // 残高をE列に設定
  sheet.getRange(currentRow, balanceColumn).setValue(newBalance);

  // 以下、残りのデータ行の残高を再計算(修正された行以降)
  const lastRow = sheet.getLastRow();
  for (let i = currentRow + 1; i <= lastRow; i++) {
    const prevRowBalance = sheet.getRange(i - 1, balanceColumn).getValue();
    const currentIncome = sheet.getRange(i, 3).getValue();
    const currentExpense = sheet.getRange(i, 4).getValue();
    sheet.getRange(i, balanceColumn).setValue(prevRowBalance + currentIncome - currentExpense);
  }
}

この関数は、指定された行の残高を計算し、さらにその行以降のすべての残高を再計算するためのものです。

  • const balanceColumn = 5;:
    • 残高を表示するE列の列番号を定数として定義しています。これにより、コードの可読性が上がります。
  • const income = sheet.getRange(currentRow, 3).getValue();:
    • sheet.getRange(行番号, 列番号) で特定のセルを指定し、.getValue() でそのセルの値を取得しています。ここでは、現在の行のC列(収入)の値を取得しています。expense も同様にD列(支出)の値を取得しています。
  • let previousBalance = 0; ...:
    • if (currentRow === 2): もし現在処理している行が2行目(最初のデータ行) なら、その前の残高はないので 0 とします。
    • else: それ以外の行の場合は、currentRow - 1 で1つ前の行の残高列(E列)の値を取得し、previousBalance に格納します。
  • const newBalance = previousBalance + income - expense;:
    • 前の行の残高に、現在の行の収入を足し、支出を引くことで、新しい残高を計算しています。
  • sheet.getRange(currentRow, balanceColumn).setValue(newBalance);:
    • 計算した newBalance を、現在の行のE列に設定(書き込み)しています。
  • for (let i = currentRow + 1; i <= lastRow; i++) { ... }:
    • この for ループがこのスクリプトの重要なポイントの一つです。
    • もしあなたが途中の行(例えば4行目)の収入や支出を修正した場合、その行の残高はもちろん変わりますが、それ以降のすべての行の残高も影響を受けます
    • このループは、編集された行の次の行からスプレッドシートの最終行までを順番に処理し、各行の残高を再計算して更新します。これにより、残高が常に正しく保たれます。

3. onOpen() と recalculateAllBalances() 関数 – メニューから手動で更新する機能

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('現金出納帳')
      .addItem('残高を全て更新', 'recalculateAllBalances')
      .addToUi();
}

function recalculateAllBalances() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // 「現金出納帳」シートでのみ動作
  if (sheet.getName() !== '現金出納帳') {
    SpreadsheetApp.getUi().alert('「現金出納帳」シートを開いてから実行してください。');
    return;
  }

  const lastRow = sheet.getLastRow();
  if (lastRow < 2) { // ヘッダー行のみの場合
    return;
  }

  // 2行目から最終行までループして残高を再計算
  for (let i = 2; i <= lastRow; i++) {
    updateBalance(sheet, i);
  }
  SpreadsheetApp.getUi().alert('残高が全て更新されました。');
}

これらの関数は、スプレッドシートのメニューにカスタム項目を追加し、そこから手動で残高をすべて再計算できるようにします。

  • onOpen():
    • これも onEdit と同様に特別なトリガー関数です。スプレッドシートが開かれるたびに自動的に実行されます
    • SpreadsheetApp.getUi(): スプレッドシートのユーザーインターフェース (UI) オブジェクトを取得します。
    • ui.createMenu('現金出納帳'): スプレッドシートのメニューバーに「現金出納帳」という新しいメニューを作成します。
    • .addItem('残高を全て更新', 'recalculateAllBalances'): 作成したメニューの中に「残高を全て更新」という項目を追加します。この項目がクリックされると、recalculateAllBalances 関数が実行されます
    • .addToUi(): 作成したメニューと項目をUIに表示させます。
  • recalculateAllBalances():
    • これは、ユーザーがメニュー項目をクリックしたときに実行されるカスタム関数です。
    • SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(): 現在開いているスプレッドシートの、アクティブなシートを取得します。
    • if (sheet.getName() !== '現金出納帳') { ... }: ここでも、誤って別のシートで実行されないようにチェックが入っています。
    • const lastRow = sheet.getLastRow();: シートの最終行を取得します。これにより、データがある範囲だけを処理できます。
    • for (let i = 2; i <= lastRow; i++) { updateBalance(sheet, i); }: 2行目から最終行までループし、すべての行に対して updateBalance 関数を呼び出します。これにより、シート全体の残高が再計算されます。
    • SpreadsheetApp.getUi().alert('残高が全て更新されました。');: 処理が完了したことをユーザーに知らせるアラートを表示します。

まとめ

このスクリプトは、onEdit トリガーを利用して自動化を行い、updateBalance 関数で効率的に残高を管理し、さらに onOpenrecalculateAllBalances で手動での更新機能も提供することで、非常に使いやすい現金出納帳を実現しています。

GASの基本的な機能とイベント駆動型プログラミングの良い例になっているので、今後別のGASアプリを作る際にも、このコードの構造や考え方が役立つと思います。

Copied title and URL