Unforntunately Salesforce does not support Field History for OpportunityLineItemSchedules. A workaround would be to duplicate Salesforce's Field History object and update it using a trigger. (I have already done this for OpportunityLineItems). But, alas, triggers are not supported for OpportunityLineItemSchedules!

Fortunately, changes to an OpportunityLineItemSchedule revenue or quantity, deletions, and additions of records update its OpportunityLineItem parent. So there might be some hope.

An answer to a similar post as mine suggested querying all the OpportunityLineItemSchedule records associated with the OpportunityLineItem trigger.old in a on before update OpportunityLineItem trigger and then comparing them to the OpportunityLineItemSchedules records queried from trigger.new in an on after update OpportunityLineItem trigger.

To test that solution I wrote an on before update OpportunityLineItem trigger that builds a map of all the OpportunityLineItemSchedule records associated with the OpportunityLineItem records from trigger.old. I then print the map in the debug log.

I updated an OpportunityLineItemSchedule record and looked at the debug log.

Unfortunately the map shows the UPDATED NEW values from the OpportunityLineItemSchedule record not the OLD values.

Perhaps I am misunderstanding that solution.

Any insights on the solution above or how one would track field history for OpportunityLineItemSchedules would be appreciated.

  • From the posts below and other research, the only solution I can see is to mirror the OpportunityLineItemSchedules using a trigger on OpportunityLineItem, and then compare the mirror copies.
    – MWH
    Commented Jun 27, 2013 at 12:46

2 Answers 2


I played around with this and found that if I edited a single OpportunityLineItemSchedule record, all of the records associated with that line item were deleted and a whole new set of records were inserted. I thought that maybe the old records would at least be kept around with IsDeleted=TRUE but that was not the case.

Based on this evidence, it appears to me that you will need to have both delete and insert trigger logic on the OpportunityLineItemSchedule object and correlate the events using the OPPORTUNITYLINEITEMID field.

This Salesforce implementation of delete/insert records probably makes sense since you can imagine it is easiest to simply recalculate the whole schedule anytime a value is modified (e.g. number of payments or period type).

  • Miles, interesting insight. Unfortunately per post, OpportunityLineItemSchedules do not support triggers. You cannot create a trigger for that object.
    – MWH
    Commented Jun 25, 2013 at 21:13
  • Miles, I further tested your results. Oddly, sometimes Salesforce does create new records (even when you are simply updating a Schedule record). I found that it always deleted the previous records if you added a new schedule record, replacing the deleted record(s) with a new ones. But there were cases where it simply updated the previous record. This may have only been if there was a single schedule record. There are even cases where it created TWO schedule records (one with a quantity, another with a revenue) but the GUI displays a single record.
    – MWH
    Commented Jun 27, 2013 at 12:45

The key to make this work requires understanding a couple trigger concepts. I'd suggest reviewing the apex documentation on this. The short of it is you need to query the schedule records in a BEFORE trigger not an AFTER trigger.

After vs. Before

Any queries that take place in an before trigger will return the state of the database prior to the transaction. Any queries that take place in an after trigger represent the state of the database after the transaction.

Trigger.Old vs Trigger.New

Trigger.old represent the state of the specific objects being operated on by the trigger at the start of the transaction. Trigger.new represents the current state of the specific objects being operated on by the trigger at the moment (it starts as the initial update, but can be changed by workflow or triggers throughout the course of the transction.

Your Solution

Since you're querying data in an after trigger it's always going to give you the state of the OpportunityLineItemScehdule objects after the transaction has been committed. Trigger.old is only for the specific object being operated on by the trigger, in this case OpportunityLineItems. Since the ids are going to be the same in both the pre and post commit state it really doens't matter which you're using to get the schedule data (except for inserts for which trigger.old won't have ids).

  • Ralph, thanks for the follow-up. The trigger I am using is an on before update trigger.
    – MWH
    Commented Jun 27, 2013 at 12:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .