Generate SOA, Print it to PDF file location, Send on Outlook

Hello Team,

I’ve pirated some code from this post and modified it to do Sales Order Ack’s (thanks @bmanners)
The code compiles fine and it works only when I run it on our Epicor Server via Remote Desktop

The code is meant to Generate the SOA, and then Print to PDF with a specific name and save it to a location on the server… and then launch a new email in Outlook with the PDF attached

When I run it on a Users computer, I start getting errors (below) - Can anybody give some clues please??? I believe it is related to security settings but I don’t know where to start with them

The Code:

		private void bntSendSOA_Click(object sender, System.EventArgs args)
		{
			// ** Place Event Handling Code Here **
			prepareSOAPDF();
		}


		private void prepareSOAPDF()
		{

		EpiDataView edvAutoAttachOrderHed = (EpiDataView)(oTrans.EpiDataViews["AutoAttachOrderHed"]);
		EpiDataView edvOrderHed1 = ((EpiDataView)(this.oTrans.EpiDataViews["OrderHed"]));
		DataRow editRow = edvOrderHed1.CurrentDataRow;
		String soNum = editRow["OrderNum"].ToString(); 
		int isoNum = Convert.ToInt32(editRow["OrderNum"]);
	
	

		salesOrderAckAdapter soa = new salesOrderAckAdapter(oTrans);
		soa.BOConnect();
		soa.GetNewParameters();
		soa.ReportData.SalesOrderAckParam[0].OrderNum = isoNum;
		soa.ReportData.SalesOrderAckParam[0].AgentID = "SystemTaskAgent";
		soa.ReportData.SalesOrderAckParam[0].ReportStyleNum = 1001;
	
		Guid workstationid = Guid.NewGuid();
		soa.ReportData.SalesOrderAckParam[0].WorkstationID = String.Format("{0}",workstationid);
		soa.ReportData.SalesOrderAckParam[0].ArchiveCode = 1;
		soa.ReportData.SalesOrderAckParam[0].AutoAction = "SSRSGenerate"; //generate
		soa.SubmitToAgent("SystemTaskAgent",0,0);
		//MessageBox.Show("Print Job Has been submitted.");
	
	
		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(1000);
			timer = timer + 1;
			if (timer > 120)
				{
				MessageBox.Show("Attempts to generate a SOA 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\SOAReports\{0}.pdf", soNum);
		string FileName = String.Format(@"//SERVER/EpicorData/SOAReports/{0}.pdf", soNum);


		GenerateReportPDF(tableguid,FileName);

	
		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 =  "TWG Sales Order Acknowledgement " + soNum ;
			
			Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
			Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add("test@test.com.au");
			oRecip.Resolve();	
				
			oMsg.Attachments.Add(FileName,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 edvAutoAttachOrderHed.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.	

			}
		catch (Exception Ex)
			{
			MessageBox.Show("SOA Email was attempted but failed. Please try again. If that doesn't work, please contact ERP Support");
			}	
		}
	


		private void GenerateReportPDF(String tableguid, String PDFfilename)
        {
			
			// Render arguments  
      	  byte[] result = null;  
			string report = "/reports/CustomReports/SalesOrderAcknowledgement/SOForm_LIVE";
      	  string format = "PDF";  
			
            // 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;
		
			ParameterValue[] parameters = new ParameterValue[1];
     	   parameters[0] = new ParameterValue();  
     	   parameters[0].Name = "TableGuid";  
    	    parameters[0].Value = tableguid; 		
			
            // Create a Report Execution object
            Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ReportExecutionService rsExec = new ReportExecutionService();
        
			rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
					
            rsExec.Url = "http://SERVER/ReportServer/ReportExecution2005.asmx"; //ServerURL;
		MessageBox.Show("Url ");	///<<< This message always shows
            // Load the report
            rsExec.LoadReport(report,  historyId);
		MessageBox.Show("LoadReport");  ///<<< This message sometimes shows

            // pass parameters
            rsExec.SetExecutionParameters(parameters, null);
		MessageBox.Show("SetExecutionParameters");   ///<<< This message never shows
            // get pdf of report
            result = rsExec.Render(format, deviceInfo, out extension, out mimeType, out encoding, out warnings, out streamIDs);
			
		MessageBox.Show("result"); ///<<< This message never shows
            File.WriteAllBytes(PDFfilename, result); 
		MessageBox.Show("WriteAllBytes");  ///<<< This message never shows
        }

When I run it on a users computer it gets partway through the execution and then throws the following errors

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 tableguid, String PDFfilename)
   at Script.prepareSOAPDF()
   at Script.bntSendSOA_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)

