【業務改善】GASを使って業務フローを改善した話

## 目次

- [本記事の対象者](#本記事の対象者)
- [こんなの作りました](#こんなの作りました)
- [解決した課題](#解決した課題)
- [こんな導線です](#こんな導線です)
    - [Googleフォームのデータ設計](#Googleフォームのデータ設計)
        - [挫折ポイント](#挫折ポイント)
    - [GASからスプレッドシートの転記](#GASからスプレッドシートの転記)
    - [GASからカレンダーに転記](#GASからカレンダーに転記)
        - [工夫した部分](#工夫した部分)
- [最後に](#最後に)
- [参考した記事](#参考した記事)

## 本記事の対象者

:::note info
・社内向けに情報共有をしやすい仕組みを考える方
・抜け漏れを防げたい方
:::

## こんなの作りました

事務職と営業に繋ぐワークフローを再構築の一環で、
スプレッドシート登録、Slack報告とカレンダー登録の作業を、Google Formとスプレッドシート二つで完結させました。

```mermaid
graph TD;
    GoogleFormから商品登録-->スプレッドシートから取得した内容を別シートに転記;
    スプレッドシートから取得した内容を別シートに転記-->転記した内容を1クリックでカレンダー登録;
    転記した内容を1クリックでカレンダー登録-->一連の作業を1クリックでSlackに報告;
```

## 解決した課題

:::note warn
一言で言うと、作業フローを改善し、報告、入力を最小限にした。
:::

今までの問題はコレです↓↓↓
```mermaid
graph TD;
    A_報告_商品を出すの決めましたけど_日程未定-->B_決まったら教えてください;
    B_決まったら教えてください-->B_商品出す日程どうなってますか;
    B_商品出す日程どうなってますか-->A_カレンダーに記入したよ;
    A_カレンダーに記入したよ-->B_Slackに上がってこなかった_スプシも未記入;
    B_Slackに上がってこなかった_スプシも未記入-->A_手が回らなかった_ごめん_間に合うようにお願いします
    A_手が回らなかった_ごめん_間に合うようにお願いします-->B_,,,,,,
```

こうやって、本物の悪者のいない悲劇が日々起きてます。
システムを改善するため、作業流れを少なくしたくて、GASでちょいロボットを作ってみました。

おさらい！！　今までの流れ：

```mermaid
graph TD;
    口頭報告-->Slackの専用チャンネル報告;
    Slackの専用チャンネル報告-->カレンダー記入;
    カレンダー記入-->シート記入;
```

同じ情報何度も記入すると、だんだん抜け漏れあったり、やりたくない感情が湧いてくるのもわかります。だったら、少なくして、必要な情報だけ振り分ければいいやん！と思って、ちょいロボットを作成しました！！

```mermaid
graph TD;
    GoogleFormから商品登録-->スプレッドシートから取得した内容を別シートに転記;
    スプレッドシートから取得した内容を別シートに転記-->転記した内容を1クリックでカレンダー登録;
    転記した内容を1クリックでカレンダー登録-->一連の作業を1クリックでSlackに報告;
```


## こんな導線です

必要な項目をGoogle Formに記入し、自動書き出しのスプレッドシートから、必要な情報だけ別のシートに振り分け、最後に、Googleカレンダーに転記して、完成!! 

項目の中、この情報をGoogleカレンダーに自動転記できたら、重複作業 & 抜け漏れが減らせます。

### Googleフォームのデータ設計

Google Formからスプレッドシートにデータを落とすとき、全部横へ展開しますので、最初はここの処理をまず必要です。
理想な形は商品、イベント回数を縦に管理したいところですが、Google Form経由だと不可能なので、このような設計になりました。

商品分類はパッと見てわかるように、種類を２段階に分けて、プルダウン形式で記入させます。
日付もイベント回数に沿って、イベント日を入力していただくことにしました。記入漏れを発見しやすくためです。

<table>
<th>商品名
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>イベント回数</th>
<th>1日目</th>
<th>2日目</th>
<th>3日目</th>

<tr>
<td>B</td>
<td> </td>
<td>B1</td>
<td> </td>
<td> </td>
<td>3</td>	
<td>2023/12/02</td>	
<td>2023/12/09</td>	
<td>2023/12/10</td>
</tr>
<td>C</td>
<td> </td>
<td> </td>
<td>C1</td>	
<td> </td>
<td>1</td>	
<td>2023/11/15</td>
<td> </td>
<td> </td>
</tr>
</table>

### GASからスプレッドシートの転記

```
function 転記と振り分け() {
  // ソースシート
  var source_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('ソースシート');
  
  // 転記先のシート
  var target_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('転記シート');

  // ソースシートからデータを取得
  var data_range = source_sheet.getRange(2, 1, source_sheet.getLastRow() - 1, source_sheet.getLastColumn());
  var data = data_range.getValues();
  
  // ターゲットシートのヘッダーを設定
  target_sheet.getRange(1, 1).setValue("記入状況");
  target_sheet.getRange(1, 2).setValue("日付");
  target_sheet.getRange(1, 3).setValue("イベント");

  // ソースデータを処理して振り分け
  for (var i = 0; i < data.length; i++) {
    // 1列目が"済"の場合はスキップ
    if (data[i][0] === "済") {
      continue;
    }

    var product = "";
    for (var col = 3; col <= 5; col++) {
      // 2, 3, 4の列を順番に確認し、最初に見つかったデータを商品名として扱う
      if (data[i][col] !== "") {
        product = data[i][col];
        break;
      }
    }
    var イベント = data[i][3];
    
    // 商品名が空でない場合のみ処理を行う
    if (product !== "") {
      for (var j = 1; j < 10; j++) { // 商品名がある列の数に応じて変更
        var 日付 = data[i][j + 7];
        var イベント = product + "イベント" + (j + 0) + "日目";
        
        // すでにターゲットシートに転記されていないかつ「済」でない場合に振り分ける
        if (日付 !== "" && !Transcribed(target_sheet, 日付, イベント)) {
          target_sheet.appendRow(["", 日付, イベント]);
        }
      }
      
      // 転記が完了したら、ソースシートの1列目に"済"を記入
      source_sheet.getRange(i + 2, 1).setValue("済");
    }
  }
}
```

### **挫折ポイント**　
1 
最初の構想では、転記できたら、転記シートに済を記入したらいいね！と思ったが、なかなかうまくいかず、ソースのシートに済と記入した方が、データ自体が使用済みになるので、`source_sheet.getRange(i + 2, 1).setValue("済");` こちらによって、同じデータ２度と転記されないようにできています。


2
Google Formをベースにしたので、Google Formの型から逆算して考えなきゃ行けなかったので、for文が大したうまくない自分にとって、`商品`と`日付`の処理はやや面倒くさかった。

```
// 指定された日付とイベントがすでに転記されているかどうかを確認する関数
function Transcribed(target_sheet, 日付, イベント) {
  var lastRow = target_sheet.getLastRow();
  
  if (lastRow <= 1) {
    return false; // シートにデータがない場合は転記されていないとみなす
  }

  var range = target_sheet.getRange(2, 2, lastRow - 1, 2).getValues(); // 日付とイベントの列を取得

  for (var i = 0; i < range.length; i++) {
    if (range[i][0] === 日付 && range[i][1] === イベント) {
      return true; // 転記されている場合はtrueを返す
    }
  }

  return false; // 転記されていない場合はfalseを返す
}
```





### GASからカレンダーに転記

8割こちらの記事を参考して作成しました。すごく読みやすいコードで、ぜひ!!

https://www.whizz-tech.co.jp/3996/


#### **工夫した部分**
1. ソースデータの最初の1列に「済」が入ったら、同じデータを振り分けないようにする。
1. Googleカレンダーに転記済みのものを「済」とマークする。[←こちらの記事でほぼできます。](https://www.whizz-tech.co.jp/3996/)
1. カレンダーに転記したらSlackに商品作成報告する。


## 最後に

年末なので、ちょい振り返り!! 

去年からプログラミングを学んで、一番大きな変化は、GASを使って効率化により、実現したかった職場環境を手に入れつつである。人間がやっても、GASで組んでも結果が一緒なら、自動化しよう!! 

小さい仕組みを改善して、一つのタスクに関わる人が少しずついい感じに働ける環境になっていくのが楽しみです。他の言語も触ってみたけど、2023年に、一番楽しく使ってたのがGASだと思います。

最近話題になったSmartHRの動画からのメッセージのように、「仕組みで解決できるなら、やさしさで解決しない」。来年も継続的にやっていくつもりです。

https://accessibility.smarthr.co.jp/specialmovie/

そして、現在はByNameというプロダクトを手伝っていて、デザイナーからもらったデザインをコーディングしたり ^^

自分が人となかなか打ち解けないので、初対面の前に自分のプロフィールを相手に渡して、初対面の気まずさを緩和できると願ってます ^^;;;;

プロフィールをAI生成できちゃうので、ぜひやってみてください!!
ユーザー登録を待ちしております ^^

私のフライヤーはこちら↓↓

https://byn.jp/flyer/ebfca40c-d718-4d02-8a14-dfd93cb3d716

では、みなさん、
Merry Christmas & 良いお年を!!


## 参考した記事

Google Formからデータを取り出して、そっからはこの記事のコードを参考にしました。
https://www.whizz-tech.co.jp/3996/

ChatGPTにコード修正してもらいました!!