Obtener el nombre del workflow padre con ParentContext

Cuando desplegamos un plugin o un workflow en nuestra instancia de CRM Dynamics estamos activando un flujo de trabajo que se ejecutará ante un determinado evento. En el caso del workflow podemos configurar mediante el menú de edición de Dynamics unas condiciones extra que se deben de dar para que se ejecute el código –como podría ser que determinado campo del registro modificado esté valorizado-.

Podría darse el caso de que este registro del que hablamos sea modificado por el usuario mediante un formulario de CRM, y además también podría ser modificado mediante la ejecución de otro workflow o plugin de, por ejemplo, actualización de datos nocturnos. Y rizando el rizo podemos suponer que un workflow puede llamar a otro, y este a otro, y así repetidas veces, pudiendo encontrar problemas si no controlamos bien el contexto en el que se ejecuta nuestro código.

En la ejecución de un Workflow o plugin siempre podemos obtener el objeto Context que vendrá heredado y que contendrá información sobre la profundidad –accesible mediante la propiedad Depth del objeto- además de otros parámetros de interés.

Cuando la profundidad es igual o mayor a uno implica que la ejecución de nuestro código ha sido invocada desde otro workflow o plugin. Cuando esto ocurre,  podremos acceder al ParentContext que será un objeto del mismo tipo pero que contendrá información del contexto del workflow que precede al nuestro que incluso podría darse el caso de que sea el mismo workflow.

La idea es poder obtener el nombre literal de ese workflow padre para poder poder condicionar la ejecución de nuestro workflow mediante un if.

Nombre literal del workflow en la entidad "Trabajos del sistema"

Nombre literal del workflow en la entidad “Trabajos del sistema”

Como hemos dicho, el ParentContext contiene información del contexto del workflow invocador de nuestro workflow, y entre otros datos contiene el parámetro CorrelationId que sería el id único del registro de tarea del sistema creado por este workflow. Con este id seremos capaces de obtener el nombre de éste workflow y condicionar la ejecución, como se indica en el siguiente ejemplo:

String connection CRM

 

String connection

Las string connections son variables de tipo string que contienen los datos necesarios para realizar una conexión a un entorno. Se utilizan mucho para, por ejemplo, conectarse a una base de datos. Estas cadenas de texto contienen todos los datos necesarios para que el cliente que realiza la petición sepa a qué base de datos debe conectarse y bajo qué usuario y password debe realizarlo. Son muy útiles porque nos permiten definir todos los datos necesarios para conectarse en una única variable, lo que simplifica el mantenimiento de la aplicación.

CRM Dynamics no es distinto y nos ofrece la posibilidad de conectarnos a una instancia de CRM únicamente indicando la string connection de esa instancia. El procedimiento ha cambiando un poco desde la versiones antiguas de CRM y la nueva versión 365 pero en esencia es igual. Vamos a ver cómo utilizar una string connection desde una aplicación hecha en C#:

SDK CRM 2011, 2013, 2015 y 2016

 

SDK CRM 365

 

Las diferencias entre las versiones son simplemente en el objeto que se instancia y de qué clase proviene. En las versiones antiguas se generaba la interface IOrganizationService desde el objeto OrganizationService mientras que en la nueva versión 365 el IOrganizationService se instancia desde el objeto CrmServiceClient del namespace Microsoft.Xrm.Tooling.Connector. También observar que la string connection para 365 tiene el parámetro extra de Authtype.

Cómo construir nuestra propia String Connection

Las String Connection por desgracia no son siempre iguales. En función del tipo de instancia que tengamos, o del tipo de autentificación se construirán de un tipo u otro. Vamos a ver qué parámetros se pueden incluir y algunos ejemplos:

 

Nombre de parámetro Parámetro Descripción
Server, Url, or Service Uri Url, Server, ServiceUri  La URL de nuestro CRM.

  • Si es una instancia on premise, la URL debería incluir la organización. Por ejemplo http://servidorcrm:puerto/nombre-organizacion.
  • Si es una instancia online, la URL será la que utilizamos para acceder. Por ejemplo: http://nuestra-organizacion.crm4.dynamics.com/

Para la string connection, funcionará igual si utilizamos la palabra Url, Server o ServiceUri

Domain Domain  El dominio de nuestra organización. Estaría relacionado con el Active Directory si estamos hablando de una instancia on premise. Para los online no es necesario incluir este parámetro.
Username or User ID Username Nuestro nombre de usuario.
Password Password Nuestro password. Podemos incluir dobles comillas al inicio y al final si nuetro password incluye espacios u otros caracteres especiales.
Timeout Timeout Por defecto el timeout de las conexiones a CRM son 2 minutos, pero si lo deseamos podemos aumentar o reducir esta cantidad. El formato sería timespan del tipo “hh:mm:ss”.
 Authtype Authtype  Necesario solo para instancias CRM 365. Si tenemos un CRM Dynamics 365 la string connection deberá incluir este parámetro. Los valores que puede tomar son:

  • Authtype=”Office365″ si nuestro CRM 365 es Online
  • Authtype=”AD” si nuestro CRM es on premise y validamos los credenciales contra el Active Directory
  • Authtype=”IFD” si nuestro CRM es on premise y validamos los credenciales mediante IFD

Los parámetros deberán incluirse uno detrás de otro separados por punto y coma en formato texto dentro de nuestra String. No son necesarias las comillas para indicar un parámetro a no ser que el valor de éste incluya carácteres especiales o espacios. Para las versiones on premise es posible también conectarse utilizando seguridad integrada de Windows, no incluyendo los parámetros Username y Password en la string connection. Si hacemos esto, la ejecución de las peticiones se realizará con el usuario que esté ejecutando la sesión de windows.

Algunos ejemplos:

CRM 365 online

“ServiceUri=https://ourorganization.crm4.dynamics.com/; Username=name@ourorganization.onmicrosoft.com; Password=OurPassw0rd; Authtype=Office365;”

 

CRM 365 on premise

“ServiceUri=http://ipcrm:5555/OrganizationName; Domain=ourdomain; Username=username; Password=OurPassw0rd; Authtype=AD;”

 

CRM 2011/2013/2015/2016 online

“ServiceUri=https://ourorganization.crm4.dynamics.com/; Username=name@ourorganization.onmicrosoft.com; Password=OurPassw0rd;”

 

CRM 2011/2013/2015/2016 on premise

“ServiceUri=http://ipcrm:5555/OrganizationName; Domain=ourdomain; Username=username; Password=OurPassw0rd;”

 

CRM 365 on premise con seguridad integrada

“ServiceUri=http://ipcrm:5555/OrganizationName; Authtype=AD;”

 

CRM 2011/2013/2015/2016 on premise con seguridad integrada

“ServiceUri=http://ipcrm:5555/OrganizationName;”

 

Fuentes: Microsoft, Ax3Group

SDK Rest Retrieve con Expand

La librería SDK.REST es la mejor herramienta que tenemos para hacer queries a CRM desde Javascript. Esta librería ofrece una serie de métodos con los cuales podemos interactuar con la Api REST de CRM. Uno de esos métodos es el Retrieve que incluye el parámetro Expand que vamos a analizar.

Con el método Retrieve podemos obtener un registro de CRM indicándole la entidad y el Id del mismo. Además es siempre recomendable que le indiquemos los campos que necesitamos puesto que por defecto te devolverá todos, cosa que en la mayoría de los casos no necesitaremos y además ahorraremos recursos.

La definición del método RetrieveRecord según la librería es el siguiente:

El primer y el segundo parámetro son el Id y entidad del registro que queremos recuperar. Es importante notar que el nombre de la entidad es el Nombre de Esquema (Schema name) que se escribe con mayúsculas/minúsculas según está definido en la solución.

El tercer parámetro son los campos que queremos recuperar. En este caso sería una cadena de texto con los nombres (de esquema) de los campos que queremos obtener, separados por comas.

Las dos ultimas, son las funciones Callback de Exito/Error que se ejecutarán si el registro se ha devuelto bien o si se ha encontrado algún error respectivamente.

Finalmente, como cuarto parámetro tenemos el Expand. El Expand es una cadena de texto donde se incluirán los nombres de las relaciones que queremos expandir siempre en referencia al registro que estamos pidiendo. Se podrán incluir relaciones 1:N y N:1. En cada caso obtendremos un objeto distinto como resultado.

Relaciones 1:N de la entidad Account

Relaciones 1:N de la entidad Account

Es interesante recalcar que con los Expands no se indican qué campos de la entidad expandida quieres, sino que te devuelve todos. Es por esto que aunque en la definición de la librería diga que se pueden hasta expandir 6 relaciones, en mi opinión no es nada recomendable puesto que te devolverá en una sola llamada un volumen muy grande de datos [ 1 registro padre + (N1 registros hijos relación 1 * M1 campos cada registro)  + (N2 registros hijos relación 2 * M2 campos cada registro) + …  ]. Si multiplicamos esto por cada usuario de CRM que esté trabajando podemos sobrecargar el sistema.

Expand con relación 1:N

Un ejemplo sería obtener una cuenta y además todos los contactos asociados a la cuenta. Como es lógico, cuando hacemos esto obtenemos 1 resultado padre, la cuenta, y N hijos, todos los contactos relacionados con esa cuenta. La petición y deserialización sería del siguiente modo:

Como vemos en la siguiente imagen, el objeto response que nos devuelve como parámetro en el SuccessCallBack tiene primero los campos pedidos en el Select del registro padre (cuenta) y además, colgando del objeto contact_customer_accounts.results tenemos un Array con cada uno de los resultados hijos (contactos) y todos sus atributos.

Estructura del objeto response en un Retrieve con Expand 1:N

Estructura del objeto response en un Retrieve con Expand 1:N

Para recorrer el array de respuesta lo haremos como en se muestra en el código superior, con un bucle For que recorra todos los results de la expansión.

Expand con relación N:1

Ahora, en el caso opuesto, vamos a expandir una relación N:1. Esto es, queremos el padre del registro que estamos solicitando. Como no puede ser de otra manera, en este caso solo esperamos que nos devuelva un resultado y no N como en el ejemplo anterior.

Siguiendo con el ejemplo anterior, vamos a expandir la relación de “Contacto principal” de una Cuenta.

El código quedaría algo del estilo:

En este caso, al disponer de un solo resultado en la expansión, se ahorra el results del objeto account_primary_contact dentro del objeto response.

Estructura del objeto response en un Retrieve con Expand N:1

Estructura del objeto response en un Retrieve con Expand N:1

Expand con relación N:N

Desconozco si es posible expandir una relación N:N pero todas las pruebas que he hecho no han funcionado. Si alguien sabe cómo hacerlo le agradecería que indicase cómo en los comentarios!

Mezclando expansiones

Como hemos indicado con anterioridad, es totalmente posible expandir varias relaciones en la misma petición (hasta 6) y por cada una de ellas obtendremos un objeto colgando del response con el nombre de la relación. Si es 1:N además éste contendrá un Array denominado results con todos los hijos del registro.


Para terminar, indicar con la extensión para Chrome HUDCRM, en la pestaña “Query constructor” podéis obtener todos estos códigos mostrados en el post de manera muy sencilla.

Ejemplo constructor de queries SDK.REST con la extensión para Chrome HUDCRM

Ejemplo constructor de queries SDK.REST con la extensión para Chrome HUDCRM

 

Parametros que se envian a Web Resource desde formulario

Cuando creamos un Web Resource desde el menú de edición del formulario de la entidad, podemos configurar que se envíen parámetros al mismo en la iniciación del formulario. Esto se consigue marcando la casilla “Pasar código tipo de objeto de registro e id. Único como parámetros”.

Configuración de Web Resource para pasar parámetros desde el formulario

Configuración de Web Resource para pasar parámetros desde el formulario

Cuando tenemos esta casilla activada durante la carga del Web Resource en nuestro formulario se invocará la URL y se añadirán algunos parámetros del contexto donde se está abriendo ese Web Resource. Esto es algo bueno puesto que mediante este contexto de información podremos desarrollar un Web Resource personalizado, por ejemplo, para el cliente que se esté viendo en ese momento.

Los parámetros que se envían por defecto cuando seleccionamos esta casilla son los siguientes:

# Parámetro Descripción
1 OrgLCID Id del código de lengua de la organización
2 UserLCID Id del código de lengua del usuario
3 Id Id del registro que estamos cargando
4 Orgname Nombre de la organización
5 Type Tipo de formulario.  0 = Undefined, 1 = Create, 2 = Update, 3 = Read Only, 4 = Disabled, 5 = Quick Create, 6 =  Bulk Edit, 11 = Read Optimized
6 Typename Nombre de la entidad donde se ha abierto el WR

Un ejemplo de URL completa para nuestro sería el siguiente:

new_prueba_web_resource?OrgLCID=3082&UserLCID=3082&id={42DCC3D2-7339-E611-80D6-C4346BAC8D78}&orgname=NuestraOrganizacion&type=2&typename=contact

El modo en el que podemos capturar estos parámetros desde nuestro javascript se ha indicado ya en este post antiguo. En este caso el proceso sería similar.

CRM también nos permite enviar parámetros personalizados introduciéndolos en el cuadro de texto que está encima del check indicado con anterioridad, en las propiedades del Web Resource. Si fuese este el caso, estos parámetros se enviarán a continuación de los ya indicados.

Podéis ver los parámetros que se han enviado a un Web Resource fácilmente con la extensión HUDCRM.

Obtener parámetros de carga de un web resource desde HUDCRM

Obtener parámetros de carga de un web resource desde HUDCRM

Variable window.IsUSD = true que introduce USD sobre el header

Una de las funcionalidades que más destaca del Unified Service Desk es la integración nativa con los formularios de CRM mediante la navegación a una URL de nuestra instancia. Además de esto, el USD nos permite por lo general navegar a cualquier otra dirección que deseemos mediante la UIIAction Navigate. Esto nos permitirá abrir aplicaciones web externas dentro de nuestro USD. ¿Es posible desde una aplicación web saber si la navegación se ha producido dentro de una pestaña del USD? La respuesta es sí: mediante la variable window.IsUSD.

El Unified Service Desk se toma la molestia de introducir en el Header de cada web que se carga un pequeño fragmento de código Javascript como el siguiente:

 

 

De modo que mediante el acceso a esta variable podremos saber si nuestra aplicación web -o nuestro Web Resource incrustado en un formulario de CRM- ha sido visitada desde un USD.

Variable IsUSD en el Header de Google

Variable IsUSD en el Header de Google

 

En el caso de que estemos navegando sobre un formulario de CRM, el USD también incluirá esta variable en el Header de los Iframes que contiene (Iframes normales o Webresources).

Variable IsUSD en el Header de Bing abierto en un Iframe de un formulario CRM

Variable IsUSD en el Header de Bing abierto en un IFrame de un formulario CRM

 

Variable IsUSD en el Header de un Web Resource de un formulario CRM

 

Pero, ¿en qué situaciones podríamos aprovecharnos de este hecho?

Las razones por las cuales necesites saber si un USD ha abierto tu aplicación web pueden ser muchas, pero existe un gran motivo por el cuál esa variable está ahí.

De modo nativo, el USD nos avisa de eventos generados en cualquier formulario. Un ejemplo sería un evento OnSave de un formulario. Este evento se envía al USD y éste lo recibe pudiendo generar con él una Action Call que derive en cualquier otra acción o ejecución de código. El método que utiliza CRM para “avisar” al USD de que en el formulario se ha producido un evento de guardado es mediante la ejecución de un comando Javascript del tipo:

 

Cuando el USD detecta que queremos navegar a una web del dominio event lo interpretará como que esa página web le está avisando de un evento y no realizará la navegación.

Y aquí está la clave de la variable IsUSD. Si incluimos una linea como la anterior en un Web Resource y abrimos el formulario desde un navegador y no desde el USD, el navegador ejecutará esa orden produciendo que la página navegue a esa “URL”. El resultado será que nuestro navegador nos abrirá una ventana de una página web totalmente ajena a nuestro proyecto y que por supuesto mostrará publicidad de cualquier tipo.

Esta aquí uno de los motivos por los cuales Microsoft ha incluido esta funcionalidad de inyectar sobre cualquier web una variable que nos avise de que la navegación se está produciendo desde USD y no desde otro navegador. Mediante la verificación de esta variable podremos ahorrarnos ejecutar esa orden de evento si la navegación está fuera del USD añadiendo a nuestro código la siguiente comprobación:

Con ello podremos controlar este hecho en nuestras aplicaciones web

Navegando en el mismo formulario con y sin USD

Navegando en el mismo formulario con y sin USD

 

Instalación Unified Service Desk en entorno CRM y PC

El Unified Service Desk es una herramienta que nos ofrece Microsoft para todos los usuarios de CRM que nos brinda la oportunidad de integrarnos con nuestro entorno desde una aplicación de escritorio, que además es 100% administrable desde nuestra configuración en CRM. En este post veremos como realizar la instalación en nuestro CRM.

La filosofía de USD es la siguiente: En tu PC tendrás instalada una DLL que incluya el código fuente de un Botón (por ejemplo), con su interfaz gráfica, su propiedades, métodos y eventos. Ahora bien, si quieres que en tu USD aparezca un botón tendrás que ir a CRM e indicarlo en la configuración definida para ti.
Cuando inicia el USD, siempre lo hará con las credenciales de un usuario (o agente) de CRM. Este agente, por lo general tendrá definido en su ficha de agente de CRM una configuración, y dentro de esa configuración en CRM estará definido un botón. Así pues, cuando abras el USD toda esta información relativa a tu configuración se descargará y se guardará en caché. Si en esa configuración (definida en CRM) se indica que tu USD tiene un botón, entonces USD te pintará un botón. Además ese botón tendrá todas las características que le hayas indicado en la propia configuración del botón en CRM como pueden ser su texto para mostrar, acciones asociadas, eventos, etc.

El ejemplo indicado trata de un botón pero existen muchos otros tipos de objetos que se definen desde CRM y que cambian el comportamiento del USD como pueden ser navegadores, paneles, barras de botones, imágenes etc.

Sobre esto podemos hablar y extendernos mucho, no obstante para este post nos interesa sólo saber que existen dos mitades que necesitan la una de la otra y que completan el USD: DLLs en nuestro PC y configuración en nuestro CRM.

Partes fundamentales USD instalación

Partes fundamentales USD instalación

Vamos entonces a instalar las dos partes. Lo primero de todo que necesitamos es descargarnos los paquetes de la página. Los paquetes necesarios son el PackageDeployer y la versión de USD que queramos instalar en nuestro PC (32 o 64bits).

Descargamos los paquetes y los descomprimimos.

Primero vamos a instalar el PackageDeployer. Este paquete lo que hará será instalar en nuestro CRM todas las entidades que son necesarias para definir los elementos del USD, además de sus relaciones, reglas, imagenes etc. Además nos creará los formularios en CRM para interactuar con la configuración de nuestro USD y poder definir cada uno de sus elementos.

Abrimos el archivo CRM2016-USD-2.1.0-PackageDeployer.exe.

Instalacion Package Deployer Step 1

Instalacion Package Deployer Step 1

Click en aceptar y Continue

Instalacion Package Deployer Step 2

Instalacion Package Deployer Step 2

Tendremos que seleccionar una carpeta donde extraer los archivos de instalación. En esta carpeta no se instalará nada, solo es una carpeta de extracción para la instalación.

Instalacion Package Deployer Step 3

Instalacion Package Deployer Step 3

Una vez que se termine de extraer se nos abrirá el instalador

Instalacion Package Deployer Step 4

Instalacion Package Deployer Step 4

En la siguiente pantalla nos pedirá un login. El proceso es distinto si nuestra instancia es online u onpremise. Si es el caso de una instalación onpremise el login debería ser parecido al de la siguiente imagen:

Instalacion Package Deployer Step 5. Login on premise

Instalacion Package Deployer Step 5. Login on premise

Por el contrario, si nuestro CRM es online solo debemos indicar nuestro usuario y contraseña, el mismo con el que nos logueamos en el portal de Microsoft

Instalacion Package Deployer Step 5. Login online

Instalacion Package Deployer Step 5. Login online

Una vez iniciada sesión nos pedirá que seleccionemos un tipo de instalación. Esta instalación es una instalación nueva de cero. Eso significa que en el CRM que queremos instalar el Unified Service Desk no hay ninguna otra versión previa instalada. Si fuese así, deberíamos de actualizar y no instalar de cero.

Instalacion Package Deployer Step 6. Selección tipo instalación

Instalacion Package Deployer Step 6. Selección tipo instalación

Aceptamos los términos de la licencia

Instalacion Package Deployer Step 7

Instalacion Package Deployer Step 7

Aceptamos en la siguiente ventana y comenzará la instalación

Instalacion Package Deployer Step 8

Instalacion Package Deployer Step 8

La primera parte de la instalación es recapitular toda la información que hemos introducido

Instalacion Package Deployer Step 9

Instalacion Package Deployer Step 9

La segunda parte, y la más larga, es la carga en el CRM de las soluciones con sus entidades, formularios y relaciones.

Instalacion Package Deployer Step 10. Instalando

Instalacion Package Deployer Step 10. Instalando

Este proceso puede durar varios minutos en función de tu conexión. Al final deberíamos tener algo como lo siguiente:

Instalacion Package Deployer Step 10. Instalación completada

Instalacion Package Deployer Step 10. Instalación completada

Una vez terminado esto, finalizamos la instalación

Instalacion Package Deployer Step 11

Instalacion Package Deployer Step 11

Una vez terminada la instalación podemos comprobar que se nos ha habilitado un menú en la barra superior de CRM, en el menú de configuración, donde podremos acceder a la configuración de USD.

Acceder al menú de configuración de Unified Service Desk desde CRM

Acceder al menú de configuración de Unified Service Desk desde CRM

Nota: Si no ha aparecido el botón es probable que sea porque tenías el CRM abierto durante la instalación. La barra superior de menús no se recarga al navegar entre formularios por lo que para que aparezca prueba a recargar la página entera mediante Control + F5.

Nota:  una vez terminada esta instalación podemos eliminar la carpeta de extracción que creamos en el segundo paso.

Ya tenemos la primera mitad del USD instalada. Ahora necesitamos que esta configuración de CRM sea efectiva en nuestra aplicación de escritorio.

Procedemos a instalar la segunda parte. Esta instalación deberá realizarse en todos y cada uno de los ordenadores en los que un usuario quiera acceder al CRM mediante el Unified Service Desk. También puede instalarse en un escritorio virtual VDI al que accederán distintos usuarios.

Abrimos el archivo CRM2016-USD-2.1.1-amd64.exe

Instalación Unified Service Desk. Step 1

Instalación Unified Service Desk. Step 1

Dejamos el directorio por defecto para la instalación

Instalación Unified Service Desk. Step 2

Instalación Unified Service Desk. Step 2

Para que Unified Service  Desk funcione correctamente es necesario tener también instalados el .NET Framework 4.5.2 y el Windows Identify Foundation. Ambos están incluidos en el instalador y si los seleccionamos nos los instalará antes del USD.

Instalación Unified Service Desk. Step 3

Instalación Unified Service Desk. Step 3

Comenzamos la instalación

Instalación Unified Service Desk. Step 4

Instalación Unified Service Desk. Step 4

Cuando termine esta instalación, de modo automático nos abrirá el Unified Service Desk. La imagen que se ve a continuación es la pantalla inicia del USD donde, pulsando sobre Cambiar credenciales nos permitirá configurar a qué CRM queremos que nuestro USD se conecte.

Ventana de inicio Unified Service Desk

Ventana de inicio Unified Service Desk

Las opciones de login son las mismas que en el Package deployer. Podemos conectarnos al CRM online u onpremise.

Ventana de login Unified Service Desk. On premise

Ventana de login Unified Service Desk. On premise

Ventana de login Unified Service Desk. Online

Ventana de login Unified Service Desk. Online

Una vez que introducimos los credenciales e iniciamos sesión el USD se quedará cargando y finalmente nos mostrará la ventana principal. Es en este periodo de carga después de iniciar sesión cuando se produce en background la operación de descarga de información del CRM donde hemos indicado, y descarga de configuración de nuestro agente para pintarnos la interfaz gráfica del modo indicado en el CRM.

