sábado, 29 de agosto de 2009

Validaciones en el evento OnSave() de los formularios

Muchas veces necesitamos realizar validaciones en los formularios de CRM, que impidan que se guarden los datos introducidos en el mismo.
MSCRM 4.0 nos da la opción de recoger el evento que provocó la grabación del formulario, para poder realizar la validación que se necesite.
La documentación del evento OnSave() aparece en la SDK de CRM 4.0.
Allí nos detalla que podemos recoger la acción en el OnSave() accediendo a los valores de event.Mode que son los siguientes:


Hora intentaré hacer un par de ejemplos prácticos en relación con esto. Los ejemplos serán Javascripts que deberán ponerse en el evento OnSave() del formulario.

1) En una entidad donde tenemos una "Fecha desde" y una "Fecha hasta", no dejar guardar el formulario si la "Fecha hasta" es menor que la "Fecha desde":

if (event.Mode==1 event.Mode==2) // si es un evento de "Guardar" o "Guardar y cerrar"
{
var fechadesde=crmForm.all.new_fechadesde.DataValue;
var fechahasta=crmForm.all.new_fechahasta.DataValue;
if (fechadesde>fechahasta)
{
alert("La 'Fecha hasta' no puede ser menor que la 'fecha desde'.");
event.returnValue = false;
return false;
}
}

2) Ejemplo para no dejar completar una Cita, si no se rellena algo en el campo de descripción, para así obligar a rellenar los comentarios acerca de la misma:

if (event.Mode==58) // si es un evento de "Guardar como completado"
{
var comentarios=crmForm.all.description.DataValue;
if (comentarios==null || comentarios=="")
{
alert("Para completar la cita, debe rellenar los comentarios de la misma.");
event.returnValue = false;
return false;
}
}

viernes, 28 de agosto de 2009

Ha salido el Update Rollup 6

Esta semana ha salido un nuevo Rollup para el CRM 4.0.
la URL para la descarga está aquí:
Update Rollup 6 for Microsoft Dynamics CRM 4.0 (KB 970148)

Para ver un resumen de las actualizaciones entrar aquí:
El paquete acumulativo de actualizaciones 6 para Microsoft Dynamics CRM 4.0 supone disponible

Como toda actualización, tener mucho cuidado antes de instalarlo, antes que nada instalarlo en un servidor de desarrollo, probar todos los desarrollos y personalizaciones.

Un saludo!

miércoles, 26 de agosto de 2009

Importador de datos del CRM

En este artículo, intentaré dar algunas recomendaciones acerca de la utilización del importador de datos del CRM.
En primer lugar hay que tener en cuenta que el importador sólo permite la importación de datos desde ficheros en formato .CSV (separado por comas).
De esta forma podremos insertar datos de forma masiva en CRM.
Para explicarlo mejor, voy a realizar un ejemplo de importación de datos de una serie de Contactos, desde un fichero de Excel, hasta la inserción en CRM.

En primer lugar vamos a crear un Excel, con las columnas de información que queremos importar. Como recomendación, introducir como nombre de las columnas, los mismos "Nombres para mostrar" de cada uno de los atributos del CRM que queremos importar (respetanto mayúsculas y acentos).
El excel quedaría así (los nombres son todos ficticios):


Ahora lo que vamos a hacer, es guardar el excel en formato .CSV pulsando en "Guardar como" y seleccionando de la siguiente manera:


Para realizar la importación, debemos ir a Herramientas->Importar Datos...:


Debemos seleccionar el fichero .CSV y seleccionar como delimitador de campo "Punto y coma (;)":


Ahora se debe seleccionar el "Tipo de registro" a impotar (en este caso "Contacto"). Al haber introducido como cabecera los mismos nombres para mostrar que los atributos en CRM, la Asignación de datos es "Automático":


Seleccionar a quién se le asignarán los registros y si se desea que se importen duplicados:


Introducir un nombre para el trabajo de importación y confirmar la misma:


La importación se lanza en un proceso asíncrono. Para realizar un seguimiento del estado del proceso de importación, se puede ir a Área de trabajo->Importaciones (la importación va pasando por los estados "Enviado","Analisis","Transformacion","Importando","Completado"):


Una vez acabado se podrá abrir el registro del proceso asíncrono, y desde allí identificar los registros que se a creado, y los posibles errores y causas de los mismos. En este caso de los 7 registros, 2 han dado error, por no encontrar la referencia de la empresa "Sunny":


Finalmente los registros están creados en el CRM:


Cosas a tener en cuenta para la importación:

  • Las columnas de tipo referencia o "Lookup" deben ser rellenadas con los nombres de las entidades a los que se referencia. Los registros de la tabla referenciada, ya deben de estar creados.
  • La velocidad de las creaciones de los registros puede variar según el servidor de que se trate.
  • Las columnas de tipo desplegable o "Picklist" deben ser rellenadas con los valores en texto del desplegable.

