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
SerahSerah 

Trigger to update a field on master object with a detail object field

I'm working with Opportunity object and OpportunityDetails object that have a master-detail relationship with one another. The master's api name is Opportunity and the detail's api name is Opportunity__Details__c.I have created a custom field in the Master object OppStatus__c.In that field I want to display the minimum status  of field Status__c value of Detail object. The field Status__c is a picklist value field with values Closed,Pending,New . And i have multiple records in the detail object .
(If the Status field in any record contains New, then it should update OppStatus field with New. 
I meant if in the records, 
for eg, Record 1 the field Status has value Closed
            Record 2 value is New, Record 3 value is Pending
           Record 4 value is Closed 

Then value should be updated in oppstatus is New. 
If in Record 2 , the value is pending or closed insted of new., the min value is pending. 

If all the values are closed, then the value closed should be updated. 

Like new is the minimum if new is not present, pending is the min. 
if pending is not present, closed is the min.) 
How to populate the field in master object. 
Thanks. 
Bryan Leaman 6Bryan Leaman 6
The following is untested code and may have typos or other issues, but the technique should be pretty sound.

You could update it whenever the opportunity is updated, something like the following, but then you'll also have to update the opportunity anytime an opportunity detail record is updated. This could be a good back-up in case of some other failure or someone trying to force an incorrect status by updating the opportunity directly.
trigger on Opportunity (before update) {
     OpportunityTriggerHandler.updateStatus(Trigger.newMap);
}

public class OpportunityTriggerHandler {
    private static Map<Id, Opportunity> oppMapWithDetails= newMap<Id, Opportunity>>();
    private void retrieveOpportunityDetails(Map<Id,Opportunity> newmap) {
        oppMapWithDetails = new Map<Id, Opportunity>([
            SELECT Id, Name, 
                  (SELECT Id, Name, Status__c FROM Opportunity_Details__r)
            FROM Opportunity
            WHERE Id in :newmap.keySet()
        ]);
    }

    private static Map<String, Integer> statusPriority = new Map<String, Integer>{
          'New' => 1,
          'Pending' => 2,
          'Closed' => 3
    }

    public static void updateStatus(Map<Id,Opportunity> newmap) {
        retrieveOpportunityDetails(newmap);
        for(Opportunity opp : newmap.values()) {
             List<Opportunity_Details__c> oppDetails = oppMapWithDetails.get(opp.Id)?.Opportunity_Details__r;
             String minStatus = null;
             Integer minStsPriority = 0;
             if (oppDetails!=null) {
                 for(Opportunity_Detail__c det : oppDetails) {
                     Integer detStsPriority = statusPriority.get(det.Status__c);
                     if (minStsPriority==0 || minStsPriority>detStsPriority) {
                        minStsPriority = detStsPriority;
                        minStatus = det.Status__c;
                 }
             }
             opp.Status__c = minStatus;
        }
    }

}

You could update the header status from a trigger on the opportunity detail, which is probably more efficient unless an update to opportunity detail is already forcing an update to the opportunity:
trigger on Opportunity_Detail__c (after insert, after update) {
     OpportunityDetailHandler.updateStatus(Trigger.newList);
}


public class OpportunityDetailHandler {

    private static Map<String, Integer> statusPriority = new Map<String, Integer>{
          'New' => 1,
          'Pending' => 2,
          'Closed' => 3
    }

   private static Map<Id, Opportunity> opportunityMap = new Map<Id, Opportunity>();
   private static void retrieveOpportunityStatus(List<Opportunity_Detail__c> newlist) {
        Set<Id> oppIds = new Set<Id>();
        for(Opportunity_Details__c oppdetail : newlist) {
             if (oppdetail.Opportunity__c!=null) oppIds.add(oppdetail.Opportunity__c);
        }
        opportunityMap = new Map<Id, Opportunity>([
             SELECT Id, Status__c
             FROM Opportunity
             WHERE Id in :oppIds
        ]);
   }


   public static void updateStatus(List<Opportunity_Detail__c> newlist) {
       retrieveOpportunityStatus(newlist);
       Map<Id, Opportunity> updOpportunity = new Map<Id, Opportunity>();
       for(Opportunity_Detail__c oppdetail : newlist) {
            Opportunity opp = opportunityMap.get(oppdetail.Opportunity__c);
            if (opp!=null) {
                Integer oppStsPriority = statusPriority.get(opp.Status__c);
                Integer detStsPriority = statusPriority.get(det.Status__c);
                if (detStsPriority < oppStsPriority) {   // assumes no missing statuses!
                    opp.Status__c = det.Status__c;       // save new status for next detail record for same opp!
                    updOpportunity.put(opp.Id, new Opportunity(Id=opp.Id, Status__c=det.Status__c));
                }
            }
       }
       if (updOpportunity.size()>0) update(updOpportunity.values());
   }
}