Ventana principal Unified Service Desk

Ventana principal Unified Service Desk

Con esto ya tenemos nuestro USD operativo tanto en nuestro PC como en nuestro CRM.

Relacion entre datos cargados y entidad ImportFile

La funcionalidad que dispone CRM para importar archivos es bastante atractiva para los clientes que compran el producto. El poder cargar de modo automático grandes archivos de datos en la base de datos de CRM es una funcionalidad que se valora, sobre todo cuando el CRM es un sistema complementario a otros como podría ser un SAP, para tener los entornos alineados.

Lo único que es necesario configurar para automatizar la tarea de importación es un mapping de datos. Este mapping se tendrá que hacer con el primer archivo que se cargue y en él se indicará qué columnas del archivo Excel se cargarán en qué campos de la entidad de CRM. Posteriormente, el usuario de CRM únicamente tendrá que seleccionar el archivo que quiera importar y el mapping que se creó relativo a ese archivo. Como punto negativo únicamente decir que CRM admite de modo nativo importaciones de archivos con extensión CSV. Desde el propio Excel es relativamente sencillo exportar nuestro archivo con extensión .XLSX/.XLS a un archivo .CSV.

Desde el menú de Excel Guardar como podremos seleccionar la opción “CSV (delimitado por comas)” que nos generará el archivo con la estructura adecuada para Dynamics.

Exportar Excel como CSV

Exportar Excel como CSV

Para quien le interese el tema, si abrimos el archivo CSV con un editor de texto plano nos daremos cuenta que la estructura del propio archivo es muy simple, siendo la primera línea el nombre de las columnas separadas por punto y coma, y el resto los valores para cada columna, separados con el mismo carácter. Con esta estructura, no sería muy complicado escribir un programa que generase archivos CSV de cualquier base de datos, listos para importar en nuestro Dynamics.

Volviendo a la importación, una vez seleccionado el archivo y el mapping, el CRM empezará a cargar los datos. Nuestro trabajo terminaría aquí si únicamente nos interesase cargar los datos sin ningún tipo de procesado.
No obstante, no son pocos los clientes que se interesan por no solo cargar datos, sino también aplicarle algún tipo de lógica. Me viene a la mente por ejemplo una lógica de sustitución de un código cargado en el archivo por otro que esté ya en la base de clientes de CRM. O sencillamente relacionar cada registro cargado con un lookup a otra entidad mediante algún campo de identificación.

La idea de este post no es proponer una arquitectura de workflow o programa que aplique esta lógica puesto que en función de la cantidad de datos cargados se elegirá una u otra. El propósito de este post es descubrir de qué modo quedan relacionadas cada una de los registros creados en nuestra entidad con el archivo cargado.

Partimos por tanto de un dato conocido: el archivo cargado en la entidad ImportFile así como todos los datos asociados a él (número de líneas procesadas, fecha de inicio de carga, fecha de fin de carga, etc). Para complicarlo vamos a ponernos la restricción de que todos los archivos cargados van a la misma entidad. Sea cual sea el tipo de archivo se cargará en una entidad personalizada para la carga, escribiendo solo en unos campos en función del maping. El objetivo es conociendo únicamente el archivo de carga, obtener todos los registros creados en CRM a partir de él.

Logical name Schema name Label Type Descripción
importfileid ImportField Import Uniqueidentifier Id unico del registro
createdby CreatedBy Created By Lookup Usuario que cargo el file
completedon CompletedOn Completed On DateTime Fecha en la que se completó la importación
createdon CreatedOn Created On DateTime Fecha en la que se creó el registro
failurecount FailureCount Errors Integer Numero de lineas con error
partialfailurecount PartialFailureCount Partial Failures Integer Numero de lineas con error parcial
successcount SuccessCount Successes Integer Numero de lineas importadas correctamente
totalcount TotalCount Total Processed Integer Total de lineas (debería ser igual a la suma de los tres valores anteriores)
source Source Source String Nombre del file fuente
name Name Import Name String Nombre del registro en CRM. Coincide con el source
targetentityname TargetEntityName Target Entity String Entidad donde se cargarán los datos (en el ejemplo new_uploadentity)

Campos de la entidad ImportFile de CRM

Una primera idea sería obtener las fechas de inicio y final de carga del archivo y realizar un Retrieve Multiple de datos creados en ese intervalo de tiempo en nuestra entidad. Esta solución tiene un problema que es que funcionará siempre y cuando no se carguen dos –o más- archivos al mismo tiempo. Como lado positivo, esta es una query rápida que no requiere de joins y que si no mezclamos archivos al mismo tiempo obtiene buenos resultados.

Pero los usuarios no entienden de restricciones y si existe la posibilidad de importar files, seguro que más de una vez nos encontramos con que se solapan cargas. Para solucionar esto vamos a realizar una búsqueda de registros insertados en nuestra entidad partiendo del ID del archivo cargado.

