Updating Custom Date Field on Purchase Order Release

Hi all,

I am currently working on an Epicor 10.1 “Customization” and I’m having trouble setting a custom date field value on a purchase order line item’s release (PORel). Essentially, when I modify a custom date value on the purchase order header (POHeader), or on the line item (PODetail), I’d like to copy the date value over to the release (PORel).

Scenario #1 - When the purchase order header (POHeader) custom date changes, cascade the change to all line items (PODetail) and releases (PORel)

I’ve been able to solve this scenario using the following approach:

  1. Add logic to the "POHeader_AfterFieldChange" event to listen for the custom date field change
  2. On change, loop through each qualifying row in the EpiDataView for releases (PORel) and set the custom date field
  3. Use the oTrans.Update() method to save the release changes otherwise upcoming changes to the PO line items will wipe them out
  4. Next, loop through the qualifying PO line items (PODetail) and set the custom date field
  5. Call oTrans.Update() again to save the line item changes

I’m not convinced that this is the correct solution or efficient for that matter, but it is semi-functional at the moment.

Scenario #2 - When a line item (PODetail) custom date changes, cascade the change to the related releases (PORel)

For this scenario, I’ve tried countless approaches without much success. It appears that there is a relationship between the PODetail and PORel EpiDataViews, along with internal Epicor events, causing the purchase order release row to be re-initialized when the parent line item is changed. I am currently able to set the custom date value on the release and see it presented on the UI, but the “save” button or oTrans.Update() causes the value to reset as if it is not committed to the database. A quick list of the methods I’ve tried in various ways can be found below:

  • .BeginEdit()
  • .EndEdit()
  • ["RowMod"] = "U"
  • oTrans.Update()
  • oTrans.Refresh()
  • Notify()
  • NotifyAll()
  • EpiDataView.RaiseRowChanged(…)
  • EpiDataView.EpiDataChange()

Does anyone happen to have a working code snippet for altering a field value on a purchase order line item release? If using a BPM instead of a Customization is recommended, feel free to comment as well. I will gladly post some of my current logic if needed, but I’d rather not have non-functioning code as the initial focal point. Thank you for any input and advice!

-Jamie

I’d make two separate actions one that updates POReleases on a change to the POLine. And another to update the POLines on a change to the POHead.

Changing the Header should cause the lines to update and each line change should cause the Release to update.

One potential bug would be if the Lines already have the date the header is changing to, but their releases were different. Those releases would not update.

Example

Header:  2/15/19
Line 1:  2/20/19
Rel 1.1: 2/25/19

Changing the Header to 2/20, would not cause a change to the Line, so its Release would not be updates

