Copy UD Field from Sales Order Header to Line and Release

I have added a UD date field to the sales order header, line and release.

Part 1
As new line and releases are added, I want to copy the value from the header to the line and release.

I have created two post-processing method directives on, Erp.BO.SalesOrder.GetNewOrderDtl and Erp.BO.SalesOrder.GetNewOrderRel. I am trying to set OrderDtl ud date field to the OrderHed UD date field, but get the error “There are no records in the table” whenever I point to anything in the OrderHed table. For the OrderRel UD date field, I assigned the value from the OrderDtl and it worked fine. I just can’t get the value from the OrderHed.

Part 2
If the value changes on the order head, I want to prompt the user the to update the value on the order line and release or not. The same if the value changes on the line, prompt the user to update the value on the release or not.

This will be implemented on the Classic UX for now, but will be moved to Kinetix UX in a couple months. A solution that works in both is prefered. Suggestions on the best way to implement Part 1 and Part2 are appreciated.

Part 1

You won’t find OrderHed data in the ds for the GetNewOrderDtl and GetNewOrderRel methods since it’s just returning a fresh OrderDtl or OrderRel row, you’ll need to go to the database for it. I have some BPMs doing similar stuff, here’s how I structure them (in this case for GetNewOrderDtl):

foreach (var OrderDtl_row in ds.OrderDtl.Where(x => x.RowMod == "A"))
{
        // Fetch the header-level value you want to copy from the database
        string headerStringField = (
            from OrderHed_row in Db.OrderHed
            where OrderHed_row.Company == callContextClient.CurrentCompany
                && OrderHed_row.OrderNum == orderNum // (orderNum is a parameter)
            select OrderHed_row.StringField
        ).FirstOrDefault();
        
        // Assign the corresponding field in OrderDtl to the fetched value
        if (headerStringField != null)
        {
            OrderDtl_row.StringField = headerStringField;
        }
    }
}

Part 2

I’ve also been working on something similar, but haven’t quite gotten it done yet. I have it separated into two BPMs, a Pre-Processing to check for the change to my field and confirm with the user, then a Post-Processing to make the change to the other tables in the database. Here’s the general structure I am still working through:

Pre-Processing

  1. Start
  2. Condition (the selected field has been changed from any to another)
  3. Call BPM Data Form (confirming with the user)
  4. If confirmed → Enable Post Directive

Post-Processing

  1. Start
  2. Condition (enabled from pre-processing directive)
  3. Custom code to update the database

Here’s the structure of that custom code block, not sure it’s working yet:

var OrderHed = ds.OrderHed.FirstOrDefault();

if (OrderHed != null)
{
    var OrderDtl = Db.OrderDtl.Where( x =>
        x.Company == OrderHed.Company &&
        x.OrderNum == OrderHed.OrderNum &&
        x.OpenLine == true
    );

    foreach (var OrderDtl_row in OrderDtl)
    {
        OrderDtl_row.StringField = OrderHed.StringField;
    }

    Db.Validate();
}

Hope this helps!

Thanks, I was able to get the field off the order header. Moving on to the next step.

Hi Brendan,

I would not recommend doing a direct database update. It is safer on UD fields, but it’s very much not recommended. The pre-processing part is correct, but your custom code does a direct DB update, which you shouldn’t do. Instead of that, use an Invoke Function widget.

  1. Create an Epicor function library
  2. In “References”, add the Service “SalesOrderSvc”
  3. Add a new Custom Code Function
  4. In the function signature, add an int “orderNum” and string “newStringUD”
  5. In the custom code editor:
var OpenLines = Db.OrderDtl
                      .Where( x => x.Company  == Session.CompanyID 
                                && x.OrderNum == orderNum 
                                && x.OpenLine )
                      .Select( s => s.OrderLine )
                      .ToList();


CallService<Erp.Contracts.SalesOrderSvcContract>( svc => {
    
    foreach ( int orderLine in OpenLines )
    {
        var SalesOrderTS = svc.GetByID( orderNum );

        var row = SalesOrderTS.OrderDtl.FirstOrDefault( x => x.OrderLine == orderLine );

        if ( row == null || !row.OpenLine ) continue;

        row.StringField = newStringUD;
        row.RowMod = "U";

        svc.Update( ref SalesOrderTS );
    }
});
2 Likes