フローでSalesforceのレコード情報をSlackに投稿する

レコード詳細ページでボタンを押したら、レコード情報をSlackに投稿する機能を考えてみます。
Apexで作っちゃえば簡単なのですが、投稿内容を変更するのにいちいちApexを修正するとなると、お客様が修正するのは大変ですね。
**フローを使えばノンコーディングで投稿内容を修正可能**にできるなーと思ってやってみました。

# 作るもの

まとめると今回作ってみるのは以下のような機能です。

* 商談レコードページにアクションを置く
* アクションをクリックすると商談レコードをSlackに投稿する
* Flow Builderで投稿内容を自由に編集できる

![sendtoslack.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/0e1b1fdc-136b-f011-b38e-2152f9d79e6f.gif)

# Slackに投稿するApexクラスを作る

最初にSlackに投稿するApexクラスを作ります。

```java:SendToSlackAction.cls
public class SendToSlackAction {
    public class SlackException extends Exception {}
    
    public class SendMessageRequest {
        @InvocableVariable(required=true label='Webhook URL')
        public String webhookUrl;
        @InvocableVariable(required=true label='メッセージJSON')
        public String message;
    }
    public class SendMessageResponse {
        @InvocableVariable
        public Boolean success;
        @InvocableVariable
        public String message;
        @InvocableVariable
        public String detail;
    }

    @InvocableMethod(label='Slackに投稿')
    public static SendMessageResponse[] sendMessage(SendMessageRequest[] requests) {
        SendMessageResponse[] results = new List<SendMessageResponse>();
        for (SendMessageRequest request : requests) {
            try {
                sendMessage(request.webhookUrl, request.message);
                SendMessageResponse res = new SendMessageResponse();
                res.success = true;
                results.add(res);
            } catch (Exception e) {
                System.debug(e);
                SendMessageResponse res = new SendMessageResponse();
                res.success = false;
                res.message = e.getMessage();
                res.detail = e.getTypeName() + ': ' + e.getMessage() + '\n' + e.getStackTraceString();
                results.add(res);
            }
        }
        return results;
    }
    
    private static void sendMessage(String webhookUrl, String msg) {
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(webhookUrl);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(msg);
        HttpResponse res = http.send(req);
        Integer statusCode = res.getStatusCode();
        if (statusCode != 200) {
            throw new SlackException(res.getBody());
        }
    }
}
```

Webhook URLをリモートサイトに追加はしておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/e8ea13a2-e031-77d1-ae09-e23956c86f52.png)

# Flowを作る

Flow Builderを開きます。

今回は商談レコードページにアクションとして配置するので、レコードIDを受けるために、 `recordId` という変数を追加します。`マネージャ` > `新規リソース` から追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/7ac1afb8-b80a-d149-9da3-29373f121299.png)

`要素` > `レコードを取得`をデザイナーにドロップし、以下のように設定します。
商談レコードを絞り込みで `Id = {!recordId}` にするのがポイントです。これで今見ている商談が取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/a40529cf-04b7-eaf0-2057-fa40ec936a04.png)

同じダイアログの下の方に行って、 `レコード変数` で `新規リソース` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/278c6a2f-9f28-96fd-e628-fa242ef61d56.png)

以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/27a79257-c6af-ed08-0b8a-c22cef5213a4.png)

`変数に保存する商談項目を選択` に投稿したい項目を適当に選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/c3ac7d56-7405-7666-aaad-eec98bf266a7.png)

`Apexアクション` をドロップして、以下のように設定します。
SlackのWebhook URLは適当に取得してきてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/93755020-9121-b3d5-759b-1f46e56475f6.png)

入力値の `MessageJson` は新規数式リソースを以下のように作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/830cf60d-2f32-4e77-00f5-ac4e9e999d22.png)

数式の中身はこんな感じです。`テキストテンプレート`リソースでもよかったんですが、数式のほうが`JSENCODE`関数が使えてよいかと思います。
Slackのメッセージフォーマットについては[An overview of message composition | Slack](https://api.slack.com/messaging/composing)を見てください。

```
'{' &
'  "icon_url": "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/1ccfdf75-9564-1469-55df-d8c0ba1a01b2.png",' &
'  "username": "Salesforce",' &
'  "text": "' & JSENCODE({!CurrentOpportunity.Name}) & 'を共有しました!!"' &
'}'
```

ここまでで一応動きますが、結果の画面表示用に出力値も変数に保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/225b565d-6d12-e104-5192-f9386460f646.png)

`決定` ブロックをドロップして、以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/81d8b982-d710-110d-a703-86b12985863d.png)

成功画面を作ります。`画面`ブロックをドロップし、以下のように設定します。
細かいところは適当に設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/3a8f163c-09ca-047d-0ea1-5fe97112a6d5.png)

失敗画面も同様に作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/08b34bb9-d3bf-5fd0-07ec-e1cb096b9593.png)

以下のようにつなぎます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/f5622df4-71ac-5dd5-b15a-f9ffb64a3f06.png)

フローを保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/5f1ba697-88f1-9ee4-6df3-a0fc6b7ea0a5.png)

# アクションを作る

以下のようなアクションを作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/4d0c4161-4bcf-6e1c-e100-1801b3c0472e.png)

ページレイアウトに配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/36e82dc5-dd8a-94af-ed70-52324f83abe6.png)

完成です。

# 完成

ボタンを押すとSlackに投稿されます。

![sendtoslack.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/0e1b1fdc-136b-f011-b38e-2152f9d79e6f.gif)

Slackにはこんな感じに投稿されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/f600ed54-999f-5379-7ebb-bc4fe3995f32.png)

数式をがんばると

```
'{' &
'  "icon_url": "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/1ccfdf75-9564-1469-55df-d8c0ba1a01b2.png",' &
'  "username": "Salesforce",' &
'  "blocks": ['&
'    {' &
'      "type": "section",' &
'      "fields": [' &
'        {' &
'          "type": "mrkdwn",' &
'          "text": "<https://atskimura-dev-ed.lightning.force.com/' & {!CurrentOpportunity.Id} & '|' & JSENCODE({!CurrentOpportunity.Name}) & '>を共有しました!!"' &
'        }' &
'      ]' &
'    },' &
'    {' &
'      "type": "section",' &
'      "fields": [' &
'        {' &
'          "type": "mrkdwn",' &
'          "text": "*取引先名:*\n' & JSENCODE({!CurrentOpportunity.Account.Name}) & '"' &
'        },' &
'        {' &
'          "type": "mrkdwn",' &
'          "text": "*金額:*\n' & TEXT({!CurrentOpportunity.Amount}) & '"' &
'        },' &
'        {' &
'          "type": "mrkdwn",' &
'          "text": "*担当者:*\n' & JSENCODE({!CurrentOpportunity.Owner.LastName} & {!CurrentOpportunity.Owner.FirstName}) & '"' &
'        },' &
'        {' &
'          "type": "mrkdwn",' &
'          "text": "*フェーズ:*\n' & TEXT({!CurrentOpportunity.StageName}) & '"' &
'        }' &
'      ]' &
'    }' &
'  ]' &
'}'
```

もっとリッチにできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27267/6bc395b4-85fd-9436-ae49-c36a45f41e25.png)

でも、JSONを数式で書くの辛いなあ。