Last updated – 18th Nov 2017
This blog has come up with a Good news for all CRM Developers, who are struggling with PDF loading issues. Sometimes, after implemeting this code, developers can generate the PDF file but when they download and open it, they get an error that the file is currpted or not able to open the PDF file.
This is happening because of the report paramenters. Please perform below steps if you're facing the problem,
First, open your '.rdl' file (e.g. report.rdl) in XML form.
Then, find <QueryParameters> tab in report XML and validate your parameters with the parameters you're passing in the GetReportingSession() function in your code.
Hope this will be helpful.
Last updated – 10th June 2016
This blog post uses SDK.SOAP.js to perform all CRM web service calls.
Please refer following link to know more about the SDK.SOAP.js.
http://ankit.inkeysolutions.com/2014/10/sdksoapjs.html
Recently, I came across a requirement where I had to create a functionality that will create an email activity on “Order” entity that would be having a custom report in PDF format as an attachment. This functionality needs to be executed on a ribbon button click. I couldn’t find any complete example that covers all these functionalities. Hence, in this post, I will be sharing the complete solution to generate PDF file from a custom SSRS report and attach the same to newly created email activity.
Please follow below steps to achieve this functionality:
http://ankit.inkeysolutions.com/2014/10/sdksoapjs.html
Recently, I came across a requirement where I had to create a functionality that will create an email activity on “Order” entity that would be having a custom report in PDF format as an attachment. This functionality needs to be executed on a ribbon button click. I couldn’t find any complete example that covers all these functionalities. Hence, in this post, I will be sharing the complete solution to generate PDF file from a custom SSRS report and attach the same to newly created email activity.
Please follow below steps to achieve this functionality:
1) Variable initialization and EmailReport(), a starting point, this method needs be called via JavaScript code.
2) Creating an email activity for the “Order” entity.
3) On this step, we will fetch the SSRS report's GUID by using report name.
4) Creating an attachment for the email activity and binding the report in a PDF format as attachment.
Variable initialization and EmailReport() method that can be called via JavaScript code. – Step 1
This code initializes the variables, which are required in next steps of this post. Plus, it defines two JavaScript methods,
var reportName = "SampleReport"; //Please specify your report name. var reportId = null; var fileName = "PDF01"; //Please specify a file which you want to save. var fromFieldId = null; var fromFieldEntityName = null; var toFieldId = null; var toFieldEntityName = null; var emailId = null; //This function is need to be called from action side e.g. Ribbon button click. function EmailReport() { //This function does not work in add mode of form. var type = Xrm.Page.ui.getFormType(); if (type != 1) { GetIds(); // Set ids in global variables. CreateEmail(); //Create Email } } //Gets the fromFieldId and toFieldEntityName used to set Email To & From fields function GetIds() { fromFieldId = "00000000-0000-0000-0000-000000000000";//The Guid which needs to be set in form field. fromFieldEntityName = "systemuser";//Please specify entity name for which you have specified above Guid. Most probably it's systemuser. toFieldId = "00000000-0000-0000-0000-000000000000"; //The Guid which needs to be set in to field. toFieldEntityName = "contact";//Please specify entity name for which you have specified above Guid. }
Creating an email activity for the “Order” entity – Step 2
With this step we will first create an email activity for the “Order” entity. When you create an email activity for an entity you must associate the entity and activity with either To, From or Regarding participation type. In this example the entity “Order” for which the email activity is created, is associated as Regarding in the email activity.
Now, we will have to set “To” and “From” fields of the email activity. The “To” and “From” are Activity parties associated with the email activity.
//Create Email and link it with Order as Reagrding field function CreateEmail() { var id = Xrm.Page.data.entity.getId(); id = id.replace('{', ""); id = id.replace('}', ""); var entityLogicalName = Xrm.Page.data.entity.getEntityName(); var regardingObjectId = new Sdk.EntityReference(entityLogicalName, id); var email = new Sdk.Entity("email"); email.addAttribute(new Sdk.String("subject", "Your Booking")); email.addAttribute(new Sdk.Lookup("regardingobjectid", regardingObjectId)); var fromParties = PrepareActivityParty(fromFieldId, fromFieldEntityName); email.addAttribute(new Sdk.PartyList("from", fromParties)); var toParties = PrepareActivityParty(toFieldId, toFieldEntityName); email.addAttribute(new Sdk.PartyList("to", toParties)); Sdk.Async.create(email, EmailCallBack, function (error) { alert(error.message); }); } //This method get entity's id and logical name and return entitycollection of it. function PrepareActivityParty(partyId, partyEntityName) { var activityParty = new Sdk.Entity("activityparty"); activityParty.addAttribute(new Sdk.Lookup("partyid", new Sdk.EntityReference(partyEntityName, partyId))); var activityParties = new Sdk.EntityCollection(); activityParties.addEntity(activityParty); return activityParties; } // Email Call Back function function EmailCallBack(result) { emailId = result; GetReportId(); }
On this step, we will fetch the SSRS report's GUID by using report name. - Step 3
Use below code to fetch the SSRS report GUID using the SSRS report name.
//This method will get the reportId based on a report name function GetReportId() { var columns = "reportid"; var fetchQuery = new Sdk.Query.QueryByAttribute("report"); fetchQuery.setColumnSet(columns); fetchQuery.addAttributeValue(new Sdk.String("name", reportName)); Sdk.Async.retrieveMultiple(fetchQuery, RetrieveMultiple); } function RetrieveMultiple(entityCollection) { if (entityCollection.getEntities().getCount() > 0) { var entities = entityCollection.getEntities(); var getAttribute = entities.getByIndex(0).getAttributes("reportid"); if (getAttribute != null) { reportId = getAttribute.getValue(); } } //get reporting session and use the params to convert a report in PDF var params = GetReportingSession(); EncodePdf(params); }
Creating an attachment for the email activity and binding the report in a PDF format as attachment - Step 4
Once we are done with creating an email activity and fetching the GUID value of the SSRS report in above steps, we will come to this step. Here it is creating an attachment for this newly created email activity.
The function GetReportingSession() gets the required details for converting a report into PDF. Using the function EncodePdf(), the report is converted into PDF format.
The function GetReportingSession() gets the required details for converting a report into PDF. Using the function EncodePdf(), the report is converted into PDF format.
//Gets the report contents function GetReportingSession() { var pth = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/reportviewer.aspx"; var retrieveEntityReq = new XMLHttpRequest(); var Id = Xrm.Page.data.entity.getId(); retrieveEntityReq.open("POST", pth, false); retrieveEntityReq.setRequestHeader("Accept", "*/*"); retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); var orgUniqueName = Xrm.Page.context.getOrgUniqueName(); //The following line is required only when you have parameters to be passed to your SSRS custom report. var reportPrefilter = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='salesorder'><all-attributes /><filter type='and'><condition attribute='salesorderid' operator='eq' value='" + Xrm.Page.data.entity.getId() + "' /></filter></entity></fetch>"; var req = "id=%7B" + reportId + "%7D&uniquename=" + orgUniqueName + "&iscustomreport=true&reportName=" + reportName + "&isScheduledReport=false&p:CRM_FilteredSalesOrder=" + reportPrefilter; retrieveEntityReq.send(req); var StartAfterComment = retrieveEntityReq.responseText.indexOf("e440105867d249ce8a45696677d42bcb") + 32; var x = retrieveEntityReq.responseText.lastIndexOf("ReportSession="); var ret = new Array(); ret[0] = retrieveEntityReq.responseText.substr(x + 14, 24); //the session id x = retrieveEntityReq.responseText.lastIndexOf("ControlID="); ret[1] = retrieveEntityReq.responseText.substr(x + 10, 32); //the control id return ret; } function EncodePdf(params) { var retrieveEntityReq = new XMLHttpRequest(); var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF"; retrieveEntityReq.open('GET', pth, true); retrieveEntityReq.setRequestHeader("Accept", "*/*"); retrieveEntityReq.responseType = "arraybuffer"; retrieveEntityReq.onload = function (e) { if (this.status == 200) { var uInt8Array = new Uint8Array(this.response); var base64 = Encode64(uInt8Array); CreateEmailAttachment(base64); } }; retrieveEntityReq.send(); } var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; function Encode64(input) { var output = new StringMaker(); var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0; while (i < input.length) { chr1 = input[i++]; chr2 = input[i++]; chr3 = input[i++]; enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output.append(keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4)); } return output.toString(); } var StringMaker = function () { this.parts = []; this.length = 0; this.append = function (s) { this.parts.push(s); this.length += s.length; } this.prepend = function (s) { this.parts.unshift(s); this.length += s.length; } this.toString = function () { return this.parts.join(''); } } //Create attachment for the created email function CreateEmailAttachment(encodedPdf) { //Get order number to name a newly created PDF report var orderNumber = Xrm.Page.getAttribute("ordernumber"); var emailEntityReference = new Sdk.EntityReference("email", emailId); var newFileName = fileName + ".pdf"; if (orderNumber != null) newFileName = fileName + orderNumber.getValue() + ".pdf"; var activitymimeattachment = new Sdk.Entity("activitymimeattachment"); activitymimeattachment.addAttribute(new Sdk.String("body", encodedPdf)); activitymimeattachment.addAttribute(new Sdk.String("subject", "File Attachment")); activitymimeattachment.addAttribute(new Sdk.String("objecttypecode", "email")); activitymimeattachment.addAttribute(new Sdk.String("filename", newFileName)); activitymimeattachment.addAttribute(new Sdk.Lookup("objectid", emailEntityReference)); activitymimeattachment.addAttribute(new Sdk.String("mimetype", "application/pdf")); Sdk.Async.create(activitymimeattachment, ActivityMimeAttachmentCallBack, function (error) { alert(error.message); }); } //ActivityMimeAttachment CallBack function function ActivityMimeAttachmentCallBack(result) { Xrm.Utility.openEntityForm("email", emailId); }
Note: This functionality is tested with Parameterized Custom Report in CRM Online.
The simplest and quickest way to insert data for Many-to-Many relationship in Dynamics CRM is the Drag and drop listbox.
http://www.inkeysolutions.com/DynamicCRMDragAndDropListBox.html
Hi Ankit,
ReplyDeleteYou are a CRM genius! I did not think there was any way to create an e-mail with a PDF attachment in CRM Online and you could only do this sort of thing with On Premises + a 3rd party tool.
Is there any way to do something similar with Workflow in CRM Online, so that this could be automated and not require a user to click a button?
Thanks!
Len
Hi Len,
DeleteI am not sure that you are looking for the same solution but can try this.
You can create custom entity and "on required event" you can create a record in this custom entity and on Creation of record of this custom entity your plugin will fire.
Is it help full or you want me explain more?
Dear Len,
ReplyDeleteThank you for your comment.
Honestly, I am not genius!! I am far away from it!
In my opinion there must be some action on which you would like to send such e-mails activities directly to customer.
The given code is completely based on JavaScript & VBScript.
In workflow either you cannot inject such code or you do not have any actions on which you could run such code. Do we?
However, instead of workflow we can send the newly created e-mail activity via JavaScript code without user intervention.
How can you do it with JavaScript without user intervention?
ReplyDeleteI have a couple of cases where the user is assigning a "Claim" record to an Appraiser and could run the script from there.
I also have a case though where we want a document to go out if there is no action after X number of days, which is why I had thought to use a workflow. Is there a workaround for that?
Thanks very much!
Len
Dear Len,
ReplyDeleteFor claim record I assume you would like to send an e-mail with claim as an attachment to appraiser.
If my understanding is correct then you can inject the above code on assign button click or any other custom button click on claim record form wherein the given code will convert the custom SSRS claim report to PDF & creates an e-mail activity with that PDF. In continuation you can further send the same e-mail synchronously to appraiser. Refer below link to send an e-mail Synchronously using JavaScript.
http://mileyja.blogspot.in/2012/02/send-email-synchronously-in-microsoft.html
For second scenario we need a workflow or some background programs that wait for X number of days.
Unfortunately, in CRM 2011 online you cannot send an e-mail activity (that is being already created) via a workflow.
Hence we cannot use the above code in such scenarios.
I hope this will be helpful.
Thanks Ankit - that is definitely very helpful!
ReplyDeletethis is very slow for bigger report data
ReplyDeleteHello Daniel,
ReplyDeleteYes, that's correct. This solution is taking too much of time for bigger report data. I would be happy to work out on this again to make it more faster with bulky report data.
Hi Ankit, do you have a CRM solution to make a quick try? Thanks in advance. Marco
ReplyDeleteDear Marco,
ReplyDeleteAt present I do not have a separate solution for this, if you want then I can prepare it for you.
Please share your interest.
Dear Ankit , please how i can send you my code to tell me what's wrong? Thank you very much
ReplyDeleteYou can reach out to me at ankithimmatlalshah@gmail.com
ReplyDeletehi Ankit,
ReplyDeletewhat could be the reason when only the first call to create the E-Mail activity is very slow? (about 30 seconds) afterwards it takes only about 3sec..
anyway your solution works great.
thanks in advance
Hello,
ReplyDeleteIn my opinion all call should take the same time.
Could you please share some more details how you think that the first call is very slow? Did you check the attachment file size when the execution was completed in 3 sec.?
How do you get all of this working together? Did you combine them all into one script and but inside a ribbon button ? and what did you do with the HTML File?
ReplyDeleteThere are two web resource components. One a JavaScript type which is being called from a custom ribbon button. It creates the e-mail activity and attachment file of custom report. It also calls the other HTML web resource component to convert binary to byte array. The other HTML web resource component is embedded on entity form where we have placed our ribbon button.
ReplyDeleteCan you please share the screen shots of this workflow to get a clear idea,how it works...Thnx in advance and I'm working for the same requirement but i didn't use any custom ribbon Buttons.It woulld be a great help for me and i've been trying it since 4-5dsys.
DeleteHello Ankit!
DeleteMy requirement is: I generated custom Report using BIDS for Quote(Entity).Here im trying to attach the generated custom Report as PDF Attachment and send Email.I tried using Note(Annotation) way but that doesn't meet all my requirements.So while googling,i found ur code helpful.I added buttons for each function in ur code like-(Create,Attach,GetReport).But i still dnt get why you didn't mention any buttons in ur HTML Web resource...But if it is because you have a custom Button already,pls do guide me into a right direction to get through my problem.
Thanks,
Manu.
Hello Manu,
DeleteSorry for the late response.
The HTML web resource should be added/embedded on the form where you wish to execute this functionality. In your case it should be added as hidden web resource component on quote entity form. Then the scripting part of step 3 will use it in conversion from binary to byte array.
I have implemented this functionality on Order form. I have one custom button on top ribbon bar on click on that one of the custom reports get converted into PDF and the same will be attached to an e-mail activity which is being created for that particular Order record during the same process.
Please provide more details where are you right now about this implementation? Are you facing any errors?
Hello Ankit,
DeleteWhat im trying to do is-
1.I generated a Custom Report for Quote Entity using BIDS.
2.Trying to attach that report as PDF attachment to Email Entity using "ActivityMimeAttachment" instead of "Annotation".
3.I want to attach the Report to selected record and send Email directly.
4.All this-"attach report and send email" has to be done in one Click.
5.Pls find the code in the following link which I used and is similar to your code.
http://xrmmatrix.blogspot.nl/2011/06/creating-report-as-pdf-attachment-in.html
Problem:
The problem here is-
1.I created a workflow to send a mail when the status of the Quote is in Draft.
2.When i run the workflow,I can send the mail with email activity being generated but with no attachment.
3.Can you tell me what the problem might be?
4.I even tried an AddOn which is "Report to PDF" which fulfill all my requirements.
5.So is it necessary that i hav to make a ribbon control and work on it?
Hello Manu,
DeleteAs said earlier, according to my knowledge you cannot perform the above action via workflow or any other automatic mechanisms. You have to consider the user action somewhere and for that the best is to customize the ribbon. However, in the upcoming Dynamics CRM release, Orion, there will be no ribbon buttons at all on record forms. So, be careful while customizing ribbons for CRM 2011 online.
Hello Ankit!
DeleteThanks for the reply.So it is not possible to fulfill my requirement using workflows.So is creating a ribbon control a best option? If so, as you said -the upgraded CRM Online doesn't have ribbon control.What would be the best approach to make my requirement done?
And one more problem is- While attaching the report as email Attachment,all the record's reports are being attached.
Means-I can see the report with all the record's info instead of particular selected record.
Any idea or help would be appreaciated...
Thanks,
Manu.
Hello Manu,
DeleteAccording to my knowledge at present there is no option except ribbon button to call the above functionality. Additionally, you could think on other events like form load, onchange event of control or any system ribbon buttons if it sits with your business need.
On all records problem, please validate that have you applied the CRM filtration on report? Did you use the CRM_ parameter for pre-filtration?
Hi Ankit,
ReplyDeleteI want to send the report per day as an email with PDF as an attachement in CRM Online. Is it possible? Becoz i havw done it with creating the views and convert that data into PDF and attach this with the email activity.Can u please share me the easy way to do it.
Regards
RASHMI GUPTA
Hello Rashmi,
ReplyDeleteSorry for the late reply.
The above code executes on client side and requires user action to start the process of e-mail activity creation and PDF generation. According to my knowledge you cannot initiate such client side actions via workflow, plug-ins or any other automatic mechanisms. So, I believe at present it is not possible to send the custom SSRS report, attached as PDF to an e-mail activity which would be sent on daily basis for CRM 2011 online.
Hi Ankit,
ReplyDeleteI have implemented the code above. However I am facing one issue here. I have a SSRS custom report that I am running on CRM online environment. This report runs in the context on current record.
The issues is that the report gets generated in the pdf format but the report is generated everytime for some specific incident id, the report does not change if I run the report in context of other record.
Hi Ankit,
ReplyDeleteI am trying to implement your code on the order entity but i am stuck with all kinds of errors, first some basic javascript errors for undefined variables. And then the report is also not created because i am trying to use the context sensitive Order report which does not have any parameters but the report prints for the current order record.
I would really appreciate if you can provide this as a n unmanaged solution which i can import and try
Hi Ankit,
ReplyDeleteI went through you post. When I tried implementing the same code I was able to achieve the functionality with a little changes in my Report design.
If there is a report which runs in context of the entity record i.e. if enableprefiltering is set to true then this code wont work, here the report will get generated as an attachment but when we try to open pdf attachment it will give decode error saying the file is corrupt.
The resolution is that we need to remove enableprefiltering and add a parameter in report that accepts id and then when we pass the report id in the request string in the getReportSession() function report after which the report gets generated in context of the current record.
Hi, I have tried this solution and it's not working for me. I am also getting the same error that it is unable to decode the report. Can anyone please let me know the resolution?
DeleteHi Ankit,
ReplyDeleteThank you for this clear guide. I'm trying to implement this at the moment.
I'm trying to adapt the code on 3 parts:
1) I want to be able to print the report in a separate button.
2) I want to get the report through a reportserver URL;
3) If possible, I want to use a prefiltered report.
Hello Nate,
ReplyDeleteTo print a report, the below URL might help you.
http://blog.customereffective.com/blog/2011/08/printing-in-crm-2011.html
On prefiltering a report, at present this solution works only at record level. (Not at list level with multiple records.)
Hi Ankit,
ReplyDeleteI wonder if there is a way to choose the email template, to populate the description? Thanks
Renato
Hello Renato,
ReplyDeleteYes, you should get the e-mail template data via the REST call and setup the description to e-mail body. I never did it before but I believe it should work.
Hi Ankit,
ReplyDeleteThank you very much for your response!
I am having a problem passing parameter to my report.
I need to get the entity Guid to the report but it returns nothing when I do.
Thats the code without the parameter:
retrieveEntityReq.send("id=%7B" + reportId + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" + reportName + "&isScheduledReport=false");
Thats is the code with the parameter:
retrieveEntityReq.send("id=%7B" + reportId + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" + reportName + "&isScheduledReport=false&p:isite_appointmentserviceid=" + Id );
Can you see what I am doing wrong??
Thanks again!!!!!
Hi Ankit;
ReplyDeleteas you said you used only one button to execute your code ..i am just confuse how did you call your html web resource and also what code need to be go in jacascirpt file and html file could you please give suggestion
Yes, there is a custom ribbon button that executes this logic. The html web resource should be added as hidden component on the entity where you are trying to achieve above solution. The code specified in Step 3 is for HTML web resource. The source code specified in step 1 and step 2 are JavaScript file. There is no progress bar is implemented in above solution.
Deleteand also how we can use a progress bar while the email activity is being generated
ReplyDeleteHello Renato,
ReplyDeleteThe URL that you specified above seems correct to me. Can you confirm on below points:
1. Whether it is Fetxml or SQL query based report?
2. At present, the above solution does not support report prefiltering, did you apply prefiltering?
3. Are you getting any specific errors?
Hi Ankit,
DeleteThank you so much for your time.
1 - The Report is fetchxml
2 - It is prefiltering... Should I Disable that?
3 - The report returns with the fields empty.. The structure is there but the fields not populated.
Cheers...
Hi Ankit,
DeleteProblem solved... thank you very much for your help!
Hello Renato,
DeleteSorry, I am so much busy during this week. Please feel free to update this post with your resolution.
What was the solution Renato? I am about to start working on this issue with a fetchxml report.
DeleteHello Renato,
DeleteI am facing same problem with report.
So can you please guide me what to do?
This comment has been removed by a blog administrator.
DeleteThanks ankit for reply ok so when i put the function for the button which function should i call (create email)???
ReplyDeleteIt works for me.I used fetch when I pass prefiltering parameter.Thanks
ReplyDeleteAnkit,
ReplyDeleteI am confused in the 2nd step in the function GetReportID....
what do we put in the oDataSetName, columns and filter variables? I don't know because these fields names are confusing.
Please help! Thanks.
Hi Ankit,
ReplyDeleteI am trying to implement your solution, unfortunately not able to get any where near to it. Can you please help and advise how I can use this.
I have put all javascript functions in one web resource, hidden the html web resource on the form. Called function GetReportId with parameter of report name on click of a custom button.
Getting no where with it. I have tried calling CreateEmail as well on the same button click, this creates an email, but fails to attach anything to it.
Sorry for the hassle. Many Thanks.
Can you please let me know what error are you getting right now?
DeleteHi Ankit,
DeleteI am getting various errors. When I try to call CreateEmail and GetReportId on the button click I get email is not defined.
If I only call GetReportId, I get $ is undefined although I have added Jquery1.4.1min file as a web resource to the form.
It will be very helpful if you could advise what functions to call from the button click? How are the web resources to be included , i.e , jscript 1 and jscript 2 included in one web resource? or Jscript3 to be added in the same web resource as well? are there any modifications to be made to the html web resource that is used to call the functions?
Sorry, a bit new to all this.
Thanks.
Hello Mike,
ReplyDeleteThe variables had been already declared with values in GetReportID method. Do not change them, keep them "as is". Make sure you pass correct report name in this method.
Hi Ankit, thank you for the blog again.
ReplyDeleteI was having troubles passing my FetchXML parameters so I created my report in SQL. I am on premise. I made sure to select Default Value, Specify Value for my parameter and it worked like a charm passing my parameter.
I had some difficulty with passing the ReportName in your function so I also just hardcoded the Report Name and Report GUID.
Hello Ankit,
ReplyDeleteI am trying to change email activities in my entity to cancelled. but i am unable to do it.. can you please help me?
Hello Naveen,
ReplyDeleteCan you please confirm what you mean by Cancel here?
If you mean to close the newly created email activity then you need to managed the same in OData call itself.
Hi Ankit,
ReplyDeleteThanks for the solution. I have implemented your solution successfully but I have now hit a road block here.
I have a report which has many fields, thus spans to more than one page in the PDF generated. This is not acceptable by the client.
Any idea how I can convert this in a landscape mode rather than portrait as it is the case now?
Any help will be much appreciated.
Thanks in anticipation.
Shaffana.
Hello Ankit,
ReplyDeleteHere is my code, I am trying to generate report using Button click from ribbon.
I don't able to identity what the issue is ?
Please help me as i am very urgent this time.
My Objective is to Download Report using JavaScript
function getQuote() {
var pdfid = 'new_pdfid';
var result = "null";
control = Xrm.Page.getControl(pdfid);
attribute = control.getAttribute();
attribute.setValue(result);
Xrm.Page.data.entity.save();
var pdfid = 'new_pdfid';
alert("Ok1");
var result = "23A0-E111-A390-1CC13228EA01";
control = Xrm.Page.getControl(pdfid);
attribute = control.getAttribute();
attribute.setValue(result);
Xrm.Page.data.entity.save();
var reportName = "Quote"; //set this to the report you are trying to download
alert(reportName);
var reportId = "2d012dc2-1144-e311-881f-6c3be5bebd30";
var guid = Xrm.Page.data.entity.getId();
guid = guid.replace('{', '');
guid = guid.replace('}', '');
var etc = Xrm.Page.context.getQueryStringParameters().etc;
//&records=%7B” + guid + “%7D
alert(guid);
var pth = Xrm.Page.context.getServerUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
alert(pth);
var retrieveEntityReq = new XMLHttpRequest();
retrieveEntityReq.open("POST", pth, false);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
retrieveEntityReq.send("id=%7B" + reportId + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" + reportName + "&isScheduledReport=false");
alert("Ok2");
var x = retrieveEntityReq.responseText.indexOf("ReportSession=");
var ret = new Array();
ret[0] = retrieveEntityReq.responseText.substr(x + 14, retrieveEntityReq.responseText.indexOf("&", x) - x - 14);
x = retrieveEntityReq.responseText.indexOf("ControlID=");
ret[1] = retrieveEntityReq.responseText.substr(x + 10, retrieveEntityReq.responseText.indexOf("&", x) - x - 10);
alert("Ok3");
window.open(Xrm.Page.context.getServerUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + ret[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + ret[1] + "&OpType=Export&FileName=Quote&ContentDisposition=OnlyHtmlInline&Format=PDF", 'name', 'width=10,height=10');
}
Hello Ankit,
ReplyDeleteNice article. I wanted to know your opinion/advice on the task I am working on.
I wanted to create word file and copy the content of the description field of EMAIL entity. now creating word document and copying content is done but document is getting created with the text including HTML element since description field is rich text editor.
I tried to strip the HTML tags but then that is disturbing the format of the text which was originally available in the field.
can you please guide me in right direction.
Regards.
Sorry, but I never did it before, I don't have any ideas how to strip the HTML tags. However, if you will succeed in your implementation then please feel free to update this post with the approach and findings.
DeleteHello Shaffana,
ReplyDeleteYou need to change the SSRS Report Page Orientation or increase the report width to make it landscape and rest is same.
Hello Ankit
ReplyDeleteI have a little Timing out problem with a report, If I run it via crm, it timeout after 5 minutes.
The report itself takes 9-10 minutes everytime to run on server, hence the crm timing out, as I believe the default timeout is 300,000 milliseconds. The problem i have is the customer for some reason is unwilling to change this timeout. (Please dont ask me why ).
I beleive it is the NormalTimeout entry that does that ..
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM\NormalTimeout
In milliseconds. Specifies the SOAP call timeout for most operations
Default is 300,000
So I was thinking to have this report emailed as pdf. (awaiting clients decision on that)..
but meantime is there any other place or way to change this timeout that will effect Only THIS particular report.
It is on the CRM side as the report works fine when run directly on the report server.
Thanks in advance.
Bikram
Hi Ankit, I already asked you if you have a CRM solution to make a quick try.
ReplyDeleteI yes, could you please send it to mfoldes@alteanet.it?
I'd like to try your solution.
Coul'd I call the code from a javascript on the form?
Doe's it work on an online CRM?
Thanks a lot
Marco
Hello Macro,
DeleteNo, I don't have a ready made CRM solution. Yes you can call the code from a JavaScript. Yes, it works for CRM online as well.
Dear Ankit,
ReplyDeletepls help!! I dont know where exactly set my report name in your code!??
Which Command action parameter I have to set??
THANK YOU!
tubka
Hi,
Delete- Provide you custom report name in step tow for this activitymimeattachment.FileName.
- You can pass your parameters in step 3 code for the pth variable.
Refer the following code:
var pth = Xrm.Page.context.getServerUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
hello ,
ReplyDeleteis this worked with CRM 2013 ? (i already have a problem in getting session parametres)
thx for help.
Regards.
Hi Khaled,
ReplyDeleteIt is working with CRM 2013 in IE11 (Add dynamics.com site in compatibility mode in IE11.) It is not working in Chrome and Firefox.
Hello Ankit,
ReplyDeletepls. could you help me to install your great work.
- What parameter should be set on the ribbon button?
- Where should I define my Report in your script?
- Where can I get SDK.JScriptRESTDataOperations.js ?
It would be very kind if you could give me a little help for that.
Hi,
Delete- You need to call above specified CreateEmail function on your custom JavaScript ribbon button.
- Provide you custom report name in step tow for this activitymimeattachment.FileName.
- Refer the following link to download SDK.JScriptRESTDataOperations.js
http://social.microsoft.com/Forums/en-US/f501c019-aa7f-4d78-8390-5f11d1dd8820/crm-2011-sdk-crud-operation-samples?forum=crmdevelopment
Hi Ankit
ReplyDeleteI have two problems: first when I create the attachment the annotation is not connect to my email.
Second problem is that when I download the pdf file Acrobat Reader says that is in a format not recognize.
Any idea?
Thanks
Marco
Hi Marco,
DeleteSorry for the delay. Are you getting any errors? Did you try to debug your JavaScript code? Seems both the problems are related to each other.
Hi Ankit
ReplyDeleteCreating an email activity party gives an error
the 'create' method does not support entities of type 'activityparty'
CRM 2013 online
also how could i pass a fetchxml report parameters ?????
Hello Ahmed,
DeleteSorry for the late response. At present this solution is not working in chrome and fire fox for CRM 2013 online. But, it is working fine with IE 11 by adding "dynamics.com" in Compatibility View settings window.
You can pass your parameters in step 3 code for the pth variable.
DeleteRefer the following code:
var pth = Xrm.Page.context.getServerUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
hi ankit Im not able call vb script function BinaryToArray.Im woking on this since days.
ReplyDeleteHi Anbu, Sorry for the late response. Can you share what error are you getting?
DeleteHi,
DeleteThe vb script will only work from IE, it is not recognized by other browsers
Hi Ankit,
ReplyDeleteDid you have to make any changes to this so it would work after Rollup 12? We are currently on RU11 and are upgrading our Test environment to Rollup 15 later this week. I am wondering if there are any changes that I will need to plan on making? Thanks again!!
Hi Ankit,
ReplyDeleteCan you pass the CRM_FilteredInvoice parameter inside the call to "CRMReports/rsviewer/reportviewer.aspx" ? like " ... &p:CRM_FilteredInvoice=" + invoiceId ?
Your code definitely works, but it always creates a report for the first invoice it finds, not for the invoice I select (from the invoice grid). That's why I think I should pass the invoiceId somehow.
Thank you.
Hello Mihai,
DeleteThe above code is still not further developed to make it functional from the grid area of entities. But, yes it is working for the parameterised report, hence you could try the way you specified above. Please feel free to update this blog if you will be able to achieve the expected results successfully. Good luck.
Hi, I managed to get it working. You have to add a filter, as I suspected. But the filter has to be something like :
DeleteI noticed this when using Fiddler and printed the report I wanted (from CRM), this is actually what happens behind the scenes.
I created a .js function called "buildInvoiceFilter" that replaces the invoice id with the right value and returns this string, then I concatenate it to the "/CRMReports/rsviewer/reportviewer.aspx" request, so now I have something like:
...blah..blah.."&isScheduledReport=false&CRM_Filter=" + buildInvoiceFilter(invoiceId))
Seems to also work if I have invoice details (even if I don't populate the CRM_FilteredInvoiceDetail parameter)
Hello Mihai,
DeleteCan you please share you code of buildInvoiceFilter(invoiceId) function. That will help a lot.
Thanks,
Hi Ankit,
ReplyDeleteIs this solution feasible for System reports in MS CRM 2013?
I could not get report session parameters, and xml http request returns a generic error - "Try this action again. If probelm continues..... contact administrator"
Please share your thoughts.
- Praveena
Hello Praveena,
DeleteYes, it should work with system reports too. Are you using the correct report name GetReportId() method of step 2?
Hi Ankit,
ReplyDeleteWill this work for System reports?
Was anyone able to make this work for Chrome or Firefox?
ReplyDeleteOr rather I should say, was any one able to convert the VBSCRIPT function to JAVASCRIPT?
ReplyDeleteCode was working fine in CRM 2013 but today (05-29-2014)above code is attaching corrupted file.Attached PDF size is 7782 and it is not exceeding this limit.We have done it for many clients but now it is reducing the file size to 7782.
ReplyDeleteAny help?
Anyone else who is experiencing problems after the spring release? Had this running on crm 2013 online without problems until the spring release came. The pdf:s generated are now corrupt.
ReplyDeleteHi, yes you are right. The code is unable to generate the PDFs after CRM 2012 online spring 14 release. I am working on this problem and would try to resolve it as soon as I can.
ReplyDeleteHi, for crm 2013 spring edition there are some required changes to the code.
ReplyDeleteFOR CRM 2013 Spring edition which is SP1
ReplyDeletethe page you get the session id and control id is changed from
pth = Xrm.Page.context.getServerUrl() + "CRMReports/rsviewer/reportviewer.aspx";
to
pth = Xrm.Page.context.getServerUrl() + "CRMReports/rsviewer/QuirksReportViewer.aspx";
And the substring method to get the ControlID and ReportSession is like below:
ret[0] = retrieveEntityReq.responseText.substr(x + 14, retrieveEntityReq.responseText.indexOf("u0026", x) - x - 15); //the session id
ret[1] = retrieveEntityReq.responseText.substr(x + 10, retrieveEntityReq.responseText.indexOf("u0026", x) - x - 11);; //the control id
Rest of the code remains the same.
Hope this helps somebody...
All the best
Oğuz
Hello Oğuz ERDEVE,
ReplyDeleteThank you for sharing the solution. Actually, I tried with it for one of my customers but it did not work. Did you cover all changes? Can you please share the entire getReportingSession() function?
Thanks,
Ankit
Hi All,
ReplyDeleteI was able to get this working for CRM 2013 SP1 by doing the changes as mentioned by Oğuz ERDEVE. I did not had to make changes to the Session Id and Control Id though.
Hope it helps some one.
Thanks all for the input.
Hi All,
ReplyDeletethis code run very well, but i have error when i open the pdf file, i don't now why.
Any idea?
I changed the encoded funtion but not work in same.
Error message: not a supported file type or because the file has been damaged.
Hi Andre,
DeleteI have also getting the same problem as you mentioned above. I think, we need to decode the pdf file.
Thanks,
Ganesh.J
i am having the error
ReplyDeletenot a supported file type or because the file has been damaged
Your are the BEST !
ReplyDeleteThanks..
Hi Ankit,
ReplyDeleteI couldn't able to read/open the pdf file after created the email record. May I know the reason for this problem from the above code?
Thanks,
Ganesh.J.
i replaced reportname and id as mentioned under function getReportingSession()
ReplyDeletealso i removed getServerUrl() since it not longer supports in CRM2013 and i replaced with getClientUrl() and also did as Oğuz ERDEVE suggested but still no luck
Hi,
ReplyDeleteNice work. Its very informative.
could you please guide me on how to do this below requirement?
I want to generate a pdf form on click of a custom ribbon button. Your work looks similiar to my requirement but I don't want to attach it to any email.
Please suggest some solution to this. Thanks.
CRM 2015 Online Update: Hope it helps someone
ReplyDeletefunction getReportingSession()...
var ret = new Array();
ret[0] = retrieveEntityReq.responseText.substr(x + 14, retrieveEntityReq.responseText.indexOf("\\u", x) - x - 14); //the session id
x = retrieveEntityReq.responseText.indexOf("ControlID=");
ret[1] = retrieveEntityReq.responseText.substr(x + 10, retrieveEntityReq.responseText.indexOf("\\u", x) - x - 10); //the control id
return ret;
Hello,
ReplyDeleteI have a same issue for corrupt pdf.
Error message: not a supported file type or because the file has been damaged.
I am working on crm 2015 online.
Please provide a solution if any one resolved it....
Hi All,
ReplyDeleteIs there a way of using this functionality on multi browser? Currently it is using the VB script which I think is only supported in IE and not any other browser.
Has any of the Gurus came across this or solved this. Please share your solutions to the wider weaker world.
Thanks
Hello All,
ReplyDeleteBecause the CRM 2015 Update 1 gives problems with the VB script (and because we really don't like using VB anymore) we've reworked the JS a little to work without the VB script. The change is fairly simple and you only need to change the "EncodePdf" function. This way you also don't need the WebResource on the form anymore! Here is the code for it:
// Encodes a report into a PDF
this.encodePdf = function (params) {
bdy = new Array();
bdyLen = 0;
var retrieveEntityReq = new XMLHttpRequest();
var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
retrieveEntityReq.open("GET", pth, false);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.send();
return encode64(retrieveEntityReq.responseBody.toArray());
}
Sven Can you provide your entire create e-mail and attach pdf report in Version 2015?
DeleteSven, Can you supply your entire solution for email creation with PDF SSRS Report attached.
DeleteHello everyone,
ReplyDeleteThank you for sharing your feedback till date at this blog.
Today, I've applied required changes to this blog. The updated code should now work well with CRM 2011 UR 12 and above.
Thanks,
Ankit
Still receiving the following error on CRM 2015
ReplyDeletenot a supported file type or because the file has been damaged
Anwar
Hi,
DeleteIs it CRM 2015 online or on-premises?
Can you run the report in CRM from the reports area?
it is mscrm 2015 online
DeleteHello Guys
ReplyDeleteGood work Ankit...
I was able to get this code working on CRM 2015 spring release with minor changes. Here is the change i made to get this code working.
var x = retrieveEntityReq.responseText.lastIndexOf("ReportSession=");
var ret = new Array();
ret[0] = retrieveEntityReq.responseText.substr(x + 14, 24); //the session id
x = retrieveEntityReq.responseText.lastIndexOf("ControlID=");
ret[1] = retrieveEntityReq.responseText.substr(x + 10, 32); //the control id
If anyone needs complete code drop me comment in by blog..
Hello Chitrarasan,
DeletePlease know, I've already changed this blog code for the piece of code that you described here in your comment.
If you've copied the complete code from this blog then it should work as is for CRM 2015 spring release.
Thanks,
Ankit
Hi Chitrarasan,
DeleteI am trying to implement this in crm online 2015
but not able to get reportsession id.
Please provide me the complete code
Email id- pankajgpt31@gmail.com
Hi Ankit,
ReplyDeleteThanks for sharing this code.
The code works fine. The PDF attachment gets created but cannot be opened. The error message thrown is - Adobe Acrobat could not open "FileName.pdf" because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
I am trying this on CRM 2015 Online. Any suggestions?
When I debug the code I get responseBody value as "undefined" for the below line
return encode64(retrieveEntityReq.responseBody.toArray());
Thanks,
Swaroop
Hi Swaroop,
DeleteFirst, please verify, your report is working accurately or not. Also, is this report contains any parameter(s)? If yes, then these parameters are also needs to be accurately setup. Can you please share source code for following two JavaScript methods?
getReportingSession
encodePdf
Thanks,
Ankit
Hi Ankit,
DeleteThanks for your reply. Here's the code I am using. Using the code below I get the Session Id and Control Id of the report properly.
getReportingSession: function () {
var reportParams = new Array();
var url = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
var quoteId = Xrm.Page.data.entity.getId();
var quotationGUID = quoteId.replace('{', ""); //set this to selected quotation GUID
quotationGUID = quotationGUID.replace('}', "");
var reportName = "Quote Report"; //set this to the report you are trying to download
var reportId = "c1d271ab-8154-e411-94ab-6c3be5a8d218"; //set this to the guid of the report you are trying to download
var reportFilter = " ";
var reportData = "id=%7B" + reportId + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" +
reportName + "&isScheduledReport=false&p:CRM_quote=" + reportFilter;
var executeReportRequest = new XMLHttpRequest();
executeReportRequest.open("POST", url, false);
executeReportRequest.setRequestHeader("Accept", "*/*");
executeReportRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
executeReportRequest.send(reportData);
var response = executeReportRequest.responseText;
if (response != null && response.indexOf("ReportSession=") != -1) {
var sessionIdIndex = response.indexOf("ReportSession=");
var controlIdIndex = response.indexOf("ControlID=");
reportParams[0] = executeReportRequest.responseText.substr(sessionIdIndex + 14, executeReportRequest.responseText.indexOf("&", sessionIdIndex) - sessionIdIndex - 14); //the session id
reportParams[1] = executeReportRequest.responseText.substr(controlIdIndex + 10, executeReportRequest.responseText.indexOf("&", controlIdIndex) - controlIdIndex - 10); //the control id
}
return reportParams;
},
encodePdf:function(reportParameters) {
var retrieveEntityReq = new XMLHttpRequest();
var url = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + reportParameters[0] +
"&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + reportParameters[1] +
"&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
retrieveEntityReq.open("GET", url, false);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.send();
return encode64(retrieveEntityReq.responseBody.toArray());
},
Thanks,
Swaroop
Hello Swaroop,
DeleteSorry for the delayed response.
Please correct the following two lines and run your code again.
reportParams[0] = executeReportRequest.responseText.substr (sessionIdIndex + 14, 24); //the session id
reportParams[1] = executeReportRequest.responseText.substr (controlIdIndex + 10, 32); //the control id
Hi Ankit,
DeleteThe change didn't work. I am still facing the same error. I am facing this error on IE 11 and on Chrome even the attachment is not getting created and associated for the email record.
Thanks,
Swaroop
Hi Ankit,
ReplyDeleteWanted to know whether it would work for MSCRM 2013?
Thanks in advance
Yes, it works with MSCRM 2013 too.
DeleteThanks,
Ankit
HI Ankit,
ReplyDeleteGetting error in Chrome browser.
Error at this line :
bdy = encode64(retrieveEntityReq.responseBody.toArray());
Please help me how to resolve issue.
Thanks,
Benarji
Hi,
DeleteFor CRM 2011 to run it in Chrome browser you need to perform following changes.
//Need to change a body of this function.
function onSuccess(data) {
reportId = data[0].ReportId.replace('{', ").replace('}', ");
//get reporting session and use the params to convert a report in PDF
var params = getReportingSession();
encodePdf(params);
}
//Need to change a definition of this function, just pass one parameter.
CreateEmailAttachment(encodedPdf) {
//In the function "CreateEmailAttachment" just change a code of assignment the body part.
activitymimeattachment.Body = encodedPdf;
//Need to change the body part of this function.
function encodePdf(params) {
var retrieveEntityReq = new XMLHttpRequest();
var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
retrieveEntityReq.open('GET', pth, true);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.responseType = "arraybuffer";
retrieveEntityReq.onload = function (e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response);
var base64 = encode64(uInt8Array);
CreateEmailAttachment(base64);
}
};
retrieveEntityReq.send();
}
Let me know if you have any further questions about these changes.
Thanks,
Ankit
Hi,
ReplyDeleteIs this code also working for CRM 2016 online?...please reply.
Thanks,
Tin
Hello Tin,
DeleteYes it is working for CRM 2016 online.
Thanks,
Ankit
Ankit, Thanks for your response.
DeleteCan you Please share the code.
Thanks,
Tin
Code is here on the post itself. Please take it from the post and update it as per your need.
DeleteHello Ankit,
DeleteWhere from ican find the library Sdk.Soap.js?
Can you please Help me.
Thanks,
Tin
Here it is,
Deletehttps://code.msdn.microsoft.com/SdkSoapjs-9b51b99a
Hello Ankit,
DeleteThanks for your response.
I added the library "Sdk.Soap.min.js"
and getting error on the line below:
var regardingObjectId = new Sdk.EntityReference(entityLogicalName, id);
Can you please verify which library need to add.
Thanks,
Tin
Tin, please share the error details.
ReplyDeleteAnkit Thanks!
ReplyDeleteThe code works fine. The PDF attachment gets created but cannot be opened. The error showing in Foxit Reader- "Format Error: Not a PDF or corrupted."
I am trying this on CRM 2016 Online. Any suggestions?
Thanks,
Tin
Hello Tin,
DeleteCan you please share the complete code?
Thanks,
Ankit
Yeah seen Ankit thank you soo much your code is real charm !!!
ReplyDeleteIt helps me a lot many many thanks you once again bro.
Hi
ReplyDeleteis there a way to send the email directly
without opening the form of the email
Hi Abood,
DeleteYes, you can do it. You could use send email message of SDK.Soap call. http://ankit.inkeysolutions.com/2014/10/the-sdksoapjs-code-samples-of-sdksync.html
This is soooo excellent! But I get the error in trying to open the pdf:
ReplyDeleteAcrobat could not open 'PDF01TryTest.pdf' becue it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
function EncodePdf(params) {
var retrieveEntityReq = new XMLHttpRequest();
var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
retrieveEntityReq.open('GET', pth, true);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.responseType = "arraybuffer";
retrieveEntityReq.onload = function (e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response);
var base64 = Encode64(uInt8Array);
CreateEmailAttachment(base64);
}
};
retrieveEntityReq.send();
}
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function Encode64(input) {
var output = new StringMaker();
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
while (i < input.length) {
chr1 = input[i++];
chr2 = input[i++];
chr3 = input[i++];
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output.append(keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4));
}
return output.toString();
}
var StringMaker = function () {
this.parts = [];
this.length = 0;
this.append = function (s) {
this.parts.push(s);
this.length += s.length;
}
this.prepend = function (s) {
this.parts.unshift(s);
this.length += s.length;
}
this.toString = function () {
return this.parts.join('');
}
}
//Create attachment for the created email
function CreateEmailAttachment(encodedPdf) {
//Get order number to name a newly created PDF report
var orderNumber = Xrm.Page.getAttribute("new_ordernumber");
var emailEntityReference = new Sdk.EntityReference("email", emailId);
var newFileName = fileName + ".pdf";
if (orderNumber != null)
newFileName = fileName + orderNumber.getValue() + ".pdf";
var activitymimeattachment = new Sdk.Entity("activitymimeattachment");
activitymimeattachment.addAttribute(new Sdk.String("body", encodedPdf));
activitymimeattachment.addAttribute(new Sdk.String("subject", "File Attachment"));
activitymimeattachment.addAttribute(new Sdk.String("objecttypecode", "email"));
activitymimeattachment.addAttribute(new Sdk.String("filename", newFileName));
activitymimeattachment.addAttribute(new Sdk.Lookup("objectid", emailEntityReference));
activitymimeattachment.addAttribute(new Sdk.String("mimetype", "application/pdf"));
Sdk.Async.create(activitymimeattachment, ActivityMimeAttachmentCallBack, function (error) { alert(error.message); });
}
Hi KD,
DeleteA few queries,
1. Is it CRM online or on-premises? CRM version?
2. Is this report running well from CRM?
3. Is this report running well at SSRS server?
4. Is it parameterized report?
Thanks,
Ankit
1. Online, latest version
ReplyDelete2. Runs fine from Crm
3. Created using report wizard, could that be the issue?
4. No parameters
Thanks!
Hi,
DeleteOne thing can be validated is below code, as your report has no parameters then I would suggest to remove "&p:salesorderid=" + Id + "&p:createdon=1/1/9999"" from the following line,
var req = "id=%7B" + reportId + "%7D&uniquename=" + orgUniqueName + "&iscustomreport=true&reportName=" + reportName + "&isScheduledReport=false&p:salesorderid=" + Id + "&p:createdon=1/1/9999";
Thanks,
Ankit
Hi Ankit,
ReplyDeleteReally great concept. It worked great for me even in latest version of 365 online.
But one thing am trying to figure is adding multiple recipients? I tried adding it as as array and entity collection. Its only taking last email address from the loop condition?
is there something am missing?
Any guidance or direction is greatly appreciated.
THanks
Kum
Hi Kum,
DeleteIn above code there is a method, named as PrepareActivityParty(), apply change in this method to loop through all parties and prepare a collection and return that collection for TO field of your email.
Feel free to ask if you have any further questions.
Hi,
ReplyDeleteI followed your code but i'm facing problem.
I want convert an invoice to PDF format using JavaScript and send with an attachment, but main issue on opening PDF file, attachment already done and working properly and PDF file also carry some size. At the time of open an PDF file it show error for opening.
Hi,
ReplyDeleteGreat Blog,
Here my issue is that I am using ms crm online version and every thing is Ok like attachment of PDF file and send an email, but main issue is on opening attached PDF file, It also have taken some size and at the time of opening it will not open.It will show "Format Error"
kindly share your suggestion.
Hi Surya,
DeletePlease share your code here. Also, in which browser are you validating this? Did you try with Chrome?
Thanks,
Ankit
I am unable to share code with you here, so plz share email-id and I am also check both IE and chrome browser, but it was same issue.
DeleteShare the same at ankithimmatlalshah@gmail.com
DeleteHello Ankit
ReplyDeleteI am getting below retrieveEntityReq.responseText in dynamics 365.
window.location.href = '/_common/error/errorhandler.aspx?BackUri=https%3a%2f%2fpragmasys90.crm8.dynamics.com%2fmain.aspx%3fetc%3d1084%26extraqs%3d%253f_gridType%253d1084%2526etc%253d1084%2526id%253d%25257bEE6460EA-6335-E711-811E-C4346BDC6E11%25257d%2526rskey%253d%25257b008FBB15-98E9-4C5D-A81A-E685FF8CCC2C%25257d%26pagemode%3diframe%26pagetype%3dentityrecord%26rskey%3d%257b008FBB15-98E9-4C5D-A81A-E685FF8CCC2C%257d&ErrorCode=0x8004832C&Parm0=%0d%0a%0d%0a&Parm1=%28rsItemNotFound%29&RequestUri=%2fCRMReports%2frsviewer%2fQuirksReportViewer.aspx&user_lcid=1033';
Thnaks
Hi Mahak,
DeleteThe given is error handler page URL and not the actual error. Please provide some more details about an error.
Thanks,
Ankit
Actually code is working for custom reports but not working for oob reports.
DeleteIdeally it should not be case I suppose. However can you share the error that you're getting?
DeleteAnkit,
DeleteI am getting above response (retrieveEntityReq.responseText) when sending request. Not getting what else you are asking.
When i am trying to open the pdf file it is giving below error.
Acrobat could not open 'Quote.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
Code for oob Quote.rdl report
Deletefunction getReportingSession() {
var reportName = "Quote";
reportID = "262D5F7E-4625-E711-811D-C4346BDD21B1";
var pth = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/QuirksReportViewer.aspx";
var retrieveEntityReq = new XMLHttpRequest();
retrieveEntityReq.open("POST", pth, false);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
rptPathString = "id=%7B" + reportID + "%7D"+
"&uniquename=" + Xrm.Page.context.getOrgUniqueName() +
"&iscustomreport=true&reportnameonsrs=&reportName=" + reportName +
"&isScheduledReport=false";
retrieveEntityReq.send(rptPathString);
var x = retrieveEntityReq.responseText.lastIndexOf("ReportSession=");
var ret = new Array();
ret[0] = retrieveEntityReq.responseText.substr(x + 14, 24); //Report session id
x = retrieveEntityReq.responseText.lastIndexOf("ControlID=");
ret[1] = retrieveEntityReq.responseText.substr(x + 10, 32); //Report control id
return ret;
}
even if we change &iscustomreport=false, it is not working. Giving same error response.
Hello Mahak,
DeleteSorry for the delayed response.
I've made some changes in the GetReportingSession()function to get rid of the "Failed load Pdf Document" Error.
Thanks,
Ankit
Hi Ankit, thanks for sharing your knowlege.
ReplyDeleteI facing a problem. My Report is execute in context of quote entity (FetchXML Report), the report is attach to the email activity correctly but when I open the file (pdf) the data in the report is not the data of the entity context but the data of other quote (the first(?)). My report Runs well when execute directly in CRM and show the data of the context quote (prefilter), but when i use the code to generate the email and attach to, the information in the report is not of the conext quote. There is a way to acomplish this in the conext report entity?.
Hi Ankit,
ReplyDeleteThanks for a gr8 solution.
But my requirement is same as many before, need to send a custom report as pdf attachment every night in Dynamics 365. Can you provide a solution for the same.
Read through a lot of posts but could find your most apt with the only exception of manual intervention.
Hi,
DeleteYou can use Microsoft Flow and trigger this Js with your custom logic.
Thanks
Jay
Hi Ankit,
ReplyDeleteThanks for the great post, , i uesd your code in my dynamics 365 online version , Email and pdf attachment creating successfully , when open attached pdf i got "Failed load Pdf Document" Error How to resolve this issue please help me to do this
Hello Ishu,
DeleteSorry for the delayed response.
I've made some changes in the GetReportingSession()function to get rid of the "Failed load Pdf Document" Error.
Thanks,
Ankit
i am having the error while calling Create Email Method It shows below error,
ReplyDeleteSdk is not defined at CreateEmail
Hi,
DeleteSorry for the delayed response. I would recommend to go with MS Flow instead of using this approach. This is an old way to achieve the need.
Thanks,
Ankit
Hi Ankit,
ReplyDeleteCan this be used for default reports in CRM like Account Distribution and supply the parameters for TopAccounts and GroupBy? I tried it but does not work, how to set these parameters? Any examples if feasible or snippet.
Dear Srini,
DeleteThis solution works only with the custom SSRS reports.