Showing posts with label R and D. Show all posts
Showing posts with label R and D. Show all posts

Nov 10, 2013

Workflow that waits till a date in the record

This is something cool. If I elaborate this a bit; this will allow you to trigger something on an important day like contract end date or etc. This can actually replace the need of a windows service that checks something periodically.

Of course I wrote something similar sometimes back, but it is practically bad. It could make new instance again and again till the exact date reaches.

Now it is just one line waiting statement that does the magic.

Typical example I tried is to put a flag for insurance records when they reach expiry date.
 
In CRM 2011, it will be like this;
 
 
In CRM 2011 online it will be like this;

 
In CRM 2013 online
 
 
If you check the record after creation you will see the waiting statement in the workflow tab.
 
 
Since expiry date can be changed later on, it is also advisable to trigger on Update as well as on Create. If a user changes the expiry date later on, you will see an extra waiting record.
 
 
Anyway, as I tested, it worked for the correct expiry date. 


Jul 7, 2013

Coloring the Subgrid rows

As we discussed previously, we can use colours for branding purposes and improve the useability. Most clients seem happy to have different colours for different rows within the Subgrid depending on their status or etc.

For example: In my cases I have an Institute entity where sub institutes are in a Subgrid. I am going to give a colour for profit making institutes. (Highlighting expensive quote products within a Quote would make more sense for you). Outcome would be something like this;


How we going to achieve this? This consists of three steps.

1) Wait till Subgid is loaded

Biggest challenge of playing with Subgids is they load in an Asynchronous manner. In that case normal onload would not fire. So we attach a method for loading with a Delay. This is the code in loading;

setTimeout("attachGridAction();", 500);

Now we will implement the relevant method.  This got a trick. In catch statement delays and calls the method again. This allows you to wait and load the code again to see if Subgrid is loaded. Your real code will run only after that is accomplished.

function attachGridAction() 
{ 
  try 
  {
    var _grid = document.getElementById("Sub_Org_List");
    if ((_grid) && (_grid.readyState == 'complete'))
    {
        // Code goes here
    }
  }
  catch (err) 
  {
       setTimeout("attachGridAction();", 500);
  }
}

2) Determine the criteria

Now you need to determine the criteria of the records to be coloured. Actually you need to read the relevant Guids. Read the relevant Fetch XML as below. If you uncomment the second line, you will see the fetch xml statement of the Subgrid. Now you are free to retrieve those records and determine the Guids according to your criteria.

var _fetch = document.getElementById("effectiveFetchXml");
//alert(_fetch.value);

3) Colouring the row

Now you have the Guids ready. Now perform this code within a loop for your Guids; (I am just using one single record to make it clearer)

var _checkbox =   document.getElementById('checkBox_{4ACC296A-0CE5-E211-A9C3-00155D467A0E}');
var _checkboxParentParent = _checkbox.parentNode.parentNode;
_checkboxParentParent.bgColor = 'DarkKhaki'; 

Limitation;
As you may guess, this doesn’t work for next pages if paging is performed for Subgrid. What you can do is increase the items in the Subgrid allowing to have a scrollbar and ignore the paging option.

Mar 14, 2013

Sales process – Part 3 – Modifying calculation of quote product

A couple of previous posts explained the standard way of working with quotations and its level of flexibility. In rare cases, it could need you to modify the standard calculations. In this article, we will analyse options and constrains of doing such tasks in Quote product. Most popular requirement that would come your way could be implementing automated tax (or GST) system. Natively TAX is just an editable field in quote product.

Consider the pricing pane of the quote product form.


Three fields I put within the green squares are editable fields. These are the editable fields with their schema names and types.

Name
Schema Name
Type
Quantity
quantity
Decimal
Manual Discount
manualdiscountamount
Currency
Tax
tax
Currency

These are the field that can’t be edited with their schema names and types.

Name
Schema Name
Type
Price per unit
priceperunit
Currency
Volume Discount
volumediscountamount
Currency
Amount
baseamount
Currency
Extended Amount
extendedamount
Currency

