Custom workflow to send e-mail after some specific working days provided at account creation

This post is to send an email on account creation to the account holder after some specific days(in this code: 7). The email will be sent after 7 working days as described in the organization's Calendar and presuming every Saturday & Sunday as holiday.


Step 1: Create new project in Visual Studio and select 'Class Library'. Then copy the code as below and save. Build the solution to get library file(*.dll)

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
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 BusinessClosure
{
    public class BusinessClosure : CodeActivity     
    {
        [Output("SendDate")] // Name of variable to send output to CRM on registering the workflow
        public OutArgument<DateTime> SendDate { get; set; }  //This is the name that will showup when we use this custom workflow in CRM

        IWorkflowContext wc;
        IOrganizationServiceFactory serviceFactory;
        IOrganizationService service;


        /// <summary>
        /// Self executable function from which execution will start
        /// </summary>
        /// <param name="context"></param>
        protected override void Execute(CodeActivityContext context)
        {
            int actualDays = 0; //Counter to calculate actual days to delay the email
            int workingDays = 0;    //Counter to calculate working days 
            int delayDay = 7;   //Variable to hold no. of days by which we need to delay the mail

            ///To get service and context from CRM
            wc = context.GetExtension<IWorkflowContext>();
            serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
            service = serviceFactory.CreateOrganizationService(wc.InitiatingUserId);

            //To retrieve businessclosurecalendarid from the CRM
            var organization = service.Retrieve("organization", wc.OrganizationId, new ColumnSet("businessclosurecalendarid"));

            ///To retrieve date of creation of account and no. of days to delay the email sending
            Entity account = (Entity)service.Retrieve("account", wc.PrimaryEntityId, new ColumnSet(new String[] { "createdon","first_delayemail" }));
            DateTime date = ((DateTime)account.Attributes["createdon"]);

            // Checking if the user has filled the days to delay the mail
            try
            {
                delayDay = Convert.ToInt32(account.Attributes["first_delayemail"].ToString()); //setting delayDay with the specified value
            }

            catch (Exception)
            {
            }

            ///To check working days should not be greater than delay days
            while (workingDays < delayDay)  
            {
                date = date.AddDays(1);     //Increasing date by one day
                actualDays++;               //Increasing actual no. of days

                if (IsWeekDay(date) && IsNotClosure(date)) //Condition to check if the date lies on a holiday or not
                {
                    workingDays++;  //Increasing working days
                }
            }

            SendDate.Set(context, date);     //Setting out variable to the actual date on which the email will be sent
        }


        /// <summary>
        /// Function to check if the date lies on weekdays
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        protected bool IsWeekDay(DateTime date)      
        {
            var day = date.DayOfWeek;                
            return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
        }

        /// <summary>
        /// Function to check if the date does not lie on planned holidays
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        protected bool IsNotClosure(DateTime date)  
        {
            var organization = service.Retrieve("organization", wc.OrganizationId, new ColumnSet("businessclosurecalendarid")); //Getting business closure calendar ID

            ///Query to fetch calendar ID
            QueryExpression qe = new QueryExpression();
            qe.EntityName = "calendar";
            qe.ColumnSet = new ColumnSet();
            qe.ColumnSet.Columns.Add("calendarid");
            qe.Criteria = new FilterExpression();
            qe.Criteria.AddCondition("calendarid", ConditionOperator.Equal, organization["businessclosurecalendarid"].ToString());

            EntityCollection ec = service.RetrieveMultiple(qe); //Fetching all holidays records

            var ds = ec.Entities[0].GetAttributeValue<EntityCollection>("calendarrules").Entities;  //Fetching calendar rules from CRM

            foreach (Entity e in ds)    //Iterating each holiday duration
            {
                DateTime start = (DateTime)e["effectiveintervalstart"]; //Getting start date of holiday
                DateTime end = (DateTime)e["effectiveintervalend"];     //Getting end date of holiday

                if (date >= start && date <= end)   //Checking if the date lies in between holiday duration
                {
                    return false;
                }
            }
            return true;
        }
    }
}


Step 2: Register workflow in CRM
2.1       Open Plugin registration tool

2.2       Select library file(*.dll) and register assembly

Step 3: Create workflow in CRM
3.1       Go to settings and then solutions


3.2       Select Process and then ‘new’

3.3       Give name for the workflow

3.4       Fill details and select your custom workflow

3.5       Insert wait condition and give condition to it

3.6       Select to send email and fill details in it as below

3.7       Finally it will look like this

3.8       Save and activate the workflow

Comments

Popular posts from this blog

Creating a Grid dynamically using HTML in Dynamics CRM to show, update and delete associated records in an entity