AppSheet 画像(image/drawing)を規定のフォルダ構成にコピーする

画面から登録した画像ファイルは、AppSheetのルールに従って保存されます。通常はデータベースとして使っているスプレッドシートと同じディレクトリに保存されます。

例えば、以下のように車両点検を行うアプリアがあった場合、受注ごとに点検作業があり、各作業時の画像を添付するとします。

この時、通常は下記図の左側のようにスプレッドシートと同じ階層に「テーブル名_Images」フォルダが作成され、そのなかに画像が保存されます。

AppSheetを利用するだけであれば、これだけでも困りません。

一方で、あとからGoogleドライブを見返すときには、作業単位(例えば受注案件毎、など)に画像などがまとまっていること(上の画像の右側)が望まれます。

一式を顧客に提供する必要が発生した場合、そのフォルダをそのまま顧客へ提供することも可能です。

実現方法

以下のステップで実現します。

  1. 画像ファイルの更新をトリガーにオートメーションを実行
  2. オートメーションからGASを呼び出し

テーブル構成

メインとなるテーブルは「受注」「作業」になります。

1つの「受注」に複数の作業が紐づく形です。

オートメーションの設定

今回は「作業」の更新を契機に、ファイルコピーを実行するようにします。

そのため「作業」に紐づくオートメーションとして「ファイルコピー」を作成します。

イベント「When this EVENT occurs:」には、作業の「Update」を設定します。

ファイルコピーには「Call a script」を選択し、Apps Script Projectに作成した(これから作成する)GASを設定します

Apps Script Project(GAS)の作成

これがファイルをコピーする本体です。以下の3つの関数で実現しています。

  • getOrCreateFolder:ヘルパー関数: 指定したフォルダが存在しない場合は作成する
  • getFileByName:ヘルパー関数: 指定したファイル名でファイルを返す
  • copyFileToCustomerFolder:AppSheetから呼び出すメイン関数

具体的なGASのソースを以下に載せます。まずは2つのヘルパー関数からです。

getOrCreateFolder

指定したフォルダが存在する場合は、そのフォルダを返し、存在しない場合は作成したうえでフォルダを返します。

// ヘルパー関数: 指定したフォルダが存在しない場合は作成する
function getOrCreateFolder(parentFolder, folderName) {
  const folders = parentFolder.getFoldersByName(folderName);
  if (folders.hasNext()) {
    return folders.next(); // フォルダが存在する場合は取得
  } else {
    return parentFolder.createFolder(folderName); // フォルダが存在しない場合は作成
  }
}

getFileByName

フォルダ内にファイルが存在するかをファイル名で検索します。

// ヘルパー関数: 指定したファイル名でファイルを返す
function getFileByName(file_name, folder) {
  var files = DriveApp.getFolderById(folder.getId()).getFilesByName(file_name);
  while (files.hasNext()) {
    // 一つ目のファイルを返す(複数存在した場合は考慮しない)
    return files.next();
  }
  return null;
}

つぎに、メイン関数です。

copyFileToCustomerFolder

どのようなフォルダ階層にするかによって、処理内容は変わりますが、処理のポイントは2つだけです。

  1. AppSheet側から渡せる情報(または固定の値)であること
  2. フォルダ階層に従って、順次「getOrCreateFolder」を呼び出していくこと

今回のフォルダ階層は、以下のような構成で考えています。

顧客 ※1
└─ 顧客A_K001 ※2
  └─ レクサス_T001 ※3
    └─ 作業履歴 ※4
      └─ 20241001_741a8789 ※5
        └── 写真 ※6
          ├── APP_20241001_741a8789_K001_レクサス_T001_741a8789_点検項目A写真.jpg
          ├── APP_20241001_741a8789_K001_レクサス_T001_741a8789_点検項目B写真.jpg
          └── APP_20241001_741a8789_K001_レクサス_T001_741a8789_点検項目C写真.jpg

※1 顧客 :固定
※2 [顧客名]_[顧客ID] :例)顧客A_K001
※3 [車両名]_[車両ID] :例)レクサス_T001
※4 作業履歴 :固定
※5 [作業日]_[受注ID] :例)20240314_301ed456
※6 写真 :固定

以下の「XXXXXXXXXXXXXXXXXXXXXXXXXXXXX」は、Googleドライブのファイル/フォルダIDを指定する必要がありますので、ご自身の環境に合わせて頂ければと思います。

function copyFileToCustomerFolder(folderAndFileName, customerName, customerId, vehicleName, vehicleId, workDate, orderId, destinationType) {
  // 1. マイドライブ > 顧客フォルダのルート
  //const rootFolderName = "顧客";
  //const rootFolder = getOrCreateFolder(DriveApp.getRootFolder(), rootFolderName);

  // 元のフォルダIDとコピー先のフォルダID
  const sourceFolderId = "1bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXm9"; // AppSheetがファイルを保存するフォルダID
  const rootFolderId = "1xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXPN"; // コピー先フォルダのID

  const rootFolder = DriveApp.getFolderById(rootFolderId);

  // 2. 顧客フォルダの作成・取得
  const customerFolderName = `${customerName}_${customerId}`;
  const customerFolder = getOrCreateFolder(rootFolder, customerFolderName);

  // 3. 車両フォルダの作成・取得
  const vehicleFolderName = `${vehicleName}_${vehicleId}`;
  const vehicleFolder = getOrCreateFolder(customerFolder, vehicleFolderName);

  // 4. 作業履歴フォルダの作成・取得
  const workFolderName = "作業履歴";
  const workFolder = getOrCreateFolder(vehicleFolder, workFolderName);

  // 5. 作業日フォルダの作成・取得
  const dateFolderName = `${workDate}_${orderId}`;
  const dateFolder = getOrCreateFolder(workFolder, dateFolderName);

  // 6. 最終的なフォルダの取得(写真またはレポート)
  const finalFolderName = destinationType; // 例:"写真" または "レポート"
  const finalFolder = getOrCreateFolder(dateFolder, finalFolderName);

  // 7. ファイルのコピー
  //コピーするファイルの取得
  const sourceFolder = DriveApp.getFolderById(sourceFolderId);
  const fileName = folderAndFileName.split("/")[1];
  const file = getFileByName(fileName, sourceFolder);
  //ファイル名の作成
  //APP_20241001_741a8789_K001_レクサス_T001_741a8789_点検項目A写真.jpg
  const file_column = fileName.split(".")
  const newFileName = `APP_${workDate}_${orderId}_${customerId}_${vehicleName}_${vehicleId}_${orderId}_${file_column[1]}.${file_column[3]}`
  
  //コピー実行
  const copiedFile = file.makeCopy(newFileName,finalFolder);
  console.log(`File "${file.getName()}" was copied to "${finalFolder.getName()}"`);

  return copiedFile.getId(); // コピーされたファイルのIDを返す
}

上記の関数を、AppSheet側から呼び出します。

これにより、ファイルがコピーされます。

まとめ

保守性を考えたときに、可能であればGASは避けたいところ(作った人がいなくなると、ブラックボックスになりがち)ですが、業務効率が向上するならGASなどもうまく取り込んでいきたいですね。

Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です