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
Dan NorfleetDan Norfleet 

Apex Class Batch Execution Questions

I am new to SalesForce.  I have created my first Apex Class.  The goal of the class is to read through all ccrz__E_Order__c that are in 'Order Submitted' status.  For each order, read the items.  If all items are currently in 'Received' status, then update the status on the order to 'Order Received'.  I want this to be a batch process ran daily.

Following questions being a first time creator of an Apex Class.
  • Is the best way to trigger this process to run by going into Apex Class and Schedule Apex?  Or is there a more appropriate way to schedule?
  • When testing, I have used Developers Console and executed the class.  However, I run into limits.  Even when I have scheduled in our test environments, i have hit limits.  There are only a couple hundred orders in this status but it hits Too many SOQL queries system limit exception.  Is there a way to test the entire process w/o exceeding these limits?  Are they the same limits when going to production?  When testing I enter specific orders (you'll see commented out line below in the code), but when i read all orders i am hitting these limits.
  • Is there a system log that i can write totals too?  As you can see on the code below i have written beginning / ending / total information into the debug log.  But when going to production, i will comment these out - is there a traditional way to look at this kind of information in a salesforce log.  
I am including the code i have created and appreciate any feedback since this is my first attempt.

Thanks in advance for any advise.  

Dan

/*
 * @Name: Batch_OrderStatus
 * @Author: Dan Norfleet
 * Updates : 02/12/2018 - Dan Norfleet - Created Apex Class
 */
    global class Batch_OrderStatus Implements Schedulable
    {
      global void execute(SchedulableContext sc)
      {
        execute();
      }

      global void execute() 
      {
          System.debug('Batch_OrderStatus BEGIN');
          //  Create a list of Orders in status of 'Order Submitted'
          List<ccrz__E_Order__c> orders = 
                [SELECT Id, Name, ccrz__orderstatus__c 
                FROM ccrz__E_Order__c 
                WHERE ccrz__orderstatus__c = 'Order Submitted'];
//                WHERE ccrz__orderstatus__c = 'Order Submitted' AND Name = 'O-0000112447'];
          Integer total_orders_cnt = 0;
          Integer update_cnt = 0;
          Integer notupdated_cnt = 0;
          String status_received = 'Received';
          String status_order_received = 'Order Received';
          
          // Loop through the list of orders
          for(ccrz__E_Order__c ord : orders)
          { 
            total_orders_cnt = total_orders_cnt + 1;
            String order_id = ord.Id;
            // For each order, see how many items are in 'Received' status
            integer ItemsReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c = :status_received
                    AND ccrz__order__c = :order_id];
          
            integer ItemsNOTReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c != :status_received
                    AND ccrz__order__c = :order_id];
          
            if (ItemsReceived > 0)
                    { 
                if (ItemsNOTReceived == 0)
                        { 
                        ord.ccrz__orderstatus__c = status_order_received;
                        System.debug('    UPDATE Order - ID = ' + order_id + ' / Order Name = ' + ord.Name + ' / Items Received = ' + ItemsReceived + ' / ItemsNOTReceived = ' + ItemsNOTReceived);
                        update_cnt = update_cnt + 1;
                        update orders;
                        }
                    else
                        {
                        notupdated_cnt = notupdated_cnt + 1;
                        }
                    }
                
          }
          System.debug('TOTAL ORDERS IN SUBMITTED STATUS = ' + total_orders_cnt);
          System.debug('TOTAL UPDATED = ' + update_cnt);
          System.debug('TOTAL NOTUPDATED = ' + notupdated_cnt);
          System.debug('Batch_OrderStatus END');
      }
}
Best Answer chosen by Dan Norfleet
VamsiVamsi
Hi,

The above code you specified isn't executing in asynchronous mode. Its executing in synchronous mode as you are just trying to execute the above code in scheduled apex.

Try to write the above code in batch apex and then execute this batch apex from scheduled apex.

Please go through the following link https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm


Put this in start method of batch apex 

  //  Create a list of Orders in status of 'Order Submitted'
          List<ccrz__E_Order__c> orders = 
                [SELECT Id, Name, ccrz__orderstatus__c 
                FROM ccrz__E_Order__c 
                WHERE ccrz__orderstatus__c = 'Order Submitted'];

Put this code block in execute method 

Integer total_orders_cnt = 0;
          Integer update_cnt = 0;
          Integer notupdated_cnt = 0;
          String status_received = 'Received';
          String status_order_received = 'Order Received';
          
          // Loop through the list of orders
          for(ccrz__E_Order__c ord : orders)
          { 
            total_orders_cnt = total_orders_cnt + 1;
            String order_id = ord.Id;
            // For each order, see how many items are in 'Received' status
            integer ItemsReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c = :status_received
                    AND ccrz__order__c = :order_id];
          
            integer ItemsNOTReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c != :status_received
                    AND ccrz__order__c = :order_id];
          
            if (ItemsReceived > 0)
                    { 
                if (ItemsNOTReceived == 0)
                        { 
                        ord.ccrz__orderstatus__c = status_order_received;
                        System.debug('    UPDATE Order - ID = ' + order_id + ' / Order Name = ' + ord.Name + ' / Items Received = ' + ItemsReceived + ' / ItemsNOTReceived = ' + ItemsNOTReceived);
                        update_cnt = update_cnt + 1;
                        update orders;
                        }
                    else
                        {
                        notupdated_cnt = notupdated_cnt + 1;
                        }
                    }
                
          }
          System.debug('TOTAL ORDERS IN SUBMITTED STATUS = ' + total_orders_cnt);
          System.debug('TOTAL UPDATED = ' + update_cnt);
          System.debug('TOTAL NOTUPDATED = ' + notupdated_cnt);
          System.debug('Batch_OrderStatus END');
      }


 