martes, 25 de agosto de 2009

Ordenar registros por varias columnas

Muchas veces me han preguntado si se podía ordenar los registros que aparecen en las vistas del CRM por varias columnas a la vez.
La verdad que hasta ahora no lo sabía, pero sí que es posible.
Me han recomendado buscar en el famoso "Centro de recursos" de CRM, un área al que casi nunca solía acceder, pero navegando por la misma se nota que es de mucha utilidad para usuarios de CRM.
Allí se encuentra un articulo: Ordenar registros por varias columnas

Explica que para ordenar por varias columnas simplemente hay que hacer:
1) Ir a la vista que se desea ordenar (o busqueda avanzada).
2) Seleccionar la primera columa a ordenar.
3) Con las teclas CTRL+SHIFT presionados ir seleccionando las siguientes columnas.

Hasta aquí, todo bien.
Pero, me empezaron a surgir dudas de hasta donde se podía llegar con esta funcionalidad.
1) ¿Hasta cuantas columnas de orden se pueden seleccionar a la vez?: Yo llegué hasta las 25 columnas, y lo único que noté es que cada vez tardaba un poco mas en recargar la vista.
2) ¿Funciona para cualquier tipo de campo o con algun tipo de campo no te deja "Multi-ordenar"?: Funciona con cualquier tipo de campo.
3) ¿Funciona con campos de otras entidades?: Como no se puede ordenar las vistas por columnas de otras entidades, tampoco se puede "Multi-ordenar".

Me pareció una utilidad mas que intersante, en especial al exportar a Excel, ya que así podría ordenar rápidamente por lo que me interesa, y exportar a Excel sólo la página actual en la que me encuentro.

domingo, 23 de agosto de 2009

FilteredViews y autenticación de SQL Server.

Como todos saben, la información de MSCRM está almacenada en una base de datos en SQL Server.
La forma soportada y documentada en la SDK de Microsoft CRM 4.0 de acceder a la información directamente en el SQL Server, es a través de unas vistas que son llamadas "FilteredViews".
Las FilteredViews, son vistas en SQL Server cuyo nombre contiene el mismo nombre de la entidad, con el texto "Filtered" por delante. Por ejemplo "FilteredAccount" para la entidad de "Cuentas".

Al SQL Server uno se puede conectar de dos formas, y con cada una de las mismas, las FilteredViews se comportará de forma diferente:

1) Autenticación integrada de Windows:
Al conectarse de esta forma, y al realizar una consulta, automáticamente resolverá con el usuario conectado, los roles de seguridad, idioma, desplazamientos horarios, etc.
Así, por ejemplo podríamos de esta forma hacer la siguiente consulta:

SELECT * FROM FilteredAccount

Las FilteredViews detectan el usuario del directorio activo conectado al SQL Server, y lo relacionan con el usuario correspondiente de CRM.
Esto lo realiza con una función en SQL Server que podemos probar de la siguiente forma:

SELECT dbo.fn_FindUserGuid

2) Autenticación de SQL Server:
Al acceder mediante autenticación de SQL Server, las FilteredViews no pueden reconocer al usuario conectado, y si ejecutamos la consulta anterior, simplemente no devuelve nada, como si no se tuviese permisos para ver ningún registro.
Si nos conectamos de esta forma, y queremos hacer una consulta a las "FilteredViews" solo lo podemos haces "Impersonalizando" la consulta, es decir, ejecutando la misma como si fuesemos otro usuario.
Esto se puede lograr con la cláusula "EXECUTE AS USER=..." de la siguiente forma:
SELECT * FROM FilteredAccount EXECUTE AS USER='contoso\admin'

De esta forma, la consulta se realizará con los roles de seguridad y perfil del usuario que se determine.

jueves, 20 de agosto de 2009

Búsqueda rápida de registros inactivos

Al realizar una búsqueda rápida en MSCRM, solo aparecen aquellos registros que estén activos.
Por ejemplo:


Para habilitar que la "Búsqueda rápida" de una entidad busque también por registros inactivos, se debe hacer lo siguiente (el ejemplo en con las Cuentas):
1) Exportar las personalizaciones de la entidad.
2) Quitar el siguiente texto de la vista de "Búsqueda rápida de cuentas activas" (dentro de la "SavedQuery"):





3) Volver a importar la personalización y publicar.

Tener den cuenta que esta modificación es una modificación no soportada.

martes, 18 de agosto de 2009

Direcciones de envío de los Emails

