domingo, 16 de marzo de 2014

Consultando la auditoría de Dynamics CRM

Hoy me propongo la consulta del registro de Auditoría. La auditoría en Dynamics CRM 2013, se almacena en una especie de entidad, pero con limitaciones, y que no puede ser accesible por las búsquedas avanzadas estándar.
Solamente pueden consultarse en los propios registros o de forma general en Configuración->Auditoría->Vista resumen de auditoría:
image
image
Si necesitamos consultas algo mas avanzadas, sólo nos queda ir por los oscuros caminos de lo no soportado (atacando directamente al SQL Server), que no lo recomiendo, o sino utilizar la SDK.
En este caso, vamos a ver un ejemplo donde recojo todos los registros de auditorías de los últimos 30 días, y en caso de ser un Update o Create, además muestro el detalle de cambios actualizados.
El ejemplo de código es el siguiente:
static void GetAudit()
{
    //1) Consulta con Filtro de 30 días
    ConditionExpression cond = new ConditionExpression("createdon", ConditionOperator.LastXDays, 30);
    FilterExpression filter1 = new FilterExpression();
    filter1.AddCondition(cond);
    RetrieveMultipleRequest req = new RetrieveMultipleRequest();
    QueryExpression query = new QueryExpression("audit");
    query.ColumnSet = new ColumnSet(true); 
    query.Criteria.AddFilter(filter1);
    req.Query = query;
    RetrieveMultipleResponse res =(RetrieveMultipleResponse)service.Execute(req);

    //2) Recorremos la Auditoria devuelta
    foreach (Entity ent in res.EntityCollection.Entities)
    {
        //3) Leemos los datos del registro
        Audit record = (Audit)ent;
        string fecha = String.Format("Fecha:{0}", record.CreatedOn.Value.ToString());
        string usuario = String.Format("Usuario:{0}", record.UserId.Name);
        string accion = String.Format("Action:{0}", record.FormattedValues["action"]);
        string operacion = String.Format("Operación:{0}", record.FormattedValues["operation"]);
        string registro = String.Format("Tipo:{0} Name:{1} Guid:{2}", record.ObjectId.LogicalName, 
                record.ObjectId.Name, record.ObjectId.Id.ToString());
                
        //4) Escribimos un log de los datos
        Console.WriteLine(fecha);
        Console.WriteLine(usuario);
        Console.WriteLine(accion);
        Console.WriteLine(operacion);
        Console.WriteLine(registro);

        //5) Si es Create o Update 
        if (record.Action.Value == 1 || record.Action.Value == 2)
        {
            //6) Consultamos el detalle
            RetrieveRecordChangeHistoryRequest changeRequest = 
                new RetrieveRecordChangeHistoryRequest();
            changeRequest.Target = new EntityReference(record.ObjectId.LogicalName, 
                record.ObjectId.Id);
            RetrieveRecordChangeHistoryResponse changeResponse =
                (RetrieveRecordChangeHistoryResponse)service.Execute(changeRequest);
            AuditDetailCollection details = changeResponse.AuditDetailCollection;

            foreach (var detail in details.AuditDetails)
            {
                //7) Por cada detalle devuelto, pintamos valor anterior y actual
                Audit detail_record = (Audit)detail.AuditRecord;
                var detailType = detail.GetType();
                if (detailType == typeof(AttributeAuditDetail))
                {
                    var attributeDetail = (AttributeAuditDetail)detail;
                    foreach (KeyValuePair<String, object> attribute in 
                        attributeDetail.NewValue.Attributes)
                    {
                        String oldValue = "(no value)", newValue = "(no value)";
                        if (attributeDetail.OldValue.Contains(attribute.Key))
                            oldValue = attributeDetail.OldValue[attribute.Key].ToString();
                        newValue = attributeDetail.NewValue[attribute.Key].ToString();
                        Console.WriteLine("Attribute: {0}, old value: {1}, new value: {2}",
                            attribute.Key, oldValue, newValue);
                    }

                    foreach (KeyValuePair<String, object> attribute in 
                        attributeDetail.OldValue.Attributes)
                    {
                        if (!attributeDetail.NewValue.Contains(attribute.Key))
                        {
                            String newValue = "(no value)";
                            String oldValue = attributeDetail.OldValue[attribute.Key].ToString();
                            Console.WriteLine("Attribute: {0}, old value: {1}, new value: {2}",
                                attribute.Key, oldValue, newValue);
                        }
                    }
                }
            }
        }
        Console.WriteLine("---------------");
    }
    Console.ReadLine();
}

