Is there any way to edit the email content before Autoemailing the PO through SSRS Routing.?

Autoemailing PO by enabling the printing routing rules was successful. But I would like to prereview/edit the email content - before sending it to the respective supplier…

Uncheck the Routing box

image

That gets checked automatically when the reports style has an enabled Break routing. Unchecking the box makes it ignore the break routing. But you’d lose any of the detail the break routing adds.

What you could do is duplicate the report style, and its break routing. Then chge it so that it is only sent to you. Add the fields that you would have sent it to to the body, so you can se how they would have populated.

Thanks for replying Calvin.
1)unchecking the routing box it just open up the PDF document.
2)Duplicated the report style and updated the changes so that I received the email with the PO attached but again i have to do lot of editing. Adding suppliers email IDs, deleting the unwanted content etc.

I want to just pop up the outlook new message with the content of PO attached and supplier email ID’s. Later I will do the necessary edit and would like to manually click the send button of that email.

I wanted that too. But no luck. I tried very hard to intercept the email, so I could preview it before it was actually sent. But no such luck.

Maybe something in the Information Worker add-on does this.

https://www.epicor.com/en-us/business-need/data-management-and-connectivity/epicor-information-worker/

Or if you’re an O365 user, you could use the Outlook Mail REST API

What you’re describing is the Document Sender tool created by Dot Net IT, now Epicor. It isn’t particularly expensive, ask your CAM for a price.

1 Like

What we do is put the default email content in a UD field (we do this for both PO and SO) and make it visible in the Entry screen for the user to alter as they create the PO or SO. Then that text gets used in the routing as the content of the email.

2 Likes

Thanks for all your inputs. Let me try and see. If i figuring out anything new, will share.

We have a customisation on PO entry that creates and an email, inserts the suppliers email address, attaches the PO report, attaches our terms and conditions, and fills in default text in the email and leaves the email open for the user to edit as required before hitting send. It was done a long time ago so it may not be the best code… I also had some permissions issues to sort out before this worked. It is triggered from a button on the PO entry screen.

Here is the code. Note the additional dll’s that need to be distributed to the clients.

