BPM Method on SSRS Email (print) a Sales Order?

This is BPM so you should use TableSets not DataSets look at my Example

Also your GetService should be

GetService<Erp.Contracts.SalesOrderAckSvcContract>(Db)

Thanks for the correction. Guess I pulled too much out of the tracelog as I got both from the trace. Still missing something, I think it’s a reference but I’ve added the ones I think it’d need, am I missing some?

System.Drawing.Bitmap CS0246 The type or namespace name ‘SalesOrderAckTableSet’ could not be found (are you missing a using directive or an assembly reference?)

System.Drawing.Bitmap CS0246 The type or namespace name ‘SOFormParamRow’ could not be found (are you missing a using directive or an assembly reference?)

image

Hi Randy,

Can you share the code for this? I’d like to see if I can get it going on my side as well.

I attacked a similar idea in a different way. We purchased “SSRS Advanced Routing/Breaking” module recently so I’m using that to generate the print. So my BPM checks for the correct conditions on when to fire and then i’m using the “Auto Print” widget to send the print job over to SSRS Routing/Breaking.

If I generate a print from the BPM “Custom Code”, then I may not need to use the “Auto Print” widget to hand the print over to SSRS Routing/Breaking to generate the document. It may save a step. However, if I stick with the current method, I wouldn’t need to write any custom code! Decisions! :slight_smile:

Ideally, I want to print a BAQReport from the custom code but I’m not very well versed in C# so that will have to happen another time!

Thanks,
Josh

You’ll need to add the right using statement

using Erp.Tablesets;

And it should be SalesOrderAckParamRow

1 Like

Hmm, still getting errors.

Looks like it may be a UI customization that a BPM can’t do according to a EUG forum post.

“UI Customisation, not possible in a BPM…”

https://www.epicorusers.org/communities/community-home/digestviewer/viewthread?MessageKey=12c3ed1e-1cb7-4cac-8430-a687648662b3&CommunityKey=df2aacd6-d4fd-42fc-850f-eea2bb5eef97&tab=digestviewer

For the most part it’s a copy of Jose’s example and you may have more luck as you have the extra module.

I put this as a data directive, for some reason it works there.

Make sure the Assemblies has Erp.Contracts.Rpt.SalesOrderAck

Here is the code:

var reportParamTS = new Erp.Tablesets.SalesOrderAckTableset();
var reportParamRow = new Erp.Tablesets.SalesOrderAckParamRow();
reportParamTS.SalesOrderAckParam.Add(reportParamRow);

int rowIndex = 0;


var primaryTableRow = ttOrderHed.Where(tt=>tt.Updated()).FirstOrDefault();
	
if(primaryTableRow != null)
{
	reportParamRow.OrderNum = primaryTableRow.OrderNum;
	reportParamRow.ArchiveCode = Convert.ToInt32("0");
	reportParamRow.PrintReportParameters = Convert.ToBoolean("False");
	reportParamRow.SSRSEnableRouting = Convert.ToBoolean("False");
	
	reportParamRow.AutoAction =  "SSRSPrint" ;
	reportParamRow.ReportStyleNum = 2 ;
	reportParamRow.WorkstationID = "MYWorkStation";
	reportParamRow.TaskNote = "";
	
	if (reportParamTS.SalesOrderAckParam.Columns.Contains("EmailTo"))
	{
		reportParamRow.FaxTo = "";
		reportParamRow.FaxNumber = "";
	reportParamRow.FaxSubject = "The order " + primaryTableRow.OrderNum + " has been created from PO: " + primaryTableRow.PONum;
		reportParamRow.EMailTo = "testemail@yyy.net";
		reportParamRow.EMailCC = "";
		reportParamRow.EMailBCC = "";
		reportParamRow.EMailBody = "Please see the attached sales acknowledgement for order " + primaryTableRow.OrderNum + " which was created from PO: " + primaryTableRow.PONum;
		reportParamRow.AttachmentType = "PDF";
	}
	
	// Run immediately
	try
	{
	reportParamRow.AgentID = ""; /* Clear the Agent fields when running direct */
	reportParamRow.AgentSchedNum = 0;
	reportParamRow.AgentTaskNum = 0;

	// Using this method will not block the thread
	object[] outParam = null;
	Ice.Hosting.ServiceCaller.Execute("Erp:Rpt:SalesOrderAck", "WriteSysTask", new System.Collections.Specialized.NameValueCollection(), new object[]{reportParamRow}, out outParam);
	int sysTaskNum = Convert.ToInt32(outParam[0]);

	// Decrypt the password
	var password = Epicor.Security.Cryptography.Encryptor.DecryptToString(  "Your Encrypted Password"  );	

	// Create the TaskLauncher instance.
	var taskLauncher = new Ice.Hosting.TaskLauncher();
	System.Threading.Tasks.Task launchingTask = new System.Threading.Tasks.Task(() => {taskLauncher.CallTask( "manager" , password, sysTaskNum);});
	launchingTask.Start();


	}
	catch (Exception ex)
	{
	
	}
	rowIndex++;	
        	
 }
