BPM vs. Function Call

So, I spent a lot of time building my part creation tool and came across something very interesting that I wanted to share with everyone.

Be careful when using BPMs for your customizations as they can short circuit the events in Kinetic.

I had a BPM that auto generated part numbers. I followed the same logic that has been posted across this site multiple times and was originated by @timshuwy . I used a Post Processing directive on GetNewPart and then also had a Pre Processing on Update.

I started to notice something funny happening once I applied them. Every time I created a part, the UOMs would not default. I thought it was because I did not have the default flag set correctly on UOM, but I did.

I finally traced the call with my BPM and without it. I found out that my BPM was interrupting the events that were firing in the screen. There was a default UOM event or something like that that was no longer firing. My BPM broke the App Studio logic.

Because they have moved a lot of the logic into App Studio with events, you need to be careful with how you use BPMs as it may break something you were not intending to break. I turned my BPM into a Function and then created an event to call the Function instead of using a BPM and everything worked fine. I’m thinking that BPMs are going to start going the way of the dodo and we should start using functions in app studio more.

Just thought I would share.

5 Likes

Hmm, I would report that as a bug.

Even in the Function world, BPM’s have their place as a trigger/event

2 Likes

It may be that he had some custom logic that wasn’t jiving or returning expected data.

More investigation is needed.

I think I need a little bit more context here because there’s no way your BPM should be interrupting an event that happens on the UX. What I have noticed is that in the web version Epicor has taken a lot of liberties with their BOs and gone as far as creating brand new methods for a lot of business objects.

Have you run a trace (Front end) in the Kinetic UX for adding a part and did you make sure that Epicor Isn’t Invoking a different BO? Or is your BPM On GetNew doing something to the UX I don’t see how that would happen maybe via BPM Data Form?

A quick trace show they are just calling GetNewPart :thinking:

3 Likes

Hold on, I’ll recreate it.

Does anyone know if there is a way to export the Console without all of the extra gibberish that comes along with a copy and paste?

image

So if you open your layer in App Studio and do Preview

Then you do Ctrl Alt 8 (enable debug) right be fore you hit New Part

it should display all the events in sequence that happen when you click new Part

Then do it again with the BPM enabled and see if the events are different somehow?

Yeah, that’s what I did, but it comes along with 100s of lines of gibberish like what was in my screenshot. It’s just a pain to then go through and delete it all.

Here is a screenshot of the console for Base screen and Base screen with BPM. BPM is on the right.

This is what I think is happening.

When you call GetNewPart, it returns an empty data set to the browser. When that data set is loaded, they disable events.

main.64c75fadae33a1a3.js:160 event: Update_KeyFields_ViewName actions: [event-column-disable]
main.64c75fadae33a1a3.js:160 action: event-column-disable
main.64c75fadae33a1a3.js:160 column change event disabled for table KeyFields
main.64c75fadae33a1a3.js:160 onSuccess:  [row-update, event-column-enable]
main.64c75fadae33a1a3.js:160 action: row-update param:  [{…}]
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : KeyFields.PartNum, value : 
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : KeyFields.PartNum is set with value : 
main.64c75fadae33a1a3.js:160 action: event-column-enable
main.64c75fadae33a1a3.js:160 column change event enabled for table KeyFields

Here is the same section from the BPM one.

main.64c75fadae33a1a3.js:160 event: Update_KeyFields_ViewName actions: [event-column-disable]
main.64c75fadae33a1a3.js:160 action: event-column-disable
main.64c75fadae33a1a3.js:160 column change event disabled for table KeyFields
main.64c75fadae33a1a3.js:160 onSuccess:  [row-update, event-column-enable]
main.64c75fadae33a1a3.js:160 action: row-update param:  [{…}]
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : KeyFields.PartNum, value : AutoNumber
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : KeyFields.PartNum is set with value : AutoNumber
main.64c75fadae33a1a3.js:160 action: event-column-enable
main.64c75fadae33a1a3.js:160 column change event enabled for table KeyFields

Then, when the user enters a part number and tabs off, the ColumnChanging_PartNum fires. In my screenshot above, that is where the two versions start to not equal. There are multiple events that fire after ColumnChanging_PartNum that do not fire with the BPM version. Below is all of the lines that did not happen with the BPM.

main.64c75fadae33a1a3.js:160 columnChanging: ColumnChanging_PartNum actions: [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: '{TransView.XRefChecked} !== true', onSuccess: Array(1), onFailure: Array(2)}
main.64c75fadae33a1a3.js:160 expression: 'false !== true' evaluates to 'true'
main.64c75fadae33a1a3.js:160 onSuccess:  [event-next]
main.64c75fadae33a1a3.js:160 action: event-next
main.64c75fadae33a1a3.js:160 event: SearchForSimilarPart actions: [event-next]
main.64c75fadae33a1a3.js:160 action: event-next param:  {PartNum: '%value%', SysRowID: '00000000-0000-0000-0000-000000000000', RowType: ''}
main.64c75fadae33a1a3.js:160 event: GetPartXRefInfo actions: [rest-erp]
main.64c75fadae33a1a3.js:160 action: rest-erp param:  {svc: 'Erp.BO.PartSvc', svcPath: 'GetPartXRefInfo', requestMethod: 'POST', erpRequestMethod: 'ErpPostWithDataViewProcessing', methodParameters: Array(3)}
main.64c75fadae33a1a3.js:160 ['request ErpPostWithDataViewProcessing: Erp.BO.PartSvc\\GetPartXRefInfo']
main.64c75fadae33a1a3.js:160 ['response received Erp.BO.PartSvc\\GetPartXRefInfo']
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.partNum, value : 1232453546
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.serialWarning, value :
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.questionString, value :
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.multipleMatch, value : false
main.64c75fadae33a1a3.js:160  Trying to assign object in epBinding actionResult.returnObj. epBinding values should contain only number, string or bool values. Instead received  null
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.returnObj, value : null
main.64c75fadae33a1a3.js:160 onSuccess:  [row-update]
main.64c75fadae33a1a3.js:160 action: row-update param:  [{…}]
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : TransView.SerialWarning, value :
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : TransView.SerialWarning is set with value :
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : TransView.QuestionString, value :
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : TransView.QuestionString is set with value :
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : TransView.MultipleMatch, value : false
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : TransView.MultipleMatch is set with value : false
main.64c75fadae33a1a3.js:160 onSuccess:  [condition, condition, condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: '{TransView.MultipleMatch} == true', onSuccess: Array(2)}
main.64c75fadae33a1a3.js:160 expression: 'false == true' evaluates to 'false'
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{TransView.SerialWarning}' != ''", onSuccess: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''' != ''' evaluates to 'false'
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{TransView.QuestionString}' != ''", onSuccess: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''' != ''' evaluates to 'false'
main.64c75fadae33a1a3.js:160 onError:  [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{actionResult.partNum}'.toUpperCase() === '%value%'.toUpperCase()", onSuccess: Array(1), onFailure: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''1232453546'.toUpperCase() === '1232453546'.toUpperCase()' evaluates to 'true'
main.64c75fadae33a1a3.js:160 onSuccess:  [event-next]
main.64c75fadae33a1a3.js:160 action: event-next
main.64c75fadae33a1a3.js:160 event: KeyField_Changed actions: [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{SysPages.epBinding}'.startsWith('LandingPage') || {TransView.SysReadOnly} === true", onSuccess: Array(1), onFailure: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''Part.PartNum'.startsWith('LandingPage') || false === true' evaluates to 'false'
main.64c75fadae33a1a3.js:160 onError:  [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'%value%'.length > 0", onSuccess: Array(1), onFailure: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''1232453546'.length > 0' evaluates to 'true'
main.64c75fadae33a1a3.js:160 onSuccess:  [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{Part.RowMod}' != 'A'", onSuccess: Array(1), onFailure: Array(2)}
main.64c75fadae33a1a3.js:160 expression: ''A' != 'A'' evaluates to 'false'
main.64c75fadae33a1a3.js:160 onError:  [event-next, event-next]
main.64c75fadae33a1a3.js:160 action: event-next
main.64c75fadae33a1a3.js:160 event: SysSetProposedValue actions: [row-update]
main.64c75fadae33a1a3.js:160 action: row-update param:  [{…}]
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : TransView.SysProposedValue, value : 1232453546
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : TransView.SysProposedValue is set with value : 1232453546
main.64c75fadae33a1a3.js:160 action: event-next
main.64c75fadae33a1a3.js:160 event: Update_ViewName_ColumnChanged actions: [row-update]
main.64c75fadae33a1a3.js:160 action: row-update param:  [{…}]
main.64c75fadae33a1a3.js:160 dataview.setAsync called. epBinding : Part.PartNum, value : 1232453546
main.64c75fadae33a1a3.js:160 columnChanging: ColumnChanging_Part_PartNum actions: [event-next]
main.64c75fadae33a1a3.js:160 columnChanging: ColumnChanging_Part_All actions: [condition]
main.64c75fadae33a1a3.js:160 action: event-next param:  {ProposedPartNum: '%value%'}
main.64c75fadae33a1a3.js:160 event: ChangePartNum actions: [rest-erp]
main.64c75fadae33a1a3.js:160 action: rest-erp param:  {svc: 'Erp.BO.PartSvc', svcPath: 'ChangePartNum', requestMethod: 'POST', erpRequestMethod: 'ErpPostWithDataViewProcessing', methodParameters: Array(1), …}
main.64c75fadae33a1a3.js:160 ['request ErpPostWithDataViewProcessing: Erp.BO.PartSvc\\ChangePartNum']
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'{Part.COASegReferences}' !== '' && '{Part.RowMod}' === 'A'", onSuccess: Array(1), onFailure: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''' !== '' && 'A' === 'A'' evaluates to 'false'
main.64c75fadae33a1a3.js:160 onError:  [condition]
main.64c75fadae33a1a3.js:160 action: condition param:  {expression: "'%column%' === 'ImageID' && '%value%' != ''", onSuccess: Array(1)}
main.64c75fadae33a1a3.js:160 expression: ''PartNum' === 'ImageID' && '1232453546' != ''' evaluates to 'false'
main.64c75fadae33a1a3.js:160 ['response received Erp.BO.PartSvc\\ChangePartNum']
main.64c75fadae33a1a3.js:160  Trying to assign object in epBinding actionResult.returnObj. epBinding values should contain only number, string or bool values. Instead received  null
main.64c75fadae33a1a3.js:160 dataview.set called. epBinding : actionResult.returnObj, value : null
main.64c75fadae33a1a3.js:160 dataview.setAsync complete. epBinding : Part.PartNum is set with value : 1232453546

