Mass Update Tasks by Quote

I need to mass update some tasks on quotes by an identified list of quote numbers.
This would involve completing the active tasks and setting the next task.
My first gut feel is DMT on QuoteHed, but what would be a tried and true way to approach this?

I’m using a BPM invoked by User Process Scheduler. This is driving me nuts, because it worked a couple of times and now is giving me an error when I invoke

Code:

Summary
var Parameters = new Ice.Core.TaskParameterInformation(this.Db, taskNum);
    var custNum = Convert.ToInt32(Parameters.GetCharacterValue("TxtParam1"));
    var followUpDate = Convert.ToDateTime(Parameters.GetDateValue("DatParam1"));//looks misspelled but isn't

    /*
    DateTime dateValue = DateTime.Now;
    DateTime.TryParse(Parameters.GetCharacterValue("DatParam1"), out dateValue);//looks misspelled but isn't
    var followUpDate = dateValue;
    */
    Dictionary<int, DateTime?> queue = new Dictionary<int, DateTime?>();

    foreach(var quote in (from q in Db.QuoteHed.With(LockHint.NoLock)
                        where
                          q.Company == Session.CompanyID 
                          && q.CustNum == custNum
                          && q.Quoted == false
                          && q.QuoteClosed == false
                          && q.ActiveTaskID == "ACTV"                   
                        select new {
                          q.QuoteNum, q.FollowUpDate
                          }
                        ))
                      
                        /*Start Iteration Action*/
                        
                        {
                          if(quote != null)
                          {
                            queue.Add(quote.QuoteNum, quote.FollowUpDate);
                          }
                        }
                        
                        /*End Interation Action*/

    //TEST WITH SINGLE QUOTE 
    //queue.Add(59689, DateTime.Today);
    if(queue.Any())
    {
      foreach(var row in queue)
      {
        using(Erp.Contracts.QuoteSvcContract quoteSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db))
        {
          //update the QuoteHed.ResponsibleFor_c and QuoteHed.Character03 to "ASC" and "COVID-19 Hold"
          //set QuoteHed.FollowUpDate to either the user input follow up date or if it has one, leave it alone. 
          var quoteTS = quoteSvc.GetByID(row.Key);
          quoteTS.QuoteHed[0]["ResponsibleFor_c"] = "ASC";
          quoteTS.QuoteHed[0]["Character03"] = "COVID-19 Hold";
          quoteTS.QuoteHed[0].RowMod = "U";
          if(row.Value != null)
            {
              quoteTS.QuoteHed[0].FollowUpDate = row.Value;
            }
          else
            {
              quoteTS.QuoteHed[0].FollowUpDate = followUpDate;
            }
          quoteSvc.Update(ref quoteTS);       
        }
        //Update the task from "Active" to "Hold"     
        using(Erp.Contracts.TaskSvcContract taskSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db))
        {
            string whereClause = string.Format("Key1 = '{0}' AND RelatedToFile = 'QuoteHed' BY TaskSeqNum DESC", row.Key.ToString());
            int pageSize = 0;
            int absolutePage = 0;
            bool morePages = false;
          
            var taskTS = taskSvc.GetRows(whereClause, "", pageSize, absolutePage, out morePages);
            //use the top row to get the specific task
            /*
            string relatedToFile = "QuoteHed";
            string key1 = row.Key.ToString();
            string key2 = "";
            string key3 = "";
            int taskSeqNum = taskTS.Task[0].TaskSeqNum;        
            taskTS = taskSvc.GetByID(relatedToFile, key1, key2, key3, taskSeqNum);
            */
            
           bool lProposedComplete = true;
           string cMessage = "";     

           //prepare update
           taskTS.Task[0].Complete = true;
           taskTS.Task[0].ReasonCode = "Next";
           taskTS.Task[0].NextTaskSeq = 10;
           taskTS.Task[0].NextStage = "OPPORTUNITY";
           taskTS.Task[0].NextTaskList = "10`Hold~30`Order Complete";
           taskTS.Task[0].TaskCompletePasswordIsValid = true;
           taskTS.Task[0].RowMod = "U";       
           taskSvc.ChangeComplete(ref taskTS, lProposedComplete, out cMessage);
           
           //prepare update
           taskTS.Task[0].Complete = true;
           taskTS.Task[0].ReasonCode = "Next";
           taskTS.Task[0].NextTaskSeq = 10;
           taskTS.Task[0].NextStage = "OPPORTUNITY";
           taskTS.Task[0].NextTaskList = "10`Hold~30`Order Complete";
           taskTS.Task[0].TaskCompletePasswordIsValid = true;
           taskTS.Task[0].RowMod = "U";       
           taskSvc.Update(ref taskTS);
        }
      }
      queue.Clear();
    }

