High level explanation of start activity on custom screen

I need to help in debugging now. I have all of the calls in the code, with the appropriate paramters, and it compiles successfully. However, it gives me an error when I try to run it.

Here’s what the error says.

Application Error

Exception caught in: mscorlib

Error Detail 
============
Message: Unable to cast object of type 'Infragistics.Win.UltraWinGrid.UltraGridCell' to type 'System.IConvertible'.
Program: CommonLanguageRuntimeLibrary
Method: ToInt32

Client Stack Trace 
==================
   at System.Convert.ToInt32(Object value)
   at Script.StartActivityButton_Click(Object sender, EventArgs args)
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at Infragistics.Win.Misc.UltraButtonBase.OnClick(EventArgs e)
   at Ice.Lib.Framework.EpiButton.OnClick(EventArgs e)
   at Infragistics.Win.Misc.UltraButton.OnMouseUp(MouseEventArgs e)
   at Ice.Lib.Framework.EpiButton.OnMouseUp(MouseEventArgs e)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I figure it must be something so do with my parameters and variables not being the right type. The problem is, I don’t know for sure how to figure out which one it is. Should I just comment out all of the calls except the first one and keep running it until I find the offending line? Or is there a better way to figure out what is wrong? A trace doesn’t show anything, so I guess I don’t know how far it’s getting.

Here’s my full code if that helps.

// **************************************************
// Custom code for MainController
// Created: 3/12/2018 1:41:56 PM
// **************************************************
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Ice.BO;
using Ice.UI;
using Ice.Lib;
using Ice.Adapters;
using Ice.Lib.Customization;
using Ice.Lib.ExtendedProps;
using Ice.Lib.Framework;
using Ice.Lib.Searches;
using Ice.UI.FormFunctions;
using Erp.BO;
using Erp.Adapters;


public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **

EpiUltraGrid WorkGrid;
int RowNum;

	public void InitializeCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls

		this.StartActivityButton.Click += new System.EventHandler(this.StartActivityButton_Click);
		// End Wizard Added Custom Method Calls
		WorkGrid = (EpiUltraGrid)csm.GetNativeControlReference("994a7055-2964-46f1-8488-0c2359109f4f");
	}

	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal

		this.StartActivityButton.Click -= new System.EventHandler(this.StartActivityButton_Click);
		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal
		WorkGrid = (EpiUltraGrid)csm.GetNativeControlReference("994a7055-2964-46f1-8488-0c2359109f4f");
	}

	private void StartActivityButton_Click(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
	RowNum = -1;
	foreach(var row in WorkGrid.Rows)
		{
		RowNum = RowNum+1;
			var LHS = Convert.ToInt32(WorkGrid.Rows[RowNum].Cells["Calculated_CalcLaborHeadSeq"]);
			var EmpID = Convert.ToString(WorkGrid.Rows[RowNum].Cells["Calculated_CurrentEmpID"]);
		if(row.Selected)
			{
			var JN = Convert.ToString(WorkGrid.Rows[RowNum].Cells["JobHead_JobNum"]);
			var AS = Convert.ToInt32(WorkGrid.Rows[RowNum].Cells["JobAsmbl_AssemblySeq"]);
			var OS = Convert.ToInt32(WorkGrid.Rows[RowNum].Cells["JobOper_OprSeq"]);
			var RID = Convert.ToString(WorkGrid.Rows[RowNum].Cells["Calculated_ResourceID"]);
			var msg = "testing";
			var la = new LaborAdapter(oTrans);
			la.BOConnect();
			la.GetByID(LHS);
			la.StartActivity(LHS,"P");
			var JobNum = new JobEntryAdapter(oTrans);
			JobNum.ValidateJobNum(JN);
			la.DefaultJobNum(JN);
			la.LaborRateCalc();
			la.DefaultAssemblySeq(AS);
			la.DefaultOprSeq(OS, out msg);
			la.LaborRateCalc();
			la.CheckWarnings(out msg);
			la.CheckEmployeeActivity(EmpID,LHS,JN,AS,OS,RID, out msg);
			la.CheckFirstArticleWarning(out msg);
			la.SetClockInAndDisplayTimeMES();
			la.Update();
			}
		}
	}
}

