NIKHIL RAJENDRAN

Being customer-centric isn’t just an added value that an organization has to offer anymore. It is a quintessential feature that defines a company. It has been proven that it is cost-effective to retain old customers and one of the best ways of doing that is taking care of them. This could mean going the extra mile, observing their consumerist (sans the ideology) behavior, predicting their requirements before they even narrate. Now in a parallel world would require a mind-reader or a hypnotist but thank God for Microsoft Dynamics 365, you do not have to venture far.

Microsoft is like that magician who keeps on pulling out a trail of colorful kerchiefs from his hat. For a five-year-old, this is the most fascinating act but for us adults, we tend to look up his sleeve. And the sleeve doesn’t seem to disappoint either. In 2001, Microsoft with the acquisition of iCommunicate had stepped into the world of CRM and paved the path for revolutionizing the most sought-after sector of any business. Fast forward to 2018, Dynamics 365 was released combining ERP and CRM applications.

So why do we have a plethora of organizations, restricting themselves and employing this CRM application? The reasons are plain and plenty. It is easier, flexible, scalable. With this, a company can have a unified system and the users do not have to shuffle between systems. This essentially saves time and money. All the teams, sales, marketing, service, and delivery can access the same system at one go, without the issue of restricted access.

Now when companies use the CRM software, they do it with the purpose of making their business lives a little less difficult. I would like to take the example of an entertainment company when talking about ease of business.

Usually, with emails that are sent to clients, the attachments must be static in nature. Such as standard boilerplate, terms and conditions documents. These kinds of documents do not have the need to be altered. As such, attaching and sending doesn’t take much of a hassle.

However, when such a company requests for dynamic documents such as payment receipts etc. to be sent out, then it becomes the job of the developer to assist the client with the request. Although, sending varied documents isn’t a precondition that Microsoft had insisted upon, but the CRM system is scalable and can be tailormade as per the client’s requirement.

In our case, for the entertainment company, a specific code had to be written. Let’s visit some of the points that had to be covered while taking care of the request.

Prerequisite – The report needs to be created already in the CRM Organization and we need to have the report name and report guid.

 

Implementation stage:

  1. Creating the workflow and mention the triggering action.Dynamics 365 Workflow
  2. Creating the email body – mentioning the sender and receiver. Entering the subject and body of the email.Dynamics365 Email
  3. Open Visual Studio and create a web reference with the report server name. example for report server name –

                   http://reportssrs-01/Reportserver/ReportExecution2005.asmx

  1. Now create a custom workflow with the following code:
 

1)  using System;

2)  using System.Linq;

3)  using System.Text;

4)  using System.Threading.Tasks;

5)  using Microsoft.Xrm.Sdk.Workflow;

6)  using Microsoft.Xrm.Sdk;

7)  using Microsoft.Xrm.Sdk.Query;

8)  using System.Activities;

9)  using Microsoft.Xrm.Sdk.Client;

10) using System.Web.Services.Protocols;

11) using Microsoft.Crm.Sdk.Messages;

12) using System.Net;

13)

14) namespace customNamespace

15) {

16)     //4077,(Contract) //4182,

17)     ////http://rich-cent01/reportserver/ReportService2010.asmx?wsdl

18)     public class AttachContractToEmail : CodeActivity

19)     {

20)         const string ReportPathFromSettings = “Report Path”;

21)         const string ReportServerFromSettings = “Report Server”;

22)

23)         [Input(“E-Mail”)]

24)         [ReferenceTarget(“email”)]

25)

26)         public InArgument<EntityReference> Email { get; set; }

27)

28)         [Input(“inputParameterNeededForReport”)]

29)         [ReferenceTarget(“inputparameterneededforreport “)]

30)         public InArgument<string> inputParameterNeededForReport { get; set; }

31)

32)

33)         protected override void Execute(CodeActivityContext executionContext)

34)         {

35)             IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

36)             IOrganizationServiceFactory servicefactory = executionContext.GetExtension<IOrganizationServiceFactory>();

37)             IOrganizationService _service = servicefactory.CreateOrganizationService(context.UserId);

38)

39)             //Sample guid of contract : 4AE5200F-1000-E611-80C5-005056AA8521

40)             string test = inputparameterneededforreport.Get(executionContext);

41)             Entity attachment = new Entity(“activitymimeattachment”);

42)             byte[] reportresult;

43)             DateTime startDate = DateTime.Now.AddMonths(-15);

44)             DateTime endDate = DateTime.Now;

45)             if (test != null)

46)             {

47)                 ParameterValue[] parameters = new ParameterValue[1];

48)                 parameters[0] = new ParameterValue();

49)                 parameters[0].Name = “QuoteId”;

50)                 parameters[0].Value = string.Format(test);

51)

52)                         var reportServer = //reportServerNameGoesHere

53) //example for report server name – http://reportssrs-01/Reportserver/ReportExecution2005.asmx

54)                 CommonMethods rg = new CommonMethods(reportServer, new NetworkCredential(userid, password, domain));

55)                 reportresult = rg.Render(reportPathGoesHere, FormatType.PDF, parameters);

56)

57)                 attachment[“objectid”] = Email.Get<EntityReference>(executionContext);

58)                 attachment[“objecttypecode”] = “email”;