It’s getting through the Quote Update on the first record, then dumping an exception in the System Monitor saying “The table ttTask has more than one record”

Ok I got it working, it executes and changes the task of all the identified entries with this code:

Summary
var Parameters = new Ice.Core.TaskParameterInformation(this.Db, taskNum);
var custNum = Convert.ToInt32(Parameters.GetCharacterValue("TxtParam1"));
var followUpDate = Convert.ToDateTime(Parameters.GetDateValue("DatParam1"));//looks misspelled but isn't

Dictionary<int, DateTime?> queue = new Dictionary<int, DateTime?>();
foreach(var quote in (from q in Db.QuoteHed.With(LockHint.NoLock)
                    where
                      q.Company == Session.CompanyID 
                      && q.CustNum == custNum
                      && q.Quoted == false
                      && q.QuoteClosed == false
                      && q.ActiveTaskID == "ACTV"                   
                    select new {
                      q.QuoteNum, q.FollowUpDate
                      }
                    ))
                  
                    /*Start Iteration Action*/
                    
                    {
                      if(quote != null)
                      {
                        queue.Add(quote.QuoteNum, quote.FollowUpDate);
                      }
                    };
                    
                    /*End Interation Action*/


//TEST WITH SINGLE QUOTE 
//queue.Add(59688, DateTime.Today);

//START DEBUG        
       string path = @"\\dev01\C$\Temp\BPMDebugger.txt";
       string content = JsonConvert.SerializeObject(queue, Formatting.Indented);
       if(!File.Exists(path))
       {
          File.WriteAllText(path, content + Environment.NewLine);
       }      
       File.AppendAllText(path, Environment.NewLine + content); 
//END DEBUG 
if(queue.Any())
{
  foreach(var row in queue)
  {
    using(Erp.Contracts.QuoteSvcContract quoteSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db))
    {
      //update the QuoteHed.ResponsibleFor_c and QuoteHed.Character03 to "ASC" and "COVID-19 Hold"
      //set QuoteHed.FollowUpDate to either the user input follow up date or if it has one, leave it alone. 
      var quoteTS = quoteSvc.GetByID(row.Key);
      quoteTS.QuoteHed[0]["ResponsibleFor_c"] = "ASC";
      quoteTS.QuoteHed[0]["Character03"] = "COVID-19 Hold";
      quoteTS.QuoteHed[0].RowMod = "U";
      if(row.Value != null)
        {
          quoteTS.QuoteHed[0].FollowUpDate = row.Value;
        }
      else
        {
          quoteTS.QuoteHed[0].FollowUpDate = followUpDate;
        }
      quoteSvc.Update(ref quoteTS);       
    }
    //Update the task from "Active" to "Hold"    
     
 
    using(Erp.Contracts.TaskSvcContract taskSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db))
    {
       string whereClause = string.Format("Key1 = '{0}' AND RelatedToFile = 'QuoteHed' BY TaskSeqNum DESC", row.Key.ToString());
       int pageSize = 0;
       int absolutePage = 0;
       bool morePages = false;
      
       var taskTS = taskSvc.GetRows(whereClause, "", pageSize, absolutePage, out morePages);

       //use the top row to get the specific task      
       string relatedToFile = "QuoteHed";
       string key1 = row.Key.ToString();
       string key2 = "";
       string key3 = "";
       int taskSeqNum = taskTS.Task[0].TaskSeqNum;        
       taskTS = taskSvc.GetByID(relatedToFile, key1, key2, key3, taskSeqNum);        
        
       bool lProposedComplete = true;
       string cMessage = "";     

       //prepare ts for ChangeComplete
       taskTS.Task[0].Complete = true;
       taskTS.Task[0].ReasonCode = "Next";
       taskTS.Task[0].NextTaskSeq = 10;
       taskTS.Task[0].NextStage = "OPPORTUNITY";
       taskTS.Task[0].NextTaskList = "10`Hold~30`Order Complete";
       taskTS.Task[0].TaskCompletePasswordIsValid = true;
       taskTS.Task[0].RowMod = "U";       
       taskSvc.ChangeComplete(ref taskTS, lProposedComplete, out cMessage);
       
       //prepare ts for Update
       taskTS.Task[0].Complete = true;
       taskTS.Task[0].ReasonCode = "Next";
       taskTS.Task[0].NextTaskSeq = 10;
       taskTS.Task[0].NextStage = "OPPORTUNITY";
       taskTS.Task[0].NextTaskList = "10`Hold~30`Order Complete";
       taskTS.Task[0].TaskCompletePasswordIsValid = true;
       taskTS.Task[0].RowMod = "U";  
       taskSvc.Update(ref taskTS);  
    }
  }   
}
queue.Clear();

