function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
shan876shan876 

If the value changes????Then fire off a trigger??

Hi all:

   I have the following trigger and class...

Basically, this works real well when an user creates a quote.. it copies everything from product line to quoteline automatically once the quote is created...

Now the situation I have is if the Partner__c value changes then the sales_discount off the quoteline must change accordingly...

I am totally at a lost to do that...

Here is my trigger:

 

trigger quoteTrigger on SFDC_520_quote__c (after insert) { for (SFDC_520_Quote__c q : Trigger.new) { if (Trigger.isInsert) util.copyLineItemsFromOpp(Trigger.new); } }

 My class:

 

global class util { // Class variables can be used for communication between triggers public static Boolean inQuoteTrigger; public static Set<Id> opportunityIds = new Set<Id>(); public static SFDC_520_Quote__c[] getOtherPrimaryQuotes(list<SFDC_520_Quote__c > qs) { // Retrieve the list of all opportunities referenced by the given quotes List<Id> ops = new List<Id>(); for(SFDC_520_quote__c q : qs) ops.add(q.opportunity__c); // Now retrieve all quotes that reference the opportunities, // excluding the given quotes SFDC_520_Quote__c[] others = [select id from SFDC_520_quote__c where opportunity__c in :ops and id not in :qs and primary__c = true]; return others; } // This method moves opportunity line items to the given quote q. public static void copyLineItemsFromOpp(List<SFDC_520_Quote__c> qs) { // We will modify and update the quotes with totals at the end, so we clone it // first since Trigger.new records cannot be modified in after triggers. Notice that // we use the deepClone method on the list as clone for sobjects creates a shallow // copy which is still read-only. List<SFDC_520_quote__c> quoteList = qs.deepClone(true); try { // By setting the inQuoteTrigger class variable, this method tells // the quoteLine trigger that it should disable itself during this // operation (the quoteLine trigger is described in Example 3) inQuoteTrigger = true; //Now the method creates an empty array of quote line items List<SFDC_520_QuoteLine__c> quoteItemList = new List<SFDC_520_QuoteLine__c>(); // Next get the opportunity line items for the respective Opportunities. // This demonstrates the aggregate relationship query pattern for getting // children correlated back to their parent. You could also query // OpportunityLineItem directly but would then have to correlate the items // back to their respective parents (opportunity) inside the code manually. // We are constructing a map so the respective opportunity // (with its line items) can be easily correlated back to quote as we process // them below. Map<Id, Opportunity> opportunityMap = new Map<Id, Opportunity>( [select Id,Partner__c, (Select Id, OpportunityId, SortOrder, PricebookEntryId, Quantity, TotalPrice, UnitPrice, ListPrice, ServiceDate, Description, CreatedDate, CreatedById, LastModifiedDate, LastModifiedById, SystemModstamp, IsDeleted , PricebookEntry.Name, PricebookEntry.Product2id from opportunitylineitems order by createddate) from Opportunity where Id IN :getOpportunityIds(quoteList)]); // Iterate through the quotes in the bulk operation. for(SFDC_520_Quote__c quote:quoteList) { // Next, the method manually calculates the overall total for the quote // by iterating over an array of OpportunityLineItem records from the // preceeding SOQL query. The query selects the data from opportunity // line items that match the opportunity associated with the quote. Double tot = 0; // The running total Integer i = 0; // Number the line items // Get the respective opportunity and its line items from the map. Opportunity opp = opportunityMap.get(quote.opportunity__c); // If this quote is not associated to an opportunity then skip it. if(opp == null) continue; for (opportunitylineitem oppline : opp.OpportunityLineItems) { i++; // For each opportunity line item, the method // calculates the running total if (oppline.unitprice != null && oppline.quantity != null) tot += oppline.unitprice * oppline.quantity; // And then it adds a new quote line item to the quoteitems, // array, initializing it with values. Reseller__c[] r =[Select Name, License__c from Reseller__c where Name=:quote.Partner_Direct__c]; if(r.isEmpty()){ quoteItemList.add(new SFDC_520_quoteline__c( quote__c = quote.id, Sales_Discount__c = 0.0, Qty_Ordered__c = oppline.Quantity, Unit_Price__c = oppline.UnitPrice, Description__c = oppline.Description, ServiceDate__c = oppline.ServiceDate, Product2__c = oppline.PricebookEntry.Product2id));} if(!r.isEmpty()){ quoteItemList.add(new SFDC_520_quoteline__c( quote__c = quote.id, Sales_Discount__c = r[0].License__c, Qty_Ordered__c = oppline.Quantity, Unit_Price__c = oppline.UnitPrice, Description__c = oppline.Description, ServiceDate__c = oppline.ServiceDate, Product2__c = oppline.PricebookEntry.Product2id)); } } } //The method adds the whole array of quote line items //to the database with a single insert statement. insert quoteItemList; update quoteList; } finally { // To clean up the working variable, the method resets inQuoteTrigger to false; inQuoteTrigger = false; } } // Generate a unique set of opportunity IDs that represents all the // quotes in the argument list. private static Set<Id> getOpportunityIds(List<SFDC_520_Quote__c> quotes) { Set<Id> idSet = new Set<Id>(); for(SFDC_520_Quote__c quote:quotes) { if(quote.opportunity__c != null) idSet.add(quote.opportunity__c); } return idSet; } static testMethod void testQuoteApp() { // To begin, the sample application first creates the necessary records // to test OpportunityLineItems: Pricebook2, Product2, and PricebookEntry // First it creates a product with a standard price Product2 p = new product2(name='x'); insert p; Pricebook2 stdPb = [select Id from Pricebook2 where isStandard=true limit 1]; insert new PricebookEntry(pricebook2id = stdPb.id, product2id = p.id, unitprice=1.0, isActive=true); // Next, it creates a new pricebook with an entry for this product Pricebook2 pb = new pricebook2(name='test'); insert pb; PricebookEntry pbe = new PricebookEntry(pricebook2id=pb.id, product2id=p.id, unitprice=1.0, isActive=true); insert pbe; // To test the first example from the sample application, the test // method creates an opportunity line item using the pricebook entry, // and then asserts that the Color field was correctly copied from the // product after record insertion. Opportunity o = new Opportunity(name='test', pricebook2id=pb.id, stageName='Open', CloseDate=Date.newInstance(2006,10,10)); insert o; OpportunityLineItem oli = new OpportunityLineItem(opportunityid=o.id, pricebookentryid=pbe.id, unitprice=1.5, quantity=2); insert oli; /*System.assertEquals('c', [select color__c from opportunitylineitem where id = :oli.id].color__c);*/ // To test the fifth example from the sample application, the test method // creates a primary quote and then asserts that its Primary field cannot // be deselected. The code uses the try...catch testing idiom to assert // that the error message is correct. SFDC_520_Quote__c q = new SFDC_520_Quote__c(opportunity__c = o.id, primary__c = true); insert q; // Cannot mark it non-primary q.primary__c = false; try { update q; } catch (DmlException e) { System.assert(e.getMessage().contains('first error: FIELD_CUSTOM_VALIDATION_EXCEPTION,'+ ' Primary quote cannot be marked non-primary: [Primary__c]'), e.getMessage()); System.assertEquals('Primary quote cannot be marked non-primary', e.getDmlMessage(0)); System.assertEquals(SFDC_520_Quote__c.Primary__c, e.getDmlFields(0)[0]); } // To test the second and third examples from the sample application, the // test method asserts that the inserted quote has the proper quote line // data copied from the opportunity line item, and that the quote's total // value is properly calculated. System.assertEquals(1, [select count() from SFDC_520_quoteline__c where quote__c = :q.id]); //delete o; // delete q; // To test the fifth example from the sample application, the test method // creates a primary quote and then asserts that its Primary field cannot // be deselected. The code uses the try...catch testing idiom to assert // that the error message is correct. SFDC_520_Quote__c q2 = new SFDC_520_Quote__c(opportunity__c = o.id, primary__c = true); insert q2; // To test the fifth example from the sample application, the test method // creates a primary quote and then asserts that its Primary field cannot // be deselected. The code uses the try...catch testing idiom to assert // that the error message is correct. //System.assert(![select primary__c from SFDC_520_quote__c where id = :q.id].primary__c); // Can't have the same opportunity marked as primary for the same opportunity // in the same insert/update SFDC_520_Quote__c[] quotes = new SFDC_520_Quote__c[] { new SFDC_520_Quote__c(opportunity__c = o.id, primary__c = true), new SFDC_520_Quote__c(opportunity__c = o.id, primary__c = true)} ; insert quotes; // Finally, the test method performs DML operations on quote line // items to assert that the quote line item values are properly // recalculated when associated values change. SFDC_520_QuoteLine__c qLine = new SFDC_520_QuoteLine__c(quote__c = q.id, product2__c = p.id, unit_price__c = 2.0, Qty_Ordered__c = 2); SFDC_520_QuoteLine__c qLine1 = qLine.clone(); insert qLine; // qLine.unit_price__c = 3.0; // update qLine; delete qLine; // Bulk line item operation insert new SFDC_520_QuoteLine__C[]{qLine1, qLine1.clone()}; // Test that updating the product master color and then updating the quote colors works } }

 

 Any Help would be kindly appreciated...

 

 

 

 

WhyserWhyser

trigger quoteTrigger on SFDC_520_quote__c (after insert, before update) { for (SFDC_520_Quote__c q : Trigger.new) { if (Trigger.isInsert) util.copyLineItemsFromOpp(Trigger.new); if ( Trigger.isUpdate && ( q.Partner__c != Trigger.oldMap.get( q.Id) ) ) {// Do your logic to change the sales_discount__c accordingly q.sales_discount__c = newvalue; // no need to run any update statements since you are modifying Trigger.new BEFORE it updates. When it updates it will take in the changes you made to Trigger.new } } }

 

I'm guessing that you want this to run off a trigger?

 

 

shan876shan876

Thank you for replying back ....

but when I do this:

 

trigger quoteTrigger on SFDC_520_quote__c (after insert, before update) { for (SFDC_520_Quote__c q : Trigger.new) { if (Trigger.isInsert) util.copyLineItemsFromOpp(Trigger.new); if (Trigger.isUpdate && (q.Partner_Direct__c != Trigger.oldMap.get(q.id))) { // Do your logic to change the sales_discount__c accordingly //q.sales_discount__c = newvalue; util.copyLineItemsFromOpp(Trigger.new); // no need to run any update statements since you are modifying Trigger.new BEFORE it updates. //When it updates it will take in the changes you made to Trigger.new }

} }

 I get an error on

 if (Trigger.isUpdate && (q.Partner_Direct__c != Trigger.oldMap.get(q.id))) 

Save error: Comparison arguments must be compatible types: String, SOBJECT:SFDC_520_Quote__c    quoteTrigger.trigger    sensage/src/triggers    line 6  

???

See the partner_direct__c field is an update field from Opportunity. So when someone changes the partner field in opportunity the quote changes. 

When this changes, then

util.copyLineItemsFromOpp

 

 to run again... deleting the previous record and re-inserting new records because the sales_discount will change accordingly...

Thanks

 

WhyserWhyser

shan876 wrote:

Thank you for replying back ....

but when I do this:

 

trigger quoteTrigger on SFDC_520_quote__c (after insert, before update) { for (SFDC_520_Quote__c q : Trigger.new) { if (Trigger.isInsert) util.copyLineItemsFromOpp(Trigger.new); if (Trigger.isUpdate && (q.Partner_Direct__c != Trigger.oldMap.get(q.id).Partner_Direct__c)) { // Do your logic to change the sales_discount__c accordingly //q.sales_discount__c = newvalue; util.copyLineItemsFromOpp(Trigger.new); // no need to run any update statements since you are modifying Trigger.new BEFORE it updates. //When it updates it will take in the changes you made to Trigger.new }

} }

 I get an error on

 if (Trigger.isUpdate && (q.Partner_Direct__c != Trigger.oldMap.get(q.id))) 

Save error: Comparison arguments must be compatible types: String, SOBJECT:SFDC_520_Quote__c    quoteTrigger.trigger    sensage/src/triggers    line 6  

???

See the partner_direct__c field is an update field from Opportunity. So when someone changes the partner field in opportunity the quote changes. 

When this changes, then

util.copyLineItemsFromOpp

 

 to run again... deleting the previous record and re-inserting new records because the sales_discount will change accordingly...

Thanks

 


Sorry that's my bad. Please see the bolded text above for the corrections. I was comparing Partner_Direct__c value to the SFDC_520_Quote__c object, which is a mistake.