Considerations for plug-in development

Obviously we need to develop our own plug-ins to enhance/modify the current calculations. Now consider my research result on plugin behaviour in this regard.

 
Create
Update
Pre stage
Post stage
Pre stage
Post stage
Editable fields
(of first table)
Available, can modify
Available, can modify
Modified field available and others can be retrieved, can modify *
Modified field available and others can be retrieved, can modify*
Other field
(of second table)
Not available, cannot modify
Not available, cannot modify
Can be retrieved, cannot modify.
Can be retrieved, cannot modify.
* If you modify the same entity in Update event make sure you avoid infinite loops.

Essence of this result is we can only play around with Quantity, Manual Discount and Tax. Good news is any time you change those fields; calculations are done accordingly to newly changed values of those fields. In other terms “Extended amount” get the correct value regardless of where you change those fields.

It implies CRM does its own calculations after the plug-in engine has completed its performances. In fact, you should not/ cannot amend other fields such as Price per Unit, Volume Discount, Amount and Extended Amount.

Some points to think

1) If you want to introduce an auto tax calculation method, it’s possible. Better have the logic for both create and modify event plug-ins.

2) If you consider the fact that we have two fields (namely Tax and Manual discount) to play around; tax is being added and Manual discount is being subtracted from total automatically. So whatever the additions and subtractions you need can be pushed to the current calculation mechanism if you are creative enough. Think a bit.

3) There is a chance your logic needs fields which are unavailable in plug-in context such as Price per Unit, Volume Discount and Amount. In that case, you are still able to retrieve first two fields from Price List and Discount List entities respectively and Calculate Amount. Read my 1st and 2nd parts of this article for better understanding.

4) One would also think of give up the native total fields and introduce new custom fields, WHICH IS NOT RECOMMONDED AT ALL. This means you are rewriting your own calculation logic for entire quoting including quote product and quote. That will also push you to introduce your own recalculation button in Quote header. Also you are again facing problems when quote values are transferred to Order entity in a later stage. Personally, I don’t see any reason to go in to this mess.

1st part of this article: Sales process – Part 1 – Product Catalog
2nd part of this article: Sales process – Part 2 – Quoting
4th part of this article: Sales process – Part 4 – Modifying calculation of quote

Feb 25, 2013

Self-referential relationship explained

Parent-child relationship

Ability to use self-referential relationship in Dynamics CRM is quite cool. Especially, this caters the need of maintaining parent-child relationships using the same entity. Simply office entity (custom) can be used to keep records of parent office as same as child office. In fact, this is a 1:n relationship.

We will see simple way of setting up this relationship.  (Suppose I got custom entity called Test).
Simply go to the customization of the entity and move to n:1 relationships; then create new relationship. We can give meaningful (which explains parent-child relationship) names to lookup field display name and navigation item label name as below;


Now you can add this field to the main form. Now see how we see when record is opened.


Our intension is catered and the relationship is clear to the user.

Issue of using self-referential n:n

Now we will examine the usage of self-referential many-to-many relationship. Just go to n:n relationship section of the customization and create one. Relationship information will be seen as below by default.


Now this is how we see from the front end.


Confusing! This shows two associate links with the same name.

When Dynamics CRM 2011 create many-to-many relationships, it creates a third table with primary keys of the two tables involved in and front end identifies this table twice (since its self-referential, both fields contains primary key of same table) when listing the relationships for UI. This makes sense for a developer, but not for a user. Biggest issue is these two links are not the same, but two side of the relationship.

Now we will do little change to identify this. I open the relationship properties and give two different custom labels for display options. I though it’s meaningful to use something like “To” and “From” to identify the two ends as below;


Now I am able to identify two associate links of our relationship distinctly. Now I open my sample record “test  000” and add “test 001” and “test 002” records as “related to” as shown below.


Now open one of “test 001” or “test 002” and see how the related record is shown. (Under “Related From” link)


I think this explains the role of two links very clearly.

After giving the custom labels this relationship became “little” clearer. That means, when using self-referential n:n, at least we have to give a “meaning” to the relationship that gives distinct names to two sides. Ex: “advised by – advised to” and etc. Otherwise this becomes a mess to the user. This is a constraint.

If we take the big picture, CRM 2011 got a smart concept of maintaining relationships which is called Connections. So it is recommended to use Connections for most cases.

Below presentation summarize the way Connections can be used.



Hope this is helpful.

Nov 21, 2012

Recursive workflows instead of windows services?

Please refer this for better solution.

In Dynamics CRM, we don’t have a facility to schedule an activity. Typically, one might need to change the status of a record without any interaction/ trigger. For example expiration of insurance policy. For this what we usually do is writing a windows service.

http://crmbusiness.wordpress.com/2011/05/24/crm-2011-how-to-schedule-recurring-workflows-in-crm-2011/

This blog article encourages us to use a recursive workflow instead of a windows service. It is a clever way of writing a workflow in a recursive pattern with delays to accomplish the objective. It seems fantastic since it can be achieved without any trouble or coding. I did a test workflow as this author explains (with a waiting time of 1 hour) and it worked well for me. 

Anyway, it is yet to be taken to the discussion table to check positive and negative consequences.

Also I think, it is better to do the state change like simple operation through the workflow and triggers a plug-in for rest of the complex operations if the requirement consists of lengthy logics.
Furthermore, we can even identify this call by filtering by asynchronous call filter as below.

if (context.CallerOrigin.GetType() == 
            typeof(Microsoft.Crm.Sdk.AsyncServiceOrigin))
        {
            //plug-in steps
        }

May 10, 2012

Handle Save, Save & close and unload of CRM form

This is a tricky situation one can come across in CRM 4.0 development. Leaving the form can happen in three ways. Those are SAVE, SAVE AND CLOSE, UNLOAD
We can write JavaScript for all three occasions.

UNLOAD

If you put below code in onLoad event, you can execute a script on unload.

// Put this in onload
window.onbeforeunload = function()
{
    alert("unload event")      
}

SAVE & SAVE AND CLOSE

Saving is straight forward in CRM form, but you can distinguish two ways of saving by event mode. Try below script in save event.

var _mode = event.Mode;
alert("Save event .. with mode : " +_mode);

Different modes could be easily distinguished as blow.



SAVE - 1
SAVE AND CLOSE – 2

Now my real focus is to do something when we leave a form with any of above three methods. Best example would be Quote entity can have total fields which depend on quotedetail entities under it (quotedetai is a child of quote). If we need them to be accurate at any given moment... we might need to do the calculations (unless we do it in plug-ins) whenever any of above events occur.

Way above event occurs are quite messy.
Please check what I found. Different combination of events trigger depends on circumstance.

SAVE (without change to form data) - Save event
SAVE (with change to form data) - save event, unload event
SAVE AND CLOSE (without change to form data) - save event, unload event

SAVE AND CLOSE (with change to form data) - save event, unload event

So, if we place the calculation event in all the three events, nothing will go wrong but in some occasions, it will run twice. Still I don’t know how to solve this simply. What we could do is maintaining a hidden check box (Boolean field) to say whether form needs recalculation. We should be smart enough to update this field even when child records are changed, if they influence the calculations.

Then we can add our own calculation methods to all three events, but calculation should always check the Boolean field before execution. In this way, we can avoid happening of calculation twice for no reason.

I am glad to hear if someone got better approach for this.

Mar 25, 2012

Issue of using Onload JavaScript for “create form” of Quote

This is just a simple warning. We all use onload JavaScript for any entity and we simply know how to handle them separately for Create form and Update form, when necessary.  For example, below is a popular way of doing something (for onLoad) just for “create form”.

var CRM_FORM_TYPE_CREATE = 1;     
var CRM_FORM_TYPE_UPDATE = 2;

if (crmForm.FormType == CRM_FORM_TYPE_CREATE)
{
  //some script create form onload
}

Now I am going to use this for Quote entity. Can you guess the issue related to this attempt?

