BPM Help - Add lines to TFO

,

Hi Guys,

I’m trying to write a method directive that will let our guys in goods outwards create a Transfer order shipment pack, enter a TFO number, and then have all the picked lines automatically be created on the shipment but I’m struggling to convince Epicor to save the record.

Here’s my code - its attached post-proc on TransOrderShip.ChangeTFShipHeadTFOrdNum

var ttTFO = (from sh in ttTFShipHead
              where sh.Company == "Eschmann"
             select new {sh.PackNum}).FirstOrDefault();
             
  string sttTTFO = $"ttTFO PackNum:{ttTFO.PackNum} - ipProposedTFOrdNum:{ipProposedTFOrdNum}";
  this.PublishInfoMessage(sttTTFO, Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "1", "2");

var pickedLines = (from pl in Db.PartAlloc
                    where pl.PickedQty > 0
                    && pl.TFOrdNum == ipProposedTFOrdNum
                   select new {pl.TFOrdNum, pl.PartNum, pl.DimCode, pl.TFOrdLine, pl.PickedQty}); 


  
  //create the ShipDtl line from the picked TFO line
using(var TransOrderShipSvc = Ice.Assemblies.ServiceRenderer.GetService<TransOrderShipSvcContract>(Db))
{

  foreach(var p in pickedLines)
  {
    string sPickedLines = $"{p.TFOrdNum} - {p.TFOrdLine} - {p.PartNum} - {p.PickedQty}";
    this.PublishInfoMessage(sPickedLines, Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "1", "2");
    
	//check if the TFO line exists on another open/unshipped pack
    //ToDo
	

    TransOrderShipTableset ts = this.ds;
    TransOrderShipSvc.GetNewTFShipDtl(ref ts, ttTFO.PackNum);
    var newShipLine =(from sd in ts.TFShipDtl
                        where sd.Company == "Eschmann" 
                        && sd.RowMod == "A" select sd).FirstOrDefault();
                      
    string snewShipLine = $"{newShipLine.PackNum}";
    this.PublishInfoMessage(snewShipLine, Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "1", "2");
    newShipLine.TFOrdNum = ipProposedTFOrdNum;
    newShipLine.TFOrdLine = p.TFOrdLine;
    newShipLine.WarehouseCode = "ETECHENG";      
    newShipLine.BinNum = "ENGSHIP";
    newShipLine.PartNum = p.PartNum;
    newShipLine.IUM = p.DimCode;
    newShipLine.OurStockShippedQty = p.PickedQty;
    newShipLine.ShippedQty = p.PickedQty;
    newShipLine.requestdate = System.DateTime.Now; 
    string allocationMessage = "";
    string cMessage = "";
    TransOrderShipSvc.Update(ref ts);
    //this.dsHolder.Attach(ts);
    return;
  }
  
} 

Here’s the error I’m getting.

edit to add i know i got something funky going on with getting and updating the right NewTFShipDtl line (“newShipLine”) at the moment, but i got a return at the bottom so just trying to get it to create one line and save it as a starting point before I deal with that. If i cant save one record then I guess there is no point looping through all the other records i want to create.

Cheers

Andy

Hi All,

Just coming back to update this. I never managed to get close with a BPM so ended up doing this in a screen customisation. When you leave a new textbox on the screen (we gonna scan barcodes from picking lists) this code runs a BAQ and adds the lines.

