Attach order acknowledgement to email in BPM

Another … “better” approach might be to use Auto Print, or Run the Report using the Breaking and Routing Capabilities of the system to do the emailing for you.

So instead of doing the email in the BPM, you run the report and let the report do the emailing for you automaticaly.

2 Likes

New plan:
finish my BPM by sending the acknowledgment to the system agent.
Setup a new async BPM that fires when SysTask.TaskStatus changes to COMPLETE.
If it’s a report I sent (aka it has some signature in the TaskNote), then I’ll build the email and add the attachment.

The only reason I don’t want to go this route is it does not support HTML (at least not in my version).

1 Like

side note: is there a way to enable a standard directive and pass some info with it? Like a variable or something?

Pass information in CallContext

1 Like

Thanks. You might not know it, but I am slowly leveling up haha. And I try to pay it forward as much as I can.

2 Likes

What are you a Dr of ?

Those are just my initials. The nickname stuck from when I was a teenager.

1 Like

Hi dr_dan,

Were you able to get a working BPM that sends the Order Acknowledgement form? I am trying to automate that process, and I’m having an issue getting the report as a pdf attachment.

Yes and no.
I thought I had it working OK (I got it to work seemingly reliably) but at some point I realized it was not working every time. So I ended up disabling it and haven’t gotten back to it to figure out why it wouldn’t work reliably.

I don’t know if either of you are still looking for this, but since I was referencing @dr_dan 's post to refresh my memory I thought I would pop this in.

Your answer lies in using RunDirect, instead of SubmitToAgent. If you want it to run asynchronously, run it via a scheduled function, which you can schedule on the fly to run “Now”.

Here is the run direct example, which just so happens to be the same report :tada:

2 Likes

I’ll have to circle back. I don’t know why I needed to have HTML formatting. I mean, just getting a plain text email with a file attachment would be much better than getting a pretty email with no email attachment. Why wouldn’t I want to use AutoPrint I guess now that I’m thinking about it?

I don’t question peoples motives,(I lie too.) I just provide answers :rofl:

Hello @dr_dan,
Good to see the code you have shared.
I am working in a case where I need to send email with attachment of OrderAck report PDF when user modify some fields. The tricky portion is, I need to put before and after update data in to the email body.

When I try with your code, facing below error

As I checked in the available assembly list, there is no MemoryStream and Stream.

Could you please help me on this?

The assembly reference is System.IO I believe. That’s what you need to add.

1 Like

Also, please find a better way than what I was trying there with the sleep. Basically, I needed to wait for the report to be generated before it would be available to attach in an email… and I thought that would do it… but in the end I don’t think it worked reliably.

I don’t know if it needs to be asynchronous, or another BPM that triggers when the report itself is actually generated… not sure. I never got back to it. But I wanted to give you that caution.

1 Like

@dr_dan Thanks for the update. Is there any other suggestion for my case?

Email should be triggered with OrdAck report attachment along with the body information contains what data had been modified.

If I go for, Autoprint widget and APR, no option to particularly insert last updated field record in the email body.

Here’s a function I wrote when my company didn’t want to spring for APR. It has a static Body in this function, but you can change it and pass in data from the BPM and set the body of the email to whatever you want

/*== Email Sales Order Acknowledgment  =====================================
    
    Using statements:
        using System.Net;
        using System.Net.Mail;
        using Erp.Tablesets;

    Library Reference:
        Service -> ERP.Rpt.SalesOrderAck
        Table -> ICE.SysRptLst (Read Only)
        Table -> ICE.SysTask (Read Only)

    Request Parameters:
        orderNum - System.Int32  


            --Kevin Veldman <rfptsolutions@gmail.com>
===========================================================================*/



//_ Delegate Function to generate Sales Order Acknowledgment
Func<int, byte[]> GetASalesOrderPDF = someOrderNum => {

    byte[] reportPDF = null;

    CallService<Erp.Contracts.SalesOrderAckSvcContract>( soa => {

        string taskNote = Guid.NewGuid().ToString(); 

        SalesOrderAckTableset salesOrderAckTS = soa.GetNewParameters();
        SalesOrderAckParamRow paramRow = salesOrderAckTS.SalesOrderAckParam.First();
        
        paramRow.OrderNum = someOrderNum;
        paramRow.AgentID = "SystemTaskAgent";
        paramRow.AutoAction = "SSRSGENERATE";
        paramRow.ReportStyleNum = 1008;
        paramRow.TaskNote = taskNote;
        
        soa.RunDirect( salesOrderAckTS );

        reportPDF = Db.SysRptList.Join( Db.SysTask,
                                    x => new { x.Company, x.SysTaskNum },
                                    y => new { y.Company, y.SysTaskNum },
                                    (x,y) => new { sr = x, st = y } )
                                .Where( z => z.st.TaskNote == taskNote )
                                .Select( z => z.st.RptData ).FirstOrDefault();
    });

    return reportPDF;
};


//_ Generate, save Sales Order Acknowledgement
var rptBytes = GetASalesOrderPDF( orderNum );
string fileName = $@"C:\EpicorData\Companies\EPI06\Temp\SOAck_{orderNum}.pdf";
System.IO.File.WriteAllBytes( fileName, rptBytes );



//_ Set up Email Message
using ( var message = new MailMessage() ) {

    string sendName = "Display Name";
    string sendFrom = "myEmail@company.com";
    message.From = new MailAddress( sendFrom, sendName ); //Display Name is optional

    message.To.Add(new MailAddress( "customer@email.com" ));
    message.CC.Add(new MailAddress( "customerCC@email.com" ));
    message.Bcc.Add(new MailAddress( "blindCopy@company.com" ));

    message.Subject = $"Sales Order Acknowledgment {orderNum}";

    message.IsBodyHtml = true;
    message.Body = "<p>Your Sales Order Has Been Received and Processed</p>";
    
    message.Attachments.Add(new Attachment( fileName ));


    //_ Send Email
    using ( var smtp = new SmtpClient( "smtp.office365.com", 587 ) ) {

        try {

            smtp.EnableSsl = true;
            smtp.Credentials = new NetworkCredential( sendFrom, "SendFromPassword" ); //NetworkCredential stores the password as SecureString
            smtp.Send( message );

        } 
        catch ( Exception ex ) {

            string logName = @"C:\EpicorData\Logs\smtpErrors.log";
            string logDtls = $"\n{DateTime.Now:G}:\n{ex.Message}\n";
            System.IO.File.AppendAllText( logName, logDtls );

        }
        finally {

            System.IO.File.Delete( fileName );
        }
    }
}
2 Likes

Hey @kve,

I really appreciate your support. I am trying to reuse the same code but facing this error. Is there any assembly missing?

CS1061 ‘ILibraryContext’ does not contain a definition for ‘SysRptList’ and no accessible extension method ‘SysRptList’ accepting a first argument of type ‘ILibraryContext’ could be found (are you missing a using directive or an assembly reference?)

image

image

You are right! Now that error disappeared. Thank you so much! :grinning:

That’s a typo, I think it should be SysRptLst