Duplicate Record Button using Jscript in Microsoft CRM 2011

As detailed here, Rollup Pack 8 for Microsoft CRM 2011 gave us a couple of shiny new jscript toys:

Xrm.Utility.openEntityForm(name,id,parameters)

and

Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)

In this post I will show you how to add a “Duplicate Record” button to a CRM form, using the new openEntityForm function.

First, lets add the button.  Download Erik Pool’s ribbon editor from CodePlex.  If you are still editing ribbon xml manually and not using this tool then you are mad.   Run the tool, connect to your CRM organisation and open the ribbon you wish to edit.  I am going to add my button to the Case form, adding to the last Group of buttons on the right hand side.  I click in that Button Group and then click New Button and name my button:

image

My button appears small by default so I change the Template Alias to Large.  I need an icon for my button and the one I see on the “Copy Selected” button looks good so I can click on that button and copy and paste the image properties from that button over to my new button:

image

I tidy the Label and Tooltip and then click on the Action tab and enter the name of my jscript library and function, which we will create next:

image

Finally, I save the change and then check my button appears in CRM:

image

I want to demonstrate copying a range of data types so I add a few custom fields to my Case form:

image

Ok, now we can write the jscript function.  There are 3 steps to this:

1. Collect field values from the source record

2. Define the values you want to populate into the destination record

3. Pop the form, passing across the values to be populated

I’ve pasted just the first part below.  Most of this is just me using CRM’s getValue() functon, but you will see I do some null value checks on the lookup fields (to avoid errors) and I also need to extract multiple values from each lookup field.  You will also note for the date field I call another function so that the value returned by the getValue() call gets converted into the MM/DD/YYYY format that the next step requires:

function DuplicateCase() {
    //get values from the Form
    var CaseId = Xrm.Page.data.entity.getId();
    var CaseTitle = Xrm.Page.data.entity.attributes.get("title").getValue();
    if (Xrm.Page.data.entity.attributes.get("customerid").getValue() != null) {
        var CustomerId = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].id;
        var CustomerName = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].name;
        var CustomerType = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].entityType;
    }
    if (Xrm.Page.data.entity.attributes.get("subjectid").getValue() != null) {
        var SubjectId = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].id;
        var SubjectName = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].name;
    }
    var CaseOriginCode = Xrm.Page.data.entity.attributes.get("caseorigincode").getValue();
    var CaseTypeCode = Xrm.Page.data.entity.attributes.get("casetypecode").getValue();
    var CaseDate = FormatDate("new_dateofincident");  // wants "MM/DD/YYYY" (this might be environment specific though)
    var CaseUrgent = Xrm.Page.data.entity.attributes.get("new_urgent").getValue();
    var CaseClaimAmount = Xrm.Page.data.entity.attributes.get("new_claimamount").getValue();
    if (Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue() != null) {
        var CurrencyId = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].id;
        var CurrencyName = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].name;
    }
    if (Xrm.Page.data.entity.attributes.get("ownerid").getValue() != null) {
        var OwnerId = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].id;
        var OwnerName = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].name;
        var OwnerType = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].entityType;
    }
    var CaseDescription = Xrm.Page.data.entity.attributes.get("description").getValue();

Here’s the second section of the function, here I am basically placing each of the values I extracted during step 1 into a parameter object (testing for and excluding null values as I go):

 

    //define default values for new Incident record
    var parameters = {};
    if (CaseTitle != null) {
        parameters["title"] = CaseTitle + " - COPY";
    }
    if (CustomerId != null && CustomerName != null) {
        parameters["customerid"] = CustomerId;
        parameters["customeridname"] = CustomerName;
        parameters["customeridtype"] = CustomerType;
    }
    if (SubjectId != null && SubjectName != null) {
        parameters["subjectid"] = SubjectId;
        parameters["subjectidname"] = SubjectName;
    }
    if (CaseOriginCode != null) {
        parameters["caseorigincode"] = CaseOriginCode;
    }
    if (CaseTypeCode != null) {
        parameters["casetypecode"] = CaseTypeCode;
    }
    if (CaseDate != null) {
        parameters["new_dateofincident"] = CaseDate;
    }
    if (CaseUrgent != null) {
        parameters["new_urgent"] = CaseUrgent;
    }
    if (CaseClaimAmount != null) {
        parameters["new_claimamount"] = CaseClaimAmount;
    }
    if (CurrencyId != null && CurrencyName != null) {
        parameters["transactioncurrencyid"] = CurrencyId;
        parameters["transactioncurrencyidname"] = CurrencyName;
    }
    if (OwnerId != null && OwnerName != null) {
        parameters["ownerid"] = OwnerId;
        parameters["owneridname"] = OwnerName;
        parameters["owneridtype"] = OwnerType;
    }
    if (CaseDescription != null) {
        parameters["description"] = CaseDescription;
    }
    if (CaseId != null && CaseTitle != null) {
        parameters["new_parentcase"] = CaseId;
        parameters["new_parentcasename"] = CaseTitle;
    }

And the last bit is simply:

    //pop incident form with default values
    Xrm.Utility.openEntityForm("incident", null, parameters);
}

Here’s how it looks in action.  Here’s my source record:

image

And here’s what pops up when I click the button:

image

To use this yourself in your unique scenarios you will obviously need to edit the getValue() and parameters lines to match your fields.  I’ve covered off the main data types and added a little bit of robustness to help guide you on this.   The openEntityForm utility certainly helps out here.

Here’s the jscript function in full and the missing FormatDate function:

function DuplicateCase() {
    //get values from the Form
    var CaseId = Xrm.Page.data.entity.getId();
    var CaseTitle = Xrm.Page.data.entity.attributes.get("title").getValue();
    if (Xrm.Page.data.entity.attributes.get("customerid").getValue() != null) {
        var CustomerId = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].id;
        var CustomerName = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].name;
        var CustomerType = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].entityType;
    }
    if (Xrm.Page.data.entity.attributes.get("subjectid").getValue() != null) {
        var SubjectId = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].id;
        var SubjectName = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].name;
    }
    var CaseOriginCode = Xrm.Page.data.entity.attributes.get("caseorigincode").getValue();
    var CaseTypeCode = Xrm.Page.data.entity.attributes.get("casetypecode").getValue();
    var CaseDate = FormatDate("new_dateofincident");  // wants "MM/DD/YYYY" (this might be environment specific though)
    var CaseUrgent = Xrm.Page.data.entity.attributes.get("new_urgent").getValue();
    var CaseClaimAmount = Xrm.Page.data.entity.attributes.get("new_claimamount").getValue();
    if (Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue() != null) {
        var CurrencyId = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].id;
        var CurrencyName = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].name;
    }
    if (Xrm.Page.data.entity.attributes.get("ownerid").getValue() != null) {
        var OwnerId = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].id;
        var OwnerName = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].name;
        var OwnerType = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].entityType;
    }
    var CaseDescription = Xrm.Page.data.entity.attributes.get("description").getValue();

    //define default values for new Incident record
    var parameters = {};
    if (CaseTitle != null) {
        parameters["title"] = CaseTitle + " - COPY";
    }
    if (CustomerId != null && CustomerName != null) {
        parameters["customerid"] = CustomerId;
        parameters["customeridname"] = CustomerName;
        parameters["customeridtype"] = CustomerType;
    }
    if (SubjectId != null && SubjectName != null) {
        parameters["subjectid"] = SubjectId;
        parameters["subjectidname"] = SubjectName;
    }
    if (CaseOriginCode != null) {
        parameters["caseorigincode"] = CaseOriginCode;
    }
    if (CaseTypeCode != null) {
        parameters["casetypecode"] = CaseTypeCode;
    }
    if (CaseDate != null) {
        parameters["new_dateofincident"] = CaseDate;
    }
    if (CaseUrgent != null) {
        parameters["new_urgent"] = CaseUrgent;
    }
    if (CaseClaimAmount != null) {
        parameters["new_claimamount"] = CaseClaimAmount;
    }
    if (CurrencyId != null && CurrencyName != null) {
        parameters["transactioncurrencyid"] = CurrencyId;
        parameters["transactioncurrencyidname"] = CurrencyName;
    }
    if (OwnerId != null && OwnerName != null) {
        parameters["ownerid"] = OwnerId;
        parameters["owneridname"] = OwnerName;
        parameters["owneridtype"] = OwnerType;
    }
    if (CaseDescription != null) {
        parameters["description"] = CaseDescription;
    }
    if (CaseId != null && CaseTitle != null) {
        parameters["new_parentcase"] = CaseId;
        parameters["new_parentcasename"] = CaseTitle;
    }

    //pop incident form with default values
    Xrm.Utility.openEntityForm("incident", null, parameters);
}

// This function takes the fieldname of a date field as input and returns the value of that field in MM/DD/YYYY format
// Note: the day, month and year variables are numbers
function FormatDate(fieldname) {
    var d = Xrm.Page.data.entity.attributes.get(fieldname).getValue();  
    if (d != null) {
        var curr_date = d.getDate();
        var curr_month = d.getMonth();
        curr_month++;  // getMonth() considers Jan month 0, need to add 1
        var curr_year = d.getFullYear();
        return curr_month + "/" + curr_date + "/" + curr_year;
    }
    else return null;
}

13 thoughts on “Duplicate Record Button using Jscript in Microsoft CRM 2011

  1. Pingback: CRM 2011 Jscripts… « Roman's Blog

  2. matt

    Great post…very useful. I do have a question about Opening Entity records using Xrm.Utility.openEntityForm. We have a scenario where we are calling a NEW form from a Web Resource in a modal window. Upon closing the window we would like to refresh teh parent. This seems fairly straight forward when running in IE; however, while running in Outlook client we are unable to refresh and receive an error. Do you know how to open and Entity Form in Outlook client and allow for refresh of calling parent?

    Thanks
    Matt

    Reply
  3. Nick

    I literally did this the other day for a customer. Is there any issue with forms with lots of fields? i.e. URL lengths becoming an issue? I decided not to risk it and went with another option.

    Reply
  4. puneet joshi

    Gareth,

    I have a business requirement where I have to copy record from Entity A to Entity B on Click of a Ribbon Button.

    On Entity A’s Form, i have created a Ribbon button called “Copy Record”, Because i was not able to trigger Plug-in from Ribbon button, i have used a hidden Boolean field (Yes/No) in the Entity A’s Form and on click on that Ribbon Button i am updating the Boolean field’s Value from NO to Yes. Then i am trying to trigger a plug-in which will create a record in the Update Message of Entity A. I Could not figure out where and why it is failing. I have a deadline so i was looking into other options, i visited your post and seems like it can help.

    I could have used WF’s to do it but the only challenge is I can copy the Option Sets using Work Flow. Other than that everything is getting copy over. I am sure you have see this post ages back. http://blogs.msdn.com/b/crm/archive/2008/06/13/use-workflow-to-configure-business-data-auditing-in-microsoft-dynamics-crm-4-0.aspx

    Please direct me how to leverage your above mentioned code to copy record from one entity to another. Entity B’s fields are same as Entity A (Similar DataType, Similar Structure).
    Also i have 100+ record in Entity A’s form to copy over to Entity B. Will it possible to copy so many fields.

    Your help will be much appreciated.

    Thanks.

    Reply
  5. Daniel Critchley

    Hope it’s ok that I took your code and restructured it to be simpler to use…

    function addParam(p, att, type)
    {
    if (Xrm.Page.getAttribute(att) != null && Xrm.Page.getAttribute(att).getValue() != null)
    {
    var attV = Xrm.Page.getAttribute(att).getValue(); //get value
    switch (type)
    {
    case ‘lookup’:
    p[att] = attV[0].id;
    p[att + “name”] = attV[0].name;
    break;
    case ‘customer’:
    case ‘owner’:
    p[att] = attV[0].id;
    p[att + “name”] = attV[0].name;
    p[att + “type”] = attV[0].entityType;
    break;
    case ‘date’:
    // This takes the fieldname of a date field as input and
    // returns the value of that field in MM/DD/YYYY format
    // Note: the day, month and year variables are numbers
    var curr_date = attV.getDate();
    var curr_month = attV.getMonth();
    curr_month++; // getMonth() considers Jan month 0, need to add 1
    var curr_year = attV.getFullYear();
    p[att] = curr_month + “/” + curr_date + “/” + curr_year;
    break;
    default:
    p[att] = attV;
    break;
    }
    }
    return p; //return parameters array
    }

    function DuplicateThisRecord()
    {
    //declare and add to a params array
    var p = {};
    p = addParam(p,”new_activitytitle”,null);
    p = addParam(p,”statuscode”,null);
    p = addParam(p,”new_activitytype”,null);
    p = addParam(p,”new_descriptionnotes”,null);
    p = addParam(p,”new_workrequiredtype”,null);
    p = addParam(p,”location”,null);
    p = addParam(p,”new_requestedby”,”lookup”);
    p = addParam(p,”new_crmopscasereference”,null);
    p = addParam(p,”scheduledstart”,”date”);
    p = addParam(p,”scheduledend”,”date”);
    p = addParam(p,”isalldayevent”,null);
    p = addParam(p,”scheduleddurationminutes”,null);
    p = addParam(p,”new_includesoutofhourswork”,null);
    p = addParam(p,”new_noofdays”,null);
    p = addParam(p,”new_timeutilisation”,null);
    p = addParam(p,”ownerid”,”owner”);
    //regarding – unable to set regarding lookups
    //resources – unable to set partylist types

    var s = “Duplicating record…/r/n”;
    s += “/r/n”;
    s += “You will need to set the following fields manually:/r/n”;
    s += ” – Regarding/r/n”;
    s += ” – Resources/r/n”;
    alert(s);

    //pop incident form with default values
    Xrm.Utility.openEntityForm(“serviceappointment”, null, p);
    }

    Reply
  6. Stephanie Smith

    This is a great solution. I would like to use this on the Quote entity. How do I gather the information regarding the Quote Products so I can copy that also?

    Reply
  7. Julz

    Hi,
    I have implemented this script at a client but the issue I have is that unless the Case has been saved before pressing the “copy” button it will not bring across the “Parent Case” data. I can see why this is as the record doesn’t exist as of yet.
    I tried to add Xrm.Page.data.entity.save(); at the beginning of the script, but it doesn’t work.
    Any idea on how I can make this button function as a “Save and Copy” rather than a “Copy”.

    Thanks!

    Reply
  8. Pingback: Adding Activate Buttons to Microsoft CRM Activity Ribbons | Roman's Blog

  9. Silla

    Hi Gareth, Great article.

    I am trying to achieve something similar but its the email entity form with a button that opens another activity entity. I keep getting a blank window with only the ribbon, using your example i am only passing a subject field is it necessary to pass all the other form fields?? My script is as follows. Any comment will be highly appreciated. Warm Regards

    function ReplySMS () {

    var EmailId = Xrm.Page.data.entity.getId();
    var EmailSubject = Xrm.Page.data.entity.attributes.get(“subject”).getValue();

    var parameters = {};
    if(EmailSubject != null) {
    parameters [“subject”] = EmailSubject;

    }
    if (EmailId != null && EmailSubject !=null){
    parameters[“do_MobilePhone”] = EmailSubject;

    }

    Xrm.Utility.openEntityForm(“do_sms”,null,parameters)

    }

    Reply

Leave a comment