スプレッドシートで顧客管理を作る#3

スプレッドシートで顧客管理を作る

前回、データの検索・検索処理を作りました。
今回は、データの更新・削除処理を作りたいと思います。

この記事まで実装すると、通常のスプレッドシートに情報を入力するより、使い勝手の良い顧客管理シートが出来上がるかと思います。
ちょっとした罠がありますが、完成後に説明します。

今回の目標

更新・削除用にボタンを用意して、検索結果の更新と削除をできるようにします。
また、A2に一意の id を描画するようにします。

上記動画のようなところまで作成します。

更新・削除のボタンを用意する

検索→登録 > 更新 > 削除 の頻度で使う気がするので、そのような並びにします。

全体の流れは、

flowchart LR A[顧客管理開始] --> B[検索] --> C{既に登録済み} C --> |いいえ| D[新規登録] --> B C -.-> |はい| E{データチェック} E --> |更新処理が必要| F[更新] --> B E -.-> |不要なデータ| G[削除] --> B

検索して登録がなければ新規登録、
検索して情報が誤っていれば更新処理、
検索して不要なデータなら削除処理といった感じですね。

実装する

実装してみましょう。
まずは更新処理からです。
今回、更新・削除処理において、更新・削除前のデータを保存していません。
もし、更新・削除前のデータに戻す要望がある場合は、処理の度にログを取るなどして元に戻せるような仕組みが必要になります。

データの更新処理

データシートのデータを更新してみます。
検索処理実行後、登録シートには顧客データの id が振られています。
ということで、id を元にデータシートのデータを更新します。

flowchart LR 検索 --> 登録シートから検索結果のidを取得 --> idを元にデータが存在する行を取得 --> 行のデータを更新

といった流れとなります。

// 登録シートから検索結果の id を取得する
function getUserIdForAddSheet() {
  const SHEET_NAME = '登録シート';
  return SpreadsheetApp.getActive().getSheetByName(SHEET_NAME).getRange(3, 1).getValue();
}
// 引数に渡した id の行番号を返す
function getDataRowNum(findId) {
  const DATA_SHEET_NAME = 'data';
  // 全顧客データ
  const sheetData = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME).getDataRange().getValues();
  // 描画中の id と一致する行を返す
  for(let i = 0; i < sheetData.length; i ++) {
    if(sheetData[i][0] !== findId) continue;
    return i + 1;
  }
  // 見つからなければ -1 を返す
  return -1;
}
// 行のデータを更新する 更新に失敗したら false 成功したら true を返す
function updateData() {
  // 描画中の検索結果の id
  const findId = getUserIdForAddSheet();
  // 描画中の検索結果の行番号
  const findRow = getDataRowNum(findId);
  console.log(findId, findRow);
  // 描画中の行番号が見つからなければ false を返す
  if(findRow === -1) return false;
  // 登録フォームの更新情報
  const data = getRegisterData();
  const DATA_SHEET_NAME = 'data';
  const dataSheet = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME);
  // 更新処理
  console.log(data);
  dataSheet.getRange(findRow, 2, 1, data.length).setValues([data]);
  return true;
}

データシートからデータを削除する

実はデータの削除処理は、データの更新処理とほとんど変わりません。
というのも、データが存在する行を取得するまでは同じで、
行のデータを 更新する or 削除する
の違いしかないからです。

flowchart LR 検索 --> 登録シートから検索結果のidを取得 --> idを元にデータが存在する行を取得 --> 行のデータを削除
// データの削除
function deleteData() {
  // 描画中の検索結果の id
  const findId = getUserIdForAddSheet();
  // 描画中の検索結果の行番号
  const findRow = getDataRowNum(findId);
  // 描画中の行番号が見つからなければ false を返す
  if(findRow === -1) return false;
  const DATA_SHEET_NAME = 'data';
  const dataSheet = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME);
  // 削除処理
  dataSheet.deleteRow(findRow);
  // 登録フォームを初期化する
  initFindResult();
  clearRegisterData();
  return true;
}

