Googleフォーム入力完了時に、Kintoneのアプリ上でレコードを自動生成する

初投稿です:beginner:
筆者は飲食業界のDXを目的としたITベンダーで
営業企画・コールセンターのSV・データアナリスト等を担当しています。

## 目次

1.背景と目的
2.事前の環境準備
3.コード作成
4.実行結果
5.参考文献

## 1.背景と目的
- **Kintoneのアカウントを持っていない外部のメンバーに、
ログインせずにレコードを作成してほしい**

筆者の所属するコールセンターでは、
アウトバウンドコールによる商談アポの獲得を外部業者に委託し、
また顧客管理のためにKintoneを使用していますが、
機密情報が数多く記載されたKintoneに彼らをログインさせたくない、
社内の人間のみKintoneにログインできるような形を取りたい・・・という
要望がありました。

そこで、
**外部のメンバーにはGoogleフォーム上でアポ情報を入力してもらい、
その回答終了と同時に、自動的にKintone上でレコード情報が生成されれば良い、**
と考え、以下のようなシステムを構築しました。

## 2.事前の環境準備
### Googleフォームの用意
まず、Googleスプレッドシートを新規作成して、
アポ獲得時に記録が必要な項目を設問として設けます
（Googleフォームの作成方法の詳細については、ここでは割愛します）。

作成したGoogleフォーム上で何度かテスト回答を行い、
問題なく回答が出力されることを確認したら、
ひとまずGoogleスプレッドシートとGoogleフォーム側の準備は完了です。


### Kintoneのアプリの用意
今回の例ではアプリを新規作成します。
（Kintoneのアプリ作成方法の詳細についても、ここでは割愛します）。

この時、可能であれば
**各フィールド名・フィールドコードはGoogleフォームの各設問項目とまったく同じ、
もしくは近い内容にしておく**と、
次のコードを書くステップで作業がしやすくなります。

新規作成したアプリ上で、問題なくレコードが作成できることを確認したら、
Kintone側の準備も完了です。
ここから、GoogleフォームとKintoneを自動連係するためのコードを書いていきます。

## 3.コード作成

### GASエディタの準備とやりたいことの整理

今回のコード作成ではGASを使用します。
先ほど作成したGoogleスプレッドシート上で、
GASの編集（エディタ）画面を開きます。
（エディタ画面の編集方法の詳細についても、ここでは割愛します）。

先に、今回やりたいことを大まかに整理しておくと、

- **Googleフォームの回答を取得する**
- **Kintoneのアプリ上のどのカラムに回答内容を出力するかを、設問別に指定する**
- **取得した回答内容を、実際にKintoneに自動連携する**

となります。
以下、上記の順を追って書いていきます。

#### スクリプト全体の構成を整えながら、Googleフォームの回答を取得する

まず、以下のように書きます。
（関数名は任意ですが、今回は「Kintone自動接続テスト」とします）

    function Kintone自動接続テスト() {
      'use strict';
      const itemResponses = e.response.getItemResponses();  //Googleフォームの回答を取得
      const records = '[';
         //ここで、設問ごとにKintoneのアプリ上のどのカラムに回答内容を自動出力するか、を書きます
      records += ']';
    Logger.log('Response JSON is "%s"', records);
    return records;
    }

##### <3行目　const itemResponses…>
変数itemResponsesを宣言し、getItemResponsesメソッドによって
後述する別の関数の戻り値を取得し、変数に格納するようにあらかじめ記述しています。

##### <4行目　const records…>
今回はJSON形式でデータを取得してKintoneに連携するため、
格納用の変数recordsを宣言しています。
このデータ数は、後述のようにGoogleフォームの回答によって増減しますが、
いずれにせよ最後に角カッコを閉じる必要があるため、
6行目で変数の最後に"}"を追記します。

##### <7行目　Logger.log…>
コード実行後のJSONリクエストの成否をログ出力します。

##### <8行目　return…>
関数の処理を終了し、処理結果を返します。


### Kintone上の出力先カラムを、Googleフォームの設問別に指定する

