BPM Automated Email with Quote PDF attached

I am needing to have an automated email be sent when a quote is created. The email needs to be sent with a quote pdf attached. The “To” would be sent to the customer email and the “From” needs to be set to the employee creating the quote. I wondering what the best way to perform this bpm would be.

This sounds like a good candidate for SSRS Breaking/Routing rules setup on your report style. The user would still need to “Print” the quote but in doing so it would sent the email to the customer with the quote attached as a PDF.

I have a report that gets emailed when Purchase Orders are pending. Using a BPM with the auto print object (though setup to email). I use a standard data-directive on the POHeader.

The PO is passed as a report parameter

image

It looks like you can specify “QuotForm” with auto print and pass the report the “QuoteNum”

1 Like

Hello @Tripb44

It depends on how fancy you want it to look, the suggestions above are good and easy to do, however, my team didn’t like the vanilla looking emails so I pieced together the below (This is for sending ProForma Invoices from the Order Entry UI - It can be adapted to send Quotes from the Quote Entry UI)

This part is the UI customization


//Customization to send ProForma Invoices from UI  + BPM

// UI customization

		private void btnEmailPI_Click(object sender, System.EventArgs args)
		{
			preparePIPDF("E");
		}
		private void btnPIFolder_Click(object sender, System.EventArgs args)
		{
			preparePIPDF("F");
		}



		private void preparePIPDF(string emailorfolder)
		{
		EpiDataView orderDtl = ((EpiDataView)(this.oTrans.EpiDataViews["OrderDtl"]));
		int lineCount = orderDtl.dataView.Count;
		EpiDataView edvOrderHed1 = ((EpiDataView)(this.oTrans.EpiDataViews["OrderHed"]));
		DataRow editRow = edvOrderHed1.CurrentDataRow;
		Ice.Core.Session userSess = (Ice.Core.Session)SalesOrderForm.Session;
		string userID = userSess.UserID;	
		int soNum = Convert.ToInt32(editRow["OrderNum"]);
		string custName = editRow["CustomerName"].ToString();
		string timeNow = DateTime.Now.ToString("- dd MMM yyy - hhmm tt");
		string mainFolder = String.Format (@"\\StorageServer\3 Sales\SPO2 AO\{0} - {1}\02 Cust PO, Accepted SP, SOA + PI",soNum,custName);
		System.IO.Directory.CreateDirectory(mainFolder);
				
			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;
				
			}

		ProFormaInvcAdapter ppi = new ProFormaInvcAdapter(oTrans);
		ppi.BOConnect();
		ppi.GetNewParameters();
		ppi.ReportData.ProFormaInvcParam[0].OrderNum = soNum;
		ppi.ReportData.ProFormaInvcParam[0].AgentID = "SystemTaskAgent";
		ppi.ReportData.ProFormaInvcParam[0].ReportStyleNum = 1001;
	
		Guid workstationid = Guid.NewGuid();
		ppi.ReportData.ProFormaInvcParam[0].WorkstationID = String.Format("{0}",workstationid);
		ppi.ReportData.ProFormaInvcParam[0].ArchiveCode = 1;
		ppi.ReportData.ProFormaInvcParam[0].AutoAction = "SSRSGenerate"; //generate
		ppi.SubmitToAgent("SystemTaskAgent",0,0);
	//	MessageBox.Show("Print Job Has been submitted - This will take approx. 20 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 PI pdf has timed-out. Please try again, and if that does not work, contact ERP Support " + timer);
				return;
				}
			RptList = RM.GetList(@"WorkStationID ='"+workstationid+"'", 0, 0, out morepages);
			}

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

		string FileName = String.Format(@"\\StorageServer\3 Sales\SPO2 AO\{0} - {1}\02 Cust PO, Accepted SP, SOA + PI\TWG_Tax_Invoice_{0}_{1} {2}.pdf", soNum,custName,timeNow);
		string filePath = String.Format(@"\\StorageServer\3 Sales\SPO2 AO\{0} - {1}\02 Cust PO, Accepted SP, SOA + PI\~TWG_Tax_Invoice_{0}_{1} {2}.pdf~{3}", soNum,custName,timeNow,userID);
	

		GeneratePIPDF(tableguid,FileName);
			
		try
			{
			if(emailorfolder == "E")
				{

				Process.Start(FileName);
				
				editRow.BeginEdit();
				editRow["PIFileRef_c"] = filePath;
	
				editRow["IsProFormaSent_c"] = true;
				editRow.EndEdit();
				this.oTrans.SetCurrentEvent(TransactionEvent.None);
				this.oTrans.Update();
				MessageBox.Show("The email has been sent, please check you inbox to see if it bounced", "Important!!!!", MessageBoxButtons.OK, MessageBoxIcon.Warning);	
					
					
				}
				if(emailorfolder == "F")
				{
					
					MessageBox.Show("Please drag the Email that you send to the Customer into the SP02 folder", "Important!!!!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
					Process.Start(mainFolder);
					Process.Start(FileName);
				}
	

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


		private void GeneratePIPDF(String tableguid, String PDFfilename)
        {
			
            Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ReportExecutionService rsExec = new ReportExecutionService();
			rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
			rsExec.PreAuthenticate = true;
			rsExec.Url = "http://EpiServer/ReportServer/ReportExecution2005.asmx"; //ServerURL;
			
			

		// Render arguments  
      	  byte[] result = null;  
			string report = "/reports/CustomReports/ProFormaInvc/ProFormaInvc_LIVE";
      	  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); 

        }	

This is the BPM

and the custom code

// The BPM part		
// Standard Data Directive BPM		 


var order = ttOrderHed.Where(p => p.Company == Session.CompanyID && p["PIFileRef_c"].ToString() != "").FirstOrDefault();
if(order != null)
{

var pdf = order["PIFileRef_c"].ToString();

var fileName = order["PIFileRef_c"].ToString().Split('~')[1];
var filePath = order["PIFileRef_c"].ToString().Split('~')[0] + fileName;
var userID = order["PIFileRef_c"].ToString().Split('~')[2];

//var folder = order["SO02Folder_c"].ToString();
var didntSend ="";
int btNum = order.BTCustNum;
int stCustNum = order.CustNum;
var stNum = order.ShipToNum;
var terms = order.TermsCode;
var prepaidnote = "";

if(terms.ToLower().Contains("pre"))
{
prepaidnote = "Your trading terms are \"PrePaid\", this means this invoice will need to be paid before the order can be fulfilled<br><br>";
}
var cust = Db.Customer.Where(x => x.Company == Session.CompanyID && x.CustNum == btNum).Select(x => x.Name).FirstOrDefault();
var btName = cust;
var btCntName = "";
int soNum = order.OrderNum;
var poNum = order.PONum;
int ShpConNum = order.ShpConNum;
int prcConNum = order.PrcConNum;

var stName = "";
var stemail = "";
//var btName = "";
var btemail = "";
//var sendTo = "";
var ordEntPer = userID; //order.EntryPerson;
var sendCC = ordEntPer + "@testco.com.au; ";
var ordEnter = ordEntPer.Split('.')[0].ToUpper() + " " + ordEntPer.Split('.')[1].ToUpper();
var ordEnterInt = (ordEntPer.Split('.')[0].Substring(0, 3) + ordEntPer.Split('.')[1].Substring(0, 1)).ToUpper();



if(ShpConNum > 0)
{
var sTcustConN = Db.CustCnt.Where(x => x.Company == Session.CompanyID && x.CustNum == stCustNum && x.ShipToNum == stNum && x.ConNum == ShpConNum).Select(x => new {x.FirstName, x.EMailAddress}).FirstOrDefault();
if(sTcustConN != null)
{
stName = sTcustConN.FirstName ?? "";
stemail = sTcustConN.EMailAddress ?? "";
}
}

if(stNum == "")
{
var sTcustConN = Db.CustCnt.Where(x => x.Company == Session.CompanyID && x.CustNum == stCustNum && x.ShipToNum == "" && x.ConNum == ShpConNum).Select(x => new {x.FirstName, x.EMailAddress}).FirstOrDefault();
if(sTcustConN != null)
{
stName = sTcustConN.FirstName ?? "";
stemail = sTcustConN.EMailAddress ?? "";
}
}




if(prcConNum > 0)
{
var bTcustConN = Db.CustCnt.Where(x => x.Company == Session.CompanyID && x.CustNum == btNum && x.ShipToNum == "" && x.ConNum == prcConNum).Select(x => new {x.FirstName, x.EMailAddress}).FirstOrDefault();
if(bTcustConN != null)
{
btCntName = bTcustConN.FirstName ?? "";
btemail = bTcustConN.EMailAddress ?? "";
}
}
var sendTo = "";
var sendName = "";
if(stemail != "" && btemail != "") //both
{
sendTo = stemail + "; " + btemail;
sendName = stName + " and " + btCntName;
}
if(stemail == "" && btemail != "") //bt only
{
sendTo = btemail;
sendName = btCntName;
}
if(stemail != "" && btemail == "") //st only
{
sendTo = stemail;
sendName = stName;
}
if(stemail == btemail)  // ===
{
sendTo = stemail;
sendName = stName;
}
if(stemail == "" && btemail == "")  // none
{
sendTo = ordEntPer + "@testco.com.au";
sendName = "<b>This has not been sent to the customer, there was no email address</b>";
order["IsProFormaSent_c"] = false;
}
 
     
    var eSubject = "Treadwell Group Invoice";
    var eBody = "<html><body><p>" + didntSend +"<b>" + btName + "<br>Sales Order Number: " + soNum + "<br>Your PO Number: " + poNum + "</b><BR><BR>Hello " + sendName + ",<BR><BR>Please see attached invoice for payment.<BR><BR>" + prepaidnote + "In order to ensure a seamless delivery experience, please take the time to check the details listed on the invoice; If no changes are made, this will be taken as confirmation of the details.<br><br>Kind regards,<br><br><b style=\"color:red;\">" + ordEnter + "</b> | Customer Service<br>P  1800 246 800<br>E " + ordEntPer + "@testco.com.au<BR><BR><a href=\"https://www.testco.com.au\"><img src=\"https://testco.com.au/epi/banner.png\" alt=\"Treadwell Logo\"></a><br></p></body></html>";
 
/* if(userID.ToLower().Contains("lawson")) // for testing // comment out for LIVE
 { 
 sendTo = "lrb@testco.com.au";
 sendCC = "lrb@testco.com.au";
 }  */
 
 
 
 
    var mailer = this.GetMailer(async: true);
    var  message = new Ice.Mail.SmtpMail();
   // message2.SetFrom(fromAddress);
    message.SetFrom("Sales Support | Treadwell Group<do-not-reply@testco.com.au>");
    message.SetTo(sendTo);
    message.Priority = System.Net.Mail.MailPriority.High;
    message.SetCC(sendCC);
    message.SetBcc("lrb@testco.com.au; ");
    message.SetReplyTo(sendCC);
    message.SetSubject(eSubject);
    message.SetBody(eBody);
    Dictionary<string, string> attachments = new Dictionary<string, string>();
     //attachments.Add(pdf, folder + pdf);
     attachments.Add(fileName, filePath);
     mailer.Send(message, attachments);
     
     order.SetUDField<System.String>("PIFileRef_c","");
     }

And what it looks like

4 Likes

@LBARKER this is an excellent solution! Mine is for internal emails so the appearance isn’t really a factor. I will bookmark this to reference if I ever need to send customer facing emails. Thanks for sharing.

I can supply the code for generating the quote PDF if you need it, I haven’t done the email part on the quotes yet though

The coding was mostly pirated from this site…

I’ve adapted the code above to send PO’s to suppliers and to send Sales Order Ack’s as well

Thank you for the code sample.

I’m trying to replicate some of what you’ve done here, but I had a tiny problem come up, this error below:

Error: CS0234 - line 29 (29) - The type or namespace name ‘Reporting’ does not exist in the namespace ‘Microsoft’ (are you missing an assembly reference?)

this error came up when I tried to add this assembly reference

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

have you faced that problem before? if so, how did you solve it?

thanks in advance.

You will need to add some dll’s to your client folder and reference them
More detail in this post

Thanks man, the problem is fixed. :+1:t3: :+1:t3:

Hi,

@LBARKER @aamerabuarja @asalvatore @Adam_Jones @Tripb44

Any idea BPM itself needs to Save to folder and send the Email.,