All Answers

VamsiVamsi
Hi,

The above code you specified isn't executing in asynchronous mode. Its executing in synchronous mode as you are just trying to execute the above code in scheduled apex.

Try to write the above code in batch apex and then execute this batch apex from scheduled apex.

Please go through the following link https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm


Put this in start method of batch apex 

  //  Create a list of Orders in status of 'Order Submitted'
          List<ccrz__E_Order__c> orders = 
                [SELECT Id, Name, ccrz__orderstatus__c 
                FROM ccrz__E_Order__c 
                WHERE ccrz__orderstatus__c = 'Order Submitted'];

Put this code block in execute method 

Integer total_orders_cnt = 0;
          Integer update_cnt = 0;
          Integer notupdated_cnt = 0;
          String status_received = 'Received';
          String status_order_received = 'Order Received';
          
          // Loop through the list of orders
          for(ccrz__E_Order__c ord : orders)
          { 
            total_orders_cnt = total_orders_cnt + 1;
            String order_id = ord.Id;
            // For each order, see how many items are in 'Received' status
            integer ItemsReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c = :status_received
                    AND ccrz__order__c = :order_id];
          
            integer ItemsNOTReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c != :status_received
                    AND ccrz__order__c = :order_id];
          
            if (ItemsReceived > 0)
                    { 
                if (ItemsNOTReceived == 0)
                        { 
                        ord.ccrz__orderstatus__c = status_order_received;
                        System.debug('    UPDATE Order - ID = ' + order_id + ' / Order Name = ' + ord.Name + ' / Items Received = ' + ItemsReceived + ' / ItemsNOTReceived = ' + ItemsNOTReceived);
                        update_cnt = update_cnt + 1;
                        update orders;
                        }
                    else
                        {
                        notupdated_cnt = notupdated_cnt + 1;
                        }
                    }
                
          }
          System.debug('TOTAL ORDERS IN SUBMITTED STATUS = ' + total_orders_cnt);
          System.debug('TOTAL UPDATED = ' + update_cnt);
          System.debug('TOTAL NOTUPDATED = ' + notupdated_cnt);
          System.debug('Batch_OrderStatus END');
      }


 
This was selected as the best answer
Dan NorfleetDan Norfleet
Vamshi, thanks so much for this detail.  I will make the suggested changes today :)

Dan
VamsiVamsi
Hi,


Also, you are trying to run below SOQL queries in FOR loop and its not a recommended approach by Salesforce.
 
integer ItemsReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c = :status_received
                    AND ccrz__order__c = :order_id];
          
            integer ItemsNOTReceived = 
                    [SELECT COUNT() 
                    FROM ccrz__E_OrderItem__c 
                    WHERE ccrz__orderitemstatus__c != :status_received
                    AND ccrz__order__c = :order_id];

So try to query them out side of the FOR loop and store in Maps and make use of them appropriately.

In execute method 

Initially query the map of  ccrz__E_Order__c  records as 
 
// Getting list of  ccrz__E_Order__c  records 
Map<id, ccrz__E_Order__c  > OrderList = new Map<id, ccrz__E_Order__c  > ([select id from  ccrz__E_Order__c where ID IN : scope]);  //Here scope is the list of  ccrz__E_Order__c  records from start method of batch apex and default batch size is 200.

// Getting count of  ccrz__E_OrderItem__c  for each  ccrz__E_Order__c  when status is  status_received.

Map<ID,Integer> Receivedlist = new Map<ID,Integer>();
for(Aggregateresult ag : [select count(id) size, ccrz__order__c from ccrz__E_OrderItem__c where ccrz__orderitemstatus__c = :status_received AND  ccrz__order__c  IN : OrderList .Keyset() GROUP BY ccrz__order__c ])
{
    Receivedlist.put((ID)ag.get(' ccrz__order__c '),(integer)ag.get('size'));
}

// Getting count of  ccrz__E_OrderItem__c  for each  ccrz__E_Order__c  when status is   not received 


Map<ID,Integer> NotreceivedList= new Map<ID,Integer>();
for(Aggregateresult ag : [select count(id) size, ccrz__order__c from ccrz__E_OrderItem__c where ccrz__orderitemstatus__c != :status_received AND  ccrz__order__c  IN :OrderList .Keyset() GROUP BY ccrz__order__c ])
{
    NotreceivedList .put((ID)ag.get(' ccrz__order__c '),(integer)ag.get('size'));
}


Now make use of the above in Order For Loop

 
for(ccrz__E_Order__c ord : orders)
          {
				if(Receivedlist.get(ord.id)> 0 && !NotreceivedList.contains(ord.id))
				{
					 ord.ccrz__orderstatus__c = status_order_received;
					System.debug('    UPDATE Order - ID = ' + order_id + ' / Order Name = ' + ord.Name + ' / Items Received = ' + ItemsReceived + ' /         ItemsNOTReceived = ' + ItemsNOTReceived);
					update_cnt = update_cnt + 1;
					update orders;
				}
				else
				{
				   notupdated_cnt = notupdated_cnt + 1;
				}
          }