Wednesday, 15 February 2017

Error: "Unable to Login to Dynamics CRMOrganizationWebProxyClient is nullOrganizationWebProxyClient is nullOrganizationServiceProxy is nullOrganizationServiceProxy is null" during connecting to CRM Online using Xrm.Tooling.Connector

It’s been long time I have not written any post.
So, now I just want to share my experience when I have error once trying to connect to the CRM Online using Xrm.Tooling.Connector

Here is there error:

"Unable to Login to Dynamics CRMOrganizationWebProxyClient is nullOrganizationWebProxyClient is nullOrganizationServiceProxy is nullOrganizationServiceProxy is null"

Here is my connection string:
image

It does seem okay since I am following the example given by SDK:
image

But I receive that error as it makes me cannot connect to the CRM.

Then, how to solve it?

It is easy, just fix the URL and ensure that’s you have correct Username, password and also AuthType parameter

So, the mistake here is just the URL, change this to your unique organization, not the friendly/display name
image

*I know it can be misleading because the example is using the display name as same as you use to type your URL when you are trying to access through your browser.

*Change to:
image

To find the Unique name, please to the Customizations –> Developer Resource and find the unique name of your organization
image

Hope this helps!
Thank you

Tuesday, 6 September 2016

Utilize Custom Action to Help Filtering The Lookup View in CRM Form

Overview

Sometimes in our project, we have requirement to filter lookup based on some conditions and it can be achieved using addCustomView or addCustomFilter function.

And sometimes it is just not too easy to do it in Javascript or the complex fetch xml, so in my blog I just want to share another method to get the filtered result same as you wanted, that is using Javascript + Custom Action!

Detail

Following my previous post: http://missdynamicscrm.blogspot.sg/2014/08/crm-2013-using-addcustomfilter-to-get-filtered-lookup-field-based-on-linked-entity.html

So, considering you have this filter:
image

To get the result as per expected, you can use Custom Action.

Steps:

1. You need to create a custom action that give you output, either STRING or ENTITYCOLLECTION

2. Inside the custom action code, if you want to return string, you can use comma delimited concept, or using | as delimiter, or you can just return the Final XML Filter already.

If you use EntityCollection, you might need to parse it again.

3. Then create a javascript that can call the Custom Action, you can use this method for easy way:
http://www.magnetismsolutions.com/blog/paulnieuwelaar/2015/08/12/Call-Action-in-CRM-2015-Easily-from-JavaScript-Library

4. Then you get the result as parameter, you can just set it to the filter = “the Result” (if you use Final XML Filter as the Output) or you parse the GUID if you use the comma or | delimited concept, or if you use EntityCollection then you need to parse it back.

5. See the result

Basically, you just need to get this result:

image

Either you just easily using String as output or other method it is up to u.

But the point here is we can use Custom Action for solving complex filtering and remember that we can use impersonation also to get the data you want if it is related to the other entities as well, imagine if we also need to have multiple entities involved then it might be easier if we use Custom Action as we just replace the DLL if there is any other changes using Plugin Registration Tool.

Hope this helps!

Thanks,
Aileen

Modify the Delete (Dustbin icon) Button in the CRM Subgrid

Overview

Sometimes we need to modify the Delete button in the CRM Subgrid, example:

1. For preventing users to perform the delete button (but you dont want to just disable it)

2. Call another function or call custom function that needs client site programming (We can do plugin onDelete or onAssociate, but in case you want to show it in the client site)

3. To do impersonation

The Code

function modifyRibbon() {
    modifySubgridDeleteButtonEventHandler("subgrid_name_in_the_form", deleteSubgridRecord, true);
    discountStructureControl();
}

function deleteSubgridRecord() {
    alert("test");
}

function modifySubgridDeleteButtonEventHandler(subgridName, functionToCall, passGridControl) {
    try {
        //to store the original function ones
        var originalFunctionDeleteRecordSubgrid = Mscrm.GridCommandActions.deleteRecords;
        debugger;
        //add new standard subgrid
        Mscrm.GridCommandActions.deleteRecords = function (selectedControl, selectedControlSelectedItemReferences, selectedEntityTypeCode) {
            //if (typeof (gridControl.get_id).toString().toLowerCase() == "undefined") {} //no need since I replaced by the previous line
            if (selectedControl.get_id() != subgridName) {
                originalFunctionDeleteRecordSubgrid(selectedControl, selectedControlSelectedItemReferences, selectedEntityTypeCode);
            }
            else {
                if (passGridControl) {
                    functionToCall(selectedControl);
                }
                else {
                    functionToCall();
                }
            }
        }
    }
    catch (e) {

    }
}