En resumen, utilizo el mensaje ExecuteMultiple para la consulta general y luego para el detalle utilizo el mensaje RetrieveRecordChangeHistory.

El resultado obtenido en mi caso es el siguiente:

image

Como puede verse, tengo toda mi auditoría en un resultado ordenado, por fecha, usuario entidad y tipo de acción.

Este ejemplo es 100% funcional, tengo idea de hacer algún tipo de herramienta a futuro, que ayudarnos con los datos que hay en los registros de auditoría, para que sea mas sencillo su explotación.

Espero les sea útil este ejemplo, a mí me ha servido.

domingo, 9 de marzo de 2014

Compartir registros con el propietario antes de reasignar

En Dynamics CRM, tenemos la posibilidad de antes de reasignar un registro, este quede compartido con el propietario original.

De esta manera podemos permitir que personas que fueron propietarios de un registro, puedan seguir teniendo permisos sobre el mismo, a la vez que consultar sus registros relacionados (si es que la relación esta definida para que se comparte en cascada).

Imaginemos algún escenario real:

Una operadora de atención al cliente, recibe una incidencia de un Cliente nuevo, que mas tarde un jefe de ventas asigna a un delegado comercial. Si la operadora de atención al cliente tiene privilegios de solo ver sus cuentas (de las que es propietaria), dejaría de ver esa cuenta que ha creado ella.

Lo ideal sería que al asignarlo a un delegado comercial, esta Cuenta (y sus relaciones hijas), se compartan con el la operadora que inicialmente la ha creado.

Para que funcione de esta manera, existe una opción en la configuración principal, con el nombre “Compartir registros reasignados con el propietario original”:

image

Pero, ¿como se comporta esto? la idea es bastante sencilla, imaginemos que tenemos una cuenta asignada a Demian:

image

La asignamos al usuario Test User:

image

Si vamos al menú de Compartir:

image

Podemos ver como el registro se ha compartido al usuario propietario inicial (Demian):

image

Excelente solución, solo tienen que tener cuidado con una cosa:

  • Esto se aplica para todos los registros, de todas las entidades, por lo tanto hay que tener cuidado de si se desea este comportamiento de forma “global” para todo el sistema.

Esta opción de configuración es una opción que prácticamente no he utilizado, ni he encontrado que mucha gente la utilice, aunque creo que es una idea muy buena.

un saludo y espero les sirva!

miércoles, 5 de marzo de 2014

Dynamics CRM como plataforma de desarrollo

Como todos conocen, Dynamics CRM es la mejor solución del mercado para todas las gestiones típicas de CRM como de ventas, marketing, servicio, etc. (Winking smile).

Pero cada día que pasa, veo mas a Dynamics CRM también como una excelente plataforma para implementar cualquier tipo de procesos de negocio. Esto nos permite diseñar, desarrollar, implementar y poner en marcha procesos de negocio en tiempo record, en un entorno controlado, amable y moderno, que además evoluciona y mejora por parte del fabricante (Microsoft).

Obviamente, este planteamiento no puede ser aplicado para cualquier tipo de desarrollo (aunque personalmente suelo ser bastante extremista con esto), pero si para una gran parte.

