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
Anoop Patel 7Anoop Patel 7 

How can you prevent users from deleting a record based on certain criteria?

I have written the code below to stop any users from deleting a record on my custom object (Service Items) if the related Opportunity is Closed Won. This is within another trigger that I have already developed and tested but now when I try to save I get a error message 'Error: Compile Error: line breaks not allowed in string literals at line 36 column -1'. I'm not even sure if the new piece of code will do what I want.

if(Trigger.isDelete && Trigger.isBefore){
        for (Service_Item__c si: trigger.old){
        if(si.Opportunity__c!= null){
          qoppIds.add(si.Opportunity__c);
            system.debug('oqppid++'+ qoppIds);
             }  
           }    
      qoppdetails = [select Id,StageName from Opportunity where Id in : qoppIds];
        system.debug('qoppdetails++'+ qoppdetails);           
       
       for(Opportunity q : qoppdetails){
       if(q.StageName=='Closed Won') - this is line 36 in my code.
      {
       q.adderror(‘Do Not Delete.Thank you.');
      }
      }
      }
Best Answer chosen by Anoop Patel 7
Denis VakulishinDenis Vakulishin
Yes, Just because qoppdetails is declared in IF statement for insert and update. Sorry.
Try this 
trigger PopulateAccountfromOpp on Service_Item__c(before insert, before update){
 if((Trigger.isInsert || Trigger.isUpdate)&& Trigger.isBefore){
  Set<Id> oppIds = new Set<Id>();
  List<Opportunity> oppdetails = new List <Opportunity>();
  Set<Id> qoppIds = new Set<Id>();

  List<Opportunity> qoppdetails = new List <Opportunity>();


  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c!= null){
      oppIds.add(ser.Opportunity__c);
      system.debug('oppid++'+ oppIds);
    }  
  }    
  oppdetails = [select Id,Accountid from Opportunity where Id in : oppIds];
  system.debug('oppdetails++'+ oppdetails);

  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c != null) {  
     ser.Account__c = oppdetails[0].Accountid;
    } 
  } 
}
  if(Trigger.isDelete && Trigger.isBefore){

    Map<Id, List<Service_Item__c>> oppIdToSItem = new Map<Id, List<Service_Item__c>>();
    for (Service_Item__c si: trigger.old){
        if(si.Opportunity__c!= null){
          if(oppIdToSItem.containsKey(si.Opportunity__c))
            oppIdToSItem.get(si.Opportunity__c).add(si);
          else
            oppIdToSItem.put(si.Opportunity__c,new List<Service_Item__c>{si});
          system.debug('oqppid++'+ qoppIds);
        }  
    }    
    List<Opportunity> qoppdetails = [select Id,StageName from Opportunity where Id in : oppIdToSItem.keySet()];
    system.debug('qoppdetails++'+ qoppdetails);           

    for(Opportunity q : qoppdetails){
     if(q.StageName=='Closed Won')
     {
       List<Service_Item__c> denyDeleteServiceItems = oppIdToSItem.get(q.Id);
       for(Service_Item__c si : denyDeleteServiceItems)
       {
        si.addError('Do not delete. There\'s object has reference to closed Opportunity');
       }
     }
   }
  }
}


All Answers

