在批准报价、运行报告、生成 PDF 并发送带有 PDF 作为附件的电子邮件
Posted
技术标签:
【中文标题】在批准报价、运行报告、生成 PDF 并发送带有 PDF 作为附件的电子邮件【英文标题】:On Approval Of Quotation, Run Report, Generate PDF and Send an Email With PDF as attachment 【发布时间】:2014-06-17 17:47:00 【问题描述】:我正在使用 CRM ONLINE 2013。
如何自动化以下流程?
在批准报价时,运行报告。
生成 PDF。
发送带有 PDF 作为附件的电子邮件。
因为我已经浏览了很多关于这个主题的论坛,但是在 CRM ONLINE 中创建用于生成报告 PDF 的插件代码是不可能的。
有什么替代方法可以做到这一点..?
【问题讨论】:
【参考方案1】:我已经尝试了下面的代码,它对我来说工作正常。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript">
if (typeof (SDK) == "undefined")
SDK = __namespace: true ;
SDK.JScriptRESTDataOperations =
_context: function ()
if (typeof GetGlobalContext != "undefined")
return GetGlobalContext();
else
if (typeof Xrm != "undefined")
return Xrm.Page.context;
else return new Error("Context is not available.");
,
_getServerUrl: function ()
var serverUrl = this._context().getServerUrl()
if (serverUrl.match(/\/$/))
serverUrl = serverUrl.substring(0, serverUrl.length - 1);
return serverUrl;
,
_ODataPath: function ()
return this._getServerUrl() + "/XRMServices/2011/OrganizationData.svc/";
,
_errorHandler: function (req)
return new Error("Error : " +
req.status + ": " +
req.statusText + ": " +
JSON.parse(req.responseText).error.message.value);
,
_dateReviver: function (key, value)
var a;
if (typeof value === 'string')
a = /Date\(([-+]?\d+)\)/.exec(value);
if (a)
return new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10));
return value;
,
Create: function (object, type, successCallback, errorCallback)
var req = new XMLHttpRequest();
req.open("POST", this._ODataPath() + type + "Set", true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function ()
if (this.readyState == 4 /* complete */)
if (this.status == 201)
successCallback(JSON.parse(this.responseText, SDK.JScriptRESTDataOperations._dateReviver).d);
else
errorCallback(SDK.JScriptRESTDataOperations._errorHandler(this));
;
req.send(JSON.stringify(object));
,
Retrieve: function (id, type, successCallback, errorCallback)
var req = new XMLHttpRequest();
req.open("GET", this._ODataPath() + type + "Set(guid'" + id + "')", true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function ()
if (this.readyState == 4 /* complete */)
if (this.status == 200)
successCallback(JSON.parse(this.responseText, SDK.JScriptRESTDataOperations._dateReviver).d);
else
errorCallback(SDK.JScriptRESTDataOperations._errorHandler(this));
;
req.send();
,
Update: function (id, object, type, successCallback, errorCallback)
var req = new XMLHttpRequest();
req.open("POST", this._ODataPath() + type + "Set(guid'" + id + "')", true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("X-HTTP-Method", "MERGE");
req.onreadystatechange = function ()
if (this.readyState == 4 /* complete */)
if (this.status == 204 || this.status == 1223)
successCallback();
else
errorCallback(SDK.JScriptRESTDataOperations._errorHandler(this));
;
req.send(JSON.stringify(object));
,
Delete: function (id, type, successCallback, errorCallback)
var req = new XMLHttpRequest();
req.open("POST", this._ODataPath() + type + "Set(guid'" + id + "')", true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("X-HTTP-Method", "DELETE");
req.onreadystatechange = function ()
if (this.readyState == 4 /* complete */)
if (this.status == 204 || this.status == 1223)
successCallback();
else
errorCallback(SDK.JScriptRESTDataOperations._errorHandler(this));
;
req.send();
,
RetrieveMultiple: function (type, filter, successCallback, errorCallback)
if (filter != null)
filter = "?" + filter;
else filter = "";
var req = new XMLHttpRequest();
req.open("GET", this._ODataPath() + type + "Set" + filter, true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function ()
if (this.readyState == 4 /* complete */)
if (this.status == 200)
successCallback(JSON.parse(this.responseText, SDK.JScriptRESTDataOperations._dateReviver).d.results);
else
errorCallback(SDK.JScriptRESTDataOperations._errorHandler(this));
;
req.send();
,
__namespace: true
;
</script>
<script type="text/javascript">
//Create Email and link it with Order as Regarding field
var Xrm;
var email = new Object();
var ownerID = "";
var CustomerId = "";
if (window.opener) Xrm = window.opener.Xrm;
else if (window.parent) Xrm = window.parent.Xrm;
//Get ownerid who send email of quotation to customer
function GetOwnerID()
var owner = Xrm.Page.getAttribute("ownerid").getValue();
ownerID = owner[0].id;
var ownerName = owner[0].name;
var entityType = owner[0].entityType;
GetToEmailGUID();
//Get customerid who receive email of quotation from owner
function GetToEmailGUID()
var Customer = Xrm.Page.getAttribute('customerid').getValue();
CustomerId = Customer[0].id;
var CustomerName = Customer[0].name;
var entityType = Customer[0].entityType;
//if CustomerId is type of "Account" then get Primary Contact id of that account
if (entityType == "account")
var contact = Xrm.Page.getAttribute("customerid").getValue();
if (contact === null) return;
var serverUrl = Xrm.Page.context.getClientUrl();
var oDataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/AccountSet(guid'" + contact[0].id + "')?$select=PrimaryContactId";
var req = new XMLHttpRequest();
req.open("GET", oDataSelect, false);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
req.onreadystatechange = function ()
if (req.readyState === 4)
if (req.status === 200)
var retrieved = JSON.parse(req.responseText).d;
CustomerId = retrieved.PrimaryContactId.Id;
else
alert(this.statusText);
;
req.send();
function CreateEmail()
GetOwnerID();
email.Subject = "Email with Report Attachment";
//Set The current order as the Regarding object
email.RegardingObjectId =
Id: Xrm.Page.data.entity.getId(), //Get the current entity Id , here OrderId
LogicalName: Xrm.Page.data.entity.getEntityName()//Get the current entity name, here it will be “salesOrder”
;
//Create Email Activity
SDK.JScriptRESTDataOperations.Create(email, "Email", EmailCallBack, function (error) alert(error.message); );
// Email Call Back function
function EmailCallBack(result)
email = result; // Set the email to result to use it later in email attachment for retrieving activity Id
var activityPartyFrom = new Object();
// Set the From party of the ActivityParty to relate an entity with Email From field
activityPartyFrom.PartyId =
Id: CustomerId, //"79EBDD26-FDBE-E311-8986-D89D6765B238", // id of entity you want to associate this activity with.
LogicalName: "contact"
;
// Set the "activity" of the ActivityParty
activityPartyFrom.ActivityId =
Id: result.ActivityId,
LogicalName: "email"
;
// Now set the participation type that describes the role of the party on the activity).
activityPartyFrom.ParticipationTypeMask = Value: 2 ; // 2 means ToRecipients
// Create the from ActivityParty for the email
SDK.JScriptRESTDataOperations.Create(activityPartyFrom, "ActivityParty", ActivityPartyFromCallBack, function (error) alert(error.message); );
var activityPartyTo = new Object();
// Set the From party of the ActivityParty to relate an entity with Email From field
activityPartyTo.PartyId =
Id: ownerID, //"79EBDD26-FDBE-E311-8986-D89D6765B238", // id of entity you want to associate this activity with.
LogicalName: "systemuser"
;
// Set the "activity" of the ActivityParty
activityPartyTo.ActivityId =
Id: result.ActivityId,
LogicalName: "email"
;
// Now set the participation type that describes the role of the party on the activity).
activityPartyTo.ParticipationTypeMask = Value: 1 ; // 1 means Sender
// Create the from ActivityParty
SDK.JScriptRESTDataOperations.Create(activityPartyTo, "ActivityParty", ActivityPartyToCallBack, function (error) alert(error.message); );
//ActivityParty From Callback
function ActivityPartyFromCallBack(result)
//ActivityParty To Callback
function ActivityPartyToCallBack(result)
GetReportId('Quotation');
//Create attachment for the created email
function CreateEmailAttachment()
//get reporting session and use the params to convert a report in PDF
var params = getReportingSession();
//Email attachment parameters
var activitymimeattachment = Object();
activitymimeattachment.ObjectId = Object();
activitymimeattachment.ObjectId.LogicalName = "email";
activitymimeattachment.ObjectId.Id = email.ActivityId;
activitymimeattachment.ObjectTypeCode = "email",
activitymimeattachment.Subject = "File Attachment";
activitymimeattachment.Body = encodePdf(params);
activitymimeattachment.FileName = "Report.pdf";
activitymimeattachment.MimeType = "application/pdf";
//Attachment call
SDK.JScriptRESTDataOperations.Create(activitymimeattachment, "ActivityMimeAttachment", ActivityMimeAttachmentCallBack, function (error) alert(error.message); );
//ActivityMimeAttachment CallBack function
function ActivityMimeAttachmentCallBack(result)
var features = "location=no,menubar=no,status=no,toolbar=no,resizable=yes";
var width = "800px";
var height = "600px";
window.open(Xrm.Page.context.getServerUrl() + "main.aspx?etc=" + 4202 + "&pagetype=entityrecord&id=" + email.ActivityId, "_blank", features);
// To open window which works in outlook and IE both
//openStdWin(Xrm.Page.context.getServerUrl() + "main.aspx?etc=" + 4202 + "&pagetype=entityrecord&id=" + email.ActivityId, "_blank", width, height, features);
//This method will get the reportId based on a report name that will be used in getReportingSession() function
function GetReportId(reportName)
var oDataSetName = "ReportSet";
var columns = "ReportId";
var filter = "Name eq '" + reportName + "'";
retrieveMultiple(oDataSetName, columns, filter, onSuccess);
function retrieveMultiple(odataSetName, select, filter, successCallback)
var serverUrl = Xrm.Page.context.getServerUrl();
var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
var odataUri = serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "?";
if (select)
odataUri += "$select=" + select + "&";
if (filter)
odataUri += "$filter=" + filter;
$.ajax(
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: odataUri,
beforeSend: function (XMLHttpRequest)
XMLHttpRequest.setRequestHeader("Accept", "application/json");
,
success: function (data)
if (successCallback)
if (data && data.d && data.d.results)
successCallback(data.d.results);
else if (data && data.d)
successCallback(data.d);
else
successCallback(data);
,
error: function (XmlHttpRequest, errorThrown)
if (XmlHttpRequest && XmlHttpRequest.responseText)
alert("Error while retrieval ; Error – " + XmlHttpRequest.responseText);
);
function onSuccess(data)
reportId = data[0].ReportId.replace('', ").replace('', ");
CreateEmailAttachment(); // Create Email Attachment
//Gets the report contents
function getReportingSession()
var pth = Xrm.Page.context.getServerUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
var retrieveEntityReq = new XMLHttpRequest();
var Id = Xrm.Page.data.entity.getId();
var quotationGUID = Id.replace('', ""); //set this to selected quotation GUID
quotationGUID = quotationGUID.replace('', "");
var reportName = "Quotation"; //set this to the report you are trying to download
var reportID = "7C39D18F-1DC6-E311-8986-D89D6765B238"; //set this to the guid of the report you are trying to download
var rptPathString = ""; //set this to the CRMF_Filtered parameter
var strParameterXML = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='quote'><all-attributes /><filter type='and'><condition attribute='quoteid' operator='eq' uitype='quote' value='" + quotationGUID + "' /> </filter></entity></fetch>";
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&p:CRMAF_Filteredquote=" + strParameterXML;
//remove the part starting from &p:salesorderid if your report has no parameters
retrieveEntityReq.send(rptPathString);
var x = retrieveEntityReq.responseText.indexOf("ReportSession=");
var ret = new Array();
ret[0] = retrieveEntityReq.responseText.substr(x + 14, retrieveEntityReq.responseText.indexOf("&", x) - x - 14); //the session id
x = retrieveEntityReq.responseText.indexOf("ControlID=");
ret[1] = retrieveEntityReq.responseText.substr(x + 10, retrieveEntityReq.responseText.indexOf("&", x) - x - 10); //the control id
return ret;
var bdy = new Array();
var bdyLen = 0;
function concat2Bdy(x)
bdy[bdyLen] = x;
bdyLen++;
function encodePdf(params)
bdy = new Array();
bdyLen = 0;
var retrieveEntityReq = new XMLHttpRequest();
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";
retrieveEntityReq.open("GET", pth, false);
retrieveEntityReq.setRequestHeader("Accept", "*/*");
retrieveEntityReq.send();
BinaryToArray(retrieveEntityReq.responseBody);
return encode64(bdy);
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('');
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();
</script>
<script type="text/vbscript">
Function BinaryToArray(Binary)
Dim i
ReDim byteArray(LenB(Binary))
For i = 1 To LenB(Binary)
byteArray(i-1) = AscB(MidB(Binary, i, 1))
concat2Bdy(AscB(MidB(Binary, i, 1)))
Next
BinaryToArray = byteArray
End Function
</script>
</head>
<body>
<input type="button" onclick="CreateEmail();" value="Attach Report" />
</body>
</html>
【讨论】:
以上是关于在批准报价、运行报告、生成 PDF 并发送带有 PDF 作为附件的电子邮件的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 MS Access 基于变量发送带有附加报告的自定义电子邮件? 2003 年或 2007 年