Success so far: Used DMT to close all old quotes by updating the Task List to LOSE. Closed 6500 quotes in a few minutes.
Still to Do: Add a BPM that closes quotes when they become Expired. Expiration Process runs every day at 2:00 am, but it does not close quotes. I have an existing Standard Data Directive on AlertQue that triggers on Quote Expirations and sends emails to SalesReps.
I created a widget based Method Directive that can be manually triggered on the Quote Form to call the Task.UpdateExt and successfully close the quote. But, I need to make that happen automatically when quotes expire.
Data Directives do not have Fill-Table-By-Query or Invoke-BO-Method widgets, so I can’t just copy my working Method Directive to Data Directive.
I started to reverse engineer the widget source code that I find on the server for my BPM, but that is slightly beyond my current programming capabilities.
Is custom code in a Data Directive on the AlertQue table the right approach, or is there some other way to get these quotes to automatically close when the Expiration process marks them Expired?
At your version, you have a couple of options, none of them are amazing, but I would offer that you make an In-Transaction Data Directive on the SysTask table. When the Quote Expiration process has an End Date, then your BPM would loop through all Expired Quotes that are still open and use BO Methods to close them.
I’m struggling with converting a widget based method directive to a code based data directive to close a Quote. I want to use GetByID to fill a Task tableset, then change the Task fields in that tableset to complete the Task, then pass that tableset to UpdateExt to complete the task and close the quote.
Problem is that GetByID returns a TaskTableset, and UpdateExt requires a UpdExtTaskTableset. Is there another approach I should be using?
Code so far:
var MyTaskTS = new Erp.Tablesets.UpdExtTaskTableset();
bool ErrorOccurred;
Erp.Contracts.TaskSvcContract hTask =null;
hTask = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db);
var ttQuoteHed_xRow = (from ttQuoteHed_Row in ttQuoteHed
select ttQuoteHed_Row).FirstOrDefault();
MyTaskTS = hTask.GetByID("QuoteHed",ttQuoteHed_xRow.QuoteNum.ToString(),"" ,"", 10);
//ToDo: set Conclusion = LOSE, ReasonCode = EXP, Complete = true, CompleteDate = today()
hTask.UpdateExt(ref MyTaskTS, true, true, out ErrorOccurred);
Well, I tried and tried to get a Data Directive to work like the widget based Method Directive, but never got it. I tried various versions of UpdateExt trying to piece together the appropriate dataset and that didn’t work for me. At your suggestion, I also tried to use GetByID and Update on the ‘regular’ dataset, and programmed each method and paramter I saw in the trace of setting the Task to LOSE, and that didn’t work for me either. It was nearly there, the Task got marked Complete, and Lost, the Quote even got marked Closed, but the big red “LOST” text box that normally shows up on the Summary tab didn’t show up. So, I must have been leaving something out that UpdateExt knows about.
I ended up using DMT to accomplish my goal. I used the command line processing capabilities of DMT in a PowerShell script. It runs DMT first to extract a list of Quotes in a BAQ, that are then formatted into a CSV file formatted for DMT. then another call to DMT processes that file that completes and losses the Task for each quote.
So far so good. But, I found 1 out of 10 quotes that have their Tasks completed, don’t get the quote closed. For those quotes I ended up running DMT another time to force the quote closed by updating Quote Header.
Now I have the PowerShell script running in Windows Task Scheduler every day at 2:15 am (after the Epicor Quote Expiration process runs at 2:00 am). All is good.
Jason-- I know this is an old post but I am attempting to currently implement a solution along this line of thinking.
The problem I am having is that my directive does not seem to trigger based on the following conditions in the SysTask table:
ttSysTask.TaskDescription field of the Changed Row is equal to “Quote Expiration”
and ttSysTask.TaskStatus field of the Changed Row is equal to “COMPLETE”
I have tried using “added row”, “updated row”, and “changed row”-- none seem to trigger under these conditions. Am I missing anything you can think of?
Thank you so much for the quick response. I have verified the text values, and I am attempting to test by using the “Show Message” widget as the only execution after the conditions. I have not yet been able to get a message to pop up no matter the conditions. I am wondering if the SysTask table works with data directives the way the erp tables do.
May I ask why you are scheduling an Export? What exactly are you accomplishing with this customization?
A little backstory on my situation:
I am attempting to scan all expired quotes that are not LOST (ReasonType = ‘’) and lose them. I was able to accomplish this with a data directive on the QuoteHed table and it worked when I expired the quotes one by one with the DMT tool, and my eventual plan was to schedule the Quote Expiration Process for a nightly run. However, the Quote Expiration Process seems to bypass the data directives for some reason and it does not trigger the code to run.
So now I am working on a data directive in the SysTask table with conditions checking for the Quote Expiration process complete, which triggers based on the conditions well. But, in my code I am grabbing all QuoteHed records where Expired == true and ReasonType == “”, but my code to LOSE the active task on the quote one by one (with a foreach loop) no longer works.
I am curious how/why you are closing or losing quotes by exporting a BAQ on a schedule.
Essentially I am replacing the Epicor out of the box quote expiration process. AND on top of that losing the actually quotes that are marked expired. In the current version of Epicor we are on we could have used a scheduled function to do this same thing, but a BAQ BPM was the fastest way for me to deploy. The “Export” of the BAQ essentially fires the GetList method of the UBAQ. This is the method where all my code to accomplish the above tasks lie.