Thank you for your reply Calvin. Your suggestions follow my current logic quite closely. I have two actions (C# functions) that are called to update the custom date fields. One action updates the purchase order releases (PORel) and features an optional parameter for the line item number (POLine). The second action updates the custom date field on the line items (PODetail).

To work around the bug you described, I set a boolean flag indicating that the header was modified and then I call both actions starting with the releases action first to work around the issue described in my original post. Since the header flag is set, I can avoid calling the releases action a second time during the "AfterFieldChange" event of the related line item. Once both actions are complete, I clear the header flag. Below is a quick wireframe of how I call the two actions. Please note that the code below is for reference only and will not compile.

//Header flag
private bool isPOHeader_AfterFieldChange;

private void POHeader_AfterFieldChange(object sender, DataColumnChangeEventArgs args)
{
//...
//If Date field was changed...

//Set the PO header changing flag
isPOHeader_AfterFieldChange = true;

//Update the releases without the line number parameter
SetPORelCommitmentDates(dateValue);

//Update the line items
SetPODetailCommitmentDates(dateValue);

//Clear the PO header changing flag
isPOHeader_AfterFieldChange = false;

}

private void PODetail_AfterFieldChange(object sender, DataColumnChangeEventArgs args)
{
//...
//If Date field was changed...

//Check if the PO header flag was set
if(!isPOHeader_AfterFieldChange){
SetPORelCommitmentDates(dateValue, poLineNumber);
}
}

private void SetPORelCommitmentDates(DateTime dateValue, int? poLine = null){
//...
//Loop to update PORel EpiDataView rows
//...
}

private void SetPODetailCommitmentDates(DateTime dateValue){
//...
//Loop to update PODetail EpiDataView rows
//...
}

If you or other developers have suggestions for the setting field values on either the release or the detail, feel free to share them. I can also post the complete logic I have currently, but unfortunately, it is only semi-functional as originally described. Thanks again!

Don’t Forget to account for:

  1. Paste Insert / Paste Update into Grid
  2. Creating a New PORel should probably by default populate to Date as its siblings?
  3. Creating a New PODtl creates a silent PORel (might trigger diff events)

Other Helper Vars that could assist you are:

// Last Active View
if (oTrans.LastView.ViewName == "PORel") { ... }

The issue we are seeing (I am a coworker of Jamie’s) is that the values being set via the Form Customization code are being sent to the server on Save (Update), but on the next Refresh (GetByID) the values in PORel are coming back as they were prior to the custom code executing. See attached text file for the ‘changed values’ portion of the tracelog on Update.

We’re trying to figure out if there is something special about PO Entry behavior that is affecting the values being sent, that will have to be worked around via fancy codework… or if our method of updating these values is incorrect. Is there more to updating an existing record than changing a field value and setting its RowMod = U?

8014222-Save.txt (5.2 KB)

You will have to post more code, so we can see how you are updating the rows for a start (ex your foreach loop).

Also PO Update maybe one of many that doesn’t support multiple dirty rows, so you would have to oTrans.Update() after each single Column Change.

foreach(OrderRel) { modifyaColumn(); oTrans.Update(); }

I think this might be the key. I wasn’t aware that there were some Update methods that only support a changing a single row at a time. Is there a way to know this apart from trial and error?

Below is a snippet of code used to update the purchase order releases. When this function is called from the “POHeader_AfterFieldChange” event and the line item parameter (poLine) is left NULL, it is working as desired. If called from the “PODetail_AfterFieldChange” event where the current PO line number is known and provided, it does not properly save the release changes. It seems that the oTrans.Update() statement reverts the custom date value.

	private void SetPORelCommitmentDates(DateTime? commitmentDate, int? poLine = null){
		//Prepare the dataView filter
		string filter = "OpenRelease = True";

		//Check if a PO line number was specified
		if(poLine != null){
			//Only open releases on the provided PO line
			filter = String.Format("POLine = {0} and {1}", poLine, filter);
		}

		//Confirm that we have one or more rows to update
		if(edvPORel.dataView.Table.Select(filter).Length > 0){
			try
			{
				//Update the UI status bar
				oTrans.PushStatusText("Updating release Commitment Date...", true);
		
				//Process the PO releases
				foreach(DataRow release in edvPORel.dataView.Table.Select(filter)){							
					oTrans.PushStatusText(String.Format("Updating Commitment Date on release {0} of line {1}...", release["PORelNum"], release["POLine"]), true);						
					release.BeginEdit();
					release["CommitmentDate_c"] = commitmentDate;
					//release["RowMod"] = "U";
					release.EndEdit();
					//release.SetModified();
					
					//Check if the PO line number was provided
					if(poLine != null){
						//NOTE: When the PO line number exists, this would indicate that the change was triggered by editing the PODetail commitment date
						//Commit the changes to the database
						oTrans.PushStatusText(String.Format("Saving release {0} of line {1} Commitment Date changes...", release["PORelNum"], release["POLine"]), true);
						oTrans.Update();					
					}
				}

				//Check if the PO line number exists
				if(poLine == null){
					//If a specific PO line number was not provided, this would indicate that the change was triggered by updating the PO Header commitment date
					//NOTE: Saving here is required here due to the form events on the POEntryForm
					//NOTE: When the UI save feature is used, it appears that the PORel view is re-initialized causing a row filter and the release of the current PODetail to be set.
					//Commit the changes to the database
					oTrans.PushStatusText("Saving release Commitment Date changes...", true);
					oTrans.Update();
				}	
	
			}
			catch(Exception ex){
				throw ex;
			}
			finally{
				//Reset the UI status bar
				oTrans.PushStatusText(String.Empty, false);
			}
		}
	}

Feel free to ask questions or request missing logic. Thanks again!
-Jamie

For anyone following this thread, or reading it at a later date, we were able to solve the issue using the CheckBeforeUpdate() and Update() functions of the POAdapter to independently commit the purchase order release changes. (Thanks Andrew!)

Below is an updated snippet for reference:

				//Process the PO releases
				foreach(DataRow release in edvPORel.dataView.Table.Select(filter)){							
					oTrans.PushStatusText(String.Format("Updating Commitment Date on release {0} of line {1}...", release["PORelNum"], release["POLine"]), true);						
					release.BeginEdit();
					release["CommitmentDate_c"] = commitmentDate.HasValue ? (object)commitmentDate : (object)DBNull.Value;
					release.EndEdit();					
				}

				//Commit the changes to the database
				oTrans.PushStatusText("Saving release Commitment Date changes...", true);
				poAdapter.CheckBeforeUpdate(out cOrderChangedMsgText, out vendorChangedMsgText, "PORel");
				poAdapter.Update();

2 Likes

many thanks @jlohrberg,
is it possible to share the full script editor screen for this PO customization ?

Hi @A.Baeisa, the script is currently going through user acceptance testing and I’ll see if I can post a finalized version soon after.