【LineAPI×GAS】②新規開拓営業マンとマネージャー層向けLINEbot

# 目標
<img width="400px" alt="arrow.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/d7064462-da5b-0830-f540-8c3708529e7f.jpeg">

終了をトリガーとして、その日の行動件数等を入力し、
平均などと比較した上での評価を出力するbotを作成していきます。

※javascript上で完結するのが難しかったため、
　スプレッドシートの関数も使用しております。

# 実際に使用したもの

- GAS(Google Apps Script)
- LINE Messaging API
- Googleスプレッドシート

※完全に理解できていない部分もありますが、大目に見て頂けますと幸いです。

# 流れ
1 LINEのMessaging APIを作成する
2 Googleスプレッドシートを編集する
3 GoogleAppsSpreadsheetを編集する
4 deployを行う

今回は3、4をご紹介します。
※１，２に関しては[こちら](https://qiita.com/japwork/items/89aca2edd79778a4cf67)

# GoogleAppsSpreadsheetを編集する
## GoogleAppsSpreadsheetの変更手順
1 編集したスプレッドシートを開く
2 画面上部のツールを選択
3 スクリプトエディタを開く
![googlespreadsheet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/9b969d6b-f11f-3ace-c661-a6020b86d326.png)


## 実際にコードを記入する
完成版はこちら

```js:
const ACCESS_TOKEN = "ここにLINEのMessaging API設定の下部にあるチャネルアクセストークンを貼り付け";
const HEADERS = {
  "Content-Type": "application/json; charset=UTF-8",
  "Authorization": "Bearer " + ACCESS_TOKEN
};
const url = "https://api.line.me/v2/bot/message/reply";
const SHEET = 'スプレッドシートのURLにあるIDを貼り付け';
const ss = SpreadsheetApp.openById(SHEET).getSheetByName("行動履歴");

function replyMessage(replyToken, message) {
  let url = "https://api.line.me/v2/bot/message/reply";
  let postData = {
    "replyToken": replyToken,
    "messages": [{
      "type": "text",
      "text": message
    }]
  };
  let options = {
    "method": "POST",
    "headers": HEADERS,
    "payload": JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);
}

function isNumber(val) {
  let regexp = new RegExp(/^([1-9]\d*|0)$/);
  return regexp.test(val);
}


function doPost(e) {
  let webhookData = JSON.parse(e.postData.contents).events[0];
  let replyToken = webhookData.replyToken;
  let message = webhookData.message.text;

  if(ss.getRange("A1").getValue() == 0 ){
    if (message === "終了") {
      ss.getRange(1, 1).setValue(1);
      var text = "本日もお疲れさまでした！\n本日の行動量を入力してください。";
      return replyMessage(replyToken, text);
    }else{
      var text = "「終了」と入力すると行動を記録出来ます。";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 1 ){
    if(isNumber(message)){
      if(message == 0){
        ss.getRange(1, 1).setValue(0);
        var text = "行動量は" + message + "件だね！\n今日は忙しかったかな？明日はしっかり行動しよう！";
        return replyMessage(replyToken, text);
      }else{
        for(let i = 4; i <= 30; i++){
          if(!ss.getRange(i, 2).getValue()){ 
            ss.getRange(i, 2).setValue(message);
            break;
          }
        }
        ss.getRange(1,1).setValue(2);
        var text = "行動量は"+ message + "件だね！\n次は通電数を教えて！";
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 2 ){
    if(isNumber(message)){

      var ss_range = ss.getRange("B:B").getValues();
      var lastRow = ss_range.filter(String).length;

      if(message > ss.getRange(lastRow, 2).getValue()){
        var text = "通電数が行動量を上回ています。もう一度入力してください。";
        return replyMessage(replyToken, text);
      }else{
        ss.getRange(lastRow, 4).setValue(message);
        ss.getRange(1, 1).setValue(3);
        var text = "通電数は"+ message + "件だね！\n次はアポ獲得数を教えて！";
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 3 ){
    if(isNumber(message)){
      var ss_range = ss.getRange("B:B").getValues();
      var lastRow = ss_range.filter(String).length;
      if(message > ss.getRange(lastRow, 4).getValue()){
        var text = "アポ数が通電数を上回ています。もう一度入力してください。";
        return replyMessage(replyToken, text);
      }else{
        ss.getRange(lastRow, 6).setValue(message);
        ss.getRange(1, 1).setValue(0);
        var text = "アポ数は"+ message + "件だね！\nまとめると・・・\n\n" + ss.getRange(lastRow, 9).getValue();
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }
}
```

それぞれ補足していきます。
##　LINEのAPIを使用するための設定
ここはそのままコピーしてお使いしてください。

```js:
const ACCESS_TOKEN = "ここにLINEのMessaging API設定の下部にあるチャネルアクセストークンを貼り付け";
const HEADERS = {
  "Content-Type": "application/json; charset=UTF-8",
  "Authorization": "Bearer " + ACCESS_TOKEN
};
const url = "https://api.line.me/v2/bot/message/reply";
```
##　スプレッドシートを使用するための設定

```js:
const SHEET = 'スプレッドシートのURLにあるIDを貼り付け';
// https://docs.google.com/spreadsheets/d/この部分のIDを貼り付け/edit#gid=0

const ss = SpreadsheetApp.openById(SHEET).getSheetByName("行動履歴");
// 行動履歴のシートを参照しています。
```

##　Linebotからメッセージを返信するための設定
ここはそのままコピーしてお使いしてください。

```js:
function replyMessage(replyToken, message) {
  let url = "https://api.line.me/v2/bot/message/reply";
  let postData = {
    "replyToken": replyToken,
    "messages": [{
      "type": "text",
      "text": message
    }]
  };
  let options = {
    "method": "POST",
    "headers": HEADERS,
    "payload": JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);
}
```
##　送信されたメッセージが０以上の数字かどうかを判定するための設定
ここはそのままコピーしてお使いしてください。

```js:
function isNumber(val) {
  let regexp = new RegExp(/^([1-9]\d*|0)$/);
  return regexp.test(val);
}
```

##　返信する内容を設定
この部分に条件分岐を記述し、LINEbotの返信内容を決めます。
今回はA1セルに数字を入力し、その値に応じて処理を変更しています。

```:反応処理
A1セル = 0 の場合　終了と入力されるとA1セル = 1を代入し行動量入力に進む。
A1セル = 1 の場合　数字が入力されるとA1セル = 2を代入し通電数入力に進む。
A1セル = 2 の場合　数字が入力されるとA1セル = 3を代入しアポ獲得数入力に進む。
A1セル = 3 の場合　数字が入力されるとA1セル = 0を代入し、今までの値に対する評価を送信する。
```
```js:
function doPost(e) {
  let webhookData = JSON.parse(e.postData.contents).events[0];
  let replyToken = webhookData.replyToken;
  let message = webhookData.message.text;

  if(ss.getRange("A1").getValue() == 0 ){
    if (message === "終了") {
      ss.getRange(1, 1).setValue(1);
      var text = "本日もお疲れさまでした！\n本日の行動量を入力してください。";
      return replyMessage(replyToken, text);
    }else{
      var text = "「終了」と入力すると行動を記録出来ます。";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 1 ){
    if(isNumber(message)){
      if(message == 0){
        ss.getRange(1, 1).setValue(0);
        var text = "行動量は" + message + "件だね！\n今日は忙しかったかな？明日はしっかり行動しよう！";
        return replyMessage(replyToken, text);
      }else{
        for(let i = 4; i <= 30; i++){
          if(!ss.getRange(i, 2).getValue()){ 
            ss.getRange(i, 2).setValue(message);
            break;
          }
        }
        ss.getRange(1,1).setValue(2);
        var text = "行動量は"+ message + "件だね！\n次は通電数を教えて！";
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 2 ){
    if(isNumber(message)){
      
      // 行動量が入力された最終行を取得しています。
      var ss_range = ss.getRange("B:B").getValues();
      var lastRow = ss_range.filter(String).length;

      if(message > ss.getRange(lastRow, 2).getValue()){
        var text = "通電数が行動量を上回ています。もう一度入力してください。";
        return replyMessage(replyToken, text);
      }else{
        ss.getRange(lastRow, 4).setValue(message);
        ss.getRange(1, 1).setValue(3);
        var text = "通電数は"+ message + "件だね！\n次はアポ獲得数を教えて！";
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }

  if (ss.getRange("A1").getValue() == 3 ){
    if(isNumber(message)){
      var ss_range = ss.getRange("B:B").getValues();
      var lastRow = ss_range.filter(String).length;
      if(message > ss.getRange(lastRow, 4).getValue()){
        var text = "アポ数が通電数を上回ています。もう一度入力してください。";
        return replyMessage(replyToken, text);
      }else{
        ss.getRange(lastRow, 6).setValue(message);
        ss.getRange(1, 1).setValue(0);
        var text = "アポ数は"+ message + "件だね！\nまとめると・・・\n\n" + ss.getRange(lastRow, 9).getValue();
        return replyMessage(replyToken, text);
      }
    }else{
      var text = "[エラー] 数字だけを入力してください";
      return replyMessage(replyToken, text);
    }
  }
}

```

# まとめ
javascriptのコードの意味は今回は割愛しますが、
const、var、let、if、for、return
スプレッドシートのコードとしては
getRange、getValues、getValue、setValue
このあたりの意味を理解できれば、目標物のものは作れるかと思います。

Linebotの制作に取り掛かり始めた人の参考になれば幸いです。