How to loop through all Quote tree nodes for Mtl?

Hi, In 10.2.300.15 in the Quote Entry form I’m working on a customization that for a material can update
EstUnitCost like so…

EpiDataView edvJobMtl = (EpiDataView)(oTrans.EpiDataViews["JobMtl"]);
edvJobMtl.CurrentDataRow["EstUnitCost"] = gridPriceValue;

after gridPriceValue has been set by the users after they click a button (has word “Uno” in it in screen shot) where they make price list and historical decisions on a new custom sheet
That part is fine and working for me.
However, now for each material in the quote I was hoping the user could click one new button (has word “Muchos” in it in screen shot) to loop through all the Mtl: nodes in the Quote
and automatically click the “Uno” button on each. This would be a big time saver for them since they would only have to make decisions once
for that material that occurs repeatedly through the quote e.g. multiple lines, sub assemblies, etc. since I hold the previous part and price in a datatable so I can use it again.

I thought I might be able to loop thought the nodes with something like the following code, but fieldInfo is always null and raising an error.
Does anyone see the problem with this approach or have another to suggest?

Here's the details
using System.Reflection;
//Is there another table I should be using below? I've tried edvJobMtl, edvJobHead & edvQuoteHed
	private void edvQuoteDtl_EpiViewNotification(EpiDataView view, EpiNotifyArgs args)
	{
		// ** Argument Properties and Uses **
		// view.dataView[args.Row]["FieldName"]
		// args.Row, args.Column, args.Sender, args.NotifyType
		// NotifyType.Initialize, NotifyType.AddRow, NotifyType.DeleteRow, NotifyType.InitLastView, NotifyType.InitAndResetTreeNodes
		if ((args.NotifyType == EpiTransaction.NotifyType.Initialize))
		{
			if ((args.Row > -1))
			{
                Ice.Lib.Framework.JobLib.MethodTree methodTree = default(Ice.Lib.Framework.JobLib.MethodTree);
                FieldInfo fieldInfo = default(FieldInfo);
                Ice.Lib.Framework.JobLib.MethodTreePanel treeviewPanel = default(Ice.Lib.Framework.JobLib.MethodTreePanel);
                fieldInfo = typeof(Erp.UI.App.QuoteEntry.QuoteForm).GetField("mfgDetailsJobTreePanel1", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
                treeviewPanel = (Ice.Lib.Framework.JobLib.MethodTreePanel)fieldInfo.GetValue(QuoteForm);
                methodTree = treeviewPanel.MethodTree;
                foreach (UltraTreeNode rootNode in methodTree.Nodes)
                    IterateNodes(rootNode);
            }
		}
	}

  private void IterateNodes(UltraTreeNode node)
    {
        foreach (UltraTreeNode childNode in node.Nodes)
        {
            if (childNode.ToString().StartsWith("Mtl: "))
            {
                MessageBox.Show("Test - On a Mtl Node");
                //childNode.ExpandAll(); //click my button that allows the user to make custom decisions
            }
                IterateNodes(childNode);
        }
    }


Thanks,
-Dave

Additionally, has anyone had any success implementing the AfterSelect event for the Tree?
e.g.

private void ultraTree1_AfterSelect(object sender, SelectEventArgs e)
        {
            UltraTreeNode node = e.NewSelections[0];
           
           //Determine by checking the key of the selected node
            Console.WriteLine(node.Key);
            
            //Determine by checking the Text property
            Console.WriteLine(node.Text);

           //Determine the Level of the node; Root nodes are level 0. //Children of the root are Level 1, etc.
            Console.WriteLine(node.Level);      
  }

So I did come up with a prototype that will loop though materials for each group of materials that a user clicks in (whether it be general materials or in a sub assembly) and make the updates based on user decisions. However I really need a one click solution that for each material, will apply the update for all instances of that material in the quote. So what is the proper Epicor approach for handling a problem like this? e.g. get a list of all material in a quote, have some UI for each material and then update the set of data for each material.

BTW, Here is a code snippet from my prototype.

int assemblySeq;
EpiDataView edvJobMtl = (EpiDataView)(this.oTrans.EpiDataViews["JobMtl"]);
assemblySeq = (int)edvJobMtl.CurrentDataRow["AssemblySeq"];
string filter = String.Format("APSAddResType = 'M' and AssemblySeq = {0}", assemblySeq);
foreach (DataRow partRow in edvJobMtl.dataView.Table.Select(filter))
...
//Then I just break when UI needs to happen, then restart it and make the appropiate tests to proceess as needed
2 Likes

Also, the Update should be this and not what I originally stated…

EpiDataView edvJobMtl = (EpiDataView)(oTrans.EpiDataViews["JobMtl"]);
edvJobMtl.dataView.Table.Rows[cntPartRow]["EstUnitCost"] = gridPriceValue;

There is a .dataView which has filters typically associated to the Parent QuoteAsm. If you want to loop through all the JobMtl’s in that Asm then you can do something like.

EpiDataView edvJM = this.oTrans.Factory("JobMtl"); // I have JobMtl, perhaps its QuoteMtl in Quote.

foreach (DataRowView drJM in edvJM.dataView)
{
	// Variables
	decimal vQP = Convert.ToDecimal(drJM["QtyPer"]);
	string vPC = drJM["Class"].ToString();

	// Calculate Per Order & Quantity Per Year
	drJM["MtlCalcQtyOrder"] = Math.Round(vQQ * vQP, 2);
	drJM["MtlCalcQtyYear"] = Math.Round(vSEQ * vQP, 2);
}

// Probably followed by a 
this.oTrans.Update(); // you can try without it first so it doesnt commit data until user actually saves

If you ever want to loop through all JobMtl’s, sometimes depending on the Table Epicor will load all the data in and show it in the DataTable.

For DataTable Foreach its

EpiDataView edvJobMtl = this.oTrans.Factory("JobMtl");
foreach(DataRow dr in edvJobMtl.dataView.Table.Rows)
{		
	dr["OverrideRates"] = true;
	dr["ProdLabRate"] = prevWageRate;
}

When to Trigger?

So when do you want to call the above first loop?

  1. You could set a AfterFieldChange on JobMtl and then look for when someone changes the Price Column.
  2. You could also listen for the QuoteDtl Engineered Checkbox and do it then, for all?

Perhaps a Better Option?

  1. Use a BPM when JobMtl Column changes and then update all the other Materials via a BPM?
2 Likes

Thanks @hkeric.wci I really appreciate what you posted.
However, as a test if I put a button here with this code

        EpiDataView edvJobMtl = this.oTrans.Factory("JobMtl");
        EpiDataView edvQuoteMtl = this.oTrans.Factory("QuoteMtl");

And I debug watch edvJobMtl, I’m not seeing where I might have all the parts for this quote.
Also, edvQuoteMtl is null.

Do you (or anyone) have a quote with multiple lines and assemblies within where you can see/verify the needed?

So I’ve been able to loop through all the lines knowing this:
edvQuoteDtl.dataView.Table.Rows.Count
and I do this
edvQuoteDtl.Row = indexQuoteDtl;

And I know the count of assemblies in each Line knowing this:
edvJobAsmbl.dataView.Table.Rows.Count
and I do this
edvJobAsmbl.Row = indexJobAsmbl;

And I can loop through and set using this:
EpiDataView edvJobMtl = (EpiDataView)(this.oTrans.EpiDataViews[“JobMtl”]);
or
EpiDataView edvJobMtl = oTrans.Factory(“JobMtl”);
followed by an index I maintain for this:
edvJobMtl.Row = cntPartRow;

Then I can set whatever I want using
edvJobMtl.dataView.Table.Rows[cntPartRow][“EstUnitCost”] = whatever;

HOWEVER, I’m not having any success in trying to get edvJobMtl to be anything other than default AssemblySeq 0 materials,
so I can set the same for materials in Subassemblies/Operations.
Is there a version of this or something
EpiDataView edvJobMtl = oTrans.Factory(“JobMtl”);
that can return the AssemblySeq that I want when I know what the seq and index is?

BTW, I know how to filter the DV…that’s no what I’m asking for.

Ended up doing my solution in this post…