見出し画像

SalesforceのEventオブジェクトを使いやすくする実装の話

弊社のSalesforce上にはいわゆる商談に関する基本的なオブジェクト以外にも様々なオブジェクトを作成して日々のデータの蓄積に活用しています。

そんな中、最近では、なにか固定されたレコードを定点的に観測して記録に残す必要が増えてきました。例えば採用選考で面接の記録を取ったり、学生向けの部活のメンタリングの記録をとったりと、時系列で記録していくということを行っています。

Salesforceには標準で活動(Activity)・行動(Event)というオブジェクトがあり、それを使うことでこと足りるのですが、少し癖があって敬遠していました(後述します)。そんなこんなでこれまではわざわざ記録用のオブジェクトを作って、ターゲットとなるオブジェクトにぶら下げていたんですよね。今回はそんな実装をやめて、Salesforceで使う標準的な使い方に準じつつもっと便利に使いましょうみたいなはなしです。

Event/Activityオブジェクトの便利なところはどこか

カスタムオブジェクトを作る際に、活動を許可というチェックボックスがあるので、それをTRUEにしておけばどのオブジェクトに対してもぶら下げることが可能です。先述したようにオブジェクトごとに記録用のカスタムオブジェクトを作るとその分オブジェクト数がかさみますし、同じような構成のオブジェクトが乱立することになってデータ管理的に面倒なことになります。(というか弊社環境はなりました)

オブジェクト上では、専用のウィジェットが用意され、そこから情報の記入が可能になりますこんなかんじで。

画像1

なんでこんなことが可能になるかというテクニカルな話を少しすると、Eventオブジェクトには関連先(whatid)という、先程の許可を出したオブジェクトのどれにでも関連付けられる項目が存在しています。弊社環境だとこんな感じ。

行動___Salesforce

そんな項目はカスタム項目としては存在しません。作れればいいのに。

これとは別に名前項目(Whoid)というものもあり、これはリードと取引先責任者のどちらかを参照できる項目になっています。

割と便利だと思うのですが、ここからは上述した癖の話です。

Activity/Eventオブジェクトを敬遠していた理由

このオブジェクト、弊社で利用するのは営業報告を書くというシーンに限られていました。本当は昔やりたかったことの一つとして、ターゲットとなる商談にいくつ営業報告があるのか積み上げ集計したいというものがありました。ただ、このオブジェクトは主従関係で紐づくわけではないので積み上げ集計では集計ができないんですよね。諦めました。

敬遠の理由その2:数式項目が使えない

Whatidは特殊な項目で参照しています。通常であれば参照項目を作ることで、数式を使えば参照先オブジェクトにある項目の中身を取得することができます。whatidではそれができないんですよね。

たとえば、先程の採用情報のスクショでいうと、下の方にある面談記録というリンクをクリックした先がEventのレコードそのもののページになります。それがこちら

画像3

モザイクかけてある部分は後述します。

活動オブジェクトにはカスタム項目を作ることができますので、この画像の下の方にある項目のいくつかはカスタム項目として足したものです。通常はこのページを開いてしまうと、そもそもなんのレコードに紐付いている行動なのかを把握する術がありません。もちろん関連先(whatid)のリンクをクリックすれば戻れるのですが、端的に言って一覧性が悪く使いづらいのです。

使いやすくする実装とはなにか

ここでも書いたのですが、最近トリガを上手に使えるようになってきました。

そこで閃いたんですよね✨

やったことは以下の通りです

1:Eventオブジェクトに、正規のカスタム項目として他のオブジェクトへの参照項目を作る
2:whatidにIDが入っていたら、トリガを使ってオブジェクトを判定する
3:例えば1で商談という参照項目を作り、whatidに入っているものが商談のIDだったとすれば、その商談の項目にもIDを入れてしまうというトリガを書きました
4:そうすることで、Eventレコードを作った瞬間に作成した参照項目にIDが自動的に入ります
5;Eventオブジェクトには数式項目で例えば商談の金額を参照するようなものを作成すれば、Eventページ上で金額を見ることが可能です。便利!

と、いうことで、今まで敬遠していたユーザビリティの低さを技術で乗り越えたよという話でした。興味がある人は以下のコードで実装してみてください。そんなに難しくはないとおもいます。

ターゲットとするオブジェクトAPI名:Event項目をぶら下げるターゲットとなるオブジェクトのAPI名です。 __c ってやつ。
参照項目API名__c:Activityオブジェクトにカスタム項目として参照項目を作ってください。そのAPI名を入れます。

getWhatIDObjectTrigger.apxt

//Eventオブジェクトに関するトリガ
trigger getWhatIDObjectTrigger on Event (before insert,before update) {
	//Trigger.Old is null in a Before Trigger. 
   if(Trigger.new[0].whatid != NULL){//whatidが存在しているときだけ処理する
       ID objID = Trigger.new[0].whatid;
       sObjectType whatid_sObjType = objID.getSObjectType();
       DescribeSObjectResult whatid_sObjectDescribe= whatid_sObjType.getDescribe();
       String whatid_objName = whatid_sObjectDescribe.getName();//オブジェクトのAPI名を取ります

       if(whatid_objName == 'ターゲットとするオブジェクトAPI名'){
           for(Event ev : Trigger.new){
               ev.参照項目API名__c = ev.whatid;
           }
       } // 他のパターンを続けたい場合はこんな感じで書く else if(whatid_objName == 'オブジェクトAPI名'){}

   }
}

getWhatIDObjectTriggerTest

@isTest
private class getWhatIDObjectTriggerTest {
   static testMethod void test1() {
		System.debug('01======================開始=========================');
		ターゲットとするオブジェクトAPI名 obj = new ターゲットとするオブジェクトAPI名(Name = 'test等');
       insert obj;
       Event ev = new Event(whatid = obj.id,DurationInMinutes = 10,ActivityDateTime=Datetime.now());
       Test.startTest();
       insert ev;
       Test.stopTest();        
   }
}

テスト書くの難しい場合は、先にほしいレコードを作っておいて、

whaid = obj.idとなっているところを
whatid = '0061000001D0nmxAAB'
みたいな形にハードコーディングしてしまうと楽です。Sandboxと本番両方必要なのでその場合はこんなふうに書いてください

@isTest
private class getWhatIDObjectTriggerTest {
  static testMethod void test1() {
		System.debug('01======================開始=========================');
		ターゲットとするオブジェクトAPI名 obj = new ターゲットとするオブジェクトAPI名(Name = 'test等');
      insert obj;
      ID wid;
      Organization org = [select Id, IsSandbox from Organization limit 1];
       if(org.IsSandbox == FALSE){
       	wid = '0061000001D0nmxAAB'; // 本番環境のレコードのID
       }else{
       	wid = '0061000001DfemxABC'; // Sandbox環境のレコードのID
       }
      Event ev = new Event(whatid = wid,DurationInMinutes = 10,ActivityDateTime=Datetime.now());
      Test.startTest();
      insert ev;
      Test.stopTest();        
  }
}

これを実装することで解決すること

こうやって自動的にオブジェクトへの参照が設定されると何がよいかというと、ActivityオブジェクトにSalesforceのGUIから数式項目を作ってページレイアウトで配置すれば、開発者じゃなくても自由にぶら下がり元のデータを配置することができるということです。

これが先程後述すると書いたモザイクの部分

画像4

これができれば、レポートを作るのも容易になるだろうし、良いことづくめなのではないでしょうか。

noteにはこれまでの経験を綴っていこうかと思います。サポートによって思い出すモチベーションが上がるかもしれない。いや、上がるはずです。