How to programmatically call the "Create Jobs" button on Order Entry program in Epicor 10?


(Arash Farmagham) #1

Hi everyone,

I have been trying to figure out the functionality behind the “Create Jobs” button on the summary page of Order Entry program. Basically when you click on it, it creates jobs for line releases that are set as ‘Make Direct’.

I have been trying to automate this so when user creates lines and saves, I would call the methods required to create jobs. I have done tracing and debugging on adapter methods but I have not been able to catch anything.

Have you guys ever tried to automate this button’s functionality?

I would appreciate your help and feedback! Thank you!


(Chris Conn) #2

I’ve never dealt with it, but if the intention is just to call that on save, it should be straight forward (assuming there are no repercussions for calling it when unneeded - for example, user clicks save multiple times)

//on save (get this even either from the toolclick or by after adapter method Update
Find the guid of the button.
var myButton = (EpiButton)csm.GetNativeControlReference(“The guid here”);
myButton.PerformClick();


(Arash Farmagham) #3

Thanks Chris,

Great solution, however I have been looking for a solution that is independent of the UI where I can call elsewhere.

Thanks and I appreciate your time :slight_smile:


(Ken Nash) #4

We created a BPM to create jobs. Is that what you are trying to do? or in C#?

We started the C# route, but then went with using the BPM widgets.

We invoke the BPM by creating a row in a UD Table. We fill the UD fields of the UD table with the information needed for the job. This then lets us use the UD update pre processing BPM widgets to create job, fill job with information, then save all using widgets. The UD table also lets us track who is creating jobs, but you might not need that.


(Chris Conn) #5

I dont have time at the moment, but i was in your shoes and wanted to know what that button does, I’d use a decompiler like ILSpy, DotPeek, etc to look at the code of that form dll


(Arash Farmagham) #6

I am hoping for a simple and straightforward solution like whateverObject.CreateJobs(orderNum);

I did trace the Job Entry program while creating a job for a sales order and added material and then checked all the method calls. I was able to mimic the process and create jobs using C# code but it is not a very clear process and sometimes it just fails to create jobs. It involves creating rows in the following tables:

JobHead
JobAsmbl
JobPart
JobProd

It is like a few hundred lines of code where you have to enter lots of information into those tables for the job you are creating.

But when you click on the ‘Create Jobs’ button on the Order Entry program, it literally takes 2 seconds for the system to generate jobs, so I am still not sure how they do it. And am surprised that the code is not available for us. (Tracing does not register the method calls when you click on that button).


(Chris Conn) #7

You can get the actual source code if you buy the SDK.


(Ken Nash) #8

That would be awesome.

The BO do a ton of the heavy lifting (as when you create a job and add a part, the other tables you mentioned get filled out epimagicly)

Try a few tests.


(Arash Farmagham) #9

So there is no easy way I assume!

I was hoping to get rid of the large code I have as it sometimes fails to do the job! The failure is usually when I call this method:

jobBO.GetNewJobProd(…)

If any of you find a super short way to generate jobs (blank jobs linked to order line releases without anything in them) please let me know. I appreciate your help :slight_smile:


(Tim Shoemaker) #10

I was able to create a “Quickjob” using a BPM and widgets… the nice thing about quickjob is that by setting parameters, you can specify all the facts up front, and then tell the quickjob Business Object to do the work. It reports back the job number that was created.
If you run a trace while using QuickJob to create a sample job, you can find the business object called, and the parameters used.


(Daryl Hewison) #11

We also do this via BPM rather than the client. You do need to be quite exact passing the table values between the components of the OrderJobWiz BO, from memory, but otherwise it works quite seamlessly. I wouldn’t call it super-quick, mind you. It usually takes 3-5 seconds per job.

I have no reason to suppose the same wouldn’t work from within a customization, but our users prefer the process not to delay them between lines, rather have it kick off once they’ve completed the order, so I have never tried. I think I’d still be inclined to use a BPM even so, though.


(Arash Farmagham) #12

In QuickJob Entry you must enter part numbers… I don’t think you can use it to just create a job and assign it to an order line release without having any part numbers.


(Daryl Hewison) #13

Try the OrderJobWiz BO.

You can run a trace on that from Order Entry, which is what you want anyway.


(Dan) #14

Everything you need should be contained within the JobEntry adapter.

Connect to Adapter
GetNewJobHead
GetNextJobNum
Fill in your JobEntryData jobhead dataset
Update
GetByID (created job)
GetNewJobProd
Update
GetDetails
Update

I use this to create my orders and then jobs from project entry.


(Arash Farmagham) #15

I have done this and it works 99% of the time!! Sometimes it fails on jobBO.GetNewJobProd(…) and a re-login or IIS cache flush fixes it.
Problem is I didn’t want to do loads of code, filling datasets, updating many tables and so on just to create empty jobs. I thought maybe somewhere inside one of these business objects there is a method that can be called with only order number as the parameter and let it create jobs… preferably an Epicor method… similarly mimicking what happens when user clicks on the ‘Create Jobs’ button. I am basically trying to simplify the already big solution I have in place that works 99% of the time!!!


(Jeff) #16

