MSCRM 4.0: Añadir línea de separación en una sección

28 11 2010

A continuación os dejo el código que me ha pasado un cliente (con el que realizamos consultorías periódicas de mejora de su MSCRM 4.0) y que permite mostrar un título con un subrayado entre los atributos de una misma sección. De este modo no tenemos que crear varias secciones para separar o agrupar los atributos. En la imagen observareis que sobre el atributo Cuenta primaria se ha creado un título con una línea horizontal de separación:

El código de la función es el siguiente:

function lineaHorizontal(nom_obj , titulo)
{
  var obj_M = document.getElementById(nom_obj);
  if (obj_M != null)
  {
    var nodo = document.createElement('TR');
    var nodotd = document.createElement('TD');
    nodotd.colSpan=4;
    nodotd.innerHTML = "<B>" + titulo + "</B>" + "<HR>"
    nodo.appendChild(nodotd);
    obj_M.parentNode.parentNode.insertBefore(nodo , obj_M.parentNode);
  }
}

Para ejecutar el ejemplo se ha utilizado la sentencia:

lineaHorizontal("parentaccountid_c", "Ejemplo de título");




SQL: Obtener la fecha actual sin la hora

24 11 2010

Como simple curiosidad os transcribo la sentencia que he usado para obtener mediante T-SQL la fecha actual sin la hora, es decir, obtener siempre la fecha con la hora a 00:00:00. A primera vista puede parecer trivial, pero T-SQL no dispone de ninguna función específica que devuelva ese valor. GETDATE() devuelve siempre la fecha con la hora actual. Puestos a crear una función he buscado por internet la más optima y he encontrado la siguiente:

CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

De todas las soluciones que he encontrado esta es la más simple y la que menos tiempo tarda en calcular la fecha.





NET: Encriptar secciones de web.config

22 11 2010

A menudo cuando desarrollamos aplicaciones Web (normalmente como extensiones de MSCRM) utilizamos el archivo web.config de la aplicación web para almacenar variables globales de la aplicaciones. Así por ejemplo, solemos añadir las cadenas de conexión a datos que posteriormente usaremos en la aplicación para conectar a bases de datos… Es muy importante saber que normalmente, el acceso al archivo web.config desde el navegador debe estar restringido pero, puede suceder que por alguna configuración ajena se permita este acceso. Por tanto, cualquier información que estemos añadiendo en este archivo de texto, puede comprometer la seguridad de nuestro sistema o puede estar ofreciendo al usuario información no deseada. En algunas instalaciones he llegado a ver que en este archivo se introduce incluso el password sin encriptar del usuario administrador de MSCRM!!!.

Figura 1. Error al acceder a web.config desde u navegador

Pues bien, además de intentar no introducir información clave en este archivo, si nos es necesario podemos optar por la opción de cifrar ciertas secciones de este archivo. Así por ejemplo, imaginad que tuviéramos definida una cadena de conexión a datos sobre la base de datos CRM en nuestro archivo web.config:


<connectionStrings>
<add name="strConn" connectionString="Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=MINHAC_MSCRM;Server=." />
</connectionStrings>

En este caso, la cadena de conexión no contiene usuario y password pues se utiliza la autenticación de Windows (la más recomendada en estos casos) para acceder al SQL Server). Sin embargo si trabajáramos con autenticación de SQL Server (poco recomendable) aparecería el usuario y la clave!!!.

Para encriptar esta sección y cifrar su contenido tan sólo necesitamos ejecutar un comando propio de NET Framework. Debemos situarnos en el directorio del NET Framework correspondiente a la aplicación Web (normalmente, si estamos en CRM 4.0, la versión de NET Framework es la 2.0) y ejecutar el siguiente comando:

Tras ejecutar este comando podremos observar que la sección connectionStrings de nuestro web.config ha sido encriptado:


<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData> <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA3I15yxfdeUywFzxPgNcnwwQAAAACAAAAAAADZgAAqAAAABAAAAB3OUG0nsxHtLh8yzBw6VtjAAAAAASAAACgAAAAEAAAAOSsEyXru5ZMGH6CC1uompVoAQAAsj8zgTP6NrsguTxVWPv0xm6Y04836QDdJ4r6yt/9XqN70ToMQABZqWnEnaSaqDDWIZaEEt/0OmJCxJXiedVomhKf2S0I+fMTBVLSLqj4pKaqSjlNjQgSfa+EoKZz5u7o3AxC4zhQS5TJ7nqdgIzIwe+upxfVUJpH0//m41u1rarWdrI/k3nUzlsvz3f7eiVyfsnk+PQ9QWXbWnIqPpFizAmGOcwbhWtk7AzT2VkMg2xdwZFYg4hpTXFYHqaU5XXocryrdHBxrj2zjE+h+4NURC3mmCd8NPEkpe2iGydJo75F1dHsuToGc9E3XRiDwHmB2dVXQkcNFxkdgS7Z6eRhJGdBVri5TYq6U1Gj8kIUe6g4CwkUnZaW8F3FjSWf3Lfl8KZLLG6OCBmwcyQEwUw06BVQah4KfKE8fHZHabI5EMWFaQ11ywsXs0YEJg+XdkHv+mUOocl3qAF+Y25GfYVgSm5JI5SyqvMHFAAAAJUDQ5kizMW2E+7oqVbIEhAbyUyK
</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>

Esta acción no requiere que en el código de la página ASP.NET en la que usemos esta cadena de conexión realicemos ninguna acción especial pues es el propio IIS el que realiza la encriptación y desencriptación y por tanto, al leer la cadena desde la págia ASPX, IIS ya realiza el descifrado.

Para recuperar el archivo original, tan sólo es necesario utilizar el mismo comando con otro parámetro:

Tan sólo hay que tener presente un par de cuestiones:

1. El cifrado depende de la máquina donde está instalado IIS por tanto, si tenemos dos entornos NO podemos copiar el archivo web.config con secciones cifradas de un servidor a otro pues en el nuevo no se interpretaría el cifrado. Debe ejecutarse el comando individualmente en ambos servidores

2. Existen dos tipos de cifrado (que indicamos en el parámetro –prov) que se pueden usar: DataProtectionConfiguratioProvider y RsaProtectionConfigurationProvider. Al desencriptar no es necesario indicar el proveedor pues ya se especifica en el archivo





ASP.NET: Declaración DOCTYPE y su efecto sobre el diseño de webforms

22 11 2010

Supongo que más de uno se habrá preguntado que significa o para que sirve el tag (o declaración) DOCTYPE que encontramos en los web form creados en Visual Studio. Tras crear un nuevo webform observaremos que se nos crea la siguiente declaración tras la directiva @Page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Pues bien, el tema tiene su miga! Para los más curiosos os recomiendo el link http://aspnetresources.com/articles/doctype.aspx donde se explica muy detalladamente el origen, significado y alguna que otra curiosidad al respecto. Pero el motivo de mi artículo no es el de explicar su significado o propósito (para eso ya hay páginas enteras). El motivo de este artículo es el comentaros una de las consecuencias una vez más de no prestar (o no tener suficiente tiempo para prestar…) atención a los que por defecto nos crea Visual Studio.

Ejemplo de webform creado en VS2008 SP1 (NET 2.0) donde se añade automáticamente el DOCTYPE

En esta ocasión tras haber creado muchas páginas ASP.NET en muchas integraciones de MSCRM he descubierto ( o mejor dicho, por fin he podido prestar atención!!!) los efectos de esa ‘inofensiva’ declaración DOCTYPE. Pues bien, los que tengáis paciencia o interesa por haber leído el link donde se describe la declaración DOCTYPE habréis comprendido, entre otras cosas, que esa declaración permite que la página tan sólo utilice objetos con compatibilidad sobre unas versiones de IE (no entraré en detalle). Pero, nunca hubiera imaginado que esa declaración afectaría al comportamiento de ciertos estilos o controles!!!

Uno de los temas en los que he dedicado más tiempo ha sido en poder crear un formulario web en el que el contenido de la página se redimensionara al variar el tamaño de la ventana. Una de las opciones que uno piensa en primer lugar és crear una tabla con altura y anchura 100%, ¿correcto?. Pues bien, si dejamos la declaración DOCTYPE que nos aparece al crear el web form, el atributo altura 100% (height en el style) NO funcionará! Por tanto, desde hace mucho tiempo he utilizado la solución del control panel y código JavaScript en los eventos onload y onresize para redimensionar el panel al cambiar las dimensiones de la ventana… Harto de ver en mil y un foros que la gente utilizaba el height 100%, me paré a investigar porqué a mí no me funcionaba y, finalmente, encontré la explicación en la declaración DOCTYPE.

