とんたんの技術メモ

注)ただのメモです。

GASで企業のフォルダーをたくさん作る作業メモ

企業一覧のCSVから、グーグルドライブの企業のフォルダをたくさん作って、そのフォルダURLをCSVに追記するという作業をした時のメモです。

ディレクトリ構成

CompanyDirs
    ├ 企業A
         └ 商品画像
   └ 企業B
        └ 商品画像

CreateCompanyDirsScript
    ├ CreateCompanyFolders.gs
    ├ CreateCompanyFoldersImport.csv
    ├ CreateCompanyFoldersExport.ss
   └ README

README

## インストール

### 1. Google Apps Script Install

[Google Apps Script chorome拡張をインストールする](https://chrome.google.com/webstore/detail/google-apps-script/eoieeedlomnegifmaghhjnghhmcldobl?hl=ja)

### 2. CSVをアップロード
マイドライブ > CreateCompanyFoldersScript に以下条件のCSVをアップロード。
- フォーマットは「得意先コード/企業名/店舗名」の3つに整形
- 文字コードは、UTF-8(SJISはサポート外)

### 3. スクリプトを実行
マイドライブ > CreateCompanyFoldersScript > CreateCompanyFolders の設定を確認。
問題なければ再生ボタンでスクリプト実行。



## スクリプトの仕様
既にある企業や店舗、店舗ごとのフォルダはそのまま、新規追加分だけ新しく追加される。



## 店舗が増えて本店の名前が変わった場合

### 1. ドライブでフォルダ名を変更
 対象企業の「本店」->「〇〇店」

### 2. CSVを作成
追加分の企業と店舗を入れたCSVを作成
※注 空だったところに「〇〇店」を追記忘れずに

### 3. インポート
インストール手順の2-3を実行

CreateCompanyFolders.gs

GASには5分の実行制限があるので、トリガー機能を使ってそれ以降の処理を出来るようにしました。 ただし、トリガーには厳しいAPI制限があるので、5000件中、4000件くらいしか出来ませんでした。 なので、残りの1000件は別の日に再実行しました。 最後の実行記録はストアに保存されているので、再実行すれば続きから実行出来ます。

var Lib = new function() {

  this.getItem = function (item) {
    return (item.hasNext())? item.next() : false;
  }

  this.deleteItem = function (item) {
    var file = this.getItem(item);
      if (file) {
        file.setTrashed(true);
        return true;
      }
    return false;
  }

  this.getCsv = function (targetDir, csvName) {
    var csvFile = this.getItem(targetDir.getFilesByName(csvName));
    if (!csvFile) {
      return null;
    }
    return Utilities.parseCsv(csvFile.getBlob().getDataAsString("utf8"));
  }

  this.createDir = function (targetDir, dirName) {
    var dir = this.getItem(targetDir.getFoldersByName(dirName));
    if (!dir) {
      dir = targetDir.createFolder(dirName);
    }
    return dir;
  }

  this.createDirList = function (targetDir, companyName, shopName, shopDefaultDirs) {
    var result = {
      companyDirUrl: "",
      shopDirUrl: "",
    };

    var companyDir = this.createDir(targetDir, companyName);
    result.companyDirUrl = companyDir.getUrl();

    var shopDir = this.createDir(companyDir, shopName);
    result.shopDirUrl = shopDir.getUrl();

    for (var idx in shopDefaultDirs) {
      var dirName = shopDefaultDirs[idx];
      var shopInDir = this.createDir(shopDir, dirName);
    }

    return result;
  }

  this.editSs = function (targetDir, sheetName) {
    var ssId;
    var file = this.getItem(targetDir.getFilesByName(sheetName));
    if (!file) {
      ssId = SpreadsheetApp.create(sheetName).getId();
      var tmpSs = DriveApp.getFileById(ssId);
      DriveApp.getRootFolder().removeFile(tmpSs);
      targetDir.addFile(tmpSs);
    }
    return (file)? SpreadsheetApp.open(file) : SpreadsheetApp.openById(ssId);
  }

  this.saveSsRow = function (ssInstance, targetLine, row) {
    Logger.log([targetLine, row]);
    ssInstance.getRange(targetLine, 1, 1, row.length).setNumberFormat('@').setValues([row]);
  }

  this.setTrigger = function (triggerKey, functionName) {
    this.deleteTrigger(triggerKey);
    var triggerId = ScriptApp.newTrigger(functionName).timeBased().after(10000).create().getUniqueId();
    Logger.log(triggerId + "triggerId");
    PropertiesService.getScriptProperties().setProperty(triggerKey, triggerId);
  }

  this.deleteTrigger = function (triggerKey) {
    var triggerId = PropertiesService.getScriptProperties().getProperty(triggerKey);
    if (!triggerId) return;
    ScriptApp.getProjectTriggers().filter(function(trigger){
      return trigger.getUniqueId() == triggerId;
    })
    .forEach(function (trigger) {
        ScriptApp.deleteTrigger(trigger);
    });
    PropertiesService.getScriptProperties().deleteProperty(triggerKey);
  }

}();

function myFunction() {
  var startTime = new Date();
  var triggerKey = "CreateCompanyFolders";
  var outputDir = Lib.getItem(DriveApp.getFoldersByName("CompanyFolders")); // 出力先のフォルダー名
  var scriptDir = Lib.getItem(DriveApp.getFoldersByName("CreateCompanyFoldersScript")); // スクリプトがあるフォルダー名
  var shopDefaultDirs = ["商品画像"]; // 店舗内に作成するフォルダー名
  var headerList = ["企業ID","企業名","店舗名","店舗フォルダーURL"]; // 出力するSSのヘッダー名
  var exportSs = Lib.editSs(scriptDir, "CreateCompanyFoldersExport").getActiveSheet(); // 出力するSS名
  var rows = Lib.getCsv(scriptDir, "CreateCompanyFoldersImport.csv"); // インポーとするCSVファイル名

  if (rows == null) {
    Logger.log("インポートデータ無し");
    return;
  }

  // スタート行を設定
  var properties = PropertiesService.getScriptProperties();
  var startIdx = parseInt(properties.getProperty("startIdx")) || 1;

  // ヘッダー書き込み
  Lib.saveSsRow(exportSs, 1, headerList);

  for (var idx=0; idx<rows.length; idx++) {
    if (idx < startIdx) continue;

    // 4分経過すると新規トリガー
    if (parseInt((new Date() - startTime) / (1000 * 60)) >= 4) {
      properties.setProperty("startIdx", idx);
      Lib.setTrigger(triggerKey, "myFunction");
      Logger.log(startIdx + '-' + idx + "Complete!");
      return;
    }

    var companyId = rows[idx][0].trim();
    var companyName = rows[idx][1].trim();
    var shopName = rows[idx][2].trim();
    if (!(companyId && companyName)) {
      Logger.log("不正なデータ" + idx + "行目");
      continue;
    }

    if (!shopName) {
      shopName = "本店";
    }

    var dirUrlList = Lib.createDirList(outputDir, companyName, shopName, shopDefaultDirs);
    Lib.saveSsRow(exportSs, idx + 1, [companyId, companyName, shopName, dirUrlList.shopDirUrl]);
  }

  Lib.deleteTrigger(triggerKey);
  properties.deleteProperty("startIdx");
  Logger.log("完了!");
}