function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
PharaohgirlPharaohgirl 

Is it possible to update the status on a parent record based on the status of multiple child object records with a lookup relationship?

Hi everyone,

I am very new to Apex (as in completed the introductory Apex Trailhead badge a few days ago), so apologies if I say anything stupid or that doesn't make sense.

I have a custom object called Rulecloseout__c and a second custom object called Rule_change_milestone__c which has a lookup relationship to Rulecloseout__c.

There will be multiple milestones for each rulecloseout.

Each milestone has a status, and I want to update the parent Rulecloseout's status based on these (and every time they're edited).

So if all child milestones for a rulecloseout record are updated to be either Completed or No longer required (picklist values), then I want the Rulecloseout status to automatically be updated to Completed.

I've done quite a bit of reading, and the only possible solution I can find is an Apex trigger rollup summary of all the child milestone statuses on the Rulecloseout, and then a formula field for the status using the contains function.

1) Will this work?

2) Could someone please help me with what I need to put in the Apex Trigger?

You probably think I'm trying to run before I can walk, which is true! But I am going to go away and do the Trailhead units on Apex Triggers in the meantime.

Thanks in advance for your help.

Rowena

Andrew GAndrew G
I did something similar with Skill Requirements in a Work Order recently - so i will provide the code to let you extrapolate

The trigger layout - to handle insert, edits and deletion of the child record.  It is after as the saved child needs to be read to update the parent.
trigger CS_SkillRequirementTrigger on SkillRequirement (after insert, after update, after delete) {

    System.debug('In Trigger - cs_SkillRequirementTrigger ');

    if ( trigger.isAfter ) {
        if ( trigger.isInsert ) {
            System.debug('In Trigger - about to call on after insert');         
            cs_SkillRequirementTriggerHandler.OnAfterInsert( trigger.new );
        } else if ( trigger.isUpdate ) {
                System.debug('In Trigger - about to call on after update');         
                cs_SkillRequirementTriggerHandler.OnAfterUpdate( trigger.old, trigger.new, trigger.oldMap, trigger.newMap );
            } else if (trigger.isDelete ) {
                System.debug('In Trigger - about to call on after delete');         
                cs_SkillRequirementTriggerHandler.OnAfterDelete( trigger.old, trigger.oldMap );
            }
    }
}
The Class
As noted, the purpose was to update the Work Order if none of the associated skills were of type "site induction".
From notes - SiteInductionCheck__c is a formula number field on the Skill Requirement object testing for 'site induction' in the Name field (value being 1 or 0 )
So I used the aggregrate function to sum the value int records and then update a field on the Service Appointment.  I then had validation on teh Work Order to raise an alert in that interface.  Based on the value being equal to 0 (zero).

Instead of the aggregate function, you could loop your collection of child records testing the status and then escape if a "non closing" status was seen before end of loop.  On escape, don't update the parent record.  If you complete the loop, update the field in the parent record.  Alternately, set a boolean at the start of the loop and then update if a non closing status is tested.  
Psuedo
Boolean closeTheParent = True
Loop
       If status <> "closed status" 
           Update closeTheParent = False
End Loop
If Boolen closeTheParent
     Update parent
Else
     //do nothing  - don't update parent.

  I'm not sure what you mean by using a formula using contains.
 
/*
Author: Andrew G
Created Date: 17/09/2018
Description: Handler for Skill Requirement Trigger 
*/

public with sharing class CS_SkillRequirementTriggerHandler {

    public static void OnAfterInsert( List<SkillRequirement> newRecords ) {
    //update the Count Value when new records are inserted from trigger
         updateSiteInductionCount(newRecords);
    }

    public static void onAfterUpdate( List<SkillRequirement> oldRecords,List<SkillRequirement> updatedRecords, Map<ID,SkillRequirement> oldMap, Map<ID,SkillRequirement> newMap ) {
    //update the Count Value when records are updated from the trigger
        updateSiteInductionCount(updatedRecords);
    }
 
    public static void onAfterDelete( List<SkillRequirement> oldRecords, Map<ID,SkillRequirement> oldMap ) {
    //update the Count Value when records are deleted from the trigger
        updateSiteInductionCount(oldRecords);
    }

    //where the skill requirement is associated with a Work Order, using the aggregate function count how many skills are of type Skill Requirement
    //SiteInductionCheck__c is a formula number field on the Skill Requirement object testing for 'site induction' in the Name field
    //Update the Work Order field SiteInductionCount__c so that we can query using Formula fields and VF pages on the Work Order object
    private static void updateSiteInductionCount (List<SkillRequirement> newRecords) {

        List<Id> woIDs = new List<Id>();
        List<WorkOrder> toUpdate = new List<WorkOrder>();
        
        //skill requirement associated with Work Order Record
        for (SkillRequirement sr : newRecords) {
            if (String.valueof(sr.RelatedRecordId).startsWith('0WO')) {
                woIDs.add(sr.RelatedRecordId);  
            } 
        }
    
        for (ID woid : woIDs) {
            System.debug ('#### wo id ' + string.valueof(woid));
        }

        AggregateResult[] counts = [SELECT RelatedRecordId, sum(SiteInductionCheck__c)sic FROM SkillRequirement WHERE RelatedRecordId IN :woIds GROUP BY RelatedRecordId];
        
        if (counts.isEmpty()) {   //to handle where all related skills have been deleted
            for (ID woid : woIDs ) {
                WorkOrder tempWO = new WorkOrder(Id = woid, SiteInductionCount__c = 0);
                toUpdate.add(tempWO);
            }   
        } else {
            for (AggregateResult ar : counts ) {
                System.debug ('#### ar id ' + string.valueof(ar.get('RelatedRecordId')));
                System.debug ('#### count ' + string.valueof(ar.get('sic')));

                WorkOrder tempWO = new WorkOrder(Id=string.valueof(ar.get('RelatedRecordId')), SiteInductionCount__c=integer.valueof(ar.get('sic')));

                toUpdate.add(tempWO);
            }
        }
        update toUpdate;
    }

}


HTH

Regards

Andrew