Skip to main content
Solved

Workflow Event Handler Not Firing.

  • October 24, 2024
  • 5 replies
  • 124 views

martinxfe
Jr Varsity II
Forum|alt.badge.img

I’ve been having trouble getting a custom event handler to fire. I’ve followed this process...

...as closely as I could, and while the action that fires the event runs, the transition triggered by the event does not. 

I feel like I’m missing something obvious, but I just can't put my finger on it. 

I’m working with 24R1 Build 24.101.0059.

For context, this is more an exercise in personal edification than looking for a workaround. 

Any input would be appreciated. 

 // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
 public class APInvoiceExtZ : PXCacheExtension<PX.Objects.AP.APInvoice>
 {
     public class Events : PXEntityEvent<APInvoice>.Container<Events>
     {
         public PXEntityEvent<APInvoice> DescChanged;
     }
 }



 // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
 public class APInvoiceEntry_Ext : PXGraphExtension<APInvoiceEntry>
 {

     public PXAction<APInvoice> ChangeDescription;
     [PXUIField(DisplayName = "ChangeDescription")]
     [PXButton]
     protected virtual IEnumerable changeDescription(PXAdapter adapter)
     {
         Base.Document.Current.DocDesc = "The Action changed this Description";

         APInvoiceExtZ.Events
             .Select(e => e.DescChanged)
             .FireOn(Base, Base.Document.Current);

         return adapter.Get();

     }


     #region Entity Event Handlers
     public PXWorkflowEventHandler<APInvoice> OnDescChanged;
     #endregion
 }



 // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
 public class APInvoiceEntry_WorklowExt : PXGraphExtension<APInvoiceEntry_Workflow, APInvoiceEntry_Ext, APInvoiceEntry>
 {
     public sealed override void Configure(PXScreenConfiguration config) { Configure(config.GetScreenConfigurationContext<APInvoiceEntry, APInvoice>()); }

     protected static void Configure(WorkflowContext<APInvoiceEntry, APInvoice> context)
     {
         context.UpdateScreenConfigurationFor(screen =>
         {
             return
             screen
             .WithActions(actions =>
             {
                     actions.Add<APInvoiceEntry_Ext>(g => g.ChangeDescription, a => a.WithCategory(PredefinedCategory.Actions));
             })

             .WithHandlers(handlers =>
             {
                     handlers
                     .Add(handler =>
                     {
                         return
                         handler
                         .WithTargetOf<APInvoice>()
                         .OfEntityEvent<APInvoiceExtZ.Events>(e => e.DescChanged)
                         .Is<APInvoiceEntry_Ext>(g => g.OnDescChanged)
                         .UsesTargetAsPrimaryEntity()
                         .DisplayName("OnDescChanged");
                     });

             })

             .UpdateDefaultFlow(flow =>
                     flow
                     .WithFlowStates(fss =>
                     {
                         fss.Update<APDocStatus.hold>(flowState =>
                         {
                             return flowState
                             .WithActions(actions => actions.Add<APInvoiceEntry_Ext>(g => g.ChangeDescription))
                             .WithEventHandlers(handlers => { handlers.Add<APInvoiceEntry_Ext>(g => g.OnDescChanged); });
                         });

                     })

                     .WithTransitions(transitions =>
                     {
                         transitions.UpdateGroupFrom<APDocStatus.hold>(ts =>
                             ts.Add(t => t
                                 .To<APDocStatus.balanced>()
                                 .IsTriggeredOn<APInvoiceEntry_Ext>(g => g.OnDescChanged)
                             )
                         );
                     })
             );
         });
     }
 }

 

Best answer by Keith Richardson

Looking through the 2023r2 code (which I am on) I can see one thing - and it may be due to the document type you picked to test on. This screen has a sequence, and the states are buried in there:

 

All of the transitions to Open come from HoldToBalance. 

Inside there, there is a sequence, and many of the actions go move to next.

For example, when adding the approval workflow, it states:

 that Pending Approval is added after hold, and is skipped when approved or rejected. So if approvals are not running, it goes to the next, and the next, etc.

So how are these triggered?
The transition shows going from hold to balance to itself when OnUpdateStatus is triggered:


This is defined as a handler tied to updating the hold flag:
 



So because of this screen, and how the workflow is configured, I would use existing logic and just remove from hold, when your handler is called, and give that a try:




Give this a try:
 

