+ Start a Discussion
kevin Carotherskevin Carothers 

I Can't insert an OpportunityLineItem from a trigger.

My use case is that, when a rep inserts an "Advanced" product (product code 99997) on and opportunity, I have to look at all the opportunities on the related account, and see if a "Basic" product is also on an opportunity on the account (product code 99998).  

If not, I need to insert an OpportunityLineItem record with the  Basic product.
What's weird to me is that, after building and inserting the OpportunityLineItem and putting it in the correct Opportunity (the one being edited), the 'before' and 'after' debug statements show no change to the number of opportunitylineitems.... This seems very strange to me.
 

Does anyone have a clue as to what may be happening?   Is it even possible to programmatically add opportunitylineitems?

Thanks,

 

trigger CheckOpportunityForProperProducts on OpportunityLineItem (after insert) {
    Set<Id> accIdList = new Set<Id>();
    List<Id> oppIdList = new List<Id>();    

	// Get Pricebook info for later (possible) insert
    Pricebook2 standardBook = [SELECT Id FROM Pricebook2 WHERE IsStandard = true];
    PricebookEntry BasicEntry = [SELECT Id, UnitPrice FROM PricebookEntry WHERE Pricebook2Id = :standardBook.Id AND Product2.ProductCode = '99998'];

	//All opportunity IDs in a list
	for(OpportunityLineItem oli :Trigger.new) {
		oppIdList.add(oli.OpportunityId);
	    }

    // this gives us just the account IDs related to this insert...
    List<Opportunity> tmpOpps = [SELECT Id,  AccountId FROM Opportunity WHERE Id in :oppIdList];
    List<Opportunity>  updateTheseOpportunities = new List<Opportunity>();

	for(Opportunity o :tmpOpps) {
		accIdList.add(o.AccountId);
	    }

	// Now get the complete set of working data
    Map<Id, Opportunity> allOpps = new Map<Id, Opportunity> ([SELECT Id, AccountId, StageName, CreatedDate,
	                                             Type, CloseDate, Name,
	                                                   (SELECT Quantity, UnitPrice, TotalPrice,
	                                                           PricebookEntry.Name,
	                                                           PricebookEntry.Product2.ProductCode
	                                                    FROM OpportunityLineItems)
	                                        FROM Opportunity WHERE AccountId in :accIdList
	                                        AND StageName LIKE '%Stage 5:%'
	                                        AND Count_of_Products__c > 0
                                        ORDER BY CreatedDate  ASC]);

	for(Id  acctId :accIdList) {
		Boolean  AdvancedRuleFound = false;
		Boolean  BasicRuleFound = false;
		Id theOppId = null;

		for(Opportunity o :allOpps.values()) {
			if(o.OpportunityLineItems != null && o.AccountId == acctId) {   // oppty related to this account
				// check all oppty products on this account
				for(OpportunityLineItem opptyLineItem : o.OpportunityLineItems) {
					if(opptyLineItem.PricebookEntry.Product2.ProductCode == '99997') {   // Advanced
						AdvancedRuleFound = true;
						theOppId = o.Id;    // put on the same opportunity that the Advanced is on....
						}
					if(opptyLineItem.PricebookEntry.Product2.ProductCode == '99998') {    // Basic
						BasicRuleFound = true;					
						}
					} // end of sifting thru olis
				}   // END check for OpportunityLineItems
			}    // END for(Opportunity o :allOps)

	    	System.debug('allOpps.get(theOppId).OpportunityLineItems.size() - Before: ' + allOpps.get(theOppId).OpportunityLineItems.size());
	    
		if(BasicRuleFound== false && AdvancedRuleFound == true && theOppId != null) {   // need to insert the basic product...
			OpportunityLineItem oppli = new OpportunityLineItem(PricebookEntryId=BasicEntry.Id, OpportunityId=theOppId, UoM__c='Each', NRC__c = 1000, UnitPrice=0, Quantity=1);
			allOpps.get(theOppId).OpportunityLineItems.add(oppli);
			System.debug('allOpps.get(theOppId).OpportunityLineItems.size() - After: ' + allOpps.get(theOppId).OpportunityLineItems.size());
			updateTheseOpportunities.add(allOpps.get(theOppId));
			}
    	}
        //upsert updateTheseOpportunities;
    }
 


 

Zuinglio Lopes Ribeiro JúniorZuinglio Lopes Ribeiro Júnior
Hello,

