Friday, December 16, 2016

Associate Lead to Email Send in Dynamics CRM


The Associate Lead to Email Send custom workflow activity will accept a Lead and an Email Send and associate the two via a CRM many-to-many relationship named cdi_emailsend_lead

Inputs

Name
Type
Notes
Email Send
EntityReference (cdi_emailsend)
Lookup to the Email Send
Lead
EntityReference (lead)
Lookup to the Lead


Name
Type
Notes
Success
Boolean
Indicates Success or failure of the code

OutputsAssociate two records

using Microsoft.Xrm.Sdk;

using Microsoft.Xrm.Sdk.Messages;

using Microsoft.Xrm.Sdk.Workflow;

using System;

using System.Activities;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;


namespace CustomWorkflow

{

    public class AssociateContactToEmailSend : CodeActivity

    {

        #region Input Properties

        [RequiredArgument]

        [Input("Contact")]

        [ReferenceTarget("contact")]

        public InArgument<EntityReference> Guest { get; set; }


        [RequiredArgument]

        [Input("Email Send")]

        [ReferenceTarget("cdi_emailsend")]

        public InArgument<EntityReference> EmailSend { get; set; }

        #endregion

        protected override void Execute(CodeActivityContext context)

        {

            IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>();

            IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>();

            IOrganizationService service = serviceFactory.CreateOrganizationService(workflowContext.UserId);

            //Create the tracing service

            ITracingService tracingService = context.GetExtension<ITracingService>();


            var guest = Guest.Get(context);

            var emailSend = EmailSend.Get(context);


            tracingService.Trace("Guest:" + guest.Id);

            tracingService.Trace("Email Send:" + emailSend.Id);


            Microsoft.Xrm.Sdk.EntityReference Moniker2 = new Microsoft.Xrm.Sdk.EntityReference();

            Moniker2.Id = guest.Id;

            Moniker2.LogicalName = "contact";//Entity Name


            // Code Create Moniker for second Entity: New_CustomEntity

            Microsoft.Xrm.Sdk.EntityReference Moniker1 = new Microsoft.Xrm.Sdk.EntityReference();

            Moniker1.Id = emailSend.Id;

            Moniker1.LogicalName = "cdi_emailsend";

            tracingService.Trace("Started Assosiating");

            AssociateManyToManyEntityRecords(service, Moniker1, Moniker2, "cdi_emailsend_contact");

            tracingService.Trace("Completed Assosiating");

        }


        private bool AssociateManyToManyEntityRecords(IOrganizationService service, Microsoft.Xrm.Sdk.EntityReference moniker1, Microsoft.Xrm.Sdk.EntityReference moniker2, string strEntityRelationshipName)

        {

            try

            {

                AssociateRequest request = new AssociateRequest();

                request.Target = moniker1;

                request.RelatedEntities = new EntityReferenceCollection { moniker2 };

                request.Relationship = new Relationship(strEntityRelationshipName);


                // Execute the request.

                service.Execute(request);



                return true;

            }

            catch (Exception exp)

            {

                return false;

            }

        }

    }

}








Thursday, December 15, 2016

Update the fetchXML that will be used by the Sub- grid in Dynamics CRM