And sometimes this error

Application Error

Exception caught in: System.Web.Services

Error Detail 
============
Message: The request was aborted: The request was canceled.
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.SetExecutionParameters(ParameterValue[] Parameters, String ParameterLanguage)
   at Script.GenerateReportPDF(String tableguid, String PDFfilename)
   at Script.prepareSOAPDF()
   at Script.bntSendSOA_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)

Lawson,

Not sure if this is the issue but might be worth checking. In our SSRS setup we have the user which runs the Epicor App Pool enabled to run reports.

To check…

  • open the SQL Reporting Services Configuration manager on the SQL server and get the URL for the Report Manager
  • open the report manager in IE. If I remember right chrome doesn’t work.
  • click on the reports folder and select security
  • Check to see if the Epicor App Pool user has access.

Brett

Thanks Brett,
The problem I’ve got is, the people that set out Epicor up originally, the user that they created for the App Pools isn’t a Windows user,

When I go to put that user name into the security settings it says “The user or group name ‘print’ is not recognized.”

@bmanners , I’ve added the user to the domain and added it to where you mention above, I’ve also added a domain group to the Report Services that include all of our Epicor users… still no go :frowning:

First off, when running on the client computer, is the PDF actually generated? Does it work if you only try to generate the PDF, and not the Outlook part?

If the PDF is created, does the client computer have access to the location where it resides?

Hello @ckrusen, thanks for chipping in,

On the client computer

It does the SSRSGenerate part, I can see it in the system monitor, that part generates the data for the making of the PDF, when it goes to create the PDF it gets to around this part of the code and errors out

     rsExec.Url = "http://SERVER/ReportServer/ReportExecution2005.asmx"; 
		MessageBox.Show("Url ");	///<<< This message always shows

            // Load the report
            rsExec.LoadReport(report,  historyId);
		MessageBox.Show("LoadReport");  ///<<< This message sometimes shows

            // pass parameters
            rsExec.SetExecutionParameters(parameters, null);
		MessageBox.Show("SetExecutionParameters");   ///<<< This message never shows

If I run the full code on the server first it creates the SOA pdf

If I then run the code on the client computer with the above part of the code commented out, it will run right through and pick up the pdf previously created by the server run and attach it to the Email in Outlook

So from that, it looks like the file paths are accessible from the client computer (I set the permissions before I started) (I also checked in Windows Explorer)

Also the server url http://SERVER/ReportServer/ReportExecution2005.asmx is accessible from the client computer

Whats your architecture?

Separate or combined servers for SQL server, SSRS server, Epicor App Server? On Prem or cloud hosted? Is the client running on the users machines or are you using a Citrix / terminal server setup?

Brett

Good morning Brett,

The SQL server, SSRS server, Epicor App Server are all on the same server, hosted locally (On Prem)

The clients are running on the users machines

Regards Lawson

That’s a simple setup. I expect the code will be running as the local user so I guess we want to check if the local user has access.

Can you run the report through the report manager URL? To do this I run the report in Epicor (set archive period to a week) then grab the GUID from the task monitor and paste that into SSRS. I can explain in more detail if you are not familiar with this trick.

Can you output the defaultCredentials that the system is pulling to a message box just to check?

It is also possible to hard code in the username and password (I had that for a while). I don’t have the exact syntax handy but it is possible. You could hard code in your credentials as a test.

last thing I notice we also have “everyone” with the browse role in SSRS on the base folder. You said you added a domain group with the Epicor users in it so I expect that should be enough…