.WithHandlers(handlers =>
{
    handlers
        .Add(handler =>
            {
                return
                handler
                .WithTargetOf<APInvoice>()
                .OfEntityEvent<APInvoiceExtZ.Events>(e => e.DescChanged)
                .Is<APInvoiceEntry_Ext>(g => g.OnDescChanged)
                .UsesTargetAsPrimaryEntity()
                .WithFieldAssignments(fas => fas.Add<APInvoice.hold>(f => f.SetFromValue(false)))
                .DisplayName("OnDescChanged");
            });

})

 

View original
Did this topic help you find an answer to your question?

5 replies

darylbowman
Captain II
Forum|alt.badge.img+13

Keith Richardson
Semi-Pro I
Forum|alt.badge.img+2

I notice there is no saving in the action, give that a try.

    APInvoiceExtZ.Events
        .Select(e => e.DescChanged)
        .FireOn(Base, Base.Document.Current);
    Base.Persist();


martinxfe
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • 22 replies
  • October 25, 2024

Thanks for taking my question, Keith.

I had tried Base.Save.Press(). Unfortunately neither that nor Base.Persist() are doing the trick. It’s performing the rest of the action fine. The Description updates and saves as expected. But still no transition. 

I’m still learning the workflow API. Would the fact that the hold state is a substate of the H > B state on the APInvoiceEntry default workflow impact how the transition fires? 


Keith Richardson
Semi-Pro I
Forum|alt.badge.img+2

Looking through the 2023r2 code (which I am on) I can see one thing - and it may be due to the document type you picked to test on. This screen has a sequence, and the states are buried in there:

 

All of the transitions to Open come from HoldToBalance. 

Inside there, there is a sequence, and many of the actions go move to next.

For example, when adding the approval workflow, it states:

 that Pending Approval is added after hold, and is skipped when approved or rejected. So if approvals are not running, it goes to the next, and the next, etc.

So how are these triggered?
The transition shows going from hold to balance to itself when OnUpdateStatus is triggered:


This is defined as a handler tied to updating the hold flag:
 



So because of this screen, and how the workflow is configured, I would use existing logic and just remove from hold, when your handler is called, and give that a try:




Give this a try:
 

.WithHandlers(handlers =>
{
    handlers
        .Add(handler =>
            {
                return
                handler
                .WithTargetOf<APInvoice>()
                .OfEntityEvent<APInvoiceExtZ.Events>(e => e.DescChanged)
                .Is<APInvoiceEntry_Ext>(g => g.OnDescChanged)
                .UsesTargetAsPrimaryEntity()
                .WithFieldAssignments(fas => fas.Add<APInvoice.hold>(f => f.SetFromValue(false)))
                .DisplayName("OnDescChanged");
            });

})

 


martinxfe
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • 22 replies
  • October 30, 2024

Thank you again, Keith. 

Although that would have been a perfectly fine work around in a pinch, I knew I was supposed to be able to manipulate the sub-states with more nuance than being slave to the hold flag. 

 

You were exactly right, that it had to do with the sequence on the screen. I ended up digging into sequences, and here’s what I was able to come up with:

//Replace
                        .WithFlowStates(fss =>
                        {
                            fss.Update<APDocStatus.hold>(flowState =>
                            {
                                return flowState
                                .WithActions(actions => actions.Add<APInvoiceEntry_Ext>(g => g.ChangeDescription))
                                .WithEventHandlers(handlers => { handlers.Add<APInvoiceEntry_Ext>(g => g.OnDescChanged); });
                            });
                        })

//With

                        .WithFlowStates(fss =>
                        {
                            fss.UpdateSequence<APDocStatus.HoldToBalance>(seq =>
                                seq.WithStates(sss =>
                                    {
                                        sss.Update<APDocStatus.hold>(flowstate =>
                                            {
                                                return
                                                flowstate
                                                .WithActions(actions =>
                                                    actions.Add<APInvoiceEntry_Ext>(g => g.ChangeDescription)
                                                )
                                                .WithEventHandlers(handlers =>
                                                {
                                                    handlers.Add<APInvoiceEntry_Ext>(g => g.OnDescChanged);
                                                });
                                            }
                                        );
                                    }
                                )
                            );
                        })

This got the actions and events working as intended, and gave me full control over the workflow.

It seems existing sequence states(sub states)/actions/events must be manipulated at the sequence method level, not directly in the flowstate method level. 


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings