Order Discount BPM

I’m trying to write a data directive, in-trans method on the OrderDtl table to set the discount of certain part numbers to a discount percentage defined elsewhere in the system.
The intention being, when the add/update a part on the line, it defaults to that specified percent instead of the default at the header. The data directive was also chosen because when they change the header percentage and blow it down to all the lines, I don’t want those lines with the custom discount to change, so it’s being intercepted there.
I have the BPM do some checks and gather data, then ultimately set the following three fields: DiscountPercent, DocDiscount, and DocDspDiscount. Hurray, it works! … Kinda. Turns out it totally hoses up the OrderHed.TrueDiscountPercent and OrderHed.(Doc)TotalDiscount fields–as in it doesn’t recalc these numbers and they eventually get out of sync and it starts to throw errors. Boo! So, next, I did a trace and identified what BO’s are being used (trace below) and executed those in a custom code block. Same result as just setting the fields. Hmmm.
My last attempt was to set the fields using the widgets, then, at the very end, I wrote some code to loop through all of the lines to calculate the total discount, then push that to the OrderHed.(Doc)TotalDiscount field. This successfully updates the field and the OrderHed.TrueDiscountPercent recalcs properly, but, as you can imagine, on large orders, the performance is terrible.
(I did try all of this on a method directive, but it had the same issues plus some poor user experience)
Does anyone have any other suggestions?

