Labor Detail created but not marking Operation as complete


I am trying to add a Data Directive BPM that creates a LaborDtl on a job when it is shipped to complete the final operation (and trigger the operation and material backflushes on that job). The code I have is at the bottom here, but I’ll explain how I arrived at it first.

I went through the process of manually creating the LaborDtl using the Time and Expense Entry screen with my trace on (including full datasets). It worked fine, the operation was marked as completed and the backflush processed. I then wrote the below code based on that trace, including each LaborImpl method that was triggered in the trace. I also compared the LaborTableset as it was returned from each method to what it looked like when it was passed to the next method, and made the same changes using set statements.

It compiles fine and gives no errors when it runs, and it creates and approves the LaborDtl as expected. It can be viewed in the Time and Expense Entry form and looks normal when compared to manually input one (including having Operation Complete checked) However, when I open the related job in Job Entry, that operation is not marked as complete and the backflush doesn’t take place. I can even recall and resubmit the LaborDtl through the Time and Expense Entry form and nothing happens (no errors and no changes).

Is anyone familiar with this able to give me any pointers? I’ve been banging my head against this for a few days and rewritten it three times, and it always gives me the same results.

string msg;
bool errorBool;
foreach(var jOper in JobOper)
      //Get Default Employee for operations
      var EmpBasic = (from EmpBasic_Row in Db.EmpBasic.With(LockHint.NoLock)
      where EmpBasic_Row.EmpID == jOper.OpCode && jOper.Company == EmpBasic_Row.Company
      select EmpBasic_Row).ToList();
      string empExpenseCode = "VICLAM"; //Default
      if(EmpBasic != null){
        //Get Expense Code
        empExpenseCode = EmpBasic[0].ExpenseCode;
      using(var laborBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.LaborSvcContract>(this.Db))
              //Find LaborHed and create new detail
              string whereClauseLaborHed = "EmployeeNum = '" + jOper.OpCode + "' AND PayrollDate = '" + DateTime.Now.ToString("MM/dd/yyyy") + "'";
              LaborTableset lds = laborBO.GetRowsCalendarView(whereClauseLaborHed, "ActiveTrans = 0", "", "", "", "", "", "", "", "", "", "", 0, 0, jOper.OpCode, DateTime.Now, DateTime.Now, out errorBool);
              laborBO.GetNewLaborDtlNoHdr(ref lds,jOper.OpCode, false, DateTime.Now, 0, DateTime.Now, jOper.EstProdHours);
              //Find added row
              int rowNum = 0;
              for(int i = 0; i < lds.LaborDtl.Count; i++){
                if (lds.LaborDtl[i].RowMod == "A"){
                  rowNum = i;
              //Follow update path in Time and Expense Entry Trace
              lds.LaborDtl[rowNum].DtClockIn = DateTime.Now;
              lds.LaborDtl[rowNum].DtClockOut = DateTime.Now;
              laborBO.DefaultJobNum(ref lds, jOper.JobNum);
              laborBO.LaborRateCalc(ref lds);
              laborBO.DefaultOprSeq(ref lds,jOper.OprSeq, out msg);
              laborBO.LaborRateCalc(ref lds);
              laborBO.DefaultLaborQty(ref lds, jOper.RunQty, out msg);
              lds.LaborDtl[rowNum].NewDifDateFlag = 2;
              laborBO.CheckWarnings(ref lds, out msg);
              laborBO.Update(ref lds);
              lds.LaborDtl[rowNum].RowMod = "U";
              laborBO.ValidateChargeRateForTimeType(ref lds, out msg);
              laborBO.SubmitForApproval(ref lds, false, out msg);

Does the back flush work when entered manually through Time and Expense entry?

Yes, it does on both the operation and materials. I do have to prompt it somehow - the way I’ve found is to open Job Closing and load up the relevant job, and just loading it seems to trigger the back flush.

Did you mention which table you are launching this from?

I didn’t - this is custom code in a Data Directive running on ICE.UD11. When a Customer Shipment is marked as Shipped, it writes a new line to the UD11 table with data indicating the event and the shipment number that triggered it. I did it like that so I could trigger the same code when a Transfer Shipment is created.

I ended up trying to do this a different way, issuing the material through code instead of relying on the backflush. I’ll include the code below. It seemed to be working, the material transactions were being created, but then I discovered that while the material was moving and it had a unit cost, the part transactions had no total cost.

You can see it in the image below. The top 6 rows are all my test autoissues, and the rest below that are issues I did manually to capture the events. They appear identical, except that the “Amount” column is 0 for the autoissued ones, even though the Unit Cost remains the same for all of them.

It strikes me as similar to the first issue I was experiencing, where the transaction is occurring but not all of the normal follow up changes are occurring. It makes me think I’m missing a call, but then I don’t know why it wouldn’t show up in my trace.

Does anyone have any experience issuing material through a Data Directive (or any automated process, I don’t mind changing it to a method directive or a customization).

Code is below.

foreach(var jMtl in JobMtl)
      using(var issueBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.IssueReturnSvcContract>(this.Db))
          //Find PlantWhse to get bin records
          string primBin = "BOARD"; //default board
          var PlantWhse = (from PlantWhse_Row in Db.PlantWhse.With(LockHint.NoLock)
                    where PlantWhse_Row.Company.ToString() == jMtl.Company.ToString() && PlantWhse_Row.Plant.ToString() == jMtl.Plant.ToString() && PlantWhse_Row.WarehouseCode.ToString() == jMtl.WarehouseCode.ToString()
                    select PlantWhse_Row).ToList();          
          if(PlantWhse != null){
            if(PlantWhse.Count > 0){
              primBin = PlantWhse[0].PrimBin;
          SelectedJobAsmblTableset ds1= new SelectedJobAsmblTableset();
          IssueReturnTableset issueReturnDs = new IssueReturnTableset();
          bool error;
          //issueReturnDs = issueBO.GetNewJobAsmblMultiple("STK-MTL", Guid.Empty, "IssueMaterial", ref ds1, out msg);
          //issueBO.GetNewIssueReturn("STK-MTL", Guid.NewGuid(), "IssueMaterial", ref issueReturnDs);  
          issueBO.GetNewIssueReturnToJob(jMtl.JobNum, jMtl.AssemblySeq, "STK-MTL", Guid.Empty, out msg, ref issueReturnDs);

          var newRow = issueReturnDs.IssueReturn[0];
          //** SET VALUES
          newRow.Company = jMtl.Company;
          newRow.TranDate = DateTime.Today;
          //newRow.FromJobNum = string.Empty;
          //newRow.FromAssemblySeq = string.Empty;
          //newRow.FromJobPartNum = string.Empty;
          //newRow.FromAssemblyPartNum = string.Empty;
          //newRow.FromJobSeqPartNum = string.Empty;
          //newRow.FromJobPartDesc = string.Empty;
          //newRow.FromAssemblyPartDesc = string.Empty;
          //newRow.FromJobPartDescription = string.Empty;
          newRow.TranType = "STK-MTL";
          newRow.DimConvFactor = 1;
          //newRow.FromJobPlant = string.Empty;
          //newRow.ToJobPlant = “MfgSys”;
          newRow.DummyKeyField = string.Empty;
          newRow.TreeDisplay = jMtl.JobNum + " : " + jMtl.AssemblySeq.ToString();
          newRow.ProcessID = "IssueMaterial";
          newRow.Plant = jMtl.Plant;
          newRow.TranReference = "Autoissued on shipment " + PackIDToReceive;
          //Default Values
          newRow.PartNum = jMtl.PartNum;
          newRow.TranQty = jMtl.RequiredQty;
          newRow.FromJobSeq = 0;
          newRow.DimCode = jMtl.BaseUOM;
          newRow.ReasonCode = string.Empty;
          newRow.OrderNum = 0;
          newRow.OrderLine = 0;
          newRow.OrderRel = 0;
          newRow.FromWarehouseCode = jMtl.WarehouseCode;
          newRow.FromBinNum = primBin;
          newRow.FromJobSeqPartDesc = string.Empty;
          //newRow.OnHandQty = 0;
          newRow.QtyRequired = jMtl.RequiredQty;
         // newRow.QtyPreviouslyIssued = 0;
          newRow.IssuedComplete = true;
          newRow.ToJobNum = jMtl.JobNum;
          newRow.ToAssemblySeq = jMtl.AssemblySeq;
          newRow.ToJobSeq = jMtl.MtlSeq;
          newRow.ToWarehouseCode = jMtl.WarehouseCode;
          newRow.ToBinNum = "RECEIVING";
          newRow.ToJobPartNum = string.Empty;
          newRow.ToAssemblyPartNum = string.Empty;
          newRow.ToJobSeqPartNum = string.Empty;
          newRow.ToJobPartDesc = string.Empty;
          newRow.ToAssemblyPartDesc = string.Empty;
          newRow.ToJobSeqPartDesc = string.Empty;
          newRow.ReasonType = string.Empty;
          newRow.FromAssemblyPartDescription = string.Empty;
          newRow.FromJobSeqPartDescription = string.Empty;
          newRow.ToJobPartDescription = string.Empty;
          newRow.ToAssemblyPartDescription = string.Empty;
          newRow.ToJobSeqPartDescription = string.Empty;
          newRow.SerialNoQty = 0;
          newRow.MtlQueueRowId = Guid.Empty;;
          newRow.InvAdjReason = string.Empty;
          newRow.DUM = jMtl.IUM;
          newRow.UM = jMtl.IUM;
          newRow.EnableToFields = false;
          newRow.EnableFromFields = true;
          newRow.RequirementUOM = jMtl.BaseUOM;
          newRow.RequirementQty = 0;
          newRow.EnableSN = false;
          newRow.SerialControlPlant = string.Empty;
          newRow.SerialControlPlantIsFromPlt = false;
          newRow.SerialControlPlant2 = string.Empty;
          newRow.TrackDimension = false;
          newRow.OnHandUM = jMtl.IUM;
          newRow.TranDocTypeID = string.Empty;
          newRow.TFOrdNum = string.Empty;
          newRow.TFOrdLine = 0;
          newRow.ReassignSNAsm = false;
          newRow.ReplenishDecreased = false;
          //newRow.EnablePCID = false;
          newRow.EnablePCIDGen = false;
          newRow.EnablePCIDPrint = false;
          newRow.PkgControlID = string.Empty;
          newRow.FromPCID = string.Empty;
          newRow.ToPCID = string.Empty;
          newRow.ToPCIDItemSeq = 0;
          newRow.FromPCIDItemSeq = 0;
          newRow.DimCodeDimCodeDescription = string.Empty;
          newRow.FromBinNumDescription = string.Empty;
          newRow.FromWarehouseCodeDescription = string.Empty;
          newRow.LotNumPartLotDescription = string.Empty;
          newRow.PartTrackLots = false;
          newRow.PartTrackSerialNum = false;
          newRow.PartTrackDimension = false;
          newRow.PartSalesUM = jMtl.IUM;
          newRow.PartIUM = jMtl.IUM;
          newRow.PartPricePerCode = jMtl.PricePerCode;
          newRow.PartSellingFactor = 1;
          newRow.PartPartDescription = string.Empty;
          newRow.ReasonCodeDescription = string.Empty;
          newRow.ToBinNumDescription = string.Empty;
          newRow.ToWarehouseCodeDescription = string.Empty;
          //newRow.ExtCost = 0;
          newRow.RowMod = "U";
          //**ADD ROW TO TABLE
          issueBO.OnChangingToJobSeq(jMtl.MtlSeq, ref issueReturnDs);
          var pcMessage = string.Empty;
          issueBO.OnChangeToJobSeq(ref issueReturnDs, "IssueMaterial", out msg);
          issueBO.OnChangeTranQty(jMtl.RequiredQty, ref issueReturnDs);
          var legalNumberMessage = string.Empty;
          var partTranPKs = string.Empty;
          //issueReturnDs.IssueReturn[0].LotNum = lotNum;
          //issueBO.OnChangingToJobSeq(jMtl.MtlSeq, ref issueReturnDs);
          //issueBO.OnChangeToJobSeq(ref issueReturnDs, "IssueMaterial", out msg);
          //issueBO.OnChangeTranQty(jMtl.RequiredQty, ref issueReturnDs);
          issueBO.PrePerformMaterialMovement(ref issueReturnDs, out error);
          issueBO.MasterInventoryBinTests(ref issueReturnDs, out msg, out msg, out msg, out msg, out msg, out msg);
          issueBO.PerformMaterialMovement(false, ref issueReturnDs, out msg, out msg);