Quote can be created from other entities; for example from Opportunity. This script will not work when we create a quote from opportunity. That’s because, when quote is being created from opportunity, quote is first created in the background before pop-up a form for user. What we really see is an Update form not a create form. In such cases, you may move in to plug-ins than Java Scripts. Actually, you don’t get a create event. Quite tricky! Isn’t it?

Mar 21, 2012

onChange vs onClick for checkbox?

Previously I wrote a post to tell how to use onClick event in CRM 4.0 for checkboxes. Recently I felt it is not completed. I think, it’s a matter of usability engineering expectations. You can simply use either onChange or onClick for checkboxes.

Will check onChange;
You can simply double click the field in customization form view and see the event. Then you know how to add the script in the relevant box and enable it. It’s as simple as that.


For example put below alert statement to check the firing of the event.

alert("onChange event fired");

Now if you browse the form after publishing... try to change the value of checkbox. What you will notice is you have to do two clicks to fire the event. You got to click the checkbox (nothing happens) and click somewhere else (to take the focus away) to confirm your change... then you can see the alert message pops up.

Will check onClick;
Here you are not touching anything in the relevant field... but write a method in the loading of the form as below. Now if you browse the form and do the previous test here.. you will notice, once you click the checkbox alert triggers. This means you only need one click.

deliveryCheckbox();

deliveryCheckbox = function()
{
    crmForm.all.msn_isDelivery.onclick = function()
    {
        alert("onClick event fired");
    }
}

As a conclusion, I would suggest you to use onClick for all the cases, if there is no special reason to use onChange. My point is “not just saving one mouse click” our users are not always technical people. I have seen users just click the check box and try to save the form. If we have used a script to work for onChange event, it wouldn’t have happened in such cases.

Related Posts;
Issues of using checkbox in CRM 2011

Nov 22, 2011

State (Statecode and statuscode) change through a JavaScript

We can find a nice code on status changes here. I tried to make it more generalised as below and it works for me.

SetStateRequest = function (_entityname, entityid, _state, _status)
{
    var requestMain = ""
    requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
    requestMain += "  <s:Body>";
    requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
    requestMain += "      <request i:type=\"b:SetStateRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
    requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
    requestMain += "          <a:KeyValuePairOfstringanyType>";
    requestMain += "            <c:key>EntityMoniker</c:key>";
    requestMain += "            <c:value i:type=\"a:EntityReference\">";
    requestMain += "              <a:Id>" + entityid + "</a:Id>";
    requestMain += "              <a:LogicalName>" + _entityname + "</a:LogicalName>";
    requestMain += "              <a:Name i:nil=\"true\" />";
    requestMain += "            </c:value>";
    requestMain += "          </a:KeyValuePairOfstringanyType>";
    requestMain += "          <a:KeyValuePairOfstringanyType>";
    requestMain += "            <c:key>State</c:key>";
    requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
    requestMain += "              <a:Value>" + _state + "</a:Value>";
    requestMain += "            </c:value>";
    requestMain += "          </a:KeyValuePairOfstringanyType>";
    requestMain += "          <a:KeyValuePairOfstringanyType>";
    requestMain += "            <c:key>Status</c:key>";
    requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
    requestMain += "              <a:Value>" + _status + "</a:Value>";
    requestMain += "            </c:value>";
    requestMain += "          </a:KeyValuePairOfstringanyType>";
    requestMain += "        </a:Parameters>";
    requestMain += "        <a:RequestId i:nil=\"true\" />";
    requestMain += "        <a:RequestName>SetState</a:RequestName>";
    requestMain += "      </request>";
    requestMain += "    </Execute>";
    requestMain += "  </s:Body>";
    requestMain += "</s:Envelope>";
    var req = new XMLHttpRequest();
    req.open("POST", _getServerUrl(), false)
    // Responses will return XML. It isn't possible to return JSON.
    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    var successCallback = null;
    var errorCallback = null;
    req.onreadystatechange = function () { SetStateResponse(req, successCallback, errorCallback); };
    req.send(requestMain);
}