private void epiButtonC1_Click(object sender, System.EventArgs args)
{
		// ** Place Event Handling Code Here **

		// This customisation requires 2 .dll files for the email automation to work. These files must exsist in the client
		// folder on the client machine before the customistaion can load. 
		// The files are:
		// - Microsoft.Office.Interop.Outlook.dll
		// - Microsoft.ReportViewer.WebForms.dll

		
		EpiDataView edvPOHeader = (EpiDataView)oTrans.EpiDataViews["POHeader"];
		int PONUM;
		string Approved;
		string Requestor;
		string Supplier;
		string CurrentCompany;

		// check if there is data loaded into the form. if not return from method.
		if ( (bool)edvPOHeader.HasRow == false )
		{
						MessageBox.Show("There is no data present to email");
						return;
		}
		
		// Get data from the form
		Approved = (string)edvPOHeader.dataView[edvPOHeader.Row]["ApprovalStatus"];
		PONUM = (int)edvPOHeader.dataView[edvPOHeader.Row]["PONum"];
		Requestor = (string)edvPOHeader.dataView[edvPOHeader.Row]["Character01"];
		Supplier = (string)edvPOHeader.dataView[edvPOHeader.Row]["VendorVendorID"];
		CurrentCompany = (string)edvPOHeader.dataView[edvPOHeader.Row]["Company"];
		
		if (Approved == "A")
		{
				// check the supplier has an email address in Purchase Point.
				// grab the email address textbox (this textbox is a customisation) so we can check and get the address if it is there.....
				string PPemailAddress;

				PPemailAddress = epiTextBoxC3.Text;  //Supplier email address is in this Textbox.
				if (PPemailAddress == "")
				{
                    MessageBox.Show("No Email address. Add address to Supplier Purchase Point");
                    return;  // bailout - no email address...
				}

				Erp.Proxy.Rpt.POFormImpl Form = WCFServiceSupport.CreateImpl<Erp.Proxy.Rpt.POFormImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Erp.Contracts.POFormSvcContract>.UriPath);

				// Make the report from the PO data
				Erp.Rpt.POFormDataSet POFormDS;
				POFormDS = Form.GetNewParameters();

				// set the PO number and report style and submit the form to the system agent.
				POFormDS.POFormParam[0].PONum = PONUM;

				switch (CurrentCompany) 
				{
					case "A":
						POFormDS.POFormParam[0].ReportStyleNum = 1002;
						break;
					case "B":
						POFormDS.POFormParam[0].ReportStyleNum = 1003;
						break;
					default:
						POFormDS.POFormParam[0].ReportStyleNum = 1002;
						break;
				}
				
				Guid workstationid = Guid.NewGuid();  // Put a GUID in the workstationId to allow searching for the report later.
				POFormDS.POFormParam[0].WorkstationID = String.Format("{0}",workstationid);			 // Using a GUID as the WorkstationID so it is easy to reteive this report
				POFormDS.POFormParam[0].DateFormat = "dd/MM/yy";
				POFormDS.POFormParam[0].ArchiveCode = 1;

				POFormDS.POFormParam[0].AutoAction = "SSRSGenerate";
				//MessageBox.Show("Submit to System Agent ...");
				Form.SubmitToAgent(POFormDS, "SystemAgent", 0, 0, "Erp.UIRtp.POForm");   //Submit the report to be generate by the system agent.
				

				// get report data. Make a ReportMonitor, use it to get a reportmonitor dataset. The reportmonitor dataset will have the sysrowID of the report
				// we want, we can then use the sysrowID to get the report data to put into the SSRS report.
				Ice.Proxy.BO.ReportMonitorImpl RM = WCFServiceSupport.CreateImpl<Ice.Proxy.BO.ReportMonitorImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.ReportMonitorSvcContract>.UriPath);
		
				int timer=0;
				
				bool morepages;
				SysRptLstListDataSet RptList;
				RptList = RM.GetList(@"WorkStationID ='"+workstationid+"'", 0, 0, out morepages);

				while (RptList.SysRptLstList.Count == 0 ) // setup a loop to look for when the report has been generated.
					{					
					System.Threading.Thread.Sleep(500);
					timer = timer + 1;
					if (timer > 120)
						{
						MessageBox.Show("Attempts to generate a PO pdf has timed-out. Please try again, and if that does not work, contact ERP Support");
						return;
						}
					RptList = RM.GetList(@"WorkStationID ='"+workstationid+"'", 0, 0, out morepages);
					}

				string tableguid;
				tableguid = RptList.SysRptLstList[0].FileName.Replace("REPORT DATABASE: ","");
				

				// make a pdf of the PO from the report
				string FileName = String.Format(@"\\<SERVER>\EpicorData\PO Reports\{0}.pdf", PONUM);
				string reportStyle;
				switch (CurrentCompany)
				{
					case "A":
						reportStyle = "/Reports/CustomReports/POForm  - With Line Notes";
						break;
					case "B":
						reportStyle = "/Reports/CustomReports/POFormB  - With Line Notes";
						break;
					default:
						reportStyle = "/Reports/CustomReports/POForm  - With Line Notes";
						break;
				}
				GenerateReportPDF("http://<SSRS_SERVER>/reportserver_Epicor/ReportExecution2005.asmx",reportStyle,tableguid,FileName);

				// create email message
				try
					{
					//MessageBox.Show("Attaching to email...");
					Outlook.Application oApp = new Outlook.Application();
					Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
					Outlook.Inspector  MsgInspector =  oMsg.GetInspector; 
					string Signature = oMsg.HTMLBody; //capture signature for appending to custom message later.
					oMsg.Subject = PONUM.ToString() + " Purchase Order" ;

					switch (CurrentCompany)
					{
						case "A":
							oMsg.HTMLBody = "Put your default text here in html format" + Signature;
							break;
						case "B":
							oMsg.HTMLBody = "Put your default text here in html format" + Signature;
							break;
						default:
							oMsg.HTMLBody = "Put your default text here in html format" + Signature;
							break;
					}


					// Set up the recipients for the email
					Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
					Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(PPemailAddress);
					oRecip.Resolve();
					// Find the requestors email and add that
					if (Requestor != "")
					{
						Ice.Proxy.BO.UserFileImpl userBO = WCFServiceSupport.CreateImpl<Ice.Proxy.BO.UserFileImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.UserFileSvcContract>.UriPath);
						try
							{
	                		UserFileDataSet user = userBO.GetByID(Requestor);
							oRecip = oRecips.Add(user.UserFile[0].EMailAddress);
	              	  	oRecip.Resolve();
							}
						catch
							{
							MessageBox.Show("Could not add requestors email address to email, user " + Requestor + " not found in Epicor.");
							}					
					}
					
					// Attach pdf of PO, terms, and any other attachments to PO.
					oMsg.Attachments.Add(FileName,Outlook.OlAttachmentType.olByValue, Type.Missing,Type.Missing);
					



						oMsg.Attachments.Add(@"\\<SERVER>\Shared\Purchasing\Purchase Order Terms and Conditions.pdf",Outlook.OlAttachmentType.olByValue, Type.Missing,Type.Missing);
					
					
					var FolderId = Guid.NewGuid().ToString("N").ToUpper();		          
		            var TempPath = Path.Combine(Path.GetTempPath(), FolderId);
		            if (!Directory.Exists(TempPath))
		            {
		                Directory.CreateDirectory(TempPath);
		            }
					foreach (DataRowView row in edvAutoAttachPOHeader.dataView)
	                {
	                    var AttachPath = row["FileName"].ToString();
	                    var AttachFileName = Path.GetFileName(AttachPath);
	                    var AttachNewPath = Path.Combine(TempPath, AttachFileName);
	                    var AttachDesc = row["DrawDesc"].ToString();
	                    File.Copy(AttachPath, AttachNewPath);
	                    if (File.Exists(AttachNewPath))
	                    {
	                        oMsg.Attachments.Add(AttachNewPath, Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing);
	                    }
	                }

					MsgInspector.Activate();   // shows the new email message as topmost window.
					
					//Clean up
					oRecips = null;
					oRecip = null;
					oMsg = null;
					oApp = null;
					
					}
				catch (Exception Ex)
					{
					MessageBox.Show("PO Email was attempted but failed. Please try again. If that doesn't work, please contact ERP Support");
					}
			}
		else
			MessageBox.Show("PO must be approved before it can be sent out");

	}

    private void GenerateReportPDF(String ServerURL, String report, String tableguid, String PDFfilename)
        {
            // setup report variables
            string deviceInfo = null;
            string extension = String.Empty;
            string mimeType = String.Empty;
            string encoding = String.Empty;
            Warning[] warnings = null;
            string[] streamIDs = null;
            string historyId = null;

            // Create a Report Execution object
            Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ReportExecutionService rsExec = new ReportExecutionService();
            
			rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
            rsExec.Url = ServerURL;

            // Load the report
            rsExec.LoadReport(report, historyId);

            // pass parameters
            rsExec.SetExecutionParameters(
            new ParameterValue[] { new ParameterValue() { Name = "TableGuid", Value = tableguid } }, null);

            // get pdf of report
            Byte[] results = rsExec.Render("PDF", deviceInfo,
                out extension, out encoding,
                out mimeType, out warnings, out streamIDs);

            File.WriteAllBytes(PDFfilename, results);

        }