///<reference path="XrmPage-vsdoc.js"/>
function UpdateSubGrid()
{
 window.scroll(0,0);
 var rereferralsGrid = document.getElementById("rereferrals");
 var lookupfield = new Array;
 lookupfield = Xrm.Page.getAttribute("ftd_familymember").getValue();
 intakeid = Xrm.Page.getAttribute("safy_intakeid").getValue();

 if (lookupfield != null)
 {
     var lookupid = lookupfield[0].id;
 }

else
 {
    return;
 }


if (rereferralsGrid ==null || rereferralsGrid.readyState != "complete")
{
    setTimeout('UpdateSubGrid()', 2000);
    return;
}   

 //Update the fetchXML that will be used by the grid.
 var fetchXml = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" 
 fetchXml += "<entity name='ftd_intakeassessment'>";
 fetchXml += "<attribute name='safy_intakeassessment'/>";
 fetchXml += "<attribute name='ftd_intakeassessmentid' />";
 fetchXml += "<attribute name='safy_intakeid' />";
 fetchXml += "<attribute name='safy_ica_status_reason' />";
 fetchXml += "<attribute name='safy_ica_status' />";
 fetchXml += "<attribute name='safy_ica_provider_worker_name' />";
 fetchXml += "<attribute name='safy_ica_name' />";
 fetchXml += "<attribute name='safy_ica_intake_office' />";
 fetchXml += "<attribute name='safy_familymembername' />";
 fetchXml += "<attribute name='safy_ica_assess_supervisor' />";
 fetchXml += "<order attribute='safy_intakeid' descending='false' />";
 fetchXml += "<filter type='and'>";
 fetchXml += "<condition attribute='safy_initialassessment' operator='eq' value='1' />";
 fetchXml += "<condition attribute='safy_intakeid' operator='ne' value='"+ intakeid +"' />"
 fetchXml += "<condition attribute='ftd_familymember' operator='eq' uiname='Family Member' uitype='ftd_familymember' value='" + lookupid + "' />";
 fetchXml += "</filter>";
 fetchXml += "</entity>";
 fetchXml += "</fetch>";

 rereferralsGrid.control.SetParameter("fetchXml", fetchXml);
 rereferralsGrid.control.refresh();
}

Wednesday, December 14, 2016

Formats a postal code & Sets a lookup field in Javascript

function formatPostalcode(pcode) {
    var regexObj = /^\s*([a-ceghj-npr-tvxy]\d[a-ceghj-npr-tv-z])(\s)?(\d[a-ceghj-npr-tv-z]\d)\s*$/i
    if (regexObj.test(pcode)) {
        var parts = pcode.match(regexObj);
        var pc = parts[1] + " " + parts[3];
        return pc.toUpperCase();
    }
    else {
        return pcode;
    }
}



function SetLookup(fieldName, idValue, textValue, typeValue) {
    var value = new Array();
    value[0] = new Object();
    value[0].id = idValue;
    value[0].name = textValue;
    value[0].typename = typeValue;

    setDisabledField(fieldName, value);
}

Gets the current user and enters string into specified field

function loggedUser(field) {
    var user = Xrm.Page.context.getUserId();
    var userId = user.substring(1, 37);
    var serverUrl = document.location.protocol;
    serverUrl += "//" + document.location.host;
    serverUrl += "/" + Xrm.Page.context.getOrgUniqueName();
    var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
    var ODATA_EntityCollection = "/SystemUserSet";
    var ODATA_Query = "(guid\'" + userId + "')";
    var ODATA_Final_url = serverUrl + ODATA_ENDPOINT + ODATA_EntityCollection + ODATA_Query;

    $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        datatype: "json",
        url: ODATA_Final_url,
        beforeSend: function (XMLHttpRequest) {
            XMLHttpRequest.setRequestHeader("Accept", "application/json");
        },
        success: function (data, textStatus, XmlHttpRequest) {
            var userName = data.d.FullName;
            Xrm.Page.getAttribute(field).setSubmitMode("always");
            Xrm.Page.getAttribute(field).setValue(userName);
        },
        error: function (XmlHttpRequest, textStatus, errorThrown) {
            alert('Error: ' + ODATA_Final_url);

        }
    });

}

Checks to see if the user has a particular role in Dynamics CRM

//  UserHasRole(roleName)           Checks to see if the user has a particular role
function UserHasRole(roleName) {
    var oXml = GetCurrentUserRoles();
    if (oXml != null)
    {
        var roles = oXml.selectNodes("//BusinessEntity/q1:name");
        if (roles != null)
        {
            for (i = 0; i < roles.length; i++)
            {
                if (roles[i].text == roleName)
                {
                    return true;
                }
            }
        }
    }
    return false;
}

//  GetCurrentUserRoles()           Gets user's security roles
function GetCurrentUserRoles() {
    var xml = "" +
     "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
     "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
     GenerateAuthenticationHeader() +
     " <soap:Body>" +
     " <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
     " <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
     " <q1:EntityName>role</q1:EntityName>" +
     " <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
     " <q1:Attributes>" +
     " <q1:Attribute>name</q1:Attribute>" +
     " </q1:Attributes>" +
     " </q1:ColumnSet>" +
     " <q1:Distinct>false</q1:Distinct>" +
     " <q1:LinkEntities>" +
     " <q1:LinkEntity>" +
     " <q1:LinkFromAttributeName>roleid</q1:LinkFromAttributeName>" +
     " <q1:LinkFromEntityName>role</q1:LinkFromEntityName>" +
     " <q1:LinkToEntityName>systemuserroles</q1:LinkToEntityName>" +
     " <q1:LinkToAttributeName>roleid</q1:LinkToAttributeName>" +
     " <q1:JoinOperator>Inner</q1:JoinOperator>" +
     " <q1:LinkEntities>" +
     " <q1:LinkEntity>" +
     " <q1:LinkFromAttributeName>systemuserid</q1:LinkFromAttributeName>" +
     " <q1:LinkFromEntityName>systemuserroles</q1:LinkFromEntityName>" +
     " <q1:LinkToEntityName>systemuser</q1:LinkToEntityName>" +
     " <q1:LinkToAttributeName>systemuserid</q1:LinkToAttributeName>" +
     " <q1:JoinOperator>Inner</q1:JoinOperator>" +
     " <q1:LinkCriteria>" +
     " <q1:FilterOperator>And</q1:FilterOperator>" +
     " <q1:Conditions>" +
     " <q1:Condition>" +
     " <q1:AttributeName>systemuserid</q1:AttributeName>" +
     " <q1:Operator>EqualUserId</q1:Operator>" +
     " </q1:Condition>" +
     " </q1:Conditions>" +
     " </q1:LinkCriteria>" +
     " </q1:LinkEntity>" +
     " </q1:LinkEntities>" +
     " </q1:LinkEntity>" +
     " </q1:LinkEntities>" +
     " </query>" +
     " </RetrieveMultiple>" +
     " </soap:Body>" +
     "</soap:Envelope>" +
     "";

    var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

    xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
    xmlHttpRequest.setRequestHeader("SOAPAction", " http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
    xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
    xmlHttpRequest.send(xml);

    var resultXml = xmlHttpRequest.responseXML;
    return (resultXml);
}

Show Hide Sections in MS Dynamics CRM

/************************************************
stateSectionsOnChange - function to handle which fields 
to show based on the state selected
************************************************/
function stateSectionsOnChange() {
    var closeTab = Xrm.Page.ui.tabs.get("Professional Info");
var showTXSection = false;
    var showOHSection = false;
    var showINSection = false;

    switch (Xrm.Page.getAttribute("col_addressstate").getText()) {
        case "Texas":
showTXSection = true;
            showOHSection = false;
showINSection = false;
            break;
        case "Ohio":
showTXSection = false;
            showOHSection = true;
showINSection = false;
            break;
        case "Indiana":
showTXSection = false;
            showOHSection = false;
showINSection = true;
            break;
    }

    closeTab.sections.get("Texas").setVisible(showTXSection);
    closeTab.sections.get("Ohio").setVisible(showOHSection);
    closeTab.sections.get("Indiana").setVisible(showINSection);
}
/***    end stateSectionsOnChange     ***/

Tuesday, November 1, 2016

Want to delete a managed component? Use the clone solution feature in CRM 2016.


Have you ever had the need to delete a component present in a managed solution? Let’s say, I have a solution ‘Delete from Managed’ with two entities ‘Entity to Retain’ and ‘Entity to Delete’ at the development server. I export it as a managed solution and then import it at the production server. Everything works fine. Some stage later, you find that ‘Entity To Delete’ is no longer needed and you want to remove it from the production server, but you cannot do so because the solution is a managed one. What do I do now?

Before CRM 2016, there was a work around to this issue i.e. holding solution. In CRM 2016 I’ve found that we could use the clone solution feature to complete this task.

Let’s see it step by step.



The screen below shows my original solution.
 









First, I clone the solution at the development server.












Notice that cloning solution increases the version number of the solution.

I then, delete the unused entity ‘Entity To Delete’ from the solution. I export it again as a managed solution and then import it at the production server.

The initial screen while importing, where I select the zip file, is shown below,








I click next and get the following screen,








I click next again, and get the following screen,






This is an important step. Here we need to make sure that we select the check box named ‘Stage for Upgrade’.

I click ‘Import’ and the import starts.

Once the import finishes successfully, your CRM instance will have two solutions,

DeleteFromManaged
DeleteFromManaged_Upgrade (CRM creates this renamed solution)


And you are presented the following screen,






Click ‘Apply Solution Upgrade’.

CRM 2016 will create a solution named same as your solution, but with a suffix ‘_Upgrade’. CRM 2016 will automatically manage to delete the component for you, and at successful completion of this step, you will only have one final solution named ‘DeleteFromManaged’. The entity ‘Entity To Delete’ will no longer be present at the production server.



Hope this helps!!!


Tuesday, July 26, 2016

Get count of Attachments for Email in Dynamics CRM without code

Recently we had a requirement from our customer to show the number of attachments for each email in a view. The number needs to be reflected whenever the user refreshes the view.
Simple requirement right? And what is coming to your mind? Plugins? Workflows?
Well if you are thinking of the Plugins and workflows, I am sure you are not alone. In fact the first thing that came to my mind was the same. But we are in CRM 2016 right? And is there no other way to achieve this?
I brainstormed for sometime and then came up with the below solution. Believe me it is a simple solution without any code and I am pretty sure you would like it. No it is not rollup field. It is using the calculated field feature of Dynamics CRM.
Let us first look at the email entity in CRM. A quick glance at the email entity and you could see there is field already in the email entity called ‘Attachment Count’. Wow! Can’t we use this field. Unfortunately the answer is ‘No’. If you open this field, it is a non-editable field and it won’t appear in your view and advanced find as well. Nor you can use it in roll-up fields or calculated fields editor. Sad isn’t it.

image
image
I was pretty sure that this field could give us the count of attachments for an email. But how to get around the limitation. Well you have CRM 2016 after all which is just awesome. All we consultants need to do is to explore it a bit to make it work for all situations Smile
To start with I created a solution with the email entity in it. And then I created a dummy field called ‘Attachment Count Dummy’. Don’t worry I am just creating a dummy field here. I will delete it later when done. As of now just make sure you make the field as ‘whole number’ type.
image

Great. So we are done with our first step. Now we create our real field to store the attachments. I name it the same ‘Attachment Count’ of type whole number. But this I make it a calculated field.
image
I set it to be equal to ‘Attachment count dummy’ field. You may be asking why not set this field to the OOBattachmentcount field. Because as I mentioned before, the OOB attachmentcount field cannot be used in calculated field editor.
image
Save and close the editor. Include this calculated field in whichever views you want.
All set and done. Now comes the real trick. Publish everything and export the solution. Once the solution is exported, unzip it and you would see the contents. It should have a Formulas folder where CRM stores all the calculated field formulas.
image

Open the folder and then open the formula of the ‘Attachment Count’ calculated field .xaml file in a xml editor of your choice. Replace the dummy field name with the name ‘attachmentcount’.  Note this is the most important step.

Before:
image

After:
image
Save and close the file. Now zip the contents of the solution back and import the solution again in your CRM environment. Once the publish is completed, open advanced find and then check for the views
image
I open my email, attach one more attachment and as soon as I refresh the view, I could see the count being incremented.
image

Are we missing something here? Yes. You remember we created an extra dummy field. Go ahead and delete it. It won’t do any harm if you delete it. But you would be left with an unnecessary field.
Wonderful isn’t it? I hope you liked the idea

Friday, July 15, 2016

Date and Time field behavior in MS CRM

For CRM versions earlier than CRM Online 2015 Update 1 and CRM 2016 (on-premises), you cannot define the behavior of the date and time values. By default, the date and time values are stored as  UserLocal.

But in latest version,  behavior of date and time field is classified as 3 types.




UserLocal:
·        This behavior always stores the date and time in UTC format. While retrieving, it will returns date and time in UTC format.

·         When user trying to update date and time, if user enters date in UTC, system will update the value as it is or else it will convert entered date and time into UTC format then stores.

·         This behavior is used for system attributes like CreatedOn and ModifiedOn, and cannot be changed. You should use this behavior for custom attributes where you want to store date and time values with the time zone information

DateOnly:
·         This behavior will stores date only and time will be always stores as 12:00AM (00:00:00).
·         While retrieving the value also, time will always carries as 12:00AM.
·         This behavior should be used for custom attributes that store birthdays and anniversaries, where the time information is not required

TimeZoneIndependent:
·         Stores the date and time in system regardless of user time zone.
·         While updating the date and time also, it will stores date and time what user enters as it is.

·         This behavior should be used for attributes that store information such as check in and check out time for hotel

If you do not specify the behavior while creating a date and time attribute, the attribute is created with the UserLocal behavior by default

Improving MS CRM Performance

Performance on MS CRM is always a crucial thing and we may follow different ways to achieve the performance thing. Below is the one more approach we can improve the performance bit more.
In IIS setting of a website where MS CRM is hosted, there we can change the Output Cache property. By changing this property to true, initially any entity record load may take bit time; later on it will open the records in much lesser time. This is quite a good approach to improve the performance.
Below screenshot explains where to change the output Cache settings

Open IIS, click on Microsoft Dynamics CRM site-> On Right side Panel click on Feature View-> Configuration Editor









































(source of below description: MSDN)
What is omitVaryStart:
Gets or sets a value indicating whether the vary header is enabled.


true if the vary header is enabled; otherwise, false. The default is false.

The vary header indicates the request-header fields that the server uses to determine which of multiple cached responses are sent in response to a client request. The default for the OmitVaryStar property is false. By default, ASP.NET sends the vary header in all POST requests, as well as in all GET-request query strings. If the OmitVaryStar is true, ASP.NET omits the vary header when returning the response for cached pages, provided that the GET request to a response is cached with no VaryByCustom property and thePOST request to a response is cached with no VaryByParam property and no VaryByCustom property.

Upsert in MS Dynamics CRM

If we want to update a record in any entity, we should require GUID. If we know the GUID, we can do it easily, if not, we should retrieve the GUID of that record first, then we can update the record. Here, two database calls (Retrieve and Update) we are making which impacts performance of an application.


In these scenarios, Upsert will be very useful. Upsert request will check in database whether record exists in database, if exists it will update the record or else it will create the record.






So, how do we know that whether Upsert create or update record in each call?


This information we can get from UpsertResponse which contains a Boolean property RecordCreated. If RecordCreated contains “true” it indicates Upsert created the record else updated the record.


Sample Code:

               Entity testEntity = new Entity("new_test");
                testEntity["new_test1"] = "test1";
                testEntity["new_test2"] = "test2";
                testEntity["new_test3"] = "test3";

                UpsertRequest request = new UpsertRequest()
                {
                    Target = testEntity
                };
                try
                {
                    UpsertResponse response = (UpsertResponse)_serviceProxy.Execute(request);
                }
                catch (Exception ex)
                {
                  }


Note: For Microsoft Dynamics CRM Online organizations, this feature is available only if your organization has updated to Dynamics CRM Online 2015 Update 1. This feature is not available for Dynamics CRM (on-premises).

Get files of last hour in Azure Data Factory

  Case I have a Data Factory pipeline that should run each hour and collect all new files added to the data lake since the last run. What is...