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
Mitchell McLaughlin 1Mitchell McLaughlin 1 

Error on Delete - Trigger

Hi -
I'm getting this error when I try to hard delete a Service_Staff_Assignment__c object record. 

Validation Errors While Saving Record(s)
There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger ServiceStaffAssignmentTrigger caused an unexpected exception, contact your administrator: ServiceStaffAssignmentTrigger: System.LimitException: Apex CPU time limit exceeded". 


Here's the trigger. 

trigger ServiceStaffAssignmentTrigger on Service_Staff_Assignment__c (after insert, after update, after delete) {
  if (Trigger.isAfter) {
    if (Trigger.isInsert) {
      Service_Staff_Assignment__c[] assignments = Trigger.new;
      ServiceStaffAssignmentServices.setSalesRepOnCustomerSegment(assignments);
      ServiceStaffSharing.newServiceStaffSharing(Trigger.new);
    } else if (Trigger.isUpdate) {
      Service_Staff_Assignment__c[] assignments = Trigger.new;
      ServiceStaffAssignmentServices.setSalesRepOnCustomerSegment(assignments);
    } else if (Trigger.isDelete) {
      ServiceStaffSharing.deleteServiceStaffSharing(Trigger.oldMap, Trigger.newMap);
    }
  }
}

The strange thing is I cannot replicate the problem in the Beta environment, and I cannot edit/inactivate the trigger directly in production. The only thing I can think of is to promote this trigger when it's deactivate back to production, or possibly delete the trigger some how, and then put it back into the system.

I don't think the trigger is a big issue, because it's only one record!!

Any suggestions on maybe how to hard delete directly from the database, or get around this trigger, or fix this trigger perhaps?

Thanks!

Magesh Mani YadavMagesh Mani Yadav
Hi Mitchell

Can you provide me code for class "ServiceStaffAssignmentServices" and "ServiceStaffSharing" that will help me in identifying the issue.

Thanks 
Magesh
Mitchell McLaughlin 1Mitchell McLaughlin 1
Ah, of course. Thank you!
 
public with sharing class ServiceStaffAssignmentServices {

  public static void setSalesRepOnCustomerSegment(Service_Staff_Assignment__c[] serviceStaffAssignments) 
  {
     Set<Id> customerSegmentIds = new Set<Id>();
     Set<Id> serviceStaffIds = new Set<Id>();
     
     for (Service_Staff_Assignment__c assignment : serviceStaffAssignments)
     {
       if (IsActiveSalesRep(assignment))
       {
         customerSegmentIds.add(assignment.Customer_Segment__c);
         serviceStaffIds.add(assignment.Service_Staff__c);
        }
     } 
     
     
     Map<Id,Customer_Segment__c> customerSegments = new Map<Id,Customer_Segment__c>(
       [SELECT Sales_Rep__c FROM Customer_Segment__c WHERE id in :customerSegmentIds  ]
     );
     
     Map<Id,Service_Staff__c> serviceStaffs = new Map<Id,Service_Staff__c>(
       [SELECT User__c FROM Service_Staff__c WHERE id in :serviceStaffIds  ]
     ); 
     
     
     for (Service_Staff_Assignment__c assignment : serviceStaffAssignments)
     {
       if (IsActiveSalesRep(assignment))
       {
         Customer_Segment__c matchingSegment = customerSegments.get(assignment.Customer_Segment__c);
         Service_Staff__c serviceStaff =  serviceStaffs.get(assignment.Service_Staff__c);
         
         if (matchingSegment.Sales_Rep__c != serviceStaff.User__c)
         {
           matchingSegment.Sales_Rep__c = serviceStaff.User__c;
           update matchingSegment;
         }
        }
     }
  }
  
  @TestVisible private static boolean IsActiveSalesRep(Service_Staff_Assignment__c assignment){
    if (assignment.Employee_Role__c == 'Sales Representative' && assignment.Active__c)
    {
      return true;
    } else {
      return false;
    }
    
  }
  
}

 
 
 
 
 
 
