Tuesday, September 18, 2018

Order Product Bundle Items


In this post, I am going to describe how to retrieve Sales Order Product items for a particular Product Bundle. If a bundle has 10 products and this bundle is added in sales order lines. This will make 11 sales order lines one header with bundle title and rest as bundle products.
So if we want to get quantity of all bundle items excluding header bundle item then we need to find the relationship and data values insert by Dynamics 365 in backed.
In below plugin, I am demonstrating how to get the bundle item id (sales order line item). Then we can query (fetchxml / query expression) to retrieve all lines having the bundle id in Parent Bundle Id.

Plugin (In this plugin I am showing how to  retrieve bundle id)

using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test.Plugins
{
    public class BundleProductQtyCheck : IPlugin
    {
        bool IsDebug = false;
       
        public void Execute(IServiceProvider serviceProvider)
        {
            IsDebug = false;
            Entity DebugEntity = new Entity("new_plugindebug");
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
           
            string DebugDesc = " Started...";
           
            try
            {

           
               


                string strGcTest = "";
                string NEWLINE = "";
                strGcTest = " Plugin Debug started... at " + DateTime.Now + NEWLINE;
               


                string entityName = "";

                Entity OrderLine = null;
                Entity RetrievedOrderLine = null;
                OrderLine = (Entity)context.InputParameters["Target"];
                entityName = OrderLine.LogicalName;

                if (context.MessageName == "Update")
                {
                    if (OrderLine.Attributes.Contains("shipto_telephone"))
                        return;
                    RetrievedOrderLine = service.Retrieve(OrderLine.LogicalName, OrderLine.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
                    if (RetrievedOrderLine.Attributes.Contains("parentbundleid")) {
                        OrderLine["shipto_telephone"] = ((Guid)RetrievedOrderLine["parentbundleid"]).ToString();
                        service.Update(OrderLine);

                    }
                }

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex.InnerException);
                tracingService.Trace(ex.Message);
                if (IsDebug)
                {
                    DebugEntity["new_name"] = this.ToString();
                    DebugEntity["new_description"] = DebugDesc + "\n" + DebugEntity.GetAttributeValue<string>("new_description") + ex.Message + "\n" + ex.ToString();
                    service.Create(DebugEntity);
                }
            }
        }

    }
}








㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Tuesday, September 4, 2018

Auto No Dynamics 365 V8.2

I was involved in project using Microsoft Dynamics 365 V8.2. I downloaded the auto number solution, one available for Dynamics CRM 2016 and previous releases. This solution was working fine on previous versions but on Dynamics 365 V8.2, there was error using this solution. I searched and tried to find some alternatives but was not able to find any one. So I thought to develop my own Auto-Number utility / solution for Microsoft Dynamics 365 V8.2.

Below are screen shots for the entity holding configurations for auto number.


At this time Auto No Length is fixed to 5. I will make that dynamic later. Below are details of configuration
Name: Put whatever name you want
Auto No Length: Put 5 (Fix at this time)
Auto No Value: Put value from where you want auto no to increment (First number is 0)
Entity Name: Name of entity
Mapping Field: Field schema name which will hold the auto number value
Prefix / Sufix: Will update in next versions
Zero Pad: Currently zeros are displayed with length of 5 i.e. for number 1 four zeros will be added. This is not changeable int current version

Currently Plugin is also not dynamic (Based on configuration value to fire plugin). Customization Consultant / Developer has to manually register plugin for desired entity and message.

Below is plugin step screen shot.























This is Auto No Solution for Dynamics 365 V8.2 (Uploading soon....)


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Monday, September 3, 2018

Web API Invoke Roll up Field Update

In this post I am sharing the solution to requirement of updating Roll up field using Web API.

Tested on: Dynamics 365 V9.0 Online
Entity Name = new_projects
Field Name = new_totalactualduration


