Generating a mobile report and attaching it to an email using JavaScript in Resco Mobile CRM

In this post I will show an example of how to execute a mobile report and sending it within an email using javascript in Resco CRM.

I had a requirement to provide a way of quickly creating an email with all work order jobs notes and a copy of an invoice report attached. Below is the entire code which achieves this but I will go into more detail in some of the more interesting functions later on in this post.

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta charset="utf-8" />
	<title>Send Invoice Email&lt;/title>
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="initial-scale=1, user-scalable=no" />
	<script src="JSBridge.js"></script>
</head>
<body>
	<script>
	
var annotations = [];
var email;

//Executed when button is pressed in the Invoice record	
MobileCRM.UI.EntityForm.onCommand("custom_SendInvoiceEmail",
	function (entityForm) {
		MobileCRM.UI.EntityForm.requestObject(
			function (entityForm) {
				var currentInvoice = entityForm.entity;
				var workOrderId = currentInvoice.properties.workorder.id;
				var InvoiceName = currentInvoice.primaryName;
				var InvoiceId = currentInvoice.id;
				var customerId = currentInvoice.properties.customerid.id;

				MobileCRM.Configuration.requestObject(function (config) {
					/// <param name='config' type='MobileCRM.Configuration'/>
					var filepath = config.storageDirectory + "/Invoice.pdf"; // Create file in storage directory.	
					fetchAnnotations(filepath, workOrderId, InvoiceName, InvoiceId, customerId);
				}, MobileCRM.bridge.alert, null);

			},
			MobileCRM.bridge.alert
		);
	}, true, null);

//Executed when button is pressed in the Invoice view	
MobileCRM.UI.EntityList.onCommand("custom_SendInvoiceEmail", function (entityList) {

	var currentInvoice = entityList.selectedEntity;
	var workOrderId = currentInvoice.properties.workorder.id;
	var InvoiceName = currentInvoice.primaryName;
	var InvoiceId = currentInvoice.id;
	var customerId = currentInvoice.properties.customerid.id;

	MobileCRM.Configuration.requestObject(function (config) {
		/// <param name='config' type='MobileCRM.Configuration'/>
		var filepath = config.storageDirectory + "/Invoice.pdf"; // Create file in storage directory.	
		fetchAnnotations(filepath, workOrderId, InvoiceName, InvoiceId, customerId);
	}, MobileCRM.bridge.alert, null);

}, true, null);


function fetchAnnotations(filepath, workOrderId, InvoiceName, InvoiceId, customerId) {
	var entity3 = new MobileCRM.FetchXml.Entity("fs_workorder");
	entity3.addAttribute("invoice_email");
	entity3.filter = new MobileCRM.FetchXml.Filter();
	entity3.filter.where("id", "eq", workOrderId);
	var fetch3 = new MobileCRM.FetchXml.Fetch(entity3);
	fetch3.execute("Array",
		function (result) {
			if (result && result.length) {
				for (var i in result) {
					var results = result[i];
					email = results[0];
				}
			}
		},
		function (error) {
			MobileCRM.bridge.alert(error);
		},
		null
	);

	var entity2 = new MobileCRM.FetchXml.Entity("annotation");
	entity2.addAttribute("id");
	entity2.addAttribute("notetext");
	entity2.addAttribute("documentbody");
	entity2.addAttribute("filename");
	entity2.filter = new MobileCRM.FetchXml.Filter();
	entity2.filter.where("objectid", "eq", workOrderId);
	var fetch2 = new MobileCRM.FetchXml.Fetch(entity2);
	fetch2.execute("Array",
		function (result) {
			if (result && result.length) {
				for (var i in result) {
					var results = result[i];
					var id = results[0];
					var notetext = results[1];
					var documentbody = results[2];
					var filename = results[3];
					annotations.push({
						id: id,
						notetext: notetext,
						documentbody: documentbody,
						filename: filename
					});
				}
			}
			makeTableHTML(filepath, annotations, InvoiceName, InvoiceId, email);
			annotations = [];
			email = null;
		},
		function (error) {
			MobileCRM.bridge.alert(error);
		},
		null
	);
}

function makeTableHTML(filepath, annotations, InvoiceName, InvoiceId, email) {
	var result = "Hi, <br><br>";
	result += "Job completed today: <br><br>";

	if (annotations.length > 0) {
		for (var i = 0; i < annotations.length; i++) {
			if (annotations[i].notetext != null) {
				result += "<i>" + annotations[i].notetext + "</i>" + "<br><br>";
			}
		}
		result += "Invoice and job report attached. <br><br>";

		fetchReportXML(filepath, annotations, InvoiceName, InvoiceId, email, result);
	}
}

function fetchReportXML(filepath, annotations, InvoiceName, InvoiceId, email, result) {
	var report = new MobileCRM.FetchXml.Entity("resco_mobilereport");
	report.addAttribute("resco_data");
	report.filter = new MobileCRM.FetchXml.Filter();
	report.filter.where("name", "eq", "Invoice Report");

	var fetch = new MobileCRM.FetchXml.Fetch(report);
	fetch.execute("Array", function (res) {
		if (res.length > 0) {
			var reportXML = res[0][0];

			runMobileReport(reportXML, filepath, annotations, InvoiceName, InvoiceId, email, result);
		}
	}, MobileCRM.bridge.alert, null);
}

function runMobileReport(reportXML, filepath, annotations, InvoiceName, InvoiceId, email, result) {
	var fetchXML = "<fetch version='1.0' count='1' resultformat='Array' mapping='logical' distinct='true'><entity name='invoice'><filter type='and'><condition attribute='id' operator='eq' value='" + InvoiceId + "'/></filter></entity></fetch>";

	MobileCRM.Configuration.requestObject(function (config) {
		MobileCRM.MobileReport.runReport(fetchXML, reportXML, "Pdf", null, false, filepath, function (res) {
			createEmail(filepath, InvoiceId, InvoiceName, result, email, annotations);
		}, MobileCRM.bridge.alert);

	}, MobileCRM.bridge.alert, null);
}

function createEmail(filepath, InvoiceId, InvoiceName, result, email, annotations) {
	var attachments = [];
	attachments.push(filepath);

	if (attachments.length > 0 && annotations.length > 0) {
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			result, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length == 0 && annotations.length > 0) {
		attachments.push(null);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			result, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length > 0 && annotations.length == 0) {
		attachments.push(filePath);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			null, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length == 0 && annotations.length == 0) {
		attachments.push(null);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			null, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	}
}				
	</script>
</body>
</html>

Executing code from an OnCommand function (via the form)

In code below is an example on how to execute code from an OnCommand function from the form and how to read values on the record you are executing the command from, in this case I running the code from the invoice entity.

As you can also see I am using the MobileCRM.Configuration.requestObject function which I am using to get the default storage directory where the invoice report will be stored. This works for both Windows 10 and Android and have there own directory paths for each. (You may find that adding documents to any other directory may not work as Resco CRM will not have permissions to add documents there).

//Executed when button is pressed in the Invoice record	
MobileCRM.UI.EntityForm.onCommand("custom_SendInvoiceEmail",
	function (entityForm) {
		MobileCRM.UI.EntityForm.requestObject(
			function (entityForm) {
				var currentInvoice = entityForm.entity;
				var workOrderId = currentInvoice.properties.workorder.id;
				var InvoiceName = currentInvoice.primaryName;
				var InvoiceId = currentInvoice.id;
				var customerId = currentInvoice.properties.customerid.id;
 
				MobileCRM.Configuration.requestObject(function (config) {
					/// 
					var filepath = config.storageDirectory + "/Invoice.pdf"; // Create file in storage directory.	
					fetchAnnotations(filepath, workOrderId, InvoiceName, InvoiceId, customerId);
				}, MobileCRM.bridge.alert, null);
 
			},
			MobileCRM.bridge.alert
		);
	}, true, null);

Executing code from an OnCommand function (via the view)

In code below is an example on how to execute code from an OnCommand function from the view and how to read values on the view record you are running the command from, in this case I running the code from the invoice entity.

I am doing the same as the code snippet above but using the function MobileCRM.UI.EntityList.onCommand so the user can run the code directly on the view instead on going into the entity form itself.

//Executed when button is pressed in the Invoice view	
MobileCRM.UI.EntityList.onCommand("custom_SendInvoiceEmail", function (entityList) {
 
	var currentInvoice = entityList.selectedEntity;
	var workOrderId = currentInvoice.properties.workorder.id;
	var InvoiceName = currentInvoice.primaryName;
	var InvoiceId = currentInvoice.id;
	var customerId = currentInvoice.properties.customerid.id;
 
	MobileCRM.Configuration.requestObject(function (config) {
		/// 
		var filepath = config.storageDirectory + "/Invoice.pdf"; // Create file in storage directory.	
		fetchAnnotations(filepath, workOrderId, InvoiceName, InvoiceId, customerId);
	}, MobileCRM.bridge.alert, null);
 
}, true, null);

