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:
Add logic to the "POHeader_AfterFieldChange" event to listen for the custom date field change
On change, loop through each qualifying row in the EpiDataView for releases (PORel) and set the custom date field
Use the oTrans.Update() method to save the release changes otherwise upcoming changes to the PO line items will wipe them out
Next, loop through the qualifying PO line items (PODetail) and set the custom date field
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!
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!
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?
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();