BPM for one table to update another table

I am currently having no luck building a BPM that takes these 4 data fields: CustID, AreaID, CustName and a Package from a Service Plan form, and TRIGGER the creation of another form and populate its field details based on the CustID from the previous Service Plan form.

I am inside the Update method directive for a Service Plan form. An external process is sending an object with the above data into Epicor. My current BPM starts if a row has been updated on the Service Plan table. I then invoke BO method (TablesUpdatedByExternalEvent). If the external event argument is false I then set “callContextBpmData.CharacterXX” field to the data field expressions. When I put an exception message at the end of my BPM to display the bpmData characters, I instead get this generic invalid operation error:

image

This is as far as I’ve gotten and I have no idea how to proceed to do the following:
A) Link the two forms based off the CustID and trigger the creation of a new secondary form
B) Filter one of the fields so that it sets “callContextBpmData.CharacterXX” to only start with “ABC”, if it doesn’t then throw an exception.
D) To enable a post processing directive or not

I’ve considered to use custom C# code on a function or a BAQ adding the first table fields data into the second table fields data, which I think is the correct option but am unsure of how to proceed.

The end goal is to automate the process of manually going in and creating a new form rather when a new client is signed up to a service plan, a new unique ID for them is also created.

Well first things first, click Detail, and lets see the full stack.

That would help!

Here is the full picture:

If the 1st condition - “There is atleast one updated row in the ds.AC_CCServicePlan table” is true we invoke the below method as the data was pulled in through an external API.


Next if the EventFrmInbounc variable is = true, it will set “callContextBpmDataCharacter01 - 04” fields with the 4 data fields (CustID, AreaID, CustName and Package) respectively.

We then arrive at a filter, if the Package.CD begins with “HCP” set the data field, if it doesn’t throw an exception.

From here I wanted the message to display below:


Now I am unsure if this is even the correct way to solve this problem (with a BPM). The next step besides setting the 4 data fields is to trigger the creation of a new form (Segment Account Values) form which should populate rows inside that table with the 4 data fields above.

Kind’ve confused on how to achieve this solution with the existing BPM, would it be better achieved through a BAQ subquery solution or Custom C# code?

Remove that link between Invoke BO Method and Condition 3 so the rest are orphaned.
See if the error still occurs.

If it does, you have a problem there.

Can’t answer that one, I don’t have that integration module, and still trying to wrap my head
around what you’re doing :slight_smile:

The link has been removed between condition 3 and Invoke BO Method and I am still getting the same error as above.

To be honest I was fuzzy on what the actual solution should require but now I have a more consolidated idea. The idea is to check whether there is an existing Account Segment Value for a client, if there is not, I want to create a new one for that client. So from this understanding I would want to query the rows on the respective tables and fill a table with a value if it does not have one or check if there is a duplicate.

I have looked on the data dictionary viewer and need to add the SegmentCode of the COASegValues table to display the value of CustID from the AC_CCServicePlan table if the Customer(Client) has a segment code, if it is empty, I need to assign the CustID to the SegmentCode field.
We’ll want to be Adding/Inserting records, not updating. SegmentCode and Segment Name needs to be set to the CustID.

I want to create Account Segment Values for their CustID’s.

Okay, I have consolidated something I think tries to explain what I am doing in a better way.

This is done inside a custom C# widget on a pre-processing update BPM inside the AC_CCServicePlan directive.