public class ServiceStaffSharing {

  public static void newServiceStaffSharing(List<Service_Staff_Assignment__c> assignments) {

    Set<Id> testSetIds = new Set<Id>();
    for (Service_Staff_Assignment__c assignment : assignments) {
      testSetIds.add(assignment.Id);
    }

    List<Service_Staff_Assignment__c> assignmentList = [SELECT Id, Salesforce_User_ID__c, Account__c, Employee_Role__c FROM Service_Staff_Assignment__c
            WHERE Id IN :testSetIds];

    List<Service_Staff_Role_Right__c> serviceStaffRoles = Service_Staff_Role_Right__c.getall().values();
    Set<Id> custSegIds = new Set<Id>();


    Set<String> roles = new Set<String>();
    for (Service_Staff_Role_Right__c ssrr : serviceStaffRoles) {
      roles.add(ssrr.Role__c);
    }

    AccountShare accountShr;
    AccountTeamMember acctTM;
    Customer_Segment__Share customerSegmentShare;
    Credit_Request__Share creditRequestShare;

    List<AccountShare> accShares = new List<AccountShare>();
    List<AccountTeamMember> accTMListToInsert = new List<AccountTeamMember>();
    List<Customer_Segment__Share> custSegShares = new List<Customer_Segment__Share>();
    List<Credit_Request__Share> credReqShares = new List<Credit_Request__Share>();
    Map<Id, List<Service_Staff_Assignment__c>> accId2SSAList = new Map<Id, List<Service_Staff_Assignment__c>>();

    String accLevel;
    Boolean hasUserId;

    for (Service_Staff_Assignment__c serviceStaffAssignment : assignments) {

      accLevel = Utilities.checkAccessLevel(serviceStaffAssignment, serviceStaffRoles);
      hasUserId = checkSFUserId(assignmentList, serviceStaffAssignment);

      if (hasUserId && roles.contains(serviceStaffAssignment.Employee_Role__c)) {
        accountShr = new AccountShare();
        acctTM = new AccountTeamMember();
        acctTM.AccountId = serviceStaffAssignment.Account__c;
        acctTM.UserId = serviceStaffAssignment.Salesforce_User_ID__c;
        acctTM.TeamMemberRole = 'Service Staff';
        accountShr.AccountId = serviceStaffAssignment.Account__c;
        accountShr.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        accountShr.AccountAccessLevel = accLevel;
        accountShr.CaseAccessLevel = accLevel;
        accountShr.ContactAccessLevel = accLevel;
        accountShr.OpportunityAccessLevel = 'none';
        accShares.add(accountShr);
        accTMListToInsert.add(acctTM);

        System.debug('accTMListToInsert'+accTMListToInsert);


        customerSegmentShare = new Customer_Segment__Share();
        customerSegmentShare.ParentId = serviceStaffAssignment.Customer_Segment__c;
        customerSegmentShare.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        customerSegmentShare.AccessLevel = accLevel;
        custSegShares.add(customerSegmentShare);

        custSegIds.add(serviceStaffAssignment.Customer_Segment__c);

        if (accId2SSAList.containsKey(serviceStaffAssignment.Account__c)) {
          accId2SSAList.get(serviceStaffAssignment.Account__c).add(serviceStaffAssignment);
        } else {
          accId2SSAList.put(serviceStaffAssignment.Account__c, new List<Service_Staff_Assignment__c> {serviceStaffAssignment});
        }
      }
    }

    List<Account> accList = [SELECT Id,
                             (SELECT Id FROM Credit_Requests__r)
                             FROM Account WHERE Id IN :accId2SSAList.keySet()];

    for (Account acc : accList) {
      for (Service_Staff_Assignment__c ssa : accId2SSAList.get(acc.Id)) {
        accLevel = Utilities.checkAccessLevel(ssa, serviceStaffRoles);

        for (Credit_Request__c cr : acc.Credit_Requests__r) {
          creditRequestShare = new Credit_Request__Share();
          creditRequestShare.ParentId = cr.Id;
          creditRequestShare.UserOrGroupId = ssa.Salesforce_User_ID__c;
          creditRequestShare.AccessLevel = accLevel;
          credReqShares.add(creditRequestShare);
        }
      }
    }

    List<Opportunity_Segment__c> oppSegList = [
                SELECT Id, Opportunity__c, Customer_Segment__c
                FROM Opportunity_Segment__c
                WHERE Customer_Segment__c IN :custSegIds
            ];
    OpportunitySegmentSharing.newOpportunitySegmentSharing(oppSegList);

    try {
      Database.SaveResult[] srList = Database.insert(accShares, false);
      Database.SaveResult[] srList2 = Database.insert(custSegShares, false);
      Database.SaveResult[] srList3 = Database.insert(credReqShares, false);
//      Database.SaveResult[] srList4 = Database.insert(accTMListToInsert, false);
    } catch (Exception e) {
      System.debug(LoggingLevel.ERROR, 'INSERT FAILED ' + e.getMessage());
    }
  }

