Attach order acknowledgement to email in BPM

@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

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