Quote Line Discount % reverts to 0 when changing Qty - how to force it to remain unless specifically over-typed?

Example
We Have built a quote in Quote Entry, with 25 lines.
We have applied a discount (say 10% to 30%) on most of those lines.
We later amend the quote qty per line (from say 10 to 11) and the discount % reverts to 0%.
We have to manually add in the discount %.

Epicor state that this is working as it should.
Our choices are to apply a fixed discount % via pricelist or by customer.
However neither of these work for us.
We tailor our quote to land a big order with a customer and will apply a bespoke discount per line according to the deal we are trying to win.

Is it possible to set a BPM (or similar) so that when the QuoteDtl.ExpectedQty field changes from ‘any’ to ‘another’ - the QuoteDtl.DiscountPercent does not change?

I tried a BPM to instruct the QuoteDtl.DiscountPercent to = QuoteDtl.DiscountPercent when the qty field changed, but it didn’t work, it reverted to 0.

In reality, our quote can be 100+ lines long and so amending the discount % line by line is incredibly tedious for sales so if we can instruct it to remain in place unless over-typed, that would be fantastic!

There is a similar issue when changing the ShipTo. The prices all revert back to $0.00.

I’ve seen a suggestion were you add a UD field to the line, to hold the value you want to keep. Then with a pre-proc BPM, copy the real value in the QuoteDtl to the UD field. Then in a post-proc BPM, copy the UD value back to the QuotDtl field.

Not sure which BO Method(s) you’d need to hook into. Use Trace to see which ones fire.

1 Like

EDIT

You’ll need to save both the QuoteDtl.DiscountPercent and QuoteDtl.DocDiscount fields. So you’ll need 2 UD fields

end edit

The following appears to work:

Two Method Directives as shown below

image

Method #1 (the Pre-Proc)

Set the UD field to the current DiscPct. Note that I didn’t add a UD field, but just used the field Rpt1Discount. You should add the UD field and use that

Method #2 (the Post- Proc)

Set the DiscPct field to the UD field’s value. (agin I just used Rpt1Disc in my example, you should use a UD field)

Note that both of those methods are required

1 Like

Ckrusen do you wear a Cape and tights?
Actual superhero

2 Likes

I like solving problems. It’s the best way to learn!
:man_superhero:

I am winning at 75% of this.
pre Processing on: Erp.Quote.ChangeSellingExpQty

set new UD field to store QuoteDtl.Discount, yes this works
set new UD field to store QuoteDtl.DiscountPercent, yes this works

Post Processing on on: Erp.Quote.ChangeSellingExpQty

set QuoteDtl.Discount to equal the new QuoteDtl Discount UD field, No not working, stays wiped at 0.00
set QuoteDtl.DiscountPercent to equal the new QuoteDtl Discount PercentUD field, yes working.

I’m guessing that this is because the quotedtl.discount field is already a calculated field based on several ‘if’ clauses?

field help on quotedtl.discount:
QuoteDtl.DiscountPercent * (QuoteQty * UnitPrice). This field can also be directly updated by the user, However it is refreshed whenever the DiscountPercent, UnitPrice or OrderQty fields are changed?

Any help appreciated!

Try setting DocDiscount, instead of just Discount

Thanks - I have tried docdiscount too.

I’ve run a trace log

When I first enter a discount %, the discount amount does not change, see here where the discount% is set to 10 but the actual discount value remains at 0:

This occurs a long way under the ‘GetUnitPriceInfo’ method name, but it’s the closes method I can see listed before the 10% discount is displayed:

Erp.Proxy.BO.QuoteImpl GetDtlUnitPriceInfo
      <DiscountPercent>10.00</DiscountPercent>
      <Discount>0</Discount>
      <DocDiscount>0</DocDiscount>  

The actual discount value doesn’t change until much further along the trace log, under the “Update” method name:

Erp.Proxy.BO.QuoteImpl Update

[removed lots of lines inbetween….]
10.00
3.80
3.80

Long story short, I’ve tried to implement the Quotedtl.discount field to restore back to it’s original content (via the new ud field) under the update method instead, but I still get nothing.

I’ve set up an extra new ud field which will take the value of the saved discount amount, so I know I can
a) save the quotedtl.discount value and
b) set another field to take that value

I just can’t get it to work on quotedtl.discount!

If you save the line with the mismatching DiscPct and Disc, and then refresh, does it then show the proper discount?

It does when I first enter a discount %
The discount amount is 0.00 until I save
If I then change the expected selling qty, the discount % now remains in place (e.g. 10%) but the discount amount reverts to 0.00, and save/refresh does not pull in the correct amount, or any change at all, it stays at 0.00
so I have discount 10%, but discount amount 0.00

We have some similar issues with special rates, which I could only solve by forcing changes to the QuoteQty table, because at some hard-to-define points the QuoteDtl fields seem to re-set to the same as QuoteQty. May be worth exploring?

Thanks Daryl, have you any examples? even a basic overview - my sales team are ready throw Epicor out the window and use paper and wax crayons instead :wink:

Here’s the thread where I was wrestling with it.

I’ve got to get out of the office now so anything else will have to wait until tomorrow, I’m afraid. But in general terms, I found that there are some fields in QuoteDtl that, if you’re changing them programmatically, need to be changed in the associated QuoteQty rows(s) as well if you want them to stick. I assume there must be a correct approach that can handle it all in the background as the native UI does, but I haven’t found it. For me, QuoteDtl keeps reverting to QuoteQty and I can’t stop it so I have to make sure both are the same before it happens.

thanks Daryl

Something I just realized… You don’t want to save the existing Discount amount, but rather recalculate it based on the qty and Price (which could get tricky if you use price breaks).

Also … What if you try setting the DiscountPct first (before setting Discount) - since the Disc amount is based on that. Especially since the UI flows that way (you tab to the DiscPct first)

For completeness, here’s the code which is now working for us. It’s from a uBAQ rather than a BPM, but the same BO applies for both.

// Update QuoteQty with changed prices (necessary before setting QuoteDtl price, otherwise QuoteDtl price will reset to this)
            // note: if quantity breaks can be used then checks to update only the correct row will be needed
            foreach (var ttRow in ttResultsUpdate)
            {
                int qline = ttRow.QuoteDtl_QuoteLine;
                foreach (var qqty in (from row in q.QuoteQty where row.QuoteLine == qline select row))
                {
                    decimal docprice = ttRow.QuoteDtl_DocExpUnitPrice;
                    if (qqty.DocUnitPrice != docprice || qqty.PricePerCode != ttRow.QuoteDtl_ExpPricePerCode)
                    {
                        decimal price = Decimal.Round(docprice / exrate,2);
                        qqty.UnitPrice = price;
                        qqty.DocUnitPrice = docprice;
                        qqty.PricePerCode = ttRow.QuoteDtl_ExpPricePerCode;
                        qqty.RowMod = "U";
                        upd = true;
                    }
                }
            }
            if (upd)
            {
                svc.Update(ref q);
                upd = false;
            }
            
            // Update main QuoteDtl with changed prices or discounts
            foreach (var ttRow in ttResultsUpdate)
            {
                int qline = ttRow.QuoteDtl_QuoteLine;
                foreach (var qdtl in (from row in q.QuoteDtl where row.QuoteLine == qline select row))
                {
                    decimal docprice = ttRow.QuoteDtl_DocExpUnitPrice;
                    decimal disc = ttRow.QuoteDtl_DiscountPercent;
                    if (qdtl.DocDspExpUnitPrice != docprice || qdtl.ExpPricePerCode != ttRow.QuoteDtl_ExpPricePerCode)
                    {
                        qdtl.DocDspExpUnitPrice = docprice;
                        qdtl.ExpPricePerCode = ttRow.QuoteDtl_ExpPricePerCode;
                        qdtl.RowMod = "U";
                        svc.GetDtlUnitPriceInfo(true,false,ref q);
                        svc.GetDtlUnitPriceInfo_User(true,false,false,true,ref q);
                        qdtl.RowMod = "U";
                        upd = true;
                    }
                    if (qdtl.DiscountPercent != disc)
                    {
                        qdtl.DiscountPercent = disc;
                        qdtl.RowMod = "U";
                        svc.GetDtlUnitPriceInfo(true,false,ref q);
                        qdtl.RowMod = "U";
                        upd = true;
                    }
                }
            }
            if (upd)
            {
                svc.Update(ref q);
                upd = false;
            }

Obviously it’s incomplete as it’s part of a larger piece of code we’re using, but when we do this the discounts and prices do stay in place. The key is the additional method calls which do the recalculation, I think, and for us (as I said) making sure the QuoteQty doesn’t conflict.

Thank you so much for sharing.

@KMenz -

It works for me when I do the following in the post-proc

  1. Set Field 0: Set the ttQuoteDtl.DiscountPercent field to the UD field from the pre-proc
  2. Set Atguemnet/Var: Set the variable newDiscAmt to
    ttQuoteDtlRow.Rpt1Discount * ttQuoteDtlRow.SellingExpectedQty /100
  3. Set Field 1: Set the ttQuoteDtl.Discount field to the variable newDiscAmt
  4. Set Field 2: Set the ttQuoteDtl.DocDiscount field to the variable newDiscAmt

QuoteKeepDisc

EDIT

Step 2 is missing the unit price, and uses RptDiscount1 for my test when the UD field is what should be used.

1 Like

I’m sure this is the approach to take. I’d just add a couple of caveats based on the fact that I’ve been wrestling with Quotes on and off for months now:

Although calculating the fields (as per your Set Argument) mostly works fine, it can cause sporadic problems. It’s more reliable to call the methods in the Quote BO that do it for you, and I think in this case it just needs GetDtlUnitPriceInfo with the right parameters after setting DiscountPercent.

Sometimes you need an extra step to make sure the changes show up in the client. It shouldn’t the way you’ve done it, but I’m never surprised when it is needed.

1 Like

Thanks so much @dhewi and @ckrusen

Annoyingly,I can get the discount % to stick but still can’t get the discount amount to recalculate in the QuoteDtl.Discount or QuoteDtl.DocDiscount fields.

I’ve tried setting the variable to generate the new discount amount as :

(ttQuoteDtlRow.SellingExpectedQty *
ttQuoteDtlRow.DocExpUnitPrice )
*
(ttQuoteDtlRow.UDField<System.Decimal>(“SaveDiscountPct_c”) /100 )

I’ve also set a new UD field to store this value just so I can run SQL and check it works, and it does. So I can trust the build to a fair extent, but it seems that QuoteDtl.Discount and QuoteDtl.DocDiscount are protected by a force field and I can’t push a value in there.

I’ve tried on
Quote >
ChangeSellingExpQty
GetUnitPriceInfo
Update

I could set the new UD field to be our discount amount but the work then needed to amend every report and other calculation feeding from it would be insane.