Salesforceに登録した情報をslackAPIを介してslackにpostして視認性を上げた話

slackを使ってよかったことの一つにEmailインテグレーションがあります。
特定のチャンネルでこれを設定すると、slackがメールアドレスを割り当ててくれるのですが、そこにメールを投げると、チャンネルに流れるんですね。こんな感じで

<img width="419" alt="bizreport.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/22294/bedfeee5-2f59-b7ad-0e87-38e906b8e7eb.jpeg">

設定も簡単なので重宝しているのですが、ご覧の通り
- メールの送信者名
- メールのサブジェクト
- 本文が1行

という表示で一瞥して得られる情報が限られます。
そこで、slackAPIを介してpostすることで、もう少し情報の取得しやすさを向上しましょうという取り組みです。

## やっていること
ここでやっていることは、プロセスビルダーでapexを叩きに行くタイミングを制御し、起動したapexからslackAPIを叩きに行くというシンプルなものです

## 良かった点
slack APIで許される限りの装飾を施すことが出来ます。
特にAttachment周りを活用すれば、情報の整理に役立つのではないでしょうか
参考：https://api.slack.com/docs/message-attachments

<img width="525" alt="color.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/22294/dfcd3e72-c0f6-3538-7723-e393a84d613e.jpeg">
こちらは営業報告を想定していますが、受注の場合は少し賑やかしを入れたりもできますね。
colorの設定も変更できるので、重要なものは目立つ色、そうでないものは暗い色とかにしておく等も良いかもしれません。
特定のチャンネルに流すということを想定するのであれば、重要度の高いものの色を把握していれば、ざっとチャンネルのタイムラインを遡るだけで、現在のステータスを把握できる可能性があります。

## プロセスビルダーの設定について
今回の実装はEventオブジェクトを使って行っています。特に主従関係を設定せずとも、各オブジェクトで情報を入れられますし、使いこなすのに少しコツがいるオブジェクトだなとは思いますが、あらゆるオブジェクトに関する報告類はここにまとめてしまうという運用にしておくと割と便利な気がします。

対象オブジェクトは行動
発動条件は適宜設定をしてください。条件なしで全部通過してapex classを呼び出してしまっても良いかもしれません。
呼び出すApexにはレコードIDを受け渡すだけで基本的にはOKです。(下のコードでは、投稿者名も渡していますが、SOQLでも取得出来るのでどちらでも良いと思います)

## Apexについて
ベースになるコードをどこかから拝借していたのですが…わからなくなってしまったので書いておきます。

```postToSlack.cls
public class postToSlack {
    private static final String slackWebhookURL = 'Webhookで作ったslackのURL';

    public class recordVariable {
        @InvocableVariable(label='レコードID')
        public ID recordID;//プロセスビルダーから参照できるようになります
        @InvocableVariable(label='投稿者名')
        public String postUserName;//slackに名前を投げたいのでプロセスビルダーから投稿者名を受け取っています(必須じゃないです)
    }
     
    @InvocableMethod(label='SlackAlertBizRep')
    public static void postToSlack(List<recordVariable> recordVariables) {
        recordVariable o = recordVariables[0]; // If bulk, only post first to avoid overloading Slack channel

        //レコードIDからEventのレコードに付随する情報を取得します
        EVENT myrep = [SELECT 
        					id,
        					Description,
        					Owner.Name,
        					OwnerSlackID__c,//カスタム項目としてUser.slackid__cを作り、それを参照しています
        					Result__c,//先程の画像に載せた、[受注]という項目です。ここに、要再提案とか見込みなしみたいな選択項目を作って、どんな結果だったのかを選ばせています
        					Subject,
        					ActivityDate,
        					WhatID
    					FROM Event 
    					WHERE 
    						id = :o.recordID //プロセスビルダーから入ってきたIDを指定
						LIMIT 1];

//Eventがどのオブジェクトに紐付いていたのかが分からないので、それを取得するにはこんな感じにするとオブジェクト名が取れる
		if(myrep.WhatID != NULL){
			sobjecttype objectType = myrep.whatID.getSobjectType();
		}

//商談の場合は商談名とか色々把握したいので↑ではなくこちらを使います
		String whatName;//商談名を入れる
		Opportunity whatOpportunity = new Opportunity();//商談
		String AccountName;//取引先名を入れる
		if(myrep.WhatID != NULL){
			sobjecttype objectType = myrep.whatID.getSobjectType();
			String wquery = 'SELECT Name FROM ' + objectType + ' WHERE id = \'' + myrep.WhatID + '\' LIMIT 1';//クエリをStringで組むと自由が効きやすい
			sObject whatData = Database.query(wquery);
			whatName = String.valueOf(whatData.get('Name'));
			if(String.valueOf(objectType) == 'Opportunity'){
				whatOpportunity = [SELECT Account.Name,Account.id,Amount,CloseDate FROM Opportunity WHERE id = :myrep.WhatID LIMIT 1];//取引先名、取引先ID、商談ID、金額、完了予定日を取得しています
			}
		}

        Map<String,Object> msg = new Map<String,Object>();
        msg.put('author_name', myrep.Owner.Name);
		msg.put('text',  '[' + myrep.Result__c + ']' + myrep.Subject + '(' + o.postUserName + ' <@' + myrep.OwnerSlackID__c + '>) *実施日* ' + myrep.ActivityDate + '\n *結果詳細* ' + myrep.Description);
		String atcText;
		LIST<String> atcTexts = new LIST<String>();//attachmentのtextに突っ込むためのString配列。最終的にStringに変換する
		if(whatName != NULL){
			if(whatOpportunity != NULL){
				if(Result__c == '受注'){
					atcTexts.add('🎉🍣🎉🍣🎉🍣🎉🍣🎉🍣🎉🍣🎉');//ちょっとした賑やかしを。
				}
				atcTexts.add('*商談* <https://yourID.lightning.force.com/' + myrep.whatid + '|' + whatName + '> *金額* ¥' + whatOpportunity.Amount.format() );//URLを貼ってリンクしておくと、slackから欲しいページへ直接飛べるので便利です
				atcTexts.add('*取引先* ：<https://yourID.lightning.force.com/' + whatOpportunity.Account.id + '|' + whatOpportunity.Account.Name +'>');
				atcTexts.add('*完了予定日* ' + whatOpportunity.closeDate);
			}else{
				atcTexts.add('*関連先名* <https://yourID.lightning.force.com/' + myrep.whatid + '|' + whatName + '>');
			}
		}

		atcText = String.join(atcTexts,'\n');//textに突っ込むためにjoinする

		LIST<Object> texts = new LIST<Object>();//Attachmentは配列で入れる必要がある(複数項目ある場合は)

		String colorString;//結果によって色を変えたかったのでこんな感じに
		if(myrep.Result__c == '要提案'){		colorString = '#001592';
		}else if(myrep.Result__c == '先方検討'){	colorString = '#00ff54';
		}else if(myrep.Result__c == '受注'){	colorString = '#ff0000';
		}else if(myrep.Result__c == 'その他'){	colorString = '#6d0071';
		}
		texts.add(new MAP<String,String>{
										'text' => atcText,//ここが本文
										'color' => colorString//色設定
										});

		//texts.add(new MAP<String,String>{'title' => 'at Title'});//追加したい情報があればこんな感じでMapを追加していく

		msg.put('attachments',texts);

        msg.put('mrkdwn', true);

        String body = JSON.serialize(msg);   
	System.enqueueJob(new QueueableSlackCall(slackWebhookURL, 'POST', body));//ここでslackにpostする
    }
     
    public class QueueableSlackCall implements System.Queueable, Database.AllowsCallouts {
         
        private final String url;
        private final String method;
        private final String body;
         
        public QueueableSlackCall(String url, String method, String body) {
            this.url = url;
            this.method = method;
            this.body = body;
        }
         
        public void execute(System.QueueableContext ctx) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(url);
            req.setMethod(method);
            req.setBody(body);
            Http http = new Http();
            try{
                HTTPResponse res = http.send(req);
                }catch(Exception e){
            }
        }
    }
}

```
こんな感じ処理してみると、slack通知が見やすくなるとおもいます。