Automating adding a Labor Detail row

We’re attempting to automate some of our Customer Service ( repair/upgrade ) functions. One of these is the Start Job Production Activity in MES.

I’ve got a Customization which calls the attached code, but always runs into the same error :
Error Detail
============
Description: Labor cannot be reported to a non-location resource.

The error is from adapterLabor.Update(). I commented out that line to be certain, and when that line is commented out, the error does not occur ( also, of course, the database is not updated ).

I checked Resource Groups, and the ResourceGrpID “Depot” is a Location ResourceGrpID. Which it would have to be, as that is what is used to process repairs/upgrades via MES.

The calls to set fields in the block ending with RowMod = “U” are there for testing. The JobNum is correct; this is Active for my employee ID in MES. These lines are set with specific values for testing; if/when the data can be updated for this record, I’ll test some others and then go to work on setting those values automatically.

I’ve done some debugging, and found that the calls to set fields in the block ending with RowMod = “U” do run; I checked several of those fields before and after those calls and the values do change to those set in the calls. I initially had only the first of those calls ( JobNum), then added the rest one at a time to see if I could get past the error. No luck; the error still occurs.

The lack of documentation of the Adapter Methods is the reason for the guesswork in trying to use the adapter.

The LaborDtlSeq value does correctly increment for the new LaborDtl row, but since the new row doesn’t get written, it keeps incrementing to the same value. I tried adding a new LaborDtl row to this Job via MES; that new row used the LaborDtlSeq that was coming up from the procedure, and the procedure then incremented to the next value on the next run.

Not sure where to look from here. I haven’t been able to find anything useful in the Trace logs, even when the MES Trace log has more than just Trace Log packets.

Any ideas, or experiences similar to this ?

Thanks,

Ken Brunelli

	private void StartJobProductionActivityMES()
	{
		try
		{
			// Declare and Initialize EpiDataView Variables
			EpiDataView edv_WIP_Status = ((EpiDataView)(this.oTrans.EpiDataViews["edv_WIP_Status"]));
			EpiDataView edv_WIP_ActiveTrans = ((EpiDataView)(this.oTrans.EpiDataViews["edv_WIP_ActiveTrans"]));

			// Check if valid EpiDataView Row(s) are selected
			if ((edv_WIP_Status.Row < 0)) { return; }
			if ((edv_WIP_ActiveTrans.Row < 0)) { return; }

			// Declare and create an instance of the Adapter.
			LaborAdapter adapterLabor = new LaborAdapter(this.oTrans);
			adapterLabor.BOConnect();

			// Declare and Initialize Variables
			string stringId = ((string)(edv_WIP_Status.dataView[edv_WIP_Status.Row]["UD07_ShortChar02"]));
			string stringEmployeeNum = ((string)(edv_WIP_ActiveTrans.dataView[edv_WIP_ActiveTrans.Row]["LaborHed_EmployeeNum"]));
			Int32 integerLaborHedSeq = ((Int32)(edv_WIP_ActiveTrans.dataView[edv_WIP_ActiveTrans.Row]["LaborHed_LaborHedSeq"]));

			// Call Adapter methods - Labor
			adapterLabor.GetByID(integerLaborHedSeq);

			bool resultGetNewLaborDtl = adapterLabor.GetNewLaborDtl(integerLaborHedSeq);

			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].JobNum = "4652";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].OprSeq = 10;
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].OpCode = "DptRepar";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].ResourceID = "Depot";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].ResourceGrpID = "Depot";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].TimeStatus = "A";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].EmployeeNum = "kb01";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].LaborType = "P";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].LaborTypePseudo = "P";
			adapterLabor.LaborData.LaborDtl[ ( adapterLabor.LaborData.LaborDtl.Count - 1 ) ].Shift = 1;
			adapterLabor.LaborData.LaborHed[ 0 ].RowMod = "U";

			bool resultLaborUpdate = adapterLabor.Update();

			// Cleanup Adapter Reference
			adapterLabor.Dispose();

		} catch (System.Exception ex)
		{
			ExceptionBox.Show(ex);
		}
	}

