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.
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.
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.
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.
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?
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");