The roll-up summary field is only updated after the field updates, triggered by your workflow rules, have been completed. See Triggers and Order of Execution.
I'm not aware of a workaround which you could implement, without using code. So have a go at adapting the below.
Note -
This is an After trigger because changing the Opportunity Product's UnitPrice
will cause the Opportunity Amount
field to recalculate, causing the recursive trigger error.
This will update the Sales Price of all Opportunity Products which are related to the Opportunity which has just had it's roll-up field update. I'm guessing that that's what you'll want but if not, let me know.
Trigger
trigger UnitPriceUpdate on Opportunity (after update) {
Map<Id,Decimal> softwareRevenue = new Map<Id,Decimal>();
List<Opportunity> upOpps = new List<Opportunity>();
List<OpportunityLineItem> upOppProds = new List<OpportunityLineItem>();
Decimal oppExpRev;
for(Opportunity o : Trigger.new){
Opportunity oldOpp = Trigger.oldMap.get(o.Id);
//change Software_Line_Item__c to roll-up field name
if(oldOpp.Software_Line_Item__c != o.Software_Line_Item__c){
//do the same here
softwareRevenue.put(o.Id,o.Software_Line_Item__c);
upOpps.add(o);
}
}
//replace prcntge_of_maintenance__c with formula field containing % on Opportunity Product
for(OpportunityLineItem oli : [SELECT Id, prcntge_of_maintenance__c, OpportunityId FROM OpportunityLineItem
WHERE OpportunityId IN :upOpps])
{
oppExpRev = softwareRevenue.get(oli.OpportunityId);
//replace prcntge_of_maintenance__c with formula field containing % that you want to apply on Opportunity Product
oli.UnitPrice = oppExpRev*oli.prcntge_of_maintenance__c;
upOppProds.add(oli);
}
update upOppProds;
}
Test Class
@isTest
public class UnitPriceUpdateTest {
@testSetup
static void dataSetup() {
Product2 p = new Product2();
p.Name = 'TestProduct';
insert p;
Id pricebookId = Test.getStandardPricebookId();
PricebookEntry pbe = new PricebookEntry(
Pricebook2Id = pricebookId,
Product2Id = p.Id,
UnitPrice = 10000,
IsActive = true);
insert pbe;
List<Opportunity> opps = new List<Opportunity>();
for (Integer i = 0; i < 200; i++) {
Opportunity o = new Opportunity(
Name = 'Test Opp' + i,
CloseDate = date.today() + 1,
StageName = 'Prospecting');
opps.add(o);
}
insert opps;
List<OpportunityLineItem> oppProds = new List<OpportunityLineItem>();
for(Opportunity o : opps) {
OpportunityLineItem oli = new OpportunityLineItem(
OpportunityId = o.Id,
PricebookEntryId = pbe.Id,
UnitPrice = 100,
Quantity = 1,
Sales_Price1__c = 100,
Description = '<0>');
oppProds.add(oli);
}
insert oppProds;
}
static testMethod void testNewSoftRev() {
List<OpportunityLineItem> oppProds1 = [SELECT Id, Sales_Price1__c FROM OpportunityLineItem WHERE Description = '<0>'];
test.startTest();
for(OpportunityLineItem oli : oppProds1) {
oli.Sales_Price1__c = 200;
}
update oppProds1;
test.stopTest();
// Retrieve the updated Opportunity Products using an SOQL query here
// then use system.assert to check that the correct UnitPrice has been calculated.
// This is not necessary to achieve 100% code coverage but it ensures that your code
// has done what it's supposed to (and hasn't been impacted by changes in your org in the future).
}
}