kintone
投稿日:

「お客様のライフイベント、把握できていますか?」── kintoneで保険代理店の顧客フォローを自動化する

皆さんこんにちは。kintoneアプリエンジニアのtomiokaです。

先日、保険代理店のお客様から「契約者のフォローが後手に回っている」と相談がありました。

従業員12名ほどの代理店で、担当者1人あたり約300件の契約を抱えています。結婚、出産、住宅購入、退職といったライフイベントのタイミングで保障内容の見直し提案をしたいのに、気づいたときには他社に乗り換えられていた、、、、というケースが年に数件発生していたそうです。

今回は、顧客アプリにライフイベント情報を登録すると、フォローアップタスクが自動で生成される仕組みを構築した事例を紹介します。担当者50〜500名規模の保険代理店で、顧客フォローをExcelや紙の台帳で管理している営業担当・マネージャーの方に参考になる内容です。

Excelでの顧客管理で起きていた問題

保険代理店の顧客管理をExcelで行っていると、ほぼ必ずと言っていいほど以下の問題が発生します。

  • 契約者の家族構成や住所変更といった情報が更新されず、古いまま放置される
  • 「結婚した」「子どもが生まれた」などのライフイベント情報が担当者の記憶頼みになる
  • フォロー対象の契約者を抽出するために、毎週Excelをフィルタリングする手間がかかる
  • 担当者が異動・退職すると、フォロー履歴が引き継がれない
  • マネージャーが各担当者のフォロー状況を把握できず、対応漏れに気づけない

特に「ライフイベントの把握」が課題でした。お客様との雑談の中で聞いた情報をメモに残しても、それが提案につながるフォロータスクになっていない。情報はあるのに活用されていない状態だったんです。

構築した3アプリの構成

今回は以下の3つのアプリを連携させました。

アプリ名役割主なフィールド
顧客マスタアプリ契約者の基本情報・ライフイベント履歴を管理顧客名、生年月日、家族構成、担当者、契約種別、ライフイベントテーブル
フォロータスクアプリライフイベントに応じた提案タスクを管理顧客(ルックアップ)、タスク種別、期限、ステータス、対応メモ
対応履歴アプリ実際のフォロー結果を記録顧客(ルックアップ)、対応日、対応方法、対応内容、次回アクション

ポイントは、顧客マスタアプリにサブテーブルとして「ライフイベントテーブル」を持たせたことです。ライフイベントを登録すると、自動でフォロータスクアプリにレコードが作成される流れになっています。

顧客マスタアプリのフィールド構成

フィールド名フィールドタイプフィールドコード備考
顧客名文字列(1行)customerName必須
フリガナ文字列(1行)customerKana
生年月日日付birthDate
担当者ユーザー選択assignee
電話番号文字列(1行)phone
メールアドレス文字列(1行)email
契約種別チェックボックスcontractType生命保険、損害保険、自動車保険、火災保険
契約ステータスドロップダウンcontractStatus契約中、満期、解約
ライフイベントテーブルテーブルeventTableサブテーブル
├ イベント種別ドロップダウンeventType結婚、出産、住宅購入、転職、退職、子の進学、相続
├ 発生日日付eventDate
└ 備考文字列(1行)eventNote

フォロータスクアプリのフィールド構成

フィールド名フィールドタイプフィールドコード備考
タスクタイトル文字列(1行)taskTitle自動生成
顧客名ルックアップlookupCustomer顧客マスタアプリから取得
タスク種別ドロップダウンtaskType保障見直し提案、新規提案、更新確認、情報更新
期限日付deadlineイベント登録日から14日後を自動設定
ステータスドロップダウンtaskStatus未着手、対応中、完了、見送り
担当者ユーザー選択taskAssignee顧客マスタから自動コピー
対応メモ文字列(複数行)taskMemo

ライフイベント登録時のタスク自動生成カスタマイズ

今回のカスタマイズの核となる部分です。顧客マスタアプリでレコードを保存した際に、新しく追加されたライフイベントに対応するフォロータスクを自動生成します。

(function() {
  'use strict';

  // フォロータスクアプリのID
  var TASK_APP_ID = 456;

  // ライフイベントごとのタスクテンプレート
  var EVENT_TASK_MAP = {
    '結婚': { type: '保障見直し提案', title: '【結婚】保障内容の見直し提案', days: 14 },
    '出産': { type: '新規提案', title: '【出産】学資保険・保障追加の提案', days: 14 },
    '住宅購入': { type: '保障見直し提案', title: '【住宅購入】火災保険・団信の確認', days: 7 },
    '転職': { type: '保障見直し提案', title: '【転職】団体保険・保障の見直し', days: 21 },
    '退職': { type: '保障見直し提案', title: '【退職】保障継続・年金プランの提案', days: 14 },
    '子の進学': { type: '情報更新', title: '【進学】学資保険の確認・教育費プラン', days: 30 },
    '相続': { type: '新規提案', title: '【相続】相続対策・資産整理の提案', days: 21 }
  };

  // 日付にn日加算する関数
  function addDays(dateStr, n) {
    var d = new Date(dateStr);
    d.setDate(d.getDate() + n);
    var yyyy = d.getFullYear();
    var mm = ('0' + (d.getMonth() + 1)).slice(-2);
    var dd = ('0' + d.getDate()).slice(-2);
    return yyyy + '-' + mm + '-' + dd;
  }

  // レコード保存成功後イベント
  kintone.events.on(
    ['app.record.create.submit.success',
     'app.record.edit.submit.success'],
    function(event) {
      var record = event.record;
      var customerName = record.customerName.value;
      var assignee = record.assignee.value;
      var eventTable = record.eventTable.value;

      if (!eventTable || eventTable.length === 0) {
        return event;
      }

      var today = new Date();
      var todayStr = today.getFullYear() + '-'
        + ('0' + (today.getMonth() + 1)).slice(-2) + '-'
        + ('0' + today.getDate()).slice(-2);

      var postRecords = [];

      eventTable.forEach(function(row) {
        var eventType = row.value.eventType.value;
        var eventDate = row.value.eventDate.value;
        if (!eventDate || !eventType) return;

        var eventDateObj = new Date(eventDate);
        var diffDays = Math.floor(
          (today - eventDateObj) / (1000 * 60 * 60 * 24)
        );
        if (diffDays > 30) return;

        var template = EVENT_TASK_MAP[eventType];
        if (!template) return;

        postRecords.push({
          taskTitle: {
            value: template.title + ' - ' + customerName
          },
          lookupCustomer: { value: customerName },
          taskType: { value: template.type },
          deadline: { value: addDays(todayStr, template.days) },
          taskStatus: { value: '未着手' },
          taskAssignee: { value: assignee },
          taskMemo: {
            value: eventType + '(' + eventDate
              + ')に基づく自動生成タスク'
          }
        });
      });

      if (postRecords.length === 0) {
        return event;
      }

      var body = {
        app: TASK_APP_ID,
        records: postRecords
      };

      return kintone.api(
        kintone.api.url('/k/v1/records.json', true),
        'POST', body
      ).then(function(resp) {
        console.log(
          'フォロータスクを' + resp.ids.length + '件作成しました'
        );
        return event;
      }).catch(function(error) {
        console.error('タスク作成エラー:', error);
        return event;
      });
    }
  );
})();

処理のポイントを整理します。

  • レコード保存成功後(submit.success)のタイミングでタスクを生成しています。submitイベントだと保存失敗時にもタスクが作られてしまうためです
  • ライフイベントの種別に応じて、タスクのタイトルや期限日数を自動で切り替えています
  • イベント発生日から30日以上経過しているものはタスク生成をスキップします。過去のイベントを一括登録したときに大量のタスクが生成されるのを防ぐためです

ハマりどころ

実装中にいくつかハマったポイントがあります。

サブテーブルの差分検知ができない問題

edit.submit.successイベントでは、サブテーブルのどの行が新規追加されたのか判別できません。既存行のイベントにも反応してしまい、、、、同じタスクが何度も生成される問題が発生しました。対策として、フォロータスクアプリ側で「顧客名+イベント種別+イベント日」の組み合わせで重複チェックをかけるようにしました。上記のサンプルコードでは省略していますが、実際の運用ではGETリクエストで既存タスクを検索してから生成する処理を入れています。

ルックアップフィールドへの値セットの制約

フォロータスクアプリの「顧客名」はルックアップフィールドです。REST APIでレコードを作成する際、、、、ルックアップのキーとなるフィールドに値をセットするだけでは関連フィールドがコピーされません。APIで作成したレコードは、一度開いて「取得」ボタンを押す必要があります。運用上はルックアップではなく関連レコード一覧で参照する形に切り替えたケースもありました。

ユーザー選択フィールドのフォーマット

担当者フィールド(ユーザー選択)をAPIで設定する際、値の形式が [{code: 'user@example.com'}] という配列形式である必要があります。顧客マスタから取得した値をそのまま渡せば問題ないですが、、、、初回実装時に文字列で渡してしまいエラーになりました。

導入結果

導入から3か月後、以下の成果が出ました。

  • フォロー対応率が導入前の42%から78%に向上した
  • ライフイベント起点の提案による追加契約が月平均3.2件発生するようになった
  • 担当者の異動時に、フォロータスクの引き継ぎが「担当者フィールドの変更」だけで完了するようになった
  • マネージャーがフォロータスクアプリの一覧画面で、各担当者の対応状況をリアルタイムに把握できるようになった

特に大きかったのは、「提案のきっかけ」が仕組み化されたことです。以前は担当者の記憶と勘に頼っていたフォローが、イベント登録という簡単な操作だけで自動的にタスク化されるようになりました。

まとめ

今回は保険代理店の顧客フォローを、kintoneのライフイベント管理とタスク自動生成で効率化した事例を紹介しました。

保険業界では「いかにお客様のタイミングを逃さないか」が解約防止と追加提案の両面で重要です。しかし担当者の記憶やExcel管理に頼っている限り、対応漏れは避けられません。

今回の構成で押さえておきたいポイントは以下の3つです。

  • ライフイベントをサブテーブルで構造化し、種別ごとにタスクテンプレートを用意する
  • タスク生成はsubmit.successイベントで行い、保存失敗時の誤生成を防ぐ
  • 重複チェックの仕組みを入れて、既存イベントの再登録時にタスクが重複しないようにする

結果として、担当者12名の代理店でフォロー対応率が約36ポイント改善し、属人的だった顧客フォローが組織的な営業活動に変わりました。

株式会社ファストコーディングでは、kintoneのカスタマイズや業務アプリの構築を承っています。お問い合わせフォームからお気軽にご連絡ください。