SetStateResponse = function (req, successCallback, errorCallback)
{
    if (req.readyState == 4)
    {
        if (req.status == 200)
        {
            if (successCallback != null)
            { successCallback(); }
        }
        else
        {
            errorCallback(SDK.SAMPLES._getError(req.responseXML));
        }
    }
}

Also need below two supportive methods.

_getServerUrl = function ()
{
    var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
    var serverUrl = "";
    if (typeof GetGlobalContext == "function")
    {
        var context = GetGlobalContext();
        serverUrl = context.getServerUrl();
    }
    else
    {
        if (typeof Xrm.Page.context == "object")
        {
            serverUrl = Xrm.Page.context.getServerUrl();
        }
        else
        { throw new Error("Unable to access the server URL"); }
    }
    if (serverUrl.match(/\/$/))
    {
        serverUrl = serverUrl.substring(0, serverUrl.length - 1);
    }
    return serverUrl + OrgServicePath;
}

_getError = function (faultXml)
{
    var errorMessage = "Unknown Error (Unable to parse the fault)";
    if (typeof faultXml == "object")
    {
        try
        {
            var bodyNode = faultXml.firstChild.firstChild;
            //Retrieve the fault node
            for (var i = 0; i < bodyNode.childNodes.length; i++)
            {
                var node = bodyNode.childNodes[i];
                if ("s:Fault" == node.nodeName)
                {
                    for (var j = 0; j < node.childNodes.length; j++)
                    {
                        var faultStringNode = node.childNodes[j];
                        if ("faultstring" == faultStringNode.nodeName)
                        {
                            errorMessage = faultStringNode.text;
                            break;
                        }
                    }
                    break;
                }
            }
        }
        catch (e) { };
    }
    return new Error(errorMessage);
}


Few examples I tried;
Deactivating an account -> SetStateRequest("account", _accountid, 1, 2)
Changing a Salesorder to submitted state -> SetStateRequest("salesorder", _salesorderid, 1, 3)
Disqualifying a lead with reason "No longer interested" -> SetStateRequest("lead", _leadid, 2, 6)

Anyway, still I don’t know whether this works for all the entities... but so far so good :-)

Aug 4, 2011

Changing the icons of default entities

Can we change the icons of default entities? Answer for this question is “No”. Don’t encourage anyone to do so. CRM 4.0 is not supporting this change. I tried to search web to find a way of doing it but failed to find a proper way. However, I managed to do a little experiment by myself to gather some information on this.

Actually entity icons for CRM 4.0 are stored in below location and they are in .GIF format.

Program Files\Microsoft Dynamics CRM\CRMWeb\_imgs\

Actually, I tried to play around with account entity. When I replace below image files, I could change the account icon in the application such as account grid and detail view of selected account.

ico_16_1 (size 16x16 pixels)
ico_16_1_d (size 16x16 pixels)
ico_18_1 (size 16x16 pixels)
ico_lrg_1 (size 66x48 pixels)

There is something tricky; this doesn’t change the icons (links) vertically lined in the left hand side navigation panel. You can see a long vertical stripe like images in below folder;

\Program Files\Microsoft Dynamics CRM\CRMWeb\_imgs\imagestrips

Particularly, entity_imgs_1.gif (18x546) does the magic. I simply couldn’t realise how one static image could be used in CRM for different configurations of navigation. You will be amazed to see how smart CRM is using this one static strip for different arrangements of navigation panel. In order to make it sure, I did a little mark in the account icon in it and checked the outcome.


It changes the navigation pane.


I don’t know whether this gives a total solution, but this will help someone who wishes to try changing the icons of default entities. Anyway, I would say something for sure; creating icons for CRM is not a job of someone who knows “something” about imaging. It should be a job of professional, because you won’t be able to create a meaning full icon in just 16x16 pixels within a transparent background, unless you are really skilful.

FYI : Good site to search for icons for Dynamics CRM http://www.softicons.com