Resolved code for updating OpportunityLineItemSchedule ScheduleDate to new CloseDate when close date is changed on Opportunity object. Also to update OpportunityLineItem ServiceDate on change of Opportunity CloseDate Trigger:
trigger OpportunityReScheduling on Opportunity (after update, before update, after insert)
{
for (Opportunity o: Trigger.new)
{
if (Trigger.isBefore)
{
Opportunity oldCloseDate = Trigger.oldMap.get(o.ID);
if (o.CloseDate != oldCloseDate.CloseDate)
{
Integer Oldday = Integer.valueOf(oldCloseDate.CloseDate.Day());
Integer day = Integer.valueOf(o.CloseDate.Day());
Integer month = Integer.valueOf(o.CloseDate.Month());
Integer year = Integer.valueOf(o.CloseDate.Year());
Integer DayDiff = day - Oldday;
OpportunitySchedulingHandler.ScheduleDateUpdate(o.id, day, month, year, DayDiff);
}
}
if (Trigger.isAfter || Trigger.isInsert)
{
OpportunitySchedulingHandler.ScheduleServiceDateUpdate(o.id);
}
}
}
Class:
public with sharing class OpportunitySchedulingHandler {
//Update LineItemSchedule dates for all scheduling dates
public static void ScheduleDateUpdate(String oppid, Integer day, Integer month, Integer year, Integer DayDiff)
{
List<OpportunityLineItem> idval = [SELECT id FROM OpportunityLineItem WHERE OpportunityId=:oppid];
List<OpportunityLineItemSchedule> datelist = new List<OpportunityLineItemSchedule>();
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++)
{
if(DayDiff <> 0)
{
//automatic functionality actually adds 24 list (12 for quantity 12 for revenue)
//editing schedule for quantity
if(k<12)
{
Date mydate = date.newInstance(year,month,day);
datelist[k].ScheduleDate = mydate.addmonths(k);
}
//editing schedule for revenue
else
{
Date mydate = date.newInstance(year,month,day);
datelist[k].ScheduleDate = mydate.addmonths(k-12);
}
}
}
if(!datelist.isEmpty())
{
update datelist;
}
}
}
//Update ServiceDate with closeDate
public static void ScheduleServiceDateUpdate(String oppid)
{
List<Opportunity> oliList = [SELECT Id, Name, CloseDate, (SELECT Id, ServiceDate, OpportunityId from OpportunityLineItems) from Opportunity where Id =:oppid];
List<OpportunityLineItem> oliUpdateList = new List<OpportunityLineItem>();
for(Opportunity x : oliList)
{
for(OpportunityLineItem oli : x.OpportunityLineItems)
{
oli.ServiceDate = x.CloseDate;
oliUpdateList.add(oli);
}
}
if(!oliUpdateList.isEmpty())
{
update oliUpdateList;
}
}
}
Test Class:
@isTest
private class OpportunityReSchedulingTest {
static testMethod void myUnitTest() {
// TO DO: implement unit test
Test.starttest();
Account acc = new Account();
acc.Name='NewAcc';
insert acc;
Opportunity opp = new Opportunity();
opp.Name='NewOpp';
opp.AccountId=acc.Id;
opp.StageName='Prospecting';
opp.CloseDate=Date.today().addDays(10);
insert opp;
Product2 Prod = new Product2();
Prod.Name='NewProd';
Prod.IsActive=True;
insert Prod;
PricebookEntry pbe = new PricebookEntry();
pbe.Product2Id=Prod.Id;
pbe.IsActive=True;
pbe.UnitPrice=70;
pbe.Pricebook2Id = Test.getStandardPricebookId();
pbe.UseStandardPrice=false;
insert pbe;
OpportunityLineItem opli = new OpportunityLineItem();
opli.UnitPrice = 57;
opli.Quantity = 12;
opli.OpportunityId=opp.Id;
opli.PricebookEntryId=pbe.id;
insert opli;
opp.CloseDate = opp.CloseDate.addDays(20);
update opp;
Test.stoptest();
}
}
Note:
Scheduling might give an error if OpportunityLineItemSchedule will be created manually (using establish/Re-establish function) for more than 12 schedules.