Not sure if I got it right but try this:
 
trigger CheckOpportunityForProperProducts on OpportunityLineItem (after insert) {
    Set<Id> accIdList = new Set<Id>();
    List<Id> oppIdList = new List<Id>();    

	// Get Pricebook info for later (possible) insert
    Pricebook2 standardBook = [SELECT Id FROM Pricebook2 WHERE IsStandard = true];
    PricebookEntry BasicEntry = [SELECT Id, UnitPrice FROM PricebookEntry WHERE Pricebook2Id = :standardBook.Id AND Product2.ProductCode = '99998'];

	//All opportunity IDs in a list
	for(OpportunityLineItem oli :Trigger.new) {
		oppIdList.add(oli.OpportunityId);
	    }

    // this gives us just the account IDs related to this insert...
    List<Opportunity> tmpOpps = [SELECT Id,  AccountId FROM Opportunity WHERE Id in :oppIdList];
    List<OpportunityLineItem>  lineItensToInsert = new List<OpportunityLineItem>();

	for(Opportunity o :tmpOpps) {
		accIdList.add(o.AccountId);
	    }

	// Now get the complete set of working data
    Map<Id, Opportunity> allOpps = new Map<Id, Opportunity> ([SELECT Id, AccountId, StageName, CreatedDate,
	                                             Type, CloseDate, Name,
	                                                   (SELECT Quantity, UnitPrice, TotalPrice,
	                                                           PricebookEntry.Name,
	                                                           PricebookEntry.Product2.ProductCode
	                                                    FROM OpportunityLineItems)
	                                        FROM Opportunity WHERE AccountId in :accIdList
	                                        AND StageName LIKE '%Stage 5:%'
	                                        AND Count_of_Products__c > 0
                                        ORDER BY CreatedDate  ASC]);

	for(Id  acctId :accIdList) {
		Boolean  AdvancedRuleFound = false;
		Boolean  BasicRuleFound = false;
		Id theOppId = null;

		for(Opportunity o :allOpps.values()) {
			if(o.OpportunityLineItems != null && o.AccountId == acctId) {   // oppty related to this account
				// check all oppty products on this account
				for(OpportunityLineItem opptyLineItem : o.OpportunityLineItems) {
					if(opptyLineItem.PricebookEntry.Product2.ProductCode == '99997') {   // Advanced
						AdvancedRuleFound = true;
						theOppId = o.Id;    // put on the same opportunity that the Advanced is on....
						}
					if(opptyLineItem.PricebookEntry.Product2.ProductCode == '99998') {    // Basic
						BasicRuleFound = true;					
						}
					} // end of sifting thru olis
				}   // END check for OpportunityLineItems
			}    // END for(Opportunity o :allOps)

	    	System.debug('allOpps.get(theOppId).OpportunityLineItems.size() - Before: ' + allOpps.get(theOppId).OpportunityLineItems.size());
	    
			if(BasicRuleFound== false && AdvancedRuleFound == true && theOppId != null) {   // need to insert the basic product...
				OpportunityLineItem oppli = new OpportunityLineItem(PricebookEntryId=BasicEntry.Id, OpportunityId=theOppId, UoM__c='Each', NRC__c = 1000, UnitPrice=0, Quantity=1);
				lineItensToInsert.add(oppli);
			}
    	}
    }
	
	if(!lineItensToInsert.isEmpty()) Database.insert(lineItensToInsert);
}

Let me know if it worked.


Regards.

Don't forget to mark your thread as 'SOLVED' with the answer that best helps you.
kevin Carotherskevin Carothers
Hi Zuinglio,

Close, but the culprit was I needed to insert the OpportunityLineItem directly - basically like this;
 
[---]

if(BasicRuleFound== false && AdvancedRuleFound == true && theOppId != null) {   // need to insert the basic product...
			OpportunityLineItem oppli = new OpportunityLineItem(PricebookEntryId=BasicEntry.Id, OpportunityId=theOppId, UoM__c='Each', NRC__c = 1000, UnitPrice=0, Quantity=1);
			//allOpps.get(theOppId).OpportunityLineItems.add(oppli);
			//updateTheseOpportunities.add(allOpps.get(theOppId));
			insert oppli;
			}

...But I gave you a thumbs up for effort - and thanks for the prompt reply..... I hope to return the favor some day :-)