For any of these calls where you reference Cells[“”] you need to ask for teh cell’s Value
WorkGrid.Rows[RowNum].Cells[“Calculated_CalcLaborHeadSeq”].Value

Sweet, Fixed that. Now it will clock my into an operation. I still am getting this error. It does clock me in though. That method doesn’t show in the trace, so it looks like it skips that one. Is the validate methods on typing something into a field? So should that really be on a leave field event if I were going to use that? Does that sound correct? It’s the only method that doesn’t use the labor adapter, so it seems like doesn’t belong anyways.

Application Error

Exception caught in: Erp.Adapters.JobEntry

Error Detail 
============
Message: Object reference not set to an instance of an object.
Program: Erp.Adapters.JobEntry.dll
Method: ValidateJobNum

Client Stack Trace 
==================
   at Erp.Adapters.JobEntryAdapter.ValidateJobNum(String ipJobNum)

You’ve created the job entry adapter in the line above, but haven’t called BOConnect. That could be because you’re trying to get hold of the current adapter?

I ended up just commenting those lines out. The tracing in MES is kind of a pain because you can’t clear the trace once you open the screen, so it’s hard to isolate what you are doing to each and every method called. So I’m pretty sure that the ValidateJobNum is called when I type in the Job numbers on the screen, but since using the grid to populate that parameter, I don’t think I need it. It seems to be working without it.

That being said, I think you are right, I’ll try adding the BOConnect on that one, and I bet that would make it work. Although, like I said, it’s probably redundant. Can anyone verify that?

Yeah you don’t need this adapter at all for what you are doing. It’s just “FAIL SAFE” as long as you know that job exists… you are good.l;

So now I am trying to do the end activity, and since I discovered the drag and drop method in a Ubaq I want to see if I can get that to work (I’m pretty sure I can do this is a customization, but what you said about the code in the BAQ makes sense so I want to see if it can work there). I followed the trace and called the methods as follows.

Labor.GetDetail
Labor.EndActivity
Labor.DefaultLaborQty
Labor.CheckWarnings
Labor.Update

Pretty much what the trace calls for except the the getlists and getbyID on the Job tableset (which isn’t used in the Labor.Update, so I figured it didn’t do me any good to call it)

I set all of the parameters based on what is in my grid. but I get this error when trying to run it.

Server Side Exception

BPM runtime caught an unexpected exception of 'NullReferenceException' type.
See more info in the Inner Exception section of Exception Details.

Exception caught in: Epicor.ServiceModel

Error Detail 
============
Description:  BPM runtime caught an unexpected exception of 'NullReferenceException' type.
See more info in the Inner Exception section of Exception Details.
Program:  Erp.Services.BO.Labor.dll
Method:  CheckWarnings
Line Number:  3176
Column Number:  13
Original Exception Type:  NullReferenceException
Server Trace Stack:     at Erp.Services.BO.LaborSvc.CheckWarnings(LaborTableset& ds, String& vMessage) in C:\_Releases\ERP\UD10.1.600.5\Source\Server\Services\BO\Labor\Labor.cs:line 3176
   at Erp.Services.BO.LaborSvcFacade.CheckWarnings(LaborTableset& ds, String& vMessage) in C:\_Releases\ERP\UD10.1.600.5\Source\Server\Services\BO\Labor\LaborSvcFacade.cs:line 233
   at Epicor.Customization.Bpm.Ubaq7C9A2DF0539D4458B4374FEAF8A66DCD.UpdateBaseDirective_EndActivity_5BA27B16453B4FAAABB4FF9E21E9BBDA.A004_InvokeBOMethodAction()
   at Epicor.Customization.Bpm.Ubaq7C9A2DF0539D4458B4374FEAF8A66DCD.UpdateBaseDirective_EndActivity_5BA27B16453B4FAAABB4FF9E21E9BBDA.ExecuteCore()
   at Epicor.Customization.Bpm.DirectiveBase`3.Execute(TParam parameters) in c:\_Releases\ICE\3.1.600.0\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 129



Client Stack Trace 
==================
   at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
   at Ice.Proxy.BO.DynamicQueryImpl.Update(DynamicQueryDataSet queryDS, DataSet queryResultDataset)
   at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass27_0.<Update>b__0(DataSet datasetToSend)
   at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func`2 methodExecutor, Boolean refreshQueryResultsDataset)
   at Ice.Adapters.DynamicQueryAdapter.Update(DynamicQueryDataSet queryDS, DataSet updatedDS, Boolean refreshQueryResultsDataset)
   at Ice.UI.App.BAQDesignerEntry.BAQTransaction.<CallUpdate>b__376_0(Int32& rowReturned)
   at Ice.UI.App.BAQDesignerEntry.Forms.BAQDiagramForm.ShowQueryResults(DataSet dsResults, getQueryResult getResults, ReportAdditionalInfo additionalInfo)
   at Ice.UI.App.BAQDesignerEntry.BAQTransaction.CallUpdate()

