Mass Issue BPM (data directive) Error Help

Hi, I am frustrated with an error I am getting in the server event viewer when testing a new customization I am working through.

Long story short I need to properly trigger mass issue to MFG for job mtl’s when it’s released. I am currently getting the error “Specified Cast is Invalid.” but I cannot find anywhere that I am casting any data types and I get no syntax errors in the editor. I know I am missing something but can’t seem to find it…

here is my code:

string c = callContextBpmData.ShortChar01.ToString();
string j = callContextBpmData.ShortChar02.ToString();
callContextBpmData.ShortChar01 = "";
callContextBpmData.ShortChar02 = "";

using (var m = ServiceRenderer.GetService<Erp.Contracts.MassIssueToMfgSvcContract>(Db)) {
  
  try {
    
    var jh = Db.JobHead.Where(jhRow => jhRow.Company == c && jhRow.JobNum == j).FirstOrDefault();
    var jm = Db.JobMtl.Where(jmRow => jmRow.Company == jh.Company && jmRow.JobNum == jh.JobNum);
    var ja = Db.JobAsmbl.Where(jaRow => jaRow.Company == jh.Company && jaRow.JobNum == jh.JobNum);
    
    
    Erp.Tablesets.MassIssueInputTableset mInTs = new Erp.Tablesets.MassIssueInputTableset();
    Erp.Tablesets.MassIssueToMfgTableset mTs = new Erp.Tablesets.MassIssueToMfgTableset();
    
    string bs = "";
    bool f = false;
    string pcView = "Open";
    string ipSysRowId = jh.SysRowID.ToString();
    System.DateTime tranDate = System.DateTime.Today;
    
    m.GetNewMassIssueInput(ref mInTs, f);
    
    var mInJRow = mInTs.GetTable("MassIssueInputJob").NewRow();
    mInJRow["Company"] = c;
    mInJRow["JobNum"] = j;
    mInJRow["IsReturn"] = f;
    mInJRow["dummyKeyField"] = "";
    mInJRow["SysRowID"] = jh.SysRowID;
    mInJRow["RowMod"] = "A";
    
    mInTs.GetTable("MassIssueInputJob").Add(mInJRow);
    
    m.OnChangeJobNum(j,ref mInTs);
    
    mInJRow["RowMod"] = "";
    
    //mInTs.GetTable("MassIssueInputJob").Clear();
    //mInTs.GetTable("MassIssueInputJob").Add(mInJRow);
    
    foreach (var jaRow in ja) {
    
      var mInRow = mInTs.GetTable("MassIssueInput").NewRow();
      
      mInRow["TranDate"] = tranDate;
      mInRow["JobNum"] = jaRow.JobNum;
      mInRow["JobType"] = jh.JobType;
      mInRow["AssemblySeq"] = jaRow.AssemblySeq;
      mInRow["IncludeSubassemblies"] = f;
      mInRow["IncludeSubassembliesOverrun"] = f;
      mInRow["PartNumJH"] = jh.PartNum;
      mInRow["PartDescJH"] = "";
      mInRow["CallNum"] = jaRow.CallNum;
      mInRow["CallLine"] = jaRow.CallLine;
      mInRow["PartNumAsm"] = jaRow.PartNum;
      mInRow["PartDescAsm"] = jaRow.Description;
      mInRow["Company"] = jaRow.Company;
      mInRow["JobDescJH"] = jh.PartDescription;
      mInRow["IUM"] = jaRow.IUM;
      mInRow["AssemblyQty"] = jaRow.RequiredQty;
      mInRow["dummyKeyField"] = "";
      mInRow["FSCallhdInvoiced"] = f;
      mInRow["RequiredQty"] = jaRow.RequiredQty;
      mInRow["ReadOnly"] = f;
      mInRow["PartNum"] = jaRow.PartNum;
      mInRow["Description"] = jaRow.Description;
      mInRow["IsReturn"] = f;
      mInRow["AttributeSetDescription"] = "";
      mInRow["AttributeSetID"] = jaRow.AttributeSetID;
      mInRow["AttributeSetShortDescription"] = "";
      mInRow["SysRowID"] = jaRow.SysRowID;
      mInRow["RowMod"] = "U";
      
      mInTs.GetTable("MassIssueInput").Add(mInRow);
    }
    
    
    mTs = m.BuildMassIssueBrowse(ref mInTs,ipSysRowId,out bs);
    
    //FIRST create false Seq 0 row using JobAsm row, then hit each JobMtl seq below that using JobMtl Rows
    foreach (var jaRow in ja) {
    
      var mIsRow = mTs.GetTable("MassIssue").NewRow();
      mIsRow["AssemblySeq"] = jaRow.AssemblySeq;
      mIsRow["SeqNum"] = 0;
      mIsRow["Parent"] = 0;
      mIsRow["PartNum"] = jaRow.PartNum;
      mIsRow["RevisionNum"] = "";
      mIsRow["Description"] = "";
      mIsRow["QtyRequired"] = 0;
      mIsRow["SaveReq"] = jaRow.RequiredQty;
      mIsRow["QtyRequiredMtl"] = 0;
      mIsRow["QtyIssued"] = 0;
      mIsRow["ProdQty"] = jh.ProdQty;
      mIsRow["PullQty"] = 0;
      mIsRow["QtyPer"] = jaRow.QtyPer;
      mIsRow["OverRunQty"] = 0;
      mIsRow["BuildQty"] = jh.ProdQty;
      mIsRow["RemPullQty"] = 0;
      mIsRow["EstScrapType"] = "";
      mIsRow["EstScrap"] = 0;
      mIsRow["FixedQty"] = f;
      mIsRow["Warehouse"] = "";
      mIsRow["BinNum"] = "";
      mIsRow["ToWarehouse"] = "MFG";
      mIsRow["ToBinNum"] = "";
      mIsRow["IssuedComplete"] = jaRow.IssuedComplete;
      mIsRow["CmpFlagOrig"] = f;
      mIsRow["JobComplete"] = jh.JobComplete;
      mIsRow["PrevIssued"] = 0;
      mIsRow["SaveIssued"] = 0;
      mIsRow["DimTrack"] = f;
      mIsRow["LotTrack"] = f;
      mIsRow["LotNum"] = "";
      mIsRow["UnitMeasure"] = "EA";
      mIsRow["TranType"] = "STK-ASM";
      mIsRow["TranClass"] = "I";
      mIsRow["TranReference"] = "Mass Issued by manager.";
      mIsRow["InventoryTrans"] = true;
      mIsRow["EntryPerson"] = "manager";
      mIsRow["CostMethod"] = "A";
      mIsRow["IsPart"] = f;
      mIsRow["JobNum"] = j;
      mIsRow["TranDate"] = tranDate; 
      mIsRow["JobType"] = jh.JobType;
      mIsRow["CallNum"] = 0;
      mIsRow["CallLine"] = 0;
      mIsRow["IncludeSubassemblies"] = f;
      mIsRow["IncludeSubassembliesOverrun"] = f;
      mIsRow["Company"] = c;
      mIsRow["dummyKeyField"] = "";
      mIsRow["StopAction"] = "None";
      //mIsRow["StockQty"] = 0;
      mIsRow["OKToIssue"] = f;
      mIsRow["JustQtyIssued"] = 0;
      mIsRow["ThisTransaction"] = 0;
      mIsRow["RelatedOperSort"] = 0;
      mIsRow["AbleToIssue"] = f;
      mIsRow["IsReturn"] = f;
      mIsRow["DispNumberOfPieces"] = 0;
      mIsRow["SysRowID"] = ipSysRowId;
      mIsRow["RowMod"] = "";
      mTs.GetTable("MassIssue").Add(mIsRow);
      
      foreach (var jmRow in Db.JobMtl.Where(jmR => jmR.Company == jaRow.Company && jmR.JobNum == jaRow.JobNum && jmR.AssemblySeq == jaRow.AssemblySeq)) {
        
        if (jmRow.IssuedComplete = false) {
          var pbRow = Db.PartBin.Where(pbR => pbR.Company == jmRow.Company && pbR.PartNum == jmRow.PartNum && pbR.WarehouseCode == jmRow.WarehouseCode).FirstOrDefault();
          
          var mIsMtlRow = mTs.GetTable("MassIssue").NewRow();
          mIsMtlRow["AssemblySeq"] = jaRow.AssemblySeq;
          mIsMtlRow["SeqNum"] = jmRow.MtlSeq;
          mIsMtlRow["Parent"] = 0;
          mIsMtlRow["PartNum"] = jmRow.PartNum;
          mIsMtlRow["RevisionNum"] = jmRow.RevisionNum;
          mIsMtlRow["Description"] = jmRow.Description;
          mIsMtlRow["QtyRequired"] = jmRow.RequiredQty;
          mIsMtlRow["SaveReq"] = jmRow.RequiredQty;
          mIsMtlRow["QtyRequiredMtl"] = jmRow.RequiredQty;
          mIsMtlRow["QtyIssued"] = jmRow.IssuedQty;
          mIsMtlRow["ProdQty"] = 0;
          mIsMtlRow["PullQty"] = 0;
          mIsMtlRow["QtyPer"] = jmRow.QtyPer;
          mIsMtlRow["OverRunQty"] = 0;
          mIsMtlRow["BuildQty"] = 0;
          mIsMtlRow["RemPullQty"] = 0;
          mIsMtlRow["EstScrapType"] = jmRow.EstScrapType;
          mIsMtlRow["EstScrap"] = jmRow.EstScrap;
          mIsMtlRow["FixedQty"] = f;
          mIsMtlRow["Warehouse"] = jmRow.WarehouseCode;
          mIsMtlRow["BinNum"] = pbRow.BinNum;
          //RESUME WORK HERE: FIGURE OUT WAREHOUSE AND BIN DATA LOCATIONS?!
          //mIsMtlRow["ToWarehouse"] = "MFG";
          //mIsMtlRow["ToBinNum"] = "MFG";
          mIsMtlRow["IssuedComplete"] = jaRow.IssuedComplete;
          mIsMtlRow["CmpFlagOrig"] = f;
          mIsMtlRow["JobComplete"] = jh.JobComplete;
          mIsMtlRow["PrevIssued"] = 0;
          mIsMtlRow["SaveIssued"] = 0;
          mIsMtlRow["DimTrack"] = f;
          mIsMtlRow["LotTrack"] = f;
          mIsMtlRow["LotNum"] = "";
          mIsMtlRow["UnitMeasure"] = jmRow.BaseUOM;
          mIsMtlRow["TranType"] = "STK-MTL";
          mIsMtlRow["TranClass"] = "I";
          mIsMtlRow["TranReference"] = "Mass Issued by manager.";
          mIsMtlRow["InventoryTrans"] = true;
          mIsMtlRow["EntryPerson"] = "manager";
          mIsMtlRow["CostMethod"] = "A";
          mIsMtlRow["IsPart"] = true;
          mIsMtlRow["JobNum"] = j;
          mIsMtlRow["TranDate"] = tranDate;
          mIsMtlRow["JobType"] = jh.JobType;
          //mIsMtlRow["CallNum"] = 0;
          //mIsMtlRow["CallLine"] = 0;
          mIsMtlRow["IncludeSubassemblies"] = f;
          mIsMtlRow["IncludeSubassembliesOverrun"] = f;
          mIsMtlRow["Company"] = c;
          mIsMtlRow["dummyKeyField"] = "";
          mIsMtlRow["StopAction"] = "None";
          //mIsMtlRow["StockQty"] = 0;
          mIsMtlRow["OKToIssue"] = true;
          mIsMtlRow["JustQtyIssued"] = jmRow.RequiredQty - jmRow.IssuedQty;
          mIsMtlRow["ThisTransaction"] = jmRow.RequiredQty - jmRow.IssuedQty;
          mIsMtlRow["ActTransUOM"] = jmRow.BaseUOM;
          mIsMtlRow["StockUOM"] = jmRow.BaseUOM;
          //mIsMtlRow["RelatedOperSort"] = 0;
          mIsMtlRow["AbleToIssue"] = f;
          mIsMtlRow["IsReturn"] = f;
          //mIsMtlRow["DispNumberOfPieces"] = 0;
          //mIsMtlRow["SysRowID"] = //ipSysRowId;
          mIsMtlRow["RowMod"] = "U";
          
          mTs.GetTable("MassIssue").Add(mIsMtlRow);
        }
      }
    }
    
    m.IssueAll(pcView,ref mTs);
    
    m.NegativeStockCheck(j, ref mTs, out bs, out bs);
    
    //Set AbleToIssue to true now only for JobMtl's (not assembly row..... per trace log.)
    foreach (var tRow in mTs.MassIssue.ToList()) {
      if (tRow.SeqNum.ToString() != "0") {
        tRow.AbleToIssue = true;
        tRow.RowMod = "U";
      }
    }
    
    var ht = new System.Collections.Hashtable();
    
    m.PrePerformMassIssueHT(ref mTs, ref ht);
    
    m.PerformMassIssue(j, tranDate, 0, f, true, ref mTs, out bs);
    
  }
  catch (Exception e) {
    string msg =e.Message;
    Ice.Diagnostics.Log.WriteEntry(msg);
  }
  
  m.Dispose();
}

