lunes, 28 de mayo de 2012

Javascript: Añadiendo notificaciones al formulario

Esta vez voy a publicar un artículo en donde vamos a añadir una funcionalidad que CRM 2011 no dispone, pero que a veces es muy útil teniendo en cuenta que a veces a los usuarios se los debe “Guiar” o añadir información necesaria para la introducción de información en los formulario de CRM.
La descripción del ejemplo de hoy es la siguiente:
Formulario: Cuenta
Evento: OnLoad() y OnChange()
Atributos: para este ejemplo, todos los requeridos y recomendados. 
Funcionalidad: Añade una notificación general de información del formulario, y verifica todos los atributos requeridos o recomendados y añade una alerta si es que están vacíos. Además en el OnChange() se actualiza el mensaje, dependiendo de si se ha introducido o no.
La idea es que en el formulario se enseñen notificaciones de la siguiente manera:
image
El javascript puede descargarse desde la página de Codeplex de EBDDCRM, en donde también iremos añadiendo mas funciones:
http://elblogdedynamicscrm.codeplex.com/documentation
El método principal que debe ser llamado tanto desde el OnLoad() como en el OnChange() es el siguiente:
function Verificaciones()
{
   addNotification ("",1);

   addNotification ("Formulario con la información general de la Cuenta.",2);
   
   var attributes = Xrm.Page.data.entity.attributes.get();
   for (var i in attributes)
    {
        var attribute = attributes[i];

        var requiredLevel = attribute.getRequiredLevel();
        var value="";
  if (attribute.getValue()!=null){value=attribute.getValue()};
  var control=Xrm.Page.getControl(attribute.getName());
  
  switch (requiredLevel)
  {
     case "required":
        if (value=="")
     {
    addNotification ("El campo "+control.getLabel()+" es requerido.",1);
     }
        break;
     case "recommended":
     if (value=="")
     {
    addNotification ("El campo "+control.getLabel()+" es opcional.",3);
     }
        break;
  }
  
    }
}


Lo que hacemos aquí es primero eliminar todas las notificaciones y luego recorrer los atributos del formulario y añadir notificaciones según estén rellenos o no los mismos.


Para hacer las llamadas a añadir notificaciones simplemente se debe llamar a la función “addNotificacion” con el texto y el tipo de notificación (1 crítico, 2 información, 3 advertencia).


El método que añade la notificación es el siguiente:


 function  addNotification (message, level) {
        /// The warning level of the message: [1 critial, 2 information, 3 warning]
        var notificationsArea = document.getElementById('crmNotifications');
        if (notificationsArea == null) {
            alert('div not found'); return;
        }
        if (level == 1) {
            //critical  
            notificationsArea.AddNotification('mep1', 1, 'source', message);
        }

        if (level == 2) {
            //Info  
            notificationsArea.AddNotification('mep3', 3, 'source', message);
        }
        if (level == 3) {
            //Warning  
            notificationsArea.AddNotification('mep2', 2, 'source', message);
        }
        if (message == "") {
            notificationsArea.SetNotifications(null, null);
        }
    }


Este método se apoya en ciertos métodos de CRM que no están documentados en la SDK y que por lo tanto no están soportados, que hay que tener en cuenta, pero que aporta mucha funcionalidad de cara a los usuarios finales.


Lo bueno de este ejemplo es verlo “en acción”, en donde se puede ver como va cambiando el listado de notificaciones según se van rellenando los valores del formulario.


Espero les sirva.


Un abrazo!

jueves, 24 de mayo de 2012

Excel PowerPivot y Dynamics CRM 2011 OnPremise

Como algunos sabrán, con la salida del SQL Server 2012, existen una serie de herramientas de explotación de información nuevas. Una de ellas es PowerPivot, que básicamente consiste en un Add-In del Excel, que permite explotar mejor la información extendiendo las propias funcionalidades del Excel.

En este artículo enseñaré como utilizar sencillamente PowerPivot conectándose a la base de datos de CRM.

Lo primero que hace falta, es descargar e instalar el PowerPivot (gratuito) de aquí:http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=7609

Luego nos vamos a nuestro CRM a los recursos del desarrollador:

image

De allí copiamos la URL del servicio OData:

image

Luego abrimos el Excel y la ventana de PowerPivot:

clip_image001

Luego al botón de obtener Feed:

image

Introducimos la ruta REST de las Accounts y Contacts (/AccountSet y /ContactSet):

image

Y dejamos que acabe la importación:

image

Y luego se pueden relacionar mediante la opción de “Crear relación”:

image

Creamos un gráfico y una tabla:

image

y listo nuestro primer informe en PowerPivot con datos de CRM (REST):

image

Un saludo,

lunes, 21 de mayo de 2012

Javascript: Como hacer una consulta al CRM