Result

*After clicking the ‘Delete’ button

image

Note: This method is overwriting the CRM functions and it works for CRM 2013, for CRM 2015/2016, this function [Mscrm.GridCommandActions.deleteRecords] might have been changed, so need to find out the current function name based on your CRM Version. And again, it means it is unsupported Smile

Thanks!

Wednesday, 17 August 2016

Insert Label After the Field in CRM Form using Javascript

Hi all,
Long time I did not blog any post due to workload.
And this is my first post in this month (I know it is end of the month already)
This post basically a quick one because I have the requirement.

So, the users just want to have guidance when they entering inputs in the system.

Which we can have these solutions:

1. Tooltip (using CRM Field description)

See my post here:
http://missdynamicscrm.blogspot.sg/2014/05/crm-20112013-power-of-description.html

2. Using HTML Web Resource

This is a supported way and very useful as well. But it will make the form slower because will load the web resource and how many web resource you should create and insert. Well, you can create 1 common .html then pass the label text as the parameter

3. Using other way

So, unfortunately if those 2 solutions still not the best choice, we could go to another way using the help of CSS and Javascript.

*This is unsupported way…

And here is the Code

The Code


function insertLabelToField(fieldname, text, objSpan) {
    var elemDiv = document.getElementById(fieldname + "_c");
    //var tbl = document.createElement('table');     //elemDiv.parentNode.insertBefore(tbl, elemDiv.nextSibling);
    //var tr = tbl.insertRow();     //var td1 = tr.insertCell();     //td1.appendChild(elemDiv);     var td1 = elemDiv;     //td1.style.borderRight = "2px solid #c1c7c4";     td1.style.paddingBottom = "5.5px";
    var spanPref = null;
    if (!objSpan) {         spanPref = document.createElement('span');                 //you can change the color condition here         if (attr(fieldname).getRequiredLevel() == "required") {             spanPref.style.color = '#e31a1a';         }         else {             spanPref.style.color = '#4b4c54';         }         spanPref.style.fontSize = '10.51px';         spanPref.style.fontStyle = 'italic';     }     else {         spanPref = objSpan;     }     spanPref.id = 'spanPref_' + fieldname;         td1.appendChild(spanPref);     document.getElementById('spanPref_' + fieldname).innerText = text; }

How to Call

 
insertLabelToField(“fieldname”, "(Please describe me)");


And here is the Result

image

Hope this helps.

Thanks

Wednesday, 10 August 2016

Modify Subgrid Ribbon Behaviour Using Form Script

Introduction

A Quick post, just want to post how to Modify Subgrid button behaviour to always “Create New child record”, instead of “Add Existing record”.

This will use the similar method like described in the previous post before, but it does not call the custom funtion, it just will “redirect” the function to your “Create new record”.

Note: This is an unsupported way, for the supported way you can do two things:

1. Make the parent lookup field name to ‘Required’
2. Modify the Ribbon of the subgrid and Hide the ‘Add Existing’ button
*For your reference – > Nice post by Gareth: https://garethtuckercrm.com/2013/11/19/fixing-the-sub-grid-user-experience-in-crm-2013/

But, those will apply to the subgrid regardless the Condition, probably for the second method, you could apply some Enable/Display Rule on the subgrid ribbon.

But, if you want to do it only for specific entity and based on Parent Form condition (can be based on parent fields or even other entity values), then there is another way to do this that I will put the code in this post.

The Code

Ok, so back to the code.

Here is the code:
//function to insist create new record form instead of Add Existing
function openNewRecordFormFromSubgridButton(subgridName, passGridControl) {
    debugger;
    try {
        //to store the original function ones
        var originalFunctionAddNewStandard = Mscrm.GridRibbonActions.addNewFromSubGridStandard;
        var originalFunctionAddExistingStandard = Mscrm.GridRibbonActions.addExistingFromSubGridStandard;
        var originalFunctionAssociated = Mscrm.GridRibbonActions.addExistingFromSubGridAssociated;

        var primaryControl = document.getElementById('crmForm');
        var parentEntityId = Xrm.Page.data.entity.getId();
        var parentEntityTypeCode = Xrm.Page.data.entity.getEntityName();

        //add existing standard subgrid
        Mscrm.GridRibbonActions.addExistingFromSubGridStandard = function (gridTypeCode, gridControl) {
            if (gridControl.get_id() != subgridName) {
                originalFunctionAddExistingStandard(gridTypeCode, gridControl);
            }
            else {
                var primaryControl = document.getElementById('crmForm');
                originalFunctionAddNewStandard(gridTypeCode, parentEntityTypeCode, parentEntityId, null, gridControl);
            }
        }
  
        //and even possible for the N:N (but this is a rare scenario)
        //add associate subgrid (N:N)
        Mscrm.GridRibbonActions.addExistingFromSubGridAssociated = function (gridTypeCode, gridControl) {
            if (gridControl.get_id() != subgridName) {
                originalFunctionAssociated(gridTypeCode, gridControl);
            }
            else {
                var primaryControl = document.getElementById('crmForm');
                originalFunctionAddNewStandard(gridTypeCode, parentEntityTypeCode, parentEntityId, null, gridControl);
            }
        }
    }
    catch (e) {

    }
}

How to call:

openNewRecordFormFromSubgridButton("mysubgrid_name", true);

Result

*Previous
image
As we can see it opens lookup to look to the Existing record, it is 1:N, the record is almost possible already linked to another record, so it will make the users confused when they open this lookup.
*After
image

*And I never set any Required field to the parent lookup value, because this field is NOT always mandatory field, so it is conditional only.

Note: Use this method if you want to control the subgrid plus button based on some conditions and using the Form on Load script (easier), and it only works for the subgrid inside the form that load the function, other subgrid from another parent entity that does not have this function will not be affected, that is the advantage of using this method, to only affect subgrid of the child based on some parent entities and the function will be placed in the Parent Entity Form OnLoad and this is unsupported way.

“This is for dynamically control the subgrid behaviour through parent form onload functions based on some conditions logic, especially for 1:N relationship that usually already linked to another parent record, so that it is supposed to insist to open new Form, instead of asking the user to choose another existing record.

Hope this helps!

Thanks

Tuesday, 31 May 2016

Modify CRM View Query or Filter Criteria on Demand Dynamically using Plugin Retrieve

Hi guys,

Just want to share how we can modify the View Filter Criteria/Condition dynamically.

Introduction

Recently I have requirement that I need to create a View in CRM that there is no way to construct it from Advanced Find and make it dynamic.

For example,
I need to have query that:
1. The Date parameter is must be changed accodingly based on the today date and
2. Another parameter must get the value from a Configuration Entity
Ok, for number 1, we can force the users to always go to the View and change the date accordingly, but how about number 2?

So, my use case:

Show me the list of Customers that due date is in the next 21 days?
Meanwhile, 21 here is must be dynamically obtained from another Configuration entity.

So, this is nearly impossible, because even we use Advanced Find there is no way to use variable as parameter in the filter criteria that we need to query from another entity that is NOT related at all!
As we know that Advanced Find Query, only has limited operator and also it cannot Query from another entity, only limited to the related entities.

Use Case

So, to go to the code, I need to tell the scenario first, and to make it simpler, I just use this use Case:
I want to get all Active Customers that birthday is this Month.

This month is May for example.
So, I have a custom field = Birthday Month

Which I have auto-populated this field before with the Date Birth component (in another plugin).
So, now I need to always update the View to always Query to the:

Status = Active and Birthday Month = 5

And for the Next Month (June) should be:
Status = Active and Birthday Month = 6

Which last Month for April
Status = Active and Birthday Month = 4

Those number 5, 6, and 4 are supposed to be generated dynamically.

And I can’t use the This-Month operator because I dont have May 2016 Data, since I save the DOB, not updating every customer BOD every year plus 1 year.

You can also add another requirement, such as must be a Member Customer with Annual Income more than X, which X is you taken from Configuration entity.

What you need is just a new fetch XML or Query Expression that you can just convert use this request!


QueryExpressionToFetchXmlRequest req = new QueryExpressionToFetchXmlRequest();
req.Query = qenew;
QueryExpressionToFetchXmlResponse resp = (QueryExpressionToFetchXmlResponse)service.Execute(req);

But, for this use case, my point is jut to point out to you how to modify the Query just as per you wish (sorry as per Users’ whish Smile)

The Current View

image

So, for the post here, I just need to replace the Query from the Existing View (in your case, you might need to create a new View)

image

Then I got the savedqueryid from this view

The Code

public void Execute(IServiceProvider serviceProvider)

{
            #region must have


            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));


            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));


            // Create service with context of current user
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);


            //create tracing service
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));


            #endregion


            if (context.OutputParameters.Contains("BusinessEntity"))
            {
                var retrievedResult = (Entity)context.OutputParameters["BusinessEntity"];
                Entity entity = retrievedResult;
                string fetch = string.Empty;


                //the below GUID, you can do advance query to make this as non-hardcoded one, you can find by name as well, for example
                //just for my use case here, I post here as final GUID of the 'Active Customer' view GUID
                //in ACTUAL case, do not use harcoded one because it will change in different environment unless for Out of The Box Entities View
                if ((Guid)entity["savedqueryid"] == new Guid("00000000-0000-0000-00AA-000010001004")) 
                {
                    QueryExpression qenew = new QueryExpression("contact");


                    ConditionExpression activeCon = new ConditionExpression()
                    {
                        AttributeName = "statecode",
                        Operator = ConditionOperator.Equal,
                        Values = { 1 }
                    };


                    int currentMonth = DateTime.Now.Month; //this is the variable that dynamically you need to insert in


                    ConditionExpression birthdayCon = new ConditionExpression()
                    {
                        AttributeName = "ags_birthdaymonth",
                        Operator = ConditionOperator.Equal,
                        Values = { currentMonth }
                    };


                    qenew.Criteria.Conditions.Add(activeCon);
                    qenew.Criteria.Conditions.Add(birthdayCon);


                    //for easy fetch XML I use the Query Expression then convert to FetchXML
                    //but you can always use the directly generated fetchXML and also can get from Advanced Find as well
                    QueryExpressionToFetchXmlRequest req = new QueryExpressionToFetchXmlRequest();
                    req.Query = qenew;
                    QueryExpressionToFetchXmlResponse resp = (QueryExpressionToFetchXmlResponse)service.Execute(req);


                    //work with newly formed fetch string
                    string myfetch = resp.FetchXml;


                    //change the existing
                    entity["name"] = "Active Customer Birthday this Month"; 
                    entity["fetchxml"] = myfetch;
                }
            }
}