Dynamics ha realizado un gran trabajo en este aspecto implementando un método de carga en paralelo a dos entidades. Por cada línea de nuestro archivo CSV se cargarán en CRM dos registros. El primero será siempre el registro que contiene la información de nuestros datos del Excel con el mapping aplicado en nuestra entidad de carga. Esta sería la importación misma. El segundo registro se almacena en la entidad ImportData. Este segundo registro no incluye información del archivo sino más bien información de la línea en bruto. Algunos datos que podemos encontrar en esta entidad son la posición de la línea en el file, los datos sin procesar de la línea o el ID de la línea en nuestra entidad de carga. Además en la entidad ImportData existe un campo lookup a la entidad ImportFile. El esquema de entidades sería el siguiente:

Relación entre entidad ImportFile, entidad ImportData y nuestra entidad de carga

Relación entre entidad ImportFile, entidad ImportData y nuestra entidad de carga

Como vemos, cuando cargamos un file se crea un registro en la entidad ImportFile que contiene la información de cabecera del file. En el proceso de importación, por cada línea del Excel se creará un registro en la entidad ImportData y otro registro en nuestra entidad de carga, en el esquema new_uploadentity.  El modo en que quedan relacionadas son que en el campo recordid del registro creado en ImportData  se incluye el id único del registro new_uploadentityId.

Ya tenemos todo para realizar la query y obtener los resultados. Las dos opciones que propongo son QueryExpression y Linq. Por mi parte recomiendo Linq puesto que no tiene la limitación de los 5000 registros recibidos.

En ambos casos la función nos devolverá los datos cargados en nuestra entidad new_UploadEntity dado el ID de un file de la entidad ImportFile.

En QueryExpression el código será similar a:

Si utilizamos Linq el código sería

En ambos casos he utilizado una clase de definición como la siguiente:

 

 

Cómo saber a que DLL corresponde un Hosted Control

Existe un método muy sencillo y que no requiere de ninguna instalación especial para conocer el namespace y el tipo de cada uno de los hosted controls que hay definidos en la configuración de USD en CRM.

Muchas veces necesitaremos en nuestro código hacer referencia a uno de estos objetos especiales para modificar algún atributo o para captar un evento. Estos ojbetos especiales son los que aparecen listados en la configuración de USD cuando creamos un nuevo hosted control, en el campo USD Component Type.

Tipos de hosted controls predefinidos

Tipos de hosted controls predefinidos

Como ya hemos visto en otras entradas a veces necesitamos hacer referencia a alguno de estos objetos (en esta entrada al Debugger por ejemplo). Para capturar la instancia del objeto necesitamos dos cosas: el nombre del hosted control y el tipo. El nombre es el que elijamos en la configuración del USD en CRM. El tipo es en principio desconocido.

Bien pues vamos a ver cómo consultar el tipo de la manera más sencilla. Lo primero de todo es irnos a la configuración del USD en CRM y crear un nuevo hosted control (como en la imagen de arriba).

Luego en el desplegable de USD Component Type seleccionamos el objeto que queremos averiguar. En nuestro caso queremos averiguar por ejemplo la DLL y el tipo del objeto Debugger:

Selección de Hosted Control Debugger

Selección de Hosted Control Debugger

A continuación lo único que deberemos hacer es volver a pinchar sobre el campo USD Component Type y seleccionar la opción USD Hosted Control. Como veremos cuando hagamos esto, aparecerán debajo dos campos: Assembly URI y Assembly Type. Además aparecerán rellenos con el tipo del objeto que hayamos seleccionado en primer lugar (en nuestro caso el objeto Debugger).

Selección de USD Hosted Control

Selección de USD Hosted Control

Una vez que conocemos el tipo, en nuestro Custom Hosted Control podremos obtener la instancia del objeto del siguiente modo:

Con esto ya somos capaces de modificar cualquier atributo de la instancia cargada en nuestro USD de este objeto.

El motivo por el que ocurre esto es que al seleccionar cualquier tipo especial en el campo USD Component Type los campos Assembly URI y Assembly Type se auto rellenan y además se ocultan. El fallo está en que al cambiar el desplegable no se resetean estos valores.

Web Resources dinámicos: Pasar y recibir parámetros

Los Web Resources son elementos que se sitúan en los formularios y que dan libertad al desarrollador de introducir páginas webs externas dentro del contexto de un formulario de CRM. Son muy útiles puesto que a menudo el alcance de un formulario de CRM se queda corto para implementar soluciones específicas que cumplan los requerimientos del cliente.

Con el Web Resource podemos introducir lógica propia a un formulario, interactuar con el formulario o con el resto del CRM mediante código Javascript. Una de las cosas buenas que tiene CRM es que podemos crear un HTML flexible, subirlo como un Web Resource y utilizarlo en distintos formularios de entidades. Además como veremos a continuación podemos incluir parámetros de entrada en cada uno de los Web Resources que insertemos para personalizar el contenido.