If anyone cares to assist, I am also wondering-- HOW do I know which fields specifically need to be filled out in these tablesets that feed into the BO methods versus fields I can leave empty/disregard? (aside from the obvious ones).

Thanks for reading,
Dylan.

You’re not getting any errors in the editor because you are using dynamic binding to the column names.

You would if you weren’t.

Give me a minute and I can show you how to go about fixing it.

1 Like

Great point, I hadn’t thought about that regarding the editor and the dynamic column binding. You are a gentleman and a scholar, thank you so much for the response. I’ll look into that.

1 Like
  //using Erp.Tablesets;

  MassIssueInputTableset mInTs = new MassIssueInputTableset();
    
  MassIssueInputJobRow mInJRow = (MassIssueInputJobRow)mInTs.MassIssueInputJob.NewRow();
  
    mInJRow.Company = c;
    mInJRow.JobNum = j;
    mInJRow.IsReturn = f;
    mInJRow.dummyKeyField = "";
    mInJRow.SysRowID = jh.SysRowID;
    mInJRow.RowMod = "A";

Start converting your code over to use it like this. Much more maintainable and most errors will be caught at compile time.

Not to be nitpicky, but take some hard learned advice from a man who has been burned:

Use very descriptive variable names. c, j, jh will come back to bite you.

