CRM2013 – Multilookup: Modify the code CRM2011

I migrated the solutions from CRM2011 to CRM2013 but I found a big problem with Multilookup: It does not work…  I tryed to use the solution inside this post https://mscrmmindfire.wordpress.com/2014/05/20/crm-2013-manipulate-look-up-to-show-multiple-entity-record/ but does not work..

Customer type Lookups in Dynamics CRM have always been an interesting and powerful feature that allows you to associate records of multiple entities with entities like Cases, Orders, etc. PartyList Lookups are similar to Customer type lookups, except for the fact that it allows you to have access to a vast array of entities. They are generally available in Activities like Appointments, Phone Calls, etc.

Sometime or the other, you might have had the requirement to modify customer type lookup in CRM to restrict records to a particular entity. For example, you might want to restrict the end user from selecting Accounts while placing an Order from the “Customer” Lookup. Well, there’s a way to achieve that in CRM using JavaScript. It isn’t exactly a supported one. But chances of Rollups breaking it is very less.

img1

Things are a bit different in CRM 2013. In CRM 2011 and even CRM 4.o, the DOM was a litte bit different. But CRM 2013 has its own brand new DOM structure. So, the code differs from that of CRM 2011. If you simply want to get to the code to implement, you can move directly to the next section. If you want to know why that code is required, read on.

Consider we want to restrict the Cusom lookup to a specific entity, Account. If you’re using Internet Explorer, press F12 to open up the Developer Tools. Search for “new_testfield_i” and you’ll find something as follows.

img3

Now, this “new_testfield_i” is basically the magnifying glass image in the “TestField” lookup button. It consists some interesting properties that determine what entities will be displayed in the lookup form. However, we are interested in only a handful of them in order to get our job done. They are “lookuptypes”, “lookuptypeIcons”, “lookuptypenames” and “defaulttype”. Having a closer look at them pretty much explains what each property signifies.

So, now that we have identified what needs to be changed where, let’s get to the coding part of it. Basically, the idea here is to append “_i” after the Customer type lookup field name. Once you get that element, change its properties to get the desired result.

If you have followed the earlier section, you’d know why the following code snippet is required and what exactly it does. Just to be on the same page, the following code will allow only “Account” records to be displayed in the “Regarding” lookup field (in the Phone Call entity).

document.getElementById("new_testfield_i").setAttribute("lookuptypes", "1");
document.getElementById("new_testfield_i").setAttribute("lookuptypeIcons", "/_imgs/ico_16_1.gif");
document.getElementById("new_testfield_i").setAttribute("lookuptypenames", "account:1:Account");
document.getElementById("new_testfield_i").setAttribute("defaulttype", "1");

Well, don’t think it’s done yet! Although the above code might work most of the times, you might find it failing sometimes. Why? Because the entire DOM of Dynamics CRM 2013 is loaded in an asynchronous manner. Hence, the point where your script executes, the field “Regarding” might not have been rendered yet! Let’s add this small fix for it to work perfectly.

setTimeout(function() {
document.getElementById("new_testfield_i").setAttribute("lookuptypes", "1");
document.getElementById("new_testfield_i").setAttribute("lookuptypeIcons", "/_imgs/ico_16_1.gif");
document.getElementById("new_testfield_i").setAttribute("lookuptypenames", "account:1");
document.getElementById("new_testfield_i").setAttribute("defaulttype", "1");
}, 1000);

Now, that was if you wanted to restrict a Customer lookup field to a single entity. What do you do if you want to allow multiple entities, and restrict only a few? It’s simple. See the following code to get it.

setTimeout(function() {
document.getElementById("new_testfield_i").setAttribute("lookuptypes", "1,2");
document.getElementById("new_testfield_i").setAttribute("lookuptypeIcons", "/_imgs/ico_16_1.gif?ver=-475068199:/_imgs/ico_16_2.gif");
document.getElementById("new_testfield_i").setAttribute("lookuptypenames", "account:1:Account,contact:2:Contact");
document.getElementById("new_testfield_i").setAttribute("defaulttype", "1");
}, 1000);

The result now is as follows with Account and Contact being the only allowed Entities.

img5

 

Annunci

CRM2011 – Retrieve Plugin

2007_microsoft_dynamics_crmToday I need to execute a method every time open a Contact record.

Usually this would be frowned upon because this code could easily present a performance issues, especially if the data you’re gathering is hosted on an external resource.

In the off-change you do need to do this, here is the solution:

First, create a new Plugin and sign the assembly with a key:

public void Execute(IServiceProvider serviceProvider)
{
    // Obtain the execution context from the service provider.
    Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
        serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

    if (context.Depth == 1)
    {
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

        // Obtain the target entity from the input parmameters.
        EntityReference entity = (EntityReference)context.InputParameters["Target"];

        ColumnSet cols = new ColumnSet(
                             new String[] { "lastname", "firstname", "address1_name" });

        var contact = service.Retrieve("contact", entity.Id, cols);

        if (contact != null)
        {
            if (contact.Attributes.Contains("address1_name") == false)
            {
                Random rndgen = new Random();
                contact.Attributes.Add("address1_name", "first time value: " + rndgen.Next().ToString());
            }
            else
            {
                contact["address1_name"] = "i already exist";
            }
            service.Update(contact);
        }
    }
}

Next, hop over to the Plugin Registration Tool (included with the CRM SDK) and register the plugin:
Unbenannt

What you’ll end up with in this example is:

On first open of the record:

clip_image002_thumb

 

 

 

On all future opens of the record:

clip_image0025_thumb

CRM 2011 – Pass Data Between Plugins using SharedVariables

2007_microsoft_dynamics_crmEvery day I have new things to learn … and yesterday I had a problem about tho share variables between plugins in my CRM2011 project. MSCRM2011 and the execution pipeline provides the ability to pass data from one plug-in to another through an IPluginExecutionContext property called SharedVariables. This property is a collection of key/value pairs which developers can use to share data between plug-ins which are registered on both the pre and post events.

Here is the way to pass some paramters and get in between the steps in MS CRM 2011, while writing plugin.

Pre-Create Account Plug-in

if (context.InputParameters.ContainsKey("Target") && context.InputParameters["Target"] is Entity)
{
Entity target = context.InputParameters["Target"] as Entity;
if (target != null)
{
// some wacky data validation
string city = target.GetAttributeValue<string>("address1_city") ?? string.Empty;
int numEmployees = target.GetAttributeValue<int>("numberofemployees");
int accountCategory = target.GetAttributeValue<int>("accountcategorycode");

// city is auckland, numEmployees > 100, account category is preferred customer
bool updateRelated = city.Equals("Auckland", StringComparison.InvariantCultureIgnoreCase) && numEmployees > 100 && accountCategory == 1;
context.SharedVariables.Add("updatedRelated", updateRelated);
}
}

Post-Create Account Plug-in

if (context.InputParameters.ContainsKey("Target") && context.InputParameters["Target"] is Entity)
{
Entity target = context.InputParameters["Target"] as Entity;
if (target != null)
{
if (context.SharedVariables.ContainsKey("updatedRelated"))
{
bool updateRelated = (bool)context.SharedVariables["updatedRelated"];
if (updateRelated)
{
// additional logic to update related records of the Account
}
}
}
}

CRM 2011 – How to get the current user from within a dialog

2007_microsoft_dynamics_crmI needed to get the current user in a dialog but CRM 2011 Dialogs do not provide any easy way to access the currently logged in user’s information. To get this information I found two ways (I don’t know if they are the unique ways.. but run!!):

1. USE ENTITY

The first way was to create a new instance if an entity: I created a new entity, the owner field will contain the currently logged in user.
The steps I followed:

  • Log into CRM and create a new entity, call it new_CurrentDialogUser. You do not have to add any new fields.
  • Open your existing dialog for editing.
  • From the Dialog editor, the first thing to do is create an instance of new_CurrentDialogUser.
    • Create a new stage, positioned at the very beginning of the dialog.
    • Click ‘Add Step’ and select ‘Create Record’.
    • Choose the type to be new_CurrentDialogUser.
    • Click on properties. Notice the owner field is presented. Do not populate this field. Instead, when the ‘Create Record’ step executes, it will default the owner to the currently logged in user.
  • Once the ‘Create Record’ steps executes in your dialog, you have the ability to reference this step from throughout the rest of your dialog, just as if you were referencing the current record that is related to your dialog.
  • In my case, I use an ‘Assign Value’ step to store the owner of the newly created new_ CurrentDialogUser to a local variable, called CurrentUser.
    • Click ‘Add Step’ and choose ‘assign value details.’
    • In the ‘Look For’, select from the local values, the choice ‘Create (Current Dialog User)’.
  • Finally, once my am done using the current user, I perform an ‘UpdateStatus’ step, as a means to
    deactivate the dynamically created new_CurrentDialogUser instance.
    • Add step, select ‘Change Status’
    • Select the ‘Create (Current Dialog user)’.
    • Change the status to ‘Inactive’.

2. USE ACTIVITY WORKFLOW

I created a new workflow activity with Output parameters. This output parameters are all parameters that I needed in my dialog. For example I have the Current User, etc. In following the piece of code:

// <copyright file="ParametersActivity.cs" company="">
// Copyright (c) 2014 All Rights Reserved
// </copyright>
// <author>Alessandro Graps</author>
// <date>6/25/2014 8:34:52 AM</date>
// <summary>Implements the ParametersActivity Workflow Activity.</summary>

using ActivityRecording.Entities;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;

namespace Winvs.Next.ActivityRecording.Workflow
{
    using System;
    using System.Activities;
    using System.ServiceModel;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Workflow;

    public sealed class ParametersActivity : CodeActivity
    {
        [Output("Current User")]
        [ReferenceTarget("systemuser")]
        public OutArgument<EntityReference> CurrentUser { get; set; }

        [Output("Current Time Mapping")]
        [ReferenceTarget(winvs_unitconfiguration.EntityLogicalName)]
        public OutArgument<EntityReference> CurrentTimeMapping { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>();

            if (workflowContext == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
            }

            if (workflowContext.Depth > 1)
                return;
            
            CurrentUser.Set(context, new EntityReference("systemuser", workflowContext.InitiatingUserId));


            IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(workflowContext.UserId);

            winvs_unitconfiguration winvsUnitconfiguration = GetConfigurationEntityUnitGroup(service);

            CurrentTimeMapping.Set(context, new EntityReference("winvs_unitconfiguration", winvsUnitconfiguration.Id));

        }

        public winvs_unitconfiguration GetConfigurationEntityUnitGroup(IOrganizationService service)
        {
            string entityName = "winvs_unitconfiguration";

            // Get the metadata for the currently list's entity
            // This metadata is used to create a "Property Descriptor Collection"

            QueryExpression qe = new QueryExpression();
            qe.ColumnSet = new ColumnSet(true);
            qe.EntityName = entityName;

            RetrieveMultipleRequest request = new RetrieveMultipleRequest();
            request.Query = qe;
            RetrieveMultipleResponse response = (RetrieveMultipleResponse)service.Execute(request);


            if (response.EntityCollection.Entities.Count == 0)
                throw new Exception(string.Format("The configuration entity is empty."));

            foreach (Entity unitConfigurationEntity in response.EntityCollection.Entities)
            {
                winvs_unitconfiguration winvsUnitconfiguration = unitConfigurationEntity.ToEntity<winvs_unitconfiguration>();
                return winvsUnitconfiguration;
                break;
            }

            throw new Exception(string.Format("The configuration entity is empty."));
        }

    }
}

This is a fast way to get all information that I don’t have in dialogs.

CRM2011 – Disable / enable fields, sections, tabs and the whole form

Today the problem is about enable and disable fields on form in CRM. When working with CRM, you often want to enable (set to read/write) or disable (set to read / only) selected fields, sections, tabs and the whole form depending on your business logic.

1) Enable / Disable a field

Xrm.Page.getControl("fieldname").setDisabled(false); 

2) Enable / Disable a Section

	function sectiondisable (sectionname, disablestatus)
	{
	    var ctrlName = Xrm.Page.ui.controls.get();
	    for(var i in ctrlName) {
	         var ctrl = ctrlName[i];
	         var ctrlSection = ctrl.getParent().getName();
	         if (ctrlSection == sectionname) {
	               ctrl.setDisabled(disablestatus);
	        }
	    }
	}  // sectiondisable

3) Enable / Disable a Tab

	function tabdisable (tabname, disablestatus)
	{
	 var tab = Xrm.Page.ui.tabs.get(tabname);
	 if (tab == null) alert("Error: The tab: " + tabname + " is not on the form");
	 else {
	     var tabsections =  tab.sections.get();
	     for (var i in tabsections) {
	         var secname = tabsections[i].getName();
	         sectiondisable(secname, disablestatus);
	     }
	  }
	}   // tabdisable

4) Enable / Disable a Form

	function formdisable(disablestatus)
	{
	    var allAttributes = Xrm.Page.data.entity.attributes.get();
	    for (var i in allAttributes) {
	           var myattribute = Xrm.Page.data.entity.attributes.get(allAttributes[i].getName());
	           var myname = myattribute.getName();          
	           Xrm.Page.getControl(myname).setDisabled(disablestatus); 
	    }
	} // formdisable

5) Disabling all Fields on a Form
Add this code to your web resource:

function doesControlHaveAttribute(control) {
    var controlType = control.getControlType();
    return controlType != "iframe" &amp;&amp; controlType != "webresource" &amp;&amp; controlType != "subgrid";
}


function disableFormFields(onOff) {
    Xrm.Page.ui.controls.forEach(function (control, index) {
        if (doesControlHaveAttribute(control)) {
            control.setDisabled(onOff);
        }
    });
}

Call the function:
Generally, you will have another function that is triggered on-load that will determine if the form should be disabled. It may check a picklist value or it may check the current user’s role.

function setupForm(){
    if (Xrm.Page.ui.getFormType() == 2 &amp;&amp;
        Xrm.Page.getAttribute("incidentstagecode").getValue() != null &amp;&amp;
        Xrm.Page.getAttribute("incidentstagecode").getValue() == "200001") 
    {
           disableFormFields(true);
    }
}

– See more at: http://blog.avtex.com/2011/04/01/disabling-all-fields-on-a-form-in-crm-2011/#sthash.nfN8z64a.dpuf

CRM2011 – Associate and Disassociate Many to Many relationship records

In my Solution I needed to associate programmaticaly an N:N relationship in my entity.

If we have any N:N(Many to Many) relationship in Microsoft Dynamics CRM 2011, need to manually assign relationship between two entities using SDK.

In the next example we discuss about the example to associate and disassociate N:N(Many to Many) relationship records in CRM 2011 thru SDK.

In the example I have N:N relationship between Case (Incident) and Activity (task). Relationship name is ls_incident_activity_task.

// Creates the custom many-to-many relationship between the case and task.
public void AssociateRelationship(IOrganizationService service, EntityReference caseRef, EntityReference taskRef)
{
//If one of the ID's is null, do nothing
if (caseRef == null) return;
if (taskRef == null) return;
if (caseRef.LogicalName != "incident") return;
if (taskRef.LogicalName != "task") return;

var caseId = caseRef.Id;
var taskId = taskRef.Id;

//The relationship schema to create
string relationshipName = "ls_incident_activity_task";

//Create a query that will check to see if the relationship already exists between this account and contact
QueryExpression query = new QueryExpression(relationshipName)
{
NoLock = true,
ColumnSet = new ColumnSet(false),//only get the row ID, since we don't need any actual values
Criteria =
{
Filters =
{
new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
//Get the row for the relationship where the account and contact are the account and contact passed in
new ConditionExpression("incidentId", ConditionOperator.Equal, caseId.ToString()),
new ConditionExpression("activityId", ConditionOperator.Equal, taskId.ToString()),
},
},
}
}
};
var result = service.RetrieveMultiple(query);
//Check if the relationship was not found
if (result == null || result.Entities == null || result.Entities.Count < 1)
{
//The relationship was not found, so create it
service.Associate(caseRef.LogicalName, caseRef.Id, new Relationship(relationshipName), new EntityReferenceCollection() { caseRef });
}
}


public void DisassociateRelationship(IOrganizationService service, EntityReference caseRef, EntityReference taskRef)
 {
     //If one of the ID's is null, do nothing
     if (caseRef == null) return;
     if (taskRef == null) return;
     if (caseRef.LogicalName != "incident") return;
     if (taskRef.LogicalName != "task") return;
 
     var caseId = caseRef.Id;
     var taskId = taskRef.Id;
 
     //The relationship schema to create
     string relationshipName = "ls_incident_activity_task";
 
     //Create a query that will check to see if the relationship already exists between this account and contact
     QueryExpression query = new QueryExpression(relationshipName)
     {
         NoLock = true,
         ColumnSet = new ColumnSet(false),//only get the row ID, since we don't need any actual values
         Criteria =
         {
             Filters =
             {
                 new FilterExpression
                 {
                     FilterOperator = LogicalOperator.And,
                     Conditions =
                     {
                         //Get the row for the relationship where the account and contact are the account
                         new ConditionExpression("incidentId", ConditionOperator.Equal, caseId.ToString()),
                         new ConditionExpression("activityId", ConditionOperator.Equal, taskId.ToString()),
                     },
                 },
             }
         }
     };
     var result = service.RetrieveMultiple(query);
     //check if record exists
     if (result != null && result.Entities != null && result.Entities.Count > 0)
     {
         //Delete the N:N relation
         service.Disassociate(caseRef.LogicalName, caseRef.Id, new Relationship(relationshipName), new EntityReferenceCollection() { taskId });
     }
 }

MobileDev: panoramica sullo sviluppo Mobile e sulle possibili alternative .Net

FocusDayCiao a tutti,

volevo pubblicizzare il Focus Day di Overnet che si terrà a settembre. In particolare l’evento “MobileDev: panoramica sullo sviluppo Mobile e sulle possibili alternative .Net“. In questo evento di circa 4 ore discuteremo sul mondo Mobile (I mercati, i device ed inoltre vedremo una valida alternativa per riutilizzare codice .Net: XAMARIN). Naturalmente il relatore saro’ io.. Spero possa interessare e spero di vedervi numerosi. Di seguito il link dell’evento: http://overneteducation.it/DettaglioCorso.aspx?corso=EV030&v=1

 

L’evento si terrà a Milano. L’indirizzo è il seguente:

OverNet Education
Strada 4 Palazzo Q7, 1°piano
Centro Direzionale Milanofiori
20089 – Rozzano MI