function UpdateRollUp(){
var id ="";
var url = "https://WebAPIAddress/api/data/v9.0/CalculateRollupField(Target=@tid,FieldName=@field)?@tid={%27@odata.id%27:%27new_projects()%27}&@field=%27new_totalactualduration%27"

}




㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Check User Specific Role - Web API (1 API Call) - Dynamics CRM 365

I was working in a requirement where ribbon customization was required based on user role. Many ribbon buttons were hidden / visible based on different roles assigned to user. There was also custom button on ribbon bind with custom JavaScript function.

 Due to more buttons bind with Enable Rules to set their visibility result in slow page load and increase user wait for Ribbon Buttons.

Previously, I was getting user roles ids from XRM method and then checking the name of roles by getting role name through Web API retrieve request and passing guid of role as parameter. This means if there are 7 roles assigned to user then system will make 7 API Calls.
Also on custom button trigger, System was again loading the webresource and as API Calls were made outside any function therefore system also made API Calls before triggering custom ribbon button function. There were separate web resource for Enable Rules of Ribbon Buttons. There were methods which were used in Entity Main web resource and in Enble Rules web resource.
What I did was that I create another web-resource and write a class of Dynamics CRM Roles. This class contain method and an array to load all roles from Dynamics CRM 365. So I loaded the array with role name and role guid using the Web API retrieve request for roles. This technique loaded the array with all roles and made the API Call only once.
Now in my logic and other areas where I was checking with role name whether user is assigned that or not, I was using the roles array to match.
So this result in making Web API Call only once.

Here is my code logic.

Updating shortly ....






㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Custom Workflow to send Email to All Team members

There was a requirement in project to send email to all Team members of a certain Queue, whenever a new item is added to that Queue.
To achieve this requirement, I have developed custom workflow so that configuration can be done from the Dynamics Workflow interface / window.

Below is Dynamics Workflow screen
For Beginners: Solution -> Processes -> Create New Process as workflow



















































Saturday, March 31, 2018

Check User Specific Role - Web API - Dynamics CRM 365

In this post, I am going to demonstrate how to check that current logged in user has specific role or not in Dynamics CRM 365 using JavaScript & Web API.


function IsRoleExist(RoleName) {
    var currentUserRoles = Xrm.Page.context.getUserRoles();
    for (var i = 0; i < currentUserRoles.length; i++) {
        var userRoleId = currentUserRoles[i];
        if (GetRoleName(userRoleId) == RoleName) {
            return true;
        }
    }
    return false;

}

function GetRoleName(RoleId) {
    var select = "roles(" + RoleId + ")?$select=name";

    var result = AWXRM.WebAPISelectVersion(select, "8.2");
    var Rolename = result["name"];
    return Rolename;

}

function OnLoad() {

var Role_Admin = "System Admin_1";
var IsRoleExist = null;

   if (IsRoleExist(Role_Admin))
            IsRoleExist = true;
        else
            IsRoleExist = false;
}

Dependency:
Need this library to be included in form load / page load
AWXRMLibrary


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn



Enable Rule for Default Buttons - Ribbon Workbench - Dynamics CRM 365


1) Install Ribbon Workbench from here
2) Import solution in your Dynamics CRM 365 instance
3) A button "RIBBON WORKBENCH 2016" is created in Solution Page. Click on it
























4) Now new window is opened. Select your desired solution containing entity to be customized. It is better to create a separate solution to be used for ribbon customization and contains only desired entity. In this scenario I have created a new solution "Ribbon Solution" contain only Case entity. Here I am selecting solution Ribbon Solution

























5) Now solution is opened in ribbon workbench. Select your desired entity and on button right mouse click. Now select Customize Command. (In my case as button is already customized therefore this command is shown disabled)























6) Now in command section, select the generated command and click on Add Enable Rule. Now select Add New Enable Rule.




























7) Now click on Add Step & select CustomRule. There are others rules to apply enable rules on button. Here I am only showing the CustomRule.