1 Like

Will do. I’ll let you know what I find. Thank you very much.

1 Like

Haha-- understood. This code is going to get neat rewritten by the time I get it working, I start with basic stuff and little to no comments but make everything user friendly once the meat and potatoes even exist.

1 Like

That’s fine, I have my own little process too. You just never know.
I’d rather risk offending someone a wee bit, than them have trouble down the line.

:slight_smile:

1 Like

I totally agree! Thank you for your help and thoughtful insights.

Wow. So after switching the dynamic column binding to explicit I now see that every single instance of calling on columns is producing an error. I guess the NewRow() method is just creating an IceRow and not a table row like I thought… This list of errors is hilariously bad now that I’ve converted it xD I will not make this mistake again! Thanks again Kevin.

Now time to figure out what the heck I did wrong here haha.

Yes, you need to add them to the datasets.

Ex:

mInTs.MassIssueInput.Add(mInJRow);

So its not that part that I am confused about-- I have that in the code. Its the actual creation of the correct tableset row before setting the values and adding it.

I only took a very high level look at your code. I’ve got a meeting but I might can peruse it when I’m done.

1 Like

Wait I got it!!!

int i = 0;
    foreach (var jaRow in ja) {
    
      mInTs.MassIssueInput.NewRow();
      var mInRow = mInTs.MassIssueInput[i];
      mInRow.TranDate = tranDate;
      mInRow.JobNum = jaRow.JobNum;
      mInRow.JobType = jh.JobType;
      mInRow.AssemblySeq = jaRow.AssemblySeq;
      mInRow.IncludeSubassemblies = f;
      mInRow.IncludeSubassembliesOverrun = f;
      mInRow.PartNumJH = jh.PartNum;
      mInRow.PartDescJH = "";
      mInRow.CallNum = jaRow.CallNum;
      mInRow.CallLine = jaRow.CallLine;
      mInRow.PartNumAsm = jaRow.PartNum;
      mInRow.PartDescAsm = jaRow.Description;
      mInRow.Company = jaRow.Company;
      mInRow.JobDescJH = jh.PartDescription;
      mInRow.IUM = jaRow.IUM;
      mInRow.AssemblyQty = jaRow.RequiredQty;
      //mInRow.dummyKeyField = "";
      mInRow.FSCallhdInvoiced = f;
      mInRow.RequiredQty = jaRow.RequiredQty;
      mInRow.ReadOnly = f;
      mInRow.PartNum = jaRow.PartNum;
      mInRow.Description = jaRow.Description;
      mInRow.IsReturn = f;
      mInRow.AttributeSetDescription = "";
      mInRow.AttributeSetID = jaRow.AttributeSetID;
      mInRow.AttributeSetShortDescription = "";
      //mInRow.SysRowID = jaRow.SysRowID;
      mInRow.RowMod = "U";
      //mInTs.MassIssueInput.Add(mInRow);
      i++;
    }