Hope this is useful.

Brett

11 Likes

Thanks @bmanners -
SO MUCH GOOD STUFF IN THAT!!!

And since that uses the office program running on the client to send, this wouldn’t require configuring E10 to be able to send emails. And the email would originate from the sender, not the no-reply@company.com that was setup in company config. Correct?

Yep, no need to setup email in Epicor and it comes from users email account.

I set this up years ago but if remember right I had some issues getting all the permissions right. It has been working well since.

Brett

Hello Brett, You mention that you have had permission issues. What kind of/which issues and how did you solve it?
I am working on a solution for sending an email using Outlook. It seems to work (almost), since I do not get any error messages from Outlook. But somehow the email is not send. My guess is that it keeps waiting somewhere on the epicor/email server.

Regards,
John

John,

Slow response as I have been away on holidays.

Note, that the code I posted creates a new email within the users Outlook application and leaves the new email open on the screen for the user to click send. The code dose not send the email.

We also use the Epicor configured email send email notifications with BPM’s etc. For that I had to get the IT folks to allow emails to be sent from the account setup in company config and to allow emails to be generated from the server.

Brett

Hello @bmanners,

I’m in the process of recreating your code above to send Sales Order Ack, I’ve got the first part of the code compiling, but when I add the last private void to generate the report, I get the following errors