先ほどのスクリプトに、以下のように追記します。
今回の例では、Googleフォーム上に
「企業ID」「アサイン希望」「今回の商談のポイント」「至急？」
というタイトルの設問があり、それに対応するKintoneのカラム名を
「企業ID」「アサイン希望営業」「今回の商談のポイント」「至急」
とします。

    function Kintone自動接続テスト() {
      'use strict';
      const itemResponses = e.response.getItemResponses();//Googleフォームの回答を取得
      const records = '[';
      for (const i = 0; i < itemResponses.length; i++) {　//1問目から最後の設問まで
        const itemResponse = itemResponses[i];
        switch (itemResponse.getItem().getTitle()) {    //switch文で条件分岐
    　　　//以下、設問ごとにKintone上の連携先を指定
          case "企業ID":
          records += Utilities.formatString(',"企業ID" : { "value": "%s" }',itemResponse.getResponse()); 
          break;

          case "アサイン希望":
          records += Utilities.formatString(',"アサイン希望営業" : { "value": "%s" }',itemResponse.getResponse());
          break;

          case "今回の商談のポイント":
          records += Utilities.formatString(',"今回の商談のポイント" : { "value": "%s" }',itemResponse.getResponse());
          break;    

          case "至急？":
          records += Utilities.formatString(',"至急" : { "value": "%s" }',itemResponse.getResponse());
          break;
        }
      }
      records += ']';
    Logger.log('Response JSON is "%s"', records);
    return records;
    }

##### <5行目　for…>
変数iを宣言し、
**Googleフォーム上の設問数分**、繰り返し処理を実行します。
JSON形式でデータ取得する場合、配列に値を格納することになるので、
**変数iに格納する要素番号は、実際の設問番号nから1を引いた数**として考える必要があります。
（今回であれば設問1の配列上の要素番号は[0]、設問4は[3]）

そこで、for文を記載する際には、
最初の設問番号から（i = 0;）
最後の設問番号未満の整数まで（i < itemResponses.length;）、
1ずつ数字を増やしていく（i++）、という形で繰り返し条件を指定します。

##### <6行目　const itemResponse…>
変数itemResponseを宣言し、
繰り返し処理ごとにGoogleフォーム上の設問の内容を取得します。

##### <7行目　switch…>
switch文を使用して、以下
**変数itemResponseで取得した設問のタイトル（ .getItem().getTitle() ）によって、
Kintoneの連携先を分岐させる**
という条件を書いていきます。

※今回の例ではGoogleフォームの設問タイトルが
「企業ID」「アサイン希望」など、体言止め形式になっていますが、
「企業IDを入力してください。」など、文章形式でも構いません。
その場合、上記スクリプト中のformatStringメソッドの第二引数にも
まったく同じ文章を入れます。

##### <8行目　case…>
まずは設問タイトルが"企業ID"の場合、
9行目で、変数recordsの格納内容に設問の回答をJSON形式で追記するとともに、
kintoneの連携先のカラムのフィールドコードを指定します。

**※先のステップで、フィールドコードをGoogleフォームの設問項目と同じにしておくと
　ここで作業しやすくなります。**

10行目で、その処理を終了して次の繰り返し処理へ進みます（break）。

以下同様に、設問ごとに分岐条件を指定して、
Kintone上のカラムを指定します。
※上記例では設問数が4になっていますが、実際の設問数に合わせて増減します。

すべて終わったところで、こちらの関数は完成です。

### 取得した回答内容を、実際にKintoneに自動連携する

続けて、先ほどの関数で3行目に記述した"e"を引数とする
別の関数を同じスクリプト上で作成します。
今回、Kintone上の連携先アプリ名は「テスト用アプリ」とします。

    function sendToKintone(e) {
      'use strict';
      const subdomain = "************.cybozu.com";  //サブドメイン名
      const apps = {
        YOUR_APPLICATION1: { appid: *, name: "テスト用アプリ", token: "****************************************" }
      };//Kintone上のappid、アプリ名、token（APIトークン）を指定

      const manager = new KintoneManager.KintoneManager(subdomain, apps);
      const str = getFormResponse(e);
      str = str.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
      const jsonrecords = JSON.parse(str);
      const response = manager.create("YOUR_APPLICATION1", records);//kintone レコードの生成

      const code = response.getResponseCode();  // ステータスコード（成功すれば200になる）
      Logger.log('Response code is "%s"', code);
    }

