Enhancing Automation and Customization with Acumatica Business Events

  • 13 June 2023
  • 6 replies

Userlevel 7
Badge +18


I am excited to share with you the Acumatica Business Events and their powerful capabilities for automating business processes through configuration. Typically, Business Events are utilized to trigger various actions such as Email notifications, Import Scenarios, and Mobile Push Notifications. However, during my recent exploration, I came to know that we can also invoke custom code alongside these notifications.

In one of my projects, I encountered a unique requirement that I would like to share with you today. The scenario involved sending an email notification while simultaneously executing custom code to update specific details in custom tables. To achieve this, we can leverage the flexibility of Business Events by incorporating our logic within a custom subscriber. By doing so, the Acumatica framework seamlessly handles the functionality, eliminating the need to write the logic within the Confirm Shipment button or other areas.

By taking advantage of Acumatica Business Events, we can streamline our business processes and enhance automation, all while enjoying the convenience of configuration-based customization.


Create Custom Subscriber with Code

Below is the code snippet to create the Business Event Custom subscriber.

using PX.BusinessProcess.DAC;
using PX.BusinessProcess.Event;
using PX.BusinessProcess.Subscribers.ActionHandlers;
using PX.BusinessProcess.Subscribers.Factories;
using PX.BusinessProcess.UI;
using PX.Common;
using PX.Data;
using PX.Data.BusinessProcess;
using PX.PushNotifications;
using PX.SM;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace MyTestCustomSubscriber
public class CustomSubscriberEventAction : IEventAction
public Guid Id { get; set; }
public string Name { get; protected set; }
private readonly Notification _notificationTemplate;
public void Process(MatchedRow[] eventRows, CancellationToken cancellation)
string SOShipmentType = string.Empty;
string SOShipmentNbr = string.Empty;
string SOShipmentOperation = string.Empty;

