Attach order acknowledgement to email in BPM

Hello!
I am looking and not finding anything that specifically addresses what I’m trying to do. It’s probably getting deep but it’s worth a shot.

I have a BPM that will adjust the ReqDate on OrderRel based on user input/feedback. It will also update our Forecast to match the adjustment made to the order. Long story short, I get all of the stuff to update like I want and then generate a pretty HTML email to select people to inform them of the changes.

WHAT I AM TRYING TO DO: Print a new acknowledgement to PDF and attach it to this same email. Can that be done? Or should I quit while I’m ahead?

Thanks in advance!

We have a resource in our Technical Services Group that does this all the time. it is a BPM with routing widgets.

1 Like

Ok. Good to know. Any idea what they’re doing/how they go about it?

Alternatives:

One would be to reach out to your CAM and ask for the CSG Extension called Document Sender. It does a fine job of emailing a number of customer facing documents and gives the user control over it.

Another - If you require less control and more automation, then you can also talk to your CAM about Advanced Print Routing (and if you already have the license or not) as it allows BPM style control over almost any Report Style.

1 Like

We do have APR. I am comfortable getting an email to send using that method… As of my version, APR does not allow for HTML formatting.

But, APR triggers from a print request. Really, the trigger in my “potential use case” is this BPM that updates the order. Since I am already formatting an email to notify someone of the change, I thought it might be nice to include the order acknowledgement in that same email for reference. If not, it’s not the end of the world.

ok sorry - I missed that you you were trying to print ANOTHER report and add it to the outgoing email generated by your BPM… sometimes I read too fast :slight_smile:

It might be possible to call the business objects for printing a report within a custom code block widget and push that PDF out to a specific location/name and then include it as an attachment on the email. I’m thinking there are a number of posts here that deal with this in some fashion but I don’t recall if you can attach a PDF to a BPM generated email or not.

Perhaps it needs to be a APR Report style that has a standard body block of “we’ve changed your dates and here’s your new SO Ack” - or some combination of BPM and APR…

I am going to research what the business object is that AutoPrint uses and see if it returns anything of use that I might be able to hijack and insert into an attachment using the BPM Mailer.

@dr_dan This post may help.

2 Likes

Admittedly, I’ve come across several very helpful posts here that have guided me. I feel like I’m one nudge away from getting over the hump. I have boiled down what I think needs to happen for me to do this.

1. Programmatically print a new Order Acknowledgement. (I have been able to send that to the System Agent and get it to show up in my Report Monitor as having been “completed”).
2. Retrieve this PDF using some method - I’m still working on this and need insight. It looks like a UBAQ is suggested but I don’t know how to call the UBAQ through an existing BPM. I could also write the PDF to a file path when it’s printed and then look up that file path and get it… then delete it.
3. Attach the PDF to the mail before I send it (I feel I have this under control if I can get step 2 done).

Is there a source where I can view the different attachment options on the SmtpMail object? The terms seem to generic for Google to be effective. I need to know what I can do within Epicor. It appears the only way I can add an attachment to an email is from a file directory… but I’d love to attach the file directly in the code… But I don’t know what method that might be called, or if it even exists…

@dr_dan The UBAQ is just to run the bpm so if you are already triggering a bpm then just code it in there. The other thread you are posting on has all of the bits to get the pdf back into an byte array and I am pretty sure you can attach that just like it is a file.

1 Like

@gpayne - I am grateful for your help. The only thing I can’t reconcile is the Ice.Mail assembly… That does not appear to be the same as System.Net.Mail, which is in the link you provided. So I can’t find a way to create an attachment on the mail any other way besides providing a link to a directory where the file resides. I believe it’s probably very plausible to do it - but I can’t find a reference to show me what methods might be available for the Ice.Mail assembly. That’s the million dollar question for me. I have looked on EpicWeb hoping to find some manual and I am striking out.

Well, I found this. This seems to be what I’m asking.

I haven’t figured out how to get my bytes[] to a stream yet, but I suspect I can find that if I look hard also. Getting closer. Thanks again everyone who’s chimed in.

Hi @dr_dan , in the reportstyle you could put below parameter “ReportOptions”. This will automatically save the file into server folder under the user name.

then in your program you can attach the last file that has been dropped.

image

Basically, we done it in a way that when user press “Send Email” button in POForm, it will generate the poform and open a custom form showing the attachment, and provides user to type email body message and press button to send email.

but you could also use standard email option.

This is good to know also. At this point, I am already filling the body of the email because this is an “automated” email to update people that the order was changed. So I’m attaching the new acknowledgement for their reference. I can completely understand your use case and why you’d want to handle it the way you’re doing it. I will definitely keep this in mind.