更新ボタン押下時の処理として登録する

ボタンに処理を登録するいつものやつですね。
また、処理完了時にメッセージを表示するようにします。

// 更新ボタンを押下した時に実行するようにする
function onClickUpdateButton() {
  if(!updateData()) SpreadsheetApp.getUi().alert('更新に失敗しました。');
  else SpreadsheetApp.getUi().alert('更新しました!');
}

削除ボタン押下時の処理として登録する

更新ボタンと同様に、処理完了時にメッセージを表示するようにします。

// 削除ボタンを押下したときに実行するようにする
function onClickDeleteButton() {
  if(!deleteData()) SpreadsheetApp.getUi().alert('削除に失敗しました。');
  else SpreadsheetApp.getUi().alert('削除しました!');
}

最後に

さて、ここまでで「スプレッドシート × GAS で顧客管理を作る」が終了しました。
が、色々と気になるところがあります。
例えば、
・登録ボタンを連打すると何度も登録されてしまう点
・ソースコードに同じような処理が複数出現している点
・ipad 等で使用する際、スプレッドシートのアプリではGASが動かない点
などなど、許容できるところとできない点があると思います。

ということで、次回はソースコードを少しきれいにすることと、使用者がもう少し使いやすいようにします。
完成したらXにて報告、この記事にもリンクを貼っておきます。
良かったらフォローしてあげてください。

最後に今回作成したスクリプトをまとめたものを載せておきます。

// 登録シートから検索結果の id を取得する
function getUserIdForAddSheet() {
  const SHEET_NAME = '登録シート';
  return SpreadsheetApp.getActive().getSheetByName(SHEET_NAME).getRange(3, 1).getValue();
}
// 引数に渡した id の行番号を返す
function getDataRowNum(findId) {
  const DATA_SHEET_NAME = 'data';
  // 全顧客データ
  const sheetData = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME).getDataRange().getValues();
  // 描画中の id と一致する行を返す
  for(let i = 0; i < sheetData.length; i ++) {
    if(sheetData[i][0] !== findId) continue;
    return i + 1;
  }
  // 見つからなければ -1 を返す
  return -1;
}
// 行のデータを更新する 更新に失敗したら false 成功したら true を返す
function updateData() {
  // 描画中の検索結果の id
  const findId = getUserIdForAddSheet();
  // 描画中の検索結果の行番号
  const findRow = getDataRowNum(findId);
  console.log(findId, findRow);
  // 描画中の行番号が見つからなければ false を返す
  if(findRow === -1) return false;
  // 登録フォームの更新情報
  const data = getRegisterData();
  const DATA_SHEET_NAME = 'data';
  const dataSheet = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME);
  // 更新処理
  console.log(data);
  dataSheet.getRange(findRow, 2, 1, data.length).setValues([data]);
  return true;
}
// データの削除
function deleteData() {
  // 描画中の検索結果の id
  const findId = getUserIdForAddSheet();
  // 描画中の検索結果の行番号
  const findRow = getDataRowNum(findId);
  // 描画中の行番号が見つからなければ false を返す
  if(findRow === -1) return false;
  const DATA_SHEET_NAME = 'data';
  const dataSheet = SpreadsheetApp.getActive().getSheetByName(DATA_SHEET_NAME);
  // 削除処理
  dataSheet.deleteRow(findRow);
  // 登録フォームを初期化する
  initFindResult();
  clearRegisterData();
  return true;
}
// 更新ボタンを押下した時に実行するようにする
function onClickUpdateButton() {
  if(!updateData()) SpreadsheetApp.getUi().alert('更新に失敗しました。');
  else SpreadsheetApp.getUi().alert('更新しました!');
}
// 削除ボタンを押下したときに実行するようにする
function onClickDeleteButton() {
  if(!deleteData()) SpreadsheetApp.getUi().alert('削除に失敗しました。');
  else SpreadsheetApp.getUi().alert('削除しました!');
}

*このサイトを参考に何かを作成した際に起こった全ての責任を負いません*