1

I'm trying to write a trigger that would populate a custom field on the OppLineItem when the parent Opportunity stage is updated.

The field would be populated with a value from the Product.

What adjustments do i need to make to my code to get it to function?

trigger OppProductNetValue on Opportunity(before insert,before update){

   Set<Id> pbeIds=new Set<Id>();

    for(Opportunity opps:Trigger.new){
        for(OpportunityLineItem oli:opps.OpportunityLineItems){
            if(oli.PricebookEntryId != null){
                pbeIds.add(oli.PricebookEntryId);
            }

    Map<Id,Opportunity> oppMap=new Map<Id,Opportunity>([SELECT StageName,Order__c from Opportunity where id in :pbeIds]); 
    Map<id,PriceBookEntry> pbeMap = new Map<id, PriceBookEntry>([SELECT id, Product2.id, Product2.True_Price__c FROM PriceBookEntry WHERE id in :pbeIds]);
    oppMap.putall([select Id, StageName, Order__c from Opportunity where Id  in:oppMap.keyset()]);
        for(Opportunity opptys:Trigger.new){ 
            for(OpportunityLineItem ol:opptys.OpportunityLineItems){
                if((pbeMap.containsKey(oli.PriceBookEntryId))&& (oppMap.get(oli.OpportunityId).Order__c == 'Sales Unit')&&  (oppMap.get(oli.OpportunityId).StageName == 'Won')){
                    oli.Net_Price__c = pbeMap.get(oli.PriceBookEntryId).Product2.True_Price__c*oli.Quantity;      
                    }else{
                        oli.Net_Price__c = (1-oli.Discount*.01)*(oli.Quantity)*(oli.UnitPrice);
                    }  
            }
        }
    }
}
}

2 Answers 2

1

I see that you've written a BEFORE trigger. How is the Opportunity Stage being updated? Is it updated manually or by workflow? If by workflow, this will need to be an AFTER trigger which is one of several reasons that could possibly explain why its not working as its currently written. You'd also need to add a test to check to see if Trigger.new.Stage != Trigger.old.Stage for it to fire & collect IDs to run the trigger on if that's the case.

Looking further into your code, after editing it to align and look for matching brackets, I see some issues if you are going to run it as a BEFORE trigger.

First, it appears to me that the first for loop should be closed as shown below before you run your first query when collecting your set of pbeIds:

for(Opportunity opps:Trigger.new){
    for(OpportunityLineItem oli:opps.OpportunityLineItems){
        if(oli.PricebookEntryId != null){
            pbeIds.add(oli.PricebookEntryId);
        }
    }
}

It doesn't make sense that you'd run a separate query for each opp Id. I don't know if that was a typo when you pasted or not, but there was a mismatch of brackets. That causes things to look a bit differently down below after your two queries:

for(Opportunity opptys:Trigger.new){ 
    for(OpportunityLineItem ol:opptys.OpportunityLineItems){
        if((pbeMap.containsKey(oli.PriceBookEntryId))&& (oppMap.get(oli.OpportunityId).Order__c == 'Sales Unit')&&  (oppMap.get(oli.OpportunityId).StageName == 'Won')){
            oli.Net_Price__c = pbeMap.get(oli.PriceBookEntryId).Product2.True_Price__c*oli.Quantity;      
        }else{
            oli.Net_Price__c = (1-oli.Discount*.01)*(oli.Quantity)*(oli.UnitPrice);
        }  
    }
}

Then you'll just have one final closing bracket to match the one where you opened your trigger that follows what's above.

3

You could also accomplish this using a formula field.

Opportunity.StageName

AdvancedFormula

You will have to add the TEXT("") function for it to function with a pick-list like StageName.

TEXT(Opportunity.StageName)

The same applies for the other fields on product

ProductFields

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.