+ Start a Discussion

Cloning Opportunity Line Items



In our company we occasionally have opportunities in which we are quoting very similar products for a customer. So we end up creating 3 line items for variations of one of our standard products. Our Line Items are heavily customized, so there is quite a lot of data to be entered.


Unfortunately there doesn´t seem to be an option to Clone a Line Item, unsure why. Has anyone come accross this need? I think I will investigate how easy / difficult it is to create a button that calls an Apex function that clones this object, hopefully it can be done easily with code. Any hints / ideas much appreciated.






Maybe I'm missing something, but if you add a product to an Opportunity, the Clone button will update and offer 2 choices when selected - Clone with Products or Clone without Products.




Do you not see that behavior? Keep in mind, if your Opportunity has no products, then the Clone button does not offer these 2 choices.







Maybe it was me not explaining it clearly. It is not the Opp I want to clone with all the products. It is 1 Opp with 5 products that are similar: I create the Opp, I create Opp Product (Line Item) 1 and then I would like to replicate that 1 4 times and make small adjustments.


Hopefully I have been clearer now. Any thoughts?




Hi J,


I have the same problem as you.  Have you figured out an answer yet, because I am having no luck.  I'd be interested to hear if you have a solution.





I too am looking for a solution to this problem.  I'd like to clone the opportunity product (or opportunitylineitem) record.


Any update on this issue?  This is a need for us as well.  


Here is the code we are using for the purpose of cloning Opportunity line items: 


<apex:page standardcontroller="OpportunityLineItem" extensions="cloneOppPrd_Extension" tabstyle="OpportunityLineItem">
<!-- Provide fields so that we don't need to query them within the apex class -->
<apex:outputpanel rendered="false">
<!-- Custom clone button and form, allows users to clone and make modifications during the clone process -->

<apex:form >
<apex:sectionHeader title="Clone Opportunity Product" subtitle="Clone of {!cloneopp.PricebookEntry.Name}"/>
<apex:pageblock >
    <apex:pageBlockButtons >
        <apex:commandbutton action="{!Save}" value="Save"/>
        <apex:commandbutton action="{!Cancel}" value="Cancel"/>     
    <apex:pageBlockSection columns="2" title="Product Information">
        <apex:outputField value="{!cloneopp.OpportunityId}"/>
        <apex:outputField value="{!cloneopp.PricebookEntry.Name}"/>
        <apex:inputField value="{!cloneopp.Fixed_Price__c}"/>
        <apex:inputField value="{!cloneopp.Service_Type__c}"/>
        <apex:outputField value="{!cloneopp.PricebookEntry.ProductCode}"/>
        <apex:inputField value="{!cloneopp.Custom_Quote__c}"/>                                      

    <apex:pageBlockSection columns="2" title="Order Details">
        <apex:inputField value="{!cloneopp.Launch_Date__c}"/>
        <apex:inputField value="{!cloneopp.Brand__c}"/>
        <apex:inputField value="{!cloneopp.End_Date__c}"/>
        <apex:inputField value="{!cloneopp.Geotargeted__c}"/>
        <apex:inputField value="{!cloneopp.Description__c}"/>
        <apex:inputField value="{!cloneopp.UnitPrice}"/>        
        <apex:inputField value="{!cloneopp.ListPrice}"/>
        <apex:inputField value="{!cloneopp.Quantity}"/>
        <apex:inputField value="{!cloneopp.Volume_Tier_List_Price__c}"/>
        <apex:inputField value="{!cloneopp.PPM_Price_Per_Thousand__c}"/>                                                                                            
    <apex:pageBlockSection columns="2" title="Forecasting">
        <apex:inputField value="{!cloneopp.Expected_Performance__c}"/>


GeorgeB11, this looks great!  Thank you very much.


Will you please also post the class body of the cloneOppPrd_Extension apex class?


Much thanks!




public with sharing class cloneOppPrd_Extension {

    private final OpportunityLineItem oli; 
    public cloneOppPrd_Extension(ApexPages.StandardController stdController) {
        this.oli = (OpportunityLineItem)stdController.getRecord();
    public OpportunityLineItem cloneopp; 
    public OpportunityLineItem getCloneopp(){
      if(cloneopp == null)cloneopp = oli.clone(false,true);      
      return cloneopp;        

  public Pagereference save(){
    insert cloneopp;
    Apexpages.Pagereference retURL = new PageReference('/'+cloneopp.id);
    return retURL;
    static testmethod void testOppPrdClone(){
    Account a = new Account(Name = 'Test Account');  
    insert a;        
    Opportunity opp = new Opportunity(name='test opp', stagename='New', CloseDate=System.today(), AccountId=a.id, Commission_Information__c = 'Media Only');          
    insert opp;  
    Product2 prod = new Product2(name = 'test product', External_ID__c = 'testxid');
    insert prod;  
    Pricebook2 pb2 = [select id from Pricebook2 where IsStandard =: true];    
    PricebookEntry pbe = new PricebookEntry(UnitPrice=1, Product2Id=prod.id, Pricebook2Id = pb2.id,IsActive=true);
    insert pbe;        
    OpportunityLineItem oppLine = new OpportunityLineItem(UnitPrice=1,Quantity=100,description__c='test',expected_performance__c=80,PricebookEntryId=pbe.id,OpportunityId=opp.id,Launch_Date__c=system.today(),End_Date__c=system.today().addDays(365));      
    insert oppLine;
      ApexPages.StandardController sc = new ApexPages.StandardController(oppLine);      
        cloneOppPrd_Extension controller = new cloneOppPrd_Extension(sc);    
      PageReference pageRef = Page.cloneOppPrd;


Holy stuff!!! This is great!


Eleventy billion internets awarded to you good sir!






Thank you again for the code you posted a few months ago.


I'm having trouble with the Apex code coverage test.  I seem to be getting the following error...


System.QueryException: List has no rows for assignment to SObject

Class.cloneOppPrd_Extension.testOppPrdClone: line 30, column 1


This appears to be a reference to the following line...


Pricebook2 pb2 = [select id from Pricebook2 where IsStandard =: true];


For some reason, this query appears to be returning no rows.  Have you run into this error yourself?  Any ideas about why it isn't returning the Standard Pricebook ID?


Much thanks!



If you are not using your organisation data i.e if the seealldata=false , you can retrieve the standard price book id using the below standard method

Id pb2Id = Test.getStandardPricebookId();

Let me know if this is not you are looking for.