dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[Salesforce]Apexでリードの「取引の開始」を実行

前に書いた記事のように、リードが取引開始になった時のトリガなどを実装した場合
このトリガのテストメソッドってどうやって書くんだろう?と思って調べてみました。

Database.LeadConvertクラスのオブジェクトを使って
Database.convertLead(Database.LeadConvert)メソッドを実行するようです。

基本的な書き方

まずは、公式リファレンスにある方法を試してみる。

テストメソッド(失敗パターン)

// Leadオブジェクトを作成、insert
Lead leadToConvert = new Lead(
    FirstName = '太郎',
    LastName = 'さんぷる'
);
insert leadToConvert;

// Database.LeadConvertオブジェクトに
// insertしたリードのIdをセット
Database.LeadConvert lc = new Database.LeadConvert();
lc.setLeadId(leadToConvert.id);

// リードステータスのうち、取引を開始(IsConverted = true)した時に使用するものを1つ取得
LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true LIMIT 1];
lc.setConvertedStatus(convertStatus.MasterLabel);
lc.setDoNotCreateOpportunity(True); // 商談オブジェクトを作成しない

// Database.convertLeadにより取引の開始を実行
Database.LeadConvertResult lcr = Database.convertLead(lc);
System.assert(lcr.isSuccess());

ちなみにこのLeadStatusというのは、

カスタマイズ > リード > 項目

のリード 状況のことを指しています。

f:id:dackdive:20140703105543p:plain

上記のサンプルコードでは、「取引開始済み」フラグにチェックが入っている選択リスト値のどれか1つを取得していることになります。
(この値は@isTest(seeAllData=true)じゃなくても取得できるみたいですね)

問題点と原因

上記のコードをテストメソッドで実行すると、組織によっては以下のようなエラーが出て失敗する場合があります。

FATAL_ERROR System.DmlException: ConvertLead failed. First exception on row 0; first error: INVALID_STATUS, invalid convertedStatus: Closed - Converted : []

(「Closed - Converted」のところは「取引開始済み」フラグにチェックが入っているリードステータスのどれか)

これは、組織によってはリードのレコードタイプを設定しており、かつ、そのレコードタイプに割り当てた「レコードプロセス」によって選択可能なリードステータスの値を設定しているためです。

リードプロセスの確認方法

カスタマイズ > リード > レコードタイプ

から、レコードタイプを確認します。

f:id:dackdive:20140703105921p:plain

「新規プロセス」というレコードプロセスが割り当てられています。
このレコードプロセスの詳細を確認すると...

f:id:dackdive:20140703110144p:plain

このリードプロセスでは「Closed - Converted」というリードステータスは選択できない設定になっているようです。
先ほどのコードの

LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true LIMIT 1];

では、「取引開始済み」になっているリードステータスをどれか1つ適当に取得してくるため
設定されているレコードタイプでは選択できないリードステータスをセットしようとしてエラーが発生していたみたいですね。

解決策(イマイチだけど)

さて、このような場合にどうすればいいのか...
レコードタイプIdを取得する方法とかはあるようなのですが

  • レコードタイプを1個も作成していない組織でもエラーが起きないようなテストになるか?
  • レコードタイプが取得できたからといって、ひもづいているリードプロセス&リードプロセスに設定されているリードステータスは取得できるのか?

というあたりがわかりませんでした。

なので、かなり泥臭いやり方ですが、以下のような方法で回避できます。

テストメソッド(失敗パターン)

// Leadオブジェクトを作成、insert
Lead leadToConvert = new Lead(
    FirstName = '太郎',
    LastName = 'さんぷる'
);
insert leadToConvert;

// Database.LeadConvertオブジェクトに
// insertしたリードのIdをセット
Database.LeadConvert lc = new Database.LeadConvert();
lc.setLeadId(leadToConvert.id);

// リードステータスのうち、取引開始済みのものを全部取得してくる
List<LeadStatus> convertStatusList = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true];
Database.LeadConvertResult lcr;
for (LeadStatus convertStatus : convertStatusList) {
    try {
        lc.setConvertedStatus(convertStatus.masterLabel);
        lc.setDoNotCreateOpportunity(True); // 商談オブジェクトを作成しない
        // 取引開始
        lcr = Database.convertLead(lc);
        break;
    } catch (DMLException e) {
        // DMLExceptionが発生したら次のリードステータスを使う
    }
}
System.assert(lcr.isSuccess());

「取引開始済み」フラグにチェックが入っているステータスを全部取得して
DmlExceptionが発生しないものが見つかるまで何度も繰り返すっていうやり方ですね。

ガバナ制限にさえ気をつければ、レコードタイプが設定されている組織でもそうでない組織でも
この書き方でテストが通るようになるはず。

リファレンス

Salesforce Developers

visualforce - Convert lead through apex but should not create opportunity - Salesforce Stack Exchange

How to get the appropriate converted LeadStatus based on Lead RecordType - Salesforce Developer Community

http://mindfiresfdcprofessionals.wordpress.com/2013/10/23/how-to-get-the-recordtype-id-using-dynamic-apex/