  public static void deleteServiceStaffSharing(Map<Id, Service_Staff_Assignment__c> assignmentsMapOld,
          Map<Id, Service_Staff_Assignment__c> assignmentsMapNew
                                              ) {
    List<Id> custSegIds = new List<Id>();
    List<Id> accIds = new List<Id>();
    List<Service_Staff_Assignment__c> assignments = new List<Service_Staff_Assignment__c>();

    for (Service_Staff_Assignment__c ssa : assignmentsMapOld.values()) {
      custSegIds.add(ssa.Customer_Segment__c);
      accIds.add(ssa.Account_Id__c);
    }

    if (!custSegIds.isEmpty()) {
      for (Customer_Segment__c custSeg : [
                  SELECT Id, Account__c,
                  (SELECT Id, Employee_Role__c, Account__c, Salesforce_User_ID__c, Customer_Segment__c
                   FROM Service_Staff_Assignments__r
                  )
                  FROM Customer_Segment__c
                  WHERE Account__c IN :accIds]
          ) {
        if (custSeg.Service_Staff_Assignments__r.size() > 0) {
          for (Service_Staff_Assignment__c ssa : custSeg.Service_Staff_Assignments__r) {
            assignments.add(ssa);
          }
        }
      }

      List<Account> accList = [SELECT Id,
                               (SELECT Id FROM Opportunities),
                               (SELECT Id FROM Credit_Requests__r ),
                               (SELECT Id FROM Customer_Segments__r)
                               FROM Account WHERE Id IN :accIds];


      List<Id> oppIds = new List<Id>();
      for (Account acc : accList) {
        for (Opportunity opp : acc.Opportunities) {
          oppIds.add(opp.Id);
        }
      }

      List<Id> credReqIds = new List<Id>();
      for (Account acc : accList) {
        for (Credit_Request__c cr : acc.Credit_Requests__r) {
          credReqIds.add(cr.Id);
        }
      }

      List<AccountShare> accShares = [SELECT Id FROM AccountShare WHERE AccountId IN :accIds];
      List<OpportunityShare> oppShares = [SELECT Id FROM OpportunityShare WHERE OpportunityId IN :oppIds];
      List<Credit_Request__Share> credReqShares = [SELECT Id FROM Credit_Request__Share WHERE ParentId IN :credReqIds];
      List<Customer_Segment__Share> custSegShares = [SELECT Id FROM Customer_Segment__Share WHERE ParentId IN :custSegIds];

      try {
        Database.DeleteResult[] drListAcc = Database.delete(accShares, false);
        Database.DeleteResult[] drListOpp = Database.delete(oppShares, false);
        Database.DeleteResult[] drListCR = Database.delete(credReqShares, false);
        Database.DeleteResult[] drListCS = Database.delete(custSegShares, false);
      } catch (Exception e) {
        System.debug(LoggingLevel.ERROR, 'DELETE FAILED ' + e.getMessage());
      }
    }
    if (assignments != null) {
      newServiceStaffSharing(assignments);
    }
  }

