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
IR_Admin IR_SalesforceIR_Admin IR_Salesforce 

apex class for updating Opportunity Line Item everyday

I need to write a schedulable apex class that will update a custom field in the OpportunityLineItem object everyday.

I have this so far:

global class UpdateOLI Implements Schedulable {

    global void execute(SchedulableContext sc) {
        updateOLI();
    }

    public void updateOLI() {

        List<OpportunityLineItem> affected = [SELECT Id, Name 
                                     FROM OpportunityLineItem
                                     WHERE position_status__c <> Closed];

       // either do your logic actually here with a Message.SingleEmailMessage here, or just fire an update
       for(OpportunityLineItem thisOLI : affected) {
           // Some dummy field to trigger the workflow (gross huh!)
           thisOLI.Apex_Schedule__c = thisOLI.Apex_Schedule__c +1;
       }

      update affected;
    }
}

But have received this error: 
Apex script unhandled exception by user/organization: 

Scheduled job 'Update OLI' threw unhandled exception.

caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: OpportunityLineItem.Apex_Schedule__c

Class.UpdateOLI.updateOLI: line 15, column 1
Class.UpdateOLI.execute: line 4, column 1
 
Best Answer chosen by IR_Admin IR_Salesforce
Glyn Anderson (Slalom)Glyn Anderson (Slalom)
If you're not triggering email, then all you need to do is fix the SELECT clause.  The only other thing I would still suggest is to make it Batchable.  My version of the class is this:

<pre>
public class UpdateOLI implements Schedulable, Database.Batchable<sObject>
{
    public void execute( SchedulableContext sc )
    {
        Database.executeBatch( this );
    }

    public Database.QueryLocator start( Database.BatchableContext bc )
    {
        return Database.getQueryLocator
        (   String.join
            (   new List<String>
                {   'SELECT Id, Apex_Schedule__c' 
                ,   'FROM OpportunityLineItem'
                ,   'WHERE Position_Status__c != \'Closed\''
                }
            ,   ' '
            )
        );
    }

    public void execute( Database.BatchableContext bc, List<sObject> scope )
    {
        for ( OpportunityLineItem thisOLI : (List<OpportunityLineItem>) scope )
        {
            //  Some dummy field to trigger the workflow (gross huh!)
            thisOLI.Apex_Schedule__c = thisOLI.Apex_Schedule__c + 1;
        }
        update scope;
    }

    public void finish( Database.BatchableContext bc )
    {
        //  nothing to do here...
    }
}
</pre>

All Answers

Glyn Anderson (Slalom)Glyn Anderson (Slalom)
In order to modify the field, "Apex_Schedule__c", you must include it in your SELECT clause -- "SELECT Id, Name, Apex_Schedule__c ..."; and since you don't use the Name field, you can remove that from the SELECT clause -- "SELECT Id, Apex_Schedule__c ...".  It looks like you're trying to send an email every day for every OLI not in the "Closed" status.  That's potentially a lot of emails, particularly if they're going to the same person.  Consider a version that creates lists of OLIs for each email recipient and sending each one a single email with the entire list of OLIs that require their attention.  Then, you also wouldn't need the Apex_Schedule__c field or the associated workflow, email update and email template.  You might also consider making the class Batchable, in case the list of OLI's grows to more than 10,000.
IR_Admin IR_SalesforceIR_Admin IR_Salesforce
Hi Glyn,

Thanks for replying. I actually don't want to send an email update, but I actually want to update a field every night so that workflows can trigger on the opportunity line item. Seems like I maybe quite off here. Could you help point me in the right direction?

Thanks!
Glyn Anderson (Slalom)Glyn Anderson (Slalom)
If you're not triggering email, then all you need to do is fix the SELECT clause.  The only other thing I would still suggest is to make it Batchable.  My version of the class is this:

<pre>
public class UpdateOLI implements Schedulable, Database.Batchable<sObject>
{
    public void execute( SchedulableContext sc )
    {
        Database.executeBatch( this );
    }

    public Database.QueryLocator start( Database.BatchableContext bc )
    {
        return Database.getQueryLocator
        (   String.join
            (   new List<String>
                {   'SELECT Id, Apex_Schedule__c' 
                ,   'FROM OpportunityLineItem'
                ,   'WHERE Position_Status__c != \'Closed\''
                }
            ,   ' '
            )
        );
    }

    public void execute( Database.BatchableContext bc, List<sObject> scope )
    {
        for ( OpportunityLineItem thisOLI : (List<OpportunityLineItem>) scope )
        {
            //  Some dummy field to trigger the workflow (gross huh!)
            thisOLI.Apex_Schedule__c = thisOLI.Apex_Schedule__c + 1;
        }
        update scope;
    }

    public void finish( Database.BatchableContext bc )
    {
        //  nothing to do here...
    }
}
</pre>
This was selected as the best answer
Bhargavi TunuguntlaBhargavi Tunuguntla
Hi

The error can be solved by quering  Apex_Schedule__c  in your query as below:
List<OpportunityLineItem> affected = [SELECT Id, Name,Apex_Schedule__c  
                                     FROM OpportunityLineItem
                                     WHERE position_status__c <> Closed];

Hope this helps.
Thanks.
IR_Admin IR_SalesforceIR_Admin IR_Salesforce
Hi Glyn, This worked! Thanks