Heres the code incase its useful to anyone.


	private static void epiTextBoxC1_Leave(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
		if(epiTextBoxC1.Text == "")
		{
		}
		else
		{
			CallTransOrderShipAdapterUpdateMethod();
			MessageBox.Show("LOL dunnit");
		}
	}

	private static void CallTransOrderShipAdapterUpdateMethod()
	{
		try
		{

			//get the lines that have been picked for this TFO by running a BAQ
			DynamicQueryAdapter dqa = new DynamicQueryAdapter(oTrans);
			dqa.BOConnect();
			QueryExecutionDataSet qeds = dqa.GetQueryExecutionParametersByID("GetPickedTFOLines");
			qeds.ExecutionParameter.Clear();
			qeds.ExecutionParameter.AddExecutionParameterRow("TFONum",  epiTextBoxC1.Text, "nvarchar", false, Guid.NewGuid(), "A");
			dqa.ExecuteByID("GetPickedTFOLines", qeds);
			DataTable pickedLines = dqa.QueryResults.Tables["Results"];
			if(pickedLines.Rows.Count > 0)
			{

				// Declare and Initialize EpiDataView Variables
				EpiDataView edvTFShipHead = (EpiDataView)oTrans.EpiDataViews["TFShipHead"];
				EpiDataView edvTFShipDtl = (EpiDataView)oTrans.EpiDataViews["TFShipDtl"];
				// Declare and create an instance of the Adapter.
				TransOrderShipAdapter adapterTransOrderShip = new TransOrderShipAdapter(Script.oTrans);
				adapterTransOrderShip.BOConnect();
				
	
				
				//get a new TFShipHead
				var newShip = oTrans.GetNewTFShipHead();
				if(newShip)
				{
					//Set the company field in the epiDataview
					System.Data.DataRow dr = edvTFShipHead.CurrentDataRow;
					dr["Company"] = "Eschmann";
					dr["ShipViaCode"] = "Fdx1";
				}
	
				
				//Call update
				//adapterTransOrderShip.Update();
				oTrans.Update();   //save as if clicking the save icon
				oTrans.Refresh();  // refresh as if clicking the refresh icon
				
				System.Data.DataRow dr1 = edvTFShipHead.CurrentDataRow;			
				dr1["TFOrdNum"] = epiTextBoxC1.Value.ToString();
				oTrans.ChangeTFShipHeadTFOrdNum(epiTextBoxC1.Value.ToString());
				oTrans.Update();   //save as if clicking the save icon
				oTrans.Refresh();  // refresh as if clicking the refresh icon
	

				//loop over the picked lines and create a TFOrderShipment Detail line
				foreach(DataRow r in pickedLines.Rows)
				{
					oTrans.GetNewTFShipDtl();
					System.Data.DataRow shipDtlRow = edvTFShipDtl.CurrentDataRow;
					shipDtlRow["TFOrdNum"] = r["PartAlloc_TFOrdNum"];
					shipDtlRow["TFOrdLine"] = r["PartAlloc_TFOrdLine"];
					shipDtlRow["OurStockShippedQty"] = r["PartAlloc_PickedQty"];
					shipDtlRow["OurStockQty"]= r["PartAlloc_PickedQty"];
					shipDtlRow["OrderShipmentQty"]= r["PartAlloc_PickedQty"];
					shipDtlRow["DisplayShipQty"]= r["PartAlloc_PickedQty"];	
					shipDtlRow["IUM"] = r["PartAlloc_DimCode"];
					oTrans.Update();   //save as if clicking the save icon
					//oTrans.Refresh();  // refresh as if clicking the refresh icon
				
				}
			
				// Cleanup Adapter Reference
				adapterTransOrderShip.Dispose();
				oTrans.Refresh();
			}
		}
		catch (System.Exception ex)
		{
			ExceptionBox.Show(ex);
		}
	}
}

Cheers

Andy

1 Like

Just some inspiration maybe,
That’s what we use dynamic PCIDs for, each PCID label for a box, then scan the PCID(s) into the Pack. Each PCID represents a box, so the receiver knows where to look for.
Then adjusted the TF Pack Slip to include and grop by PCID as a Putaway Slip.

Caution though, PCIDs in transfers are at least in .600 still quite buggy, if i.e. you delete a pack with PCIDs in it, they get stranded in your shipping bin and can’t be adjusted through the front end.
And we have the issue occasionally that the same PCID gets added twice, very messy.

Other than that it works a treat :laughing:

Thanks, always good to hear how others are working!

We are actually using TFOs as replenishments for our field service techs. We have written interfaces that create TFOs for each engineer to replenish their vans, these are allocated/picked manually and the pick list has a barcode to scan which triggers this code and adds all the lines to the shipment.

Once the guys in stores correct the lines for any shortages and hit ship then we have another interface which integrates with our shipping software to create the shipment with the courier and get the tracking number, completes the transfer of the stock into a different plant, put it into his “in transit” location and send the shipment into our field service app for him to receive on mobile, etc, etc

I still feel like this solution could have been done in a BPM which would perform better than in the client as a customization…but I’m not knowledgeable enough about how to make Epicor do what i want and clear documentation seems hard to come by for some of this stuff.

I see, did you try functions?
I’ve had quite some success using them as they don’t necessariy underlay the same “constraints” as BPMs.
So instead doing your logic in the BPM, the BPM only triggers the function and it goes from there.

Ie I struggled to create an Auto Ship function to replace the too ridgit Counter Sales function (always got some duplicate dataset error often mentioned), and got it working only via widgets in Functions, neat!

Maybe something to look into
Cheers

2 Likes