var param = @eventRows.Select(
r => Tuple.Create<IDictionary<string, object>,
IDictionary<string, object>>(
r.NewRow?.ToDictionary(c => c.Key.FieldName, c => c.Value),
r.OldRow?.ToDictionary(c => c.Key.FieldName,
c => (c.Value as ValueWithInternal)?.ExternalValue ??

SOShipmentType = param.Select(x => x.Item1.Where(y => y.Key == "Document_ShipmentType").Select(c => Convert.ToString(c.Value)).FirstOrDefault()).FirstOrDefault();
SOShipmentNbr = param.Select(x => x.Item1.Where(y => y.Key == "Document_ShipmentNbr").Select(c => Convert.ToString(c.Value)).FirstOrDefault()).FirstOrDefault();
SOShipmentOperation = param.Select(x => x.Item1.Where(y => y.Key == "Document_Operation").Select(c => Convert.ToString(c.Value)).FirstOrDefault()).FirstOrDefault();

if (!string.IsNullOrEmpty(SOShipmentType) && !string.IsNullOrEmpty(SOShipmentNbr))

public CustomSubscriberEventAction(Guid id, Notification notification)
Id = id;
Name = notification.Name;
_notificationTemplate = notification;

#region Transaction

class CustomSubscriberHandlerFactory : IBPSubscriberActionHandlerFactoryWithCreateAction
public IEventAction CreateActionHandler(Guid handlerId, bool stopOnError, IEventDefinitionsProvider eventDefinitionsProvider)
var graph = PXGraph.CreateInstance<PXGraph>();
Notification notification = PXSelect<Notification, Where<Notification.noteID, Equal<Required<Notification.noteID>>>>.Select(graph, handlerId).AsEnumerable().SingleOrDefault();
return new CustomSubscriberEventAction(handlerId, notification);
public IEnumerable<BPHandler> GetHandlers(PXGraph graph)
return PXSelect<Notification, Where<Notification.screenID, Equal<Current<BPEvent.screenID>>, Or<Current<BPEvent.screenID>, IsNull>>>
.Select(graph).FirstTableItems.Where(c => c != null)
.Select(c => new BPHandler
Id = c.NoteID,
Name = c.Name,
Type = LocalizableMessages.CustomNotification
public void RedirectToHandler(Guid? handlerId)
var notificationMaint = PXGraph.CreateInstance<SMNotificationMaint>();
notificationMaint.Message.Current = notificationMaint.Notifications.Search<Notification.noteID>(handlerId);
PXRedirectHelper.TryRedirect(notificationMaint, PXRedirectHelper.WindowMode.New);
public string Type
get { return "CTTP"; }
public string TypeName
get { return LocalizableMessages.CustomNotification; }
public string CreateActionName
get { return "NewCustomNotification"; }
public string CreateActionLabel
get { return LocalizableMessages.CreateCustomNotification; }

public Tuple<PXButtonDelegate, PXEventSubscriberAttribute[]> getCreateActionDelegate(BusinessProcessEventMaint maintGraph)
PXButtonDelegate handler = (PXAdapter adapter) =>
if (maintGraph.Events?.Current?.ScreenID == null)
return adapter.Get();

var graph = PXGraph.CreateInstance<SMNotificationMaint>();
var cache = graph.Caches<Notification>();
var notification = (Notification)cache.CreateInstance();
var row = cache.InitNewRow(notification);
row.ScreenID = maintGraph.Events.Current.ScreenID;

var subscriber = new BPEventSubscriber();
var subscriberRow = maintGraph.Subscribers.Cache.InitNewRow(subscriber);
subscriberRow.Type = Type;
subscriberRow.HandlerID = row.NoteID;

PXRedirectHelper.TryRedirect(graph, PXRedirectHelper.WindowMode.NewWindow);
return adapter.Get();
return Tuple.Create(handler, new PXEventSubscriberAttribute[]
new PXButtonAttribute
OnClosingPopup = PXSpecialButtonType.Refresh
public static class LocalizableMessages
public const string CustomNotification = "My Custom Subscriber";
public const string CreateCustomNotification = "My Custom Subscriber";


Custom Subscriber Configuration

Created a new Business Event with Trigger Condition i.e., When the shipment is changed to CONFIRMED status, this business event will be triggered.

Configure the Business Event with the following Subscribers, along with their respective details.

  • Email Notification
  • My Custom Subscriber

Email Notification:

When the shipment is confirmed, the system will automatically send a Shipment Confirmation Email to the user using the Shipment Confirmation notification template.


​​​​​​​​​​​​​​My Custom Subscriber:

This subscriber will trigger the custom code and execute the customized logic in the background. Please refer to the debug screenshot provided below.


This article discusses the powerful capabilities of Acumatica Business Events in automating business processes through configuration. It highlights that besides triggering actions like email notifications, import scenarios, and mobile push notifications, custom code can also be invoked alongside these notifications. The article shares a unique project requirement where an email notification was sent while simultaneously executing custom code to update specific details in custom tables. It emphasizes that by incorporating logic within a custom subscriber, the Acumatica framework seamlessly handles the functionality, eliminating the need to write logic within a specific button. The use of Acumatica Business Events allows for streamlined business processes, enhanced automation, and configuration-based customization.


Happy Coding!

6 replies

Userlevel 7

Thank you for sharing this with the community @Naveen Boga!

Userlevel 7
Badge +9

Great work Naveen.

Userlevel 3

Thank you Naveen for sharing this,

It is very helpful.

Userlevel 7
Badge +4

@Naveen Boga great writeup. Thank you for sharing this.

Badge +1

This is great for triggering custom code.

But triggering shipment confirmation email is probably not the best example since it can just be triggered with standard Business Events (no code required).

I wonder what are better use cases?

Userlevel 7
Badge +18

Hi, @Ahmed  Thanks for sharing the feedback.

Yes, we do not require the custom code to trigger email notifications.

Alongside the email notification, we have the opportunity to invoke a custom code that will enable us to execute personalized logic and perform necessary insertions or updates on data within our custom tables. This added capability allows us to seamlessly integrate our unique requirements and enhance the overall functionality of our system. 

Hope this clarifies.



About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved