Jun 27, 2013

Plugin for opportunity Win / Lose

It can be a common requirement to execute plug-ins when opportunities are closed as Win or Lose. In most cases you need to identify two cases separately. Ironically, I didn’t find many resourceful articles about it. In fact, I thought of sharing my experience.

These are the relevant statecode and statuscode combination for opportunity.


First one could think of having a State Change plug-in for this. But I learned it’s not successful.

Whether it is Win or Lose, opportunity will be closed. So it creates a record in OpportunityClose entity. Then I though, we could do a create plug-in for OpportunityClose entity. Now the problem is you are not able to catch whether it’s a Win or Lose. If your requirement is just to do something when opportunity is closed, this works.

Then only I decided to do two different plugin for Win message and Lose message which triggers the plugin in the correct action.

So correct plugin registration steps would be seen as below;



Then I checked the plug-in context which made me shocked again. It doesn’t have opportunity record but it does have an OpportunityClose.


OpportunityClose is of course an unfamiliar entity for me. For you too obviously! Then only I realised it should be called a “Black Sheep”. You know why? Could you guess the primary Key of this entity? Your obvious answer should be opportunitycloseid which is completely wrong! Check below picture. It is Activityid!

Anyway, strangeness of primary key was explained only for your knowledge. The good side is this entity contains opportunityid which is the gateway for all the attributes of our current record. So for both Win and Lose plugins I started coding as below, by passing the OpportunityClose instead of Opportunity, knowing that it contains opportunityid.

context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
service = factory.CreateOrganizationService(context.UserId);

if (context.InputParameters.Contains("OpportunityClose"))
{
   oppCloseEnt = (Entity)context.InputParameters["OpportunityClose"];
   .........
   .........
}

In summery I am passing opportunityclose, read opportunityid in it, retrieve opportunity fields I need using the service. In a way, it’s like asking something about your home from your neighbour! Anyway, it worked for me!

Jun 25, 2013

Issues of using checkbox in CRM 2011

In a previous post I explained difference of using onChange and onClick in CRM 4.0

Now it has come the time to talk the same thing against CRM 2011. As same as 4.0, even in CRM 2011 we got only the onChange in native manner. As we all know the problem is you need to click somewhere else after clicking the checkbox to execute the event.  So we need to implement onClick to accomplish this. It is bit similar to  4.0, but there is a complication.

For some crazy reason, standard Xrm model that works for 2011 doesn’t work here and have to use the 4.0 style code. Other issue is execution take cyclic pattern and our code gets executed twice! So we need to change the focus as soon as we finish the code. Please check the working code (this should go in onload event);

MyCheckbox = function()
{
    crmForm.all.new_sample.onclick = function()
    {
       //Code
       //Change focus to another field  
    }
}

Issues are not finish yet! Practically, we might need to do something according to the value of the relevant check box. Biggest confusion comes here. Values given are completely opposite. When you check the checkbox you might get false instead of true and vice versa. Why this happens?

I am trying to understand it this way. (please correct me If I am wrong) This is not an error. We are executing the code on “click”. This doesn’t mean we have changed the value in the time we execute the code. Of course what we see is the "changed" situation through the form. Actually code happens for previous value of the check box. I think this is the reason Microsoft doesn’t provide this event in their native framework.

If we understand this, we are good to proceed with our work without any trouble. Only thing is do the opposite when playing around with the value of the checkbox upon onClick.

var _checkbox = Xrm.Page.getAttribute("new_sample").getValue();
if (_checkbox == true)
{ 
  //code for false 
}
else
{
  //code for true 
}

This is bit confusing.. but manageable.

Merging DLLs to register plug-ins in database

When we code plug-ins usually, we do them according to programming principles.  One strong principle we all adhere is separating codes to different layers: mainly for calling part, Business Logic Layer, Data Access Layer and etc. So we can copy all DLLS to relevant path (Server\Bin\Assembly) when deploying the plugin and call the accessing part through plug-in registration tool. In this case we need to register the plug-in in Disk mode.

How about if we need to register the plug-in in Database mode?


Here we can only point one DLL. So are we going to get rid of our systematic code that produces few DLLs? No. You can merge the DLLs to one and register.

Suppose I got below three DLLs and XXXPlugin.dll is the calling DLL.

XXXPlugin.dll

XXXDataLayer.dll

XXXBizLayer.dll

Below is the code to bundle the DLLs to one called “PluginCaller.dll” (you can use any name).

REM ilmerge  /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319   XXXPlugin.dll    /keyfile:xxxKey.snk  /out:PluginCaller.dll 


ilmerge  /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319    PluginCaller.dll XXXBizLayer.dll XXXDataLayer.dll /keyfile:xxxKey.snk   /out:PluginCaller.dll  

Now you are good to go.

Note

Now this tempt you to use a development CRM organization too in the same server as Live, since you can register any number of plug-in versions of same DLLs.

Still I don’t think it’s an advisable thing. While infrastructure specialists can find more reasons for this, my simple question is will your client going to allow you to install development tools in the same server? Otherwise how you going to debug the development CRM? How you going to restart IIS in the process of development?

By the meantime, this will be a good solution for CRM online systems too.

(I am thanking my colleague Kin Ng for helping me with this)

Jun 17, 2013

Assigning a User or Team

Just though of posting an important code snippet on how to assign a user to a record. Please find a sample code.

using Microsoft.Crm.Sdk.Messages;

AssignRequest assignAcc = new AssignRequest
{
    Assignee = new EntityReference("systemuser", new Guid("5BA4B404-EF87-4F11-8492-D437823E18AB")),
    Target = new EntityReference("opportunity", new Guid("F01F4B23-A996-4519-8395-C7428DDEA8DB"))
};
service.Execute(assignAcc);

Here Target entity is the entity type of the record we are going to assign a new user.  In my case, its opportunity. Here I am assigning a user but we can use same code for assigning a team. In that case Assignee will have to change accordingly. (team instead of systemuser)

Jun 4, 2013

Calculate total from related entity values

This is a very common scenario. For example Quote entity contains fields to have total of all the relevant quote product values. Yet, we don’t need to bother about it since CRM is taking care of those totals. Suppose we need to do such calculation in our custom scenario it will not be handled by CRM.

Just like Quote and Quote product (or Opportunity and Opportunity product), suppose we got entity that has related records as child records or line items. Each child record could have a value for surcharge and primary entity should have the total surcharge. How you accomplish this? In other terms, when child values get changed total should get changed.


Now we will consider the events that child values could change. They are Create, Update and Delete. Obviously we need to write plug-ins for those events to adjust the total. Below would be our algorithm;

Total (Surcharge) = Sum of All Line Item (Surcharge)

Now consider different events;

Post Create – Execute above algorithm

Post Update – Execute above algorithm

What about the delete?

This is the tricky part. Since there is nothing called post-delete, obviously we need to run this in pre-delete. Still we don’t get expected value by executing the same algorithm in pre delete. Why? This uses pre values. In this case total will not be affected by the calculation. Total will not get deducted the value of deleted child record. How we solve this?

You will only have to update the surcharge value of the deleting record to zero in pre delete plug-in. When you do this, post-update plug-in will execute and total will be set except for the record which will be deleted soon. So this is the correct out come!