Como conclusión, para poder utilizar todas las novedades del lenguaje HTML, así como las característica completas de JavaScript y, en definitiva, estar a la última, se debe eliminar la declaración DOCTYPE que añade Visual Studio al inicio de los nuevos web forms que creemos. Muy probablemente seguro que existe alguna cofiguración de VS para evitar que se cree esa declaración por defecto… si alguien la conoce o la encuentra, por favor, añadidlo en u comentarios a este artículo, gracias.

Resultado de mostrar una <table> con la dimensión height a 100% con la declaración DOCTYPE

El mismo código anterior pero sin la declaración DOCTYPE

Como observamos en el ejemplo, sin la declaración DOCTYPE la dimensión height: 100% actúa correctamente!!! Con lo cual es mucho más simple crear formularios autodimensionables sin la necesidad de usar código JavaScript para realizar la ubicación y dimensionado de los controles.

P.D.: No he entrado en mucho detalle sobre el entorno de programación… pero si creo que es importante destacar que esta situación la he encontrado creando formularios web con Visual Studio 2008 SP1 en proyectos con NET Framework 2.0 (probablemente con proyectos NET Framework 3.0 o 3.5 no ocurra esto).





MSCRM 4.0: Introducción masiva de registros mediante lector de código de barras (AJAX)

22 11 2010

En este artículo os describo un nuevo desarrollo que hemos realizado en un proyecto para un cliente. Si bien tan sólo os describiré el funcionamiento y os mostraré algunas imágenes del componente, lo más importante del desarrollo es que hemos utilizado AJAX para mejorar el rendimiento.

El cliente nos solicitó un sistema para poder introducir la correspondencia devuelta de forma masiva. El usuario dispone de un lector de código de barras y toda la correspondencia devuelta está identificada con un código de barras (el código de barras se asigna de forma automática en la creación de cada registro de la entidad Correo Postal, o letter). El objetivo es disponer de una interface que permita ir identificando las cartas devueltas con el lector de código de barras y, una vez identificadas todas las cartas, procesarlas para crear un registro para cada una en una entidad llamada Devoluciones (que está relacionada con la entidad Letter). De este modo se consiguen los objetivos siguientes para el usuario:

1. No tiene que introducir manualmente cada código de barras ni localizar el registro en la entidad Letter

2. Puede seleccionar el motivo de la devolución y este se asigna a todos los registros que introduzca a continuación

3. No tiene que esperar a que se procese la devolución cada vez que introduce un registro, se procesan todos una vez introducidos todos los códigos de barra

Como comentaba al principio este desarrollo utiliza AJAX para mejorar el rendimiento del componente. En concreto se ha establecido dos zonas diferenciada en el formulario, una primera zona donde se introduce el código de barras mediante el lector y una segunda zona donde está el grid con los códigos introducidos. De este modo, el usuario puede ir leyendo códigos de barra sin esperar que se procese el registro.

Al componente se accede mediante un botón ISV en la vista principal de la entidad Devoluciones:

Una vez iniciado el componente, el foco del formulario se sitúa en el TextBox de introducción del código de barras. El lector recupera el literal del código de barras y emite un CR+LF para seleccionar el botón por defecto (Añadir). En ese momento se añade el registro leído a la tabla mediante un postback asíncrono. Previamente el usuario ha seleccionado el motivo de devolución que se asignará a todos los registros introducidos a continuación (puede modificarlo en cualquier momento). Gracias a la utilización de AJAX, mientras se procesan los registros, proceso que puede tardar unos minutos, se muestra un icono animado que da mayor sensación de robustez a la aplicación.

Una vez identificados todos los registros con su código de barras y el motivo de devolución, el usuario selecciona la opción Registrar. Al seleccionar esa opción se procesa cada uno de los registros introducidos. En concreto, para cada registro se crea un nuevo registro de la entidad Devolución (relacionado con la entidad Letter origen de la devolución). Al finalizar el proceso de todos los registros se muestra un icono para cada registro en el que se identifica si se ha podido procesar o no.

