Using REST to close a job from PHP


How would I call the job closing REST service from PHP with CURL?

The automatic job closing inside Epicor is not working for us, we have complicated business needs to keep certain jobs open that built-in Epicor controls just can’t handle.

I would like to just pass the company and job number to close the job. Is that possible?

Sure … you have the link to the helper method it shows you the data that must be passed in a POST call to invoke this object.
Simply create this JSON Object and use CURL or another library available in PHP to make the call.
You can use POSTMAN to generate the PHP code for you if you’d like. But there are a zillion examples in the ole google and a few on this website on how to use CURL to hit a REST URL.

“Simply create this JSON Object”

I’m lost how and what do do at that step. What JSON object?

Here is an example function I created that checks Epicor credentials that works:

  //This function will call a REST service on Epicor10 and check if the user+pass combo supplied by the user is legit
function check_epicor_credentials($username = "", $password = "") {

	//initialize the return value
		$valid_credentials = false;

	//Needed inside the HTTPHEADER Authorization parameter
	//Authorization is the base64 encoded string of "username:password"
		$auth = base64_encode("manager:manager");

	//Start CURL
		$curl = curl_init();

	//Set CURL Options
		curl_setopt_array($curl, array(
			CURLOPT_URL => "https://our-E10-server/E10Train/api/v1/Ice.BO.UserFileSvc/ValidatePassword",
			CURLOPT_POSTFIELDS => "{\r\n  \"userID\": \"". $username. "\",\r\n  \"password\": \"" . $password . "\"\r\n}",
				"Authorization: Basic " . $auth,
				"Cache-Control: no-cache",
				"Content-Type: application/json",

	//Run CURL
		if ( !$c_response = curl_exec($curl) ) {
		//CURL call error
			//echo curl_error($curl);
			$valid_credentials = false;
		} else {
		//CURL call success
			$s = json_decode($c_response, true);
			$valid_credentials = ($s['returnObj']); //returnObj is what the REST function returns, values of this are true or false

	//Close CURL

		return ($valid_credentials);

} //end function check_epicor_credentials

I don’t know where the POST fields go or how to package them to send to CURL. The example on the API shows a huge list of items as well, how do I generate those?

Run a Trace in Epicor on the Job Closing screen you’ll have to use those BO calls to generate the DataSet.
There’s a call in there somewhere which will return the data set. Make a call to GetNewJobClosing pass in just an empty json array

  "ds": {}


  "parameters": {
    "ds": {
      "JobClosing": [
          "Company": "EPIC06",
          "JobClosed": false,
          "ClosedDate": null,
          "JobComplete": false,
          "JobCompletionDate": null,
          "PrintProductionDetail": false,
          "BackFlush": false,
          "StockQty": 0,
          "OrderQty": 0,
          "ReceivedToStockQty": 0,
          "ShippedQty": 0,
          "JobNum": "",
          "CompleteQty": 0,
          "PartNum": "",
          "CanPrintProfitInfo": false,
          "BackFlushProcessing": false,
          "LegalNumber": "",
          "PartDescription": "",
          "ProdQty": 0,
          "UserAllowedToCloseJob": false,
          "MultiplePlant": false,
          "MultiplePlantContinue": 0,
          "PendingInspection": false,
          "PendingInspectionContinue": 0,
          "QuantityContinue": 0,
          "LegalNumberMessage": "",
          "JobUOM": "",
          "BitFlag": 0,
          "OpenDMR": false,
          "OpenDMRContinue": false,
          "WIPCleared": false,
          "SysRowID": "d98dd928-98d5-408b-8536-bd798b1f1020",
          "EnableWIPCleared": false,
          "ReceivedToJobQty": 0,
          "PartNumSalesUM": "",
          "PartNumSellingFactor": 1,
          "PartNumIUM": "",
          "PartNumTrackSerialNum": false,
          "PartNumPartDescription": "",
          "PartNumTrackDimension": false,
          "PartNumPricePerCode": "E",
          "PartNumTrackLots": false,
          "RowMod": "A",
          "ProjID_c": "",
          "ProjPhaseID_c": "",
          "VerifiedBy_c": "epicor",
          "Verified_c": false
      "JobMtl": [],
      "JobOper": [],
      "JobPart": [],
      "LegalNumGenOpts": []

That will return that dataset above, fill in the values and then post it to the CloseJob end point.

1 Like

Sorry for being dense, it’s difficult to follow what you are saying because I’m at a much lower technical level with Epicor.

I ran a trace. trace.xml (163.1 KB)

Let me know if I got this right:

  1. CURL to get JobClosingTableset
  2. CURL to get GetNewJobClosing
  3. Put the return values from JobClosingTableset into GetNewJobClosing result (how would someone do this btw?)
  4. CURL to CloseJob, pass in the GetNewJobClosing dataset that was filled with the results from step 1

If that’s correct then I don’t know how to do JobClosingTableset because there is no documentation on it in the Swagger, the Trace XML says that it’s a BO (or maybe it doesn’t, I’m not sure).

As an alternate, you could use @josecgomez’s trick and use a UBAQ and just pass in the job you want to close in a REST call to it and let the UBAQ do the heavy lifting.

Mark W.

1 Like

This sounds more like something we can handle. Calling a BAQ and passing the job to close would be great.

I just did a Trace in Job Closing Manually

Epicor Calls the following BO’s

  • Erp.Proxy.BO.JobClosingImpl.GetNewJobClosing (This returns back and Empty Job Closing Data Set)

  • Erp.Proxy.BO.JobClosingImpl.OnChangeJobNum (they pass in the above data set as well as the parameters pcJobNum with the job number you want to bring back, this returns back the dataset populated with the job data.

  • Erp.Proxy.BO.JobClosingImpl.OnChangeJobClosed (Then you check the “Closed” checkbox (set JobClosed = true) in the data set and call this

  • Erp.Proxy.BO.JobClosingImpl.PreCloseJob (you call this to check for warnings with the dataset)

  • Erp.Proxy.BO.JobClosingImpl.CloseJob (with the dataset)

You need to replicate the above in rest and make each and every one of these calls. Get the data back updated it, and call the next.

1 Like