kintoneとSlackの連携でプロセス管理をチャンネルメンション通知する方法


本エントリは iCARE Advent Calender 2020 の13日目です。

普段はCRMとして顧客管理を担当している私が、僭越ながらアドベントカレンダーで、
JavaScriptを使用したkintoneのカスタマイズについて書かせていただきます。
私自身は、エンジニアではなく、決してプログラミングがスラスラできるわけではなく、
普段は色んな方の記事を参考にしたコピペアレンジを中心にkintoneカスタマイズをしています。

今回、kintoneとSlackを連携し、プロセス管理でステータスが変更された時にSlackのチャンネルへメンションをつけて通知させた方法について書きます。

◯はじめに
弊社では、顧客管理システムとしてkintoneを使っており、
・セールスサイドでは、商談相手であるクライアントの情報から商談記録など
・受注後にはカスタマーサクセス(以下CS)での運用(オンボーディング記録、ヘルススコア管理、請求)など
の情報を全て管理しています。
セールスと一部の部署ではを利用していたのですが、CSでは導入が進んでいなかったため、今年はCS活動を中心とした受注以降の管理としてkintoneの導入・運用を進めてきました。

これまで案件受注時の情報引継ぎはSlackで行っていたのですが、
・そもそもSlackでは引継ぎ情報の蓄積ができない
・引継ぎ情報とフローがきちんと定型化できていない
・担当者が変わったときに、導入時の情報がすぐ見られない(検索をして遡らないといけない)
等々、多くの負を抱えていたため、今回kintoneを使って業務改善を行うことを決めました。

引継情報自体をkintoneで管理することとはそこまで難しくなかったのですが、
CS担当者を決めるプロセスであったり、先方へ連絡をするタイミングおよび連絡をしたかどうかの管理をどのようにするか、そして一番悩んだのは、社内コミュニケーションとして使用しているSlackのチャンネルに通知する方法でした。

というのも、kintoneに標準で用意されているSlack通知は、「プロセス管理でレコードの作業者になったユーザーにSlackのダイレクトメッセージで通知する」ものであり、チャンネルで通知できるものではないからです。また、チャンネルへ通知できたとしても、当事者だけに通知をする(担当者以外の人が余計な通知を受け取らない)ためにメンションで通知をする方法も必要だと考えて、模索しました。

kintoneとSlackの連携

今回のベースとなるkintoneとSlackの連携は、こちらの記事を参考にしました。
Incoming Webhookを使用することで、DMではなくチャンネルへの通知を可能にしました。
kintoneからSlackに通知を送る方法

メンションでのSlack通知

メンションをつけた通知は、こちらの記事を参考にしました。
テキストで "@ホゲホゲ" と書いてもテキストにしかならず、メンションに記法があることには要注意です。
SlackのIncoming Webhooksでメンションを飛ばす方法

SlackIDの管理(今回のポイント)

上の記述から、メンションでのSlack通知には、slackIDが必要なことが分かったかと思います。
SlackIDをどのように担当者に紐付けるかが肝になる訳ですが、私は担当者名とSlackIDをセットで持たせた別アプリで管理をすることにしました。
理由は、
「プロセス管理で作業者を割り当てるためにはユーザー選択フィールドが必要であるが、ルックアップ元の値としてユーザー選択のフィールドは指定できない。ただ、他のフィールドへのコピーでユーザー選択の値を反映させることはできる。」
からです。
そのため、担当者名をルックアップフィールドに入れて、担当者名に紐づくSlackIDとユーザー選択の値を取得することにしました。

元々、担当者名を入力して、ルックアップで別のアプリから値を取得することをしていたため、この社内担当者マスタを作っていまいした。なので、今回運が良かったなと思っています。
若干、【cybozu.com 共通管理】のユーザー設定で管理できる内容と重複していて、二度手間な部分はあるのですが、ルックアップのためです。仕方ありません(笑)

担当者情報を管理するアプリ。ここで、SlackIDの情報を持たせています。

社内担当者のアプリの担当者(フルネーム)をルックアップ元の値にしています。
担当者名を入れることで、SLMK_担当者SlackIDとSLMK担当者ユーザーの値が取得されます。