If it finds and updates a single record, no error appears.

With multiple items in the queue, even though it successfully updates the entries, I get an exception in the System Monitor saying “This is a duplicate entry of an existing record”. Any idea where it’s coming from? I’m sure its something small at this point.

Got it working, just needed to take out the method before the Task.Update method is called. That’s probably a UI specific one, at least in this simple case. If it were more complex of a task situation, would likely need to call that.

var parameters = new Ice.Core.TaskParameterInformation(this.Db, taskNum);
var custNum = Convert.ToInt32(parameters.GetCharacterValue("TxtParam1"));
var followUpDate = Convert.ToDateTime(parameters.GetDateValue("DatParam1"));//looks misspelled but isn't

Dictionary<int, DateTime?> queue = new Dictionary<int, DateTime?>();
foreach(var quote in (from q in Db.QuoteHed.With(LockHint.NoLock)
                    where
                      q.Company == Session.CompanyID 
                      && q.CustNum == custNum
                      && q.Quoted == false
                      && q.QuoteClosed == false
                      && q.ActiveTaskID == "ACTV"                   
                    select new {
                      q.QuoteNum, q.FollowUpDate
                      }
                    ))                  
                    /*Start Iteration Action*/                    
                    {
                      if(quote != null)
                      {
                        queue.Add(quote.QuoteNum, quote.FollowUpDate);
                      }
                    };                    
                    /*End Interation Action*/
//TEST WITH SINGLE QUOTE 
//queue.Add(59688, DateTime.Today);

//START DEBUG   
/*
 string path = @"\\dev01\C$\Temp\BPMDebugger.txt";
 string content = JsonConvert.SerializeObject(queue, Formatting.Indented);
 if(!File.Exists(path))
 {
    File.WriteAllText(path, content + Environment.NewLine);
 }      
 File.AppendAllText(path, Environment.NewLine + content); 
*/
//END DEBUG 

if(queue.Any())
{
  foreach(var row in queue)
  {
    using(Erp.Contracts.QuoteSvcContract quoteSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db))
    {
      //update the QuoteHed.ResponsibleFor_c and QuoteHed.Character03 to "ASC" and "COVID-19 Hold"
      //set QuoteHed.FollowUpDate to either the user input follow up date or if it has one, leave it alone. 
      var quoteTS = quoteSvc.GetByID(row.Key);
      quoteTS.QuoteHed[0]["ResponsibleFor_c"] = "ASC";
      quoteTS.QuoteHed[0]["Character03"] = "COVID-19 Hold";
      quoteTS.QuoteHed[0].RowMod = "U";
      if(row.Value != null)
        {
          quoteTS.QuoteHed[0].FollowUpDate = row.Value;
        }
      else
        {
          quoteTS.QuoteHed[0].FollowUpDate = followUpDate;
        }
      quoteSvc.Update(ref quoteTS);

      //Update the task from "Active" to "Hold"    
     
 
      using(Erp.Contracts.TaskSvcContract taskSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.TaskSvcContract>(Db))
      {
         string whereClause = string.Format("Key1 = '{0}' AND RelatedToFile = 'QuoteHed' BY TaskSeqNum DESC", row.Key.ToString());
         int pageSize = 0;
         int absolutePage = 0;
         bool morePages = false;
        
         var taskTS = taskSvc.GetRows(whereClause, "", pageSize, absolutePage, out morePages);
  
         //use the top row to get the specific task      
         string relatedToFile = "QuoteHed";
         string key1 = row.Key.ToString();
         string key2 = "";
         string key3 = "";
         int taskSeqNum = taskTS.Task[0].TaskSeqNum;        
         taskTS = taskSvc.GetByID(relatedToFile, key1, key2, key3, taskSeqNum);        
          
         //prepare ts for Update
         taskTS.Task[0].Complete = true;
         taskTS.Task[0].ReasonCode = "Next";
         taskTS.Task[0].NextTaskSeq = 10;
         taskTS.Task[0].NextStage = "OPPORTUNITY";
         taskTS.Task[0].NextTaskList = "10`Hold~30`Order Complete";
         taskTS.Task[0].TaskCompletePasswordIsValid = true;
         taskTS.Task[0].RowMod = "U";  
         taskSvc.Update(ref taskTS);  
      }      
    }    
   }   
}
queue.Clear();