Print Part Attachments When Mass Printing Job Travelers

Hi guys, here is what I have achieved so far by adopting code for E10. I am breaking my case into the small parts and trying to implement them step by step but getting this error:

"**Error: CS1501 - line 127 (254) - No overload for method 'GetRows' takes 27 arguments**" 

for this part of code:

for(int x=0; x < edvJobList.dataView.Table.Rows.Count; x++)
{		
   JobEntryDataSet jobEntryDS = JobEntryBO.GetRows("JobNum = '" + edvJobList.dataView.Table.Rows[x] 
  ["JobNum"].ToString() + "'" ,"","","","","","","","","","","","","","","","","","","","","","","",0,1,out morePages);
}

I do understand that something wrong with arguments for GetRows methods but after numerous tries and attempts to fix it unfortunatelly I couldn’t.

If somebody knows how to fix this or what’s the problem any help would be very much appreciated.

Thank you,

Alex

Here is the code:

// **************************************************
// Custom code for JobTravForm
// Created: 4/19/2018 4:31:39 PM
// **************************************************

extern alias Erp_Adapters_JobEntry;

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.IO;
using System.Collections.Generic;
using Erp.BO;
using System.Text;
using Ice.Core;
using Erp.Proxy.BO;

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

// End Wizard Added Module Level Variables **

// Add Custom Module Level Variables Here **
	StringBuilder Texte = new StringBuilder();

public void InitializeCustomCode()
{
	// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
	// Begin Wizard Added Variable Initialization
	edvJobList = ((EpiDataView)(this.oTrans.EpiDataViews["jobList"]));
	edvAsmList = ((EpiDataView)(this.oTrans.EpiDataViews["assemblyList"]));
	

	// End Wizard Added Variable Initialization

	// Begin Wizard Added Custom Method Calls
	this.epiButtonC1.Click += new System.EventHandler(this.epiButtonC1_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
	edvJobList = null;
	edvAsmList = null;
	this.epiButtonC1.Click -= new System.EventHandler(this.epiButtonC1_Click);
	Texte = null;
	// End Wizard Added Object Disposal

	// Begin Custom Code Disposal

	// End Custom Code Disposal
}

private void JobTravForm_Load(object sender, EventArgs args)
{
	// Add Event Handler Code
	
	SetVersionNumber(JobTravForm);

}

private void SetVersionNumber(EpiBaseForm form)
{
	string custName = oTrans.EpiBaseForm.CustomizationName;
	string version = "?.?";
	if ( custName.LastIndexOf("_") >= 0 )
	{
		version = custName.Substring(custName.LastIndexOf("_") + 1, custName.Length - custName.LastIndexOf("_") - 1);
	}
	form.Text = form.Text + " - Version " + version;
	
}


private void epiButtonC1_Click(object sender, System.EventArgs args)
{
	// ** Place Event Handling Code Here **

	if(edvJobList.dataView.Table.Rows.Count > 0)
	{

		Ice.Core.Session epiSession = default(Ice.Core.Session);
	   epiSession = (Ice.Core.Session)JobTravForm.Session;

		bool morePages = false;
		JobEntryAdapter JobEntryBO = new JobEntryAdapter((Ice.Core.Session)oTrans.Session);
		
		//Table temporaire pour filtrer les lots
		DataTable tempTable = new DataTable();
		tempTable.Columns.Add("JobNum", typeof(string));
		tempTable.Columns.Add("PartNum",typeof(string));
		tempTable.Columns.Add("FileName",typeof(string));
		tempTable.Columns.Add("AsmSeq", typeof(string));
		tempTable.Columns.Add("ParentPart", typeof(string));
		
		foreach (var value in tempTable.Columns){
			MessageBox.Show(value.ToString());
     	}
		for(int x=0; x < edvJobList.dataView.Table.Rows.Count; x++){
		
			JobEntryDataSet jobEntryDS = JobEntryBO.GetRows("JobNum = '" + edvJobList.dataView.Table.Rows[x]["JobNum"].ToString() + "'" ,"","","","","","","","","","","","","","","","","","","","","","","",0,1,out morePages);
		}

	}

	else
	{
		MessageBox.Show("Test");
	}

}	
}

Hi Alex,

I compared your line of code side by side with mine and it is exactly the same. Have you verified the jobnum you get as a parameter ? I would probably create a string variable and a message box just before the getRows call, to get the jobnum like this:

string jobNum = edvJobList.dataView.Table.Rows[x][“JobNum”].ToString();
MessageBox.Show(jobNum);

Or you can use visual studio in debugging mode also.

I see your code is for E10, I don’t know if there is differences in the implementation. I haven’t started to work code for E10 yet, but I have it installed for testing. I used the Business Logic Tester (great tool) to quickly verify the arguments. Seems to be the same as I what have in 9.05…

Sorry If i’m am not of much help on this one, but again I am not a developer, just an admin who loves playing with code.

The easiest and cheapest solution is to display the attachments into the job traveler itself. there is a way to automatically pull the drawings from the BOM onto the job when the job is confirmed. then using the xfileattach table, you can pull in the drawings using an OEL object in crystal using the path that is stored in that table. This is how we do it.

Hi Christian,

Thanks for your response. I have verified jobnum like you proposed and I am getting a correct jobnum which I selected as well as other parameters like PartNum. I am about to use Visual Studio to debug also.

Now I am thinking about a way to access Ice.XFileRef table which contains XFileName Column with a path (i.e. N:\Drawing Files\12in mini\M0161 headstock.dft). Then, I want to check if any of those columns Contain a part number and if it returns true, I want to pass that path to a network printer.

Let me check out what is Business Logic Tester as see this name the first time.

I appreciate any help and no matter how big it is. We all here to share experience and help each other as much as we can!

Thanks,

Alex

Hi Jeff,

We are not using Crystal report, only SSRS and as far as I explored it’s not possible to pull a drawing by a custom expression in SSRS.

Actually, Ice.XFileRef table in my case is what I need but now I am researching if there is a way to access it through a customization. Do you know any ways to achieve this?

Thanks,

Alex

If you want use the Xfileref table, you will need first to access the xFileattach table which contains all attachement entries for every tables. The RelatedToFile Field contains the table name to which the attachment is related to.
As an example, if you want Job Assembly attachements, the required parameters for xFileAttach will be like this:
Company = cur-comp
RelatedToFile = JobAsmbl (you specify here the table you need, Parts, Customer, QuoteHed, QuoteDtl, …)
Key1 = [yourjobNum] (Depending on the table, Partnum, CustNum, QuoteNum…)
Key2 = [yourAssemblySequence]

Then, you will link the xFileRef Table by xFileRefNum and you can access the XFilename.
You can take a look in the data dictionary for more complete explanation of the fields.

For the Business Logic tester, look on your server in the utilities folder, there should be a folder named BL tester. I like this tool to quickly test BO methods an see the data it brings back.

Hi Christian,

Thanks for reply and explanation regarding my approach of doing things. After some testing that I have done, I found that my approach with xFileAttch and xFileRef tables is not very convenient.

Instead I think that I need to follow your code to get to this point:

