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
LaaralLaaral 

How to make this code work properly

Hi, my problem is this

ServiceAvailabililtyUpdaterForCase.HandleServiceAvailabilityChange does not handle Case(s) correctly, if there is no Setup defined in the Case.

Line:
Setup__c relatedSetup = [select Id, Name, Service_Availability__c, Cost_Center__c from Setup__c where Id =: c.Related_Setup__c];
Related_Setup__c is null (when the error occurs), so the situation when there is no Setup defined in the Case, should still be able to handle that Case.

 

global class ServiceAvailabililtyUpdaterForCase implements Schedulable,
                                                           Database.Stateful/*,
                                                           Database.Batchable<sObject>*/ {

    // Implement Schedulable interface function for entry function to schedule this batch
    global void execute(SchedulableContext sc){
        
        ServiceAvailabililtyUpdaterForCase updater = new ServiceAvailabililtyUpdaterForCase();
        Date currentDate = Date.newinstance(DateTime.Now().Year(), DateTime.Now().Month(), DateTime.Now().Day());          
        updater.HandleServiceAvailabilityChange(currentDate);     
    }    
  
  /*
  * Execute method of Batchable interface
  */
  global void execute( Database.BatchableContext BC, List<sObject> records ) {
      System.debug('ServiceAvailabililtyUpdaterForCase.execute batch');            
  }      
            
    public void HandleServiceAvailabilityChange(Date currentDate) {
      
      /*
      1) Fetch not closed Support Cases
      2) Fetch valid Service Availability objects per Case
      3) Sort SAs by a) Case b) Name
      4) Update last SA with duration until end of the month
      5) Create new SA from the beginning of the new month (with same Fault Classification)      
      */
      RecordType recordType = [select Id, Name from RecordType where SObjectType = 'Case' and Name = 'Support' LIMIT 1];
      
      System.Debug('SCHEDULED: SUPPORT CASE REC TYPE ID: ' + recordType.Id);            
                               
      List<Case> suppportCases = [select Id, Fault_Classification__c, Setup_Name__c, CaseNumber, Related_Setup__c,Status_Explanation__c 
                            from Case                                                       
                            where RecordTypeId =: recordType.Id
                            and IsClosed =: false                           
                            order by CreatedDate desc]; 

        System.Debug('SCHEDULED: SUPPORT CASE COUNT: ' + suppportCases.Size());      
      ServiceAvailability saHelper = new ServiceAvailability();
      
      // Setups that are already handled. We need to process each Setup only once.
      Set<Setup__c> alreadyHandled = new Set<Setup__c>();          
      
      for (Case c : suppportCases) {
        System.Debug('SCHEDULED: CASE ' + c.CaseNumber + ' HANDLING STARTED');
              
            List<Service_Availability__c> oldSAsPerCase = 
                                        [select Name, Status__c, Duration__c, Start_DateTime__c from Service_Availability__c                                                     
                                        where Case__c =: c.Id
                                        order by Name desc];
            
            System.Debug('SCHEDULED: OLD SA COUNT: ' + oldSAsPerCase.Size());
                                                    
            if (oldSAsPerCase.Size() > 0) {              
              Setup__c relatedSetup = [select Id, Name, Service_Availability__c, Cost_Center__c from Setup__c where Id =: c.Related_Setup__c];              
              
              Id hoursToUse = saHelper.GetHoursToUse(c, relatedSetup);                                            
              RecordType recordTypeIncident = [select Id, Name from RecordType where SObjectType = 'Service_Availability__c' and Name = 'Incident' LIMIT 1];
                
                System.debug('SCHEDULED: DATE IN LAST SA: ' + oldSAsPerCase[0].Start_DateTime__c);
                System.debug('SCHEDULED: CURRENT DATE: ' + DateTime.Now());

  

 

   

LaaralLaaral

This problem is also affecting this trigger the part where starts // Related Setup, the error code is this : CaseResponseTimeTrigger: execution of BeforeUpdate caused by: System.QueryException: List has no rows for assignment to SObject: Trigger.CaseResponseTimeTrigger: line 23, column 1

 

Trigger CaseResponseTimeTrigger on Case (before update) {    

    if (Trigger.isUpdate /*|| Trigger.isInsert*/) {                
        
        for (Case updatedCase:System.Trigger.new) {
            System.Debug('CaseResponseTimeTrigger: CASE ID: ' + updatedCase.Id);           
                        
            RecordType recordType = [select Id, Name from RecordType where SObjectType = 'Case' and Name = 'Support' LIMIT 1];
            
            System.Debug('CaseResponseTimeTrigger: FETCHED RECORD TYPE: ' + recordType.Id );
            System.Debug('CaseResponseTimeTrigger: RECORD TYPE IN CASE: ' + updatedCase.RecordType.Id );
            
            // Get old Case data. We are also only interested in Support Cases.
            if (System.Trigger.oldMap.get(updatedCase.Id) != null /*&& updatedCase.RecordType == recordType*/ ) {
            
                Case oldCase = System.Trigger.oldMap.get(updatedCase.Id);            
                System.Debug('CaseResponseTimeTrigger: OLD STATUS: ' + oldCase.Status);
                System.Debug('CaseResponseTimeTrigger: NEW STATUS: ' + updatedCase.Status);
                
                if (oldCase.Status == 'New' && updatedCase.Status == 'Working' && updatedCase.Response_time__c == null && oldCase.Related_Setup__c == null) {
                    
                    // Related Setup
                    Setup__c relatedSetup = [select Id, Cost_Center__c, Name, Service_Availability__c from Setup__c where Id =: updatedCase.Related_Setup__c];
                    System.Debug('CaseResponseTimeTrigger: Related Setup: ' + relatedSetup.Name);
dseilerdseiler

Hi Laaral,

 

The problem is the following:

 

If you are executing a SOQL query you will usually get back a list of records. E.g.

List<MyObject__c> myObjectList = [Select Id, Name From MyObject__c Limit 100];

 In case you know for sure that your query will only return exactly one record, Salesforce allows you to directly assign the result of your query to an Object instead to a List of objects.

This is what you try to do in your code:

 

Setup__c relatedSetup = [select Id, Cost_Center__c, Name, Service_Availability__c from Setup__c where Id =: updatedCase.Related_Setup__c];

Since this looks like a nice short cut it is quite a dangerous thing to do because it only works if exactly one record is returned.

In your case where you query for the Id of the Setup__c object it is also possible that no record with this Id is found.

If this is the case Salesforce doesn't return "Null" but instead it returns an empty List of Setup__c records.

So it tries to assigne a list to the relatedSetup variable which causes the mentioned exception.

 

 To solve this problem you could either do:

 

Setup__c relatedSetup = null;
List<Setup__c> relatedSetupList = [select Id, Cost_Center__c, Name, 
Service_Availability__c from Setup__c where Id =: updatedCase.Related_Setup__c];
if(!relatedSetupList.isEmpty()) {
    relatedSetup = relatedSetupList.get(0);
}

 Or, even more elegant use the "for" soql notation

 

Setup__c relatedSetup = null;
for(Setup__c s = [select Id, Cost_Center__c, Name, 
Service_Availability__c from Setup__c where Id =: updatedCase.Related_Setup__c]) {
  relatedSetup = s;
}

 

This should help

 

Best regards

 

Daniel