青春GAS野郎は作業効率化の夢しか見ない


はじめまして。クラウドワークスの西村と申します。
iOS/Androidアプリと、ワーカー検索周りのPOをやっています。

[クラウドワークス Advent Calendar 2018](https://qiita.com/advent-calendar/2018/crowdworks) の21日目になりました。
昨日の @kokkokokouya による [【夜も眠れない】マーケットプレイス型プロダクトが直面する3つの課題](https://qiita.com/kokkokokouya/items/f20c9295f2d2de074c0f)に引き続き、非エンジニアによるアドベントカレンダーが続いております。

今回は、POになる以前から扱っていたGoogle Apps Script（以下、GAS）を久々に触ったところ愛が止まらなくなってしまったので、情熱の赴くままにこのテーマでブログを書くことにしました。
（途中で愛が醒めかけて、執筆直前にGAS書くお仕事をなんとか取ってきて愛を取り戻したのはここだけの話にさせてください）

POになる前まではCWコンシェルジュやコンサルティンググループに所属していましたが、エンジニアが一人もいなかったので、クラウドワークスを使う企業様向けのコンサルティングや新規サービスのフィジビリティ、チーム内の業務効率化などなどあらゆるところでGASを活用していました。

自分自身は開発の業務経験は一切なく、高校生の頃にモバスペというHP作成サイトでHTMLもどきを書いて自分のブログをカスタマイズしていた程度です（しかもガラケーで!!!）。[^1]
よって、非エンジニアという立場からGASの魅力と、GASを活用してみたい人のためのアイディア集をお届けしたいと思います。

[^1]: あの頃モバスペを触っていた女子高生たちはみんなHTML/CSSに抵抗ないんじゃないかななんて仮説を持っています。


## GASのどこが愛おしいのか
### 1. 開発環境構築がいらない
これ、ほんとでかい。
Googleアカウントさえあれば始められるのです。
これだけで始めるハードルがひとつなくなりますね。

### 2. ドキュメントが豊富
公式APIドキュメントも充実していますが、日本語の記事やブログも検索してみるとたくさんヒットします。

私がGASを触り始めた時には、先に当時の上司がある程度書いてくれたコードを修正、カスタマイズするところから始めました。
なかなか上司に質問できる機会も多くなかったので、よくわからないところは自分でググるしかなかったのですが、非常に助かったのを覚えています。
ググるついでに新しいライブラリを見つけたときには機能追加してみたり、自分のスキルも広がったと思います。

### 3. Googleのアプリケーションに関わることは基本なんでもできる
非エンジニアで業務改善に課題を抱いている方々から「GASって何ができるの？」とよく聞かれます。
そんな時私は「Googleのアプリケーションに関わることは、なんでもできる」と答えるのです。

なんでもできすぎて、何ができるかイメージできないと思いますので、それに関してはこの後でアイディアをいくつか提案したいと思います。

## GASを始めたい人にありがちなこと
「GAS教えて欲しい！」とよく言われるものの「こういうことを自動化したい！」が明確になっていなくてどう教えるのがいいか悩ましい経験が多々ありました。
詳しく聞いてみると、往往にして「それ、スプレッドシートのimportrange関数でできるよ...」みたいなことも多く。。。

結構ありがちなんですが、このツールが良さそう、このツールを使えば世界が変わりそう、というツールありきで考えるより、実現したいことベースで手段を考えるのが大事なんじゃないかなと思います！

これからGASによる業務効率化を始めてみたい方は、まずは「こういうことを自動化したい」ところから考えてみることをおすすめします。

## GASでできることアイディア
PO以前の業務経験をもとに、営業やコーポレート系職種の方々にありがちな作業の中でこんなものが自動化できるよ、という例をいくつか挙げてみたいと思います。
是非みなさんも、自分の業務で自動化できる作業はないか考えながら読んでみてください。

### Googleスプレッドシートで管理されている売上進捗をGmailで通知する
毎朝スプレッドシートを開くのでもいいかもしれませんが、普段一番使っているツールで通知が届くとより便利ですよね。
この機能では、「いちいちスプレッドシートを開かなければならない」手間を削減しています。

我々はSlackに通知することが多いですが、ここではメールで通知すると想定してみます。
※メール送信は短時間に大量に送ると迷惑メール送ってる輩だとGoogle先生に認識されて怒られてしまいますので（メール送信に限らずですが）常識の範囲内で使うようにしましょうね！！！

```js:sample.gs
function sendKPIMail() {
  //KPIが記録されているシートとセルを指定し、値を取得する
  var ss = SpreadsheetApp.getActiveSheet();
  var value = ss.getRange("b2").getValue(); 
  
  var today = Moment.moment().format("YYYY年M月D日"); 
  
  var to = "hogehoge@gmail.com"; //送り先アドレス。gmail以外でも可
  var subject = today + "[テスト]KPI通知メール";//メールの件名
  var body = today + "の売り上げ報告：" + value + "万円" ;//メールの本文
  
  //メールを送信する
  MailApp.sendEmail(to, subject, body);
}
```
todayを定義している箇所は違う書き方もあるのですが今回はラクをするために、Moment.jsというライブラリを入れてます。
おすすめです。
:link: [日付＆時刻の便利ライブラリ「Moment.js」をGoogle Apps Scriptで使う方法](https://tonari-it.com/gas-moment-js-moment/)
:link: [GAS版Moment.jsライブラリで超簡単に日時の比較をする方法](https://tonari-it.com/gas-moment-issame-isbefore-isafter/)

[Utilities.formatDate(date, timeZone, format)](https://developers.google.com/apps-script/reference/utilities/utilities#formatDate(Date,String,String)) という、Google先生が用意してくれている日付フォーマットのメソッドもあるのですが、これはあくまでも文字列に変換するだけなので、日時比較をしたい場合などはやはりMoment.jsが便利だなと思います。

ライブラリには他にもいろんなものがあるみたいですので、積極的に使ってみるとまた一段上のGAS体験ができます。

### Gmailで届いたCSVデータをスプレッドシートに貼り付ける
これも、自動化できます。

この場合は
・Gmailで届いたCSVをダウンロードする
・CSVを展開する
・特定のスプレッドシートにコピペする
という作業が発生しています。これらの工数を全て削減することができます。

ただのコピペ作業を手作業でやるのは時間の無駄ですし、 **機械に任せた方がエラーが少ない** です。

```js:sample.gs
var SEARCH_TERM = "subject:通知メール"; //Gmailフォルダの検索条件
var FOLDER_ID = "hogehoge"; //添付されたCSVを格納するフォルダ

var SS = SpreadsheetApp.getActiveSpreadsheet(); //転記先のSpread Sheetを定義


//添付ファイルの取得
function fetchFile(){
  
  var myThreads = GmailApp.search(SEARCH_TERM, 0, 1); //条件にマッチしたスレッドを検索して取得
  var myMessages = GmailApp.getMessagesForThreads(myThreads); //スレッドからメールを取得し二次元配列で格納
  
  
  for(var i in myMessages){
    for(var j in myMessages[i]){
      
      var attachments = myMessages[i][j].getAttachments(); //添付ファイルを取得
      
      if(attachments != ""){
        for(var k in attachments){
          var attachmentsName = attachments[k].getName();
          
          //同名のファイルがなければフォルダに保存する
          saveToGmailFolder(attachments);
          
          //フォルダからCSVファイルを読み込み、スプレッドシートに書き込む
          import(attachmentsName);
        }
      }
    }
  }
}

//保存したいフォルダに、nameと同名のファイルがあるか確認する
function isInGmailFolder(name) {
  
  //nameと同名のファイルをGoogleDrive全体から探す
  var files = DriveApp.getFilesByName(name);
  
  
  //ヒットしたファイルの親のフォルダが保存したいフォルダと同じ場合はtrueを返す
  while (files.hasNext()) {
    var file = files.next();
    var folders = file.getParents();
    
    while (folders.hasNext()) {
      var folder = folders.next();
      if (folder.getId() === FOLDER_ID) {
        return true;
      }
    }
    
  }
  
  /*
    同名のファイルがGoogleDrive全体から見つからない場合や
    保存したいフォルダには同名のファイルが存在しない場合にはfalseを返す
   */
  return false;
}



//添付ファイルを指定のフォルダに保存する（添付ファイルが複数ある場合を想定）
function saveToGmailFolder(attachments) {

  //保存先フォルダを指定
  var folder = DriveApp.getFolderById(FOLDER_ID);
  
  //同名のファイルがすでに保存されていなければ、フォルダにファイルを保存する
  for (var i = 0; i < attachments.length; i++) {
    if (!isInGmailFolder(attachments[i].getName())) {
      var data = DriveApp.createFile(attachments[i]);
      folder.addFile(data);
    }
  }
}



//CSVファイルの内容をスプレッドシートに転記する
function import(attachmentsName) {
  
  // 対象のCSVファイルのファイル名と置かれているフォルダを定義
  var fileName = attachmentsName;
  var folder = DriveApp.getFolderById(FOLDER_ID);
  
  
  //フォルダとファイルの検索
  var files = DriveApp.getFilesByName(fileName);
  while (files.hasNext()) {
    var file = files.next();
    if (file.getName() == fileName) {
      
      //文字化け対策
      var data = file.getBlob().getDataAsString("Shift_JIS"); 
      
      
      var csv = Utilities.parseCsv(data);
      
      var sheetName = fileName
      
      //同名のシートが存在しているかどうか確認
      if( !isInSpreadsheet(sheetName)){
        
        //転記するシートを新たに追加する
        insert(sheetName);
        var sh = SS.getSheetByName(sheetName);
        
        //↑で作ったシートに、セルA1からCSVの内容を書き込んでいく
        sh.getRange(1,1,csv.length,csv[0].length).setValues(csv);
        return;
      }
    }
  }

}


//テンプレートシートを複製し、シート名を特定のsheetNameにする
function insert(sheetName){
  var templateSheet = SS.getSheetByName("シート1");
  SS.insertSheet(sheetName, {template: templateSheet});
}


//スプレッドシートに、同名のシートがすでに存在しているかどうか確認する
function isInSpreadsheet(sheetName){

  var sheets = SS.getSheets();
  
  //スプレッドシート内にあるシート数をカウント
  for( var i in sheets){
    i++;
  }

  
  for(var v=0; v < i; v++){
    
    if( sheets[v].getName() === sheetName ){
      
      //同名のシートがすでに作られていれば、trueを返す
      return true;
    } 
  }
  //同名のシートが作られていなければfalseを返す
  return false;
}
```
結構魔改造感ある...

:link: [Gmailの添付ファイルをGoogleドライブに自動保存する](http://inaab.hatenablog.com/entry/2016/09/11/172839)
このスクリプトは、こちらの記事を参考に作りました。


### 営業メンバーから、オペレーションを回すコンサルタントへ商談情報を引き継ぐ
営業メンバー→コンサルタントに商談内容を引き継ぎ、即座にコンサルタントの対応を開始する、という状況を想定しています。

弊社ではGoogleフォーム、Googleスプレッドシート、Trelloを用いてフローを構築しました。

この機能では、人から人への情報連携をスムーズにすることのほかにも、クライアントの対応進捗状況を可視化するためのTrello登録作業が自動化される、という効果もありました。

実際の流れは以下のようになっていました。

1. 商談終了次第、営業メンバーがGoogleフォームに用件を入力し送信する
2. フォームの入力内容がSlackチャンネル上に通知され、同時にTrelloに新規カードが作られる
3. コンサルタントが即座にクライアントに連絡し対応を開始する
4. 以降の対応ステータスはTrello上で管理される

2番のところが自動化ポイントですね。
※実際のコードは大人の事情もあり今回は割愛させていただきます。

TrelloAPIが鬼のように難しかったので結構つらかったことを記憶していますｗ

## 参考
 [【保存版】初心者向け実務で使えるGoogle Apps Script完全マニュアル](https://tonari-it.com/google-apps-script-manual/)
こちらのサイトはかなり網羅的に書かれているので、本当に初めての方は上から順番にやってみるといいかも。

[GASで文字コード指定してファイルを書き出す](https://qiita.com/jsoizo/items/948e23231417d203eefa)
CSVを読み込むなどテキストを処理する際に、文字化けしたり改行がちゃんと認識されなかったりすることがあります。

[日付＆時刻の便利ライブラリ「Moment.js」をGoogle Apps Scriptで使う方法](https://tonari-it.com/gas-moment-js-moment/)
[GAS版Moment.jsライブラリで超簡単に日時の比較をする方法](https://tonari-it.com/gas-moment-issame-isbefore-isafter/)
日時のフォーマットはよく使いますが、特に日時の差分をとりたい場合などはこれ入れとくと便利です。

[formatDate(date, timeZone, format)](https://developers.google.com/apps-script/reference/utilities/utilities#formatDate(Date,String,String))
単純に日時を文字列に変換したい場合にはこちらの公式メソッドで十分です。

[Gmail で使用できる検索演算子](https://support.google.com/mail/answer/7190?hl=ja)
Gmailでメール検索する際の検索方法は、GmailApp.search()でメール検索するときの検索クエリとしてそのまま使えます。

## おわりに
営業組織やコーポレート系部署には専属のエンジニアがいないことも多いと思うのですが、GASを使うことで非エンジニアでも業務の自動化・効率化ができます。
無駄だなあと感じる作業のほとんどはGASで解決できるかもしれません。

初めたばかりの方は、最初から自分でGASを書こうとすると心が折れる可能性もありますので、まずはインターネット上のあちこちに転がっているスクリプトをコピペしカスタマイズするところから始めることをおすすめします！

ちなみに、「青春ブタ野郎はバニーガール先輩の夢を見ない」はまだ観てないのですがこんなタイトルにしてしまったのでこの年末年始の宿題にしようと思っています。