Now that I am getting the proper errors I can actually figure this thing out. You’re a huge help my friend!

Ok now go clean your room young man.

2 Likes

Well, no matter what I have tried it all came back to my original error before all this work which was “No Action Taken, No Qty To Issue”. This particular BO with it’s methods and tablesets does not seem to behave in an expected way compared to other BO’s I have worked with. I am definitely missing something here. I searched online for other posts about this and only found one gentlemen’s thread ended with the same error-- not sure if there is a way around it.

Here’s where I left off for now until my brain stops hurting lol:

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
string c = callContextBpmData.ShortChar01.ToString();
string j = callContextBpmData.ShortChar02.ToString();
callContextBpmData.ShortChar01 = "";
callContextBpmData.ShortChar02 = "";

using (var m = ServiceRenderer.GetService<Erp.Contracts.MassIssueToMfgSvcContract>(Db)) {
  
  try {
    
    var jh = Db.JobHead.Where(jhRow => jhRow.Company == c && jhRow.JobNum == j).FirstOrDefault();
    //var jm = Db.JobMtl.Where(jmRow => jmRow.Company == jh.Company && jmRow.JobNum == jh.JobNum);
    //var ja = Db.JobAsmbl.Where(jaRow => jaRow.Company == jh.Company && jaRow.JobNum == jh.JobNum);
    
    Erp.Tablesets.MassIssueInputTableset mInTs = new Erp.Tablesets.MassIssueInputTableset();
    Erp.Tablesets.MassIssueToMfgTableset mTs = new Erp.Tablesets.MassIssueToMfgTableset();
    
    string bs = "";
    bool f = false;
    string pcView = "Open";
    string ipSysRowId = jh.SysRowID.ToString();
    System.DateTime tranDate = System.DateTime.Today;
    
    m.GetNewMassIssueInput(ref mInTs, f);
    
    var newRowMIIJ = mInTs.MassIssueInputJob.NewRow();
    mInTs.MassIssueInputJob.Add(newRowMIIJ);
    mInTs.MassIssueInputJob[0].Company = c;
    mInTs.MassIssueInputJob[0].JobNum = j;
    mInTs.MassIssueInputJob[0].IsReturn = f;
    //mInTs.MassIssueInputJob[0].dummyKeyField = "";
    mInTs.MassIssueInputJob[0].SysRowID = jh.SysRowID;
    mInTs.MassIssueInputJob[0].RowMod = "A";
    
    m.OnChangeJobNum(j,ref mInTs);
    
    
    mTs = m.BuildMassIssueBrowse(ref mInTs,ipSysRowId,out bs);

    m.IssueAll(pcView,ref mTs);
    
    m.NegativeStockCheck(j, ref mTs, out bs, out bs);
    
    var ht = new System.Collections.Hashtable();
    
    m.PrePerformMassIssueHT(ref mTs, ref ht);
    
    m.PerformMassIssue(j, tranDate, 0, f, true, ref mTs, out bs);
    
  }
  catch (Exception e) {
    string msg = e.Message.ToString();
    Ice.Diagnostics.Log.WriteEntry(msg);
    
    // setup message box parameters: mbp
    var mbp1 = msg;  // text to appear on popup
    var mbp2 = Ice.Common.BusinessObjectMessageType.Information; //req'd don't change
    var mbp3 = Ice.Bpm.InfoMessageDisplayMode.Individual;
    var mbp4 = ""; // text that appears in popup Details button ->program field
    var mbp5 = ""; // text that appears in popup Details button ->method field

    // call popup message
    this.PublishInfoMessage(mbp1, mbp2, mbp3, mbp4, mbp5);
  }
  
  m.Dispose();
}