Error: CS0246 - line 892 (3026) - The type or namespace name ‘Warning’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0234 - line 898 (3032) - The type or namespace name ‘WebForms’ does not exist in the namespace ‘Microsoft.Reporting’ (are you missing an assembly reference?)
Error: CS0246 - line 898 (3032) - The type or namespace name ‘ReportExecutionService’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0246 - line 909 (3043) - The type or namespace name ‘ParameterValue’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0246 - line 909 (3043) - The type or namespace name ‘ParameterValue’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0103 - line 916 (3050) - The name ‘File’ does not exist in the current context

I added the 2 dll’s that you mentioned but it doesn’t compile

Lawson,

Just checked my code and there is a using statement that you may need.

using Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution;

Brett

Thank you Brett,

That took away a few errors but now i get this

The type or namespace name ‘WebForms’ does not exist in the namespace ‘Microsoft.Reporting’ (are you missing an assembly reference?)

Righito… I got rid of all the coding errors, now I’m getting an error when it runs, any clues would be much appreciated, in the meantime I’ll keep looking for solutions

Application Error

Exception caught in: System.Web.Services

Error Detail

Message: The underlying connection was closed: An unexpected error occurred on a receive.
Inner Exception Message: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Program: System.Web.Services.dll
Method: GetWebResponse

Client Stack Trace

at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ReportExecutionService.LoadReport(String Report, String HistoryID)
at Script.GenerateReportPDF(String ServerURL, String report, String tableguid, String PDFfilename)
at Script.prepareSOAPDF()
at Script.btnSendSOA_Click(Object sender, EventArgs args)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButtonBase.OnClick(EventArgs e)
at Ice.Lib.Framework.EpiButton.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButton.OnMouseUp(MouseEventArgs e)
at Ice.Lib.Framework.EpiButton.OnMouseUp(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Inner Exception

Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)

Inner Exception

An existing connection was forcibly closed by the remote host

at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)

Glad you sorted out the missing type or namespace WebForms issue. Please explain how you solved that for others that may come by later.

For the current issue that could be the permission issue I mentioned in a previous post. Check the user running the code has permission to access the reporting service. I am not too familiar with SSRS so I am not sure how the security works.

Brett

Brett

1 Like

Brett, how I resolved the coding was
The dll’s that I added were from a different computer so I had to open the file properties and unblock them
I had to add another using “using System.IO;”
I had to do a clear client cache

Regarding the Error above, I added a popup message just before it calls “GenerateReportPDF” and the message displays

I’ve added a message at the end of the “GenerateReportPDF” script and the Error shows before it gets to the final message

I’ve found the spot where it is throwing the error

rsExec.LoadReport(report, historyId);

I’ve checked that is has data there

All users are able to print SSRS reports via the standard buttons