画面から登録した画像ファイルは、AppSheetのルールに従って保存されます。通常はデータベースとして使っているスプレッドシートと同じディレクトリに保存されます。
例えば、以下のように車両点検を行うアプリアがあった場合、受注ごとに点検作業があり、各作業時の画像を添付するとします。
この時、通常は下記図の左側のようにスプレッドシートと同じ階層に「テーブル名_Images」フォルダが作成され、そのなかに画像が保存されます。
AppSheetを利用するだけであれば、これだけでも困りません。
一方で、あとからGoogleドライブを見返すときには、作業単位(例えば受注案件毎、など)に画像などがまとまっていること(上の画像の右側)が望まれます。
一式を顧客に提供する必要が発生した場合、そのフォルダをそのまま顧客へ提供することも可能です。
実現方法
以下のステップで実現します。
- 画像ファイルの更新をトリガーにオートメーションを実行
- オートメーションから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つだけです。
- AppSheet側から渡せる情報(または固定の値)であること
- フォルダ階層に従って、順次「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などもうまく取り込んでいきたいですね。
コメントを残す