KevinPKevinP
Can you post the full code. I suspect the line number is off.
Anoop Patel 7Anoop Patel 7
trigger PopulateAccountfromOpp on Service_Item__c(before insert, before update){

      Set<Id> oppIds = new Set<Id>();
      List<Opportunity> oppdetails = new List <Opportunity>();
      Set<Id> qoppIds = new Set<Id>();
      List<Opportunity> qoppdetails = new List <Opportunity>();
     
    
      for(Service_Item__c ser : trigger.new){
        if(ser.Opportunity__c!= null){
          oppIds.add(ser.Opportunity__c);
            system.debug('oppid++'+ oppIds);
        }  
           }    
      oppdetails = [select Id,Accountid from Opportunity where Id in : oppIds];
        system.debug('oppdetails++'+ oppdetails);
    
      for(Service_Item__c ser : trigger.new){
        if(ser.Opportunity__c != null) {  
         ser.Account__c = oppdetails[0].Accountid;
        }
      }
      if(Trigger.isDelete && Trigger.isBefore){
        for (Service_Item__c si: trigger.old){
        if(si.Opportunity__c!= null){
          qoppIds.add(si.Opportunity__c);
            system.debug('oqppid++'+ qoppIds);
             }  
           }    
      qoppdetails = [select Id,StageName from Opportunity where Id in : qoppIds];
        system.debug('qoppdetails++'+ qoppdetails);           
       
       for(Opportunity q : qoppdetails){
       if(q.StageName=='Closed Won')
      {
       q.adderror(‘Do Not Delete.Thank you.');
      }
      }
      }
}
Denis VakulishinDenis Vakulishin
In your pasted code line 36 is
q.adderror(‘Do Not Delete.Thank you.');

First quotation mark is incorrect. It looks like apostrophe mark. Try to replace iwth this 
q.adderror('Do Not Delete.Thank you.');


Shri RajShri Raj
I think you also need to add the event in the trigger. 

trigger PopulateAccountfromOpp on Service_Item__c(before insert, before update, Before Delete){


}
Anoop Patel 7Anoop Patel 7
Thanks Denis and Shri small mistakes from my part.

I have made the changes and now receiving the error below when I delete the Service Item record from Opportunity or the record itself.

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger PopulateAccountfromOpp caused an unexpected exception, contact your administrator: PopulateAccountfromOpp: execution of BeforeDelete caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.PopulateAccountfromOpp: line 9, column 1".
Denis VakulishinDenis Vakulishin
HI, 
From Docs about Trigger.new

"Note that this sObject list is only available in insert and update triggers, and the records can only be modified in before triggers."

So you cannot use Trigger.new in Delete trigger.
Anoop Patel 7Anoop Patel 7
Hi Denis,

What can I use then to make this work?

Denis VakulishinDenis Vakulishin
Hi, 
Try this. 
trigger PopulateAccountfromOpp on Service_Item__c(before insert, before update){
 if((Trigger.isInsert || Trigger.isUpdate)&& Trigger.isBefore){
  Set<Id> oppIds = new Set<Id>();
  List<Opportunity> oppdetails = new List <Opportunity>();
  Set<Id> qoppIds = new Set<Id>();

  List<Opportunity> qoppdetails = new List <Opportunity>();


  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c!= null){
      oppIds.add(ser.Opportunity__c);
      system.debug('oppid++'+ oppIds);
    }  
  }    
  oppdetails = [select Id,Accountid from Opportunity where Id in : oppIds];
  system.debug('oppdetails++'+ oppdetails);

  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c != null) {  
     ser.Account__c = oppdetails[0].Accountid;
    } 
  } 
}
  if(Trigger.isDelete && Trigger.isBefore){
    Map<Id, List<Service_Item__c>> oppIdToSItem = new Map<Id, List<Service_Item__c>>();
    for (Service_Item__c si: trigger.old){
        if(si.Opportunity__c!= null){
          qoppIds.add(si.Opportunity__c);
          if(oppIdToSItem.containsKey(si.Opportunity__c))
            oppIdToSItem.get(si.Opportunity__c).add(si);
          else
            oppIdToSItem.put(si.Opportunity__c,new List<Service_Item__c>{si});
          system.debug('oqppid++'+ qoppIds);
        }  
    }    
    qoppdetails = [select Id,StageName from Opportunity where Id in : qoppIds];
    system.debug('qoppdetails++'+ qoppdetails);           

    for(Opportunity q : qoppdetails){
     if(q.StageName=='Closed Won')
     {
       List<Service_Item__c> denyDeleteServiceItems = oppIdToSItem.get(q.Id);
       for(Service_Item__c si : denyDeleteServiceItems)
       {
        si.addError('Do not delete. There\'s object has reference to closed Opportunity');
       }
     }
   }
  }
}

Anoop Patel 7Anoop Patel 7
I now get a error message below

Error: Compile Error: Variable does not exist: qoppdetails at line 37 column 5

qoppdetails = [select Id,StageName from Opportunity where Id in : qoppIds];
Denis VakulishinDenis Vakulishin
Yes, Just because qoppdetails is declared in IF statement for insert and update. Sorry.
Try this 
trigger PopulateAccountfromOpp on Service_Item__c(before insert, before update){
 if((Trigger.isInsert || Trigger.isUpdate)&& Trigger.isBefore){
  Set<Id> oppIds = new Set<Id>();
  List<Opportunity> oppdetails = new List <Opportunity>();
  Set<Id> qoppIds = new Set<Id>();

  List<Opportunity> qoppdetails = new List <Opportunity>();


  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c!= null){
      oppIds.add(ser.Opportunity__c);
      system.debug('oppid++'+ oppIds);
    }  
  }    
  oppdetails = [select Id,Accountid from Opportunity where Id in : oppIds];
  system.debug('oppdetails++'+ oppdetails);

  for(Service_Item__c ser : trigger.new){
    if(ser.Opportunity__c != null) {  
     ser.Account__c = oppdetails[0].Accountid;
    } 
  } 
}
  if(Trigger.isDelete && Trigger.isBefore){

    Map<Id, List<Service_Item__c>> oppIdToSItem = new Map<Id, List<Service_Item__c>>();
    for (Service_Item__c si: trigger.old){
        if(si.Opportunity__c!= null){
          if(oppIdToSItem.containsKey(si.Opportunity__c))
            oppIdToSItem.get(si.Opportunity__c).add(si);
          else
            oppIdToSItem.put(si.Opportunity__c,new List<Service_Item__c>{si});
          system.debug('oqppid++'+ qoppIds);
        }  
    }    
    List<Opportunity> qoppdetails = [select Id,StageName from Opportunity where Id in : oppIdToSItem.keySet()];
    system.debug('qoppdetails++'+ qoppdetails);           

    for(Opportunity q : qoppdetails){
     if(q.StageName=='Closed Won')
     {
       List<Service_Item__c> denyDeleteServiceItems = oppIdToSItem.get(q.Id);
       for(Service_Item__c si : denyDeleteServiceItems)
       {
        si.addError('Do not delete. There\'s object has reference to closed Opportunity');
       }
     }
   }
  }
}


This was selected as the best answer
Anoop Patel 7Anoop Patel 7
Thanks Denis.

Code saved successfully but it allows me to delete the record from both the Opp and the Service Item objects.
Denis VakulishinDenis Vakulishin
Can you add debug logs after this line 
si.addError('Do not delete. There\'s object has reference to closed Opportunity')

and tell me if your code reaches this line?
Anoop Patel 7Anoop Patel 7
I found the issue! :)

the before delete function is missing and code works as expected!

Thanks Denis much appreciated. 
Denis VakulishinDenis Vakulishin
Oh, yep. I forgot to add it after copying the code, sorry.

I'm glad to hear that you found the solution