PO approval notification - email sent just once

Hello, I know this is quite an old topic… but I have exhausted all the information in this site and still struggling getting this working.

I have a data directive to POApvMsg table with condition on:

MsgType of the changed row is equal to 1 or msgtype con added row is equal to 1

if the condition is true, the following code is excecuted:

foreach (var row in ttPOApvMsg.Where(r => r.RowMod == “A” || r.RowMod == “U”))
{
    var agents = Db.PurAgent
    .Where(a => a.Company == row.Company)
    .ToList();

var approverAgent = agents.FirstOrDefault(a => a.BuyerID == row.MsgTo);
var buyerAgent    = agents.FirstOrDefault(a => a.BuyerID == row.MsgFrom);

if (approverAgent != null)
{
    callContextBpmData.Character01 = approverAgent.EMailAddress;
    callContextBpmData.Character04 = approverAgent.BuyerID;
}

if (buyerAgent != null)
{
    callContextBpmData.ShortChar02 = buyerAgent.EMailAddress;
}

var po = Db.POHeader.FirstOrDefault(p => p.Company == row.Company && p.PONum == row.PONum);
if (po == null) continue;

var vendor = Db.Vendor.FirstOrDefault(v => v.Company == row.Company && v.VendorNum == po.VendorNum);
if (vendor == null) continue;

callContextBpmData.Character02 = vendor.Name;
callContextBpmData.Character03 = po.EntryPerson;
}

this works perfect the first time, but since I have a multi level approval workflow that could be up to 4th level, only the first po approval notification is sent.

let’s say buyer1 has a po limite of 1500, his approver a po limite of 20,000. Next approver a limit of 60k and the last one has no limit.

so if buyer1 cuts out a po for more than 60k, the expectation is to have the data directive to send 3 emails… since there will be 3 approvals required, there will be cases in which 4 approvals will be needed.

with the code I have shared with you, just the first approver is receiving the notification.

BuyerID’s only have 2 authorized users, user and approver… all approvers have their own BuyerID with the same settings just 2 authorized users.

any suggestion will be very appreciated.

You want all emails to send at the same time? I have a widget based BPM that will fire off one email at a time until it hits the last appropriate approver in the hierarchy.

1 Like

that is exactly what I’m trying to achieve.. one email every time an approval is required…

I’m no expert in C# but I’m pretty sure that code is only going to return the first level approver. I think the next step would be to look into recursion to traverse the entire approval hierarchy.

do you mind sharing your bpm design, maybe i can compare it with mine

I do not have any type of recursion implemented, emails are sent one by one as the PO is approved up the chain. It works with the stock epicor approval logic but is slower than sending all mails at once. I also designed a dashboard to track what stage an approval is at.

Check for changed record

Get ApproverID

Look up approver details

Assign approver email to var

Send email back to buyer

1 Like

thank you!!! seem to be very straight forward… which version are you running? since you are quering ttpoappvmsg table, I asume this is a data directive, right?

We’re running 2023.1

Yes, this is a standard data directive.

1 Like

there is a mobile app to support PO approval

interesting!!! will give it a try…

I had to do this a few months ago and this is the routine I used from my standard alert email. It sends the approver an alert and the buyer when it is approved.

/* email PO approval needed */


string EmailAddress = string.Empty;
string UserName = string.Empty;
string vFrom = string.Empty;
string vTo = string.Empty;
string vCC = string.Empty;
string vSubject = string.Empty;
string vBody = string.Empty;
string buyerCC = string.Empty;
string EMAIL_From = string.Empty;
string EMAIL_To = string.Empty;
string EMAIL_CC = string.Empty;
string EMAIL_Subject = string.Empty;
string EMAIL_Text = string.Empty;
//Erp.Tables.UserFile UserFile;
Erp.Tables.POHeader POHeader;
//Erp.Tables.PODetail PODetail;
//Erp.Tables.PORel OLDPORel;
Erp.Tables.Vendor Vendor;
Erp.Tables.Part Part;

Ice.Diagnostics.Log.WriteEntry($"start approval email");

var  ttPOApvMsgRow  = ttPOApvMsg.Where(w => !w.Unchanged()).FirstOrDefault();
{

  bool isBuyer = Db.PurAgent.Any(s => s.Company == CompanyID && s.BuyerID ==  callContextClient.CurrentUserId);
  

  if(ttPOApvMsgRow != null && isBuyer == true)
  {

    POHeader = (from POHeader_Row in Db.POHeader
    where POHeader_Row.Company ==  ttPOApvMsgRow.Company && POHeader_Row.PONum == ttPOApvMsgRow.PONum
    select POHeader_Row).FirstOrDefault();

    var msgFromUser = (from UserFile_Row in Db.UserFile
      where UserFile_Row.DcdUserID == ttPOApvMsgRow.MsgFrom
      select UserFile_Row).FirstOrDefault();


    if (msgFromUser != null)
    {


      /*OLDPORel = (from Old_Row in ttPORel
      where Old_Row.RowMod == ""
      select Old_Row).FirstOrDefault();*/


      var msgToUser = (from UserFile_Row in Db.UserFile
      where UserFile_Row.DcdUserID == ttPOApvMsgRow.MsgTo
      select UserFile_Row).FirstOrDefault();

      var fromUser = (from UserFile_Row in Db.UserFile
      where UserFile_Row.DcdUserID == Session.UserID
      select UserFile_Row).FirstOrDefault();

      

      var buyer = (from UserFile_Row in Db.UserFile
      where UserFile_Row.DcdUserID == POHeader.BuyerID
      select UserFile_Row).FirstOrDefault();

    

      Vendor = (from Vendor_Row in Db.Vendor
      where string.Compare(Vendor_Row.Company, POHeader.Company, true) == 0 && Vendor_Row.VendorNum == POHeader.VendorNum
      select Vendor_Row).FirstOrDefault();
      var PODetailList = (from PODetail_Row in Db.PODetail
      where PODetail_Row.Company == ttPOApvMsgRow.Company && PODetail_Row.PONUM == ttPOApvMsgRow.PONum
      select PODetail_Row).ToList();

     
      if(msgFromUser.DcdUserID != fromUser.DcdUserID && ttPOApvMsgRow.MsgType == "1")
      {
        vBody = $"PO {POHeader.PONum} by {fromUser.Name} On behalf of {msgFromUser.Name}\n\n\tVendor {Vendor.VendorID}\n\n\tTotal Value {POHeader.TotalOrder:N2}";
      
      }
      
      if(msgFromUser.DcdUserID == fromUser.DcdUserID && ttPOApvMsgRow.MsgType == "1")
      {
        vBody = $"PO {POHeader.PONum} by {fromUser.Name}\n\n\tVendor {Vendor.VendorID}\n\n\tTotal Value {POHeader.TotalOrder:N2}";
      }


      if(msgFromUser.DcdUserID != fromUser.DcdUserID && ttPOApvMsgRow.MsgType != "1")
      {
        vBody = $"PO {POHeader.PONum} {ttPOApvMsgRow.ApproverResponse} by {fromUser.Name} On behalf of {msgFromUser.Name}\n\n\tVendor {Vendor.VendorID}\n\n\tTotal Value {POHeader.TotalOrder:N2}";
      }
      
      if(msgFromUser.DcdUserID == fromUser.DcdUserID && ttPOApvMsgRow.MsgType != "1")
      {
        vBody = $"PO {POHeader.PONum} {ttPOApvMsgRow.ApproverResponse} by {fromUser.Name}\n\n\tVendor {Vendor.VendorID}\n\n\tTotal Value {POHeader.TotalOrder:N2}";
      }

      



      foreach(var PODetail in PODetailList)
      {
        Ice.Diagnostics.Log.WriteEntry($"DEBUG Email  -  PO Quantity  = {PODetail.XOrderQty:N2}");
        vBody = vBody + $"\n\n\tItem {PODetail.PartNum} {PODetail.LineDesc} \n\tQty  {PODetail.XOrderQty:N2}\tPO Cost \t {PODetail.UnitCost:N2}\tExtended Cost {(PODetail.UnitCost * PODetail.XOrderQty):N2}" ;


      }


      if (!String.IsNullOrEmpty(buyer.EMailAddress.Trim()))
      {
        buyerCC = "<" + buyer.EMailAddress + ">";
      }
      else
      {
        buyerCC = "<info@domain.com>";
      }
      
      if (!String.IsNullOrEmpty(msgToUser.EMailAddress.Trim()))
      {
        EMAIL_To = "<" + msgToUser.EMailAddress + ">";
      }
      else
      {
        EMAIL_To = "<info@domain.com>";
      }

     
      vCC = buyerCC +  ";<info@domain.com>;";

      if (!String.IsNullOrEmpty(fromUser.EMailAddress.Trim()))
      {
        EMAIL_From = "<" + fromUser.EMailAddress + ">";
      }
      else
      {
        EMAIL_From = "<info@domain.com>";
      }
      Ice.Diagnostics.Log.WriteEntry($"DEBUG Email  - type { ttPOApvMsgRow.MsgType } Email From {fromUser.DcdUserID} To {msgToUser.Name} From {msgFromUser.Name} buyer {buyer.Name}");
      if(fromUser.DcdUserID == "gpay01")
      {
        EMAIL_To = "<info@domain.com>";;
        vCC  = "<info@domain.com>";
      }
      EMAIL_CC = vCC + EMAIL_From;Í
      
      if(ttPOApvMsgRow.MsgType == "1")
      {
        EMAIL_Subject = $"PO Approval Needed {POHeader.PONum}";
      }
      
      if(ttPOApvMsgRow.MsgType != "1")
      {
        EMAIL_Subject = $"PO Approval Status for {POHeader.PONum} {ttPOApvMsgRow.ApproverResponse}";
      }
      
      EMAIL_Text = vBody;


      var mailer = this.GetMailer(async: true);
      var message = new Ice.Mail.SmtpMail();

      message.SetFrom(EMAIL_From);
      message.SetTo(EMAIL_To);
      message.SetCC(EMAIL_CC);
      message.SetSubject(EMAIL_Subject);
      message.SetBody(vBody);
      message.Priority = System.Net.Mail.MailPriority.High;
      mailer.Send(message);
    }
  }
}

Ice.Diagnostics.Log.WriteEntry($"exit approval email");

1 Like