Salesforce Update Product Schedule from Opportunity using Apex Trigger

The tutorial below shows how you can use Salesforce Triggers to update the CloseDate of an opportunity and the associated Product Schedule.

First thing is we must create a product Trigger, below is the code for the product trigger:

trigger OpportunityScheduleUpdate on Opportunity (after update) {
  
  for (Opportunity o: Trigger.new) {
        Opportunity oldCloseDate = Trigger.oldMap.get(o.ID);
        if (o.CloseDate != oldCloseDate.CloseDate) {
            Integer dateval = oldCloseDate.CloseDate.daysBetween(o.CloseDate);
            OppScheduleUpdate.ScheduleDateUpdate(o.id, dateval);  
        }
    }
}

The trigger class updates all the Product ScheduleDate by the amount of the days the Opportunity Close Date has changed:

public class OppScheduleUpdate
{
    public static void ScheduleDateUpdate(String oppid, Integer dateval) 
    {
       List idval = [SELECT id FROM OpportunityLineItem WHERE OpportunityId=:oppid];
       List datelist;
       for (Integer i = 0; i < idval.size(); i++)
       {
           datelist = [SELECT ScheduleDate FROM OpportunityLineItemSchedule WHERE OpportunityLineItemId =:idval[i].id];
           for (Integer k = 0; k < datelist.size(); k++)
               {
               System.debug('DateList = ' + datelist[k]);
               Date mydate=Date.newInstance(datelist[k].ScheduleDate.Year(),datelist[k].ScheduleDate.Month(),datelist[k].ScheduleDate.Day());
               mydate=mydate.addDays(dateval);
               datelist[k].ScheduleDate = mydate;
               update datelist;
               //date datediff = date.parse(datelist[k]);
               }
       }      
    }
}

12 Comments

  1. Edson says:

    Do you have test coverage for this?

  2. Thys Michels says:

    Hi Edson, yes I tested multiple opportunities and made sure my schedule updates worked. It was successful in all cases.

  3. edson says:

    yes thanks very much sir, Can you send me the test coverage or unit test for this? Thanks again very helpful.

  4. edson says:

    yes thanks very much sir, Can you send me the test coverage or unit test for this? very much appreciated, Thanks again very helpful.

  5. edson says:

    michael? the test coverage for this or unit test is hard to make, do you have your own test coverage for this?

  6. Thys Michels says:

    I don’t have test coverage for it atm.

  7. Dave Gurr says:

    Could anyone publish the test code for this?

  8. Pavan says:

    I added an opportunity line item using custom apex code. The product which I added in the opportunity line item has a default schedule settings. But OpportunityLineItem schedule records are not created for this opportunity line item. what might be the reason?

  9. ksingh2 says:

    Hi,
    I need to write test case in which when opportunity product inserted then opportunity product schedule must be inserted.
    Thanks,
    Khillan

  10. Dave says:

    Trigger:

    Trigger OpportunityScheduling on Opportunity (after update) {

    if(!Validator_cls.hasAlreadyDone())
    {
    for (Opportunity o: Trigger.new)
    {

    Opportunity oldCloseDate = Trigger.oldMap.get(o.ID);
    if (o.CloseDate != oldCloseDate.CloseDate)
    {
    Integer dateval = oldCloseDate.CloseDate.daysBetween(o.CloseDate);
    OpportunitySchedulingHandler.ScheduleDateUpdate(o.id, dateval);

    }
    }
    }
    }

    Class:

    public with sharing class OpportunitySchedulingHandler {

    public static void ScheduleDateUpdate(String oppid, Integer dateval)
    {
    List idval = [SELECT id FROM OpportunityLineItem WHERE OpportunityId=:oppid];
    List datelist = new List();
    for (Integer i = 0; i < idval.size(); i++)
    {
    datelist = [SELECT ScheduleDate FROM OpportunityLineItemSchedule WHERE OpportunityLineItemId =:idval[i].id];
    for (Integer k = 0; k < datelist.size(); k++)
    {

    Date mydate=Date.newInstance(datelist[k].ScheduleDate.Year(),datelist[k].ScheduleDate.Month(),datelist[k].ScheduleDate.Day());
    mydate=mydate.addDays(dateval);
    datelist[k].ScheduleDate = mydate;
    update datelist;

    }
    }
    }
    }

  11. Alex says:

    Do you have by any chance the test class for this class and trigger as well? Thank you very much

  12. Constance says:

    To new developer: please don’t just copy-paste this code as it is actually not well written.
    One of the most important rule in Apex triggers is to bulkify them to avoid hitting the limits, it means not put SOQL queries or DML operation (save, update, delete) in loops. Here, there is a SOQL query in a double triple and an update operation in a triple loop.
    I work as a Salesforce developer consultant and I am now working on correcting the code of someone who just copy-pasted this one and it’s not even that difficult to bulkify it: use Trigger.newMap and Trigger.OldMap to get the old and new values of the opportunities, put the records to update in lists and actually do the update at the end of the class and never write a trigger in a loop “for(trigger.new)”.
    I can’t share my rectified code because it is for one of our client (so I don’t have the right to make it public), but please stop spreading badly written triggers.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s