Skip to main content

Making Sales Person required on Sales Order lines (Graph Extension) — sharing + looking for feedback

  • July 30, 2026
  • 5 replies
  • 49 views

Hi all,

I put together a small customization to make the **Sales Person** field
required on the Sales Order Lines grid (SO301000), since our process needs a
sales person on every line for commission tracking. I figured I'd share it
here in case it's useful to someone else, and also because I'm still fairly
new to Acumatica customization and would love a sanity check from people with
more experience.

The approach: since `SalesPersonID` already exists on `SOLine`, I used a
`CacheAttached` handler with `PXMergeAttributes(Method = MergeMethod.Merge)`
to add `Required = true` without redeclaring the field's other attributes,
plus a `RowPersisting` handler to actually block the save (since `Required`
alone only affects the UI).

Full code + explanation here: https://github.com/i-wild/acumatica-sales-person-required

```csharp
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "Sales Person", Required = true)]
protected virtual void SOLine_SalesPersonID_CacheAttached(PXCache cache)
{
}

protected virtual void _(Events.RowPersisting<SOLine> e)
{
    if (e.Row == null) return;
    if (e.Operation == PXDBOperation.Delete) return;

    if (e.Row.SalesPersonID == null)
    {
        e.Cache.RaiseExceptionHandling<SOLine.salesPersonID>(
            e.Row, null,
            new PXSetPropertyException("Sales Person is required.", PXErrorLevel.Error));

        throw new PXRowPersistingException(
            typeof(SOLine.salesPersonID).Name, null, "Sales Person is required.");
    }
}
```

I'd genuinely welcome feedback on things like:

- Is `RowPersisting` the right event for this, or would a different one be more idiomatic for a "required across all lines" rule?
- Would this be better implemented as a Business Event / Workflow condition instead of code, so it's easier for non-developers to maintain later?
- Any edge cases I'm not considering — API-created orders, imports, mass processing, etc.?

I appreciate your responses and suggestions

5 replies

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

Since you're modifying attributes anyway, you can block the save with a [PXDefault] instead of an event handler.


Thanks for the feedback — you're right that [PXDefault] would block the save automatically without needing the RowPersisting handler at all, since it triggers PXPersistingCheck.Null by default.

I went with RowPersisting + RaiseExceptionHandling on purpose, though: [PXDefault] alone gives the generic framework message (something like "'Sales Person' cannot be empty"), which doesn't tell the user why it matters for our process. With the explicit handler I can show a message tailored to our business rule instead, which is more helpful for the end user filling out the order.

If the generic message is good enough for someone else's use case, though, your approach is definitely less code to maintain — appreciate you pointing it out!


Forum|alt.badge.img+3
  • Captain I
  • July 31, 2026

@emmanuelaguilar87 

If the requirement is to make the field mandatory, I would lean toward using PXDefault(PersistingCheck = PXPersistingCheck.Nothing) since it's the standard Acumatica pattern. It enforces the validation consistently across the UI, Import Scenarios, REST/SOAP APIs operations without requiring custom RowPersisting code.

If you need a business specific validation message, then your RowPersisting approach makes sense. Otherwise, PXDefault is simpler, easier to maintain.


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

​I would lean toward using PXDefault(PersistingCheck = PXPersistingCheck.Nothing) 

A persisting check of 'Nothing' is not going to block the save.


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

With the explicit handler I can show a message tailored to our business rule instead, which is more helpful for the end user filling out the order.

Fair. In which case, I would use the PXUIVerify attribute instead. I prefer attributes in nearly every case they apply.