En estas imágenes estáticas no se puede apreciar como la utilización de AJAX mejora enormemente el funcionamiento del componente. Para que os hagáis una idea, sin AJAX, cada registro que se introducía en la tabla mediante el código de barras tardaba del orden de 3 segundos además del refresco de toda la ventana. Tras aplicar AJAX, el proceso de introducción de un registro es instantáneo e incluso el refresco de la tabla es imperceptible. En cualquier caso, si se produce una demora la ventana muestra un texto de progreso con lo que el usuario está informado (la venta no se bloquea!!!).





MSCRM 4.0: Workflow activity para formatear fechas

20 11 2010

Un problema que nos encontramos habitualmente al crear correos electrónicos u otras actividades en workflow es que, al insertar una fecha en un campo de text (por ejemplo, en el cuerpo del mensaje), no podemos dar formato a esa fecha. Para resolverlo hemos desarrollado una actividad de workflow personalizada que nos permite formatear las fechas antes de insertarlas en el mensaje. A continuación os mostramos como utilizar esta actividad personalizada.

Tras instalar la nueva actividad de workflow personalizada con PluginRegistration, se añade una nueva actividad en el interface de definición de workflows (Dar formato a fecha):

En este ejemplo hemos insertado una actividad de Dar formato a fecha para formatear la fecha de creación de un contacto. Al establecer las propiedades de la nueva actividad debemos seleccionar los siguientes valores:

  • Fecha: Atributo de fecha a formatear
  • Formato: Formato de la fecha que queremos aplicar (podéis usar cualquier formato de fecha igual que en el Parse de C#). Por ejemplo, dd-MM-yyyy, dd MMMM yy…
  • Idioma: Idioma que se aplicará al formato para temas de puntuación y literales (por ejemplo, si usáis MMMM en el formato). El idioma debe especificarse en el formato Language Code como es-ES, ca-ES, en-EN…

En el mismo workflow hemos creado un nuevo paso que genera un correo electrónico. En este correo electrónico mostraremos al fecha de creación sin formato y la fecha formateada mediante la actividad personalizada:

Para seleccionar la fecha formateada debéis seleccionar en Buscar la sección de Valores locales donde aparecerá el nombre del paso anterior del tipo Dar formato a fecha. Esta actividad devuelve una variable result que contiene el resultado de la fecha formateada:

Una vez, configurado el workflow y publicado, hemos ejecutado una prueba lanzando el workflow manualmente desde un contacto. Tras generarse el correo electrónico observamos que en el cuerpo del mensaje se han insertado la fecha de creación sin formato y la fecha de creación con el formato que hemos especificado.

Esperamos que os sea de utilidad. Si alguien está interesado en el código de la actividad personalizada de workflow Dar formato a fecha, escribidnos.





MSCRM 4.0: Workflow activity para asignar destinatarios de e-mail y enviar

18 11 2010

Recientemente he tenido que desarrollar una actividad de workflow personalizada para MSCRM 4.0 relacionada con oportunidades. En concreto, la actividad de workflow desarrollada permite asignar los destinatarios de un correo, previamente creado en el workflow de la oportunidad, y enviarlo. Los destinatarios asignados al correo son los usuarios de la misma unidad de negocio que el propietario de la oportunidad pero que tengan un role específico.

Para utilizar esta actividad en un workflow asociado a la entidad oportunidad tan sólo se requiere crear un paso en el workflow en el que se crea un registro del tipo correo electrónico (ATENCIÓN: no es lo mismo que la opción Enviar correo!!!). En las propiedades del correo (como se observa en la figura) no indicamos ningún destinatario:

A continuación creamos un nuevo paso en el workflow con la actividad personalizada Asignar destinatarios por role y enviar

Los parámetros de esta actividad personalizada són:

¿Enviar e-mail? -> Determina si al rellenar los destinatarios debe enviarse el e-mail
Role -> Nombre del role de los usuarios destinatarios (de la misma unidad de negocio del propietario de la oportunidad)
Oportunidad -> Guid de la oportunidad
Email -> Referencia del e-mail creado en el paso anterior del workflow

Tras ejecutarse el workflow (por el cambio de un atributo o cambio de estado…) obtenemos el resultado siguiente:

Observamos que en la oportunidad se ha creado un nuevo e-mail al que se le ha asignado los usuario con el role Director General de la unidad de negocio del propietario de la oportunidad (Albert Porrà):

Por supuesto la lógica de obtención de los destinatarios puede adaptarse a las necesidades de cada proyecto de forma muy simple.