Have you looked at the OrderJobWizard adapter? As Dhewi stated.


(Arash Farmagham) #17

The trace shows that ValidateJobs is called before CreateJobs. I still need to know how to fill the dataset that is being passed to ValidateJobs and then CreateJobs.

The trace doesn’t seem to have everything. Was hoping for something like this to work:

        string errMsg = string.Empty;
        string warningMsg = string.Empty;

        OrderJobWizImpl bo = WCFServiceSupport.CreateImpl<OrderJobWizImpl>(_userSession, OrderJobWizImpl.UriPath);

        OrderJobWizDataSet ds = bo.GetMatrix(10165, 0, 0);

        bo.ValidateJobs(ds, out warningMsg);

        bo.CreateJobs(ds, out errMsg);

But it does not create jobs even if you mention the line and release numbers. Also you must enter ship by date on the release prior to attempting to create jobs using the wizard according to the documentation and still no luck.


(Theodore Koch) #18

I use this and it works everytime.

	private void CreateJob(string jobNum)
	{
		if (jobNum == string.Empty)
			return;	

		if (JobExists(jobNum))
		{
			MessageBox.Show(string.Format("Job {0} already exists.", jobNum));
			return;
		}

		if (MessageBox.Show(string.Format("Job {0} will be created and linked to this release.\r Would you like to proceed?", jobNum), "Create Job", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
			return;
	
		int orderNum = Convert.ToInt32(OrderRel_Row.dataView[OrderRel_Row.Row]["OrderNum"]);
		int orderLine = Convert.ToInt32(OrderRel_Row.dataView[OrderRel_Row.Row]["OrderLine"]);
		int orderRel = Convert.ToInt32(OrderRel_Row.dataView[OrderRel_Row.Row]["OrderRelNum"]);

		JobEntryDataSet ds = new JobEntryDataSet();
        job.GetNewJobHead(ds);
        foreach (JobEntryDataSet.JobHeadRow headerRow in ds.JobHead)
        {
            if (headerRow.RowMod.ToUpper() == "A")
            {
                headerRow.JobNum = jobNum;
                headerRow.PartNum = OrderDtl_Row.dataView[OrderDtl_Row.Row]["PartNum"].ToString();
                job.ChangeJobHeadPartNum(ds);
                headerRow.PartDescription = OrderDtl_Row.dataView[OrderDtl_Row.Row]["LineDesc"].ToString();
                headerRow.Plant = ((Session)oTrans.Session).PlantID;
				headerRow.ReqDueDate = Convert.ToDateTime(OrderRel_Row.dataView[OrderRel_Row.Row]["ReqDate"]);
				headerRow.JobEngineered = true;
				job.ChangeJobHeadJobEngineered(ds);
				headerRow.JobReleased = true;
				job.ChangeJobHeadJobReleased(ds);
                job.Update(ds);

                ds = job.GetByID(headerRow.JobNum);
                job.GetNewJobProd(ds, headerRow.JobNum, headerRow.PartNum, orderNum, orderLine, orderRel, string.Empty, string.Empty, 0);
                ds.JobProd[0].ProdQty = Convert.ToDecimal(OrderRel_Row.dataView[OrderRel_Row.Row]["SellingReqQty"]);

                job.Update(ds);

				ScheduleJob(jobNum, Convert.ToDateTime(OrderRel_Row.dataView[OrderRel_Row.Row]["ReqDate"]));

				MessageBox.Show(string.Format("Job {0} created.", headerRow.JobNum));
				oTrans.Refresh();
            }
        }
	}

private void ScheduleJob(string jobNum, DateTime reqDate)
{
	try 
		{	        
			ScheduleEngineDataSet ds = new ScheduleEngineDataSet();
			ScheduleEngineDataSet.ScheduleEngineRow row = ds.ScheduleEngine.NewScheduleEngineRow();
	        row.Company = ((Session)oTrans.Session).CompanyID;
	        row.JobNum = jobNum;
	        row.AssemblySeq = 0;
	        row.OprSeq = 0;
	        row.OpDtlSeq = 0;
	        row.StartDate = DateTime.Today; //new DateTime(2015, 12, 18);
	        row.StartTime = 0;
	        row.EndDate = reqDate;
	        row.EndTime = 0;
	        row.WhatIf = false;
	        row.Finite = false;
	        row.SchedTypeCode = "ja";
	        row.ScheduleDirection = "End";
	        row.SetupComplete = false;
	        row.ProductionComplete = false;
	        row.OverrideMtlCon = true;
	        row.OverRideHistDateSetting = 2;
	        row.RecalcExpProdYld = false;
	        ds.ScheduleEngine.AddScheduleEngineRow(row);
	        bool l_finished;
	        string c_WarnLogTxt;
	        engine.MoveJobItem(ds, out l_finished, out c_WarnLogTxt);				
		}
		catch (Exception ex)
		{
			MessageBox.Show(ex.Message);
		}
}

(Arash Farmagham) #19

That’s much shorter than what I currently use. Will definitely give it a try. Thanks tkoch!


(Theodore Koch) #20

@duckor is right though, you still need to call GetNextJobNum to get the next job number available. I did not include that in the example.