foreach(DataRow ar in jobEntryDS.Tables["JobHeadAttch"].Rows)	
{	
     if(hr["jobnum"].ToString() == ar["jobnum"].ToString())
{

but here:

if(hr[“jobnum”].ToString() == ar[“jobnum”].ToString()) // I think here I can perform a slightly different check,

like :

if(ar[“FileName”].ToString().Contains(hr[“PartNum”]).ToString())
{
send a file from the path specified in FileName field to a printer (i.e. N:\Drawing Files\12in mini\M0161 headstock.dft)
}

However, to get to aforementioned step I need to resolve that error I am getting:

“Error: CS1501 - line 127 (254) - No overload for method ‘GetRows’ takes 27 arguments”

Any thoughts?

Hi Jose,

Thanks for your pointer on Document Type Maintenance.

We got some talking with Christian regarding my situation. If you got a minute wouldn’t you mind to review and comment my situation and probably advise an approach to take?
Thanks,

Alex

Alex,
I tried your code in my E10 test system, and got the same error as you. I tested with the BLTester, and the number of arguments is the same. But after digging through some post here, I think I know what is the issue. If I’m right, the GetRows method changed in E10, and it needs to be called like this: GetRows(searchOpts, morePages) where searchOpts is a variable that contains the required arguments.

As I am not familiar with using this, I will have to look into this a little bit to get it to work. I’ll keep you posted.

1 Like

Here we go, I had to change a few things but I think I managed to resolve this part. Try this code:

private void epiButtonC1_Click(object sender, System.EventArgs args)
{
// ** Place Event Handling Code Here **

if(edvJobList.dataView.Table.Rows.Count > 0)
{
	Ice.Core.Session epiSession = default(Ice.Core.Session);
        epiSession = (Ice.Core.Session)JobTravForm.Session;
			
	JobEntryAdapter JobEntryBO = new JobEntryAdapter(oTrans);
	JobEntryBO.BOConnect();
	
	//Table temporaire pour filtrer les lots
	DataTable tempTable = new DataTable();
	tempTable.Columns.Add("JobNum", typeof(string));
	tempTable.Columns.Add("PartNum",typeof(string));
	tempTable.Columns.Add("FileName",typeof(string));
	tempTable.Columns.Add("AsmSeq", typeof(string));
	tempTable.Columns.Add("ParentPart", typeof(string));
	
	foreach (var value in tempTable.Columns){
		MessageBox.Show(value.ToString());
 	}
	for(int x=0; x < edvJobList.dataView.Table.Rows.Count; x++)
	{		
		Ice.Lib.Searches.SearchOptions opts = new Ice.Lib.Searches.SearchOptions(SearchMode.AutoSearch);
		string whereClause = string.Format("JobNum = '" + edvJobList.dataView.Table.Rows[x]["JobNum"].ToString() + "'");
		opts.PageSize = 0;
		opts.AbsolutePage = 1;
		opts.NamedSearch.WhereClauses.Add("JobHead",whereClause);
		opts.DataSetMode = Ice.Lib.Searches.DataSetMode.RowsDataSet;		
		bool morePages = false;				
		
		var jobEntryDS = (Erp.BO.JobEntryDataSet)JobEntryBO.GetRows(opts,out morePages);
		foreach(DataRow hr in jobEntryDS.Tables["JobHead"].Rows)
		{
			MessageBox.Show(hr["JobNum"].ToString());
		}
	}

}
else
{
	MessageBox.Show("Test");
}

}

I have added the code for the first foreach loop in JobHead with a messagebox showing the jobnum as a way of testing.

Based on what I experienced tonight, there seems to be quite a few differences with the way of coding in E10, so it needs a little love to make the E9 code work.:wink:

and you know what the funny thing is ? I am currently working to put things in place at work to stop printing the drawings, it will be displayed on MES screen through the JobTracker instead. So in the end, I won’t have to adapt this customization in E10 ! :rofl:

Let me know how it worked for you.

P.S. I would also give a tip of the hat to @josecgomez because almost each time I’m stuck on something, I end up on some of his answers on this forum and the solution is there. This was the case 2 times tonight while working on this issue. Man, you are the master !

2 Likes

Hi Christian,

Thank you very much for your help and time on investigating my situation. I really appreciate your help!
I looked at your code and have to say that I was also on a right track but was confused at the specifying opts arguments. I tried your code and thank you it worked.

I will try to go into next table which is: jobEntryDS.Tables[“JobHeadAttch”].Rows by another foreach and see how it goes and what I will be getting from there.

Regarding MES screen, out of curiosity, how will you pass drawing from JobTraveler to MES and how it will be shown?

P.S. I also faced a lot of useful materials provided by Jose @josecgomez and they were tremendously helpful. Thank you Jose for your contributions.

1 Like

In phase 1 of our “paperless” project, we will only stop printing the drawings but we will still print the Job travelers. People on the plant floor who needs to see the drawings will use the job tracker in their MES to access it.
To make it more convenient and quick to use, I customized the Job tracker by adding a “drawings” tab. I used custom code to gather all drawings attachments path for all assemblies in the current job and list it in a grid. I modified the grid’s “FileName” column property to make the cell clickable (URL type), so when clicked, the document opens in the program associated to its extension on the computer.

Most of our drawings are done with Solidworks but a copy is saved in pdf. That’s what we use in Epicor. We also still have some old drawings done in dft, those are opened using Autovue.

2 Likes

Hi Christian,

Sorry for not being responsive for a quite some time but we are crazy busy with migration to 10.2.
About drawings, it worked and I am now having a path for our drawing. Thank you so much for your help! Now it’s just find a way to pass that to a printer, but hope it’s minor.

Regarding MES, that’s an interesting solution. I think I might do something similar in the future.

Thanks once again!

Alex

much appreciated if you can share this UI custom code here, thanks in advanced

Here it is:

    // **************************************************

    // Custom code for JobTrackerForm

    // Created: 23-04-18 12:46:12 par Christian Duguay

    // **************************************************

    using System;

    using System.ComponentModel;

    using System.Data;

    using System.Diagnostics;

    using System.Windows.Forms;

    using Epicor.Mfg.BO;

    using Epicor.Mfg.UI;

    using Epicor.Mfg.UI.Adapters;

    using Epicor.Mfg.UI.Customization;

    using Epicor.Mfg.UI.ExtendedProps;

    using Epicor.Mfg.UI.FormFunctions;

    using Epicor.Mfg.UI.FrameWork;

    using Epicor.Mfg.UI.Searches;

    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 **

    private EpiDataView edvJobHead;

    private DataTable jobAttachTbl;

    public void InitializeCustomCode()

    {

    // ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **

    // Begin Wizard Added Variable Initialization

    this.edvJobHead = ((EpiDataView)(this.oTrans.EpiDataViews[&quot;JobHead&quot;]));

    this.eugDessins.AfterCellActivate += new System.EventHandler(this.eugDessins_AfterCellActivate);

    this.edvJobHead.EpiViewNotification += new EpiViewNotification(this.edvJobHead_EpiViewNotification);

    // 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.edvJobHead.EpiViewNotification -= new EpiViewNotification(this.edvJobHead_EpiViewNotification);

    // End Wizard Added Object Disposal

    // Begin Custom Code Disposal

    this.edvJobHead = null;

    jobAttachTbl = null;

    this.eugDessins.AfterCellActivate -= new System.EventHandler(this.eugDessins_AfterCellActivate);

    // End Custom Code Disposal

    }

    public void GetAttachData()

    {

    try

    {

    string strJobNum = edvJobHead.dataView[edvJobHead.Row][&quot;JobNum&quot;].ToString();

    //MessageBox.Show(strJobNum);

    jobAttachTbl = new DataTable();

    DataRow myDataRow;

    jobAttachTbl.Columns.Add(&quot;AssemblySeq&quot;,typeof(string));

    jobAttachTbl.Columns.Add(&quot;PartNum&quot;,typeof(string));

    jobAttachTbl.Columns.Add(&quot;FileName&quot;,typeof(string));

    Epicor.Mfg.Core.Session epiSession = default(Epicor.Mfg.Core.Session);

      epiSession = (Epicor.Mfg.Core.Session)JobTrackerForm.Session;

    ///Use BO

    bool morePages = false;

    JobEntry jobEntryBO = new JobEntry(((Epicor.Mfg.Core.Session)oTrans.Session).ConnectionPool);

    JobEntryDataSet jobEntryDS = jobEntryBO.GetByID(strJobNum);

    foreach(DataRow jobHeadRow in jobEntryDS.Tables[&quot;JobHead&quot;].Rows)

    {

    foreach(DataRow jobHeadAttachRow in jobEntryDS.Tables[&quot;JobHeadAttch&quot;].Rows)

    {

    if(jobHeadAttachRow[&quot;DocTypeID&quot;].ToString() != &quot;ENGRLINK&quot;)

    {

    //MessageBox.Show(jhAttach[&quot;FileName&quot;].ToString());

    myDataRow = jobAttachTbl.NewRow();

    myDataRow[&quot;AssemblySeq&quot;] = &quot;--&quot;;

    myDataRow[&quot;PartNum&quot;] = jobHeadRow[&quot;PartNum&quot;];

    myDataRow[&quot;FileName&quot;] = jobHeadAttachRow[&quot;FileName&quot;];

    jobAttachTbl.Rows.Add(myDataRow);

    }

    }

    foreach(DataRow jobAsmblRow in jobEntryDS.Tables[&quot;JobAsmbl&quot;].Rows)

    {

    foreach(DataRow jobAsmblAttachRow in jobEntryDS.Tables[&quot;JobAsmblAttch&quot;].Rows )

    {

    if(jobAsmblAttachRow[&quot;DocTypeID&quot;].ToString() != &quot;ENGRLINK&quot;)

    {

    if(jobAsmblAttachRow[&quot;AssemblySeq&quot;].ToString() == jobAsmblRow[&quot;AssemblySeq&quot;].ToString())

    {

    //MessageBox.Show(jhAttach[&quot;FileName&quot;].ToString());

    myDataRow = jobAttachTbl.NewRow();

    myDataRow[&quot;AssemblySeq&quot;] = jobAsmblRow[&quot;AssemblySeq&quot;].ToString();

    myDataRow[&quot;PartNum&quot;] = jobAsmblRow[&quot;PartNum&quot;];

    myDataRow[&quot;FileName&quot;] = jobAsmblAttachRow[&quot;FileName&quot;];

    jobAttachTbl.Rows.Add(myDataRow);

    }

    }

    }

    }

    foreach(DataRow jobMtlRow in jobEntryDS.Tables[&quot;JobMtl&quot;].Rows)

    {

    if(jobEntryDS.Tables[&quot;JobMtlAttch&quot;].Rows.Count &gt; 0)

    {

    //MessageBox.Show(&quot;JobMtlAttch Pas vide&quot;);

    foreach(DataRow jobMtlAttchRow in jobEntryDS.Tables[&quot;JobMtlAttch&quot;].Rows)

    {

    if(jobMtlAttchRow[&quot;DocTypeID&quot;].ToString() != &quot;ENGRLINK&quot;)

    {

    myDataRow = jobAttachTbl.NewRow();

    myDataRow[&quot;AssemblySeq&quot;] = jobMtlRow[&quot;AssemblySeq&quot;].ToString();

    myDataRow[&quot;PartNum&quot;] = jobMtlRow[&quot;PartNum&quot;];

    myDataRow[&quot;FileName&quot;] = jobMtlAttchRow[&quot;FileName&quot;];

    jobAttachTbl.Rows.Add(myDataRow);

    }

    }

    }

    }

    }

    eugDessins.DataSource = jobAttachTbl;

    eugDessins.Dock = DockStyle.Fill;

    //eugDessins.DisplayLayout.Bands[0].Columns[&quot;PartNum&quot;].Width = 300;

    //eugDessins.DisplayLayout.Bands[0].Columns[&quot;FileName&quot;].Width =550;

    eugDessins.DisplayLayout.AutoFitStyle = Infragistics.Win.UltraWinGrid.AutoFitStyle.ExtendLastColumn;

    eugDessins.DisplayLayout.Bands[0].Columns[&quot;Filename&quot;].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.URL;

    //eugDessins.DisplayLayout.Bands[0].Columns[&quot;AssemblySeq&quot;].Width = 50;

    jobEntryDS.Clear();

    jobEntryDS.Dispose();

    }

    catch(Exception ex)

    {

    MessageBox.Show(ex.ToString());

    }

    }

    private void eugDessins_AfterCellActivate(object sender, System.EventArgs args)

    {

    //MessageBox.Show(args.Value.ToString());

    }


    private void edvJobHead_EpiViewNotification(EpiDataView view, EpiNotifyArgs args)

    {

    // ** Argument Properties and Uses **

    // view.dataView[args.Row][&quot;FieldName&quot;]

    // 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 &gt; -1))

    {

    GetAttachData();

    }

    }

    }

    }
