My company is interested in having Salesforce automatically create Opportunity line items upon lead conversion, based on data on the lead.
What I have set up are lookup fields on the lead for Product, and Price Book. I then mapped these fields on lead conversion mapping to corresponding custom fields on the opportunity. When I convert a lead, these lookup fields are successfully passing their data from the lead to the newly created opportunity (which gets created at the time of conversion). However, it does not appear that it is possible to create opportunity line items at the same time that the opportunity gets created. I created a trigger that should have worked, however no line items get created, and no errors are thrown. After doing a little research, I found this suggestion, along with their own trigger, which appears to clone the opportunity and then the opportunity line items are inserted to the cloned opportunity, here:
https://developer.salesforce.com/forums/?id=906F00000008oyNIAQ
This trigger doesn't even compile, but it gave me a good starting point. I'm now getting an error when I try to convert leads with an error message that's not very helpful.
Error: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, trgAddProductFromLead: execution of AfterInsert caused by: System.DmlException: Update failed. First exception on row 0; first error: MISSING_ARGUMENT, Id not specified in an update call: [] Trigger.trgAddProductFromLead: line 29, column 1: [] Class.leadconvert.BulkLeadConvert.handleOpportunityInserts: line 737, column 1 Class.leadconvert.BulkLeadConvert.convertLead: line 104, column 1
I've posted my trigger below. Let me know if you need any additional information from me, I'm pretty stumped!
trigger trgAddProductFromLead on Opportunity (after insert) {
Set<ID> oppProdId = new Set<ID>(); //Builds Product Ids to use in query
Set<ID> oppPBId = new Set<ID>(); //Builds PriceBook Ids to use in query
List<Opportunity> oppList = new List<Opportunity>(); //Builds list of Opportunities to update the Price Book ID field
List<OpportunityLineItem> oliList = new List<OpportunityLineItem>(); //Set used to create Opportunity Products
Map<ID, ID> pbeMap = new Map<ID, ID>(); //Map used to match Products to PriceBookEntry records
for(Opportunity o : Trigger.new) {
if(o.Product__c != null && o.Price_Book__c != null) { //Only use the Opportunity if it is created with a Product__c and Price_Book__c value (i.e. - On Convert)
Opportunity otemp = o.clone(false, false, false, false);
oppProdId.add(o.Product__c); //Add the product id to the set
oppPBId.add(o.Price_Book__c); //Add the pricebook id to the set
oppList.add(otemp);
}
}
update oppList; //Update all of the Opportunities with teh Price Book
for(PriceBookEntry pbe : [select Id, Product2Id from PriceBookEntry where PriceBook2Id in :oppPBId and Product2Id in :oppProdId]) {
pbeMap.put(pbe.Product2Id, pbe.id); //Build the map to use to match Procucts to PriceBookEntries
}
for(Opportunity opp : oppList) { //Build the OpportunityLineItems for each Opportunity (sets the quantity to 1 and the price to 100)
OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = opp.id, PriceBookEntryId = pbeMap.get(opp.Product__c), Quantity = 1, UnitPrice = 100);
oliList.add(oli);
}
if(oliList.size() > 0) {
insert oliList; //Create the OpportunityLineItems
}
}
Alternatively, if there is a better way to go about this (I have not found one online), I'm willing to try something else!
update oppList;