Code Explanation

*For the GUID of savedqueryid section, I got the ID and I implement in my code

image

*In your case, you need to do query, do not hardcode, please see my comment in the code as well.
For the Query Expresison, this is the place for you to change the logic as per your current requirement


image

Then for the Fetch XML

image

As the title mentioned, Then you need to register as POST event for RETRIEVE message, entity = savedquery.
Refresh the Advanced Find or View to see the result.

Result

As we can see that now, the Active Customer View (The View that we just now changed the fetchXML dynamically), now has this Query

image


You can also try to tweak your code, by just add additional conditional over the existing view by retrieving the fetch xml

string baseFetchXML = enSavedQuery["fetchxml"].ToString();

Then use this request to convert to Query Expression easily

FetchXmlToQueryExpressionResponse

Example of what I Did:



Remember, you can also add another Parameters.

So use this method for Querying:
1. Query that different from the static query from the View
2. Query that requires dynamic Date/Datetime variables
3. Query that needs condition obtained from another non-related entity
4. Query with variable from another Entity, let’s say Configuration Entity
5. Another Impossible Query using standard static Advanced Find
6. Also can do query that involving Current User, Security Role, or Team Query
7. Query requires Operator like “Does-Not-Equal Today” then you can utilize the “ON-OR-BEFORE” or “ON-ON-AFTER”
8. Query for “NOT IN”, then this one you can utilize the “DOES NOT EQUAL” function

