viernes, 17 de enero de 2014

AngularJS en Dynamics CRM 2013

image
Imagino que casi todos ya lo conocen, y muchos ya lo utilizamos hace algún tiempo. AngularJs es un framework de javascript que permite trabajar con modelos MVC (Modelo Vista Controlador) de forma fácil y rápida.
La verdad que el mundo del javascript esta pegando los últimos años unas mejoras y expansión espectacular, y lo bueno de todo esto, es que Dynamics CRM está apoyado en todo esto y nos permite aprovecharnos de todo lo nuevo.
Lo que voy a hacer hoy es una especie de “Hola mundo”, aprovechando lo siguiente:
  • AngularJS (con su NGGrid)
  • jQuery
  • Ejemplos en javascript de la SDK de CRM
La idea funcional es mostrar en un Dashboard de CRM (Panel), un web resource, que recoja datos de CRM y mediante AngularJS, me cree un grid, con funcionalidades como agrupar, ordenar, etc.
Lo que finalmente obtengo es lo siguiente, un grid de Cuentas, con sus ciudades, y la posibilidad de ordenar y agrupar haciendo drag & drop, todo esto en un web resource dentro de un dashboard:
image
image
Como lo hice, es bastante sencillo. Primero empiezo con un web resource de tipo HTML con el siguiente código:
<html ng-app="myApp">  
    <head lang="en">
        <meta charset="utf-8">
        <title>CRM con AngularJS</title>  
        <link rel="stylesheet" type="text/css" href="new_nggrid.min.css" />
        <link rel="stylesheet" type="text/css" href="new_style.css" />
        <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
        <script type="text/javascript" src="new_jquery2.0.3.min.js"></script>
        <script type="text/javascript" src="new_jqueryui1.9.1.custom.min.js"></script>
        <script type="text/javascript" src="new_angular.min.js"></script>
        <script type="text/javascript" src="new_nggrid2.0.7.min.js"></script>
        <script type="text/javascript" src="new_SDK.REST.js"></script>
        <script type="text/javascript" src="new_script.js"></script>
    </head>
    <body ng-controller="MyCtrl">    
        <div class="gridStyle" ng-grid="gridOptions"></div>
    </body>
</html>

En este HTML, lo importante es como llamo a mi aplicación “myApp” con el parámetro ng-app y luego el control “MyCtrl” con el parámetros ng-controller, que utilizaré luego.

Fácil, el tema es que hay que añadirle muchas librerías de javascript. Para esto, las añado como web resources en mi solución:

image

Todos esos javascript son librerías genéricas (angular, jquery, etc.) salvo una que llamé “script.js”. En este fichero voy a añadir la lógica de mi formulario:

var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope, $http) {    $scope.totalServerItems = 0;
    $scope.pagingOptions = {
        pageSizes: [250, 500, 1000],
        pageSize: 250,
        currentPage: 1
    };    
     $scope.setPagingData = function(data, page, pageSize){    
        var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
        $scope.myData = pagedData;
        $scope.totalServerItems = data.length;
        if (!$scope.$$phase) {
            $scope.$apply();
        }
    };
    $scope.getPagedDataAsync = function (pageSize, page, searchText) {
        setTimeout(function () {
            var number = 50;
             var options = "$select=Name,Telephone1,Address1_City&$top=" + number ;
             
            SDK.REST.retrieveMultipleRecords("Account", options, function (retrievedAccounts){
                
                $scope.setPagingData(retrievedAccounts,page,pageSize);
                }, function (error) { alert(error.message); }, function (res){var aux=1;});
         }, 100);
    };        
    $scope.gridOptions = {
        data: 'myData',
        enablePaging: false,
        showFooter: false,
        totalServerItems: 'totalServerItems',
        pagingOptions: $scope.pagingOptions,
        filterOptions: $scope.filterOptions, 
        
        columnDefs: [{field:'Name', displayName:'Name'}, {field:'Telephone1', displayName:'Telephone1'}, {field:'Address1_City', displayName:'Address1_City'}], 
        showGroupPanel: true, 
        jqueryUIDraggable: true, 
        enableCellSelection: true,
        enableRowSelection: false,
        enableCellEdit: true,
    };
});    
Este código consulta a CRM al punto oData, y el resultado que es un objeto jSON, lo meto en gridoptions con sus columnas definidas en “columnDefs”. Además en gridOptions se pueden añadir o quitar parámetros de comportamientos del grid, como paginaciones, ediciones, selección de líneas o celdas, etc.

Para mas información, recomiendo estudiarse a fondo este framework, a mí sinceramente me encante porque soy un amante del Javascript (http://angularjs.org/). Mirar también algo específico de ngGrid (Grid de AngularJS utilizado en este ejemplo).

Por último, como siempre, les dejo toda la solución no administrada para que podáis jugar: angulasJS_1_0_0_0.zip

Un saludo!

miércoles, 15 de enero de 2014

Completado el curso de Desarrollo con Dynamics CRM 2011

Academia de la Comunidad CRM
Finalmente se ha terminado de publicar el curso completo de desarrollo con Dynamics CRM 2011 que he realizado y publicado en Comunidad CRM (www.comunidadCRM.com).
Son mas de 3 horas de grabación, que abarca todos los aspectos del desarrollo con Dynamics CRM, buenas prácticas, consejos, ideas y ejemplos reales desde cero y explicados con el Visual Studio.
Espero pueda servirle a la comunidad como introducción a este apasionante mundo del CRM. Por mi parte me siento muy orgulloso de haberlo hecho y agradezco todos los mensajes de agradecimiento que he recibido en estas semanas, y a Comunidad CRM por haber fomentado y organizado. Todo esto me motiva a seguir adelante apoyando y publicando mas y compartiendo conocimiento.
Si alguien quiere hacer el curso completo aquí les dejo el listado de enlaces con todos los capítulos publicados:
Mi consejo final: compartir conocimiento es la mejor manera de seguir aprendiendo siempre.

domingo, 12 de enero de 2014

Workflows síncronos para auto numeración

Hola a todos, antes que nada….FELIZ 2014!
Imagino que todos están al día de que CRM 2013, tenemos la posibilidad de ejecutar los workflows de forma síncrona, sino ver por favor aquí: http://www.demianrasko.com/2013/10/workflows-sincronos-en-crm-2013.html
Los workflows de ejecución síncrona, nos abren una nueva ventana de posibilidades, que hasta ahora solamente eran posibles por medio de plugins, por ejemplo:
  • Auto numeraciones
  • Concatenaciones de campos
  • Validaciones
  • Cálculos
  • etc.
Uno de los plugins mas comunes que casi todos los implementadores han creado, es un plugin para gestionar auto numeraciones. Si bien Dynamics CRM contiene auto numeraciones para determinadas entidades como pedidos, casos, etc., esta numeración no es muy personalizable, y como parte de este código, el número que se incrementa no es 100% seguro que será único.
Ahora mismo hay varias publicaciones, que nos aportan ideas de como crear un workflow síncrono para aplicar auto numeraciones, en particular destaco los posts de dos colegas MVPs:
Por un lado, Shan nos proporciona una solución basada en dos entidades y un workflow síncrono, que nos permite de forma sencilla y sin tirar ni una sola línea de código, de disponer de un autonumerador basado en estos workflows síncronos.
Por otro lado, Jukka plantea la diferencia de realizar algo así con un workflow síncrono y otro igual pero asíncrono, explicando que si es asíncrono, nos generaría códigos duplicados ya que los procesos asíncronos se ejecutan de forma paralela (threads) y no podemos controlar el orden en que se ejecutan.
Recomiendo si les interesa el tema, leer estos dos posts, muy interesantes y rápidos de leer.
De todos, a mi me gusta ir un paso mas. He intentado confirmar si una solución de este tipo puede funcionar en un entorno real, o planteando que limitaciones podemos encontrar.
Me basé en la solución creada por Shan, en donde voy a numerar en el campo “Fax”, las cuentas que voy creando. Lo he realizado, y creando algunos registros de forma manual, funciona perfectamente:
image
Ahora bien, que pasa si creamos de forma masiva miles de registros? influye en algo la forma de crearlos? si los creamos como registros relacionados o “related” o utilizando ExecuteMultiple?
Bien, he creado un ejemplo de creación de miles de registros uno a uno llamando al CreateRequest, luego hice ejemplos con registros “related” (si alguién quiere mas información sobre esto, ir a la sdk: http://msdn.microsoft.com/en-us/library/gg309282.aspx) y por último con el ExecuteRequest.
Mis resultados no podían ser mejores y podía ver como a pesar de haber creado varios miles de registros, no encontraba duplicados:
image
De todos modos, esto no era un ejemplo de todo “estresado” y estaba seguro que si ejecutaba esos mismos códigos en paralelo en diferentes “Threads”, me crearía duplicados.
Entonces, me lancé la creación de estos registros con hasta tres hilos de ejecución:
image
Y encontré que efectivamente me generaba números repetidos hasta tres veces:
image
Está bien, esto tiene sentido, los workflows son síncronos, pero es posible que se intenten crear unos registros exactamente al mismo tiempo, y por lo tanto los numera iguales, no los ejecuta en orden sino en paralelo.
Por lo tanto, he de dar algunas conclusiones como finalización de mi estudio de este tema:
  1. Es una forma sencilla, rápida y sin tirar ni una sola línea de código para auto numerar registros con Dynamics CRM.
  2. Esta forma funciona correctamente (100% seguro) para cargas de datos automáticas que se ejecuten en un solo hilo o thread. No generando duplicados nunca.
  3. En caso de los registros a numerar se creen de forma manual, este tipo de soluciones es prácticamente al 99% seguro de que no habrá duplicados. Reproducir un ejemplo en el cual dos usuarios creen el mismo tipo de registros en el mismo milisegundo, es posible pero casi improbable. Ojo, tener en cuenta que puede ocurrir, en especial en entornos con muchos usuarios.
  4. Si hay procesos por ejemplos de cargas, que se ejecuten en varios hilos de ejecución, esta solución no es viable, ya que los códigos auto numéricos se duplicarán.
Por favor tener en cuenta estos temas, espero que les sirva.
un abrazo