Muchas veces enviamos emails desde el propio MSCRM (no mediante el Outlook), que como saben son enviados a la dirección que tenga predefinida el "Customer" o Usuario, como "emailaddress1".
Ahora bien, una vez que se pincha en "enviar" desde MSCRM, se marca como para enviar, pero es posible que quede en estado "pendiente", hasta que el proceso asíncrono de EmailRouter haga efectivamente el envío, o que se quede pendiente de sincronizar con un cliente de Outlook.
Entre un momento y otro, puede pasar un tiempo, y es posible que por ejemplo el email de la Cuenta haya sido modificado.
Entonces, ¿a que dirección se enviará el Email?, para esto habría dos opciones:
1) Que se envie a la dirección que tenía al momento de crear el email.
2) Que se envíe a la dirección que tiene al momento efectivo de realizar el envío.

Bueno, la respuesta es que antes del Rollup 4 de MSCRM 4.0, ocurría lo primero, y a partir del Rollup 4, ocurre lo segundo.

¿Como funciona entonces?
Al crear un Email, se crea un registro en la tabla "ActivityParty", con el campo "addressused" con el valor que tenga en ese momento.
Esto se puede comprobar fácilmente realizando la siguiente consulta:

SELECT addressused FROM FilteredActivityParty

Una vez que se actualiza el Email del registro en cuestión (por ejemplo una Cuenta), se actualiza tambien en cascada en la tabla "ActivityParty" en campo "addressused".

Los Rollups, muchas veces resulven temas, añaden funcionalidad y otras tantas cambian cosas, que pueden no estar documentadas, por esto mucho cuidado al instalar Rollups y probar todos los desarrollos previamente en un entorno que no sea de producción para así evitarse posibles dolores de cabeza.

domingo, 16 de agosto de 2009

Valores de los "Picklists" desde SQL Server

A veces tenemos la intención de acceder a los metadatos de CRM, pero simplemente para identificar los valores posibles de un campo de tipo "Picklist" o desplegable.
Esta información además de poder accederse con la propia SDK a través de los métodos disponibles de el MetadataService, también pueden ser accedidos de forma mas rápida y sencilla desde el propio SQL Server.
La consulta es muy simple (sólo habría que modificar los campos del "WHERE"):


SELECT AttributeValue, Value
FROM StringMap
WHERE AttributeName='accountcategorycode' AND ObjectTypeCode=1
ORDER BY DisplayOrder

viernes, 14 de agosto de 2009

Control de Errores en llamadas a la SDK

Muchas veces al hacer una llamada a un método de un web service de CRM, nos devuelve un error, que si lo recogemos como la simple "Exception", no nos dice exactamente el error que devuelve el CRM, sino un simple error genérico de web service.
Se debe capturar en el "catch" el error System.Web.Services.Protocols.SoapException, y con eso, acceder a "soexp.Detail.InnerText".

Para capturar correctamente los errores devueltos por el CRM, se debe de hacer de la siguiente forma:


try
{
Guid guidAccount=service.Create(nuevacuenta);
}
catch (System.Web.Services.Protocols.SoapException soexp)
{
Console.WriteLine("La descripción del error soap es:" + soexp.Detail.InnerText);
throw soexp;
}
catch (Exception ex)
{
Console.WriteLine("La descripción del error es:" + ex.Message);
throw ex;
}

jueves, 13 de agosto de 2009

"Soportado" vs "No Soportado"