Since the events are disabled when the data set is loaded, it does not know that the part number changed. Then all of the subsequent events that are trigger IN THE BROWSER do not trigger.

1 Like

It is the ChangePartNum rest call that is not firing. If you look at the Payload and Response for it, there is no IUM in the Payload but there is an IUM in the Response.

Since the ColumnChanging_PartNum is not firing, the rest-erp event below does not happen and the default UOMs do not get applied.

main.64c75fadae33a1a3.js:160 event: ChangePartNum actions: [rest-erp]
main.64c75fadae33a1a3.js:160 action: rest-erp param:  {svc: 'Erp.BO.PartSvc', svcPath: 'ChangePartNum', requestMethod: 'POST', erpRequestMethod: 'ErpPostWithDataViewProcessing', methodParameters: Array(1), …}
1 Like

Is the Change PartNum event not happening because you doing it in the BPM?

1 Like

Yes. I am setting the PartNum in a Post Processing BPM on GetNewPart.

1 Like

fat guy GIF

@josecgomez , I know you are busy, but was wondering if you looked into this anymore? Do you think I should open a ticket? Or maybe tag some Epicor employees on here to see what they think?

So this isn’t a bug (I don’t think) the issue here is that you are invoking ChangePartNum server side and they (epicor) is hanging UX actions on that event.

This would happen in Classic Too

You have two options here

  1. in your Backend you could invoke the related server side calls like populating the UOMs etc
  2. Set your newfangled part number in a CallContext (or other field) then in AppStudio copy your new partnumber over to the partNumber field using RowUpdate so that it (hopefully) triggers the right events.
1 Like

Love to see the finished product…

Ask and ye…

1 Like

Thanks @josecgomez !!