I am attempting to (once a night) loop through all expired quotes that are not already lost, and Lose them via the active task (works when performed on a single quote in a separate BPM). Nothing seems to happen anymore. I have tried tinkering quite a bit-- any ideas when looking at this code what I am doing wrong? This is an in transaction data directive on the SysTask table and I have verified that my conditions are triggering. My code does not appear to execute at all. It is set to Synchronously execute.
Please ignore my commented lines.
<// auto lose quote via active task based on expiration task completed in SysTask table
//using (var txScope = IceContext.CreateDefaultTransactionScope())
//{
//Query all QuoteHed records from Db that are applicable to be lost/closed:
var qhRecs = Db.QuoteHed.Where(r => r.Expired == true && r.ReasonType == "" && r.QuoteClosed == false);
//Loop through each applicable Quote record and perform LOSE in the task table on the active task.
foreach (var qhRow in qhRecs) {
//Store QuoteHed information for this record to prepare the where clause for the task table query, etc.
string company = qhRow.Company;
string quoteNum = qhRow.QuoteNum.ToString();
string taskSetID = qhRow.TaskSetID;
string activeTaskID = qhRow.ActiveTaskID;
string rtf = "QuoteHed";
bool complete = false;
//Query Erp.TaskSDtl table to check that Lose is allowed on the active task.
var taskSDtlRecs = Db.TaskSDtl.Where(r => r.Company == company && r.TaskSetID == taskSetID && r.TaskID == activeTaskID);
bool loseChk = false;
foreach (var rec in taskSDtlRecs) {
if (rec.LoseAllowed == true) {
loseChk = true;
}
}
//Query Erp.Reason table to check for existence of CLEAN reason.
var rcRecs = Db.Reason.Where(r => r.Company == company && r.ReasonType == "L");
bool clnChk = false;
foreach (var rec in rcRecs) {
if (rec.ReasonCode == "CLEAN") {
clnChk = true;
}
}
if (loseChk && clnChk) {
if (quoteNum != null && quoteNum != "0" && quoteNum != "") {
using (var tsk = ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db)) {
Erp.Tablesets.TaskTableset tskTs = new Erp.Tablesets.TaskTableset();
string wc = "Company='"+company+"' AND RelatedToFile='"+rtf+"' AND Key1='"+quoteNum+"' AND Complete="+complete;
string wctc = "Company='"+company+"' AND RelatedToFile='"+rtf+"' AND Key1='"+quoteNum+"'";
bool mp = false;
tskTs = tsk.GetRows(wc,wctc,0,0,out mp);
if (tskTs != null) {
foreach (var tRow in tskTs.Task.ToList()) {
var drOrig = tskTs.Task.NewRow();
BufferCopy.Copy(tRow, drOrig);
tskTs.Task.Add(drOrig);
tRow.RowMod = "U";
tRow.Complete = true;
tRow.CompleteDate = DateTime.UtcNow.Date;
tRow.ChangeDcdUserID = "manager"; //callContextClient.CurrentUserId;
tRow.Conclusion = "LOSE";
tRow.ReasonCode = "CLEAN";
tsk.Update(ref tskTs);
Db.Validate();
}
}
tsk.Dispose();
}
}
}
}
//txScope.Complete();
//txScope.Dispose();
//}>
This seems like an odd way to trigger this. I think that this might be better to put the code into Ubaq and then schedule the BAQ to run using the BAQ Export process. Data directives can be problematic when running code in them. Plus it will be easier to test in the BAQ, AND, you can return all of your data needed to find the lines to close in the BAQ then run the code after so you don’t have to do the lookup in the code. (both ways work though)
Make the BAQ an updateable BAQ, then on the update tab, change this to Advanced BPM Update Only. Then click on the BPM Directives Configuration, and you’re into BPM land again. This only applies to this BAQ so it’s nice and contained. If you want it to run anything you run the BAQ (like when you do an export) put the code on getList Post Processing. But you have lots of options to put in BPM style code.
Brandon has suggested a great out-of-box solution.
If you’re looking for an alternative, I do your exact use-case using the “User Process Scheduler” which is a fairly cheap addon that lets you schedule BPMs.
Search around the forum I guess. The code that you have above should work for the most part. Generally you loop through your results set using something like this.
Also, don’t forget that in the BPM there is a rudimentary auto complete. If you hit Ctrl+Space you can see what your options are. It’s not 100% but it’s close and really helpful.
Thanks, I did not realize this auto complete existed in my current version. That’s wonderful.
MY SOLUTION:
So I scrapped multiple other BPM attempts within Data Directives because nothing worked the way I expected. The most surprising thing to me was that the “Quote Expiration Process” totally bypasses any Data Directive conditions that check changed row to Expired = 1. Since this project failed, I tried using the SysTask table where “Quote Expiration” task changed to COMPLETE and the conditions worked, but my custom code did not work as expected (unsure of why, seems to be a common limitation in the data directive for the amount of TODO I was trying to execute).
WHAT I ENDED UP DOING:UBAQ WITH CUSTOM BPM CODE ON GETLIST METHOD
This is the only thing I tried that worked with losing the expired quotes one by one looping through the results of my UBAQ ttResults table. Instead of querying the Quote and Task data from QuoteHed within the C# I just used the results from the BAQ I designed to return the right rows I wanted.
I basically use a foreach to scan each results row and lose the quote task one by one. Works like a charm. BPM Code below… (sorry for bad formatting in post, trying to figure out how to properly format C# blocks here, forgive me):
//Loop through each applicable Quote record and perform LOSE in the task table on the active task.
foreach (var qhRow in ttResults) {
try {
//Store QuoteHed information for this record to prepare the where clause for the task table query.
string company = qhRow.QuoteHed_Company;
string quoteNum = qhRow.QuoteHed_QuoteNum.ToString();
string taskSetID = qhRow.QuoteHed_TaskSetID;
string activeTaskID = qhRow.QuoteHed_ActiveTaskID;
string rtf = "QuoteHed";
bool complete = false;
var tsk = ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db);
if (quoteNum != null && quoteNum != "0" && quoteNum != "") {
Erp.Tablesets.TaskTableset tskTs = new Erp.Tablesets.TaskTableset();
string wc = "Company='"+company+"' AND RelatedToFile='"+rtf+"' AND Key1='"+quoteNum+"' AND Complete="+complete;
string wctc = "Company='"+company+"' AND RelatedToFile='"+rtf+"' AND Key1='"+quoteNum+"'";
bool mp = false;
tskTs = tsk.GetRows(wc,wctc,0,0,out mp);
if (tskTs != null) {
foreach (var tRow in tskTs.Task.ToList()) {
var drOrig = tskTs.Task.NewRow();
BufferCopy.Copy(tRow, drOrig);
tskTs.Task.Add(drOrig);
tRow.RowMod = "U";
tRow.Complete = true;
tRow.CompleteDate = DateTime.UtcNow.Date;
tRow.ChangeDcdUserID = callContextClient.CurrentUserId;
tRow.Conclusion = "LOSE";
tRow.ReasonCode = "CLEAN";
}
tsk.Update(ref tskTs);
Db.Validate();
}
}
//Dispose of task business object at end of code
tsk.Dispose();
tsk = null;
} catch (Exception e) {
this.PublishInfoMessage("Exception: " + e.Message,Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
}
}