3

In the following linked image is the Salesforce ERD for Process objects:

Process ERD

However I can't understand why I can use the following subquery to get a "invisible" child object for process:

[select Id, Status, TargetObjectId, ElapsedTimeInMinutes, 
                       (select ActorId, Comments, ProcessInstanceId, OriginalActorId, StepStatus from Steps order by CreatedDate asc), 
                       (select Id, ActorId, ProcessInstanceId FROM Workitems),
                       (select Id, ProcessInstanceId FROM Nodes)
                       from ProcessInstance where TargetObjectId =: recordId order by ElapsedTimeInMinutes ASC];

Is the documentation out of date or am I not understanding something here?

Thanks,

Sam

* EDIT *

Bonus points if you can show a code sample of how all the objects can be manipulated via Apex!

1 Answer 1

2

The primary question is something only the documentation team could answer. I do know that ProcessInstanceNode is a newer object than Approvals, so it may have simply slipped through the cracks (i.e. you may very well be correct that the documentation needs updating). Or, perhaps the documentation team felt it wasn't important enough to note in the ERD. Personally, I'd suggest you file feedback on the page for the documentation team to follow up on.

For the bonus question, the answer is that you can't "directly" manipulate these objects in Apex Code, in the same manner that you can manipulate accounts, for example. There's an example of how to move between approval steps, and you'll want to review the Approval documentation as well.

I've included the code from the example here:

public class TestApproval {
    void submitAndProcessApprovalRequest() {
        // Insert an account
        Account a = new Account(Name='Test',annualRevenue=100.0);
        insert a;

        User user1 = [SELECT Id FROM User WHERE Alias='SomeStandardUser'];

        // Create an approval request for the account
        Approval.ProcessSubmitRequest req1 = 
            new Approval.ProcessSubmitRequest();
        req1.setComments('Submitting request for approval.');
        req1.setObjectId(a.id);

        // Submit on behalf of a specific submitter
        req1.setSubmitterId(user1.Id); 

        // Submit the record to specific process and skip the criteria evaluation
        req1.setProcessDefinitionNameOrId('PTO_Request_Process');
        req1.setSkipEntryCriteria(true);

        // Submit the approval request for the account
        Approval.ProcessResult result = Approval.process(req1);

        // Verify the result
        System.assert(result.isSuccess());

        System.assertEquals(
            'Pending', result.getInstanceStatus(), 
            'Instance Status'+result.getInstanceStatus());

        // Approve the submitted request
        // First, get the ID of the newly created item
        List<Id> newWorkItemIds = result.getNewWorkitemIds();

        // Instantiate the new ProcessWorkitemRequest object and populate it
        Approval.ProcessWorkitemRequest req2 = 
            new Approval.ProcessWorkitemRequest();
        req2.setComments('Approving request.');
        req2.setAction('Approve');
        req2.setNextApproverIds(new Id[] {UserInfo.getUserId()});

        // Use the ID from the newly created item to specify the item to be worked
        req2.setWorkitemId(newWorkItemIds.get(0));

        // Submit the request for approval
        Approval.ProcessResult result2 =  Approval.process(req2);

        // Verify the results
        System.assert(result2.isSuccess(), 'Result Status:'+result2.isSuccess());

        System.assertEquals(
            'Approved', result2.getInstanceStatus(), 
            'Instance Status'+result2.getInstanceStatus());
    }
}

You'll notice that nowhere in the code do you refer to ProcessInstanceWorkItem, ProcessInstanceStep, ProcessInstanceNode, ProcessInstanceHistory, or ProcessInstance directly. You always use the Approval class to submit, approve, or reject an approval process or process step.

2
  • Thanks for the answer, why do you suppose that these classes are publically accessible? Is it strictly meant for querying and not manipulation directly?
    – user24634
    Jul 27, 2016 at 14:29
  • 1
    @SamCousins Yes, it's meant to be able to see the current state and history of the approval for a record. Even in the SOAP API, the objects are listed as "describeSObject", "query", and "retrieve", meaning that they are indeed read-only. I suppose they did this to help limit the possibility of people doing unusual things to those records, like perhaps trying to un-abort an aborted status.
    – sfdcfox
    Jul 27, 2016 at 14:44

You must log in to answer this question.