It’s nearly functional. I did get some tests to email me with an attachment - however I have gotten stuck where I am trying to feed a GUID into the TaskNote and then look for that record in SysRptLst. My LINQ query just doesn’t find it. If I search for that GUID manually (by copy/paste a previous report into the LINQ query explicitly, it will return the bytes and email an attachment. But it won’t do it on the fly. Here’s what I got…

    //--------------------------------
    //    PRINT NEW ACKNOWLEDGMENT
    //---------------------------------
      Guid myGuid = Guid.NewGuid();    
      string taskNote = myGuid.ToString().ToUpper();
        
      var soa = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.SalesOrderAckSvcContract>(Db);
      Erp.Tablesets.SalesOrderAckTableset dsSOA = null;
      dsSOA = soa.GetNewParameters();
      dsSOA.SalesOrderAckParam[0].OrderNum = orderNum;
      dsSOA.SalesOrderAckParam[0].OrderList = orderNum.ToString();
      dsSOA.SalesOrderAckParam[0].AgentID = "SystemTaskAgent";
      dsSOA.SalesOrderAckParam[0].AutoAction = "SSRSPREVIEW";
      dsSOA.SalesOrderAckParam[0].ReportStyleNum = 1004;
      dsSOA.SalesOrderAckParam[0].ArchiveCode = 0;
      dsSOA.SalesOrderAckParam[0].DateFormat = "m/d/yyyy";
      dsSOA.SalesOrderAckParam[0].NumericFormat = ",.";
      dsSOA.SalesOrderAckParam[0].ReportCultureCode = "en-US";
      dsSOA.SalesOrderAckParam[0].ReportCurrencyCode = "USD";
      dsSOA.SalesOrderAckParam[0].SSRSRenderFormat = "PDF";
      dsSOA.SalesOrderAckParam[0].TaskNote = taskNote;
      soa.SubmitToAgent(dsSOA, "SystemTaskAgent", 0, 0, "Erp.UIRpt.SalesOrderAck");
      soa.Dispose();
    

    //--------------------------------
    //    ATTACH ACKNOWLEDGMENT
    //---------------------------------
      Dictionary<string, Stream> attachments = new Dictionary<string, Stream>();
      int t = 0;
      
      while (t < 10000) //<< 10 seconds. It should only take a few seconds for the report to be generated. If it takes more than 10 seconds, sucks to suck.
      {
        System.Threading.Thread.Sleep(100); // 1/10 of a second
        var getFile = (from mmf in Db.SysRptLst
                   join st in Db.SysTask on new {mmf.Company, mmf.SysTaskNum} equals new {st.Company, st.SysTaskNum}
                   where mmf.Company == callContextClient.CurrentCompany
                   && st.TaskNote == taskNote
                   && st.TaskStatus == "COMPLETE"
                   orderby mmf.RecSeq descending
                   select mmf.RptData).FirstOrDefault();
      
        if (getFile != null)
        {        
          string strFile = Convert.ToBase64String(getFile);
    
          byte[] pdfBytes = System.Convert.FromBase64String(strFile);
          MemoryStream pdfFile = new MemoryStream(pdfBytes);
          attachments.Add("Order " + orderNum.ToString() + " Updated Ack.pdf", pdfFile);
          break;
        }
        else
        {
          t += 100;
        }
      }
      
      
    //--------------------------------
    //    SEND EMAIL WITH ATTACHMENT
    //---------------------------------      
      if (attachments.Count > 0)
      {
        mailer.Send(message, attachments);
      }
      else 
      {
        mailer.Send(message);
      }
while (t < 10000) //<< 10 seconds. It should only take a few seconds for the report to be generated. If it takes more than 10 seconds, sucks to suck.

This is how the local System Monitor does this. (It polls more frequently in the beginning but then slows down over time, which I didn’t show here.)

Downloading SO Acknowledgement pdf programatically - ERP 10 - Epicor User Help Forum (epiusers.help)

I guess what I am not getting is that it doesn’t find the report… but it’s there. Am I doing something goofy or violating some rule where I can’t do this? The timer ends up elapsing and does not find an attachment, so I get the email with no attachment. It’s like it won’t find the one I am creating in the same block of code.

That’s why I sent you that link. There is a status on the SysTask table called TaskStatus. Keep checking it until it’s not ACTIVE. If it’s Complete, then go get your attachment. If it errors or cancelled then inform the user.

2 Likes

I suggest you go this route, doing this in a BPM is going to make the performance on this method abysmal. If you MUST go this way I would go with an asynchronous function call which takes all the parameters and does the work outside the current thread.

Adding a waiting loop to the report print in a server side BPM is just :nauseated_face: not good

4 Likes