+ Start a Discussion
KarenCKarenC 

Need to create a button that will clone a quote and the related quote line items

Was wondering if someone has successfully accomplished cloning a quote and the related quote line items?  I need it to create a new quote revision without creating a whole new quote with new quote number...just a new revision number.

 

I am struggling and thought that this task has probaly been done by someone "out there"...

 

I appreciate your help!!

sfdcfoxsfdcfox

Salesforce has explicitly designed Quotes to not be "cloneable" (at least, not very easily). The following parameters are needed to successfully clone a Quote:

 

clone=1 -- Tells the application to use the clone feature.

oppid=Quote.OpportunityId -- Tells the application which opportunity this is for

id=Quote.Id -- Tells the application which quote to clone

 

You would use the New Quote action (see URLFOR) to create a button that would clone the quote.

 

However, they have explicitly blocked access in the Merge Field feature of the URL builder to Quote.OpportunityId, so you can't directly create a button on the quote that would clone the quote.

 

You can, however, use the AJAX toolkit (see the documentation) to first query for the opportunity ID, then construct an appropriate URL that could be used to create this button.

 

You will need a button type "execute JavaScript" on the Quote object as a detail button, then use the following:

 

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")}
result = sforce.connection.query("select id,opportunityid from Quote where id = '{!Quote.Id}'")
window.top.location.href =
"{!URLFOR( $Action.Quote.NewQuote ,null,[clone=1,id=Quote.Id,retURL="/"&Quote.Id],true)}&oppid=" +
result.records.OpportunityId

This button simply queries the existing opportunity ID, then passes all the parameters it needs to clone the quote. You can also add "save=1" if you want to skip the creation page and directly go to a new saved quote.

KarenCKarenC

Thanks sfdcfox!!!  Sorry for the delayed reply - just getting back around to this.

 

That worked perfectly!!  You rock!!

 

I have one more question for you...

 

Once I clone the quote I need to increment a revison number  by 1.  This has to be done within a quote (custom quote number field = quote_number_test__c )  also within the opportunity.

 

I am thinking I will need a before insert apex trigger.  I am totally new to this - but this is what I am thinking...what to you?

 

Here goes :

 

trigger updatequoterevision on Quotes (before insert)

{

  ID RevisionNum;

 

  Quotes[] QT = trigger.new;

  for (quotes Q:QT)

   {

     if (Q.revision? = true)   // this is a boolean that is set when the click the "clone quote button

       {

        ID QuoteRevisionNum = select max(version__c) + 1 from quotes 

              where opportunity = :opportunity  // within the current opp 

              and quote_number_test__c = :quote_number_test__c;  //within the current quote

       q.version__c = QuoteRevisionNum;

        }

     }

}

 

 

 

 

 

akcooper9akcooper9

I've tried the above code in the second post and I am still unable to 'clone' a quote. Instead, it takes me to the new quote screen and requires me to select type of quote I want ( we have two record types for quotes). Once I select the appropriate record type, Im able to edit the new quote but none of the values from the cloned quote transfer over.

 

I have just confirmed that if I inactive one of the record types, the above code in the second post works PERFECT!

 

My question is, what changes to the code need to be made in order to utilize two record types. 

bhs00bhs00

Thank you sfdcfox. 

dv4dv4

I used the same logic as mentioned above. But my quoteline items have some custom fields and those values are not being copied in my clone quote.

 

Any suggestions on how to copy the custom field values??

QRQR

Hello sfdcfox

 

I used the code that you listed and it worked perfectly.  How would I clone the actual Quote Line Items? 

 

thank you

 

QR Rob

JekeysJekeys

Hi

 

I seem to be having a bit of bother with this part of the code ,true)}&oppid=" + its saying Syntax error, have i missed something? Any help really appreciated! :)

JekeysJekeys

Hi QR Rob

 

I cant seem to make this bit work......,true)}&oppid=" + its saying Syntax error, have i missed something? Any help really appreciated! :)

HybridGHybridG

Capitalize TRUE, this is what worked for me.

Del_SantosDel_Santos

Hi sfdcfox,

 

Thanks for this. May i know where should i put the code (or how the code should be) . When cloning a quote i want a specific field to come as null. Is this possible?

 

when cloning, all the field values will be cloned except for the STATUS field value. I want this value to be null.

 

Thanks,

Del

 

josh1josh1

Is there a way to clone the quote and keep the quote line items instead of pulling the opportunity line items?

JekeysJekeys

Thanks for that! Dont suppose you have written a class for this have you? :):)

