I'm in the process of bringing the all API versions up to the current release in an old project and have run into a breaking change with how OpportunityLineItemSchedule records are created.
In v37.0 and earlier if an OpportunityLineItem
record is inserted in an Apex test case where the related Product2
record has CanUseRevenueSchedule
set to true and the Default Revenue schedule fields are set the OpportunityLineItemSchedule
records get created automatically inserted by my OpportunityLineItem trigger that detects HasRevenueSchedule
is false but the Product2
has schedules enabled.
However, when I push the test classes API version to or past v38.0 this behavior changes. The OpportunityLineItemSchedule records are no longer created as HasRevenueSchedule
field is true
in the trigger. All sorts of assertions start failing unless I pull the API version back.
I see the following in the documentation for OpportunityLineItemSchedule:
In API version 38.0 and later, when an OpportunityLineItem record is created for a product with a previously established schedule, an OpportunityLineItemSchedule record is also created.
This seems to be the opposite of my findings, unless I'm reading the docs incorrectly.
The Winter `17 release notes also have Add Products with Schedules in Lightning Experience:
Add products with revenue or quantity schedules to opportunities anywhere, any time. When your reps add a product with an established revenue or quantity schedule, the established schedule is added to the opportunity line item. This feature is available in Lightning Experience and all versions of the Salesforce1 mobile app.
I'm not touching the UI in this case. It's pure Apex code and tests.
What is confusing is that this works fine in anonymous Apex, but fails in a test context.
Why aren't the OpportunityLineItemSchedule records being created in a test context with v38.0 and later even though HasRevenueSchedule
is true?
Note that I had a trigger on OpportunityLineItem
in the original org that was showing OpportunityLineItem.HasRevenueSchedule
as true during insertion. Yet the schedules were nowhere to be found.
Repo:
Scratch org created using settings:
"productSettings" : {
"enableRevenueSchedule": true
}
Anonymous Apex that runs fine (including failing on the intentional rollback assertion):
Product2 testProduct = new Product2();
testProduct.Name = 'Test';
testProduct.CanUseRevenueSchedule = true;
testProduct.RevenueScheduleType = 'Divide';
testProduct.RevenueInstallmentPeriod = 'Daily';
testProduct.NumberOfRevenueInstallments = 1;
insert testProduct;
Id standardPricebookId = [Select Id from Pricebook2 where IsStandard = true].Id;
Opportunity opp = new Opportunity();
opp.Name = 'Test';
opp.StageName = 'Closed/Won';
opp.CloseDate = DateTime.now().date();
opp.Pricebook2Id = standardPricebookId;
insert opp;
PricebookEntry pbe = new PricebookEntry();
pbe.Product2Id = testProduct.Id;
pbe.Pricebook2Id = standardPricebookId;
pbe.UnitPrice = 1.0;
pbe.IsActive = true;
insert pbe;
OpportunityLineItem oli = new OpportunityLineItem();
oli.OpportunityId = opp.Id;
oli.Quantity = 100;
oli.TotalPrice = 700;
oli.PricebookEntryId = pbe.Id;
insert oli;
OpportunityLineItem oliAfter = [Select Id, HasRevenueSchedule from
OpportunityLineItem where Id = :oli.Id];
System.assert(oliAfter.HasRevenueSchedule, 'Expected to have Revenue Schedule');
List<OpportunityLineItemSchedule> schedules = [select Id, Type, Revenue, ScheduleDate from OpportunityLineItemSchedule where OpportunityLineItemId = :oli.Id];
System.debug(schedules);
System.assertNotEquals(0, schedules.size());
System.assert(false, 'Rollback');
Almost identical Apex in a test class that fails (needed to switch out the standard pricebook2Id):
@IsTest
public class TestClass {
@IsTest
static void createSchedules() {
Product2 testProduct = new Product2();
testProduct.Name = 'Test';
testProduct.CanUseRevenueSchedule = true;
testProduct.RevenueScheduleType = 'Divide';
testProduct.RevenueInstallmentPeriod = 'Daily';
testProduct.NumberOfRevenueInstallments = 1;
insert testProduct;
Id standardPricebookId = Test.getStandardPricebookId();
Opportunity opp = new Opportunity();
opp.Name = 'Test';
opp.StageName = 'Closed/Won';
opp.CloseDate = DateTime.now().date();
opp.Pricebook2Id = standardPricebookId;
insert opp;
PricebookEntry pbe = new PricebookEntry();
pbe.Product2Id = testProduct.Id;
pbe.Pricebook2Id = standardPricebookId;
pbe.UnitPrice = 1.0;
pbe.IsActive = true;
insert pbe;
OpportunityLineItem oli = new OpportunityLineItem();
oli.OpportunityId = opp.Id;
oli.Quantity = 100;
oli.TotalPrice = 700;
oli.PricebookEntryId = pbe.Id;
insert oli;
OpportunityLineItem oliAfter = [Select Id, HasRevenueSchedule from
OpportunityLineItem where Id = :oli.Id];
System.assert(oliAfter.HasRevenueSchedule, 'Expected to have Revenue Schedule');
List<OpportunityLineItemSchedule> schedules = [select Id, Type, Revenue, ScheduleDate from OpportunityLineItemSchedule where OpportunityLineItemId = :oli.Id];
System.debug(schedules);
System.assertNotEquals(0, schedules.size());
}
}
Raised as support case #40555632 as this seems broken.