Wednesday 5 December 2012

Plugin to generate word documetn using CRM data and Add that as an Attachment to that record

Hi all,
I hope this post will be helpful who would like to generate a word document using CRM data of a record and add that as an attachment  to that record.
Example Scenario : I have an Employee Entity, where i need to generate payslip for that employee on click of a button inside the form:
Steps to be followed:(In Form)
1. Create an Entity with the name"Employee" and add fields which are required:
2. Add a field of datatype "Two Option" and make visiblity of field as hidden
3. Create a web Resource/Javascript and write the function below in the web resource
//Function to change the Two Option Field value on a button CLick
function changeValue()
{
var value=Xrm.Page.getAttribute("FiledNAme").getValue();
 //Check the option fields value if it is yes/no (1/0)
if(value==0)
{
//set value to 1
Xrm.Page.getAttribute("FieldName").setValue(1);
 //Save the updated value
Xrm.Page.data.entity.save();
}
4.Publish ur webresource
5.Add a custom button in form using RibbonWorkBench tool and call ur JavaScript function on that button click: Follow the link to add custom button and call Javascript function
http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx

6.Create a C# plugin with the below code:

 using System;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Net;
using System.IO;
using HtmlAgilityPack;
using mshtml;
using System.Runtime.Serialization;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using NotesFor.HtmlToOpenXml;

namespace payslip
{
    public class MyPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // TODO - If you require tracing, uncomment the following line
            // ITracingService trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            Entity entity = null;

            // Check if the InputParameters property bag contains a target
            // of the current operation and that target is of type DynamicEntity.
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                // Obtain the target business entity from the input parmameters.
                entity = (Entity)context.InputParameters["Target"];

                // TODO Test for an entity type and message supported by your plug-in.
                if (context.PrimaryEntityName != "UR ENTITY NAME") { return; }
                if (context.MessageName != "Update") { return; }
            }
            else
            {
                return;
            }

            try
            {
                string invoice_number = "";
                DateTime joining_date;
                string consultant_name = "";
                string ctc_offered = "";
                string billable_amount = "";
                string tax_amount = "";
                string total_amount = "";
                DateTime invoice_date;
                string j_date = "";
                string i_date = "";
                string tax_per = "";



                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Retrieve field from ur entity
                Entity receivableEntity = service.Retrieve("new_receivable", entity.Id, new ColumnSet("new_nameoftheconsultant", "new_dateofjoining", "new_ctcoffered", "new_billamount", "new_taxamount", "new_totalamount", "new_invoicenumber", "new_invoicedate", "new_generateinvoice", "new_accountname", "new_projectname", "new_projecttype","new_taxesapplicable"));
               
EntityReference proj = (EntityReference)receivableEntity.Attributes["new_projectname"];
                string projname = proj.Name;
                EntityReference acc = (EntityReference)receivableEntity.Attributes["new_accountname"];
                string name = acc.Name;
                string add = "";
                string city = "";
                string amttot = "";

                Guid id = acc.Id;
                //string ret = receivableEntity.Attributes["new_accountname"].ToString();
                QueryExpression q = new QueryExpression("account");
                q.ColumnSet = new ColumnSet(new string[] { "new_companyaddress_test", "address2_city", "name" });
                q.Criteria.AddCondition("name", ConditionOperator.Equal, name);
                EntityCollection qu = (EntityCollection)service.RetrieveMultiple(q);
                if (qu != null && qu.Entities.Count > 0)
                {
                    Entity ent = null;
                    for (int i = 0; i < qu.Entities.Count; i++)
                    {
                        ent = qu.Entities[i];
                        add = ent.Attributes["new_companyaddress_test"].ToString();
                        city = ent.Attributes["address2_city"].ToString();
                    }
                }
               
                string a = receivableEntity.Attributes["new_generateinvoice"].ToString();
                //string projectType = receivableEntity.Attributes["new_projecttype"].ToString();
               
                if (receivableEntity.Attributes.Contains("new_generateinvoice") && a == "True")
                {
                    if (receivableEntity != null)
                    {
                        if (receivableEntity.Attributes.Contains("new_nameoftheconsultant"))
                        {
                            consultant_name = (string)receivableEntity.Attributes["new_nameoftheconsultant"];

                        }
                        if (receivableEntity.Attributes.Contains("new_taxesapplicable"))
                        {
                            tax_per = (string)receivableEntity.Attributes["new_taxesapplicable"];

                        }
                        if (receivableEntity.Attributes.Contains("new_dateofjoining"))
                        {
                            joining_date = (DateTime)receivableEntity.Attributes["new_dateofjoining"];
                            j_date = joining_date.ToShortDateString();


                        }
                        if (receivableEntity.Attributes.Contains("new_ctcoffered"))
                        {
                            //ctc_offered = (float)receivableEntity.Attributes["new_ctcoffered"];

                            //ctc_offered = Convert.ToInt32(receivableEntity.Attributes["new_ctcoffered"]);
                            ctc_offered = ((Money)receivableEntity.Attributes["new_ctcoffered"]).Value.ToString();

                        }
                        if (receivableEntity.Attributes.Contains("new_billamount"))
                        {
                            billable_amount = ((Money)receivableEntity.Attributes["new_billamount"]).Value.ToString();

                        }
                        if (receivableEntity.Attributes.Contains("new_taxamount"))
                        {
                            tax_amount = ((Money)receivableEntity.Attributes["new_taxamount"]).Value.ToString();

                        }
                        if (receivableEntity.Attributes.Contains("new_totalamount"))
                        {
                            total_amount = ((Money)receivableEntity.Attributes["new_totalamount"]).Value.ToString();
                            decimal rev = ((Money)receivableEntity.Attributes["new_totalamount"]).Value;

                            int intvalue = Convert.ToInt32(rev);
                            amttot=NumberToWords(intvalue);
                        }
                        if (receivableEntity.Attributes.Contains("new_invoicenumber"))
                        {
                            invoice_number = (string)receivableEntity.Attributes["new_invoicenumber"];

                        }
                        if (receivableEntity.Attributes.Contains("new_invoicedate"))
                        {
                            invoice_date = (DateTime)receivableEntity.Attributes["new_invoicedate"];
                            i_date = invoice_date.ToShortDateString();

                        }
//Create a format in HTML format how u wanted in ur word document
                        string docbody = "<html><body><h3><b><center>                                                                                     INVOICE</center></b></h3><p><h3><pre><span>To,      " + name + "<br/>         " + add + "<br/>" + city + "</br>" + "                            <br/> Invoice No:" + invoice_number + "                    Date:  " + i_date + "      </span></pre></h3><table border=2 style='width: 40000px; height: 200px;' >     <tr style='border-width: 2px;' >         <td colspan='5'><center>              Recruitment Charges towards Placement of <b>" + projname + "</b></center></td>     </tr>     <tr style='width: 500px; height: 30px;'>         <td style='width: 40px;'><center>SL.No</center></td>        <td style='width: 200px;'><center>Name of the candidate</center></td>         <td style='width: 200px;'><center>Date of Joining</center></td>         <td style='width: 200px;'><center>CTC offered(Rs)</center></td>         <td style='width: 200px;'><center>Billable Amount (in Rs.)</center></td>     </tr>     <tr style='width: 800px; height: 50px;'>         <td style='width: 70px;' ><center>1</center></td>         <td>" + consultant_name + "</td>         <td>" + j_date + "</td>         <td>" + ctc_offered + "</td>         <td>" + billable_amount + "</td>     </tr>     <tr style='height: 20px;'>         <td colspan='4'><span style='margin-left: 600px;'>Amount         Rs.<span></td>         <td>" + billable_amount + "</td>     </tr>     <tr style='height: 20px;'>         <td colspan='4'><span style='margin-left: 600px;'>" + tax_per + "% Service Tax  Rs.<span></td>         <td>" + tax_amount + "</td>     </tr>     <tr style='height: 20px;'>         <td colspan='4'><span style='margin-left: 600px;'>TOTAL AMOUNT      Rs.<span></td>        <td>" + total_amount + "</td>     </tr>     <tr style='height: 20px;'>         <td colspan='5'><b>Rupees in words:</b> " + amttot + " only </td>     </tr> </table> <pre></body></html>";
     //Save ur document in Server                  
string f1 = @"C:\temp\" + consultant_name + ".docx";

                        using (MemoryStream generatedDocument = new MemoryStream())
                        {
                            using (WordprocessingDocument package = WordprocessingDocument.Create(generatedDocument, WordprocessingDocumentType.Document))
                            {
                                MainDocumentPart mainPart = package.MainDocumentPart;
                                if (mainPart == null)
                                {
                                    mainPart = package.AddMainDocumentPart();
                                    new Document(new Body()).Save(mainPart);
                                }

                                HtmlConverter converter = new HtmlConverter(mainPart);
                                Body body = mainPart.Document.Body;

                                var paragraphs = converter.Parse(docbody);
                                for (int y = 0; y < paragraphs.Count; y++)
                                {
                                    body.Append(paragraphs[y]);
                                }

                                mainPart.Document.Save();
                            }
                            string w = entity.LogicalName;
                            File.WriteAllBytes(f1, generatedDocument.ToArray());
                            FileStream stream = File.OpenRead(f1);
                            byte[] byteData = new byte[stream.Length];
                            stream.Read(byteData, 0, byteData.Length);
                            stream.Close();
                            string encodedData = System.Convert.ToBase64String(byteData);


                            string filename="LISPLIN-"+name+"-240-"+i_date+".doc";
                            // Add the generated document as an attachment to that record
                            Entity annotation = new Entity("annotation");
                            annotation.Attributes["subject"] = "Invoice";
                            EntityReference noteref = new EntityReference();
                            noteref.LogicalName = entity.LogicalName;
                            noteref.Id = entity.Id;
                            annotation.Attributes.Add("objectid", noteref);
                            annotation.Attributes.Add("objecttypecode", w);
                            annotation.Attributes.Add("filename", filename);
                            annotation.Attributes.Add("mimetype", "application/ms-word");
                            annotation.Attributes.Add("documentbody", encodedData);
                            service.Create(annotation);



                        }
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
            }
        }
//function to convert number to words(32 - thirty two)

        public static string NumberToWords(int number)
        {
            if (number == 0)
                return "zero";

            if (number < 0)
                return "minus " + NumberToWords(Math.Abs(number));

            string words = "";

            if ((number / 1000000) > 0)
            {
                words += NumberToWords(number / 1000000) + " Million ";
                number %= 1000000;
            }
            if ((number / 100000) > 0)
            {
                words += NumberToWords(number / 100000) + " Lakh ";
                number %= 100000;
            }

            if ((number / 1000) > 0)
            {
                words += NumberToWords(number / 1000) + " Thousand ";
                number %= 1000;
            }

            if ((number / 100) > 0)
            {
                words += NumberToWords(number / 100) + " Hundred ";
                number %= 100;
            }

            if (number > 0)
            {
                if (words != "")
                    words += "and ";

                var unitsMap = new[] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen" };
                var tensMap = new[] { "Zero", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };

                if (number < 20)
                    words += unitsMap[number];
                else
                {
                    words += tensMap[number / 10];
                    if ((number % 10) > 0)
                        words += "-" + unitsMap[number % 10];
                }
            }

            return words;
        }
    }


}