Inner Exception 
===============
Object reference not set to an instance of an object.

So I’m trying to figure out what I am missing.

Also (and maybe it’s related), I’m assuming that the ttResultsRow.LaborDtl_LaborQty that I put in for the labor quantity is going to get the original returned value. What can I put in the expression editor to get the changed value that I type in the pop up window?

Can you paste your code?

Well, it’s not really code (it’s that drag and drop method you don’t like :wink: It makes it faster for me, however, it may not work.

image

So I couldn’t get that to work (yet) so I went back to what worked on the start activity, which is recreating the trace.

I am passing all of the paramters that the trace calls out, but, something isn’t working. I get “Labor Detail Record has not changed.” For both the EndActivity method and DefaultLaborQty.

I was thinking that those methods would make the change the data set for me. Do I need to manually change the row mod value for those to work?

You need to set the RowMods

That’s probably the same reason the drag and drop method doesn’t work too…?..?.. Anyone know how to set the RowMod field in the drag and drop method? It doesn’t show up in any of the set field menu’s

so I’ve been banging my head against the desk trying to figure out how to set the stupid row mod. I see a couple of different posts where I see the row mod being set but I can’t figure out how to use it. Here’s my code for a good laugh. After getting this work, I need to do some more head banging to try and figure out some stupid cell validation (I’m pretty sure I just need to quit and go home before I throw my computer across the room)

// **************************************************
// Custom code for MainController
// Created: 3/16/2018 9:55:33 AM
// **************************************************
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Ice.BO;
using Ice.UI;
using Ice.Lib;
using Ice.Adapters;
using Ice.Lib.Customization;
using Ice.Lib.ExtendedProps;
using Ice.Lib.Framework;
using Ice.Lib.Searches;
using Ice.UI.FormFunctions;
using Erp.BO;
using Erp.Adapters;

public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **

int RowNum;
string EndMsg;

	public void InitializeCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		this.Results_Column.ColumnChanged += new DataColumnChangeEventHandler(this.Results_AfterFieldChange);
		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls


		this.EndButton.Click += new System.EventHandler(this.EndButton_Click);
		// End Wizard Added Custom Method Calls
	}

	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal


		this.Results_Column.ColumnChanged -= new DataColumnChangeEventHandler(this.Results_AfterFieldChange);
		this.EndButton.Click -= new System.EventHandler(this.EndButton_Click);
		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal
	}



	private void Results_AfterFieldChange(object sender, DataColumnChangeEventArgs args)
	{
		// ** Argument Properties and Uses **
		// args.Row["FieldName"]
		// args.Column, args.ProposedValue, args.Row
		// Add Event Handler Code
		switch (args.Column.ColumnName)
		{
			case "LaborDtl_LaborQty":

				break;
		}
	}

	private void EndButton_Click(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
	RowNum = -1;
	EndMsg = "";
	foreach(var row in MainGrid.Rows)
		{
		RowNum = RowNum+1;
		if(row.Selected)
			{
			var LHS = Convert.ToInt32(MainGrid.Rows[RowNum].Cells["LaborDtl_LaborHedSeq"].Value);
			var LDS = Convert.ToInt32(MainGrid.Rows[RowNum].Cells["LaborDtl_LaborDtlSeq"].Value);
			var LQ = Convert.ToInt32(MainGrid.Rows[RowNum].Cells["JobOper_RunQty"].Value);
			var la = new LaborAdapter(oTrans);
			var msg = "";
			la.BOConnect();
			la.GetDetail(LHS,LDS);
			//set the row mod here.
			
			la.EndActivity();
			la.DefaultLaborQty(LQ, out msg);
			la.CheckWarnings(out msg);
			la.Update();
			}
		}
	}
}

