[Salesforce] 過去の承認プロセスでロックされた大量の見積をアンロックする

2021.04.02

先日、当社のSalesforce管理者であるちゃあこさんによる社内の見積承認プロセスの見直しがありました。

(詳しくは、[Salesforce]社内用の見積承認プロセスを構築してみた を参照ください)

簡単には、

1. 現在の承認プロセス:最終承認後レコードのロック解除
2. 昔の承認プロセス :最終承認後レコードのロックをする(ただしプロファイルで「全て変更」権限与えてたので、ユーザー側からは見積の編集が可能だった)

という変更をしたのですが、昔の承認プロセスで作った見積・商品レコードは、その時の承認プロセスの条件をそのまま覚えていているために、当社環境において過去の見積承認プロセスで承認された見積にロックがかかったままとなりました。 そのため、これらの見積や商談商品のレコードをユーザーが編集しようとした際にエラーが発生するようになりました。

このロックの解除はシステム管理者の方でClassic画面から1レコードずつアンロック(ロック解除)していく方法とApexを使った一括処理があるのですが、当社の場合8,000件以上の該当レコードがあったためとても手作業で解除はしていられませんでした。

そこで、 Apex コードによる承認プロセスのロックおよびロック解除の設定 の情報を参考に、Apexで一括アンロックを行ってみましたので、その手順やApexコードについて記述します。

準備

まず、Salesforce組織の設定変更が必要です。

[設定] から [クイック検索] ボックスに「プロセスの自動化設定」と入力し、[プロセスの自動化設定] をクリックします。次に、[Apex でのレコードのロックおよびロック解除を有効化] を選択します。

参考先のドキュメント通り、[Apex でのレコードのロックおよびロック解除を有効化]を有効化します。

プロセス自動化設定画面

一括アンロックApexコード

まず、アンロック対象の見積レコード数を調べました。

ここで対象と判断する見積レコード条件は次の通りです。

  • 作成日が2021-03-20 00:00:00 より過去1
  • 状況承認ステータスが「承認済」
  • ロックされている
List<Quote> quotes = [select Id, Name FROM Quote WHERE ApprovalStatus__c = '承認済' AND CreatedDate < 2021-03-20T00:00:00+09:00 ORDER BY CreatedDate asc]; 

Integer lockedCount = 0;

for (Quote quote : quotes) {
    boolean isLocked = Approval.isLocked(quote);
    if (isLocked) { lockedCount++; }
    System.debug(quote.Name + ' (ID is ' + quote.Id + ' ) is locked? ' + isLocked);
}

System.debug('Locked Quotes Count is ' + lockedCount);

条件を満たす見積(Quote)オブジェクトをSELECTして、ApprovalクラスisLocked(sobject)メソッドでロックの有無を判断し、カウントしているだけのシンプルなコードです。

このコードを開発者コンソールの Execute Anonymous Window2 から実行しました。 Execute Anonymous Window は開発者コンソールの[Debug] > [Open Execute Anonymous Window]から開くことができます。

結果、8,187件の対象レコードがありました。

アンロック対象見積件数

次に、次のコードでロック対象の見積をアンロックしました。

List<Quote> quotes = [select Id, Name FROM Quote WHERE ApprovalStatus__c = '承認済' AND CreatedDate < 2021-03-20T00:00:00+09:00 ORDER BY CreatedDate asc]; 

Integer lockedCount = 0;
List<Quote> lockedQuotes = new List<Quote>();

for (Quote quote : quotes) {
    boolean isLocked = Approval.isLocked(quote);
    if (isLocked) {
        lockedQuotes.add(quote);
        lockedCount++;
    }
    System.debug(quote.Name + ' (ID is ' + quote.Id + ' ) is locked? ' + isLocked);
}

System.debug('Locked Quotes Count is ' + lockedCount);

Approval.UnlockResult[] lrList = Approval.unlock(lockedQuotes, false);

// Iterate through each returned result
for(Approval.UnlockResult lr : lrList) {
    if (lr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully unlocked account with ID: ' + lr.getId());
    } else {
        // Operation failed, so get all errors
        for(Database.Error err : lr.getErrors()) {
            System.debug('The following error has occurred.');
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Account fields that affected this error: ' + err.getFields());
        }
    }
}

実行後のログにエラーが記載されておらず、また、最初のコード(対象の見積数を調べるコード)を再度実行してアンロック対象見積数が0になっていることを確認して終了です。

参考情報


  1. 承認プロセスの変更を2021年03月19日の夜に行ったため。 
  2. Execute Anonymous Window はclassも作らないような短いちょっとしたコードを実行したり、組織全体への一括処理を行う際に有用です。ただし、更新処理は実際に組織のデータを書き換えるので、事故が起こらないよう使用時には注意が必要です。