BPM C# Code to Copy from ttPartTran to PartLot

I am trying to create a BPM and use C# code to copy ttPartTran.Character01 to PartLot.Character01.
I am struggling with how to do this. Here is the code that I have right now. It saves in epicor without errors however it does not appear to be saving the data.

string strPartNum = string.Empty;
string strLotNum = string.Empty;
Erp.Tables.PartLot PartLot;

using(var txscope1=IceDataContext.CreateDefaultTransactionScope())
{
var ttPartTran_xRow=(from ttPartTran_Row in ttPartTran where string.Compare(ttPartTran_Row.Company,“ITL123456”,true)==0 select ttPartTran_Row).FirstOrDefault();

if(ttPartTran_xRow != null)
{
	strPartNum = ttPartTran_xRow.PartNum.Trim();
	strLotNum = ttPartTran_xRow.LotNum.Trim();
	
	PartLot=(from PartLot_Row in Db.PartLot.With(LockHint.UpdLock) where string.Compare(PartLot_Row.Company,"ITL123456",true)==0 && string.Compare(PartLot_Row.PartNum,strPartNum,true)==0 &&
			string.Compare(PartLot_Row.LotNum,strLotNum,true)==0 select PartLot_Row).FirstOrDefault();

	if(PartLot != null)
	{
		PartLot["Character01"] = ttPartTran_xRow["Character01"];
		Db.Validate(PartLot);
	}
}

txscope1.Complete();
}

It occurred to me that this BPM is being triggered for the Job Receipt to Inventory and there may be two ttPartTran records. Is that why this is not working?

If anyone could help I would certainly appreciate it.

Thanks,
Dave Olender
Ph: 651-246-3281

Try removing “PartLot” from Db.Validate… Instead just have:

Db.Validate();

1 Like

Mr. Chan: Thank you for the suggestion – I will give that a try.

DaveO

Olender LLC

Dave Olender

1912 Flandrau Street

Maplewood, MN 55109

Ph: 651-246-3281

mailto:dolender@olenderconsulting.com dolender@olenderconsulting.com

I tried the Db.Validate(); - It did not work. The PartLot[“Character01”] field is not updating.

Thank you for the suggestion - any other ideas greatly appreciated.

Thanks,
DaveO
Ph: 651-246-3281

Try Db.Validate(PartLot_Row);

Brenda

Thank you for the suggestion. I get the following error message:

Server Side Exception

There is at least one compilation error.

Exception caught in: Epicor.ServiceModel

Error Detail

Description: There is at least one compilation error.
Details:
Error CS0103: The name ‘PartLot_Row’ does not exist in the current context [ReceiveMfgPartToInventory.Post.SaveInfoToPartLo.cs(119,16)]
Program: Epicor.Customization.dll
Method: PrepareException
Line Number: 99
Column Number: 13

I got it working - I moved my BPM from a PostProcess to a PreProcess.

I have two versions that work.

The first one is:

string strPartNum=string.Empty;
string strLotNum=string.Empty;

Erp.Tables.PartLot PartLot;

foreach(var ttPartTran_xRow in ttPartTran)
{
var ttPartTranRow=ttPartTran_xRow;
if(ttPartTran_xRow != null)
{
PartLot=(from PartLot_Row in Db.PartLot where PartLot_Row.Company==ttPartTranRow.Company && PartLot_Row.PartNum==ttPartTranRow.PartNum && PartLot_Row.LotNum==ttPartTranRow.LotNum select PartLot_Row).FirstOrDefault();
if(PartLot != null)
{
PartLot[“Character01”]=ttPartTranRow[“Character01”];
PartLot[“Character02”]=ttPartTranRow[“Character02”];
PartLot[“Character03”]=ttPartTranRow[“Character03”];
PartLot[“Character04”]=ttPartTranRow[“Character04”];
}
}
}

This works but is missing the Scope and Db.Validate(); is that required or a better way of writing this code:

string strPartNum = string.Empty;
string strLotNum = string.Empty;
Erp.Tables.PartLot PartLot;