Db.Validate();
txScope.Complete();
txScope.Dispose();
}

See if this get’s you closer. Untested, may have some mistakes:

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
    string company = callContextBpmData.ShortChar01.ToString();
    string jobNum = callContextBpmData.ShortChar02.ToString();
    callContextBpmData.ShortChar01 = "";
    callContextBpmData.ShortChar02 = "";
    
    using (var massIssueBO = ServiceRenderer.GetService<Erp.Contracts.MassIssueToMfgSvcContract>(Db))
    {
        try
        {
            string bs = "";
            string pcView = "Open";
            System.DateTime tranDate = System.DateTime.Today;
            
            bool isReturn = false;
            
            Erp.Tablesets.MassIssueInputTableset miInputTS = massIssueBO.GetMassIssueInputForJob(jobNum, isReturn);
            Erp.Tablesets.MassIssueToMfgTableset miMfgTS = new Erp.Tablesets.MassIssueToMfgTableset();
            
            
            string ipSysRowId = miInputTS.MassIssueInputJob.First().SysRowID.ToString(); //Gonna be something in this tableset, may have to dig. Best guess
            
            massIssueBO.OnChangeJobNum(jobNum, ref miInputTS);
            
            miMfgTS = massIssueBO.BuildMassIssueBrowse(ref miInputTS, ipSysRowId, out bs);
            
            massIssueBO.IssueAll(pcView, ref miMfgTS);
            
            massIssueBO.NegativeStockCheck(jobNum, ref miMfgTS, out bs, out bs);
            
            var ht = new System.Collections.Hashtable();
            
            massIssueBO.PrePerformMassIssueHT(ref miMfgTS, ref ht);
            
            bool materialComplete = false; //true ?
            massIssueBO.PerformMassIssue(jobNum, tranDate, 0, materialComplete, true, ref miMfgTS, out bs);
        }
        catch (Exception e)
        {
            string msg = e.Message.ToString();
            Ice.Diagnostics.Log.WriteEntry(msg);
            
            // setup message box parameters: mbp
            var mbp1 = msg;  // text to appear on popup
            var mbp2 = Ice.Common.BusinessObjectMessageType.Information; //req'd don't change
            var mbp3 = Ice.Bpm.InfoMessageDisplayMode.Individual;
            var mbp4 = ""; // text that appears in popup Details button ->program field
            var mbp5 = ""; // text that appears in popup Details button ->method field
            
            // call popup message
            this.PublishInfoMessage(mbp1, mbp2, mbp3, mbp4, mbp5);
        }
    }
    
    Db.Validate();
    txScope.Complete();
}
1 Like