59)                 attachment[“filename”] = //fileNameGoesHere;

60)                 attachment[“subject”] = //subjectgoeshere;

61)                 attachment[“body”] = System.Convert.ToBase64String(reportresult);

62)             }

63)

64)

65)

66)

67)

68)             try

69)             {

70)                 _service.Create(attachment);

71)             }

72)             catch (Exception ex)

73)             {

74)                 throw new Exception(string.Format(“Error creating attachment – {0}”, ex.Message));

75)             }

76)

77)             try

78)             {

79)                 _service.Execute(new SendEmailRequest()

80)                 {

81)                     EmailId = Email.Get<EntityReference>(executionContext).Id,

82)                     IssueSend = true,

83)                     TrackingToken = string.Empty

84)                 });

85)             }

86)             catch (Exception ex)

87)             {

88)                 throw new Exception(string.Format(“Error sending email – {0}”, ex.Message));

89)             }

90)         }

91)     }

92) }

93)

94)

95)

96) internal CommonMethods(string ServiceUrl, ICredentials credentials)

97)         {

98)             if (string.IsNullOrEmpty(ServiceUrl))

99)                 throw new Exception(“Parameter ServiceUrl has to contain value”);

100)

101)                    if (credentials == null)

102)                        throw new Exception(“Parameter Credentials has to contain value”);

103)

104)                    _reportexecutionservice = new ReportExecutionService()

105)                    {

106)                        Credentials = credentials,

107)                        Url = ServiceUrl

108)                    };

109)                }

110)

111)

112)                internal byte[] Render(string Report, FormatType formattype)

113)                {

114)                    return this.Render(Report, formattype, new ParameterValue[] { });

115)                }

116)

117)                internal byte[] Render(string Report, FormatType formattype, ParameterValue[] parameters)

118)                {

119)                    byte[] result = null;

120)                    string format = GetFormatType(formattype);

121)                    string historyID = null;

122)                    string devInfo = @”<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>”;

123)                    string encoding;

124)                    string mimeType;

125)                    string extension;

126)                    Warning[] warnings = null;

127)                    string[] streamIDs = null;

128)

129)                    try

130)                    {

131)                        ExecutionInfo execInfo = new ExecutionInfo();

132)                        ExecutionHeader execHeader = new ExecutionHeader();

133)                        _reportexecutionservice.ExecutionHeaderValue = execHeader;

134)                        execInfo = _reportexecutionservice.LoadReport(Report, historyID);

135)                        _reportexecutionservice.SetExecutionParameters(parameters, “en-us”);

136)                        result = _reportexecutionservice.Render(format, devInfo, out extension,

137)                            out mimeType, out encoding, out warnings, out streamIDs);

138)                    }

139)                    catch (Exception ex)

140)                    {

141)                        if (ex is SoapException)

142)                        {

143)                            SoapException sexc = ex as SoapException;

144)                            throw new Exception(string.Format(“Error generating report – {0}”, sexc.Detail.InnerText));

145)                        }

146)                        else

147)                        {

148)                            throw new Exception(string.Format(“Error generating report – {0}”, ex.Message));

149)                        }

150)                    }

151)

152)                    return result;

153)                }

154)

155)                private string GetFormatType(FormatType formattype)

156)                {

157)                    switch (formattype)

158)                    {

159)                        case FormatType.XML:

160)                        case FormatType.CSV:

161)                        case FormatType.IMAGE:

162)                        case FormatType.PDF:

163)                        case FormatType.MHTML:

164)                        case FormatType.EXCEL:

165)                        case FormatType.Word:

166)                            return formattype.ToString();

167)                        case FormatType.HTML40:

168)                            return “HTML4.0”;

169)                        case FormatType.HTML32:

170)                            return “HTML3.2”;

171)                        default:

172)                            throw new Exception(string.Format(“Rendering type {0} is not available”, formattype));

173)                    }

174)                }

175)

176)

177)            }

178)

179)            internal enum FormatType

180)            {

181)                XML, CSV, IMAGE, PDF, HTML40, HTML32, MHTML, EXCEL, Word

182)            }

 

  1. Deploying the custom workflow.
  2. Once the custom workflow has been deployed, we need to call the custom workflow inside the main workflow. To do it, click on add step and find the custom workflow which has just been deployed.
  3. Once the custom workflow has been called, you need to declare the input parameters for the workflow. The sample code has been written with one input parameter. You can modify the code to accept more input parameters.

I would like to reiterate, that one of the primary reasons that Dynamics 365 has gained leverage is because of its scalability. The future of CRM is more than maintaining customer relationships. It is the future of any business. With an application like Dynamics 365, Microsoft has revolutionized the whole industry. Now entrepreneurs don’t just yearn for gaining more customers but strive to find applied business intelligence to retain the old ones as well.

It’s fascinating to witness this kind of radical changes brought to the genre of customer relationship by Microsoft. All we can do is wait with bated breath for the next revolution. And we know it’s not going to be too far.

We at AhaApps employ Microsoft’s applications to help our customers in making their business agile and seamless. Our Staffing Solutions and CRM consultancy services ensure that our we take care of our clients’ requirements through applied business intelligence, analytics and best practices. We endeavor to drive efficiency, find solutions and help businesses grow. To know more about our exclusive services, do contact us today.

Recent Posts