Friday, March 30, 2018

Object Oriented Javascript - Dynamics CRM 365

I have done lot of work using javascript in Dynamics 365 (CRM) / CRM Projects. During many routine tasks I always used to think about how to optimize my code?, so able to do more with less code. Therefore achieve code reuse-ability, extensiveness and object oriented style. In below Javascript technique I am trying to demonstrate this approach.






function Customer() {

    this.name =  AWXRM.GetXRMAttributeGetVal("name");
    this.custid = AWXRM.GetXRMAttributeGetVal("accountnumber");
    this.address = AWXRM.GetXRMAttributeGetVal("wtr_plot");
    this.customertype = AWXRM.GetXRMAttributeGetText("wtr_customertype");
    this.cnic = AWXRM.GetXRMAttributeGetVal("wtr_cnic");
    this.phone = AWXRM.GetXRMAttributeGetVal("telephone2");
    this.cell = AWXRM.GetXRMAttributeGetVal("telephone1");
    this.guid = Xrm.Page.data.entity.getId();
    this.guidplan = this.guid.replace("{", "");
    this.guidplan = this.guid.replace("}", "");
    this.invoices = {};
    this.invoices.invoicedetails = {};

}

function OnSave(){

   var customer = new Customer();

}




㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn

Saturday, March 24, 2018

Calling REST Web Service in Plugin


I was involved in a project where I have to consume REST Web services to integrate with Dynamics CRM 2016. Below plugin was used to perform this operation.

The web service used POST operation. and retrieved a specific authentication string present in response headers.



























Wednesday, January 17, 2018

Custom Workflow vs Plugin


Workflow / Custom Workflow:
1) Can be triggered on less than 10 actions (Create, Edit etc)
2) Have Input, Output Parameters
3) Provide Administrators interface / window to configure the parameters or triggers configurations.




Plugins
1) Run on 200+ Messages
2) Don't provide interface to configure parameters
3) Provide Plugin Registration tool to register and configure attributes and plugin to be ran on.



I wrote in hurry, I will update the plugin part later. If you can add for me, that will be great!!!


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn

Tuesday, October 10, 2017

Dynamics CRM Development using Object Oriented Design Techniques

#CompositeDesignPattern
Dynamics CRM development can be much easier and efficient using "Object Oriented Design" techniques. Let me explain.

Suppose the case study of dynamics CRM is such that xyz business is having customers as companies each company has sub branches which is again customers. Customers have people representing contacts for the business.

If I say that customers are accounts then sub branches means self relationship with accounts so there is 1-n  self relation between accounts. Now for representatives of company, we have contacts entity in CRM. so there is 1-n relation between accounts and contacts.

Means
1 - N relation : Accounts -> Accounts
1 - N relation : Accounts -> Contacts

Now suppose I want to get all such information, logic and relationships in terms of object oriented design, what I should do is. Firstly I will identify the objects in this case study.

I have two objects Accounts and Contacts.



So now I will surely and definitely  define classes for these objects. i.e. the pillar of object oriented design.
I have Account class and Contact class. Should I start writing these classes and adding properties for the respective objects? But what if I have properties which are same in both objects. Or I will prefer to make and identify properties similar for both classes and all other classes which can be added later for CRM case studies.

So for the purpose of adding similar properties I will like to define an Abstract class. This class will hold the parent class properties and act as base class to share the properties and methods for all child classes (entities of CRM).


Model: (Objects) 


