0

I wanted to updated the End date whenever the start date is update and it should always calculated the end date as below End Date = start Date + warranty duration field.

the issue here is warranty duration field is picklist field and start date and end date is date field. I tried multiple ways but my end date is not populating. Is there any suggestion. it would be really helpful

Below is code only for this scenario which I have tried.

public class WarrantyClass {
    public void updateWarrantyRecords(List<Surgery__c> newSurglist, Map<Id, Surgery__c> oldSurgMap){
         
        List<NMD_Warranty__c> updateWarrantiesList = new List<NMD_Warranty__c>();
         Map<Id, List<NMD_Warranty__c>> warrantyMap = new Map<Id, List<NMD_Warranty__c>>();
        
        Set<Id> processedWarrantiesIds = new Set<Id>();   
        
        Map<String, String> inactiveReasonMapping = new Map<String, String>{
            'Device Damaged' => 'Damaged',
            'Patient Deceased' => 'Deceased' ,
            'Device Lost' => 'Lost',
            'Device Stolen' => 'Stolen',
            'Rep Entry Error' => 'Cancelled Surgery',
            'Order Cancelled' => 'Cancelled Surgery'
        };
        
        List<NMD_Warranty__c> relatedWarranties = [Select id, Surgery__c, Inactive_Reason__c, Active__c,
                                                  Start_Date__c, NMD_Serial_Number__c from NMD_Warranty__c 
                                                  where Surgery__c IN :newSurglist];
          
       for(NMD_Warranty__c warranty : relatedWarranties){           
           if(!warrantyMap.containskey(warranty.Surgery__c)){
               warrantyMap.put(warranty.Surgery__c, new List<NMD_Warranty__c>());
               warrantyMap.get(warranty.Surgery__c).add(warranty);
           }
            
            for(Surgery__c surg : newSurglist){
                if(warrantyMap.containskey(surg.Id)){
                    List<NMD_Warranty__c> warranties = warrantyMap.get(surg.Id);
                
                    for(NMD_Warranty__c war : warranties){
                        if(!processedWarrantiesIds.contains(war.Id)){
                            if(surg.Cancellation_Reason__c != oldSurgMap.get(surg.Id).Cancellation_Reason__c && war.Active__c == true) {
                                string inactiveReason = inactiveReasonMapping.get(surg.Cancellation_Reason__c);
                                system.debug('inactiveReason in@@ :'+ inactiveReason);
                    
                                if(inactiveReason != null){
                                    war.Inactive_Reason__c = inactiveReason;
                                }
                            }
                     
                           if (surg.Procedure_Date__c != oldSurgMap.get(surg.Id)?.Procedure_Date__c && war.Active__c == true) {
                               System.debug('Procedure Date changed: ' + surg.Procedure_Date__c);
                        
                               war.Start_Date__c = Date.valueOF(surg.Procedure_Date__c);
                        
                               System.debug('Start Date updated: ' + war.Start_Date__c);
                               //war.End_Date__c = Date.valueOF(surg.Procedure_Date__c);
                            
                              
                               if(surg.Model_Number__r.Warranty_Duration__c != null){
                                    Map<String, Integer> warDurationMap = new Map<String, Integer>{
                                        '1' => 1,
                                        '2' => 2,
                                        '3' => 3,
                                        '4' => 4,
                                        '5' => 5,
                                        '10' => 10
                                    };
                                         
                                    System.debug('In warDurationMap: ' + warDurationMap);            
                                   
                                    Integer warrantyears = warDurationMap.get(surg.Model_Number__r.Warranty_Duration__c);
                                    war.End_Date__c = war.Start_Date__c.addYears(warrantyears);
                                  
                                    System.debug('End Date updated: ' + war.End_Date__c);
                                }
                            }
            
                            if(surg.Patient__c != oldSurgMap.get(surg.Id).Patient__c){
                                war.Patient__c = surg.Patient__c;
                            }
                        }
                        
                        updateWarrantiesList.add(war);
                        processedWarrantiesIds.add(war.id);
                    }
                }
                                           
                if(!updateWarrantiesList.isEmpty()){
                    update updateWarrantiesList;
                                   
                    system.debug('updateWarrantiesList:' + updateWarrantiesList);
                }
            }
        }
    }

Update code below with Error

(SurgeryTrigger: execution of AfterUpdate caused by: System.ListException: Duplicate id in list: a9c8K0000008PvfQAE Class.WarrantyServiceClass.updateWarrantyRecords: line 114, column 1 Class.SurgeryTriggerHandler.bulkAfter: line 46, column 1 Class.TriggerHandlerManager.execute: line 128, column 1 Class.TriggerHandlerManager.createAndExecuteHandler: line 56, column 1 Trigger.SurgeryTrigger: line 2, column 1)

public class WarrantyClass {

public void updateWarrantyRecords(List<Surgery__c> newSurglist, Map<Id,Surgery__c> oldSurgMap){
    
    List<NMD_Warranty__c> updateWarrantiesList = new List<NMD_Warranty__c>();
    Map<Id, List<NMD_Warranty__c>> warrantyMap = new Map<Id,List<NMD_Warranty__c>>();   
    
    set<Id> processedWarrantiesIds = new set<Id>();   
    
    Map<string,string> inactiveReasonMapping = new Map<string,string>{
        
        'Device Damaged'=> 'Damaged',
            'Patient Deceased'=>'Deceased' ,
            'Device Lost'=> 'Lost',
            'Device Stolen'=> 'Stolen',
            'Rep Entry Error'=> 'Cancelled Surgery',
            'Order Cancelled'=> 'Cancelled Surgery'
            
            
            };
                
              List<NMD_Warranty__c> relatedWarranties = [Select id, Surgery__c, Inactive_Reason__c, Active__c,
                                                        Start_Date__c, End_Date__c from NMD_Warranty__c 
                                                        where Surgery__c IN :newSurglist];
    
    for(NMD_Warranty__c warranty :relatedWarranties){
        
        if(!warrantyMap.containskey(warranty.Surgery__c)){
            warrantyMap.put(warranty.Surgery__c,new list<NMD_Warranty__c>());
            warrantyMap.get(warranty.Surgery__c).add(warranty);
        }
        
        
        for(Surgery__c surg :[SELECT Id, Model_Number__r.Warranty_Duration__c,
                              Procedure_Date__c,Cancellation_Reason__c,Patient__c
                              FROM Surgery__c
                              WHERE Id IN :newSurglist]){
            
            if(warrantyMap.containskey(surg.Id)){
                List<NMD_Warranty__c> warranties = warrantyMap.get(surg.Id);
                
                for(NMD_Warranty__c war :warranties){
                    
                  if(!processedWarrantiesIds.contains(war.Id)){
                        
                   if(surg.Cancellation_Reason__c != oldSurgMap.get(surg.Id).Cancellation_Reason__c && war.Active__c == true) {
                     string inactiveReason = inactiveReasonMapping.get(surg.Cancellation_Reason__c);
                      system.debug('inactiveReason in@@ :'+ inactiveReason);
                            
                          if(inactiveReason!=null){
                           war.Inactive_Reason__c =inactiveReason;
                                
                            }
                            
                        }
                        
                        if (surg.Procedure_Date__c != oldSurgMap.get(surg.Id)?.Procedure_Date__c && war.Active__c == true) {
                            
                            System.debug('Procedure Date changed: ' + surg.Procedure_Date__c);
                            
                            war.Start_Date__c = Date.valueOF(surg.Procedure_Date__c);
                            
                            System.debug('Start Date updated:' + war.Start_Date__c);
                           // war.End_Date__c = Date.valueOF(surg.Procedure_Date__c);
                            
                            //calcualted the end date based on warrnaty duration and start date.
                            
                            
                            if(surg.Model_Number__r.Warranty_Duration__c!=null){
                                Map<string,Integer> warDurationMap = new Map<string,Integer>{
                                        '1' => 1,
                                        '2' => 2,
                                        '3' => 3,
                                        '4' => 4,
                                        '5' => 5,
                                        '10' => 10
                                        };
                                System.debug('In warDurationMap: ' + warDurationMap);            
                                
                                Integer warrantyears = warDurationMap.get(surg.Model_Number__r.Warranty_Duration__c);
                                war.End_Date__c = Date.valueOF(surg.Procedure_Date__c).addYears(warrantyears);
                                //war.End_Date__c = Date.valueOF(surg.Procedure_Date__c) + warrantyears;
                                
                                System.debug('End Date updated: ' + war.End_Date__c);
                                    }
                        }
                        
                        if(surg.Patient__c!=oldSurgMap.get(surg.Id).Patient__c){
                            war.Patient__c = surg.Patient__c;
                        }
                    }
                    
                    updateWarrantiesList.add(war);
                    processedWarrantiesIds.add(war.id);
                    
                    
                }
            }
            
            if(!updateWarrantiesList.isEmpty()){
                update updateWarrantiesList;
                
                system.debug('updateWarrantiesList:'+updateWarrantiesList);
            }
            
        }
        
    }
    
    
    
}

}

3
  • 2
    When including code, it's much better to copy/paste the code here. Screenshots aren't as accessible, can often be difficult to read (code style/formatting issues aside), and force people to manually re-type it all if they have a suggestion on how to fix an issue. The harder you make it for other people to help you, the less help you're going to get.
    – Derek F
    Apr 17 at 13:53
  • Assigning the result of Date.addYears() to a date field is correct (because we get a new Date back from that method as opposed to the method modifying the Date it's called on). There's something else in your trigger that's wrong, but we won't be able to say what specifically is wrong unless you show us all of your trigger. Could be that you're in after update and forgot to perform DML. Could be that you're in before update but you aren't working on the record instance in trigger.new/trigger.newMap. Could be something else entirely.
    – Derek F
    Apr 17 at 13:57
  • Thank you for response @DerekF - I have updated my question with full code. can you please help. all other field is getting updated properly I am having the issue only with end Date. I am really stuck on this.
    – Puja
    Apr 17 at 14:11

1 Answer 1

1

Assuming that your updateWarrantyRecords() method is being called in a trigger context (from a trigger, from a handler in a trigger framework, etc...)

Then I believe the main issue is the following line
if(surg.Model_Number__r.Warranty_Duration__c != null){

Records in trigger context variables (trigger.new, trigger.oldMap, etc...) do not contain related data. So surg.Model_Number__r is null. This special treatment of SObjects has been around since well before the Safe Navigation Operator was introduced, and is what is preventing you from getting an NPE (null pointer exception). Because the LHS of that expression evaluates to null, you're not getting into the if() block where you adjust the end date.

To work around that, you need to explicitly query for that information. Creating a formula field to pull the Model's Warranty Duration into the Surgery__c records would also work (and is probably preferable because it could prevent you from needing to use another query).

As an aside, the way you're looping over warranties is inefficient and making your life harder than it needs to be (declaring/populating/using extra maps and sets).

You can use a parent-child subquery to get all of the Warranty records associated with a given Surgery record.

So instead of

List<NMD_Warranty__c> relatedWarranties = [Select id, Surgery__c, Inactive_Reason__c, Active__c,
                                                  Start_Date__c, NMD_Serial_Number__c from NMD_Warranty__c 
                                                  where Surgery__c IN :newSurglist];
          
for(NMD_Warranty__c warranty : relatedWarranties){           
    if(!warrantyMap.containskey(warranty.Surgery__c)){
        warrantyMap.put(warranty.Surgery__c, new List<NMD_Warranty__c>());
        warrantyMap.get(warranty.Surgery__c).add(warranty);
    }
            
    for(Surgery__c surg : newSurglist){
        if(warrantyMap.containskey(surg.Id)){
            List<NMD_Warranty__c> warranties = warrantyMap.get(surg.Id);
                
            for(NMD_Warranty__c war : warranties){
                // and so on

you could instead do this

// The (SELECT ...) bit in the SELECT clause is the parent-child subquery
// You need to use the child relationship name (usually plural + __r)
// This automatically groups the child records by their corresponding parents
for(Surgery__c surgeryRec : [SELECT Id, Model_Number__r.Warranty_Duration__c, (SELECT Id, Inactive_Reason__c, Active__c, Start_Date__c, NMD_Serial_Number__c 
                                 FROM NMD_Warranties__r) 
                             FROM Surgery__c
                             WHERE Id IN :newSurglist]) {
    // Accessing the child records also uses the child relationship name
    // Using a nested loop is the safest way to get at child records
    for(Warranty__c warrantyRec : surgeryRec.NMD_Warranties__r) {
        ...
        if(surgeryRec.Model_Number__r.Warranty_Duration__c != null) {
            warrantyRec.End_Date__c = warrantyRec.Start_Date__c.addYears(numYears);
        }
    }
}

This allows you to remove the third loop, and to do away with the alreadyProcessed set, and get rid of warrantyMap.

If, for some unfathomable reason you cannot use a parent-child subquery to do this, then at the very least you should populate warrantyMap in a separate loop before you loop over the surgery records.
I.e.

List<NMD_Warranty__c> relatedWarranties = [Select id, Surgery__c, Inactive_Reason__c, Active__c,
                                                  Start_Date__c, NMD_Serial_Number__c from NMD_Warranty__c 
                                                  where Surgery__c IN :newSurglist];
 
// The only responsibility of the first loop is to populate the map         
for(NMD_Warranty__c warranty : relatedWarranties){           
    if(!warrantyMap.containskey(warranty.Surgery__c)){
        warrantyMap.put(warranty.Surgery__c, new List<NMD_Warranty__c>());
    }

    warrantyMap.get(warranty.Surgery__c).add(warranty);
}

// The surgery-warranty loop can then be brought in one level
for(Surgery__c surg : newSurglist){
    List<NMD_Warranty__c> warranties = warrantyMap.get(surg.Id);

    // Less indentation is generally better
    // Instead of doing work when warranties is not null, skip to the next Surgery
    //   if it is null
    // This is the "fail fast" ideology
    if(warranties == null){
        continue;
    }
            
    // Since we can only get here if warranties is not null, there is no more need
    //   for a null check
    for(NMD_Warranty__c war : warranties){
        // and so on
    }
}

As some closing comments:

  • Stuff that doesn't change between iterations of a loop (like warDurationMap) can be pulled out of the loop
  • Be sure to keep all of your DML (and queries) outside of all loops
  • You don't need to check if a list is empty before performing DML (it's just a waste of typing)
  • Being consistent in code formatting (capitalization, whitespace between operators and operands, indentation) makes code much easier to read and you should make an effort to pay attention to that detail
1
  • Thank you so much @Derek F - based on the suggestion I have updated the code and end date is populating correctly for one record but while updating multiple record I am getting an duplicated ID error. I tried to debug and used a map instead a set but didn't worked, it would be great if you can help a little more. I have updated the code in my question with error.
    – Puja
    Apr 17 at 16:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .