Can anyone help me to set a BPM for Auto approve if cost is less then $2000.
I am new with this and not able to do It.
I write a code in method directive as follow: (BUT THIS CODE TAKE TOO LONG TIME AND I am getting error ) I am using EPICOR KINITIC CLOUD
in ERP.BO.Req.Update:
here is a code
// Threshold per line
decimal lineApprovalLimit = 100m;
// Get ReqSvc service
var reqSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.ReqSvcContract>(Db);
// Loop through all requisition headers in the BPM tableset
foreach (var head in Db.ReqHead)
{
int reqNum = head.ReqNum;
// Get all detail lines for this requisition
var lines = Db.ReqDetail.Where(d => d.ReqNum == reqNum).ToList();
bool allLinesBelowLimit = true;
// Check each line total
foreach (var line in lines)
{
decimal lineTotal = line.XOrderQty * line.DocUnitCost;
if (lineTotal > lineApprovalLimit)
{
allLinesBelowLimit = false;
break;
}
}
// Skip if any line exceeds limit
if (!allLinesBelowLimit)
continue;
// Load full tableset from service
var ts = reqSvc.GetByID(reqNum);
// Approve the header
ts.ReqHead[0].StatusType = "A";
string reqNumStr = reqNum.ToString(); // Convert int to string
bool includeSendToPMCond = true;
// Build Req Actions List
var actions = reqSvc.BuildReqActionsList(reqNumStr, includeSendToPMCond);
// Prepare ReqActionID
string reqActionID = "APPROVE";
// Declare out variable before calling method (C# 6 compatible)
string currDispatcherID;
// Execute action
reqSvc.BuildNextDispatcher(reqNumStr, out reqActionID, out currDispatcherID);
// 3. Save changes
reqSvc.Update(ref ts);
}
Can anyone help me to set a BPM for Auto approve if cost is less then $2000.
I am new with this and not able to do It.
I write a code in method directive as follow: (BUT THIS CODE TAKE TOO LONG TIME AND I am getting error ) I am using EPICOR KINITIC CLOUD
in ERP.BO.Req.Update:
// Threshold per line
decimal lineApprovalLimit = 100m;
// Get ReqSvc service
var reqSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.ReqSvcContract>(Db);
// Loop through all requisition headers in the BPM tableset
foreach (var head in Db.ReqHead)
{
int reqNum = head.ReqNum;
// Get all detail lines for this requisition
var lines = Db.ReqDetail.Where(d => d.ReqNum == reqNum).ToList();
bool allLinesBelowLimit = true;
// Check each line total
foreach (var line in lines)
{
decimal lineTotal = line.XOrderQty * line.DocUnitCost;
if (lineTotal > lineApprovalLimit)
{
allLinesBelowLimit = false;
break;
}
}
// Skip if any line exceeds limit
if (!allLinesBelowLimit)
continue;
// Load full tableset from service
var ts = reqSvc.GetByID(reqNum);
// Approve the header
ts.ReqHead[0].StatusType = "A";
string reqNumStr = reqNum.ToString(); // Convert int to string
bool includeSendToPMCond = true;
// Build Req Actions List
var actions = reqSvc.BuildReqActionsList(reqNumStr, includeSendToPMCond);
// Prepare ReqActionID
string reqActionID = "APPROVE";
// Declare out variable before calling method (C# 6 compatible)
string currDispatcherID;
// Execute action
reqSvc.BuildNextDispatcher(reqNumStr, out reqActionID, out currDispatcherID);
// 3. Save changes
reqSvc.Update(ref ts);
}
First, i would replace the first 19 lines of your code with one line that makes this BPM much more efficient. Let SQL do the work. You dont need to load the entire list of items for you to then for/next through the list to find a problem… let SQL do the math and find out if there are any that meet your needs. This can be done by putting your criteria into the where statement, and then using the .ANY concept… this will return either a true or false if it finds “any” that meet your criteria.
Then you should probably put one other if statement to make sure that the returned value is not null.
ALSO, I dislike “break” statements and “return” statements in the middle of anything. I would rather wrap the entire logic in a big if statement. This way you can follow all the logic without have to look for breaks and returns.
Here is some revised code (Untested of course).
OH… my first line uses your variable “lineAprovalLimit” but i am not sure where you got that from… just pointing out that this is an unknown in your logic.
// first lets find out if "ANY" of the lines exceed the approval limit
if (double.ReqDetail.Where(x => x.ReqNum == reqNum && x.XOrderQty * x.DocUnitCost > lineApprovalLimit).Any()) {
// Load full tableset from service
var ts = reqSvc.GetByID(reqNum);
if (ts != null) {
// Approve the header
ts.ReqHead[0].StatusType = "A";
string reqNumStr = reqNum.ToString(); // Convert int to string
bool includeSendToPMCond = true;
// Build Req Actions List
var actions = reqSvc.BuildReqActionsList(reqNumStr, includeSendToPMCond);
// Prepare ReqActionID
string reqActionID = "APPROVE";
// Declare out variable before calling method (C# 6 compatible)
string currDispatcherID;
// Execute action
reqSvc.BuildNextDispatcher(reqNumStr, out reqActionID, out currDispatcherID);
// 3. Save changes
reqSvc.Update(ref ts);
}
}
Not looked too closely, but this may be unneccessary, and you for sure need to be cautious. Either check for a condition or turn off bpm processing in your GetService call.
@klincecum is correct.. what business object is this BPM part of? if you are already in an update BPM, then you simply need to get the temporary record from memory, and then you can modify the data in memory. the system will take care of the actual writing for you.
// Get ReqSvc service
var reqSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.ReqSvcContract>(Db);
// Loop through all requisition headers in the BPM tableset
foreach (var head in Db.ReqHead)
{
int reqNum = head.ReqNum;
// Get all detail lines for this requisition
var lines = Db.ReqDetail.Where(d => d.ReqNum == reqNum).ToList();
bool allLinesBelowLimit = true;
// Check each line total
foreach (var line in lines)
{
decimal lineTotal = line.XOrderQty * line.DocUnitCost;
if (lineTotal > lineApprovalLimit)
{
allLinesBelowLimit = false;
break;
}
}
// Skip if any line exceeds limit
if (!allLinesBelowLimit)
continue;
// Load full tableset from service
var ts = reqSvc.GetByID(reqNum);
// Approve the header
ts.ReqHead[0].StatusType = "A";
string reqNumStr = reqNum.ToString(); // Convert int to string
bool includeSendToPMCond = true;
// Build Req Actions List
var actions = reqSvc.BuildReqActionsList(reqNumStr, includeSendToPMCond);
// Prepare ReqActionID
string reqActionID = "APPROVE";
// Declare out variable before calling method (C# 6 compatible)
string currDispatcherID;
// Execute action
reqSvc.BuildNextDispatcher(reqNumStr, out reqActionID, out currDispatcherID);
// 3. Save changes
reqSvc.Update(ref ts);
OK.. here is the revised code that doesnt use the update within the code. Instead, we just read the memory (the first query of the header) and now we can modify it. Note that I am not getting all the records, but only the modified record.
also notice that this makes the code much simpler.
decimal lineApprovalLimit = 100m;
// Get ReqSvc service
var reqSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.ReqSvcContract>(Db);
// Loop through all requisition headers in the BPM tableset - only look at the MODIFIED ones (RowMod != "")
foreach (var myReqHead in Db.ReqHead.Where(x=>x.RowMod != "")) {
// first lets find out if "ANY" of the lines exceed the approval limit
if (double.ReqDetail.Where(x => x.ReqNum == myReqHead.reqNum && x.XOrderQty * x.DocUnitCost > lineApprovalLimit).Any()) {
myReqHead.StatusType = "A"; // Approve the header
string reqNumStr = myReqHead.reqNum.ToString(); // Convert int to string
bool includeSendToPMCond = true;
// Build Req Actions List
var actions = reqSvc.BuildReqActionsList(reqNumStr, includeSendToPMCond);
// Prepare ReqActionID
string reqActionID = "APPROVE";
// Declare out variable before calling method (C# 6 compatible)
string currDispatcherID;
// Execute action
reqSvc.BuildNextDispatcher(reqNumStr, out reqActionID, out currDispatcherID);
}
}