Navigate to a Subassembly by Assembly Sequence

Is it possible to navigate to a subassembly in a job using only the Assembly Sequence number?

Often we know the Job #, Assembly Seq, and Mtl Seq of a particular job material. I want to edit this material. If it is buried in a subassembly of a multi-level Job BOM, it is very difficult to quickly navigate to the subassembly without knowing the assembly Part Number and using the Find Assembly Part command in the Job Tree context menu.

Usually you can use the Navigators on the tab, add more navigators to the Main Tab
image

or talk to @josecgomez

1 Like

If the Assembly navigator listed the assemblies at all levels that would be great. But since it is only one level deep, it doesn’t help too much.

@josecgomez’s customization is exactly what I’m looking for. Can’t believe that is not out-of-the-box functionality.

Just for the record of this thread…

You can also make your own EpiDataView and grab lets say Assembly and then remove the Filter and bind it to a Navigator and Navigate all.

Just another option (ex:)
PS: you can also make it a bit prettier.
image

I helped @Banderson with this, maybe he has a copy lay9ing around.

2 Likes

Here’s some customization code for job entry. You will need the BAQ in the system to make it work.

JobAssy-1.baq (11.6 KB)

// **************************************************
// Custom code for JobEntryForm
// Created: 7/26/2018 12:18:09 PM
// **************************************************
 
extern alias Erp_Contracts_BO_Project;
extern alias Erp_Contracts_BO_Part;
 
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;
using System.Reflection;
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 **
 
    //Create a Custom Menu Item to hang on the Tree Context
    MenuItem findAssy =null;
 
    //This BAQ Data View will carry the Assembly Sequences and GUIDs (Sys Row IDs)
    BAQDataView bdvjobAssy;
    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
 
        // End Wizard Added Custom Method Calls
 
        //Instanciate the Custom Menu Item
        findAssy =  new MenuItem("Go To Assy Num", new EventHandler(cmFindAssy));
         
        //Create an Event on the Tree to Insert Our Cutom menu
         
        oTrans.JobTree.BeforeShowContextMenu += new Ice.Lib.Framework.JobLib.MethodTree.BeforeShowContextMenuHandler(jobTree_BeforeShowContextMenu1);
 
        //instanciate our BAQDataView and subscribe it
        CreateBAQView();
    }
 
    public void DestroyCustomCode()
    {
        // ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
        // Begin Wizard Added Object Disposal
 
        // End Wizard Added Object Disposal
 
        // Begin Custom Code Disposal
 
        // End Custom Code Disposal
        oTrans.JobTree.BeforeShowContextMenu -= new Ice.Lib.Framework.JobLib.MethodTree.BeforeShowContextMenuHandler(jobTree_BeforeShowContextMenu1);
    }
 
    //When our Custom menu Is Clicked...
    private void cmFindAssy(object sender, System.EventArgs e)
    {
        //Call a little Pop up Form
        frmAssyNum frm = new frmAssyNum();
        int newAssy=0;
 
 
        if(frm.ShowDialog()==DialogResult.OK)
        {
 
            int.TryParse(frm.txtAssyNum.Text, out newAssy);
 
            //Refresh Our BAQ Data View
            RefreshBAQDataView(bdvjobAssy);
            var edvAssy = oTrans.Factory("CurrAsm");
 
            //Loop through all the Job Assemblies until the right one is found
            foreach(DataRowView x in bdvjobAssy.dataView)
            {
                //When Found, Set to current assembly
                if((int)x["JobAsmbl_AssemblySeq"] == newAssy)
                {
                    oTrans.GetDatasetForTree(oTrans.JobNum, (int)edvAssy.dataView[edvAssy.Row]["AssemblySeq"], newAssy,false);
                    oTrans.JobTree.SetAssemblyNode(((Guid)x["JobAsmbl_SysRowID"]).ToString());
                    break;
                }
            }
        }
    }
    private void jobTree_BeforeShowContextMenu1(object sender, Ice.Lib.Framework.JobLib.MethodTree.NodeArgs e)
    {
        oTrans.JobTree.TreeContextMenu.MenuItems.Add(findAssy);
    }
     
    private void CreateBAQView() {
        // create the baq view and add it to the transaction
        bdvjobAssy = new BAQDataView("JobAssy");
        oTrans.Add("JobAssyB", bdvjobAssy);
  
        // publish columns we'll bind to
        var jobBinding = "JobHead.JobNum";
         
  
        oTrans.PublishColumnChange(jobBinding, Guid.NewGuid().ToString());
         
        var jobPub = oTrans.GetPublisher(jobBinding);
         
  
         
        bdvjobAssy.SubscribeToPublisher(jobPub.PublishName, "JobAsmbl_JobNum");
      
    }
 
     private void RefreshBAQDataView(BAQDataView iBaqView)
    {
        MethodInfo mi = iBaqView.GetType().GetMethod("invokeExecute", BindingFlags.Instance | BindingFlags.NonPublic);
        mi.Invoke(iBaqView, new object[]{ true });
    }
}
 
 
//This is a simple pop up form that shows the Select Assembly  Box
 
public class frmAssyNum : EpiBaseForm
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;
 
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
 
    #region Windows Form Designer generated code
 
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.txtAssyNum = new System.Windows.Forms.TextBox();
        this.label1 = new System.Windows.Forms.Label();
        this.btnOK = new System.Windows.Forms.Button();
        this.btnCancel = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // txtAssyNum
        // 
        this.txtAssyNum.Location = new System.Drawing.Point(72, 16);
        this.txtAssyNum.Name = "txtAssyNum";
        this.txtAssyNum.Size = new System.Drawing.Size(150, 20);
        this.txtAssyNum.TabIndex = 0;
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(12, 19);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(54, 13);
        this.label1.TabIndex = 1;
        this.label1.Text = "Assy Num";
        // 
        // btnOK
        // 
        this.btnOK.Location = new System.Drawing.Point(15, 51);
        this.btnOK.Name = "btnOK";
        this.btnOK.Size = new System.Drawing.Size(75, 23);
        this.btnOK.TabIndex = 2;
        this.btnOK.Text = "OK";
        this.btnOK.UseVisualStyleBackColor = true;
        this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
        // 
        // btnCancel
        // 
        this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        this.btnCancel.Location = new System.Drawing.Point(147, 51);
        this.btnCancel.Name = "btnCancel";
        this.btnCancel.Size = new System.Drawing.Size(75, 23);
        this.btnCancel.TabIndex = 3;
        this.btnCancel.Text = "Cancel";
        this.btnCancel.UseVisualStyleBackColor = true;
        this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
        // 
        // frmAssyNum
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.CancelButton = this.btnCancel;
        this.ClientSize = new System.Drawing.Size(234, 86);
        this.ControlBox = false;
        this.Controls.Add(this.btnCancel);
        this.Controls.Add(this.btnOK);
        this.Controls.Add(this.label1);
        this.Controls.Add(this.txtAssyNum);
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
        this.Name = "frmAssyNum";
        this.Text = "Enter Assembly Number";
        this.ResumeLayout(false);
        this.PerformLayout();
 
    }
 
    #endregion
 
    public System.Windows.Forms.TextBox txtAssyNum;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Button btnOK;
    private System.Windows.Forms.Button btnCancel;
 
    public frmAssyNum()
    {
        InitializeComponent();
    }
 
    private void btnOK_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.OK;
    }
 
    private void btnCancel_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Cancel;
    }
}
5 Likes

Thanks so much for this fellas!! This works great.

For others:
If you’re on a newer version, need to change “invokeExecute” to “InvokeExecute”

You need to completely restart Epicor for it to work after adding in code. Just closing Job Entry and reopening doesn’t work; it won’t scroll to the right spot in the tree.

I added these 2 lines:

...
this.Name = "frmAssyNum";
this.Text = "Enter Assembly Number";
this.AcceptButton = this.btnOK;  // Causes Enter to activate OK
this.CancelButton = this.btnCancel;  // Causes Esc to activate Cancel
this.ResumeLayout(false);
this.PerformLayout();
...
1 Like