using(var txscope1=IceDataContext.CreateDefaultTransactionScope())
{
var ttPartTran_xRow=(from ttPartTran_Row in ttPartTran where string.Compare(ttPartTran_Row.Company,“ITL123456”,true)==0 select ttPartTran_Row).LastOrDefault();

if(ttPartTran_xRow != null)
{
	strPartNum = ttPartTran_xRow.PartNum.Trim();
	strLotNum = ttPartTran_xRow.LotNum.Trim();
	
	PartLot=(from PartLot_Row in Db.PartLot.With(LockHint.UpdLock) where string.Compare(PartLot_Row.Company,"ITL123456",true)==0 && string.Compare(PartLot_Row.PartNum,strPartNum,true)==0 &&
			string.Compare(PartLot_Row.LotNum,strLotNum,true)==0 select PartLot_Row).FirstOrDefault();

	if(PartLot != null)
	{
		PartLot["Character01"] = ttPartTran_xRow["Character01"];
		PartLot["Character02"] = ttPartTran_xRow["Character02"];
		PartLot["Character03"] = ttPartTran_xRow["Character03"];
		PartLot["Character04"] = ttPartTran_xRow["Character04"];

		Db.Validate();
	}
}

txscope1.Complete();
}

Thanks to everyone that helped with this - as I mentioned I am not a programmer - so I struggle with the syntax. However I feel like if I can get a simple example working - I can change the table and field names to get the same thing done for other scenarios.

I would appreciate any additional coding/formatting advice from the group.

Haha – one more time: Db.Validate(PartLot.PartLot_Row);

Brenda

Hey Dave,
It looks like you are making use of the code converter that Epicor provides for assistance, this is fine to get a general idea of how the flow goes but the code it generates its wholly inefficient and slow, I would be careful putting code generated by the converter in a production system.
The code below should work, a few things to note, always make sure you are working on the temp records that are either Updated or Added in 10.1 Epicor added a Added() and Updated() method to temp records which you can use. Otherwise you’ll have to compare the RowMod
Using accessors to get to the UDFields is recommended in the Temp Row, it has the advantage of giving you some syntax checking because they are typed specific.
Also when you are referring to a UD field in the Db.Context you can address those fields directly (typed) since they are generated as part of the data model when the data model is regenerated.
The transaction scope is usually redundant and not needed unless you are doing a transaction in post processing which is outside of the current transaction scope. You will need to always call DB.Validate when you are updating the DB Tables, though Epicor does that automatically for you in the background (still be a good citizen and clean up yourself)

Try this and see if it works (it should though I can’t test it), its a little simpler than the code generated by the converter.

foreach (var tempPartTran in ttPartTran.Where(pt => pt.Updated() || pt.Added()))
{
	var partLot = (from pl in Db.PartLot.With(LockHint.UpdLock) where pl.Company == tempPartTran.Company && pl.PartNum == tempPartTran.PartNum && pl.LotNum == tempPartTran.LotNum select pl).FirstOrDefault();
	if(partLot!=null)
	{
		partLot.Character01 = tempPartTran.UDField<string>("Character01", false);
		partLot.Character02 = tempPartTran.UDField<string>("Character02", false);
		partLot.Character03 = tempPartTran.UDField<string>("Character03", false);
		partLot.Character04 = tempPartTran.UDField<string>("Character04", false);
		Db.Validate();
	}
}

if pt.Update() and pt.Added() throw a syntax error (version 10.0) you can change to the following line

foreach (var tempPartTran in ttPartTran.Where(pt => pt.RowMod==IceRow.ROWSTATE_UPDATED || pt.RowMod==IceRow.ROWSTATE_ADDED))

Thank you Mr. Jose for the advice.

I’ll try your example later today.

DaveO

Mr Gomez: Thanks for the Code.
I tried your version and it works (no surprise there).

I must admit I am confused by the syntax. What is the
ttPartTran.Where(pt => pt.Updated() || pt.Added())

Where did the “pt” come from? and what does it stand for? Is it shortcut for “PartTran”? is pt a variable that I can change to pq if I am using the PartQty table?

Thanks,
DaveO

Its a Lambda expression (its a “shorthand” way of doing LINQ)

Check out

1 Like

Mr. Jose - Thank you for the help.

I am feeling a little more confident about the C# stuff. Most of what I have to do is simple copy this field to this table kind stuff and you have helped immensely.

I can only hope I will be able to return the favor some day.

Take care,

DaveO

pt is sort of an input parameter, its a variable you can declare it to be anything you want, zz if you like. It’s basically a function that will return true or false depending on how your expression (in this case pt.Updated() || pt.Added()) evaluates.