miércoles, 27 de abril de 2016

Integraciones Con Dynamics Crm 2015, 2016 Y Colas de Azure Service Bus


Hola querido lector, el día de hoy quiero presentar un tema que me emociona demasiado.

En la mayoría de proyectos que desarrollamos en nuestro día a día, siempre existe la necesidad de llevar información a otros sistemas para múltiples fines. Ya sea para mantenerla en sincronía e integra, ejecutar operaciones transaccionales, cambio de estados y miles de reglas de negocio que puedan surgir en el desarrollo de un proyecto.

El día de hoy quiero mostrarles cómo utilizar el Service Bus de Microsoft Azure, una excelente herramienta que nos permite de hacer  múltiples escenarios de integraciones que cubren muchas de las necesidades con las que nos topamos día a día.


Para seguir  este paso a paso debes contar con lo siguiente:

  • PowerShell de Microsoft Azure
  • Cuenta de Microsoft Azure
  • Dynamics CRM Online
  • Visual Studio
  • SDK Crm 2016


Nota: El Powershell de azure lo puedes instalar a través de Web Platform installer.
Instalación de powershell desde web platform installer


Una vez tengamos estos elementos, haremos lo siguiente:

Primero y antes que nada me gustaría compartir la arquitectura de integración de Dynamics CRM con Azure Service Bus, en la siguiente imagen se ve como es la integración:

Arquitectura de integración Dynamics CRM y Service Bus tomado de MSDN Microsoft

  • En la imagen # 1 hay un cliente que está escuchando y procesando los mensajes que hay en una cola de service bus llámese  aplicación de consola, Servicio de windows, Biztalk o alguna tecnología similar.
  • En la Imagen # 2 vemos a un usuario que interactúa con Dynamics CRM y dispara una acción (create, update, delete ... etc).
  • En la Imagen # 3 vemos el contexto que viaja y es almacenado en una cola de Service bus



Todo este proceso es el que vamos a implementar a continuación, como primer paso, procedemos a crear en Azure el bus de servicios. Antes de hacerlo hay que tener algo en cuenta que es muy importante. El asistente de Azure para crear el service bus, viene con un tipo de autenticación diferente a Access Control Service (ACS), que no es compatible con la implementación que realizaremos. Es por eso que como primer paso, vamos a autenticarnos en la consola de azure para poder realizar esta implementación por medio de consola, entonces procedemos a ejecutar como administrador el powershell de Azure.

Importante: Antes de iniciar con este paso, en mi caso tuve problemas con el proxy de la compañía, ya que no me permitía ejecutar completamente los comandos, si este es tu caso, solicita los permisos apropiados o intenta con una red que no tenga este bloqueo, y espero esto te sirva de referencia porque suele pasar en muchos casos.



Luego de estar autenticados, la consola nos confirmará mostrando los datos que tengo tachados en esta imagen.

Una vez autenticados, procedemos a crear el Service Bus por medio del Power shell con el siguiente comando:




La consola nos confirmará mostrando los datos de la cola que ha sido creada


Aquí hemos terminado el uso de PowerShell y lo que vamos a realizar en este momento es la creación de una cola que almacenará todos los contextos de ejecución que necesitemos en caso de integración, para esto ingresamos al portal de Azure y hacemos la creación de una cola.


En este caso para crear la cola, entra al service bus que ya ha sido creado,


Y en la opción de abajo haga clic en la opción Nuevo:

Una vez hagas clic en esta acción, se muestra el siguiente menú, en cual ingresarás la información solicitada.


Al hacer clic en crear una nueva cola, se creará la cola que utilizaremos


El siguiente paso es conectar Dynamics con esta cola, para ello vamos a configurar por medio del SDK un extremo de servicio, Autenticados en la herramienta plugin registration tool, que está contenida en la carpeta SDK\Tools\PluginRegistration del SDK. Realizaremos los siguientes pasos:

En la parte superior del plugin registration tool, utilizamos la opción Register, y seleccionamos Register new service EndPoint:


En los datos solicitados, ingresaremos en este caso, un nombre para nuestra integración, una descripción, un Namespace que en este caso es el nombre de nuestro service bus que en mi caso es integracioncrmig, el path es el nombre de la cola que creamos, el contrato como vamos a utilizar una cola en este caso seleccionamos persistentQueue y el resto lo dejaremos tal cual, a continuación una imagen:

Configuración de extremo de servicios


 Una vez ingresemos la configuración inicial, vamos a presionar el botón Save & Configure ACS, y se nos abrirá una pantalla solicitando alguna información la cual es muy importante para que se haga el proceso de autenticación, en este caso el Management key, se encuentra en el Service Bus de azure, en las siguientes imágenes se observa cómo obtener dicha key:

Hacer clic a Información de conexión

Conexión

En el campo Management Key pegamos el valor de "Clave predeterminada" mostrado en la anterior imagen, en Certificate File, seleccionamos un certificado que encontraremos en Dynamics CRM en el área de personalizaciones:

Área de personalizaciones Dynamics
Y luego ingresamos a Herramientas de desarrollador:

Herramientas de desarrollador
Estando allí, en la parte inferior, podemos ver que hay un área especial para conexiones con service bus, en este caso nos provee un Issuer Name y un link para descargar el certificado.


Procedemos a descargar el certificado a nuestro equipo local y lo seleccionamos, y en el campo Issuer Name, ingresamos el que nos proporciona Dynamics.

Configuración ACS

Hacemos clic en Configure ACS, y él nos confirmará que todo quedó bien:

Verificación de configuración
Una vez creada esta configuración, tenemos un Service endpoint al cual le podemos registrar pasos tal cual como si fueran un plugin:


EndPoint Creado

En mi caso registraré un paso en el evento Create del contacto y otro en el Update de contacto, para que a medida que vayan actualizando esos registros, estos se encolen y sean procesados por una aplicación de consola:
Pasos registrados

Así quedaría mi endpoint con los dos pasos:

Pasos registrados

Finalmente, en la carpeta del SDK, contamos con unas aplicaciones de consola de ejemplo que nos serán de utilidad para leer la cola de Azure y procesar el mensaje, la ruta de esta solución de ejemplo es SDK\SampleCode\CS\Azure y en esta solución de visual Studio, utilizaremos un proyecto llamado PersistentQueueListener.

Para leer los mensajes de la cola, hay que configurar algunas cosas:

En el app.config, hay una key llamada "Microsoft.ServiceBus.ConnectionString", esta deberá ser reemplazada por la cadena de conexión que está en el service bus de azure:

Cadena de conexión Azure

Así mismo, en el código fuente de la clase, hice un par de modificaciones:

En las variables del método consumer, puse los siguientes valores:

string serviceNamespace = "integracioncrmig"; // Es el nombre del bus de servicios
string issuerName = "owner"; // Es el emisor predeterminado
string issuerSecret = "ClavePredeterminada";// Es la clave predeterminada


En el método ProcessMessages de la misma clase, añadí la siguiente lógica para que leyera los eventos del create y update del contacto: 




Con esto ya listo y la aplicación de consola corriendo, al crear un contacto o actualizarlo, ya podré ver los contextos registrados en la cola:


Al guardar el contacto, se llevará todo el contexto de esa transacción hasta la cola:

Vista de cola en Azure

Finalmente nuestra consola estará en capacidad de procesar los mensajes almacenados en la cola:



En conslusión, Dynamics CRM ofrece sólidas posibilidades de integrar su información de una manera muy fácil y en pocos pasos. permitiendo así reducir los costos de tiempo y dinero al momento de pensar en integrar o de idearse un mecanismo seguro de integración.

Los invito a que hagan su propio experimento y me cuenten como resultó.

miércoles, 30 de marzo de 2016

AssignRequest en Dynamics CRM

Hace mucho tiempo no escribía en este blog, y hoy quiero retomar un poco temas de Microsoft Dynamics CRM ya que es en lo que enfoco la mayor parte de mi trabajo.

Hoy vamos a hablar un poco de la asignación de registros en Dynamics y la importancia de realizar dicha asignación de registros de una manera adecuada en este caso con el "AssignRequest".

Primero que nada, expliquemos que es una asignación de registros en Dynamics CRM para aquellas personas que apenas se están iniciando en el mundo de Dynamics.  Una asignación de registros, es el mecanismo por el cual Dynamics controla y brinda propiedad de acceso uno o varios  registros a usuarios o equipos, con el fin de que dichos usuarios o los usuarios que estén incluidos en los equipos tengan acceso a dichos registros por medio de los roles que tengan asignados. de esta manera, Dynamis evita que tengamos que realizar algún tipo de codificación para que el usuario no tenga acceso indebido a estos registros.

La asignación de registros únicamente es válida para aquellas entidades que sean creadas o que vengan pre configuradas en Dynamics como entidades de propiedad"Usuario o Equipo" como se muestra en el siguiente pantallazo:

Propiedad (Definición de la entidad)

Algo importante a destacar cuando creamos una entidad de propiedad usuario o equipo, es que se crea unpermisos especial a nivel de rol sobre esta entidad llamado "Asignar". Lo siguiente que ocurre es que en la definición de la entidad se crea unos atributos invisibles llamados "OwningBusinessUnit" y "OwningUser", que corresponden a la unidad de negocio del propietario y al usuario propietario respectivamente. Y se crea un atributo llamado Ownerid, que es el usuario propietario. Este último es visible.

Dicha asignación de acuerdo a los roles que posea el usuario autenticado en el sistema, podrán reflejar comportamientos de Visualización, Modificación, Eliminación Asignación, Anexar y Anexar a.

La asignación de registros se puede ejecutar de manera visual por las opciones que trae Dynamics de fábrica. aunque en algunas ocasiones, estas acciones también pueden ser lanzadas a través de extensiones tales como Plugins, Javascripts o llamando el Organization Service.

Cuando hacemos la asignación de manera visual no existe inconveniente alguno,  Pero.......... que ocurre cuando hacemos una asignación de un registro en Dynamics CRM por medio de un mecanismo de extensión?.

La manera correcta de hacer la asignación de un registro por medio de un mecanismo de extensión como por ejemplo un plugin, es realizando un AssignRequest como se muestra en el siguiente código de ejemplo:

Pero muchas veces lo realizamos haciendo una asignación directa al atributo owner y haciendo un service.update a la entidad.

Cuando lo hacemos de la manera que acabo de mencionar ocurren varias cosas incorrectas:

  • Únicamente cambia el atributo ownerid: No se actualiza el atributo OwningBusinessUnit, impidiendo el acceso al registro al usuario que lo tiene asignado. Muchas veces me pasaba que realizaba la asignación por medio del Update y el usuario que tenía asignado el registro lo podía abrir pero no editarlo. y esto era porque la unidad de negocio que había en el atributo OwningBusinessUnit, no correspondía con la del usuario propietario del registro.
  • No se ejecuta el mensaje Assign :  Si hay extensiónes que se ejecutan bajo el mensaje "Assign", estas no serán ejecutadas. se ejecutará en cambio un mensaje Update.
Por ende, como conclusión y buena práctica, recomiendo que se haga la asignación con el AssignRequest, ya que con este fin fué creado, este request puede ser ejecutado desde un plugin, Custom Activity Workflow, Javascript e Invocación al OrganizationService así que no tendremos ningún impedimento a la hora de utilizarlo.

Mil gracias por tomarte el tiempo y leer este contenido. si tienes alguna anotación adicional o algo que consideres que puedo mejorar en esta redacción, no dudes en escribirme. la finalidad de este blog es tener un espacio donde se genere conocimiento.

jueves, 28 de noviembre de 2013

Conjunto de javascripts más comunes para Dynamics CRM 2011 (SNIPPETS PARA VISUAL STUDIO)

Hola Amigos lectores, el día de hoy les voy a publicar un conjunto de funciones Javascript que se utilizan día a día en CRM, Adicional a esto traigo un conjunto de snippet's que pueden ser utilizados desde Miscosoft Visual Studio .Net que nos servirán para brindarnos una serie de atajos a la hora de programar estos  javascripts (Dichos Snippet's los podrás encontrar al final del post).

Quiero agradecer a Juan Carlos Ortiz Cordoba (Ingeniero de desarrollo de Software) quien me ha brindado algunos snipet's y además la iniciativa de crear unos propios.

Todas estas funciones han ido surgiendo de acuerdo a las buenas prácticas que he ido encontrando en el camino y en las funciones que realizo a continuación; siempre valido que el campo al que accedo sea diferente de null con el fin de no obtener errores en los script.

Ahora si; luego de esta larga introducción voy a publicar algunas funciones comunes para CRM:

1. Obtener valor del campo

var campo = Xrm.Page.getAttribute("NombredelCampo");

if(campo != null)
{
  variable = campo.getValue();
}

2. Asignar el valor del campo

var campo = Xrm.Page.getAttribute("NombredelCampo");

if(campo != null)
{
  campo.setValue("ValorDeseado");
}

3. Hablilitar o deshabilitar un campo

var campo = Xrm.Page.getControl("NombredelCampo");

if(campo != null)
{
  // Cambiar true o false según el valor deseado.
  campo.setDisabled(false);
}

4. Mostrar u Ocultar un campo

var campo = Xrm.Page.getControl("NombredelCampo");

if(campo != null)
{
  // Cambiar true o false según el valor deseado.
  campo.setVisible(true);
}

5. Obtener el valor de la etiqueta de un option Set

var campo = Xrm.Page.getAttribute("NombredelCampo");

if(campo != null)
{
  // Cambiar true o false según el valor deseado.
  variable = campo.getSelectedOption().text;
}

6. Obtener el valor de la etiqueta de un option Set

var campo = Xrm.Page.getAttribute("NombredelCampo");

if(campo != null)
{
  // Cambiar true o false según el valor deseado none, recommended, required.
  variable = campo.setRequiredLevel(“none”);
}

7. Mostrar u Ocultar un Tab por nombre

        var tabs = Xrm.Page.ui.tabs.get();
        for (var i in tabs) {

            // Se asigna el objeto tab
            var tab = tabs[i];

            // Validamos si es la ficha de viabilidad técnica
            if (tab.getName() == "NombreDelTab") {
                // Cambiar de acuerdo a la necesidad.
                tab.setVisible(false);
            }
        }

A continuación presento un listado de snippets que he creado en conjunto con Juan; muchas de estos snippets facilitarán las labores del día a día a la hora de realizar métodos de extensión Javascript para Microsoft CRM Dynamics.



Para comenzar a usar los snippet en Visual Studio debemos descargar el siguiente elemento:


extraemos los archivos en la ruta de snippets de visual studio (En el archivo Acerca de contenido en el adjunto podrá visualizar la ruta) y una vez instalados estos snippets solo bastará con abrir un archivo o crear un archivo tipo javascript y escribir el atajo de nuestro snippet, en el código escribimos la palabra CRM y el intellisense nos sugiere los nuevos snippets instalados como podemos ver en la imagen:




Bastará com presionar dos veces la tecla TAB y se completará el código




Ya solo bastará completar el resto de código y como podemos observar se nos ha facilitado escribir algunas liniecillas de codigo.

Agradezco mucho a todos sus opiniones y sugerencias, no soy un blogger profesional pero estamos para mejorar y compartir lo más libre del mundo, el conocimiento.

A todos mis lectores muchas gracias y hasta la próxima publicación.

jueves, 21 de noviembre de 2013

State and Status Codes Microsoft Dynamics CRM 2011

Hola lectores, Actualmente me encuentro trabajando con proyectos de Microsoft Dynamics  CRM 2011.

A causa de esto me he encontrado con bastantes puntos de diseño en la parte de extensión que involucran el cambio de estado y razón para el estado en la entidad, es por esto que he decidido tener como base esta tabla, ya que me ha servido bastante y comparto con ustedes.