Fetching your mobile report

Below is the code on how to fetch the XML definition of your mobile report (You create mobile reports using the report designer Resco provides, this stores the report as XML in the background). I want the XML of the invoice report I made and then pass it to the runMobileReport function where the report will be executed.

function fetchReportXML(filepath, annotations, InvoiceName, InvoiceId, email, result) {
	var report = new MobileCRM.FetchXml.Entity("resco_mobilereport");
	report.addAttribute("resco_data");
	report.filter = new MobileCRM.FetchXml.Filter();
	report.filter.where("name", "eq", "Invoice Report");
 
	var fetch = new MobileCRM.FetchXml.Fetch(report);
	fetch.execute("Array", function (res) {
		if (res.length > 0) {
			var reportXML = res[0][0];
 
			runMobileReport(reportXML, filepath, annotations, InvoiceName, InvoiceId, email, result);
		}
	}, MobileCRM.bridge.alert, null);
}

Executing your mobile report

This function below executes the mobile report by using the MobileCRM.MobileReport.runReport function where we need to pass in certain data before we can run the report.

First thing is we need to determine is what record(s) we are running the report against, in this case I have passed the fetchXML below to run the report against the current invoice, as you can see I am passing the InvoiceId into my filter so the report will be generated with data from my current invoice record.

Second argument we need to pass in is the reportXML that we got in the previous function which uses this to actually construct the report.

The third argument determines what file type the report should be, in this case I want the report to be a pdf file type.

The final argument we are interested in is the file path location we are going to save the mobile report to. I am passing the filepath variable we created in the very beginning which was like this – var filepath = config.storageDirectory + “/Invoice.pdf”; The mobile report will be stored in this directory with the name ‘Invoice.pdf’, if you want to know where the location is exactly you will need to use MobileCRM.bridge.alert(filepath); to get the name of the file path. Every time the user executes this code the file will be replaced.

Then finally I have created a function called createEmail which will create the email with notes and report automatically attached.

function runMobileReport(reportXML, filepath, annotations, InvoiceName, InvoiceId, email, result) {
	var fetchXML = "";
 
	MobileCRM.Configuration.requestObject(function (config) {
		MobileCRM.MobileReport.runReport(fetchXML, reportXML, "Pdf", null, false, filepath, function (res) {
			createEmail(filepath, InvoiceId, InvoiceName, result, email, annotations);
		}, MobileCRM.bridge.alert);
 
	}, MobileCRM.bridge.alert, null);
}

Creating an email with report attached

This function below creates the email using the MobileCRM.Platform.emailWithAttachments method which creates a draft email, either using the email record in Resco or using your default email application on your device, in our case we want to use the email records in Resco CRM.

The method requires specific arguments:

  1. Email Address – This can either be a standard email address or an activity lookup which can point to an account or contact.
  2. Email Subject – The title of the email.
  3. Email Body – The text within the body of the email (I tried passing images into the body but this is not possible).
  4. Attachments – An array of attachments. The array can support a direct file path to a file or can be a reference to a note. In this case I am passing the file path of the report I generated.
  5. Regarding – What record this email is related to.

You also need to make sure that the ‘Send Email Via’ is CRM Server if you intend on using Resco CRM email records and ‘Device App’ if you plan to use an external email application to send emails.

The email should looks like this below. As you can see the notes and invoice has been attached and ready to send.

function createEmail(filepath, InvoiceId, InvoiceName, result, email, annotations) {
	var attachments = [];
	attachments.push(filepath);
 
	if (attachments.length > 0 && annotations.length > 0) {
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			result, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length == 0 && annotations.length > 0) {
		attachments.push(null);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			result, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length > 0 && annotations.length == 0) {
		attachments.push(filePath);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			null, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	} else if (attachments.length == 0 && annotations.length == 0) {
		attachments.push(null);
		MobileCRM.Platform.emailWithAttachments(
			email, /// email address
			InvoiceName, /// email subject
			null, /// email body
			attachments,
			new MobileCRM.Reference("invoice", InvoiceId, InvoiceName),
			null,
			MobileCRM.bridge.alert,
			null
		);
	}
}				

Hopefully this post has been useful!

Leave a Reply

Your email address will not be published. Required fields are marked *