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
HTANIRSHTANIRS 

trigger on opportunlineitem to create Quote and Quotelineitem

Hi Friends,

I have a requirement where I need to create a Quote and QuoteLineItem when OpportunityLineItem is created.

I have created a trigger on Opportunitylineitem and it is working fine but I am facing an issue that more number of Quotes is getting created based on Opportunitylineitems.
For Eg: I have 3 products in Opplineitem. I need to create 1 Quote with 3 QuoteLineitem. But it is creating 3 Quotes. However, Quotelineitem is creating correctly.

Below is my trigger
trigger quoteCreation on OpportunityLineItem (after insert) {
    System.debug('--- Inside Oppslineitem Trigger ---');

    List<Quote> quoteList = new List<Quote>();
    Set<ID> oppIds = new Set<ID>();

    for(OpportunityLineItem oppli : Trigger.New){
        oppIds.add(oppli.Id);
        System.debug('--- Opportunity Id: ---' + oppli.OpportunityId);
    }
    
    List<OpportunityLineItem> opplList = [SELECT Id, Opportunity.Name, Opportunity.AccountId, Opportunity.Account.PersonContactId, OpportunityId, Opportunity.Account.Name, Opportunity.Account.PersonEmail,
                                                 Opportunity.Account.Salutation, Opportunity.Account.BillingCity, Opportunity.Account.BillingCountry, Opportunity.Account.BillingPostalCode, Opportunity.Account.BillingState,
                                                 Opportunity.Account.ShippingCity, Opportunity.Account.ShippingCountry, Opportunity.Account.ShippingPostalCode, Opportunity.Account.ShippingState,
                                                 Opportunity.Account.BillingStreet, Opportunity.Account.ShippingStreet
                                            FROM OpportunityLineItem 
                                            WHERE Id IN:oppIds];
    
    for(OpportunityLineItem oppli : opplList) {
        System.debug('--- Inside Opportunity Loop ---' + opplList.size());
        
        //Create Quote        
        Quote quo = new Quote();
        quo.Name = oppli.Opportunity.Name + '-' + 'Quote';
        quo.Status = 'Draft';
        quo.OpportunityId = oppli.OpportunityId;
        quo.ContactId = oppli.Opportunity.Account.PersonContactId;
        quo.Email = oppli.Opportunity.Account.PersonEmail;
        quo.BillingName = oppli.Opportunity.Account.Salutation + ' ' + oppli.Opportunity.Account.Name;
        quo.ShippingName = oppli.Opportunity.Account.Salutation + ' ' + oppli.Opportunity.Account.Name;
        quo.BillingStreet = oppli.Opportunity.Account.BillingStreet; 
        quo.BillingCity = oppli.Opportunity.Account.BillingCity;
        quo.BillingCountry = oppli.Opportunity.Account.BillingCountry;
        quo.BillingPostalCode = oppli.Opportunity.Account.BillingPostalCode;
        quo.BillingState = oppli.Opportunity.Account.BillingState;
        quo.ShippingStreet = oppli.Opportunity.Account.ShippingStreet;        
        quo.ShippingCity = oppli.Opportunity.Account.ShippingCity;
        quo.ShippingCountry = oppli.Opportunity.Account.ShippingCountry;
        quo.ShippingPostalCode = oppli.Opportunity.Account.ShippingPostalCode;
        quo.ShippingState = oppli.Opportunity.Account.ShippingState;
        quoteList.add(quo);
    }
        
    try {        
        if(quoteList.size() > 0) {    
            insert quoteList;
        }
        System.debug('--- Inserted Order List: ---' + quoteList.size()); 
    }
    catch(Exception e) {
        System.debug('The Following Exception has occurred: '+ e.getLinenumber() + ' : ' + e.getMessage());
    }
    
    // Insert Quote Line Item 
    set<Id> oppId = new Set<Id>();
    set<Id> pcrId = new set<Id>(); 
    List<QuoteLineItem> oliPist = new  List<QuoteLineItem>();
    
    for(Quote quo : quoteList) {
        System.debug('--- Inside Quote Loop ---' + quo);
        if(quo.opportunityId != null) {
            oppId.add(quo.opportunityId);
        }
    }
    
    Map<Id, List<OpportunityLineItem>> olitoOpp = new  Map<Id, List<OpportunityLineItem>>();
    
    for(OpportunityLineItem oli : [SELECT Id, Quantity, UnitPrice, PricebookEntryId, Product2Id, OpportunityId 
                                          FROM OpportunityLineItem WHERE opportunityId IN : oppId]) {
        pcrId.add(oli.Product2Id);
        if(olitoOpp.containsKey(oli.opportunityId)) {
            olitoOpp.get(oli.opportunityId).add(oli);
        }
        else {
            olitoOpp.put(oli.opportunityId, new List<OpportunityLineItem> {oli});
        }
    }
    
    for(Quote quot : quoteList) {
        if(olitoOpp.containsKey(quot.opportunityId)) {
            for(OpportunityLineItem  oli : olitoOpp.get(quot.opportunityId)){
    
                QuoteLineItem od = new QuoteLineItem();
                od.QuoteId = quot.Id;
                od.Quantity = oli.Quantity;
                od.PricebookEntryId = oli.PricebookEntryId;
                od.UnitPrice = oli.UnitPrice;
                od.Product2Id = oli.Product2Id;
                oliPist.add(od);
            }
        }
    }
    
    if(!oliPist.isEmpty()) {
        insert oliPist;
    }
            
}

Kindly review my code and let me know what I need to change.

Thanks in advance.
AnudeepAnudeep (Salesforce Developers) 
What is your quoteList.Size? System.debug('--- Inserted Order List: ---' + quoteList.size()); and opplList size

you need to ensure you insert  new quotes - one for each Opportunity. Can you look at the following working example? 

https://developer.salesforce.com/forums/?id=9060G0000005kYZQAY