Peticiones SOAP con AngularJS en CRM Dynamics

Soap request con AngularJS en Microsoft Dynamics CRM

La librearía AngularJS nos proporciona un potente framework de herramientas y procedimientos con los que implementar páginas web basadas en MVC. Toda esta funcionalidad se puede también utilizar dentro de nuestros recursos web –web resources- en CRM. En este post vamos a ver cómo implementar llamadas Soap con AngularJS y encadenar respuestas con los objetos promises.

Como sabemos, cuando se hace una query a CRM desde el frontal web utilizando la API debemos trabajar con funciones Callback –ya sea para peticiones utilizando la librería SDK.Rest o peticiones Soap a través del Organization Service- y en determinadas ocasiones, cuando tenemos que encadenar varias queries una detrás de otra el modo común de realizarlo es anidando Callbacks:

Con la librería AngularJS, los objetos promises que veremos a continuación y los servicios “$http” y “$q”, este ejemplo anterior se transformaría en algo del estilo:

Como vemos, el código queda más limpio en el segundo caso. Además de dejar el código más bonito la librería angular nos ofrece una mayor libertad para controlar procesos asíncronos permitiéndonos acceder al proceso de carga o ejecutando varias peticiones en paralelo.

Recordemos que para realizar una llamada Soap necesitamos tres cosas: la URL del endpoint, la acción que vamos a utilizar, y el cuerpo del mensaje. Con estas tres cosas podemos realizar la petición Soap con AngularJS.

Para construir la llamada utilizaremos el servicio “$http” de Angular como se muestra en el ejemplo.

La propiedad data del objeto response en el primer then del método RequestData contendrá el resultado de la petición. En este caso el cuerpo del mensaje es una petición de RetrieveMultiple con un filtro y nos devolverá las cuentas cuyos nombres empiecen por “A”. Recordar que esta es una respuesta http y por defecto el endpoint de CRM que estamos atacando nos devolverá mensajes serializados en XML -no es posible cambiar la respuesta a JSON como sí permite la API REST OData-. Para deserializar el XML podemos recurrir a herramientas externas o implementar nuestro propio deserializador utilizando la versión reducida de jQuery que trae angular, analizando los nodos. Yo he utilizado como base este ejemplo con una pequeña modificación.

El resultado de la ejecución nos mostraría un array de todos los Ids de las cuentas que empiezan por “A” en nuestro CRM.

Ids de todas las cuentas de CRM que empiezan por “A”

Pero donde realmente se puede sacar partido a esta librería es en el uso del servicio “$q”. Este servicio nos permite añadirle N objetos promesa y ejecutarlo. El código que esté dentro del then sucesivo se ejecutará cuando todas las peticiones hayan terminado y nos devolverá N respuestas, una para cada una de las peticiones ejecutadas. Esto es una gran noticia puesto que nos avisará cuando todas las peticiones tengan respuesta, y no se ejecutará cada vez que termine una de ellas. Así permitirá controlar el flujo de información de nuestro código de una manera mucho más limpia y clara.

Siguiendo con el ejemplo anterior, imaginemos que después de obtener todas las cuentas que empiecen por “A”, para cada una de ellas queremos obtener el nombre de todos los contactos asociados a esas cuentas.

El resultado de esta ejecución nos proporcionaría el siguiente array de nombres:

Nombres de todos los contactos que pertenecen a alguna de las empresas del ejemplo anterior

Nombres de todos los contactos que pertenecen a alguna de las empresas del ejemplo anterior

Estos son sólo dos ejemplos de lo que esta librería puede ofrecernos en CRM Dynamics  pero realmente las posibilidades son infinitas cuando juntamos peticiones Soap con AngularJS.

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

 

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.