25/5/07

Autonumeración "a la carta" en CRM

Todos hemos visto cómo Microsoft CRM genera códigos automáticos para unos pocos tipos de registros: Contratos, Ofertas, Pedidos, Facturas y artículos de la Knowledge Base. ¿Qué podemos hacer si necesitamos que, además de estas entidades, alguna otra se autonumere también? Pues recurrir a la personalización del formulario correspondiente haciendo que llame a un pequeño servicio que programaremos en el servidor.

Empezaremos por programar el servicio de autonumeración. Abrimos Visual Studio y generamos un proyecto web sobre la misma carpeta en la que tenemos el servidor de CRM. En este caso, la he llamado autonum.



Para que nuestro proyecto web conecte con el servidor de CRM, sólo tenemos que añadir una referencia Web a su Web service, que como sabéis está en

http://maquina:puerto/MSCRMServices/2006/crmservice.asmx


Le damos un nombre apropiado a la referencia, por ejemplo CrmSdk.



Ahora, creamos un nuevo WebForm y le damos el nombre default.aspx Esta será la página que nos proporcionará los números correlativos para nuestra entidad. Aquí tenéis el código:


void Page_Load(object sender, System.EventArgs e){
string entidad = Request["e"];
string campo = Request["c"];
string prefijo = Request["p"];
string numCars = Request["n"];
string formato = "{0}{1:D" + numCars + "}";
string anterior = UltimoCodigo(entidad, campo);
string parteNumerica = anterior.Substring(prefijo.Length);
int num = 1 + Int32.Parse(parteNumerica);
Response.Write(String.Format(formato, prefijo, num));
}

string UltimoCodigo(string entidad, string campo) {
string fetch = @"<fetch count='1' mapping='logical'>
<entity name='{0}'>
<order attribute='createdon' descending='true'/>
<attribute name='{1}'/>
</entity>
</fetch>";
fetch = String.Format(fetch, entidad, campo);
CrmService crm = new CrmService();
crm.Credentials = System.Net.CredentialCache.DefaultCredentials;
string res = crm.Fetch(fetch);
XmlDocument dom = new XmlDocument();
dom.LoadXml(res);
XmlNode nodoCuenta = dom.SelectSingleNode("//" + campo);
if (nodoCuenta != null)
return nodoCuenta.FirstChild.Value;
else
return "?";
}



Como véis, lo único que hace es lanzar una consulta FetchXml que busca la última entidad creada (ordenando por el campo createdon) y extrae su código, que puede ser cualquier atributo que escojamos. En el ejemplo, la entidad es account y el campo accountnumber.

Ahora tenemos que personalizar el evento OnLoad de la entidad para que, al cargarse un nuevo formulario, se conecte a nuestra página en el servidor y rellene su valor en el campo que hayamos escogido. Vamos a Configuración - Personalización y escogemos la entidad Cuenta. Luego, escogemos su formulario y abrimos sus propiedades:




El código Javascript utiliza una conexión al estilo AJAX con el objeto XmlHttp. Como la llamada es asíncrona, no bloqueará el formulario para la introducción de otros datos. Aquí tenéis el código:

if (crmForm.FormType != 1)
return;
var entidad = "account";
var campo = "accountnumber";
var prefijo = "A-";
var numCars = 4;
var xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
var params = "?e=" + entidad +"&c=" + campo + "&p=" + prefijo + "&n=" + numCars;

xmlHttp.open("GET", "/autonum" + params, true);
xmlHttp.setRequestHeader('Content-Type', 'text/xml');
xmlHttp.send('');

xmlHttp.onreadystatechange=function() {
if(xmlHttp.readyState == 4 && xmlHttp.status == 200)
{
var objDoc = xmlHttp.responseText;
if( xmlHttp.responseText.length > 0 )
crmForm.accountnumber.DataValue = xmlHttp.responseText;
}
}

A continuación, publicamos las personalizaciones y nos vamos a la lista de cuentas.




La última cuenta cread tiene el código A-0126. Hemos configurado los parámetros de la llamada para que considere el prefijo A- y utilice 4 dígitos en el código. Cuando le damos al botón Nuevo ...



Aparece la ventana de creación de nuevas cuentas, pero esta vez con el siguiente número de cuenta rellenado automáticamente. ¡Conseguido!

2 comentarios:

I.B.G dijo...

Hola, una consulta sobre la autonumeración..en el caso que ya existan cuentas creadas..como se deberia hacer para que las antiguas tengan un valor? hay que introducirlos manualmente?

Daniel Sabater dijo...

Hola, "Webont" Este código esta pensado sólo para los nuevos registros (crmForm.FormType == 1)

Si cambias esa condición por algo como accountnumber != null, también funcionaría para los antiguos, aunque se irían numerando en el orden en el que las vayas abriendo.

De todas formas, esto no es una solución completa al problema de la numeración, tan solo una idea de por dónde empezar.