Ciarán LehaneCiarán Lehane
@sfdcfox - Thanks for the code above. I am using this to Clone quotes but now I would like to clone quotes while updating the record type of the new quote to 'Quote_Not_Approved'. Can you advise on this? Many Thanks.
Jessie Rymph 3Jessie Rymph 3
Just checking in to see if anyone ever figured out how to pass the record type into the button using the Execute Javascript version. Thanks. 
Jessie Rymph 3Jessie Rymph 3
Actually, what I'm now going to do is follow the advice here. Limit the record types available on create, and set them via workflow. https://success.salesforce.com/answers?id=90630000000CkZPAA0
Marina PesciniMarina Pescini
can we use the custom "clone" button also via Salesforce1? (clone quote with quote line items)
thanks.
Robert Hutchinson 20Robert Hutchinson 20
I can't get the line items to clone also using the formula above. 

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")}
2result = sforce.connection.query("select id,opportunityid from Quote where id = '{!Quote.Id}'")
3window.top.location.href =<br>    "{!URLFOR( $Action.Quote.NewQuote ,null,[clone=1,id=Quote.Id,retURL="/"&Quote.Id],true)}&oppid=" +<br>    result.records.OpportunityId
Khyati Mehta 3Khyati Mehta 3
This is not working for me it is showing unexpected token for me.....
 
Olga Kuzmina 9Olga Kuzmina 9
Same as above - an unexcpected token! 
Olga Kuzmina 9Olga Kuzmina 9

I found a way to make this code work:

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")} 
result = sforce.connection.query("select id,opportunityid from Quote where id = '{!Quote.Id}'") 
window.top.location.href = 
"{!URLFOR( $Action.Quote.NewQuote ,null,[clone=1,id=Quote.Id,retURL="/"&Quote.Id],true)}&oppid=" + 
result.records.OpportunityId

Removing  <br> helped. 

Kashmira PuranikKashmira Puranik
Hi Olga,
Can you tell me how to implement this ? I am new to Salesforce and not pretty sure about creating URL.
Lewis HowelLewis Howel
You should be able to perform this utlising the lightning flow rather than writing code. 
Jane Brady 18Jane Brady 18
I had the issue also with the invalid token. There's a { missing at the beginning of the code. It works fine in Classic UI if you use this instead of the original first shown:

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")} 
result = sforce.connection.query("select id,opportunityid from Quote where id = '{!Quote.Id}'") 
window.top.location.href = 
"{!URLFOR( $Action.Quote.NewQuote ,null,[clone=1,id=Quote.Id,retURL="/"&Quote.Id],true)}&oppid=" + 
result.records.OpportunityId

Now I need to work out a way to do this in Lightning since OnClick isn't supported. Flow, here I come.
Ankit Kalsara 6Ankit Kalsara 6
Hi @Jane Brady 18: Were you able to solve this issue in Salesforce Lightning ?

If yes, can you please guide me with the steps. I want to clone the Quote along with the line items. 

I tried implementing flow as well but keep getting an error.

"This error occurred when the flow tried to create records: FIELD_INTEGRITY_EXCEPTION: The price book entry is in a different price book than the one assigned to the Quote, or Quote has no price book assigned.: Price Book Entry ID."
Jane Brady 18Jane Brady 18
Hi @Ankit Kalsara 6. I had started working up the Flow but got pulled in another direction so haven't gotten back to that. From the error you are getting, it sounds to me like you need to make sure you have both the PricebookEntryId and Product2Id fields added to your Quote Line Item variable. That, and make sure you do have a pricebook assignment for the product itself.
Ankit Kalsara 6Ankit Kalsara 6
Hi @Jane Brady 18, thanks for your reply.

I did added the PricebookentryId and ProductId while creating Quote line items and my product is also added to the standard price book.

User-added image.

Not able to figure out what the exact issue is.
Ankit Kalsara 6Ankit Kalsara 6
Hi @Jane Brady 18,

I was able t o resolve the issue now with the flow. I was not assigning Pricebook2Id to the Cloned quote object from original quote.
Jane Brady 18Jane Brady 18
Good job,@Ankit Kalsara 6! Care to share your Flow with the group? You are right that a number of us without the CSP do have need of this, and now you are the first who could show others the way!
Ankit Kalsara 6Ankit Kalsara 6
Hi @Jame Brady 18,

Sure, below is the flow which I created (Note: I am still doing thorough testing on this, initial round of testing looks fine)


User-added image

Element 1: Get Records(Get Quote details) --> Get the current quote details, the quote which needs to be cloned
Element 2: Create Records(Create Cloned Quote) --> create Quote object without passing ID parameter (Pricebook2Id is a must parameter which needs to be obtained from Element 1)
Element 3: Screen --> completely optional (it just guides user to click additional next button)
Element 4: Get Records (Get Quote Line Items) --> fetch all the quote line items WHERE QuoteId equals recordId (here we must fetch the fields Product2Id & PricebookEntryId)
Element 5: Loop --> loop through each element 4
Element 6: Create Records(Create line items for Cloned Quote) --> Here we need to link cloned line items with the cloned quote id (else cloned quote line items will be linked back to the original quote)
Element 7: Get Records(Get Cloned Quote Number) --> fetching the cloned quote number using cloned quote id (from element 2) for display purpose
Element 8: Screen --> Optional (just displaying the cloned quote number)

Note: Above quote can be improved since we are performing DML operation(Element 6) inside the loop. Fetch all the Quote line items and store it in the collection variable and pass the collection to Create Record element directly to save the resources.