But remember, you still need to use  FetchXML in the End.

Hope this helps!
Thanks

Friday, 13 May 2016

Filter N to N (Many to Many) Subgrid Lookup for Existing Records in CRM Without Modifying the Ribbon Action

Introduction and Post References

Basically, in this post, I just want to show how to filter the N to N lookup in the subgrid in CRM Form, without even modifying the Global Subgrid Ribbon in CRM.

image

In my previous post: http://missdynamicscrm.blogspot.sg/2015/07/filter-nn-subgrid-in-crm-2013-using.html, I have explained about a way how to filter the N to N Subgrid Lookup, but that is needed to modify the ribbon action globally and you might need to set another condition to actually skip is you need to filter only on specific entity, but your grid will be appearing in many entities, such as:

You want to filter the Contact lookup in, if you modify the subgrid ribbon, in every contact subgrid, the filter will be applied and you might need extra code of criteria to actually limit the  execution.
Good thing about that if your entity only used for single entity and you don’t need to specify is that only for subgrid or associated view, then modifying the ribbon is a better solution. however, if you want to filter only subgrid in specific entity or form, you can actually using another way.

Like you can refer to my posts:


So, in this post, basically I try to combine the ways to become one solution, to filter the N to N lookup that only applicable once the user load the form using single javascript.  This is unsupported customization, but, remember, modifying the N to N view also needs unsupported customization, so yeah, to reach the requirement we have to go further for unsupported customization eventhough strongly I also not recommend.

