In the “Start Production Activity” for MES, I would like to add additional fields for informational requirement from my users. I did a foreign key link to JobOper to get the ProductionQty and QtyCompleted. I had both of these displayed in the textbox. My user asked if I can take these 2 texbox and calculate the difference to tell them the remaining balance for each operation.
I thought since the 2 textboxes are strings, i convert them into double and then do the math. However, when I did that I get the following error.
I do have a question though. Does anyone know which Custom Object Explorer I would need to have it do it’s calculation after it pull in the Production Qty and Completed Qty to get my remaining balance?
To add the BOReader reference, from customization tools dialog–>Tools–>Custom Assembly Reference Manager, which dll is it? I am on Epicor 10.2, and I don’t see anything related to BOReader or Ice.Prox.Lib.BOReaderImpl.dll?
@cchang a recommendation not related to your question, for your own sake you should always rename the controls from their default value (epiLabelC1, epiLabelC3) to something that makes sense in the context of it’s use. IE rename epiLabelC1 to lblProdQty and epiLabelC3 to lblQtyComplete
Otherwise you’ll come back in 6 months and have no idea what in the world is epiLabelC1
Sorry for the unsolicited 2 cents, but my programmer brain twitches when it sees default control names
I guess it makes the most sense to detect the change on the last item, in this case operation. (Bcuz when job or asm changes, operation is reset)
In general (pseudo) terms, it would be kinda like
GetRef to the EpiDataView that has your job/asm/op
EpiDataView myEDV = oTrans.Factory(“Name of the correct EDV”);
Put a field change event on operation field
OnFieldChange(Operation) =>
{
get the job/asm/op from the epidataview (myEDV)
Call GetQtyInfo
}
Thanks for the help Chris. So I went and tried to detect change, however, it seems to be pulling operation 10 whenever I open my program. Also I can’t seem to get calling “GetQtyInfo”. Is there something I am missing my my code?
Here’s the entire code:
// **************************************************
// Custom code for StartProdForm
// Created: 4/2/2018 11:16:08 AM
// **************************************************
extern alias Erp_Contracts_BO_JobEntry;
extern alias Erp_Contracts_BO_JobAsmSearch;
extern alias Erp_Contracts_BO_JobOperSearch;
extern alias Erp_Contracts_BO_Resource;
extern alias Erp_Contracts_BO_ResourceGroup;
extern alias Erp_Contracts_BO_EmpBasic;
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Erp.Adapters;
using Erp.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;
public class Script
{
// ** Wizard Insert Location - Do Not Remove ‘Begin/End Wizard Added Module Level Variables’ Comments! **
// Begin Wizard Added Module Level Variables **
private static string mJobOper;
private DataView Start_DataView;
// End Wizard Added Module Level Variables **
// Add Custom Module Level Variables Here **
public void InitializeCustomCode()
{
// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
// Begin Wizard Added Variable Initialization
this.Start_DataView = this.Start_Row.dataView;
this.Start_DataView.ListChanged += new ListChangedEventHandler(this.Start_DataView_ListChanged);
mJobOper=string.Empty;
this.baseToolbarsManager.ToolClick += new Infragistics.Win.UltraWinToolbars.ToolClickEventHandler(this.baseToolbarsManager_ToolClick);
// End Wizard Added Variable Initialization
// Begin Wizard Added Custom Method Calls
// End Wizard Added Custom Method Calls
}
public void GetQtyInfo(string jobNum, int asmNum, int opNum)
{
try
{
Ice.Proxy.Lib.BOReaderImpl _bor = WCFServiceSupport.CreateImpl<Ice.Proxy.Lib.BOReaderImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.BOReaderSvcContract>.UriPath);
DataSet ds2 = _bor.GetList("Erp:BO:JobOperSearch", "JobNum = '"+jobNum+"' AND AssemblySeq = "+asmNum.ToString()+" AND OprSeq = "+opNum.ToString(), "");
if(ds2 != null)
{
txtQtyCompleted.Value = ds2.Tables[0].Rows[0]["QtyCompleted"];
txtProdQty.Value = ds2.Tables[0].Rows[0]["RunQty"];
}
MessageBox.Show(Convert.ToString(txtQtyCompleted));
}
catch(Exception e)
{
MessageBox.Show("Error: "+e.Message);
}
}
public void DestroyCustomCode()
{
// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
// Begin Wizard Added Object Disposal
this.Start_DataView.ListChanged -= new ListChangedEventHandler(this.Start_DataView_ListChanged);
this.Start_DataView = null;
mJobOper=string.Empty;
this.baseToolbarsManager.ToolClick -= new Infragistics.Win.UltraWinToolbars.ToolClickEventHandler(this.baseToolbarsManager_ToolClick);
// End Wizard Added Object Disposal
// Begin Custom Code Disposal
// End Custom Code Disposal
}
public void JobOper()
{
//Get reference to job operation
EpiDataView edvJobOper=(EpiDataView)oTrans.EpiDataViews["Start"];
if(((edvJobOper.dataView[0]["OprSeq"].ToString() !=null)&&(Convert.ToInt32(edvJobOper.dataView[0]["OprSeq"].ToString()) > 0)))
{
string strJobOper = edvJobOper.dataView[0]["OprSeq"].ToString();
if ((mJobOper != strJobOper))
{
mJobOper = strJobOper;
//GetQtyInfo();
MessageBox.Show(mJobOper);
}
else
{
mJobOper=string.Empty;
}
}
}
private void Start_DataView_ListChanged(object sender, ListChangedEventArgs args)
{
// ** Argument Properties and Uses **
// Start_DataView[0]["FieldName"]
// args.ListChangedType, args.NewIndex, args.OldIndex
// ListChangedType.ItemAdded, ListChangedType.ItemChanged, ListChangedType.ItemDeleted, ListChangedType.ItemMoved, ListChangedType.Reset
JobOper();
// Add Event Handler Code
}
private void baseToolbarsManager_ToolClick(object sender, Infragistics.Win.UltraWinToolbars.ToolClickEventArgs args)
{
switch(args.Tool.Key)
{
case "DeleteTool":
case "ClearTool":
mJobOper=string.Empty;
break;
}
}
You know why I can’t call “GetQtyInfo”? I get the error indicating “Only assignment, call, increment, await, and new object expressions can only be used as statement”.
So I am using afterfieldchange to call “GetQtyInfo”, but getting error.
Like Jose said, that’s not valid syntax. If you dont know basic C# you’re gonna have a tough time moving forward with your customization.
One final push:
switch (args.Column.ColumnName)
{
case "OprSeq":
var myDV = oTrans.Factory("THE PROPER DATAVIEW NAME HERE");
var job = myDV.dataView[myDV.Row]["JobNum"].ToString();
var asm = (int)myDV.dataView[myDV.Row]["AssemblySeq"];
var op = (int)myDV.dataView[myDV.Row]["OprSeq"];
GetQtyInfo(job,asm,op);
break;
}
To figure out what dataview you need, use Help>Field Help then select the JobNum textbox. Look at the epibinding (Table.Field). That Table name will be the name of your dataview
Sure, here’s what I did to show production qty, qty completed, and remaining qty.
// **************************************************
// Custom code for StartProdForm
// Created: 4/2/2018 11:16:08 AM
// **************************************************
extern alias Erp_Contracts_BO_JobEntry;
extern alias Erp_Contracts_BO_JobAsmSearch;
extern alias Erp_Contracts_BO_JobOperSearch;
extern alias Erp_Contracts_BO_Resource;
extern alias Erp_Contracts_BO_ResourceGroup;
extern alias Erp_Contracts_BO_EmpBasic;
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Erp.Adapters;
using Erp.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;
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 **
public void InitializeCustomCode()
{
// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
// Begin Wizard Added Variable Initialization
this.LaborDtl_Column.ColumnChanged += new DataColumnChangeEventHandler(this.LaborDtl_AfterFieldChange);
this.baseToolbarsManager.ToolClick += new Infragistics.Win.UltraWinToolbars.ToolClickEventHandler(this.baseToolbarsManager_ToolClick);
// End Wizard Added Variable Initialization
// Begin Wizard Added Custom Method Calls
// 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.LaborDtl_Column.ColumnChanged -= new DataColumnChangeEventHandler(this.LaborDtl_AfterFieldChange);
this.baseToolbarsManager.ToolClick -= new Infragistics.Win.UltraWinToolbars.ToolClickEventHandler(this.baseToolbarsManager_ToolClick);
// End Wizard Added Object Disposal
// Begin Custom Code Disposal
// End Custom Code Disposal
}
private void LaborDtl_AfterFieldChange(object sender, DataColumnChangeEventArgs args)
{
// ** Argument Properties and Uses **
// args.Row["FieldName"]
// args.Column, args.ProposedValue, args.Row
// Add Event Handler Code
EpiDataView edvJobOper=(EpiDataView)oTrans.EpiDataViews["Start"];
string jobNum = edvJobOper.dataView[edvJobOper.Row]["JobNum"].ToString();
string asmNum = edvJobOper.dataView[edvJobOper.Row]["AssemblySeq"].ToString();
string opNum = edvJobOper.dataView[edvJobOper.Row]["OprSeq"].ToString();
switch (args.Column.ColumnName)
{
case "OprSeq":
try
{
Ice.Proxy.Lib.BOReaderImpl _bor = WCFServiceSupport.CreateImpl<Ice.Proxy.Lib.BOReaderImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.BOReaderSvcContract>.UriPath);
DataSet ds2 = _bor.GetList("Erp:BO:JobOperSearch", "JobNum = '"+jobNum+"' AND AssemblySeq = "+asmNum.ToString()+" AND OprSeq = "+opNum.ToString(), "");
if(ds2 != null)
{
txtQtyCompleted.Value = ds2.Tables[0].Rows[0]["QtyCompleted"];
txtProdQty.Value = ds2.Tables[0].Rows[0]["RunQty"];
}
txtProdQty.Text = (Convert.ToDouble(txtProdQty.Value).ToString());
txtQtyCompleted.Text = (Convert.ToDouble(txtQtyCompleted.Value).ToString());
double RemainingQty = (Convert.ToDouble(txtProdQty.Text)) - (Convert.ToDouble(txtQtyCompleted.Text));
txtRemainingQty.Text = Convert.ToString(RemainingQty);
}
catch(Exception e)
{
MessageBox.Show("Error: "+e.Message);
}
break;
}
}
private void baseToolbarsManager_ToolClick(object sender, Infragistics.Win.UltraWinToolbars.ToolClickEventArgs args)
{
switch(args.Tool.Key)
{
case "DeleteTool":
case "ClearTool":
txtProdQty.Text=string.Empty;
txtQtyCompleted.Text=string.Empty;
txtRemainingQty.Text=string.Empty;
break;
}
}
Thanks for sharing this code, I want to do exactly this but in in the End Activity screen (this will also be handy in the start production activity!), we are having issues with overbooking of Jobs so to be able to show the remaining Qty is a start to try and reduce this.
How easy would it be to adapt this to work in the end activity screen, I have already added in the Production Qty and Qty completed fields, adding the calculation to populate a custom field on form load is where I am now hitting a wall, I am not a coder at all so don’t know where to start.