The pdf report / email code has been working on our system since 9.05 days, we are on 10.2.400 now. We have separate servers for SQL and Epicor but other than that the same as you. We just need to find the “magic checkbox” to let code run :slight_smile:

Brett

Brett,

I’ve tried this and it works fine

I’ve just tried this - same error

Window security doesn’t let you see this info

There must be some weird obscure security setting somewhere… the annoying thing is it works on the server but not on clients

I wonder if there are any hints in the eventview on the client or server, or the SQL logs?

We have 2 other servers in the office, I’ve just tried the code on them and it works on them, but not on the client computers… I’ll have to get the IT chaps to have a look at the group policy or server setup

Anyone got any thoughts??

Finally got it working… I made a couple of small changes to the GPO and it started working

2 Likes

Fantastic! do share what the secret trick was?

I made a couple of changes but I think the one that did it was “Allow local port exceptions”

image

I’ll try and do a full write up for anyone else that wants the code, and I’m very thankful that you shared it first

Final working code

// You will need the following Custom Assembly References

// Erp.Contracts.Rpt.SalesOrderAck
// Erp.UIRpt.SalesOrderAck
// Ice.Contracts.BO.ReportMonitor
// Microsoft.Office.Inerop.Outlook   <<<<this can be tricky to locate, when you find it, deploy it you epicor client folder, I found it here:-  C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.Outlook
// Microsft.ReportViewer.Common
// Microsft.ReportViewer.WebForms
// Microsft.ReportViewer.WinForms

//Add these using's

using Outlook = Microsoft.Office.Interop.Outlook;
using Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution;
using System.Windows.Forms;
using System.IO;


//Add this to the script
public class Script

{
	private Erp.UI.Controls.Combos.cboCustCnt soldToName; 
	private Erp.UI.Controls.Combos.cboCustCnt shipToName;
}

//Add this to InitializeCustomCode
public void InitializeCustomCode()

{
	
	soldToName = (Erp.UI.Controls.Combos.cboCustCnt)csm.GetNativeControlReference("0bd70f62-56fa-4a05-b15f-ea3cbdd18f43");
	shipToName = (Erp.UI.Controls.Combos.cboCustCnt)csm.GetNativeControlReference("50a5e4e4-46cd-4397-a600-5fb8ac57e16f");	
}

//Add this to DestroyCustomCode
public void DestroyCustomCode()
{
	
		soldToName = null;
		shipToName = null;
}		