  private static Boolean checkSFUserId(List<Service_Staff_Assignment__c> assignmentList, Service_Staff_Assignment__c assignmentToCheck) {
    for (Service_Staff_Assignment__c assignment : assignmentList) {
      if (assignment.Id == assignmentToCheck.Id
              && assignmentToCheck.Salesforce_User_ID__c != null) {
        return true;
      }
    }
    return false;
  }
}

 
 
Magesh Mani YadavMagesh Mani Yadav
Hi Mitchell,

There is an update DML statement in the for loop and also i did some refactoring
public static void setSalesRepOnCustomerSegment(Service_Staff_Assignment__c[] serviceStaffAssignments) 
  {
     Set<Id> customerSegmentIds = new Set<Id>();
     Set<Id> serviceStaffIds = new Set<Id>();
     Map<Id,Service_Staff_Assignment__c> mapOfValidServiceStaffAssignments= new Map<Id,Service_Staff_Assignment__c>();
     List<Customer_Segment__c> updateCustomerSegment = new List<Customer_Segment__c>();
     Map<Id,Service_Staff_Assignment__c>  CustomerAndServiceStaffIds = new Map<Id,Service_Staff_Assignment__c>();
     
     for (Service_Staff_Assignment__c assignment : serviceStaffAssignments)
     {
       if (IsActiveSalesRep(assignment))
       {
          mapOfValidServiceStaffAssignments.put(assignment.Id,assignment);
         customerSegmentIds.add(assignment.Customer_Segment__c);
         serviceStaffIds.add(assignment.Service_Staff__c);
        }
     } 
     Map<Id,Customer_Segment__c> customerSegments = new Map<Id,Customer_Segment__c>(
       [SELECT Sales_Rep__c FROM Customer_Segment__c WHERE id in :customerSegmentIds  ]
     );
     
     Map<Id,Service_Staff__c> serviceStaffs = new Map<Id,Service_Staff__c>(
       [SELECT User__c FROM Service_Staff__c WHERE id in :serviceStaffIds]
     ); 
     
     for (Service_Staff_Assignment__c assignment : mapOfValidServiceStaffAssignments.values())
     {
         Customer_Segment__c matchingSegment = customerSegments.get(assignment.Customer_Segment__c);
         Service_Staff__c serviceStaff =  serviceStaffs.get(assignment.Service_Staff__c);
         if (matchingSegment.Sales_Rep__c != serviceStaff.User__c)
         {
           matchingSegment.Sales_Rep__c = serviceStaff.User__c;
          updateCustomerSegment.add(matchingSegment);
         }
      }

      update updateCustomerSegment;
  }

 