using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Account
{
    class Model
    {
    }

    /// <summary>
    /// Abstract Entity Class
    /// </summary>
    public abstract class CRMEntity
    {   
        public Entity Entity;
        public EntityReference EntityReference;
        public string EntityDisplayName;
        public string Href;
        public string CurrentAttributeName;
        //Other Common Properties


        public CRMEntity(Entity entity)
        {
            this.Entity = entity;
            this.EntityReference = new EntityReference(entity.LogicalName, entity.Id);
            this.Href = "https://datainvent-sandbox.crm3.dynamics.com/main.aspx?etn=" + Entity.LogicalName + "&id=" + Entity.Id.ToString() + "&newWindow=true&pagetype=entityrecord";
            //     https://datainvent-sandbox.crm3.dynamics.com/main.aspx?etn=insr_inspectionelement&id=60a3e6da-5584-e711-8125-480fcff44541&newWindow=true&pagetype=entityrecord


        }

        public CRMEntity(Entity entity, string EntityDisplayName) : this(entity)
        {

            SetName(EntityDisplayName);
        }

        public void SetName(string EntityDisplayName)
        {
            this.EntityDisplayName = EntityDisplayName;
            this.Entity.Attributes.Add("EntityName", this.EntityDisplayName);

        }

        public bool IsValidAttribute(string name)
        {
            if (this.Entity.Attributes.Contains(name))
                return true;

            return false;
        }

    }

    public class Account : CRMEntity
    {
        public Account ParentAccount { get; set; }
        public List<Account> SubAccounts = new List<Account>();
        public List<Contact> Contacts = new List<Contact>();

        public Account() : base(new Entity(EntityNames.Account)) { }

        public Account(Entity entity) : base(entity) { }

        public Account(Entity entity, Account ParentAccount) : base(entity) {
            this.ParentAccount = ParentAccount;
        }

        public string Name
        {
            get
            {
                CurrentAttributeName = "name";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "name";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public Guid AccountId
        {

            get
            {
                CurrentAttributeName = "accountid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<Guid>(CurrentAttributeName);
                }

                return Guid.Empty;
            }
            set
            {
                CurrentAttributeName = "accountid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

        public string AccountNo
        {
            get
            {
                CurrentAttributeName = "accountno";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "accountno";
                this.Entity[CurrentAttributeName] = value;
            }


        }

    }

    public class Contact : CRMEntity
    {
        public Account ParentAccount { get; set; }

        public Contact() : base(new Entity(EntityNames.Account)) { }

        public Contact(Entity entity) : base(entity) { }

        public string FirstName
        {
            get
            {
                CurrentAttributeName = "firstname";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "firstname";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public string LastName
        {
            get
            {
                CurrentAttributeName = "lastname";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "lastname";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public Guid ContactId
        {

            get
            {
                CurrentAttributeName = "contactid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<Guid>(CurrentAttributeName);
                }

                return Guid.Empty;
            }
            set
            {
                CurrentAttributeName = "contactid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

        public EntityReference ParentAccountId
        {

            get
            {
                CurrentAttributeName = "parentcustomerid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<EntityReference>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "parentcustomerid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

    }

    public class AccountHierarchy
    {
        public List<Account> Accounts { get; set; }
        public List<Contact> Contacts { get; set; }

        public AccountHierarchy() {
            Accounts = new List<Account>();
            Contacts = new List<Contact>();
        }
    }


    public class EntityNames
    {
        public static string Account = "account";
        public static string Contact = "contact";
    }

}

Saturday, October 7, 2017

X-Frame-Options = Same Origion

This case is about adding iframe in Dynamics CRM and setting asp.net web form / mvc page to show. One error which can prevent page to load is X-Frame-Options = Same Origion. This occur if there is below line in code

 @Html.AntiForgeryToken()



Also this can occur because off AntiForgeryConfig or similar methods. Usually this is present to not allowed suspicious scripts to run. But anti forgery code add header of x-frame-options and sets value equal to 'same origion'. Which means that no cross domain script is allowed to run. If you have Ajax requests from other servers / domains, then chrome show error of

Refused to display from ..... because of X-Frame-Options = Same Origion

Tuesday, September 26, 2017

Custom Dynamics CRM Integration with SharePoint (Tested on Dynamics 365 Online)


Scenario:
Requirement is that there must be Document type with each document, so that when document is uploaded from crm to sharepoint the document type can be tracked.
One solution can be to create a field (text field / option set) in CRM & SharePoint and mapped so that when document is uploaded the filed can be filled. But this solution was not found after hours of effort and searching for SharePoint.

One solution can be to create folder as per each Document Type in respective record. This will give option to upload document using CRM in respective site location which will represent respective folder in SharePoint.

Thursday, September 21, 2017

Custom XRM Library: Enhance functions

Custom XRM Library to enhance the functionality of xrm functions. This library is a small effort from my side. This includes validations and avoid null reference exceptions in javascript.

I am improving it and planning to add more functions and improvements.

Download

Web API retrieve Specific Account all fields


   var customerid = ""; // Pass account guid here or get from context as per your logic.

    // replacing brackets if found in id

        customerid = customerid.replace("{", "");
        customerid = customerid.replace("}", "");

Sunday, June 25, 2017

CRM 365 Online - Discovery Service

Hi,

Today I was writing code in order to use CRM Discovery Service to retrieve my CRM organizations list for Dynamics 365 Online. To find out Web Application URL  (CRM Application Url), Organization Service Url and Organization data service URL






Casting Error of DiscoveryServiceProxy in CRM 365 Online







Problem Solution:
To solve Discovery Service Proxy casting error on Dynamics 365, I have used Microsoft.Xrm.Tooling.Connector


Below is the solution code.


OrganizationDetailCollection orgDet = Microsoft.Xrm.Tooling.Connector.CrmServiceClient.DiscoverOrganizations(CRMService.DiscoveryUri, null, CRMService.CRMcredentials, null);

Debug.Write(orgDet[0].Endpoints[EndpointType.OrganizationService]);


Explanation:

I tried using Microsoft.Xrm.Sdk.Client.DiscoveryServiceProxy as used to do in previous versions of CRM  (Online / On-Premises). Every thing works fine but when the program reached at line where DiscoveryResponse object is casted to its derived class RetrieveOrganizationsResponse, program throw exception as shown.




Friday, February 17, 2017

Web API Retrieve Single Record

Today I am showing how to select an entity record by passing Guid and get back desired fields.
I am running this code on 'Contact' entity and retrieving two fields. I have to remove starting and ending brackets as Web API is not accepting while processing Guids
I am using below javascript code in webresource. For application outside CRM in separate application, u have to first authenticate using Azure / AD depending upon deployment (Online / On-Premises). Refer to this link for this feature.


Code Start:


function MySelectUsingWebAPI() {



var id = Xrm.Page.data.entity.getId();



             id = id.replace("{", "");

            id = id.replace("}", "");



Friday, January 29, 2016

Value Rule - Ribbon Workbench CRM 2015

Tested on: CRM 2015

Below is the procedure to apply 'Value Rule' using Ribbon Workbench.

Situation:
Business Process is to hide Post button on invoice form page, when status reason is Posted.

Solution:

1) I have added a new Display Rule, add a step Value Rule and add display rule to Post button command, as shown in below snapshot.




















2) Now set Value Rule Properties as shown in below snapshot

Wednesday, January 27, 2016

Add Record for Many to Many Relation


Tested on: CRM 2015

In this problem, I want to add invigilators for the Exam Activity. There is Many to Many relation between Activity & Invigilators.

Here is the snapshot of relationship in CRM 2015




                      
  AssociateRequest request = new AssociateRequest{
             

Friday, November 6, 2015

Lookup Filter Through XRM


In below example, I have implemented custom filter on Student Course Lookup. This filter is forcing the student courses to show for the given Student Id. Student Id is mapped as single line of text field so default filter functionality can not be implemented for Student Course Lookup.

Student Course Lookup Before Filter














Student Course Lookup After Filter 














Xrm Code

Asp.Net MVC (5) - Exception Filter - HandleError

Applicable on Asp.Net MVC5 HandleError Filter This belongs to Exception Filters category (Authentication Filter, Authoriz...