You need to sign in to do that
Don't have an account?
Apex Code help on Triggers
Hi everyone,
I am new to the whole force.com platform and with the help of these discussion boards was able to write quite a bit of the code below.
here is what i am trying to achieve: I am trying to capture the unit price associated with each product on an opportunity level and display it in a new object (called- RevenueObject)
These product names are named like this:
eg. test/email/testproduct/ with Unit price say 400
I have to read these product names to search for key words like "/email" and then capture the revenue associated with it and update a counter field.
RevenueObject Fields-
FieldA - Counter number field ; FieldB - Currency; FieldC - Counter number field ; FieldD - Currency
The code below is able to read these product names and capture revenue and update counter. But here is the issue, it updates the revenue and counter fields (FieldA, FieldB, FieldC, FieldD) every time I save the opportunity- in turn double counting. I just want to capture one instance of it.
Currently RevenueObject UI shows (I saved the opportunity twice) -
FieldA - 2 (should be 1)
FieldB - $800 (should be $400)
Here is my code-
trigger RevenueProject2 on Opportunity (after insert, after update) { String myString1 = '/email'; String myString2 = '/rb'; RevenueObject__c rO = [Select FieldA__c, FieldB__c, FieldC__c, FieldD__c from RevenueObject__c where Id='a0tW0000000JwFu'] ; List <RevenueObject__c> rOList = new List<RevenueObject__c>(); double i=0.0; decimal j= 0.00; // This is to create a list of all product names List<OpportunityLineItem> Product = [Select CustomProdName__c, UnitPrice from OpportunityLineItem where Opportunity.StageName != 'Closed Lost' ]; // excluded FOR update // The for loop is to go through each product name and to categorize product types for(OpportunityLineItem prdct: Product) { if(prdct.CustomProdName__c.contains(myString1)) { if(rO.FieldA__c !=null || rO.FieldB__c !=null) { i = rO.FieldA__c; i++; //Updates Counter rO.FieldA__c = i; // Assigns counter to field j = prdct.UnitPrice; rO.FieldB__c += j; } else{ rO.FieldA__c = 0; // To avoid null exception rO.FieldB__c = 0; i = rO.FieldA__c; i++; //Updates Counter rO.FieldA__c = i; // Assigns counter to field j = prdct.UnitPrice; rO.FieldB__c += j; } } else if(prdct.CustomProdName__c.contains(myString2)) { if(rO.FieldC__c !=null || rO.FieldD__c !=null) { i = rO.FieldC__c; i++; //Updates Counter rO.FieldC__c = i; // Assigns counter to field j = prdct.UnitPrice; rO.FieldD__c += j; } else{ rO.FieldC__c = 0; rO.FieldD__c = 0; i = rO.FieldC__c; i++; //Updates Counter rO.FieldC__c = i; // Assigns counter to field j = prdct.UnitPrice; rO.FieldD__c += j; } } }// for loop // for updating field update rO; } // for trigger
In my revenue object I do have a Lookip relationship field to the opportunity. I understand that i should check for for opportunity id in the code..but I am having a hard time tryiing to figure this out.
I apoloize for the long post. but any help will be a bonus for me.
thanks in advance for al the help.
developernewbie
You are missing a fundamental aspect of Triggers -- the Trigger.new list - please look at the APEX Developers Guide under Triggers - there are great examples there
All Triggers need to have a main loop that is something like this:
All triggers need to be bulkified - you can't assume they apply to only one Opportunity
Since you want to get OpportunityLineItems for each triggered Opportunity, you'll need two loops like this:
I'm leaving out many details about your specific rules and business logic here, more to focus on the Trigger.new
Lastly - you do not want to use hard coded IDs for the RevenueObject__c -- IDs don't port between sandboxes and PROD. Use a SOQL select to find the relevant RevenueObject__c
Thanks so much for your reply and insight into this. As you can tell I am new to the platform and missed an integral part of the triggers. I am defnitely going back to the books and reading more about them.
I looked at your sugestions and accordingly modified my code to that. But now I get an error System.QueryException: List has more than 1 row for assignment to SObject: Trigger.RevenueProject2 when I try to save the opportunity.
The error is on line: RevenueObject__c rO = [Select FieldA__c, FieldB__c, FieldC__c, FieldD__c from RevenueObject__c] ;
I believe from my understanding that it has go to do with Id mapping. On the opportunity object, I created a new revenue object to check for FieldA and Field B.
Hi Eric,
So i was trying to debug the error and i believe i was able to solve the error and i am able to now save the opportunity. But now the revenue object field still double counts, every time i save the opportunity. I need to make sure it is not double counting.
This is the updated code:
Thanks again for all the help
developernewbie
A few questions/points:
1. How many RevenueObjects are in your application design?
The above line presumes that oIdSet contains one and only one OpportunityId. This will never be true in a batch operation. Your schema implies a one:many relationship between Opportunity and RevenueObject__c.
Since several RevenueObject__c could have the same parent Opportunity, how do you know which RevenueObject to update? Is there an implicit 1:1 relationship between RevenueObject__c and Opportunity? For the moment, I'll assume you have a 1:1 relationship
Then to handle bulkification, you will need in lieu of the above line:
Now, onto the main loop
In a bulkified trigger, this loop will retrieve OLI in unpredictable order, to wit: Oppo 1, OLI 1; Oppo 2 OLI 1; Oppo1, OLI 2, ...
You need something like this:
This will go through each triggered Opportunity and within that outer loop, each of the triggered opportunity's OLI
In your work section, you need to locate the RevenueObject__c that applies to the outer loop Opportunity
and this object, identified by inner loop variable ro, is the one to update. . At the end of each outer loop, you do:
and at the end of all the outer loop, you do
Double counting may be occurring if you have > 1 OLI per Opportunity --
Lastly, I urge you to add System.debug statements and examine the debug log after you execute - you'll quickly learn what is going on