Bien, pero hablemos sobre un ejemplo en concreto para ver que ventajas podemos encontrar. Imaginemos que en una empresa, el departamento de recursos humanos, nos plantea la necesidad de una solución para gestionar las solicitudes de cursos de formación de sus empleados. Actualmente lo hacen por email y Excel, pero es un proceso manual muy lento y se producen errores. En este caso, si se plantea un desarrollo web por ejemplo, deberíamos pensar en un modelo de gestión de usuarios y seguridad, un modelo de datos, implementar un proceso de aprobación, temas técnicos o de sistemas acerca de las tecnologías a utilizar, y otros. Obviamente es un proyecto bastante sencillo, que empezando desde cero su desarrollo podríamos tenerlo listo en aproximadamente un par de meses (aproximación mía). Una vez montado, que pasa si nos piden accesos desde móviles, cambios en la funcionalidad, nuevas validaciones o cambios en el modelo de seguridad?, seguramente nos toque desarrollar nuevamente para realizar todos estos cambios (costo alto).

Todo esto esta muy bien, yo soy desarrollador también y me gustan los retos técnicos y me gusta desarrollar, pero a veces las visiones deben de estos temas deben tener una perspectiva mas a nivel empresarial y no solamente técnica.

Si implementamos soluciones de negocio en Dynamics CRM, ya tenemos disponible un servicio de autenticación y gestión de usuarios, un modelo de seguridad, una herramienta de modelado de datos y millones de funcionalidades “out of the box” como trabajos con Excel, importaciones, auditoría, automatismos, validaciones, workflows y un largo largo etc. No hay que olvidar que todo esto esta apoyado en una solución estándar de mercado, que Microsoft se encarga de mantener y evolucionar (muy rápido últimamente).

Por esto voy a plantear unos cuantos puntos que considero grandes “ventajas” de la utilización de Dynamics CRM como “xRM”:

  • Time to market: el tiempo de implementación de un proceso de negocio con Dynamics CRM es increíblemente rápido
  • Mantenimiento y evolución: al estar basado en una plataforma estándar, no se depende tanto del implementador y esto da mas libertad
  • Soporte: el soporte de Microsoft sobre la solución es imprescindible en determinadas organizaciones que requieren niveles de seguridad altos
  • Una plataforma, N procesos: sobre la misma plataforma, se pueden implementar todos los procesos de negocio que sean requeridos
  • Integración con cualquier otra solución: Como Dynamics CRM está basado en Web services, todo lo que implementemos en esta plataforma es muy fácilmente integrable con cualquier plataforma
  • Escalabilidad: en la parte de sistemas, nos permite que sea facilmente escalable
  • Nube u Onprem: posibilidad de implementarlo en la nube o en mi casa (onpremise)
  • Mantenimiento por usuarios avanzados: muchas veces, este tipo de procesos pueden ser mantenidos, administrados y evolucionados por “power users” sin necesidad de disponer de un equipo completo de desarrollo.
  • Precio: Obviamente Dynamics CRM no es gratis, pero el pago de las licencias muchas veces es mas bajo que si hubiesemos invertido ese dinero en desarrollos a medida, que en algun momento futuro se tirará o se tendrá que evolucionar a un precio muy elevado. Estas evoluciones con Dynamics CRM son muchisimo mas sencillas, rápidas y por supuesto, a precios menores.
  • Etc.
  • Etc.

Creo que el tiempo de ver al “CRM” como un simple sitio donde gestionar relaciones con mis clientes, ha pasado. Ahora Dynamics CRM es mucho mas y ofrece muchas mas posibilidades.

Por todo esto, ante un planteamiento de un nuevo requerimiento empresarial, sea del tipo que sea, por lo menos creo que debería ser analizada la posibilidad de implementarlo en una plataforma estándar como Dynamics CRM.

Un análisis en profundidad punto a punto nos desvelará que muchas veces la utilización de Dynamics CRM como plataforma de desarrollo, no solo nos ayuda a enfocarnos mejor en la solución de negocio, sino que también es una solución con vistas a evolucionar en el futuro de forma mucho mas ordenada, soportada y mantenible.