<tracePacket>
  <businessObject>Erp.Proxy.BO.SalesOrderImpl</businessObject>
  <methodName>ChangeDiscountPercent</methodName>
  <appServerUri>net.tcp://isiepicor/TEST/</appServerUri>
  <returnType>System.Void</returnType>
  <localTime>5/13/2019 10:53:40:4825746 AM</localTime>
  <threadID>1</threadID>
  <executionTime total="82" roundTrip="37" channel="0" bpm="0" other="45" />
  <retries>0</retries>
  <parameters>
    <parameter name="ds" type="Erp.BO.SalesOrderDataSet">
      <SalesOrderDataSet xmlns="http://www.epicor.com/Ice/300/BO/SalesOrder/SalesOrder" />
    </parameter>
  </parameters>
  <paramDataSetChanges>
    <paramDataSet name="ds" useDataSetNbr="0">
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DiscountPercent"><![CDATA[13.00]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="UD_SysRevID"><![CDATA[System.Byte[]]]></changedValue>
    </paramDataSet>
  </paramDataSetChanges>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.SalesOrderImpl</businessObject>
  <methodName>MasterUpdate</methodName>
  <appServerUri>net.tcp://isiepicor/TEST/</appServerUri>
  <returnType>System.Void</returnType>
  <localTime>5/13/2019 10:53:41:8283975 AM</localTime>
  <threadID>1</threadID>
  <executionTime total="3303" roundTrip="3262" channel="0" bpm="6" other="35" />
  <retries>0</retries>
  <parameters>
    <parameter name="lCheckForOrderChangedMsg" type="System.Boolean"><![CDATA[True]]></parameter>
    <parameter name="lcheckForResponse" type="System.Boolean"><![CDATA[True]]></parameter>
    <parameter name="cTableName" type="System.String"><![CDATA[OrderDtl]]></parameter>
    <parameter name="iCustNum" type="System.Int32"><![CDATA[14722]]></parameter>
    <parameter name="iOrderNum" type="System.Int32"><![CDATA[550796]]></parameter>
    <parameter name="lweLicensed" type="System.Boolean"><![CDATA[False]]></parameter>
    <parameter name="lContinue" type="System.Boolean"><![CDATA[False]]></parameter>
    <parameter name="cResponseMsg" type="System.String"><![CDATA[]]></parameter>
    <parameter name="cCreditShipAction" type="System.String"><![CDATA[]]></parameter>
    <parameter name="cDisplayMsg" type="System.String"><![CDATA[]]></parameter>
    <parameter name="cCompliantMsg" type="System.String"><![CDATA[]]></parameter>
    <parameter name="cResponseMsgOrdRel" type="System.String"><![CDATA[]]></parameter>
    <parameter name="cAgingMessage" type="System.String"><![CDATA[]]></parameter>
    <parameter name="ds" type="Erp.BO.SalesOrderDataSet">
      <SalesOrderDataSet xmlns="http://www.epicor.com/Ice/300/BO/SalesOrder/SalesOrder" />
    </parameter>
  </parameters>
  <paramDataSetChanges>
    <paramDataSet name="ds" useDataSetNbr="0">
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DiscountPercent"><![CDATA[13.00]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="Discount"><![CDATA[2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DocDiscount"><![CDATA[2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="OrdBasedPrice"><![CDATA[20.01000]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DocOrdBasedPrice"><![CDATA[20.01000]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DocDspDiscount"><![CDATA[2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DocLessDiscount"><![CDATA[-2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DocTotalPrice"><![CDATA[20.010]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="DspDiscount"><![CDATA[2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="LessDiscount"><![CDATA[-2.99]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="TotalPrice"><![CDATA[20.01]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="CurrencySwitch"><![CDATA[False]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="RowMod"><![CDATA[U]]></changedValue>
      <changedValue tableName="OrderDtl" rowState="Modified" rowNum="1" colName="UD_SysRevID"><![CDATA[System.Byte[]]]></changedValue>
    </paramDataSet>
  </paramDataSetChanges>
</tracePacket>

<tracePacket>
  <businessObject>Ice.Proxy.BO.ReportMonitorImpl</businessObject>
  <methodName>GetRowsKeepIdleTime</methodName>
  <appServerUri>net.tcp://isiepicor/TEST/</appServerUri>
  <returnType>Ice.Tablesets.ReportMonitorTableset</returnType>
  <localTime>5/13/2019 10:53:45:4485481 AM</localTime>
  <threadID>10</threadID>
  <executionTime total="28" roundTrip="8" channel="18" bpm="0" other="2" />
  <retries>0</retries>
  <parameters>
    <parameter name="whereClauseSysRptLst" type="System.String"><![CDATA[((PrintDriver='TEXT' AND (AutoAction='PRINT' OR AutoAction='PREVIEW')) OR (PrintDriver='CRYSTAL' AND (AutoAction='PRINT' OR AutoAction='AUTOPRT' OR AutoAction='PREVIEW' OR AutoAction='AUTOPRV')) OR (PrintDriver='EPIFIN' AND (AutoAction='PRINT' OR AutoAction='PREVIEW')) OR (PrintDriver='BARTENDER' AND (AutoAction='AUTOPRT' OR AutoAction='AUTOPRV')) OR (PrintDriver='EDI' AND AutoAction<>'') OR (PrintDriver='SSRS' AND (AutoAction='PREVIEW' OR AutoAction='PRINT') AND LastAction='SSRSREADY')) AND WorkStationID='MK1LAWILLETT 1']]></parameter>
    <parameter name="pageSize" type="System.Int32"><![CDATA[0]]></parameter>
    <parameter name="absolutePage" type="System.Int32"><![CDATA[0]]></parameter>
    <parameter name="morePages" type="System.Boolean"><![CDATA[False]]></parameter>
  </parameters>
</tracePacket>

<tracePacket>
  <businessObject>Ice.Proxy.BO.SysMonitorTasksImpl</businessObject>
  <methodName>GetBallonRowsKeepIdleTime</methodName>
  <appServerUri>net.tcp://isiepicor/TEST/</appServerUri>
  <returnType>Ice.Tablesets.SysMonitorTasksTableset</returnType>
  <localTime>5/13/2019 10:53:45:4770495 AM</localTime>
  <threadID>10</threadID>
  <executionTime total="27" roundTrip="10" channel="14" bpm="1" other="2" />
  <retries>0</retries>
  <parameters>
    <parameter name="whereClauseSysTask" type="System.String"><![CDATA[history = true and startedon > 05/12/2019]]></parameter>
    <parameter name="whereClauseSysTaskLog" type="System.String"><![CDATA[]]></parameter>
    <parameter name="pageSize" type="System.Int32"><![CDATA[0]]></parameter>
    <parameter name="absolutePage" type="System.Int32"><![CDATA[1]]></parameter>
    <parameter name="morePages" type="System.Boolean"><![CDATA[False]]></parameter>
  </parameters>
</tracePacket>

So why don’t you try running it as a PostProcessing Method Directive, where you call the actual BO to change the discount and let Epicor do all the magic?

1 Like

If they change the header discount and select to push it to all lines, the method directives aren’t being fired. On top of that, it didn’t recalc the header fields when I used the BO’s anyways.

Hmm interesting I’ve done some of this before successfully with the BO before…:face_with_monocle:

Maybe I just got lost in the mix… Lemme try it again and report back.

1 Like

So, I seem to be back where I started.
Using the Post Processing requires a refresh for the discounts to appear or else you get the “Row Modified by Another User” error; not so good for UX.
Then, if they change it on the header and elect to have it change all lines, the method does not get called.

You can make a refresh from the BPM side. @hmwillett

var ds1 = svc.GetByID(orderNum)
this.dsHolder.Attach(ds1);

This run after your Post Processing Code will refresh the dataset and remove the Modified by another user issue.

4 Likes

For real?
Neat! (You can tell by the way it is)

:laughing:

Seriously, that’s the coolest thing since sliced bread.
How have I not know about this?

1 Like

Its only documented in like 1 spot =) in the ABL to C# Guide.

2 Likes

So, the last piece of the puzzle is when they change the discount on the header; it still blows down to every line.
Can I modify the orderLines parameter?
I tried setting it to something new in the Pre-Proc method, but it doesn’t seem to take.
It would be nice to be able to pass it my own list.

<tracePacket>
  <businessObject>Erp.Proxy.BO.SalesOrderImpl</businessObject>
  <methodName>UpdateOrderDtlDiscountPercent</methodName>
  <appServerUri>net.tcp://isiepicor/TEST/</appServerUri>
  <returnType>Erp.Tablesets.SalesOrderTableset</returnType>
  <localTime>5/13/2019 14:50:56:4770745 PM</localTime>
  <threadID>1</threadID>
  <executionTime total="5422" roundTrip="3249" channel="0" bpm="2153" other="20" />
  <retries>0</retries>
  <parameters>
    <parameter name="orderNum" type="System.Int32"><![CDATA[550699]]></parameter>
    <parameter name="orderLines" type="System.String"><![CDATA[1~2~3~4]]></parameter>
  </parameters>
</tracePacket>

Do you get a MessageBox asking you if you want to change the Discount on Lines and Releases?

I do, yes.

1 Like

Try setting the Lock Discount Checkbox at the line level when you do your logic?

I remember doing something with the Need By Date and Ship By Date.

I added to my SalesOrder.MasterUpdate a PRE to set

2019-05-13_1607

lCheckForOrderChangedMsg = false;
lcheckForResponse = false;

or was in the POST

Trace the MasterUpdate when you select yes and no, you can also surpress and even change the message.

But I remember I could stop it from executing and even suppress the messagebox.

Can you do this on a data directive too?
I’m getting errors with that code.

no on dataDirective you don’t have to refresh the dataset

Do you know of a good way of doing this following a “Raise Exception” widget?
Since it terminates, it never makes it to the post processing.

Instead of using throw new BLException(“…”);

Try using
ExceptionManager.AddBLException(“Your Exception Here…”) and then after your dsHolder.Attach try doing ExceptionManager.AssertNoBLExceptions();

If you need to raise an exception message but continue processing to check for additional error conditions, use ExceptionManager.AddBLException() to push the exception into the Exception Manager but allow processing to continue. When you reach a point in the code that processing should handle any errors added to the ExceptionManager, then run ExceptionManager.AssertNoBLExceptions(). If there are any exceptions in the ExceptionManager when AssertNoBLExceptions is called, all exceptions will be thrown in a single exception back
to the client.