ServiceCloudとCTI連携を実現する


# 自己紹介
この記事は「[24日後に立派なSalesforceエンジニアになるWEBエンジニア Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kakakaori)」の17日目の記事です。
8日後に立派なSalesforceエンジニアになるために今日はSalesforceとCTIシステムを連携させる方法について学びます。

# CTI連携
Salesforceコールセンターという機能を使うとサードバーティー製のCTIシステムとの連携ができる。弊社では[CT-e1](https://comdesign.co.jp/service/)を使っているのでその連携方法について記載していく。
ただし他のCTIシステムでも手順はおおよそ同じでほとんどがAppExchangeからパッケージをインストールしてユーザーを追加するだけでいけるそうな。すごい。

# コールセンター設定手順

## 1.AppExchangeからパッケージをインストール
![スクリーンショット 2022-11-29 12.01.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/71cd22e5-cc67-67a3-d441-e0a68c21aa94.png)

## 2.コールセンターにユーザーを追加する
![スクリーンショット 2022-11-29 13.57.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/99bfcd38-7fce-bb6f-1c91-ebb4026bd6f6.png)
登録されたコールセンターの詳細ページから新規ユーザーを追加していく。これだけでOK。

# 受電時の挙動を変更する
ソフトフォンレイアウトを設定することで受電時の挙動が変更できる。
変更を行うためにはまず変更を行うユーザーが上述したコールセンターユーザーに追加されている必要がある。追加されていないと変更の画面が表示されないので注意。

![スクリーンショット 2022-11-29 14.05.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/6355fa07-ead2-9ea2-1e08-f72d61ea30ee.png)

画面のポップ設定は標準で用意された選択肢以外にVisualforceページにポップさせたりフローにポップさせたりすることもできる。だから受電したら何らか処理をしてその後このページを表示したいとかも表現することができる。

# 受電時にVisualforceページにポップする
今回は受信した時にマッチした取引先責任者が紐づく取引先ページを表示する処理を作ってみる。他にも着信番号をもとに表示するサポートページを変えるとかもできそう。
やり方としてはVisualforceページからApexを呼び出して表示するAccountIdを特定して、それをjavascriptに戻して、タブ表示するという流れ。

ApexクラスからVisualforceへの値の渡し方はこんな感じでgetterを作ってあげる。
```apex:HogeController.cls
public class HogeController {
  public String getHogeText() {
    retrun 'hoge';
  }
}
```
```javascript:hogehoge.page
{!hogeText}
```

またその受け取った値をjavascriptに渡すには[apex:outputText](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_outputText.htm)を使う。

```javascript:hogehoge.page
var hoge = '<apex:outputtext value="{!hogeText}"></apex:outputtext>';
```


タブで取引先ページを表示するには[こちら](https://developer.salesforce.com/docs/atlas.ja-jp.api_console.meta/api_console/sforce_api_console_openprimarytab.htm)にあるopenPrimaryTabメソッドを使う。
それらを踏まえると全体像こんな感じ。


```html:InboundCallDisplayAccount.page
<apex:page controller="CTI_CoordinationController">
  <apex:includeScript value="/support/console/56.0/integration.js"/>
  <script type="text/javascript">
      sforce.console.openPrimaryTab(null, '/<apex:outputtext value="{!accountId}"></apex:outputtext>', true);
  </script>
</apex:page>
```

```apex:CTI_CoordinationController.cls
public with sharing class CTI_CoordinationController {
  public String ANI { get; set; } // 顧客の電話番号
  public String DNIS { get; set; } // こちら側の受電番号

  public CTI_CoordinationController() {
    this.ANI = ApexPages.currentPage().getParameters().get('ANI');
    this.DNIS = ApexPages.currentPage().getParameters().get('DNIS');
  }

  public string getAccountId() {
    // 電話番号検索で１件だった時にこの処理が呼ばれるのでレコードヒットは１件であることが保証されている
    List<List<SObject>> searchList = [
      FIND :this.ANI
      IN PHONE FIELDS
      RETURNING Contact(AccountId)
    ];
    if (searchList.isEmpty()) {
      System.debug('----- ANI : ' + this.ANI);
    }
    Contact[] contact = ((List<Contact>) searchList[0]);
    return contact[0].AccountId;
  }
}
```
これでお客さんから電話を受信すると、電話番号が該当する取引先責任者が見つかった時に、それに紐づく取引先のページが表示されるようになる。
今回のサンプルでは`DNIS`を使っていないけど、例えばお客様から「0120-xxx-xxxx」にかかってきた場合はこのページを、「0120-yyy-yyyy」にかかってきた場合は別のページを表示したいなんていう時には`DNIS`を使ってあげると表現できる。

ただこの状態だと受電時にタブが2つ（1つは空っぽのページで、もう1つは意図した通りの取引先ページ）が開く状態になってしまった。
なぜならコールシステムの設定で「受電時にvisualforceページをポップする」として今回作ったvisualforceページを設定しているため、この段階でページが一つ表示される。そしてそのvisualforceページ内で`openPrimaryTab`メソッドにより取引先ページを表示しているのでさらにもう1つタブが表示される。
つまり最初に表示したvisualforceページについてはそのタブを削除する処理を入れておく必要がある。

[getEnclosingTabId](https://developer.salesforce.com/docs/atlas.ja-jp.api_console.meta/api_console/sforce_api_console_getenclosingtabid.htm)で現在のvisualforceページを含むタブのIDを返してもらって、そのコールバック関数としてタブを閉じる処理を入れる。
こんな感じ。
```apex:CTI_CoordinationController.cls
    var closeSubtab = function closeSubtab(result) {
      var tabId = result.id;
      sforce.console.closeTab(tabId);
    };
    sforce.console.getEnclosingTabId(closeSubtab);
```
これで無事に受電時に該当の取引先ページのタブのみが開かれるようになった。

ちなみに初めはコントローラーから
```apex:CTI_CoordinationController.cls
 return new PageReference('/' + contact[0].AccountId)
```
のようにPageReferenceをreturnしてvisualforceページ側は
```html:InboundCallDisplayAccount.page
<apex:page controller="CTI_CoordinationController" action="{!hogeMethod}">
</apex:page>
```
のようにコントローラーを呼ぶだけにしてリダイレクト処理をかけていたけど、これだとリダイレクト処理になるので、ページの再読み込みが走っちゃう。つまりページ内で情報の編集途中でも電話がかかってくると強制的に再読み込みされちゃうので、再読み込みなしで該当ページの表示だけをしたくて上記のようにopenPrimaryTabを使う形に変更した。

# まとめ
これでCTI連携して、受電時に任意の処理を行うことができるようになりました。
やってみるとなんてことない処理なんだけど、この辺はググってもなかなか情報出てこなくて苦戦したので、この記事が誰かの役に立つといいなと思います。
明日はAuraコンポーネントについて学んでいきます。