Entidad
Status (statecode)
Status Reason (statuscode)
Account (account)
0 Active
1 Active
1 Inactive
2 Inactive
Activity (activitypointer)
0 Open
1 Open
1 Completed
2 Completed
2 Canceled
3 Canceled
3 Scheduled
4 Scheduled
Appointment (appointment)
0 Open
1 Free
2 Tentative
1 Completed
3 Completed
2 Canceled
4 Canceled
3 Scheduled
5 Busy
6 Out of Office
Article (kbarticle)
1 Draft
1 Draft
2 Unapproved
2 Unapproved
3 Published
3 Published
Campaign (campaign)
0 Active
0 Proposed
1 Ready To Launch
2 Launched
3 Completed
4 Canceled
5 Suspended
Campaign Activity (campaignactivity)
0 Open
0 In Progress
1 Proposed
4 Pending
5 System Aborted
6 Completed
1 Closed
2 Closed
2 Canceled
3 Canceled
Campaign Response (campaignresponse)
0 Open
1 Open
1 Closed
2 Closed
2 Canceled
3 Canceled
Case (incident)
0 Active
1 In Progress
2 On Hold
3 Waiting for Details
4 Researching
1 Resolved
5 Problem Solved
2 Canceled
6 Canceled
Case Resolution (incidentresolution, notcustomizable)
0 Open
1 Open
1 Completed
2 Closed
2 Canceled
3 Canceled
Contact (contact)
0 Active
1 Active
1 Inactive
2 Inactive
Contract (contract)
0 Draft
1 Draft
1 Invoiced
2 Invoiced
2 Active
3 Active
3 On Hold
4 On Hold
4 Canceled
5 Canceled
5 Expired
6 Expired
Contract Line (contractdetail)
0 Existing
1 New
1 Renewed
2 Renewed
2 Canceled
3 Canceled
3 Expired
4 Expired
Currency (transactioncurrency)
0 Active
0 Active
1 Inactive
1 Inactive
Discount (discounttype)
0 Active
100001 Active
1 Inactive
100002 Inactive
E-mail (email)
0 Open
0 Draft
8 Failed
1 Completed
2 Completed
3 Sent
4 Received
6 Pending Send
7 Sending
2 Canceled
5 Canceled
Fax (fax)
0 Open
0 Open
1 Completed
2 Completed
3 Sent
4 Received
2 Canceled
5 Canceled
Invoice (invoice)
0 Active
1 New
2 Partially Shipped
4 Billed
5 Booked (applies to services)
6 Installed (applies to services)
1 Closed (deprecated)
3 Canceled (deprecated)
7 Paid in Full (deprecated
2 Paid
100001 Complete
100002 Parial
3 Canceled
100003 Canceled
Lead (lead)
0 Open
1 New
2 Contacted
1 Qualified
3 Qualified
2 Disqualified
4 Lost
5 Cannot Contact
6 No Longer Interested
7 Canceled
Letter (letter)
0 Open
1 Open
2 Draft
1 Completed
3 Received
4 Sent
2 Canceled
5 Canceled
Marketing List (list)
0 Active
0 Active
1 Inactive
1 Inactive
Opportunity (opportunity)
0 Open
1 In Progress
2 On Hold
1 Won
3 Won
2 Lost
4 Canceled
5 Out-Sold
Order (salesorder)
0 Active
1 New
2 Pending
1 Submitted
3 In Progress
2 Canceled
4 No Money
3 Fulfilled
100001 Complete
100002 Partial
4 Invoiced
10003 Invoiced
Phone Call (phonecall)
0 Open
1 Open
1 Completed
2 Made
4 Received
2 Canceled
3 Canceled
Price List (pricelevel)
0 Active
100001 Active
1 Inactive
10002 Inactive
Product (product)
0 Active
1 Active
1 Inactive
2 Inactive
Quote (quote)
0 Draft
1 In Progress
1 Active
2 In Progress
3 Open
2 Won
4 Won
5 Out-Sold
3 Closed
5 Lost
6 Canceled
7 Revised
Service Activity (serviceappointment)
0 Open
1 Requested
2 Tentative
1 Closed
8 Completed
2 Canceled
9 Canceled
10 No Show
3 Scheduled
3 Pending
4 Reserved
6 In Progress
7 Arrived
Task (task)
0 Open
2 Not Started
3 In Progress
4 Waiting on someone else
7 Deferred
1 Completed
5 Completed
2 Canceled
6 Canceled



Adicional a esto, en mis plugin de CRM utilizo esta función genérica para cambiar el state y status code en cierta entidad:


En los Using

using System;

using Microsoft.Crm.Sdk.Messages;

using Microsoft.Xrm.Sdk;

La variable que ejecuta el request

IOrganizationService service;

El Código

public void CambiarStateyStatusEntidad(string nombreEntidad, Guid idRegistro, int stateCode, int statusCode)

        {
            // Cambiar el estado
            var setStateRequest = new SetStateRequest
                                      {
                                          EntityMoniker =
                                              new EntityReference
                                                  {
                                                      Id = idRegistro,
                                                      LogicalName = nombreEntidad
                                                  },
                                          State = new OptionSetValue(stateCode),
                                          Status = new OptionSetValue(statusCode)
                                      };
            this.service.Execute(setStateRequest);
        }



La tabla la he encontrado en este Blog y agradezco enormemente al autor por realizar esta compilación.