tyoshikawa1106のブログ

- Force.com Developer Blog -

SFDC:承認履歴とSOQLクエリ【改良版】

承認履歴とSOQLクエリということで、こういうブログを書きました。


Twitterでより良い方法について教えてもらったので、こちらで追記しようと思います。


承認ステップの日付情報を取得するためにProcessInstanceNodeオブジェクトの情報を取得しましたが、この日付部分はステップレコードの作成日の値と同じものでした。


そのため、次のクエリだけで必要な情報は取得できそうです。

public List<ProcessInstance> getProcessInstances(String targetObjectId) {
    return [
        SELECT
             Id
            ,CompletedDate
            ,LastActorId
            ,ProcessDefinitionId
            ,Status
            ,TargetObjectId
            ,(
                SELECT 
                     Id
                    ,ActorId
                    ,Comments
                    ,IsPending
                    ,OriginalActorId
                    ,ProcessInstanceId
                    ,ProcessNodeId
                    ,StepStatus
                    ,TargetObjectId
                    ,CreatedDate
                FROM
                    StepsAndWorkitems
                ORDER BY CreatedDate DESC
            )
        FROM
            ProcessInstance
        WHERE
            TargetObjectId =: targetObjectId
        ORDER BY CreatedDate DESC
        LIMIT 50
    ];
}


これを踏まえて簡単なサンプルをつくって確認してみました。ステップ名の表示とか細かい部分が不要な場合はこれで問題なさそうです。
f:id:tyoshikawa1106:20160302121400p:plain

f:id:tyoshikawa1106:20160302121412p:plain


サンプルコードです。


もうひとつ、割り当て先や承認者の項目(OriginalActorIdとActorId)はなぜクエリでユーザ名まで取得できないのかなと思っていたのですが、これについても教えてもらいました。承認者の割り当てではユーザだけでなくキューも指定することが可能です。
f:id:tyoshikawa1106:20160302123748p:plain


承認申請でキューを利用する場合は、キューオブジェクトの方にクエリを実行する必要があるので、状況に応じて考慮しておく必要があるみたいです。


ちなみにキューの名前はグループオブジェクトから取得できます。

キューオブジェクト

f:id:tyoshikawa1106:20160302212002p:plain

SELECT Id,QueueId,SobjectType FROM QueueSobject
グループオブジェクト

f:id:tyoshikawa1106:20160302212011p:plain

SELECT Id,Name,Type FROM Group WHERE Type= 'Queue'


承認履歴のクエリを実行するときですが、ポータルユーザやCommunityユーザではアクセスできないオブジェクトがあるので注意が必要です。
f:id:tyoshikawa1106:20160302212834p:plain


承認履歴で考慮が必要なのはこんな感じでした。

追記

StepStatus項目とSOQL

StepStatus項目を取得すると英語で取得されます。
f:id:tyoshikawa1106:20160302224946p:plain


標準画面では日本語なのでなんでだろうと思っていたのですが、選択リスト項目でトランスレーションワークベンチで日本語変換されているだけでした。


なのでtoLabel()を利用することで日本語に変換して取得できます。
f:id:tyoshikawa1106:20160302225100p:plain
f:id:tyoshikawa1106:20160302225209p:plain


取得後にIF処理判定したりする必要はありませんでした。

ProcessHistoryとoutputField

何かと便利なoutputFieldですが、ProcessHistoryオブジェクトはちょっと特殊な感じだし利用できないかなと自分でラッパークラスして対応しようと思いました。
f:id:tyoshikawa1106:20160302233145p:plain
f:id:tyoshikawa1106:20160302233158p:plain


・・・普通にoutputFieldで対応できたのでそっちの方がシンプルになりました。
f:id:tyoshikawa1106:20160302235241p:plain
f:id:tyoshikawa1106:20160302235254p:plain


特殊なオブジェクトの場合でoutputFieldがサポートされていないケースというのも見たことがあったのですが、承認履歴は普通にサポートされていたのでそちらで対応する方が簡単です。ユーザorキューがセットされるActorId項目も簡単に表示できて便利です。
f:id:tyoshikawa1106:20160302235446p:plain


GitHubのサンプルコードも直しておきました。


また、承認履歴情報は汎用的に利用できると思うのでVisualforceコンポーネントにしておくと良さそうです。教えて貰ったコードですが、こんな感じです。

<apex:page standardController="Account">
    <c:ApprovalHistoryComponent targetObjectId="{!Account.Id}"/>
</apex:page>
<apex:component controller="ApprovalHistoryController">
    <apex:attribute name="targetObjectId" type="Id" required="true" description="ProcessInstance.TargetObjectId" assignTo="{!targetObjectId0}"/>
    <apex:pageBlock mode="detail" title="承認履歴">
        <apex:pageBlockTable value="{!history}" var="e">
            <apex:column value="{!e.ProcessNode.Name}" headerValue="ステップ"/>
            <apex:column value="{!e.CreatedDate}" headerValue="日付"/>
            <apex:column value="{!e.StepStatus}"/>
            <apex:column value="{!e.OriginalActorId}"/>
            <apex:column value="{!e.ActorId}"/>
            <apex:column value="{!e.Comments}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:component>
public class ApprovalHistoryController {

    public Id targetObjectId0 { get; set; }

    public ProcessInstanceHistory[] history {
        get {
            ProcessInstanceHistory[] xs = new ProcessInstanceHistory[] {};
            for (ProcessInstance e : [
                select
                    Id, (
                        select Id, ProcessNode.Name, CreatedDate, StepStatus, OriginalActorId, ActorId, Comments
                        from StepsAndWorkitems
                        order by IsPending desc, CreatedDate desc, Id desc
                    )
                from ProcessInstance
                where TargetObjectId = :targetObjectId0
                order by CreatedDate desc, Id desc
            ]) {
                xs.addAll(e.StepsAndWorkitems);
            }
            return xs;
        }
    }

}