Sorry, ignore the previous comment, it helps when I read the full thing before giving help…Here is the code I have used to create a labor detail in the past. I hope this helps!

	private void adddata()
	{
		try
		{
			// Declare and Initialize EpiDataView Variables
			// Declare and create an instance of the Adapter.
			LaborAdapter adapterLabor = new LaborAdapter(this.oTrans);
			adapterLabor.BOConnect();

			// Declare and Initialize Variables
			int year = DateTime.Now.Year;
			int month = DateTime.Now.Month;
			int day = DateTime.Now.Day;
			int hour = DateTime.Now.Hour;
			int min = DateTime.Now.Minute;
			int second = DateTime.Now.Second;

			string employeeNum = "0020";
			bool shopFloor = true;
			System.Nullable<System.DateTime> clockInDate = DateTime.Now;
			decimal clockInTime = Convert.ToDecimal(hour + "." + min);
			System.Nullable<System.DateTime> clockOutDate = DateTime.Now;
			decimal clockOutTime = Convert.ToDecimal(hour + "." + min);

			// Call Adapter method
			adapterLabor.GetNewLaborDtlNoHdr(employeeNum, shopFloor, clockInDate, clockInTime, clockOutDate, clockOutTime);
			
			DataRow lbr = adapterLabor.LaborData.LaborDtl[adapterLabor.LaborData.LaborDtl.Rows.Count - 1];
			lbr["Company"] = "NET";
			lbr["EmployeeNum"] = employeeNum;
			lbr["LaborType"] = "P";
			lbr["Rework"] = false;
			lbr["JobNum"] = "020817";
			lbr["AssemblySeq"] = "0";
			lbr["OprSeq"] = "10";
			lbr["JcDept"] = "MILL";
			lbr["ResourceGrpID"] = "MILLS";
			lbr["ExpenseCode"] = "MILL";
			lbr["OpCode"] = "MILL";
			lbr["LaborQty"] = "111";
			lbr["ClockInDate"] = clockInDate;
			lbr["ClockInTime"] = clockInTime;
			lbr["ClockOutTime"] = clockOutTime;
			lbr["ResourceID"] = "214";
			adapterLabor.Update();
	
			// Cleanup Adapter Reference
			adapterLabor.Dispose();
			oTrans.Update();

		} catch (System.Exception ex)
		{
			ExceptionBox.Show(ex);
		}
	}

I have tested this code, and I know it works. Let me know if this works for you!

1 Like

Nick,

Thanks for looking over the post. I see you’ve pulled your reply, probably noticed on a second read that the resource is a location. I’d even thought that my login might be an issue, as I’m no longer in Production, but if I go through the MES process I don’t get the error.

I’ve just begun trying to divinate the usage of the Adapter Methods, with almost no documentation available. Odd, since Epicor is pushing the use of these Methods…or not so odd, since it is Epicor :stuck_out_tongue:

Thanks again for your time. If/when I do figure this out, I’ll post the resolution for others who might need it.

Ken

Ken Brunelli
Business Application Developer
[logo]
N7W23700 Bluemound Rd., Suite 100
Waukesha, WI 53188
ken.brunelli@embedtek.netmailto:ken.brunelli@embedtek.net
(262) 875-3228

Ken, Yeah sorry, the first post was garbage, but I reposted with code that I have used to add labor detail using adapters. Give it a look over, and see if it helps

Thanks, Nick. That did get me past the error - I hadn’t set values for the JCDept and Rework fields.

I’m curious about the call you make to GetNewLaborDtlNoHdr. My ( limited ) understanding is that LaborDtl rows are usually linked to a LaborHed row. What I see in our data is that users log in once, then that LaborHed row ( and that LaborHedSeq value ) are used for all subsequent LaborDtl rows for all jobs for months at a time.

I did find LaborDtl rows for which LaborHedSeq is zero; these are almost entirely Backflush and Adjustment rows. It appears that you’re creating LaborDtl rows without attaching them to a LaborHed row for employees - I’m guessing to fill in records when clock-outs are missed, or something similar. Is that correct, and does that add any wrinkles to reporting ?

Thanks again,

Ken

No problem! glad it helped.

I do not currently use this code, so I am not sure how it affects reporting. You are most likely correct, If I start to use this, I would need to link it to laborhed. This was a prototype I was working on that links an external software to epicor, so there are still a lot of kinks with it, I just know I had got it to store labor detail.

Ideally what I would do is do a quick search for the employee in the laborhead table, if there is a record for today where the clock out time is empty, then I would record the detail against that LaborHedSeq. Otherwise, I would create a new LaborHed record for the employee, then record the detail against the new record.

Does that make sense? Ultimately you are right, Laborhed should be used

1 Like