Magesh Mani YadavMagesh Mani Yadav
Please find my comments in the code.
  public static void newServiceStaffSharing(List<Service_Staff_Assignment__c> assignments) {
    //No Need for this loop
    //Set<Id> testSetIds = new Set<Id>();
    //for (Service_Staff_Assignment__c assignment : assignments) {
    //  testSetIds.add(assignment.Id);
    //}

    // No need for this SOQL as you already have it in 'assignments'
    //List<Service_Staff_Assignment__c> assignmentList = [SELECT Id, Salesforce_User_ID__c, Account__c, Employee_Role__c FROM Service_Staff_Assignment__c
    //        WHERE Id IN :testSetIds];

    List<Service_Staff_Role_Right__c> serviceStaffRoles = Service_Staff_Role_Right__c.getall().values();
    Set<Id> custSegIds = new Set<Id>();


    Set<String> roles = new Set<String>();
    for (Service_Staff_Role_Right__c ssrr : serviceStaffRoles) {
      roles.add(ssrr.Role__c);
    }

    AccountShare accountShr;
    AccountTeamMember acctTM;
    Customer_Segment__Share customerSegmentShare;
    Credit_Request__Share creditRequestShare;

    List<AccountShare> accShares = new List<AccountShare>();
    List<AccountTeamMember> accTMListToInsert = new List<AccountTeamMember>();
    List<Customer_Segment__Share> custSegShares = new List<Customer_Segment__Share>();
    List<Credit_Request__Share> credReqShares = new List<Credit_Request__Share>();
    Map<Id, List<Service_Staff_Assignment__c>> accId2SSAList = new Map<Id, List<Service_Staff_Assignment__c>>();

    String accLevel;
    Boolean hasUserId;

    for (Service_Staff_Assignment__c serviceStaffAssignment : assignments) {

      accLevel = Utilities.checkAccessLevel(serviceStaffAssignment, serviceStaffRoles);

      // Why do you pass a list to the checkSFUserId method? because you are in loop why dont you check for each assigment ? 
      //hasUserId = checkSFUserId(assignmentList, serviceStaffAssignment);
      hasUserId = checkSFUserId(assignments, serviceStaffAssignment); // Please check this method because this is something which you need to avoid. Its better to check for single serviceStaffAssignment than LIST in a for loop

      if (hasUserId && roles.contains(serviceStaffAssignment.Employee_Role__c)) {
        accountShr = new AccountShare();
        acctTM = new AccountTeamMember();
        acctTM.AccountId = serviceStaffAssignment.Account__c;
        acctTM.UserId = serviceStaffAssignment.Salesforce_User_ID__c;
        acctTM.TeamMemberRole = 'Service Staff';
        accountShr.AccountId = serviceStaffAssignment.Account__c;
        accountShr.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        accountShr.AccountAccessLevel = accLevel;
        accountShr.CaseAccessLevel = accLevel;
        accountShr.ContactAccessLevel = accLevel;
        accountShr.OpportunityAccessLevel = 'none';
        accShares.add(accountShr);
        accTMListToInsert.add(acctTM);

        System.debug('accTMListToInsert'+accTMListToInsert);


        customerSegmentShare = new Customer_Segment__Share();
        customerSegmentShare.ParentId = serviceStaffAssignment.Customer_Segment__c;
        customerSegmentShare.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        customerSegmentShare.AccessLevel = accLevel;
        custSegShares.add(customerSegmentShare);

        custSegIds.add(serviceStaffAssignment.Customer_Segment__c);

        if (accId2SSAList.containsKey(serviceStaffAssignment.Account__c)) {
          accId2SSAList.get(serviceStaffAssignment.Account__c).add(serviceStaffAssignment);
        } else {
          accId2SSAList.put(serviceStaffAssignment.Account__c, new List<Service_Staff_Assignment__c> {serviceStaffAssignment});
        }
      }
    }

    List<Account> accList = [SELECT Id,
                             (SELECT Id FROM Credit_Requests__r)
                             FROM Account WHERE Id IN :accId2SSAList.keySet()];

    for (Account acc : accList) {
      for (Service_Staff_Assignment__c ssa : accId2SSAList.get(acc.Id)) {
        accLevel = Utilities.checkAccessLevel(ssa, serviceStaffRoles);

        for (Credit_Request__c cr : acc.Credit_Requests__r) {
          creditRequestShare = new Credit_Request__Share();
          creditRequestShare.ParentId = cr.Id;
          creditRequestShare.UserOrGroupId = ssa.Salesforce_User_ID__c;
          creditRequestShare.AccessLevel = accLevel;
          credReqShares.add(creditRequestShare);
        }
      }
    }

    List<Opportunity_Segment__c> oppSegList = [
                SELECT Id, Opportunity__c, Customer_Segment__c
                FROM Opportunity_Segment__c
                WHERE Customer_Segment__c IN :custSegIds
            ];
    OpportunitySegmentSharing.newOpportunitySegmentSharing(oppSegList); // Am not sure whats happening in this method!

    try {
      Database.SaveResult[] srList = Database.insert(accShares, false);
      Database.SaveResult[] srList2 = Database.insert(custSegShares, false);
      Database.SaveResult[] srList3 = Database.insert(credReqShares, false);
//      Database.SaveResult[] srList4 = Database.insert(accTMListToInsert, false);
    } catch (Exception e) {
      System.debug(LoggingLevel.ERROR, 'INSERT FAILED ' + e.getMessage());
    }
  }

 
