Mark all Quote lines as Engineered

Hey gang, before you write vague references to things like “write a function”, “use a BPM”, or “fuggle the liftvarhaven” I am new to the world of BPM and Functions so I will need direction on where to even start. The only thing I know is what is possible and I know how to access Method Directive and Function Maintenance, but I wouldn’t even know where to start after that. So please either point me at some good training or take me step by step if you can. I’ve looked at a few posts similar to what I want and I got lost very quickly as the people in the threads were talking at a higher level.
I do have minimal Application Studio experience, I have a fair SQL background so BAQs are not too bad for me, I do also have programming background (admittedly on a deprecated language, but I can more or less handle C#). OK enough about me and my situation, now on to the challenge at hand.
We will rely very heavily on Epicor CPQ for our product line items. We are pretty close to having 20 CPQs completed, I anticipate that 95%+ of our line items will be driven by CPQ. Our sales team will be handling Quotes with upwards of 50 line items at times. Asking them to check the “Engineered” button on each line before sending a quote will be a real time suck. Epicor quotes cannot be printed until all lines are marked as Engineered. CPQ line items come into the Quote as Part on the fly, therefor the Engineered flag is not set. Only one of our CPQ products will actually require Engineering to review prior to quote submission. We would like to allow our sales team to send quotes without waiting and without the time suck.
I theorize we could write an Epicor Function to check the “Engineered” flag on each line item at the click of a button on the Quote screen. The reason I say Function and not BPM is that we may want to leave the lines in the un-Engineered state to allow CPQ editing until right before quote submission.
I know likely comments might steer in a different direction however let me make a few direct questions in case I am on the right path:

  1. Is an Epicor Function tied to a button on the Quote Entry page the right direction?
  2. When setting up the Function I am assuming (making an arse out of myself) I would be pretty much using a code block, but if there is somewhere else I need to start please point me in a direction. I don’t mind if you point me at documentation or training, I have been looking. So far I feel overwhelmed knowing where to start.
  3. Is there any reference materials on the code i can use in these code blocks and how to reference the particular Quote Detail lines in a loop to check if they are checked or not and make the appropriate change?

PS we are working with a consultant on other pieces already and could have them work on this, but I feel I will need to learn sooner or later and I think now is the time.
Also thanks in advance this community has already been a great help.

1 Like

You’re definitely on the right track here. BPMs are executed based on when the Epicor Business Object methods are called (Method Directives) or when specific tables are updated (Data Directives), so if you’re wanting more user control, a function is probably the way to go.

I tend to use custom code functions, but I think you could probably do this one with widgets. I would take a look at the Epicor documentation for Functions (Open up Functions Maintenance, click Help > Application Help).

For something like this, the “Update Table by Query” widget would probably do the job. In your function, you would pass in the quote number from the entry form that your user is working in as a Request Parameter (set in Function > Signature tab).

You would then use the “Invoke BO Method” to call the “Quote.GetByID” method, which will give you the Quote Tableset for the quote you’re working with. The Tableset is a collection temporary tables (QuoteHed, QuoteDtl, QuoteAsm, etc) that the Business Object uses for updating data.

Next, you can use the Update Table by Query widget to update your quote lines to engineered. If you’ve used the BAQ editor, it’s very similar. You can add the QuoteDtl table, then bind the values to the query results or specified expressions. That last part is the key, because it will let you set the QuoteDtl.Engineered field to true. You’ll also need to set the QuoteDtl.RowMod field to "U", which tells the Business Object that row needs to be Updated (U = Updated, A = Added, D = Deleted).

image

Then the last thing to do would be to invoke the BO Method “Quote.Update”, which will then save / update all the tables with populated “RowMod” fields.

If you’d prefer to use custom C# code, that can be done too. Personally, I find using code preferable to using widgets, but that’s just me. The code below essentially does the exact same thing as the widgets above, using the same BO Methods and everything:

// First, use CallService to use the Business Object

this.CallService<Erp.Contracts.QuoteSvcContract> (svc =>
{
    // Next, retrieve the Quote Tableset using the GetByID method
    Erp.Tableset.QuoteTableset QuoteTS = svc.GetByID( MyQuoteNum );

    // Now you have the Tableset, you can loop through the Quote Lines
    foreach ( var quoteLine in QuoteTS.QuoteDtl )
    {
        // Now, set your Engineered field to true and your RowMod field to "U"
        quoteLine.Engineer = true;
        quoteLine.RowMod = "U";

        //Update the Tableset to save the changes to the row
        svc.Update( ref QuoteTS );
    }
});

The Epicor Help is pretty useful for understanding the basic flow and how to use the function designer. For understanding how to code a custom code function, I find it more useful to look at the functions people have posted on this forum, especially if you can find one that does something similar.

I hope this helps!

2 Likes

Correct me if I’m wrong, but If you do the widgets, update by query will just change the field in the dataset, but I don’t believe it’s actually going to call the update method. And I don’t know if you can update more than one row at a time. (Each BO is a little different and some allow it, but most don’t). So if you’re going to use widgets, you’re going to have a set up a loop and another widget for update, right?

Edit: you did say something about update… I just looked at the picture. (oops). But the question about the loop still stands.

1 Like

I should probably bold the part just below those screencaps about adding the Invoke BO Method “Update”. It does get lost since I drop the code in there just below it.

That might be the case. In the code I always put the Update inside the loop, I had thought Update Table by Query allowed multiple row updates. I don’t use widgets very often, so there’s a good chance I’m wrong on that. If that’s the case, there’s definitely some extra widget work that needs to be done.

Me too. And the widget will update the fields. But in the UI, whenever you change lines, the system does a save, so functionally, you can never have more than one row change at a time. Because of that, most BOs only take one change at a time. It’s one of the reasons I don’t like widgets. There are many reasons to need to loop, and it’s really challenging to do with the widgets.

2 Likes

OK gang, thank you for the input. I skipped some of the first big post and see some comments that this approach may not work because I would be trying to update multiple records. Before I go digging further into the steps in that very nice first response, do I need to modify the approach before I get started?

It’s not that it won’t work, but you’ll probably have adjust the widget approach and make a loop. Some people have done it if you search around, so it’s possible, but since @kve already gave you the C#, it’s probably easier just to go with that.

2 Likes