2 Likes

Ah ha! I wasn’t declaring the variables! I did mention I’m not a coder, right? Which is why I knew it was something stupid and easy I was missing.

Looking over your code I can tell there is much more I was missing, like converting the data types (Boolean, etc) and everything from your “Run immediately” line.

I wish I could give more than one Solution checkbox both you and Jose deserve one!

Code doesn’t error and the BPM fires, but no emails so I guess we do need the “SSRS Advanced Routing/Breaking” module.

You do not need that for this can you post all your code?

Jos? C Gomez
Senior Software Engineer

This is bpm code not a customization and it does work on bpm.
Post your code

Jos? C Gomez
Senior Software Engineer

I appreciate the help guys I feel bad for not getting this going myself. The code is pretty much a copy/paste of Ken’s. I’ve verified the report style ID, Epi User/Pass (I’m using a “system agent” one we have not “manager”.

var reportParamTS = new Erp.Tablesets.SalesOrderAckTableset();
var reportParamRow = new Erp.Tablesets.SalesOrderAckParamRow();
reportParamTS.SalesOrderAckParam.Add(reportParamRow);

int rowIndex = 0;

var primaryTableRow = ttOrderHed.Where(tt=>tt.Updated()).FirstOrDefault();
    
if(primaryTableRow != null)
{
    reportParamRow.OrderNum = primaryTableRow.OrderNum; 
    reportParamRow.ArchiveCode = Convert.ToInt32("0");
    reportParamRow.PrintReportParameters = Convert.ToBoolean("False");
    reportParamRow.SSRSEnableRouting = Convert.ToBoolean("False");  
    reportParamRow.AutoAction =  "SSRSPrint" ;
    reportParamRow.ReportStyleNum = 1002 ;   // Our StyleID 
    reportParamRow.WorkstationID = "MYWorkStation";
    reportParamRow.TaskNote = "SO_Ack";
    
//    if (reportParamTS.SalesOrderAckParam.Columns.Contains("EmailTo"))
//    {
        reportParamRow.FaxTo = "";
        reportParamRow.FaxNumber = "";
        reportParamRow.FaxSubject = "The order " + primaryTableRow.OrderNum + " has been created from PO: " + primaryTableRow.PONum;
        reportParamRow.EMailTo = CustEmail;  // BPM variable 
        reportParamRow.EMailCC = "";
        reportParamRow.EMailBCC = "";
        reportParamRow.EMailBody = "Please see the attached sales acknowledgement for order " + primaryTableRow.OrderNum + " which was created from PO: " + primaryTableRow.PONum;
        reportParamRow.AttachmentType = "PDF";
        reportParamRow.RowMod = "A";
        reportParamRow.SSRSRenderFormat = "PDF";
//    }
    
    // Run immediately
    try
    {
    reportParamRow.AgentID = ""; /* Clear the Agent fields when running direct */
    reportParamRow.AgentSchedNum = 0;
    reportParamRow.AgentTaskNum = 0;

    // Using this method will not block the thread
    object[] outParam = null;
    Ice.Hosting.ServiceCaller.Execute("Erp:Rpt:SalesOrderAck", "WriteSysTask", new System.Collections.Specialized.NameValueCollection(), new object[]{reportParamRow}, out outParam);
    int sysTaskNum = Convert.ToInt32(outParam[0]);

    // Decrypt the password
    var password = Epicor.Security.Cryptography.Encryptor.DecryptToString( "ThePaswordHere" );    

    // Create the TaskLauncher instance.
    var taskLauncher = new Ice.Hosting.TaskLauncher();
    System.Threading.Tasks.Task launchingTask = new System.Threading.Tasks.Task(() => {taskLauncher.CallTask( "EpiUserNameHere" , password, sysTaskNum);});   
    launchingTask.Start();
    }
    catch (Exception ex)
    {  
    }
    rowIndex++;              
 }

I’m having my own issues with the Advanced Routing/Breaking so don’t feel bad.

Thank you for posting and also thanks to those who are helping to get this going. You are helping us both out by adding to this.

My code is for a Data Directive. not the Method directive.

There might be a few differences running from the server vs. client.

Does your code work if you hard code an email. Just to make sure that is working? Are there tasks in the system monitor? Are there errors there?

Hi Ken, I have it as a Data Directive on OrderHed In-Transaction, with our
EDI855 BPM.

No task is being submitted in the System Monitor, but I’ll try a hard-coded
Email address as I haven’t tried that yet.

Update: hard-coded email addresss didn’t work. :frowning:

Do you know your workstation id?
The ReportStyleNum might need to be tweaked as well.
last the manager password will need to be adjusted as well.

Randy,

Here is the code for a BPM. I went back to the path Jose started us on, vs showing you the data directive.

BPM Execute Custom Code. Code, Using, Reference following: Hard coded for order and email, make sure that works in a stand alone BPM. Then add your order loop.

Code:

var soForm = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.SalesOrderAckSvcContract>(Db);
SalesOrderAckTableset soTS = soForm.GetNewParameters();
SalesOrderAckParamRow r = soTS.SalesOrderAckParam[0];

r.OrderNum = 18738;
r.SysRowID = Guid.Parse("00000000-0000-0000-0000-000000000000");
r.AutoAction = "SSRSPrint";
r.AgentSchedNum = 0;
r.AgentID = "SystemTaskAgent";
r.AgentTaskNum = 0;
r.RecurringTask = false;
r.RptPageSettings = "";
r.RptPrinterSettings = "";
r.RptVersion = "";
r.ReportStyleNum = 2;
r.WorkstationID = "";
r.TaskNote = "";
r.ArchiveCode = 0;
r.DateFormat = "m/d/yyyy";
r.NumericFormat = ",.";
r.AgentCompareString = "";
r.ProcessID = "";
r.ProcessTaskNum = 0;
r.DecimalsGeneral = 0;
r.DecimalsCost = 0;
r.DecimalsPrice = 0;
r.GlbDecimalsGeneral = 0;
r.GlbDecimalsCost = 0;
r.GlbDecimalsPrice = 0;
r.FaxSubject = string.Format("Order: {0} The Sales Ack has been sent to you enjoy reading", 18738); ;
r.FaxTo = "";
r.FaxNumber = "";
r.EMailTo = "email@email.com";
r.EMailBody = "";

r.AttachmentType = "PDF";
r.ReportCurrencyCode = "USD";
r.ReportCultureCode = "en-US";
r.SSRSRenderFormat = "PDF";
r.RowMod = "A";
soForm.RunDirect(soTS);

Using: using Erp.Tablesets;

References Erp.ContractsRptSalesOrderAck

10 Likes

OMG thanks so much @josecgomez and @knash, that code worked.

Ken, I think your first code wasn’t working for me as I always had it in a Data Directive “Execute Custom Code” BPM action-node (or whatever the term is), so --sounds like to this layman-- I had it in the wrong type of node. Plus the WorkstationID I failed to manage.

Jose, it wasn’t working at first as I didn’t have the Using & References set until after I’d messed with your initial code so much it was beyond hope of working.

I owe you both a drink sometime!

2 Likes

Hi,

Looking over this- it appears to be very close to what I’m trying to achieve, when the user clicks to email the sales order acknowledgement via the SSRS Email screen we want to pre-populate the TO field with the users email address (as they always send them to themselves)

The part that I’m struggling to figure out is what Method directive to put the BPM code against- running a trace just shows Erp.Proxy.Rpt.SalesOrderAckImpl and the Submit to agent Method :slightly_frowning_face:

If you don’t mind me asking did you achieve this via a BPM in the end or via APM, or even a screen customisation (which I tried first but I cant seem to get to that screen to customize it)? and if so what directive was this placed against for the sales order ack?

Thanks in advance :slight_smile:

Hi guys (@Randy @josecgomez @knash) , I appreciate the thread. I am also interested to know what method is the code attached to. What I don’t understand is if this code automates the printing or populates the fields and allows the user to push the OK button to activate the send.

I appreciate it if someone could answer that.

It’s not a Method Directive but a Data Directive. In my case it’s OrderHed table as a “standard” directive.

We put a checkbox on the SO Entry form, on the Header tab. When the checkbox = True it’ll fire off the email. This keeps it from sending before our CSR have completed the order and allows them to “re-send” by clearing the check box, saving, and check it again. The BPM then sets various variables, ie: Customer Service Rep (CSR) name, and email address. Then it checks for a customized “Entered For” CSR info (used if a CSR enters an order for another CSR). If true, it’ll set those variables as well. Then it goes to the C# code box(es) to send the appropriate SSRS email. (Note screen shot is from our test server that also includes a test email via the email node at the bottom)

The C# code is pretty much what @knash posed and that I marked as the solution. Using variables I mentioned and fields from the OrderHed table. Example: the customer email address is a field on the OrderHed table (copied via BPM from the Customer table during order creation)

1 Like