Tuesday, September 30, 2014

Qualify Leads Without Creating An Opportunity Via A SOAP Request

Back in CRM 2011 when you qualified a Lead the user was presented with a system dialog that allowed them to choose which entities were to be created (Account, Contact, and/or Opportunity). Much to many people's dismay in CRM 2013 the process had been streamlined so that it creates an Account, a Contact, and Opportunity automatically, but in many cases the Opportunity isn't needed or wanted. Fellow MVP Gus Gonzalez wrote a nice blog post on dealing with the unwanted Opportunity by using an extra field and a workflow. Another alternative is to execute the 'QualifyLead' SOAP request using some JavaScript from a ribbon button and just telling it not to create the Opportunity at all.

If you haven’t downloaded and installed Scott Durrow's Ribbon Workbench solution do that now.

Next you’ll need to create a solution that contains all the items we’ll need so that Ribbon Workbench can do its thing. Add the existing Lead entity, if prompted you won’t need to add the dependent components. If you want your button to have images associated with it, add them at this time. For this example we'll just re-use the system images. Finally add a new JavaScript web resource file, we’ll worry about the contents in just a second.


In the JavaScript web resource add the following code:

function QualifyLead() {
    var request = [];
    request.push(" <s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">");
    request.push("   <s:Body>");
    request.push("     <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">");
    request.push("       <request i:type=\"b:QualifyLeadRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">");
    request.push("         <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">");
    request.push("           <a:KeyValuePairOfstringanyType>");
    request.push("             <c:key>LeadId</c:key>");
    request.push("             <c:value i:type=\"a:EntityReference\">");
    request.push("               <a:Id>" + Xrm.Page.data.entity.getId() + "</a:Id>");
    request.push("               <a:LogicalName>lead</a:LogicalName>");
    request.push("               <a:Name i:nil=\"true\" />");
    request.push("             </c:value>");
    request.push("           </a:KeyValuePairOfstringanyType>");
    request.push("           <a:KeyValuePairOfstringanyType>");
    request.push("             <c:key>CreateAccount</c:key>");
    request.push("             <c:value i:type=\"d:boolean\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">true</c:value>");
    request.push("           </a:KeyValuePairOfstringanyType>");
    request.push("           <a:KeyValuePairOfstringanyType>");
    request.push("             <c:key>CreateContact</c:key>");
    request.push("             <c:value i:type=\"d:boolean\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">true</c:value>");
    request.push("           </a:KeyValuePairOfstringanyType>");
    request.push("           <a:KeyValuePairOfstringanyType>");
    request.push("             <c:key>CreateOpportunity</c:key>");
    request.push("             <c:value i:type=\"d:boolean\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">false</c:value>");
    request.push("           </a:KeyValuePairOfstringanyType>");
    request.push("           <a:KeyValuePairOfstringanyType>");
    request.push("             <c:key>Status</c:key>");
    request.push("             <c:value i:type=\"a:OptionSetValue\">");
    request.push("               <a:Value>3</a:Value>"); //Qualified
    request.push("             </c:value>");
    request.push("           </a:KeyValuePairOfstringanyType>");
    request.push("         </a:Parameters>");
    request.push("         <a:RequestId i:nil=\"true\" />");
    request.push("         <a:RequestName>QualifyLead</a:RequestName>");
    request.push("       </request>");
    request.push("     </Execute>");
    request.push("   </s:Body>");
    request.push(" </s:Envelope>");

    var serverUrl = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/Organization.svc/web";
    var req = new XMLHttpRequest();
    req.open("POST", serverUrl, false);
    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    req.onreadystatechange = function () {
        if (req.readyState == 4) {
            if (req.status == 200) {
                var response = req.responseXML;
                var id = $(response).children(":first").children(":first").children(":first").children(":first").children("a\\:Results").children("a\\:KeyValuePairOfstringanyType").children("c\\:value").children(":first").children("a\\:Id").text();

                Xrm.Utility.openEntityForm("account", id);

In the JavaScript we are executing the same SOAP request that the system uses in order to qualify a Lead. In our case we are setting the "CreateOpportunity" option to false so it doesn't generate the record. In the response XML the ids of the resulting Account and Contact are returned so I included a little extra code to find the new Account id and open the record.

Now head over to Settings –> Solutions and open the Ribbon Workbench solution. You should be prompted to choose a solution to work with, use the solution you just created.

Once open I'm going to hide the existing Qualify buttons just because in this example we'll say that the organization simply just doesn't use Opportunities so we won't ever have a need to use the out of the box buttons. This is easily accomplished by right-clicking on the buttons and choosing the Hide Button option.


Next add a new button by dragging a button from the toolbox up to the ribbon.


We are going to make it look and feel like the out of the box button so click on one of the hidden buttons and check out the properties, copy the text and images locations into the same spots on your custom button making the appropriate changes to remove references to the Opportunity we aren't creating. I'd also at this time give the button a more meaningful value for the id field.


Another thing we want to do it have the custom button appear at the same times the out of the box button would. We don't want it to show up before a new Lead has been saved or when the current user doesn't have the proper permissions, etc... So in order to re-use what Microsoft has put in place, right-click on the hidden button and select Customize Command. After doing this you will see a number Display and Enable rules be created.


So now to get a button to do something when clicked we'll need to create a command. So right click on Commands and select Add New. Find and rename the new command to something meaningful. Next select the lookup by Actions and in the resulting pop-up select Add and then JavaScript Function Action. From the resulting screen use the lookup by Library to choose the JavaScript web resource you added to the solution and then enter the FunctionName from the script (the example uses QualifyLead).


In the same area under Display Rules, select the lookup and add all the existing items as these were the ones the system uses to control access to the button.


Do the same for the Enable Rules.


Almost done, now we just need to tie the command to the button. So get back to your button and select the new command from the list.


At this point before committing the changes select the Xml tab and hit the little refresh icon. This will show all the xml that this wonderful tool just generated for you. You'll want to then check the Messages tab as it will contain any warnings or errors. You'll want to resolve any errors displayed before publishing.


When you are ready use the Publish button at the top of the page to deploy your changes, it can take a little while so be patient.

Once completed you'll be able to go to a Lead and use the new Qualify button to create only an Account and Contact and have the new Account record be opened automatically.