The Code

So, I just try to combine the code becoming:

*For CRM 2013

function modifyRibbon(subgridName) {
    try {
        //to store the original function ones
        var originalFunctionAddNewStandard = Mscrm.GridRibbonActions.addNewFromSubGridStandard;
        var originalFunctionAddExistingStandard = Mscrm.GridRibbonActions.addExistingFromSubGridStandard;
        var originalFunctionAssociated = Mscrm.GridRibbonActions.addExistingFromSubGridAssociated;
        //add new standard subgrid
        Mscrm.GridRibbonActions.addNewFromSubGridStandard = function (gridTypeCode, parentEntityTypeCode, parentEntityId, primaryControl, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAddNewStandard(gridTypeCode, parentEntityTypeCode, parentEntityId, primaryControl, gridControl);
                }
                else {
                    originalFunctionAddNewStandard(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }

        //add existing standard subgrid
        Mscrm.GridRibbonActions.addExistingFromSubGridStandard = function (gridTypeCode, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAddExistingStandard(gridTypeCode, gridControl);
                }
                else {
                    originalFunctionAddExistingStandard(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }
        //add associate subgrid (N:N)
        Mscrm.GridRibbonActions.addExistingFromSubGridAssociated = function (gridTypeCode, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAssociated(gridTypeCode, gridControl);
                }
                else {
                    originalFunctionAssociated(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }
    }
    catch (ex) {
        alert(ex);
    }
}

*For CRM 2015

function modifyRibbon(subgridName) {
    try {
        //to store the original function ones
         var originalFunctionAddNewStandard = Mscrm.GridCommandActions.addNewFromSubGridStandard;
         var originalFunctionAddExistingStandard = Mscrm.GridCommandActions.addExistingFromSubGridStandard;
         var originalFunctionAssociated = Mscrm.GridCommandActions.addExistingFromSubGridAssociated;
        //add new standard subgrid
        Mscrm.GridRibbonActions.addNewFromSubGridStandard = function (gridTypeCode, parentEntityTypeCode, parentEntityId, primaryControl, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAddNewStandard(gridTypeCode, parentEntityTypeCode, parentEntityId, primaryControl, gridControl);
                }
                else {
                    originalFunctionAddNewStandard(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }

        //add existing standard subgrid
        Mscrm.GridRibbonActions.addExistingFromSubGridStandard = function (gridTypeCode, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAddExistingStandard(gridTypeCode, gridControl);
                }
                else {
                    originalFunctionAddExistingStandard(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }
        //add associate subgrid (N:N)
        Mscrm.GridRibbonActions.addExistingFromSubGridAssociated = function (gridTypeCode, gridControl) {
            if (gridControl != null) {
                if (gridControl.get_id() != subgridName) {
                    originalFunctionAssociated(gridTypeCode, gridControl);
                }
                else {
                    originalFunctionAssociated(gridTypeCode, gridControl);
                    filterTrainerProfile(gridTypeCode, gridControl);
                }
            }
        }
    }
    catch (ex) {
        alert(ex);
    }
}

* So the filterTrainerProfile(gridTypeCode, gridControl); is your custom function to filter the view, some as you filter and create new custom view that I also have example in my previous post:
http://missdynamicscrm.blogspot.sg/2015/07/filter-nn-subgrid-in-crm-2013-using.html.

Remember, to get the GUID of the list record to show, you can always using CRM Javascript or in CRM 2013 and above you can use smarter way that is to combine with Custom Action, since Custom Action can be called through Javascript.

http://missdynamicscrm.blogspot.sg/search?q=custom+action

Hope this helps! Jiayou!