商談に限らず取引先、ケース、契約などの項目にある
「取引先責任者の役割」や「パートナー」ですが、
これをApexでコピーする方法。
特に、「パートナー」をコピーするあたりで色々ハマったのでメモ。
それぞれどんなもの?というのはこのあたりを参考にしてください。
取引先責任者の役割
対象のSObjectさえわかればそれほど難しくありません。
OpportunityContactRoles
を使います。
/* * 「取引先責任者の役割」をコピー * opp : コピー元の商談(Opportunity)オブジェクト * newOpp : コピー先(新たに作成したい)の商談オブジェクト */ List<OpportunityContactRole> contactRoleList = [ SELECT ContactId, Role, IsPrimary FROM OpportunityContactRole WHERE OpportunityId = :opp.id ]; List<OpportunityContactRole> newContactRoleList = new List<OpportunityContactRole>(); for (OpportunityContactRole contactRole : contactRoleList) { newContactRoleList.add(new OpportunityContactRole( OpportunityId = newOpp.id, ContactId = contactRole.contactId, Role = contactRole.role, IsPrimary = contactRole.isPrimary )); } insert newContactRoleList;
パートナー
こっちでけっこうつまづきました。
取引先責任者の役割がOpportunityContactRole
なので
パートナーはOpportunityPartner
だろうってことで
上をそのままOpportunityPartner
に変えるとエラー。。。
で、調べてみた結果
This read-only object represents a partner relationship between an Account and an Opportunity. This object is automatically created when a Partner object is created for a partner relationship between an account and an opportunity.
ん?Read-Only?
Partnerが作成されたときに自動生成されるもの?
というわけで、パートナーについては
OpportunityPartner
ではなくPartner
というSObjectを使えばいいそうです。
そしてもう1つ注意点。
先ほどの取引先責任者の役割のコードを流用して、次のようなコードを実行してみる。
/* * 「パートナー」をコピー(失敗例) * opp, newOppは先ほどと同じ */ // 取引先IdはAccountToIdというフィールドで取得 List<Partner> partnerList = [ SELECT AccountToId, Role, IsPrimary FROM Partner WHERE OpportunityId = :opp.id ]; List<Partner> newPartnerList = new List<Partner>(); for (Partner partner : partnerList) { newPartnerList.add(new Partner( OpportunityId = newOpp.id, AccountToId = partner.accountToId, Role = partner.role, IsPrimary = partner.isPrimary )); } insert newPartnerList;
その実行結果がこちら。
何やら、エラーが出ている...
14:18:04:635 EXCEPTION_THROWN [102]|System.DmlException: Insert failed. First exception on row 1; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: OpportunityId, AccountToId (account to cannot be opportunity account): [OpportunityId, AccountToId]
きちんとfor文の中を確認すればよかったのだけれども
その前に色々調べていて次の記事を見つけた。
Custom Clone button that also clones the Partner records??? - Salesforce Developer Community
また、冒頭に記載したリンク
でも、次のようなことが書いてある。
取引先や商談で 1 つのパートナーを選択すると、自動的に逆のパートナー関係も作成され、両取引先がもう一方の取引先をパートナーとして表示します。指定した役割がパートナー取引先に適用され、そのパートナーから見た役割がもう一方の取引先に適用されます。
なるほど、
パートナーという関係は一方通行ではなく双方向なので
新規で追加した時には逆向きのパートナー情報を表すレコードも自動生成されるんですね。
例) 新しく商談を作成する。取引先は「株式会社ABC」。 「パートナー」として別の取引先「株式会社DEF」を選択。 この時に生成されるのは、以下の2つのレコード。
ちなみに、この例ではRoleに「Agency」を選択したところ
逆方向のパートナーには「Client」が選択されましたが
この対応は「パートナーの役割」で参照することができます。
以上を踏まえて、パートナーをコピーする際の正しいApexはこちら。
/* * 「パートナー」をコピー(正しい例) * opp, newOppは先ほどと同じ */ List<Partner> partnerList = [ SELECT AccountToId, Role, IsPrimary FROM Partner WHERE OpportunityId = :opp.id ]; List<Partner> newPartnerList = new List<Partner>(); for (Partner partner : partnerList) { if (partner.accountToId != opp.accountId) { // これを追記! newPartnerList.add(new Partner( OpportunityId = newOpp.id, AccountToId = partner.accountToId, Role = partner.role, IsPrimary = partner.isPrimary )); } } insert newPartnerList;
いやー、ややこしい。
ちなみに、パートナーを選択した後で商談の取引先を変更すると
パートナーはリセットされ、レコードもなくなります。