レコードには、最終的にこのような感じでそれぞれに値が入ります。
(実際は、プロセス管理にアクションが実行できる条件を設定しており、所定のフィールドに値が入力されていないとプロセス管理を進めることができないように設定しています。そのため、プロセス管理を進めながら、徐々に担当者が決まって値が入っていきます。)

そして、プロセス管理を進めていくことで、該当担当者に対してSlackにメンションをつけて通知を送ることができます。
実際は案件の引継ぎだけでなく、運用開始後の請求に関しても、上長確認のフローを入れており、請求漏れ・請求ミスもなくすようにしています。

以下、実際のアプリで使用したJavaScriptカスタマイズで使用したコードです。
(未熟故、非効率な書き方には目をつぶって、こっそり教えていただけると嬉しいです。)

(function() {
    "use strict";

    const field = {
      service : 'サービス',
      client_name : '企業名',
      slmk_name : 'SLMK_担当者名',
      cs_name : 'CS_担当者名',
      check_name : '請求可否確認_担当者名',
      slmk_slackID : 'SKMK_担当者SlackID',
      cs_slackID : 'CS_担当者SlackID',
      check_slackID : '請求可否確認_担当者SlackID',
    };

    kintone.events.on("app.record.detail.process.proceed", function(e) {
        const condition = e.nextStatus.value;
        let service = e.record[field.service].value;
        let payload_text;
        let payload_mention;
        var thisUrl = "https://icare.cybozu.com/k/" + kintone.app.getId() + "/show#record=" + kintone.app.record.getId();
        var webhookUrl = 'https://hooks.slack.com/services/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';

        switch(condition) {
          case "SLMK入力中":
              payload_mention = "@" + e.record[field.slmk_slackID].value;
              payload_text = "」の引継用レコードが作成されました。入力をお願いします!!";
               break;
          case "アサイン依頼中":
              payload_mention = "!subteam^SV8SB3EUX";
              payload_text = "」がアサイン依頼中になりました。担当者を決めて下さい!! 担当者に決まったら、HRS_PS_担当者名に名前を入力して、ステータスを変更して下さい。";
              break;
          case "SLMKメール送付前":
              payload_mention = "@" + e.record[field.slmk_slackID].value + "> <" + "@" + e.record[field.hrs_ps_slackID].value;
              payload_text = "」の担当者が、" + e.record[field.hrs_ps_name].value + "に決まりました。引継ぎメールを送付したら、ステータスを変更してください。HRSへ通知されます。企業フォルダをCS側へ移動させるのもお忘れなく! ";
              break;
          case "HRS_PS_メール送付前":
              payload_mention =  "@" + e.record[field.hrs_ps_slackID].value;
              payload_text = "」の引継ぎメールを" + e.record[field.slmk_name].value + "が送りました。後追いメールを送って引継ぎを完了させて下さい。";
              break;
          case "引継完了":
              payload_mention = "@" + e.record[field.slmk_slackID].value;
              payload_text = "」の引継ぎメールを" + e.record[field.hrs_ps_name].value + "が送りました。引継ぎ完了です。オンボーディング頑張ります!!!!";
              break;
          case "担当者請求可否入力済":
              payload_mention = "@" + e.record[field.check_slackID].value;
              payload_text = "」の請求可否確認を入力しました。確認をお願いします!!";
              break;
          case "請求可否確認済":
              payload_mention = "@UD1HALBRP" ;
              payload_text = "」の請求可否確認が完了しました。請求書発行の準備をしなさい。";
        }

        if(payload_text !== undefined){
          var payload = {
              "text": "<" + payload_mention + ">"  + " 「" + e.record[field.client_name].value + payload_text + thisUrl

        };
        return new kintone.Promise(function(resolve, reject) {
            kintone.proxy(webhookUrl, 'POST', {}, payload, function(body, status, headers) {
                console.log(status, body);            
                    resolve(e);
                });

            });

         }

    });
})();

まとめ

こんな風に、コピペを中心に自分でも勉強をしながらやっていはいますが、実際は知識不足でうまく動作せず、行き詰まることもあります。
そんな時に、弊社エンジニアの方々は優しく、気軽に質問に答えてくれます。
本当にありがたい限りで、いつも感謝しています。

そんな、素敵なエンジニアの方々の日々のブログもぜひご覧ください。
iCAREテックブログ