Ok Good thing I went home when I did.

After looking at the examples again, I figured out I need to add this.

		la.LaborData.LaborDtl[0].RowMod= "U";

Now, I’ve seen the “Magic string” issue. How do I use

LaborData.IceRowState.Updated

To set it instead of using “U”?

So I am able to end activity with my code in the dashboard and I can set the quantity using the value that I type into the dashboard.

Now I need to add some cell validation in. I don’t have any experience working the arguments and the properties so I am getting stuck. The code that the wizard gives me is shown below.

	private void Results_AfterFieldChange(object sender, DataColumnChangeEventArgs args)
	{
		// ** Argument Properties and Uses **
		// args.Row["FieldName"]
		// args.Column, args.ProposedValue, args.Row
		// Add Event Handler Code
		switch (args.Column.ColumnName)
		{			
			case "LaborDtl_LaborQty":
			{
			MessageBox.Show("edit intitiated");
			}
			break;
		}
	}

I’ve added the message box to see when it fires, and the message box pops up any time I tab out of the field, so that’s good. I can also add in args.Row.CancelEdit(); and it will cancel the edit, which I will need later.

What I need to do is compare the proposed value to (RunQty - QtyCompleted), so if the labor qty is more than what is actually left to make, it stops them from putting that value in.

I can see the helpful properties that it provides, but I can’t figure out how to use them. I’ve tried putting this in right after the message box. It compiles successfully, but it kicks out after hitting the first var. If I comment out all of the var and the if statement, it will show both message boxes. (I’m skipping the extra math for now, just trying to get some if then statement to work)

			MessageBox.Show("edit intitiated");
			var RowNum2 = Convert.ToInt32(args.Row);
			var RunQ = Convert.ToInt32(MainGrid.Rows[RowNum2].Cells["JobOp_RunQty"].Value);
			var LabQ= Convert.ToInt32(args.ProposedValue);
			if (LabQ > RunQ)
			{
				MessageBox.Show("LaborQty cannot be more than required");
				args.Row.CancelEdit();
			}
			else
			MessageBox.Show("ok");
			}

I’m sure I’m doing a bunch of things wrong at once, but I’m trying hard to learn this, I’m just getting stumped on how to use the properties provided. With all of the other stuff that I’ve been dealing with grids, it’s been in a for loop with a row counter, so I’ve been able to use the RowNum as it counted. With this I have to get the value of the selected row, which I am assuming that I can use the args.Row, but I don’t know how to use it.

I know that this is pretty basic stuff, but I gotta start somewhere right?

Thanks in advance to anyone willing to help me out.

1 Like

Thanks Brendan.
I have tried following the thread. Very interesting but a tad confusing for me…
What I am wanting to do is create a form in MES which looks kinda like this:


And then have it create a time and expense entry (laborHed/Labordetail) record in the same way that one would when entering a time and expense entry as below. The circled items would be entered by the employee, the purple squares are entered by context, and the red squares are set regardless.

If I do this with a trace I get the following:
Scrap - TraceData.txt (226.1 KB)

1 Like