Lo primero que tenemos que hacer es preparar el HTML que formará el Web Resource. Recordad que a CRM se pueden subir Web Resources con los siguientes formatos:

Tipos de Web Resources permitidos CRM

Para el ejemplo crearemos una web en HTML con algunas funciones Javascript. En particular la idea para empezar es crear una web que en función del parámetro que se le pase cambie el color del fondo del HTML.

En el ejemplo tenemos dos funciones: la primera cambiarColorFondo(color) establece el color de fondo de la página que se le pase por parámetro (con formato #AABBCC).

La segunda, parametrosGet() obtendrá la lista de parámetros que se pasen al Web Resource y los recorrerá uno a uno comprobando el nombre y el valor. Cuando el nombre sea igual a color se ejecutará el cambio de color de fondo con el valor pasado por parámetro.

Al final del código Javascript ejecutamos la función parametrosGet() para comenzar el proceso en el OnLoad de la página.

Una vez escrito el código lo subimos a la solución como Web Resource de tipo Webpage (HTML) y publicamos.

Una vez hecho esto ya podemos insertar nuestra web dinámica en cualquier formulario de CRM. Para ello editamos el formulario de cualquier entidad y accedemos a Insertar -> Web resource. La configuración de nuestro Web Resource deberá parecerse a la de la imagen:

Propiedades Web Resource

En la casilla Web Resource debemos seleccionar nuestro HTML que deberemos haber subido previamente. Es importante seleccionar el Check “Pass record object-type code and unique identifier as parameters”. Con esto nos garantizamos que el parámetro se transfiere a nuestra web para poder capturarlo con la función parametrosGet().

Finalmente personalizamos los “Custom Parameters(data)” con el color que deseemos. Si se deseasen incluir más parámetros la estructura que debería seguir esta cadena sería param1=valor1&param2=valor2&param3=valor3

Si insertamos varios Web Resources en nuestro formulario personalizando cada uno con un color distinto obtendríamos lo siguiente:

Web Resources dinámicos en un mismo formulario

Aunque el cliente nunca nos pedirá una web con distintos colores de fondo, este ejemplo nos muestra cómo reutilizar un mismo Web Resource para distintos entornos o formularios. Las posibilidades son infinitas y aún se multiplican más cuando el parámetro que se envía es el ID del registro de CRM. Este ejemplo lo explicaremos en otra entrada del blog.

Option Set: Obtener Label/Etiqueta en C#

Obtener la etiqueta de un Option Set de una entidad de CRM por código C# no es trivial. Para ello podemos utilizar dos métodos como veremos a continuación: descargar el meta o utilizar la propiedad formattedvalues

Lo que en otros lenguajes y entornos es conocido como ComboBox en CRM se le denomina Option Set. Se trataría de un desplegable de opciones disponibles que puede adoptar como valor un campo de un formulario.

La estructura de este tipo de campo constaría de una lista de parejas denominadas Label y Value. El Label correspondería a la etiqueta visible que se muestra en el formulario. Esta etiqueta será  con la que el usuario de CRM deberá interactuar y en general será de tipo String.

Además, por detrás, tenemos el Value. Esta variable identifica de modo único cada una de las opciones disponibles en el Option Set. No podrá haber dos Values iguales en el mismo Option Set puesto que este valor es el que se utiliza como clave primaria para la lógica que corre por detrás.

Campo Option Set CRM

Campo Option Set CRM

Por defecto CRM insertará los Values siguiendo una serie de reglas internas como que el prefijo sea único para cada solución. En general este dato no deberá preocuparnos y si nuestro trabajo termina en crear el formulario nos dará igual el valor de este campo aunque siempre podremos actualizarlo al valor que deseemos -cumpliendo que este valor entero sea único-.

Una aplicación en donde deberíamos cambiar los Values generados por CRM sería por ejemplo un listado de prefijos de teléfonos. En este caso sí que convendría actualizar cada item con su determinado valor (España – 34, Italia – 39, etc). En general se deberá de crear la correspondencia de Label – Value en función del alcance de nuestro desarrollo.

El motivo por el cual es bueno realizar esta correspondencia es que si accedemos mediante C# al valor de un Option Set obtendremos por defecto el Value, y no el Label. Para muchas aplicaciones con el Value será suficiente, pero para otras necesitaremos también conocer el Label del campo. Para acceder a este valor normalmente se utilizan dos métodos

El primero -y más lento- sería descargar previamente el Option Set que se desea analizar y guardarlo en un diccionario. A continuación se accederá al Value del campo en cuestión y se cruzará el valor obtenido con el diccionario obteniendo el Label correspondiente.

 

La segunda opción -más rápida- sería obtener directamente el Label del Option Set mediante la propiedad FormattedValues.

Ambas tienen sus pros y sus contras y en función de la aplicación que se esté desarrollando el programador deberá escoger cual le conviene más.

Las librerías necesarias para los objetos mostrados en los ejemplos se encuentran en la SDK 2015 de CRM. En particular hemos utilizado: