Add additional quote / order lines from Configurator Inputs

Hi,

We’re currently looking to implement Epicor at our business and one of my tasks is to set up product configurators. We’re picking up the basic concepts for the configurators quite well (at least I think we are :sweat_smile:). I’m currently trying to find a way we could add some additional quote and/or sales order lines based on a users selection in the product configurator.

So for example if someone selected the check box to “Include Chain”. We don’t ship the chain fitted to the gate, we send it loose so it has it’s own order line. So my question is how could I automate the addition of the quote / order line when this option is selected to pull the required part from the part master and add it to my quote or order?

I haven’t started into Configurator yet (on my to-do list… just wasn’t mission critical when we implemented), so I don’t know the inner workings. BUT, we’ve done something similar with our SO Lines.

I created a couple UD Columns on OrderDtl called “EngReq” and “RevEng”. These are for “Engineering Required” and “Reverse Engineering Required”.

So, when a sales person adds a Sales Order Line, they can choose to click either of those checkboxes if what they’re selling requires “Engineering” or “Reverse Engineering”.

We use a Data Directive on OrderDtl.Update with a condition that if those checkboxes change from “false” to “true” the directive runs some custom code.

If “EngReq_c” is true, the code creates a NEW Order Line for a Part within our Part Master called “EngReq”. It also immediately creates a job, gets details, schedules (forward), and releases. So, that job is ready immediately for Engineering to charge their time to.

This seems similar to what you’re looking for… so I would assume a similar Data Directive triggered by your checkboxes should work.

You need to determine any finer points. For example, in our case, we could have (5) line items on our sales order, all requiring engineering. We set up the Directive to only create (1) instance of a new “EngReq” line item per order. It will scan the order and if “EngReq” already exists on the Order, it stops. It will not add another. We treat Engineering on an ORDER basis, not a line item basis.

Also, if the user clicks the box on line item (1) and saves… A sales Order Line for EngReq will be added as Line Item 2. Any additional line items will be lines 3, 4, 5, 6, etc. So, we’ve trained our staff to enter all their line items first (1, 2, 3, 4, 5)… THEN go back and click the EngReq checkbox where needed… and then EngReq will show up as Line 6. A few extra steps, but it makes to orders cleaner.

2 Likes

Hey, I was just reading through various Configurator posts and it hit me that @timshuwy’s description here of Complimentary Parts may be what you’re looking for!

2 Likes

Hi @dcamlin,

Sorry I haven’t replied to your first reply until now! Yeah that does sound as if it’s the kind of thing we would like to happen for adding parts to quotes / orders from the part master. Your reply sent me off on a bit of a tangent with how you generate work requests for engineering to be done, I like the sound of that idea as we have one design engineer process an entire order too.

Regarding complementary parts we do plan to use then for ‘non’ configured items (we’re still planning out how we make this go live at the moment). I just don’t like the idea for a configurator because we are doing ETO items. Some options that are selected in the configurator as they change how something is manufactured. It would then need a secondary selection in complementary parts, doubling up on work, and it’s possible a member of the sales team could forget about it. It also is another thing to consider when amending a line.

That being said I appreciate the suggestion as for some items that is exactly what we need and plan to use, so it is a great solution for the right circumstance!!

Regards,
Josh Hudson

1 Like

Hi @Josh_Hudson,

I have a Configurator UDMethod for adding additional order lines based on configurator inputs. Simply call this UDMethod from the document rules if your conditions are met.

Example of the document rule syntax:

if ( Inputs.bool_AddMyPart.Value )
{
    UDMethods.AddOrderLine( "MyPartNum", 1.00m );
}

Below is the code for the UDMethod:

/*== AddOrderLine v2.0 =======================================================

    Configurator User Defined Method | Server-side | Return Type = void

    Parameters:
        string  - NewPartNum
        decimal - NewPartQty
    
    Purpose: 
        Pass in Part Number and Quantity from Configurator UI Selections
        Add OrderDtl Line from parameters after Configuration

                --Kevin Veldman <RFPTSolutions@gmail.com>
============================================================================*/

//
// Check if PartNum is Empty
//
    if ( NewPartNum == "" || NewPartQty == 0 ) return;

    int OrderNum = Context.OrderNumber;

//
// Use this section to ensure new line is not added on re-configuration
//
    var PartLineExists = Db.OrderDtl.Any(x => x.OrderNum==OrderNum && x.PartNum==NewPartNum);

    if ( PartLineExists ) return;


//
// Call SalesOrder BO to add new Order Lines
//
    using ( var svc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.SalesOrderSvcContract>(Db) )
    {
        // NOTE: Erp.Contracts.BO.SalesOrder.dll Assembly Reference added
        
        var tsOrder = svc.GetByID( OrderNum );
        svc.GetNewOrderDtl(ref tsOrder, OrderNum);

        var odX = tsOrder.OrderDtl.Select( x => x ).LastOrDefault();

        bool lSubPartsExist = false;
        string sUOM = "EA";

        if (odX != null) 
        {
            odX.PartNum = NewPartNum;
            odX.SellingQuantity = NewPartQty;

            var OrderDates = Db.OrderHed.Where(x => x.OrderNum == OrderNum)
                                        .Select(s => new {s.OrderDate, s.RequestDate, s.NeedByDate})
                                        .FirstOrDefault();

            odX.RequestDate = OrderDates.RequestDate ?? DateTime.Today;
            odX.NeedByDate  = OrderDates.NeedByDate  ?? DateTime.Today;
        }

        svc.ChangePartNum( ref tsOrder, lSubPartsExist, sUOM );
        svc.Update( ref tsOrder );
    }
2 Likes

@kve this is exactly what we were after I think, thank you!!!.

I’ve just tested it quickly as a POC on one of my configurators and it works great! I’ll have to try and make a couple of changes to it as most (if not all) items will be configured on a quote for us. I’m hoping this will be possible :crossed_fingers:. The the final thing will be when we have multiple instances of a configurator on my quote ensure the quantities accumulate for each instance they need to

2 Likes

It should be work pretty much the same way with the Quote dll:

/*== AddQuoteLine v2.0 =======================================================

    Configurator User Defined Method | Server-side | Return Type = void

    Parameters:
        string  - NewPartNum
        decimal - NewPartQty
    
    Purpose: 
        Pass in Part Number and Quantity from Configurator UI Selections
        Add QuoteDtl Line from parameters after Configuration

                --Kevin Veldman <RFPTSolutions@gmail.com>
============================================================================*/

//
// Check if PartNum is Empty
//
    if ( NewPartNum == "" || NewPartQty == 0 ) return;

    int QuoteNum = Context.QuoteNumber;

//
// Use this section to ensure new line is not added on re-configuration
//
    var PartLineExists = Db.QuoteDtl.Any(x => x.QuoteNum==QuoteNum && x.PartNum==NewPartNum);

    if ( PartLineExists ) return;


//
// Call Quote BO to add new Quote Lines
//
    using ( var svc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db) )
    {
        // NOTE: Erp.Contracts.BO.Quote.dll Assembly Reference added
        
        var tsQuote = svc.GetByID( QuoteNum );
        svc.GetNewQuoteDtl(ref tsQuote, QuoteNum);

        var qdX = tsQuote.QuoteDtl.Select( x => x ).LastOrDefault();

        bool lSubPartsExist = false;
        string sUOM = "EA";

        if (qdX != null) 
        {
            qdX.PartNum = NewPartNum;
            qdX.SellingQuantity = NewPartQty;

            var QuoteDates = Db.QuoteHed.Where(x => x.QuoteNum == QuoteNum)
                                        .Select(s => new {s.EntryDate, s.RequestDate, s.NeedByDate})
                                        .FirstOrDefault();

            qdX.RequestDate = QuoteDates.RequestDate ?? DateTime.Today;
            qdX.NeedByDate  = QuoteDates.NeedByDate  ?? DateTime.Today;
        }

        svc.ChangePartNum( ref tsQuote, lSubPartsExist, sUOM );
        svc.Update( ref tsQuote );
    }
2 Likes

This is some wild logic (like super cool), the only thing about this is re-configuration on old quotes should a configurator change right, like you couldn’t possible keep integrity if you’re making new quote lines based of a point in time configurator right?

Like say I make a quote 6 months ago and today y’all make a change where that very same configuration now would yield 1 additional quote line when 6 months ago it was 2 additional quote lines… that old quote is now toast right?

1 Like

That’s true. I initially used this for orders coming from a website with simple logic, and using Sales Orders. In those cases, it pretty much went directly into manufacturing, so we didn’t have to worry about changes much later.

For the situation you’re describing, you’d probably want to do a brand new quote, unless you add some logic to indicate which Added lines are associated with a configured part, and then have it delete those lines on re-configuration before adding the new lines.

1 Like

Right, either way that’s some cool code Kev.

2 Likes

Thank you!

2 Likes

Thanks Kev, this is awesome. Saved me sometime making those changes for sure! This is a near perfect solution for us and I think a lot of people will benefit from this!

Interesting point you guys raise on changes, we’re at a implementation phase so it’s hard to say how often that could trip us up at the moment I’m hoping not very many, so it’s something we could have staff manage manually :sweat_smile:

2 Likes