Magesh Mani YadavMagesh Mani Yadav

Hi metchell,

There is no need for this below method at all because you are passing same list of Service_Staff_Assignment__c with same record

private static Boolean checkSFUserId(List<Service_Staff_Assignment__c> assignmentList, Service_Staff_Assignment__c assignmentToCheck) {
    for (Service_Staff_Assignment__c assignment : assignmentList) {
      if (assignment.Id == assignmentToCheck.Id
              && assignmentToCheck.Salesforce_User_ID__c != null) {
        return true;
      }
    }
    return false;
  }

Instead you can put an if condition in the below code of newServiceStaffSharing method
//if (hasUserId && roles.contains(serviceStaffAssignment.Employee_Role__c)) {
if (serviceStaffAssignment.Salesforce_User_ID__c!=null && roles.contains(serviceStaffAssignment.Employee_Role__c)) {

        accountShr = new AccountShare();
        acctTM = new AccountTeamMember();
        acctTM.AccountId = serviceStaffAssignment.Account__c;
        acctTM.UserId = serviceStaffAssignment.Salesforce_User_ID__c;
        acctTM.TeamMemberRole = 'Service Staff';
        accountShr.AccountId = serviceStaffAssignment.Account__c;
        accountShr.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        accountShr.AccountAccessLevel = accLevel;
        accountShr.CaseAccessLevel = accLevel;
        accountShr.ContactAccessLevel = accLevel;
        accountShr.OpportunityAccessLevel = 'none';
        accShares.add(accountShr);
        accTMListToInsert.add(acctTM);

        System.debug('accTMListToInsert'+accTMListToInsert);


        customerSegmentShare = new Customer_Segment__Share();
        customerSegmentShare.ParentId = serviceStaffAssignment.Customer_Segment__c;
        customerSegmentShare.UserOrGroupId = serviceStaffAssignment.Salesforce_User_ID__c;
        customerSegmentShare.AccessLevel = accLevel;
        custSegShares.add(customerSegmentShare);

        custSegIds.add(serviceStaffAssignment.Customer_Segment__c);

        if (accId2SSAList.containsKey(serviceStaffAssignment.Account__c)) {
          accId2SSAList.get(serviceStaffAssignment.Account__c).add(serviceStaffAssignment);
        } else {
          accId2SSAList.put(serviceStaffAssignment.Account__c, new List<Service_Staff_Assignment__c> {serviceStaffAssignment});
        }
      }


 
Magesh Mani YadavMagesh Mani Yadav
Hi Mitchell
I hope the things which i mentioned make sense. Happy coding!

Thanks,
Magesh
Mitchell McLaughlin 1Mitchell McLaughlin 1
Magesh. That is a lot of refactoring, thank you so much! But what part is actually causing an error? In what case is this throwing an error? Again, I'm confused because I cannot get it to re-replicate the problem!!
Magesh Mani YadavMagesh Mani Yadav
Hi Mitchell,
I hope that worked for you
the method "checkSFUserId" was called inside for loop and in that method there is another for loop which is was looping again and again.
And also you were using Update dml inside for loop that may caused CPU time limit.

Thanks
Magesh

mark it solved if it helped you.