OK. I got it working through some luck and the help of a fellow Epi User Helper! I am modifying the code to clean it up now and will post the results for future users in need of assistance on this.

Here is a more final version of the working code. Keep in mind this is being done in a data directive (Standard), and other users may have different needs throughout the processes being done here.

//Set the transaction scope variable txScope, which completes at the end of the code and ensures the execution and final termination of this transaction.
using (var txScope = Erp.ErpContext.CreateDefaultTransactionScope())
{
  //Loop through each updated JobHead row (in order to handle jobs created and released via wizard, when its more than 1 job).
  foreach (var ttjhRow in ttJobHead.Where(r => r.RowMod != "")) {
    string company = ttjhRow.Company;
    string jobNum = ttjhRow.JobNum;
    
    //Create the Mass Issue to MFG BO Service Contract. "using (...){...}" to ensure termination of code block upon Dispose().
    using (var massIssue = ServiceRenderer.GetService<Erp.Contracts.MassIssueToMfgSvcContract>(Db)) {
      //Use try {} catch {} to handle any exceptions (errors).
      try {
      //Get JobHead row from Database using company and jobNum set above.
      var job = Db.JobHead.Where(jhRow => jhRow.Company == company && jhRow.JobNum == jobNum).FirstOrDefault();
      
      //Create parameter variables that will be fed to the BO Methods below.
      string ipSysRowId = Convert.ToString(job.SysRowID);
      string pcMessage;
      string pcQuestion;
      string pcError;
      System.Collections.Hashtable htPrePerform = new System.Collections.Hashtable();
      DateTime tranDate = DateTime.Today;
  
  
      //Create MassIssueInputTableset.
      Erp.Tablesets.MassIssueInputTableset massIssueInputTs = new Erp.Tablesets.MassIssueInputTableset();
      
      //Call GetNewMassIssueInput() BO method. Feed the Tableset created above as parameter 1. 
      //Parameter 2 "isReturn" set to False to indicate that this new Mass Issue is NOT a return.
      massIssue.GetNewMassIssueInput(ref massIssueInputTs, false);
      
      //Call OnChangeJobNum() BO method. Feed JobNum to parameter 1.
      //Feed MassIssueInputTableset with "ref" keyword to parameter 2.
      massIssue.OnChangeJobNum(jobNum, ref massIssueInputTs);
      
      //Referencing ROW 0 ("[0]") of the MassIssueInput table in the MassIssueInputTableset:
      //Set "IncludeSubassemblies" (true OR false per your need).
      //Set RowMod = "U" for Updated.
      massIssueInputTs.MassIssueInput[0].IncludeSubassemblies = true;
      massIssueInputTs.MassIssueInput[0].RowMod = "U";
      
      //Create the MassIssueToMfg Tableset with the data returned from the BuildMassIssueBrowse() method. 
      //Feed MassIssueInputTableset to parameter 1 with "ref" keyword.
      //Feeds SysRowId from "[0]" row in MassIssueInputTableset.MassIssueInput table above to parameter 2.
      //Feed "pcMessage" (blank string) to parameter 3 with "out" keyword.
      Erp.Tablesets.MassIssueToMfgTableset massIssueToMfgTs = massIssue.BuildMassIssueBrowse(ref massIssueInputTs, Convert.ToString(massIssueInputTs.MassIssueInput[0].SysRowID), out pcMessage);
  
      //Loop through rows existing in MassIssueToMfgTableset.MassIssue table:
      //Set RowMod = "U" on any rows where current OnHandQty exists for PartNum to issue.
      foreach (var row in massIssueToMfgTs.MassIssue)
      {
        //***if() statement below checking OnHandQty negative or 0.***
        //***"continue;" will exit the loop and therefore not update those rows.***
        //if ((decimal)row["StockQty"] <= 0) continue;
        
        //Uncomment the above if() statement if you want to NOT ISSUE when OnHandQty <= 0.
        row.RowMod = "U";
      }
      
      //Call the IssueAll() BO method:
      //Feed string "Open" to the "pcView" parameter 1 to indicate that the IssueAll() method will execute on open materials in this BOM.
      //Feed the MassIssueToMfgTableset from above to parameter 2 with "ref" keyword.
      massIssue.IssueAll("Open", ref massIssueToMfgTs);
      
      //Create hasTrans boolean variable as False. (Used below as a check to exit method).
      bool hasTrans = false;
      
      //Loop through MassIssueToMfgTableset.MassIssue table:
      //Set fields and RowMod on rows (representing materials) to Issue.
      foreach (var row in massIssueToMfgTs.MassIssue)
      {
        //***The if() statement below will exit the loop and disregard materials with nothing left to issue. This prevents an exception/error in these cases.***
        if ((decimal)row["ThisTransaction"] <= 0) continue;
        
        row.OKToIssue = true;
        row.JustQtyIssued = row.ThisTransaction;
        row.RowMod = "U";
        hasTrans = true;
        
        //Use code below (or similar UD table) if you want to track transactions done by this process.
        /*
        using (var txScope = Erp.ErpContext.CreateDefaultTransactionScope())
        {
        var ud05 = new Ice.Tables.UD05();
        Db.UD05.Insert(ud05);
        ud05.Company = Session.CompanyID;
        ud05.Key1 = "AutoIssuedParts";
        ud05.Key2 = tranDate.ToString("yyyyMMdd");
        ud05.Key3 = row["PartNum"].ToString();
        ud05.Key4 = tranDate.ToString("HHmmssfffzz");
        ud05.Key5 = Guid.NewGuid().ToString();
        ud05.ShortChar01 = row["JobNum"].ToString();
        ud05.Number01 = (int) row["AssemblySeq"];
        ud05.Number02 = (decimal)row["ThisTransaction"]; //qty being issues; 
        ud05.Date01 = (DateTime)row["TranDate"]; //transaction date; 
        ud05.Date02 = DateTime.Now; //when we're inserting this record!;  
        //from whse & bin
        ud05.ShortChar02 = row["Warehouse"].ToString();
        ud05.ShortChar03 = row["BinNum"].ToString();
        //to whse & bin
        ud05.ShortChar04 = row["ToWarehouse"].ToString();
        ud05.ShortChar05 = row["ToBinNum"].ToString();
        Db.Validate();
        txScope.Complete();
        }
        */
      }
  
      //If nothing to issue - leave method; 
      if (!hasTrans) return;
  
      //Call NegativeStockCheck() BO Method:
      //Feed JobNum to parameter 1.
      //Feed MassIssueToMfgTableset to parameter 2 with "ref" keyword.
      //Feed pcQuestion and pcError (blank strings) to parameter 3 and 4 respectively with "out" keyword.
      massIssue.NegativeStockCheck(jobNum, ref massIssueToMfgTs, out pcQuestion, out pcError);
  
      //Set AbleToIssue & rowMod on any rows where qty exists in-stock to issue; 
      foreach (var row in massIssueToMfgTs.MassIssue)
      {
        //The if() statement below will exit the loop if qty in stock <= 0.
        //if ((decimal)row.JustQtyIssued <= 0) continue;
        row.TranReference = "PrevWageJob Mass Issued by manager.";
        row.AbleToIssue = true;
        row.RowMod = "U";
      }
      
      //Call PrePerformMassIssueHT() BO Method:
      //Feed MassIssueToMfgTableset to parameter 1 with "ref" keyword.
      //Feed empty Hashtable to parameter 2 with "ref" keyword.
      massIssue.PrePerformMassIssueHT(ref massIssueToMfgTs, ref htPrePerform);
      
      //Call PerformMassIssue() BO Method:
      //Feed JobNum to parameter 1.
      //Feed TranDate (today) to parameter 2.
      //"piCallNum" as parameter 3 = 0.
      //"piMaterialComplete" as parameter 4 = false.
      //"piNegStockCheckContinue" as parameter 5 = true.
      //Feed MassIssueToMfgTableset to parameter 6 with "ref" keyword.
      //Feed pcMessage blank string to parameter 7 with "out" keyword.
      massIssue.PerformMassIssue(jobNum, tranDate, 0, false, true, ref massIssueToMfgTs, out pcMessage);
      }
      catch (Exception e) {
      string msg = e.Message.ToString();
      
      //setup message box parameters: mbp
      var mbp1 = msg;  // text to appear on popup
      var mbp2 = Ice.Common.BusinessObjectMessageType.Information; //req'd don't change
      var mbp3 = Ice.Bpm.InfoMessageDisplayMode.Individual; //req'd don't change
      var mbp4 = "JobHead Standard Data Directive"; // text that appears in popup Details button ->program field
      var mbp5 = "In attempt to MassIssueToMfg PrevWageJob"; // text that appears in popup Details button ->method field
      msg = mbp4 + "\n" + mbp5 + "\n" + mbp1;
      
      //write error to server event viewer (Epicor App Server).
      Ice.Diagnostics.Log.WriteEntry(msg);
      
      //call popup message
      this.PublishInfoMessage(mbp1, mbp2, mbp3, mbp4, mbp5);
      }
      
      //Dispose of the MassIssueToMfg BO service contract, ending the execution of this block of code.
      massIssue.Dispose();
    } 
  }
  
  //Complete and dispose of the Transaction Scope to end the execution of this transaction.
  txScope.Complete();
  txScope.Dispose();
}

Special thanks and shoutout to epi user mjbest6288 [Matthew Best] for the assistance in providing the few pieces I was missing. Also thank you to klincecum [Kevin Lincecum] for putting me on a better programming path :stuck_out_tongue: and spending time assisting me through the chaos of the MassIssueToMfg methods!