////Prepare SOA/////////////////////////////////////////////\\\\\\\\\\\//////
		private void prepareSOAPDF()
		{
		EpiDataView orderDtl = ((EpiDataView)(this.oTrans.EpiDataViews["OrderDtl"]));
		int lineCount = orderDtl.dataView.Count;
		EpiDataView edvOrderHed1 = ((EpiDataView)(this.oTrans.EpiDataViews["OrderHed"]));
		DataRow editRow = edvOrderHed1.CurrentDataRow;
			
		int soNum = Convert.ToInt32(editRow["OrderNum"]);
		
			//Get the customers info - code could be cleaned up
			String name1 = "";
			String name2 = "";
			String toName = "";
			String email1 = "";
			if(editRow["SoldToContactEMailAddress"].ToString() != "")
			{
			 email1 = editRow["SoldToContactEMailAddress"].ToString() + "; ";
			}
			
			String email2 = "";
			
			if(editRow["ShipToContactEMailAddress"].ToString() != editRow["SoldToContactEMailAddress"].ToString())
			{
			if(editRow["ShipToContactEMailAddress"].ToString() != "")
			{
			 email1 = editRow["ShipToContactEMailAddress"].ToString() + "; "; 
			}
			}
			
			if(Convert.ToInt32(soldToName.Value.ToString()) >0)
			{
			  name1 = soldToName.Text.ToString().Split(' ')[0];
			}
			if(Convert.ToInt32(shipToName.Value.ToString()) >0)
			{
			  name2 = shipToName.Text.ToString().Split(' ')[0];
			}			
			
			if(name1 == name2)
			{
				toName = name1;
			}
			else if(name2 != "" && name1 != "" )
			{
				toName = name1 + " and " + name2;
			}
			else if (name1 == "")
			{
				toName = name2;
				
			}
			

		salesOrderAckAdapter soa = new salesOrderAckAdapter(oTrans);
		soa.BOConnect();
		soa.GetNewParameters();
		soa.ReportData.SalesOrderAckParam[0].OrderNum = soNum;
		soa.ReportData.SalesOrderAckParam[0].AgentID = "SystemTaskAgent";
		soa.ReportData.SalesOrderAckParam[0].ReportStyleNum = 1001; //Change to suit your requirements 
	
		Guid workstationid = Guid.NewGuid();
		soa.ReportData.SalesOrderAckParam[0].WorkstationID = String.Format("{0}",workstationid);
		soa.ReportData.SalesOrderAckParam[0].ArchiveCode = 1;
		soa.ReportData.SalesOrderAckParam[0].AutoAction = "SSRSGenerate"; //generate
		soa.SubmitToAgent("SystemTaskAgent",0,0);
		MessageBox.Show("Print Job Has been submitted - This will take approx. 10 seconds.");
	
		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(1000 * lineCount);
			timer = timer + 1;
			if (timer > 100 * lineCount)
				{
				MessageBox.Show("Attempts to generate a SOA 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\PrintReports\Sales_Order_Acknowledgement_{0}.pdf", soNum); // use this path to save to SERVER
			string FileName = String.Format(@"C:\EpicorData\PrintReports\Sales_Order_Acknowledgement_{0}.pdf", soNum); // use this path to save to LOCAL

		GenerateReportPDF(tableguid,FileName);
		
		//The Email part - Comment out below to not do the email part
		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 =  "TWG Sales Order Acknowledgement " + soNum ;
			oMsg.HTMLBody = "<p>Hello " + toName + "<br><br>Please see attached Sales Order Acknowledgement for your approval<br><br>Please check that the Bill To and Ship To details are correct</p>" + Signature;
			
			Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
			Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(email1 + email2);
			oRecip.Resolve();	
				
			oMsg.Attachments.Add(FileName,Outlook.OlAttachmentType.olByValue, Type.Missing,Type.Missing);	
					
			MsgInspector.Activate();   // shows the new email message as topmost window.	

			}
		catch (Exception Ex)
			{
			MessageBox.Show("SOA Email was attempted but failed. Please try again. If that doesn't work, please contact ERP Support");
			}	
			
		//End of Email part	
		}
	
	private void GenerateReportPDF(String tableguid, String PDFfilename)
        {
		 // Create a Report Execution object
            Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ReportExecutionService rsExec = new ReportExecutionService();
			rsExec.Url = "http://SERVER:80/ReportServer/ReportExecution2005.asmx"; //ServerURL Change to suit
			rsExec.PreAuthenticate = true;
			rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
		// Render arguments  
      	  byte[] result = null;  
			string report = "/reports/CustomReports/SalesOrderAcknowledgement/SOForm_LIVE"; // Change to suit
      	  string format = "PDF";  
			string historyId = null;
			string deviceInfo = null;
		// Prepare report parametes
			ParameterValue[] parameters = new ParameterValue[1];
     	   parameters[0] = new ParameterValue();  
     	   parameters[0].Name = "TableGuid";  
    	    parameters[0].Value = tableguid;			 
            string extension;
            string mimeType;
            string encoding;
            Warning[] warnings = null;
            string[] streamIDs = null;	
         // Load the report
            rsExec.LoadReport(report,  historyId);
         // pass parameters
            rsExec.SetExecutionParameters(parameters, null);
         // get pdf of report
            result = rsExec.Render(format, deviceInfo, out extension, out mimeType, out encoding, out warnings, out streamIDs);
			
            File.WriteAllBytes(PDFfilename, result); 
			
        }
////END Prepare SOA/////////////////////\\\\\\\\\\\\\\\\////\\\\\\\\//////	
4 Likes

Hi @LBARKER @bmanners

I am getting errors in the below line.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem)

image

Dear All,

It’s working. if we do the below steps working.,