this.CallService<Erp.Contracts.AC_CCServicePlan>(ac_ccServicePlan => {

// Generate New Account Segment Value
var ds = new Erp.Tablesets.COASegValuesTableset();
ac_ccServicePlan.GetNewCOASegValues(ref ds);

var grpRow = ds.COASegValues.FirstOrDefault();
// if (grpRow != null)
          var COASegValuesHeadRow = ds.COASegValues.Where(x => x.RowMod == "A").FirstOrDefault();
          int servicePlanID = 0;
          
          if(pkgType == "HCP")
          {
            servicePlanID = Db.AC_CCServicePlan.Where(x => x.Company == Session.CompanyID && x.CustNum == COASegValuesHeadRow.CustNum && x.PackageCD.StartsWith(pkgType) && x.Status == "A").Select(x => x.ServicePlanID).DefaultIfEmpty(0).FirstOrDefault();
          }
          else
          {
            servicePlanID = Db.AC_CCServicePlan.Where(x => x.Company == Session.CompanyID && x.CustNum == COASegValuesHeadRow.CustNum && x.PackageCD == pkgType && x.Status == "A").Select(x => x.ServicePlanID).DefaultIfEmpty(0).FirstOrDefault();
          }
		  
		            COASegValuesHeadRow.ServicePlanID = servicePlanID;  <-- check method directives + function directive for ac_AdjHeadRow to find ServicePlanID
          ac_ccServicePlan.Update(ref ds);


// Get the CustID from the Service Plan table
string custID = (string)adapter.Get("AC_CCServicePlan", "CustID");

// Check if an Account Segment Value already exists for this CustID
using (ds segmentValuesAdapter = new ds(session))
{
    segmentValuesAdapter.BOConnect();

    ds segmentValuesTableset = segmentValuesAdapter.GetByID(custID);

    if (segmentValuesTableset.COASegValues.Rows.Count == 0)
    {
        // Create a new Account Segment Value with the CustID as the Segment Code and Name
        COASegValuesTableset.Row newRow = COASegValuesTableset.COASegValues.NewRow();

        newRow.CustID = custID;
        newRow.SegmentCode = custID;
        newRow.SegmentValueName = custID;
        newRow.COACode = "Main";
        newRow.SegmentNbr = "4";

        COASegValuesTableset.COASegValues.Rows.Add(newRow);

        segmentValuesAdapter.Update(ref ds);
    }

    Db.Validate();
}

Unfortunately my lack of experience with Epicor and C# let’s me down with not knowing how to solve the below. I know for the most part “COASegValues” and “COASegValuesTableSet” is not the correct syntax and needs to be referenced correctly, however I don’t know where to look. I have added a filter to filter the package field also.

Yeah you have a little bit of a row to hoe, but you’ll learn.

I’ll help you in the AM if I can. If not I’m sure someone will jump in here and get you started down the correct path.

I have done some custom code that I feel is on more of the right track now. However I am still getting significant errors but this is just syntax related, I feel this better displays what I’m tyring to accomplish.

/* This code first retrieves the custID and packageCD fields from the AC_CCServicePlan table and joins it with the 
COASegValues table on the CustID field. Then, it filters the results to only include records where the packageCD 
starts with "HCP". For each matching record, it checks if an Account Segment Value already exists for the CustID, 
if not, it creates a new Account Segment Value with the CustID as the Segment Code and Name. 
The new Segment Value is then added to the COASegValues table and saved using the COASegValues service. */

var result = from ac_ccServicePlanRow in Db.AC_CCServicePlan
             join COASegValuesRow in Db.COASegValues
             on ac_ccServicePlanRow.CustID equals COASegValuesRow.CustID
             where ac_ccServicePlanRow.Company == Session.CompanyID
             && ac_ccServicePlanRow.PackageCD.StartsWith("HCP")
             select new 
             {
                 ac_ccServicePlanRow.CustID,
                 ac_ccServicePlanRow.PackageCD,
                 COASegValuesRow.SegmentCode,
                 COASegValuesRow.SegmentValueName,
                 COASegValuesRow.COACode,
                 COASegValuesRow.SegmentNbr
             };

foreach (var res in result)
{
    // Check if an Account Segment Value already exists for this CustID
    using (var ds = new Erp.Tablesets.COASegValuesTableset())
    {
        ds.Read(res.CustID);

        if (ds.COASegValues.Rows.Count == 0)
        {
            // Create a new Account Segment Value with the CustID as the Segment Code and Name
            Erp.Tables.COASegValues newSegmentValue = ds.COASegValues.NewRow();

            newSegmentValue.CustID = res.CustID;
            newSegmentValue.SegmentCode = res.CustID;
            newSegmentValue.SegmentValueName = res.CustID;
            newSegmentValue.COACode = res.COACode; // set to 'Main'
            newSegmentValue.SegmentNbr = res.SegmentNbr; // set to '4'

            ds.COASegValues.Rows.Add(newSegmentValue);
            this.CallService<Erp.BO.COASegValues>(svc =>
            {
                svc.Update(ref ds);
            });
        }
    }
}

What are your errors?

I am familiar with C# referencing somewhat and I’m unsure what to change for example the custID not being an accessible extension method, I am trying to access a field called custID (or custNum) inside the COASegValues table so I don’t know why that error is occurring.

I don’t know how to proceed with any of these errors and need some guidance. The referencing of methods, classes libraries for example I am familiar with however I am new to epicor so still trying to wrap my head around how it uses the ICE Library and method directives etc…

I am also writing this code inside a code widget within a BPM inside the COASegValues.Update method directive. Just wondering if this is best practice, as all these changes should be taking place irrespective of the UI, as these updates should update the tables themselves.