2 Likes

Hi all!

I know it’s been some time since this thread’s been active, but I was just wondering if anybody was able to achieve a solution to this in 10.2. I’ve been trying multiple methods but seem to hit a wall each time. I am looking to create a button on the job traveler which automatically prints the job attachment with the job.

Any insight or code examples would be greatly appreciated!

This is probably SUPER late, but… we are on 10.2.700.13

We use “Print with Attachments”. I think this is “standard” now. We had to fight to make it a reality.

We attach drawings to the Rev of the Part. Then when the job is created Epicor pulls the attachments on the Revs on the Job as part of the Get Details process.

This works for us when printing single job travelers or mass printing. And it “interleaves” the drawings with the sub-assembly they go with.

This is not standard that’s a customization or a base extension you have. There is a product you can / could buy from Epicor Dot Net IT that did this, which is what I’m guessing you guys got.

Well. Poo.

It should be standard. I thought it was absolutely ridiculous that it wasn’t.

When the Epicor sales people were here showing off the software, we asked them if we could attach drawings. They said, “of course”. And we were ecstatic.

Then we discovered that you couldn’t do anything useful with them. Thanks Epicor.

Then our IT guy stumbled upon this Print with Attachment customization. It was a pre-built customization that we could buy “off the shelf”.

But it just dumped all the drawings at the end of the Job Traveler. It didn’t marry up the drawings with the correct subassembly. That was another fight.

I will ask our IT guy where it came from? In my opinion, everyone should have it. Unless you are already “paperless”.

We were told the same thing by Sales that sold us EPICOR. We found a solution on our own to attach drawings to Job Travellers when printing them. See link to my post on another thread. I would love the ability to have the drawing print with the Job Traveller based upon adding the attachments to the parts rev table. We have that setup now for viewing paperless but our production operators still need a paper copy of the Job Traveller that is attached to the actual parts, along with the drawing. More efficient to have paper copies at times.