Hola, en este artículo empezaremos a ver ejemplos de como utilizar pequeñas funciones de javascript que suelen ser muy útiles y que suelen ser necesarias en muchos de los proyectos a los que nos solemos enfrentar en nuestro día a día.
Para empezar vamos a crear una funcionalidad relacionada con la realización de consultas de datos al CRM desde un formulario de CRM.
La descripción del método es la siguiente:

Formulario: Cuenta
Evento: OnChange()
Atributo: primarycontactid
Funcionalidad: consulta el télefono movil y el email del contacto seleccionado y los rellena en "Otro teléfono" y "Fax" respectivamente

image
El javascript puede descargarse desde la página de Codeplex de EBDDCRM, en donde también iremos añadiendo mas funciones:
http://elblogdedynamicscrm.codeplex.com/documentation
La función principal es llamada en el "OnChange" del Contacto principal:

image2
Y la función es la siguiente:

function contact_change()
{
   var contactid="";
   var telephone2=""; var fax="";
   
   var lookupItem = new Array(); 
   lookupItem = Xrm.Page.getAttribute("primarycontactid").getValue();
   if (lookupItem!=null) contactid=lookupItem[0].id;

   
   if (contactid!="")
   {
      var obj_contact=RetrieveEntityById("contact",contactid,
"mobilephone,emailaddress1");
      telephone2=obj_contact.mobilephone;
      fax=obj_contact.emailaddress1;
  

 }
   
   Xrm.Page.getAttribute("telephone2").setValue(telephone2);         
   Xrm.Page.getAttribute("fax").setValue(fax); 


}
Esta función llama al método "RetrieveEntityById" que recibe tres parámetros y nos devuelve un objeto de Javascript, con los atributos que le hemos solicitado, para que podamos recoger los valores del mismo por ejemplo simplemente haciendo "obj_contact.mobilephone".


En el código adjunto se encuentra el código completo que se puede hacer copy/paste directamente en el formulario y es totalmente funcional.


El método que realiza la consulta "RetrieveEntityById", es el siguiente:


function RetrieveEntityById(EntityName, EntityId, EntityColumns) {
    var resultXml, errorCount, msg, xmlHttpRequest;
    var arrayEntityColumns = EntityColumns.split(",");
    var xmlEntityColumns = '';
    for (var i = 0; i < arrayEntityColumns.length; i++) {
        xmlEntityColumns += "" + arrayEntityColumns[i] + "";
    }
    var soap = PopulateSoapObject(); // //Prepare the SOAP message.
    var xml = soap.Header
        + ""
        + "" + EntityName + ""
        + "" + EntityId + ""
        + ""
        + "" + xmlEntityColumns + ""
        + ""
        + ""
        + soap.Footer;
    //call function to create Soap Request to ms crm webservice 
    xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
    xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false); // false = don't make async call 
    xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
    xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
    xmlHttpRequest.send(xml);
    // debugger;
    resultXml = xmlHttpRequest.responseXML;
    return ObjectFromXML(resultXml, arrayEntityColumns, "//RetrieveResult");
}

function PopulateSoapObject() {
    var soap = new Object();
    soap.Header = ""
        + ""
        + Xrm.Page.context.getAuthenticationHeader() + "";
    soap.Footer = "";
    return soap;
}

ObjectFromXML = function (xml, arrFields, prefix, ignoreNulls) {
    var r = {}; // Return object
    r.ok = false;
    if (xml == null) { r.errorMsg = "No XML Returned by platform!"; return r };
    var errorCount = xml.selectNodes('//error').length;
    if (errorCount != 0) {
        r.errorMsg = xml.selectSingleNode('//description').nodeTypedValue;
        return r;
    }
    if (xml == null) {
        r.errorMsg = "Null XML returned.";
        return r;
    }
    /* var recordCount = 0;
    $(xml).find(prefix.substr(2)).each(function () {
    recordCount++;
    });
    if (recordCount == 0) {
    r.errorMsg = "No Records returned.";
    return r;
    } */
    if (prefix != "") { xml = xml.selectSingleNode(prefix) }; // Grab just the first node with the prefix
    // Everything ok, now format as an object
    r.ok = true;
    for (var i = 0; i < arrFields.length; i++) {
        if (!ignoreNulls) { r[arrFields[i]] = "" }
        var node = xml.selectSingleNode("q1:" + arrFields[i]);
        if (node != null) {
            var lookup = false;
            if (arrFields[i].indexOf("id") >= 0) {
                try { // Add try loop as .text fails when atribute not present
                    var name = node.getAttributeNode("name").text;
                    var type = node.getAttributeNode("type").text;
                    if (name != null && type != null) { lookup = true }
                } catch (err) { };
            }
            if (lookup) {
                r[arrFields[i]] = { name: name, id: node.text, entityType: type} // return lookup object 
            } else {
                r[arrFields[i]] = node.text;
            }
        }
    } // for
    return r;
}             // ObjectFromXML






Espero les sea útil este post. un abrazo!