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
bg_richardbg_richard 

Custom Clone Opportunity

As discussed in Ideas (http://ideas.salesforce.com/article/show/69729) here's a solution we have used for clients to enable customisation of the Clone button on Opportunities. This can be used to selectively choose which fields to copy and set default values:

 

For full details and the code to clone opportunity Line Items please contact me directly. We will be re-writing this in VisualForce over the coming months to make it futureproof.

 

Steps to Implement - Admins only

1. Setup -> Customize -> Opportunity -> Buttons and Links

2. Create new custom button called Clone, behaviour is Execute Javascript, Display Type Detail Page Button.

3. Paste in the code below and edit to match your requirements.

4. Remember to add the new button to the Opportunity page layout(s) and hide the original Clone button.

4. Test!

 

// Copyright 2008 BrightGen Ltd - All Rights Reserved try{ {!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")} // ** EDIT THIS QUERY TO LIST THE FIELDS YOU WANT TO COPY ** var result = sforce.connection.query("Select o.Type, o.StageName, o.Product_Type__c, o.Planned_Opportunity__c, o.MarketSector__c, o.CampaignId, o.Business_Unit__c, o.Amount, o.AccountId From Opportunity o WHERE o.Id = '{!Opportunity.Id}'"); var newOpp = result.getArray("records"); // Reset the Opp Id and reset fields to default values newOpp[0].Id = ''; newOpp[0].Name = "Clone {!Opportunity.Name}"; // ** EDIT THESE FIELDS TO SET DEFAULT ANY VALUES ** newOpp[0].StageName = "1. Prospecting"; newOpp[0].CloseDate = new Date(2099, 0, 1); var saveResult = sforce.connection.create(newOpp); if (saveResult[0].getBoolean("success")) { newOpp[0].id = saveResult[0].id; alert("Opportunity cloned without line items"); } else { alert("Failed to create clone: " + saveResult[0]); } // Refresh the page to display the new oppportunity window.location = newOpp[0].id; } catch (err) { alert (err.description ); }

 

 
Message Edited by bg_richard on 02-05-2009 07:11 AM
castlebuildercastlebuilder
Great idea.  Does this code clone with or without the Product Line Item related list?  Secondly, have you any ideas on doing a Mass Close?
bg_richardbg_richard

The above code is without the clone opp line items, simply due to trying to keep the example small. If you get in touch with me directly I'm happy to send you the code for the Opp Line Items too.

 

When you say Mass Close, is this a typo for Mass Clone? In either case, you would need to write a simple Apex class method to do the clone and given a list of IDs VisualForce to create a page a control to do the record selection and display of the cloned results.

 

If you're interested in this it's something we could discuss development of.

sgoremasgorema
Hello - I would be very interested in seeing the solution that includes the cloning of opportunity line items if you have it! thanks for sharing this..very helpful!
amorganamorgan
You might be interested in voting for this idea Clone API Call
insanedukeposseinsanedukeposse

Good stuff. I'm looking for the same solution in Apex/Visualforce. Unfortuneately, list.clone() and list.deepclone() will preserve the ID (which you can not reset as you do in the example below).


Any ideas?

insanedukeposseinsanedukeposse

I hate when I do this. I found the answer myself 2 minutes after posting this.

 

Apex Language Refererence: sObject clone with the opt_preserve_id parameter.

rpr2rpr2
This sample code is great!  Thank you so much for sharing it - and for documenting which sections need to be editted.  Easy to follow and makes me feel like a developer, which I am NOT.
MarioCMarioC

Thanks for the info. I have one question on these.  We have fields that the are restricted to some users, but we want those fields to be cloned.  Is there a way to clone a field that the user does not have access to?  Kind of like a "Clone as admin" button?  That would be ideal.  Also, the attachments- did you say you had a way to carry those over as well?

 

Thanks a ton.

 

bern023bern023
Have you completed the updated code?  If so I'm looking to implement a custom "clone" button.  Any documentation on how to complete this would be of great help as I'm not a developer either.   Specifically what code below needs to be inserted, gaps in code, how to add our custom fields to clone, set default, how to reassign the opportunity to a different user, etc. 
Fra08Fra08
Hello Richard,
thank you for the code,
I am creating the clone of the opp  line items but i have some problems, it doesn.t work..
insanedukeposseinsanedukeposse
I thought this might add some value to the discussion. The Apex class supports a specific requirement to clone the attachments and comments along with a case. It's not the opportunity, but the same principles apply. 
 
I'm sure there's a way to loop through the fields on an object, but I ended up hard coding it. 
 
Earlier in the thread someone asked about cloning fields that a user can't see. Apex operates in "system mode", so by passes profile field level security. This is good and bad, so be careful with your Apex code.
 
Final note: there are several bad coding practices in here that I would do differently today. I do not like the fact that I am passing them forward, but I guess it is for the greater good...
 
 

public class CaseClone { //courtesy of "Me, Myself and I, Inc." public String CaseNumberOld {get; set; } public String CaseNumberNew {get; set; } public Id CaseIdOld {get; set; } public Id CaseIdNew {get; set; } // this is the constructor public CaseClone (){ //get the passed parm CaseIdOld = System.currentPageReference().getParameters().get('caseid') ; } // this will be invoked from VForce page // in this kind of VForce page / controller, the constructor can not do the work public void doit(){ //SPECIFICALLY EXCLUDE: // , c.Close_Reason__c // , c.ClosedDate // , c.Case_Resolution_Description__c // , c.IsClosed // , c.IsDeleted // , c.CreatedDate // , c.LastModifiedDate // , c.New_Email_Has_Arrived__c // , c.System_Comment_Added__c // , c.System_New_Comment__c // , c.SystemModstamp //this gets the case... Case cOld = [ Select c.AccountId , c.AssetId , c.Best_Time_To_Call__c , c.Bill_For_DCT__c , c.Box_Count__c , c.Caller_Type__c , c.Case_Number_Subject__c , c.Case_Reason_2__c , c.Case_Watchers__c , c.CaseNumber , c.Category__c , c.CB_CC_SAT_Brand__c , c.CB_CC_SAT_Model__c , c.Cities_Affected__c , c.ContactId , c.Controller_Type__c , c.Date_Completed__c , c.Date_Due__c , c.Description , c.Effective_Date__c , c.Email_To_Case_Ref__c , c.Equipment__c , c.External_Case_Number__c , c.Firmware_Version__c , c.GBA__c , c.HasCommentsUnreadByOwner , c.HasSelfServiceComments , c.Head_End_ID__c , c.Host_Version__c , c.Households__c , c.Id , c.Inbound_Email_Address__c , c.IR_Connected__c , c.IR_Work__c , c.Last_Email_Comment__c , c.Legacy_Ticket_Number__c , c.Message_End_Date__c , c.Message_Start_Date__c , c.Message_Title__c , c.Model_Number__c , c.MSO_Account__c , c.MSO_s_Impacted__c , c.Origin , c.OwnerId , c.ParentId , c.Priority , c.Problem_Type__c , c.Product__c , c.Product_Version__c , c.Product_Version_Lvl_2__c , c.Reason , c.Recall_Date__c , c.RecordTypeId , c.Scheme_Version__c , c.SDV_Vendor__c , c.SDV_Vendor_Version__c , c.Second_Reference_Number__c , c.Secondary_Legacy__c , c.Setup_Type__c , c.Status , c.STB_Output_CH__c , c.Sub_Product__c , c.Subject , c.SuppliedCompany , c.SuppliedEmail , c.SuppliedName , c.SuppliedPhone , c.TechOps_Script_File__c , c.Type , c.VOD_Software_Version__c , c.VOD_Vendor__c , c.Zip_Code__c from Case c where id = :CaseIdOld ] ; //grab the old case number CaseNumberOld = cOld.CaseNumber ; // clones the original (resets id) Case cNew = cOld.clone(false, false); //over ride some fields cNew.Subject = '[CLONED CASE] ' + cOld.Subject; cNew.Status = 'New' ; cNew.ParentId = cOld.id ; //insert cloned case insert cNew; CaseIdNew = cNew.Id; //for some reason need to get the CaseNumber... Case cTemp = [select id, CaseNumber from Case where id = :cNew.Id ]; CaseNumberNew = cTemp.CaseNumber; // // COMMENTS // List<CaseComment> CommentsToAdd = new List<CaseComment>(); //loop existing records... for ( CaseComment EachComment : [SELECT CommentBody, CreatedById, CreatedDate, Id , IsPublished, ParentId FROM CaseComment c WHERE parentId = :cOld.id and isDeleted = False LIMIT 50]) { system.debug ('********** ' + EachComment.Id) ; CaseComment NewComment = EachComment.clone(false, false); NewComment.ParentId = cNew.Id ; NewComment.CommentBody = '[CLONED COMMENT] ' + NewComment.CommentBody ; CommentsToAdd.add(NewComment); } // this creates a brand new comment with information about this process CaseComment NewComment = new CaseComment(); NewComment.ParentId = cNew.Id ; NewComment.CommentBody = 'Note: this case was created via a CLONE of case ' + CaseNumberOld ; NewComment.IsPublished = False ; CommentsToAdd.add(NewComment); //ready to insert? insert CommentsToAdd ; // // ATTACHMENTS // // SPecifically excluded from attachment query... // , a.SystemModstamp // , a.CreatedById // , a.CreatedDate // , a.IsDeleted // , a.IsPrivate // , a.LastModifiedById // , a.LastModifiedDate //create a list of items to add... List<Attachment> AttachmentsToAdd = new List<Attachment>(); //loop existing records... for ( Attachment EachAttachment : [Select a.Body , a.BodyLength , a.ContentType , a.Id , a.Name , a.OwnerId , a.ParentId from Attachment a WHERE parentId = :cOld.id and isDeleted = False LIMIT 50]) { system.debug ('********** ' + EachAttachment.Name ) ; Attachment aNew = EachAttachment.clone(false, false); aNew.ParentId = cNew.Id ; AttachmentsToAdd.add(aNew); } insert AttachmentsToAdd ; } }

 

 
Here's the VF
 

<apex:page controller="CaseClone" action="{!doit}"><apex:pageBlock title="Hello {!$User.FirstName}!"><br />Your support case has been cloned!<br /><br /><i><b>Warning! Do not hit "refresh" on your browser or your case will be cloned AGAIN</b></i><br /><br /><br /><table cellpadding="10"><tr> <td>Original Case Number:</td> <td>{!CaseNumberOld}</td> <td><a href="/{!CaseIdOld}">Go to this case...</a></td></tr><tr> <td>New Case Number:</td> <td>{!CaseNumberNew}</td> <td> <a href="/{!CaseIdNew}">Go to this case...</a>:</td></tr></table><br /><br /></apex:pageBlock></apex:page>

 

 
 
 
 
insanedukeposseinsanedukeposse

Wow, that does not look good. Let's try that again...

 

public class CaseClone { //courtesy of "Me, Myself and I, Inc." public String CaseNumberOld {get; set; } public String CaseNumberNew {get; set; } public Id CaseIdOld {get; set; } public Id CaseIdNew {get; set; } // this is the constructor public CaseClone (){ //get the passed parm CaseIdOld = System.currentPageReference().getParameters().get('caseid') ; } // this will be invoked from VForce page // in this kind of VForce page / controller, the constructor can not do the work public void doit(){ //SPECIFICALLY EXCLUDE: // , c.Close_Reason__c // , c.ClosedDate // , c.Case_Resolution_Description__c // , c.IsClosed // , c.IsDeleted // , c.CreatedDate // , c.LastModifiedDate // , c.New_Email_Has_Arrived__c // , c.System_Comment_Added__c // , c.System_New_Comment__c // , c.SystemModstamp //this gets the case... Case cOld = [ Select c.AccountId , c.AssetId , c.Best_Time_To_Call__c , c.Bill_For_DCT__c , c.Box_Count__c , c.Caller_Type__c , c.Case_Number_Subject__c , c.Case_Reason_2__c , c.Case_Watchers__c , c.CaseNumber , c.Category__c , c.CB_CC_SAT_Brand__c , c.CB_CC_SAT_Model__c , c.Cities_Affected__c , c.ContactId , c.Controller_Type__c , c.Date_Completed__c , c.Date_Due__c , c.Description , c.Effective_Date__c , c.Email_To_Case_Ref__c , c.Equipment__c , c.External_Case_Number__c , c.Firmware_Version__c , c.GBA__c , c.HasCommentsUnreadByOwner , c.HasSelfServiceComments , c.Head_End_ID__c , c.Host_Version__c , c.Households__c , c.Id , c.Inbound_Email_Address__c , c.IR_Connected__c , c.IR_Work__c , c.Last_Email_Comment__c , c.Legacy_Ticket_Number__c , c.Message_End_Date__c , c.Message_Start_Date__c , c.Message_Title__c , c.Model_Number__c , c.MSO_Account__c , c.MSO_s_Impacted__c , c.Origin , c.OwnerId , c.ParentId , c.Priority , c.Problem_Type__c , c.Product__c , c.Product_Version__c , c.Product_Version_Lvl_2__c , c.Reason , c.Recall_Date__c , c.RecordTypeId , c.Scheme_Version__c , c.SDV_Vendor__c , c.SDV_Vendor_Version__c , c.Second_Reference_Number__c , c.Secondary_Legacy__c , c.Setup_Type__c , c.Status , c.STB_Output_CH__c , c.Sub_Product__c , c.Subject , c.SuppliedCompany , c.SuppliedEmail , c.SuppliedName , c.SuppliedPhone , c.TechOps_Script_File__c , c.Type , c.VOD_Software_Version__c , c.VOD_Vendor__c , c.Zip_Code__c from Case c where id = :CaseIdOld ] ; //grab the old case number CaseNumberOld = cOld.CaseNumber ; // clones the original (resets id) Case cNew = cOld.clone(false, false); //over ride some fields cNew.Subject = '[CLONED CASE] ' + cOld.Subject; cNew.Status = 'New' ; cNew.ParentId = cOld.id ; //insert cloned case insert cNew; CaseIdNew = cNew.Id; //for some reason need to get the CaseNumber... Case cTemp = [select id, CaseNumber from Case where id = :cNew.Id ]; CaseNumberNew = cTemp.CaseNumber; // // COMMENTS // List<CaseComment> CommentsToAdd = new List<CaseComment>(); //loop existing records... for ( CaseComment EachComment : [SELECT CommentBody, CreatedById, CreatedDate, Id , IsPublished, ParentId FROM CaseComment c WHERE parentId = :cOld.id and isDeleted = False LIMIT 50]) { system.debug ('********** ' + EachComment.Id) ; CaseComment NewComment = EachComment.clone(false, false); NewComment.ParentId = cNew.Id ; NewComment.CommentBody = '[CLONED COMMENT] ' + NewComment.CommentBody ; CommentsToAdd.add(NewComment); } // this creates a brand new comment with information about this process CaseComment NewComment = new CaseComment(); NewComment.ParentId = cNew.Id ; NewComment.CommentBody = 'Note: this case was created via a CLONE of case ' + CaseNumberOld ; NewComment.IsPublished = False ; CommentsToAdd.add(NewComment); //ready to insert? insert CommentsToAdd ; // // ATTACHMENTS // // SPecifically excluded from attachment query... // , a.SystemModstamp // , a.CreatedById // , a.CreatedDate // , a.IsDeleted // , a.IsPrivate // , a.LastModifiedById // , a.LastModifiedDate //create a list of items to add... List<Attachment> AttachmentsToAdd = new List<Attachment>(); //loop existing records... for ( Attachment EachAttachment : [Select a.Body , a.BodyLength , a.ContentType , a.Id , a.Name , a.OwnerId , a.ParentId from Attachment a WHERE parentId = :cOld.id and isDeleted = False LIMIT 50]) { system.debug ('********** ' + EachAttachment.Name ) ; Attachment aNew = EachAttachment.clone(false, false); aNew.ParentId = cNew.Id ; AttachmentsToAdd.add(aNew); } insert AttachmentsToAdd ; } }

 

Fra08Fra08
Hello, we are really close to the fantastic clone button but:
 failed to create ProductLine {errors:{fields:'OpportunityId', message:'Opportunity ID: id value of incorrect type: 06R0000004NQ9B', statusCode:'MALFORMED_ID', }, id:null, success:'false', }
someone knows what does it mean?
insanedukeposseinsanedukeposse

I can't see your original code, so can only extrapolate what is going on from the error message.

 

I believe that the opportunity object will always have id's starting with 006 (that's zero zero six). You seem to have an id of '06R' which I can only guess is a custom object. Therefore, I have to conclude that you are trying to stick the wrong Id into the opportunity ID foreign key. Just a guess...

 

ricardo12345ricardo12345

Hi Fra08,

 

I had the same fail when I once mixed 2 ID. BTW, I'm trying the same thing here and my code is as follows, but I'm getting "undefined" so not getting to the insert, since you are getting a DB message can you tell me the way?

 

try{

{!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")}



// ** EDIT THIS QUERY TO LIST THE FIELDS YOU WANT TO COPY **

var result = sforce.connection.query("Select o.Tipo_de_Cota_o_2__c, o.AccountId, o.Name, o.Id, o.StageName, o.RecordTypeId, o.CloseDate From Opportunity o WHERE o.Id = '{!Opportunity.Id}'");

var newOpp = result.getArray("records");


// Reset the Opp Id and reset fields to default values

newOpp[0].Id = '';
newOpp[0].Name = "{!Opportunity.Name} - Pedido";
newOpp[0].RecordTypeId = '012400000009YRRAA2';
newOpp[0].Cotacao__c = '{!Opportunity.Id}';


var saveResult = sforce.connection.create(newOpp);

if (saveResult[0].getBoolean("success")) {
newOpp[0].id = saveResult[0].id;
alert("Corpo do Pedido Gerado com sucesso");
}
else {
alert("Falha para gerar o pedido: " + saveResult[0]);
}


var result1 = sforce.connection.query("Select t.Bloqueio_c__c, t.C_digo_do_produto__c, t.C_digo_do_Status_do_tem__c, t.codigocondicaodepagamento__c, t.COFINS__c, t.Com_Lote__c, t.desccondicaodepagamento__c, t.Desconto_extra__c, t.Descontoda_categoria__c, t.Descri_o_do_Status_do_tem__c, t.Encargos_financeiros_2__c, t.Estoque__c, t.Fator_de_equalizacao__c, t.Flag_Minimo_e_Multiplo__c, t.Frete_de_compra_2__c, t.Frete_de_venda_2__c, t.ICMS_DA_Cliente__c, t.ICMS_GY_DA__c, t.IPI__c, t.ListPrice, t.Lote__c, t.Lote_automatico__c, t.M_ltiplo__c, t.Markup__c, t.Minimo__c, t.Observa_es__c, t.OpportunityId, t.PIS__c, t.Preco_Venda_Total__c, t.PrecoPadrao__c, t.precovenda__c, t.PricebookEntryId, t.Quantity, t.Saldo__c, t.Status_de_Bloqueio_do_Item__c, t.Teste_Picklist__c, t.TipoRegistro__c, t.TotalPrice, t.Unidade__c, t.UnitPrice from OpportunityLineItem t WHERE t.OpportunityId = '{!Opportunity.Id}'");

var newOppline = result1.getArray("records");


// Reset the Opp Id and reset fields to default values


var i=0;
for (i=0;i<=20;i++) {

newOppline[i].Id = '';
newOppline[i].OpportunityId = newOpp[0].id
newOppline[i].Quantity = 0;

var saveResult1 = sforce.connection.create(newOppLine);

if (saveResult1[i].getBoolean("success")) {
newOppLine[i].id = saveResult1[i].id;
alert("Linha do Pedido Gerada com sucesso");
}
else {
alert("Falha para gerar a linha do pedido: " + saveResult1[i]);
}


}

// Refresh the page to display the new oppportunity
window.location = newOpp[0].id;
}
catch (err) {
alert (err.description );
}

Fra08Fra08
Hello!
I finally found the solution, it is working perfectly, I hope this can help you:
try
{
//** <script type="text/javascript" src="/soap/ajax/14.0/connection.js"></script> **

{!requireScript("/soap/ajax/14.0/connection.js")}

// ** EDIT THIS QUERY TO LIST THE FIELDS YOU WANT TO COPY **
var result = sforce.connection.query("Select o.Type, o.StageName From Opportunity o WHERE o.Id = '{!Opportunity.Id}'");

var newOpp = result.getArray("records");

// Reset the Opp Id and reset fields to default values
newOpp[0].Id = '';
newOpp[0].Name = "Clone {!Opportunity.Name}";

// ** EDIT THESE FIELDS TO SET DEFAULT ANY VALUES **
newOpp[0].StageName = "Qualification";
newOpp[0].CloseDate = new Date(2099, 0, 1);

var saveResult = sforce.connection.create(newOpp);

if (saveResult[0].getBoolean("success"))
{
newOpp[0].id = saveResult[0].id;

//var sOportunity = newOpp[0].id.substring(0, newOpp[0].id.length - 3)


// duplicamos tambien los productos de la Opportunity original
var oppLineItemQuery = sforce.connection.query("select PricebookEntryId, Model__c, Operators__c, Months__c, Quantity, UnitPrice from OpportunityLineItem where OpportunityId = '{!Opportunity.Id}'");

oppLineItemList = oppLineItemQuery.getArray("records");
var examOrderItemArray = new Array();
for(var i = 0;i<oppLineItemList.length;i++)
{
oppLineItems = oppLineItemList[i];
var examOrderItem = new sforce.SObject("OpportunityLineItem");

examOrderItem.set("OpportunityId", newOpp[0].id);
//examOrderItem.set("PricebookEntryId", "01uR0000000sZ9IIAU");
examOrderItem.set("PricebookEntryId", oppLineItems.get("PricebookEntryId"));
examOrderItem.set("Model__c", oppLineItems.get("Model__c"));
examOrderItem.set("Operators__c", oppLineItems.get("Operators__c"));
examOrderItem.set("Months__c", oppLineItems.get("Months__c"));
examOrderItem.set("Quantity", oppLineItems.get("Quantity"));
examOrderItem.set("UnitPrice", oppLineItems.get("UnitPrice"));

examOrderItemArray.push(examOrderItem);
}

try {
var examOrderItemSaveResults = sforce.connection.create(examOrderItemArray);

for (var i=0; i<examOrderItemSaveResults.length; i++)
{
if (!examOrderItemSaveResults[i].getBoolean("success")) alert("failed to create ProductLine " + examOrderItemSaveResults[i]);
/*
{
alert("new ProductLine created with id " + examOrderItemSaveResults[i].id);
} else {
alert("failed to create ProductLine " + examOrderItemSaveResults[i]);
}
*/
}
}
catch(error)
{
sforce.debug.log(error.faultcode);
sforce.debug.log(error.faultstring);
}

} else {
alert("Failed to create clone: " + saveResult[0]);
}

// Refresh the page to display the new oppportunity
window.location = newOpp[0].id;
}
catch (err) {
sforce.debug.log(err.faultcode);
sforce.debug.log(err.faultstring);
}
ricardo12345ricardo12345

Thank you very much for your code. It has helped us to move forward. But we are still getting one fail msg, that follows bellow. Have you had this problem as well? We have already tryied the Opp ID with 18 digits and 15 digits but we are still getting that fail msg, but we know that the opp is been inserted. Thanks again.

 

"failed to create ProductLine {errors:{fields:'OpportunityId', message:'Campos obrigatórios ausentes: [OpportunityId]', statusCode:'REQUIRED_FIELD_MISSING', }, id:null, success:'false', }"

 

try{ 
//** <script type="text/javascript" src="/soap/ajax/14.0/connection.js"></script> ** 

{!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")} 

// ** EDIT THIS QUERY TO LIST THE FIELDS YOU WANT TO COPY ** 
var result = sforce.connection.query("Select o.Tipo_de_Cota_o_2__c, o.AccountId, o.Name, o.Id, o.StageName, o.RecordTypeId, o.CloseDate From Opportunity o WHERE o.Id = '{!Opportunity.Id}'"); 
var newOpp = result.getArray("records"); 


// Reset the Opp Id and reset fields to default values 
newOpp[0].Id = ''; 
newOpp[0].Name = "{!Opportunity.Name} - Pedido"; 
newOpp[0].RecordTypeId = '012400000009YRRAA2'; 
newOpp[0].Cotacao__c = '{!Opportunity.Id}'; 



var saveResult = sforce.connection.create(newOpp); 

if (saveResult[0].getBoolean("success")){ 
newOpp[0].id = saveResult[0].id; 
var sOportunity = newOpp[0].id.substring(0, newOpp[0].id.length - 3); 

alert ("ID Oportunidade " + newOpp[0].id + "ID - 3 >" + sOportunity); 

var oppLineItemQuery = sforce.connection.query("Select t.Id, t.Bloqueio_c__c, t.C_digo_do_produto__c, t.C_digo_do_Status_do_tem__c, t.codigocondicaodepagamento__c, t.COFINS__c, t.Com_Lote__c, t.desccondicaodepagamento__c, t.Desconto_extra__c, t.Descontoda_categoria__c, t.Descri_o_do_Status_do_tem__c, t.Flag_Minimo_e_Multiplo__c, t.IPI__c, t.Lote__c, t.Lote_automatico__c, t.Observa_es__c, t.OpportunityId, t.PIS__c, t.PrecoPadrao__c, t.precovenda__c, t.PricebookEntryId, t.Quantity, t.Saldo__c, t.Status_de_Bloqueio_do_Item__c, t.Teste_Picklist__c, t.Unidade__c, t.UnitPrice from OpportunityLineItem t WHERE t.OpportunityId = '{!Opportunity.Id}'"); 
oppLineItemList = oppLineItemQuery.getArray("records"); 
var examOrderItemArray = new Array(); 

for(var i = 0;i<oppLineItemList.length;i++){ 
oppLineItems = oppLineItemList[i]; 
var examOrderItem = new sforce.SObject("OpportunityLineItem"); 

examOrderItem.set("OpportunityId", sOportunity); 
examOrderItem.set("Bloqueio_c__c", oppLineItems.get("Bloqueio_c__c")); 
examOrderItem.set("C_digo_do_produto__c",oppLineItems.get("C_digo_do_produto__c")); 
examOrderItem.set("C_digo_do_Status_do_tem__c", oppLineItems.get("C_digo_do_Status_do_tem__c")); 
examOrderItem.set("codigocondicaodepagamento__c",oppLineItems.get("codigocondicaodepagamento__c")); 
examOrderItem.set("COFINS__c", oppLineItems.get("COFINS__c")); 
examOrderItem.set("Com_Lote__c", oppLineItems.get("Com_Lote__c")); 
examOrderItem.set("desccondicaodepagamento__c",oppLineItems.get("desccondicaodepagamento__c")); 
examOrderItem.set("Desconto_extra__c",oppLineItems.get("Desconto_extra__c")); 
examOrderItem.set("Descontoda_categoria__c", oppLineItems.get("Descontoda_categoria__c")); 
examOrderItem.set("Descri_o_do_Status_do_tem__c", oppLineItems.get("Descri_o_do_Status_do_tem__c")); 
// errado examOrderItem.set("Encargos_financeiros_2__c", oppLineItems.get("Encargos_financeiros_2__c")); 
// errado examOrderItem.set("Estoque__c", oppLineItems.get("Estoque__c")); 
// errado examOrderItem.set("Fator_de_equalizacao__c", oppLineItems.get("Fator_de_equalizacao__c")); 
examOrderItem.set("Flag_Minimo_e_Multiplo__c", oppLineItems.get("Flag_Minimo_e_Multiplo__c")); 
// errado examOrderItem.set("Frete_de_compra_2__c", oppLineItems.get("Frete_de_compra_2__c")); 
// errado examOrderItem.set("Frete_de_venda_2__c", oppLineItems.get("Frete_de_venda_2__c")); 
// errado examOrderItem.set("ICMS_DA_Cliente__c", oppLineItems.get("ICMS_DA_Cliente__c")); 
// errado examOrderItem.set("ICMS_GY_DA__c", oppLineItems.get("ICMS_GY_DA__c")); 
examOrderItem.set("IPI__c", oppLineItems.get("IPI__c")); 
//examOrderItem.set("ListPrice", oppLineItems.get("ListPrice")); 
examOrderItem.set("Lote__c", oppLineItems.get("Lote__c")); 
examOrderItem.set("Lote_automatico__c", oppLineItems.get("Lote_automatico__c")); 
// errado examOrderItem.set("M_ltiplo__c", oppLineItems.get("M_ltiplo__c")); 
// errado examOrderItem.set("Markup__c", oppLineItems.get("Markup__c")); 
// errado examOrderItem.set("Minimo__c",oppLineItems.get("Minimo__c")); 
examOrderItem.set("Observa_es__c", oppLineItems.get("Observa_es__c")); 
examOrderItem.set("OpportunityId", oppLineItems.get("Operators__c")); 
examOrderItem.set("PIS__c", oppLineItems.get("PIS__c")); 
// errado examOrderItem.set("Preco_Venda_Total__c", oppLineItems.get("Preco_Venda_Total__c")); 
examOrderItem.set("PrecoPadrao__c", oppLineItems.get("PrecoPadrao__c")); 
examOrderItem.set("precovenda__c", oppLineItems.get("precovenda__c")); 
examOrderItem.set("PricebookEntryId", oppLineItems.get("PricebookEntryId")); 
examOrderItem.set("Quantity",0); 
examOrderItem.set("Saldo__c",oppLineItems.get("Saldo__c")); 
examOrderItem.set("Status_de_Bloqueio_do_Item__c", oppLineItems.get("Status_de_Bloqueio_do_Item__c")); 
examOrderItem.set("Teste_Picklist__c", oppLineItems.get("Teste_Picklist__c")); 
//errado examOrderItem.set("TipoRegistro__c", oppLineItems.get("TipoRegistro__c")); 
//errado examOrderItem.set("TotalPrice", oppLineItems.get("TotalPrice")); 
examOrderItem.set("Unidade__c", oppLineItems.get("Unidade__c")); 
examOrderItem.set("UnitPrice",oppLineItems.get("UnitPrice")); 

examOrderItemArray.push(examOrderItem); 
} 

try { 
var examOrderItemSaveResults = sforce.connection.create(examOrderItemArray); 

}catch(error){ 
sforce.debug.log(error.faultcode); 
sforce.debug.log(error.faultstring); 
} 

for (var i=0; i<examOrderItemSaveResults.length; i++){ 
if (!examOrderItemSaveResults[i].getBoolean("success")){ 
alert("failed to create ProductLine " + examOrderItemSaveResults[i]); 
} 
} 


} else { 
alert("Failed to create clone: " + saveResult[0]); 
} 

// Refresh the page to display the new oppportunity 
window.location = newOpp[0].id; 
} catch (err) { 
sforce.debug.log(err.faultcode); 
sforce.debug.log(err.faultstring); 
}

Fra08Fra08
hello
your error message:
message:'Campos obrigatórios ausentes: [OpportunityId]', statusCode:'REQUIRED_FIELD_MISSING', }, id:null, success:'false', }"
let me think that you have a trigger active,  like an obstacle.. try to deactivate some triggers and check what happen... 
We had a similar error and we fix it deactivating a trigger...
JakesterJakester
You might be interested in a new app that we have just released on the AppExchange called PowerClone. It's capable of up to 99 copies of a record, allows you to define rules for how the copy works, and can also copy child objects. It's fully native code, so it runs fast and installs easily. Give it a try!
http://sites.force.com/appexchange/listingDetail?listingId=a0N30000001SRXAEA4
jmaskell123jmaskell123

Hi Thanks for the code works great.

 

one problem thought , how can i get it to add 365 days to the cloned opportuntie so we can use it as a renewal.

 

Thanks

 

Jake 

jmaskell123jmaskell123
;)
jmaskell123jmaskell123
")
Vegaln1Vegaln1

Hello bg_richard... Would it be possible for me to get a copy of all the opp clone changes, including the line items as well?

 

Regards,

max_overloadmax_overload

Having some problems, the error I am receiving is:

 

"invalid assignment left hand side"

 

I got past the undefined argument errors, here is my code:

 

try{

{!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")}

// use this select statement to pull the field data from old dp that you want in the new DP
var result = sforce.connection.query("Select dp.Product__c, dp.Related_ContactId__c, dp.Related_OpportunityId__c, dp.Corp_ID__c, dp.Client_received_a_live_demo__c, dp.Fusion_Demo_Complete_Date__c, dp.Fusion_Mode__c, dp.Is_using_a_dedicated_Fusion_seat__c, dp.Salesforce_Version__c, dp.SFDC_is_backed_up__c, dp.Which_objects_Fusion_to_Manage__c, dp.Sync_Status__c, dp.Sync_Start_Timestamp__c, dp.Sync_Complete_Timestamp__c, dp.Data_SpecialistId__c From Data_Project__c dp WHERE dp.Name = '{!Data_Project__c.Name}'");

var newDP = result.getArray("records");



// Reset the DP ID and reset fields to default values

newDP[0].{!Data_Project__c.Name} = '';


// ** EDIT THESE FIELDS TO SET DEFAULT ANY VALUES **
newDP[0].{!Data_Project__c.Pissed_Blissed_Score__c} = '';
newDP[0].{!Data_Project__c.Project_Summary__c} = "Test Value";

var saveResult = sforce.connection.create(newDP);

if (saveResult[0].getBoolean("success")) {
newDP[0].{!Data_Project__c.Name} = saveResult[0].{!Data_Project__c.Name};
alert("Data Project cloned without related line items");
}
else {
alert("Failed to create clone: " + saveResult[0]);
}

// Refresh the page to display the new data proj
window.location = newDP[0].{!Data_Project__c.Name};
}
catch (err) {
alert (err.description );
}

 

 

Should I be using the "ID" value for the lookup fields that are being selected above or should I select the actual values of those related fields?

 

Any help is very appreciated in advance!

 

EnthEnth

I have an unmanaged package using VisualForce for those that can't (or no longer want to) use S-Controls. It includes a method for Clone Opportunity and Clone Opportunity with Product Line Items. It requires knowledge of Apex to edit the class to set your defaults, and hence is no good installing into a production Org. You'll need to install it to your Sandbox, make the changes below, test it then promote it to your live org using Metadata publish or Change Sets.

 

Here's the link to the package:  Unmanaged Clone Opportunity Package  

 

Instructions are as follows:

1. Install the package to your sandbox

2. Edit the Apex Class  CloneOpportunity and look for all the TODO lines. The package will work for vanilla Orgs but if you want to set your own default values or ensure all your fields are copied you need to edit the code.

3. The package includes 2 custom buttons CloneOpportunity and Clone_With_Products, these both point to the same Visualforce page - if you want to have both you'll need to do some additional development or get some help (see below). For now, just make sure you add one to your opportunity page layout.

4.  You need to make sure your user profiles can access the Visualforce page "CloneOpportunity". This page doesn't render, it's just the hidden glue to link the Buttons to the Apex code.

5. Test!

6. Install your changes to your production instance. 

 

The package assumes you want to call the Clone With Products function out of the box. As mentioned above you can change this by editing the CloneOppButtonController apex class, there is a TODO comment telling you what to change

 

 

 If you need help customising this then please contact me, otherwise good luck! 

Message Edited by Enth on 03-07-2010 10:58 AM
Message Edited by Enth on 03-07-2010 01:50 PM
max_overloadmax_overload

Checking it out in a sandbox right now. Looking good so far!

 

Thanks for your efforts on a tool like this.

 

Reccomend everyone vote up this idea:

https://sites.secure.force.com/ideaexchange//apex/ideaView?c=09a30000000D9xt&id=08730000000BpUXAA0

 

 

Thnx.

MaryaMarya

Thanks so much for posting this code.  It works great and exactly what I needed.  However, I'm having trouble customizing - any help would be greatly appreciated.

 

There are some fields in the new opportunity, that need to be populated with data from a different field in the old opportunity.  

 

For example, I need for the  new opportunity "Close Date" to be equal to the old opportunity "Contract End Date". I did this before with: 

newOpp[0].CloseDate = new Date("{!Opportunity.ContractEndDate__c}");  

 

And, I need the new opportunity "Name" to include fields from the old opportunty.  I previously accomplished this with the following code:

 

newOpp[0].Name = "{!Opportunity.ContractEndDate__c} - {!Opportunity.Product_Type__c} ({!Opportunity.End_User_Company__c})";

 

I can't seem to figure out the proper syntax to accomplish this in this "Clone with Products" code.  (I'm getting errors such as (Error: Compile Error: line 30:25 no viable alternative at character '"' at line 30 column 25")

 

EnthEnth

Hi Marya,

 

Difficult to debug your issues without being able to see the changes you've made in context. It may be as simple as not changing from double to single quotes. However, here's how I'd change the code to do as you describe, compare the difference:

 

CloneOpportunity Class: cloneOpp method

 

In the SELECT SOQL statement (Lines 20-23) add your custom fields, changes in bold:

 

// TODO: Amend this method to set the fields you wish to bring across // if they're not in the SELECT they won't be copied Opportunity origOpp = [SELECT Name, CloseDate, StageName, Amount, AccountId, CampaignId, Type, Description

,ContractEndDate__c, Product_Type__c, End_User_Company__c

FROM Opportunity WHERE Id = :oppId][0];

 

 At line 30 & 31, replace my Name and CloseDate fields with your own settings:

 

 

cloneOpp.Name = origOpp.Contract_End_Date__c + '-' + origOpp.Product_Type__c + ' (' + origOpp.End_User_Company__c + ')';

cloneOpp.CloseDate = origOpp.Contract_End_Date__c;

 

Of course, the old way using s-controls will still work with Spring 10, so if you prefer stick to that. It's only new SFDC customers that have to now use the Visualforce/Apex solution.

 

 

 

 

MaryaMarya

Thanks so much.  Working like a charm.  :smileyvery-happy:

 

One last question - for the opportunity name, where I'm displaying the close date, is there a way to format the date so it's MM/DD/YY?  Currently, it displays as YYYY-MM-DD HH:MM:SS, which is overkill for an oppurtunity name.

 

 

cloneOpp.Name = origOpp.ContractEndDate__c + origOpp.Product_Type__c + ' (' + origOpp.End_User_Company__c + ')';

 

 

 

MaryaMarya

Nevermind on the date thing.  It may not be the prettiest thing, but I got it to work:

 

cloneOpp.Name = origOpp.ContractEndDate__c.month() + '/' + origOpp.ContractEndDate__c.day() + '/' + origOpp.ContractEndDate__c.year() + ' ' + origOpp.Product_Type__c + ' (' + origOpp.End_User_Company__c + ')';

 

 

 

EnthEnth

We've now released a free package on the AppExchange that takes away the need to understand either S-Controls or Apex. It's a simple to use tool for Admins that allows them to set up default values, or blank fields for a limited set of standard salesforce objects. The free package currently supports: Account, Case, Contact, Event, Opportunity, OpportunityLineItem, Product and Task objects.

Unfortunately custom objects are not supported but custom fields on the above are.

Here's the link to the AppExchange listing:  http://sites.force.com/appexchange/listingDetail?listingId=a0N30000003IxcZEAS

larryg23larryg23

I am getting an undefined error every time I try to modify this.  Here is my code (I kept it simple fro testing, I will be adding more once I know what the problem is):

 

// Copyright 2008 BrightGen Ltd - All Rights Reserved

try{

   {!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")}

 

   // ** EDIT THIS QUERY TO LIST THE FIELDS YOU WANT TO COPY **

   var result = sforce.connection.query("Select o.Account, o.StageName, o.Name, o.CloseDate From Opportunity o WHERE o.Id = '{!Opportunity.Id}'");

   var newOpp = result.getArray("records");

 

   // Reset the Opp Id and reset fields to default values

   newOpp[0].Id = '';
   newOpp[0].Name = "Clone {!Opportunity.Name}";

   // ** EDIT THESE FIELDS TO SET DEFAULT ANY VALUES **
   newOpp[0].StageName = "In Applications Engineering";
   newOpp[0].CloseDate = new Date(2099, 0, 1);
 

   var saveResult = sforce.connection.create(newOpp);

   if (saveResult[0].getBoolean("success")) {
      newOpp[0].id = saveResult[0].id;
      alert("Opportunity cloned without line items");
   }
   else {
      alert("Failed to create clone: " + saveResult[0]);
   }

   // Refresh the page to display the new oppportunity
   window.location = newOpp[0].id;
}
catch (err) {
   alert (err.description );
}

 

If anyone can help I would really appreciate it.

 

Thanks!!

EnthEnth

The javascript undefined error is basically it's way of saying you're trying to reference something that doesn't exist or is null.  This would occur if you try and reference a non-existant attribute (try adding o.Id to your SELECT statement first), or because no data is returned by the SELECT statement.

 

To avoid wasting time you should also use debug statements to track between which points the error is occuring.  Simply add something like:

 

alert('10');
... so code here
alert('20');
.. more code 
// etc

 is easiest.

 

Finally, frustration debugging this (I wrote the original post while at BrightGen) and SFDC dropping s-Controls for new Orgs, is why I redeveloped it as a free Managed Apex Package (see previous item in thread) which works on Professional Edition too.  For all that you're trying to do it should meet your needs.

 

Good luck.

 

cfederspiel@ic-2000.comcfederspiel@ic-2000.com

@bg_richard - Could you please email me the full code that supports opp line items? Cheers! Sorry - you probably need this cfederspiel@ic-2000.com

StenderStender

How would this be different if I wanted the custom clone to perform ALL the standard clone functions with the exception that the New Opp Owner will be the same as the original, rather than being the current user?

 

Thanks in advance!

EnthEnth

Hi,

 

I've subsequently developed an Apex package to replace the Javascript solution. I no longer publish the Javascript versin but you can install EnthClone from the AppExchange for free, and this includes the cloning of line items. It's also much easier to use than the Javascript version!

 

Richard

ezlimezlim

Exactly what I was looking for.  Thanks!

cand_01cand_01

Thank you for this code.  Can you please send me the code for cloning with the Opportunity Line Items?  

EnthEnth

We have a free managed package on the AppExchange that does this. We no longer provide the Apex source code now for legal reasons. 

Tom NicolettiTom Nicoletti
I want a clone button in de Lineitems(Opportunity Product) details page. So I only want to clone the lineitem. How can I achieve this?