7. Add the required references and register the plugin for Update Message using Plugin Registration Tool
8. Now Refresh and go to ur entity open Record and Click on ur Custom button
9.Now the payslip would be generated and added as an attachment to that record








HOME PAGE GRID:
To perform the same operation for selected record from HomePage Grid Steps to be followed:
1) Create a custom button in Home Page Grid using RibbonWorkBench
2)Create a workflow which would change the Two Option Button activate the process as "As on Demand" process
3)Follow the post showing you how to trigger your workflow without writing a single line of code!
http://www.develop1.net/public/post/No-Code-Workflow-Shortcut-Ribbon-Button.aspx
4)And check ur entity attachments with generated payslip attached


7 comments:

  1. Hi nandan
    great post, do you know if this is working in office 365 crm online???

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. how to handle string f1 = @"C:\temp\" + consultant_name + ".docx";

    this part in MSCRM online!! pls telll

    ReplyDelete
  4. hey im getting error in DocumentFormat.Openxml library error

    also C:temp as dir will it work on MCSRM online

    ReplyDelete
  5. Hi Prasadh,

    Please post the error message which u r getting.


    And sorry for late response

    ReplyDelete
  6. Instead of same ,I want to attach as pdf file...Please help about the same

    ReplyDelete
  7. How do you do this for Office 365 Online?

    ReplyDelete