domingo, 29 de noviembre de 2009

CRM Filtered Lookup Multi

Hoy toca un poco más de info empresarial jeje. Bueno mencionando otra vez el sistema Microsoft Dynamics CRM 4.0, recientemente tuve la necesidad de realizar filtros al momento de asignar relaciones entre dos entidades, por ejemplo asignarle a un cliente un casillero existente pero al momento de consultar la lista de casillero que se puedan asignar sólo mostrar los que no tienen un cliente previamente asignado. Cuando estuve buscando la información noté la falta de un tutorial que estuviese en español ya que la única información al respecto que logré conseguir fue en el post de Jim Wang: CRM Filtered Lookup Multi y está en inglés. Voy a suponer que deben saber algunas cosas como poder crear y registrar plugins en el sistema así como la asignación de código en los eventos Javascript de los formularios.

Lo primero que deben hacer es crear un plugin con el siguiente código (extraído del blog de Jim Wang):

/*
 * Microsoft Dynamics CRM Lookup Filter 
 * Plug-Ins: Execute message on the Pre Stage/Synchronous/Server/Parent Pipeline.
 * Jim Wang @ Aug 2009, http://jianwang.blogspot.com, http://mscrm.cn
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
using Microsoft.Crm.Sdk;

namespace CRMExecuteEvent
{
    public class CRMExecuteEvent : IPlugin
    {     
        string lookupId;

        public void Execute(IPluginExecutionContext context)
        {

            lookupId = HttpContext.Current.Request.QueryString["id"] == null ? null : HttpContext.Current.Request.QueryString["id"].ToString();

            if (lookupId == null)   return;

            try
            {
                if (context.InputParameters.Contains("FetchXml"))
                {
                    string beforeXml = (String)context.InputParameters["FetchXml"];

                    if (beforeXml.Contains("<entity name="\"new_shippingmark\"">") /* Aquí deben reemplazar new_shippingmark y poner el nombre de la entidad a consultar */ && beforeXml.Contains("xml-platform"))
                    {
                        //Aquí deben personalizar la consulta FetchXML que desean hacer en lugar de la que iba a mandar el sistema.
                        string afterXml =
                        "";

                        //Reemplazamos el string de consulta fetchXML por el que deseamos.
                        context.InputParameters["FetchXml"] = beforeXml.Replace(beforeXml, afterXml);

                    }
                }
            }

            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the CRM plug-in.", ex);
            }
        }

    }
}


Una vez creado el plugin y teniendo el archivo .dll correspondiente deben registrar ese plugin en el evento Execute sin especificar entidad y seteando los valores en los que se pueden apreciar en esta imagen:
Register Execute Event. Deben tomar en consideración que deben adaptar el código a sus necesidades particulares.

Luego de haber hecho esto deben insertar el siguiente código en el evento OnLoad del formulario de la entidad a la que desean asociar la instancia seleccionada.

var relId = "new_new_shippingmark_quote"; //Estos son los valores que deben adaptar a sus 
var lookupId = crmForm.all.customerid;    //necesidades y acorde a las entidades a usar.

var lookupEntityTypeCode;
var navId = document.getElementById("nav" + relId);
if (navId != null)
{
    var la = navId.onclick.toString();
    la = la.substring(la.indexOf("loadArea"), la.indexOf(";"));
    
    navId.onclick = function()
    {
        eval(la);

        var areaId = document.getElementById("area" + relId + "Frame");
        if(areaId != null)
        {
            areaId.onreadystatechange = function() 
            {
                if (areaId.readyState == "complete") 
                {  
                    var frame = frames[window.event.srcElement.id];  
                    var li = frame.document.getElementsByTagName("li");    

                    for (var i = 0; i < li.length; i++)
                    {
                        var action = li[i].getAttribute("action");
                        if(action != null && action.indexOf(relId) > 1)
                        {
                            lookupEntityTypeCode = action.substring(action.indexOf("\(")+1, action.indexOf(","));
                            li[i].onclick = CustomLookup;
                            break;
                        }
                    }
                }
            }
        }
    }
}

function CustomLookup()
{
    var lookupSrc = "/" + ORG_UNIQUE_NAME + "/_controls/lookup/lookupmulti.aspx?class=&objecttypes=" + lookupEntityTypeCode + "&browse=0";
    if(lookupId != null && lookupId.DataValue != null && lookupId.DataValue[0] != null)
    {
        lookupSrc = lookupSrc + "&id=" + lookupId.DataValue[0].id;
    }

    var lookupItems = window.showModalDialog(lookupSrc, null);
    if (lookupItems)  // This is the CRM internal JS funciton on \_static\_grid\action.js
    {
        if ( lookupItems.items.length > 0 )
        {
            AssociateObjects( crmFormSubmit.crmFormSubmitObjectType.value, crmFormSubmit.crmFormSubmitId.value, lookupEntityTypeCode, lookupItems, true, null, relId);
        }
    }
}


Este código funciona en el contexto de relaciones N-N en el sistema. En el trabajo logré modificar el código que se muestra aquí para relaciones de tipo 1-N usando consultas FetchXML y AJAX pero lo pondré en otro post ya que no tengo el código disponible ahorita. Cualquier duda en cuanto a este ejemplo pregunten en los comentarios o mándenme un correo electrónico a kpantic@manapro.com

See ya,
Kris

1 comentario:

  1. es interesante, logre aplicarlo, solo tengo un problema cuando quiero asociar 1:N, me lanza un error, me gustaria saber como modificaste (o que metodo usaste) para relacionar 1:N. con el associatedObjects no me funciona.
    bueno si puedes responderme gracias.

    ResponderEliminar