Dynamics CRM - Set default unit on product line

24 August 2010

When picking a product on a CRM entity like quote product or order product the user also has to pick a unit of measure for the product. Wouldn't it be useful if CRM filled in the unit of measure field for the user based on the default unit for the product? Of course it would, but it doesn't do this out of the box.

My solution for this involves using a generic handler to get the default unit for a specific product and some JavaScript to call the handler asynchronously.

The JavaScript that is placed in the onchange event of the productid field looks like this:

var lookupItem = new Array;
// Get the lookup for the primarycontactid attribute on the account form.
lookupItem = crmForm.all.productid.DataValue;
if (lookupItem[0] != null)
{
  InitXmlHttp();
  xmlhttp.onreadystatechange= XMLHttpRequestCompleted;
  xmlhttp.open("GET", "../../../TSG.CRM.GenericHandlers/QuoteProductSetDefaultUnits.ashx?
id="+lookupItem[0].id , true );
  xmlhttp.send(null);
}
 
function InitXmlHttp() {
  // Attempt to initialize xmlhttp object
    try
    {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e)
    {
        // Try to use different activex object
        try
        {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (E)
        {
            xmlhttp = false;
        }
    }
    
    // If not initialized, create XMLHttpRequest object
    if (!xmlhttp && typeof XMLHttpRequest!='undefined')
      {     
            xmlhttp = new XMLHttpRequest();
      }    
}
 
function XMLHttpRequestCompleted()
{
        if (xmlhttp.readyState==4)
    {
        try
        {
           var lookupData = new Array();
           var lookupItem = new Object();
           var response = new Array();
           response = xmlhttp.responseText.split(',');
                             
           lookupItem.id = response[0];
           lookupItem.typename = response[1];
           lookupItem.name = response[2];
           lookupData [0] = lookupItem;
           crmForm.all.uomid.DataValue = lookupData ;
         }
        catch (e)
        {
           alert('Something has gone wrong!');
        }
    }
}
 

The generic handler code looks like this:

using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Text;
using CRM.GenericHandlers.CRMService;
using System.Configuration;
 
namespace CRM.GenericHandlers
{
    /// <summary>
    /// Summary description for $codebehindclassname$
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class QuoteProductSetDefaultUnits : IHttpHandler
    {
 
        public void ProcessRequest(HttpContext context)
        {
            string productid = context.Request.QueryString["id"];
 
            try
            {
                CrmAuthenticationToken token = new CrmAuthenticationToken();
                token.AuthenticationType = 0; 
                //add an <appsetting> to web.config for your organisation name
                token.OrganizationName = ConfigurationManager.AppSettings["OrgName"].ToString();
 
                CrmService service = new CrmService();
                service.CrmAuthenticationTokenValue = token;
                service.Credentials = System.Net.CredentialCache.DefaultCredentials;
 
                //create the ColumnSet that indicates properties to be retrieved
                ColumnSet productCols = new ColumnSet();
                ColumnSet uomCols = new ColumnSet();
               
                //set the properties of the ColumnSet
                productCols.Attributes = new string[] { "productid", "defaultuomid" };
                uomCols.Attributes = new string[] { "uomid", "name" };
                
                //retrieve quote
                Guid ProductID = new Guid(productid);
                product product = (product)service.Retrieve("product", ProductID, productCols);
 
                Guid uomID = product.defaultuomid.Value;
                uom productUom = (uom)service.Retrieve("uom", uomID, uomCols);
 
                string productUomName = productUom.name;
 
                string[] arrLookupItem = new string[3];
                arrLookupItem[0] = uomID.ToString();
                arrLookupItem[1] = "uom";
                arrLookupItem[2] = productUomName;
 
               context.Response.Write("{"+uomID+"},uom,"+productUomName); 
 
            }
            catch (SoapException ex)
            {
                context.Response.Write(ex.Message);
            }
 
        }
 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}