##### <3行目　const subdomain…>
Kintoneのポータル画面上で画像の箇所を確認して、
レコード出力先のKintoneのサブドメイン名を書きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2799869/4ffb3429-85bb-c12a-f952-bbd41c2e12cb.png)

##### <4行目　const apps…>
変数appsを宣言し、さらにその中で任意のアプリ名を定義し
（今回は"YOUR_APPLICATION1"とします）、
出力先のKintoneのappid、アプリ名、token（APIトークン）を指定します。

appidは実際のアプリ画面上から確認でき（2本のスラッシュ「/」の間の値）、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2799869/62688800-c632-a142-11b7-5b318bd6b594.png)

また、APIトークンは画像の箇所から設定・確認ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2799869/aafcccf7-2fc1-0ce6-9127-09f5b90d004b.png)

「アクセス権」として、
最低限「レコード閲覧」「レコード追加」は指定しておいてください。
トークンの新規生成時は、「保存」⇒「アプリの更新」を忘れないように注意します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2799869/feb67fe7-8073-c1db-e60b-d93c0a4d1281.png)

##### <8行目　const manager…>
変数managerを宣言してkintoneManagerライブラリを取得し、
別操作が影響しないようライブラリを初期化します。

##### <9行目　const str…>
変数strを宣言して、getItemResponsesメソッドによって、
Googleフォームの回答を取得します。
10行目では、JSON形式で読み込むため、Googleフォームの回答の文字列の置換を行い、
次の11行目で変数jsonrecordsを宣言し、JSONデータをパースした値を格納しています。

##### <12行目　const response…>
変数responseを宣言して、kintone上でレコードを生成して、一連の操作は完了です。

エラー確認のため、最後に14～15行目でステータスコードを取得し、
実行ログとして出力しています。

以上すべての完了後、Googleフォーム上でテスト回答をしてみると、
Kintoneの指定したアプリ上に回答が反映されていることが確認できるはずです。



## 4.実行結果
本システムの実装により、
**Kintoneのログイン・閲覧権限は限られた社内のメンバーのみに付与し、
一方でKintone上でのレコード生成自体は誰でも実施可能にする**、
という当初の目的が実現できました。

アポ獲得者から一度別ツールやメールなどで連絡して、
ログイン権限を持っている社内のメンバーがアポ情報を手動でKintoneに打ち込む
・・・という従来の方法のために生じていた、
- 特定のメンバーに作業負担が集中する
- 外部から社内への情報の伝達ミスが起きたり、レコードの入力漏れが発生する

という課題が解消され、また作業スピードも格段に速くなったために、
結果的に架電数やアポ獲得数、商談数など、
**コールセンターとしての実績も大きく向上**する結果となりました。

一方で、今回の方法では
- **レコード作成はできるものの、修正や削除は
アカウントを持っているメンバーで対応しないといけない**

という課題が残っているので、
今後はこの解決策を模索していこうと思います。

またKintoneの仕様上、レコードが生成されたことが分かりづらい
という課題もあり、現在この解決を求められています。

筆者の所属する会社では、社内の連絡用ツールとしてSlackを使用しているので、
今後、本記事の内容に続く形で、
- **「Googleフォーム入力によるKintoneのアプリ上でレコード生成時に、
Slack上にも自動でメッセージを飛ばす」**

仕組みについても、引き続き記事化していこうと考えています。

最後までお読みいただきありがとうございました。:smiley:
本記事の最終更新日：2022年11月6日


## 5.参考文献

Google フォームとkintoneを連携してみよう！（最終閲覧日：2022年11月6日）
https://developer.cybozu.io/hc/ja/articles/115003856483-Google-%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%A8kintone%E3%82%92%E9%80%A3%E6%90%BA%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86-