Muchas veces, nos surge la idea de hacer cosas que el CRM de forma natural no lo hace, o que lo hace de una manera que puede no servirnos, ya sea por la velocidad, o que por el propio funcionamiento del CRM no encaja con lo que quiere el cliente.
Para esto se debe hacer algun desarrollo adicional para que cubra dicha necesidad.
Estos desarrollos o extensiones puedes hacerse de una forma "soportada" o de una forma "no soportada" por Microsoft.
Las personalizaciones "no suportadas" son las siguientes:

  • Modificar o añadir cualquier fichero del directorio virtual de CRM o del directorio de instalación del CRM.

  • Modificaciones en el sitio virtual del CRM.

  • Cualquier modificación en la base de datos SQL Server (tablas, vistas, procedimientos almacenados, etc), salvo la actualización o creación de índices.

  • Referenciar directamente a las DLLs del CRM.

  • Reutilización de los controles de usuario propios del CRM.

  • Utilización de javascripts propios del CRM.

  • Hacer personalizaciones fuera de las herramientas de personalización del CRM.

  • La utilización de "HttpModules" para inyectar HTML dinámico en los formularios de CRM.


  • Ahora bien, ¿qué consecuencias podría tener hacer cosas "no soportadas"?. Las consecuencias podrían ser las siguientes:

  • Que alguna actualización de CRM pueda cambiar el funcionamiento y hacer que nuestro desarrollo no funcione.

  • Se podría perder el soporte de Microsoft, ya que se han realizado cosas "no soportadas".

  • Podríamos tener problemas en futuras migraciones a próximas versiones de CRM.

  • Las personalizaciones no soportadas podrían causar funcionamientos no esperados.


  • A pesar de esto, muchas veces no nos queda otra opción que hacer cosas "no soportadas".
    las personalizaciones "no soportadas" yo las califico entre "totalmente no soportadas" y otras que son un poco mas "light". Las diferencias entre unas y otras estan claras, las primeras podrían causar problemas graves, y las segundas no tanto, o que podrian ser modificadas con relativa facilidad en futuras versiones.
    A continuación pongo algunos ejemplos:

    miércoles, 12 de agosto de 2009

    Eliminación masiva de registros en MSCRM

    Muchas veces necesitamos eliminar toda la información de una entidad específica. Si son pocos registros, no hay problema, los eliminamos de forma manual con el propio CRM.
    Ahora, si los registros son muchos, Microsoft CRM nos da la posibilidad de llamar a unos trabajos asíncronos de eliminación, de forma que podemos dispararlos, y dejarlos hasta que acaben de eliminar todos los registros.
    Recomiendo no eliminar nunca registros "a mano" en la base de datos SQL salvo que sea extrictamente necesario. Además tener en cuenta que si se borra directamente en SQL Server, toda la funcionalidad que se le haya definido a la entidad en cuando a relaciones en cascada, los workflows, y los plugins, no se dispararán. Además, como saben, no esta soportada la eliminación de registros directamente en la base de datos.

    La siguiente función hace exactamente eso, borra todos los registros de una entidad a traves de un trabajo del sistema asíncrono. Está hecho de una forma soportada y documentada en la SDK de MSCRM 4.0:


    public static void BorradoMasivo(string crmServerUrl, string orgName, string Entidad, string Usuario, string Password, string Dominio)
    {
    CrmAuthenticationToken token = new CrmAuthenticationToken();
    token.OrganizationName = orgName;
    CrmService service = new CrmService();
    service.Credentials = new System.Net.NetworkCredential(Usuario, Password,Dominio);
    service.Url = crmServerUrl;
    service.CrmAuthenticationTokenValue = token;

    QueryExpression bulkDeleteQuery = new QueryExpression();
    bulkDeleteQuery.EntityName = Entidad;

    BulkDeleteRequest bulkDeleteRequest = new BulkDeleteRequest();
    bulkDeleteRequest.JobName = "Eliminacion de: " + Entidad;
    bulkDeleteRequest.QuerySet = new QueryBase[] { bulkDeleteQuery };

    bulkDeleteRequest.StartDateTime = new CrmDateTime();
    bulkDeleteRequest.StartDateTime.Value = DateTime.Now.ToString();

    bulkDeleteRequest.RecurrencePattern = string.Empty;
    bulkDeleteRequest.SendEmailNotification = false;
    Guid[] emptyRecipients = new Guid[0];
    bulkDeleteRequest.ToRecipients = emptyRecipients;
    bulkDeleteRequest.CCRecipients = emptyRecipients;

    BulkDeleteResponse bulkDeleteResponse = (BulkDeleteResponse)service.Execute(bulkDeleteRequest);
    }

    Este proceso puede tardar mucho en caso de haber muchos miles (o millones) de registros.

    A medio camino del "delete" en la base de datos y de la utilización de la SDK, existe una posibilidad, no soportada también, de eliminar registros.
    Al eliminar un registro en MSCRM 4.0, realmente no se elimina de la base de datos, sino que simplemente se marca como para borrar poniendo el campo "deletionstatecode=2", para que luego el proceso asíncrono se encargue de eliminar todos los registros marcados. De esta forma podríamos "eliminar" registros del CRM a traves de un "UPDATE" en la base de datos. Esto no esta soportado, así que esto se debería probar que se eliminan correctamente.

    Así, por ejemplo, podríamos eliminar todas las Cuentas:

    UPDATE AccountBase SET DeletionStateCode=2

    Las eliminaciones masivas de registros pueden ser muy lentas si se hacen de forma soportada, pero para utilizar formas no soportadas, se debería estar muy seguro de lo que se hace y realizar exhaustivas pruebas de que eso funcion correctamente y no tiene consecuencias secundarias.

    Espero pueda servirles,

    Saludos

    domingo, 9 de agosto de 2009

    Como aumentar la cantidad de registros al exportar a Excel

    Cuando se exporta a Excel mediante una Hoja de Calculo dinámica, por defecto solo se exportan los primeros 10.000 registros.
    Esta cantidad puede ser ampliada haciendo un "Update" en la base de datos.
    Para aumentar dicha cantidad, se debe actualizar el registro de la base de datos correspondiente a la organización de la siguiente forma:


    UPDATE OrganizationBase SET MaxRecordsForExportToExcel=<numero_de_registros> WHERE Organizationid = '<Guid_de_la_Organizacion>'


    Luego se debe hacer un IISRESET (reiniciar el IIS), y listo.