Override Processing Screen Views in Acumatica: A Practical Guide
When customizing Acumatica ERP, there are times when you need to modify the behavior of standard processing screens. One common requirement is to filter data based on business rules that aren't part of the out-of-the-box functionality. In this article, we'll explore how to override the data source of a processing screen using the PXOverride attribute.
⚡ Scenario: A client needed to restrict the AP Document Release screen to only show documents belonging to the current user's branch. This customization ensures users only see and release documents from their own branch.
The Challenge
The Acumatica AP Document Release screen (APDocumentRelease) displays a list of payables documents ready for release. By default, it shows all documents across all branches. However, in a multi-branch environment, it's often necessary to restrict users to only documents from their assigned branch.
The standard screen doesn't provide a built-in branch filter. To add this functionality without modifying the base code, we need to use Acumatica's Customization and Extension capabilities.
The Solution: PXOverride
The solution uses the PXOverride attribute to intercept the data retrieval method of the processing screen. This allows us to filter the results before they're displayed to the user.
The Complete Code
using System.Collections;
using PX.Data;
using PX.Objects.AP;
public class EMPAPDocumentReleaseExt
: PXGraphExtension<APDocumentRelease>
{
public delegate IEnumerable APDocumentListDelegate();
[PXOverride]
public virtual IEnumerable apdocumentlist(
APDocumentListDelegate baseMethod)
{
int? currentBranchID = Base.Accessinfo.BranchID;
foreach (object row in baseMethod())
{
BalancedAPDocument document =
PXResult.Unwrap<BalancedAPDocument>(row);
if (document?.BranchID == currentBranchID)
{
yield return row;
}
}
}
}
Code Walkthrough
1. Graph Extension
public class EMPAPDocumentReleaseExt
: PXGraphExtension<APDocumentRelease>
The class extends the APDocumentRelease graph, which is the underlying data access layer for the processing screen. By inheriting from PXGraphExtension, we can add or override functionality without modifying the original source code.
2. Delegate Declaration
public delegate IEnumerable APDocumentListDelegate();
This declares a delegate that matches the signature of the method we're going to override. The delegate allows us to call the original method from within our overridden version.
3. The PXOverride Attribute
[PXOverride]
public virtual IEnumerable apdocumentlist(
APDocumentListDelegate baseMethod)
The PXOverride attribute tells the Acumatica framework that this method should replace the original apdocumentlist method. The baseMethod parameter gives us access to the original implementation.
4. Branch Filtering Logic
int? currentBranchID = Base.Accessinfo.BranchID;
The current user's branch ID is retrieved from Base.Accessinfo.BranchID. This ensures we only show documents that match the user's branch.
foreach (object row in baseMethod())
{
BalancedAPDocument document =
PXResult.Unwrap<BalancedAPDocument>(row);
if (document?.BranchID == currentBranchID)
{
yield return row;
}
}
The code iterates through all documents returned by the base method, checks if the document's branch matches the user's branch, and yields only the matching rows.
💡 Key Insight: The yield return statement creates an iterator that lazily evaluates the collection. This is more efficient than creating a new collection, especially for large datasets.
Understanding PXResult.Unwrap
The PXResult.Unwrap<BalancedAPDocument>(row) method is crucial to understanding this code. Here's why:
- What it does: Extracts the actual
BalancedAPDocumentobject from aPXResultwrapper - Why it's needed: The
apdocumentlistmethod returnsPXResultobjects that contain multiple DACs (Data Access Classes) - How it works:
PXResult.Unwrapextracts the specific DAC type you need
Alternative Approach: Modifying the BQL
For better performance, especially with large datasets, you can filter at the database level instead of in memory:
[PXOverride]
public virtual IEnumerable apdocumentlist(
APDocumentListDelegate baseMethod)
{
int? currentBranchID = Base.Accessinfo.BranchID;
// Use a BQL delegate to add the filter
var delegateWithFilter = new APDocumentListDelegate(() =>
{
foreach (PXResult<BalancedAPDocument> result in
baseMethod().Cast<PXResult<BalancedAPDocument>>())
{
BalancedAPDocument doc = result;
if (doc.BranchID == currentBranchID)
{
yield return result;
}
}
});
return delegateWithFilter();
}
Best Practices
✅ Use PXOverride for Non-Intrusive Customization
Always prefer PXOverride over modifying base code. It makes upgrades easier and keeps your customizations maintainable.
✅ Consider Performance
For large datasets, filter at the database level using BQL delegates rather than in-memory filtering.
✅ Use Meaningful Class Names
Prefix your extension classes with your company code (e.g., EMP) to identify them as customizations.
✅ Test Thoroughly
Always test with users in different branches to ensure the filtering works as expected.
Common Pitfalls to Avoid
❌ Ignoring Null Values
Always check for null when accessing properties of unwrapped objects to avoid NullReferenceException.
❌ Not Considering Performance
In-memory filtering on thousands of records can cause performance issues. Consider database-level filtering.
❌ Forgetting the Delegate
The delegate must be correctly declared and used. Without it, you can't call the base method.
❌ Hardcoding Values
Avoid hardcoding branch IDs or other values. Always use runtime values like Base.Accessinfo.BranchID.
When to Use This Pattern
This pattern can be applied to various scenarios in Acumatica:
- Branch-Based Filtering: Restrict documents to the user's branch
- Department Restrictions: Show only documents from specific departments
- User-Specific Data: Display only records created by the current user
- Security Filters: Implement row-level security based on user roles
- Custom Business Logic: Apply any custom filtering logic to processing screens
Conclusion
Overriding processing screen data sources using PXOverride is a powerful technique for Acumatica customization. It allows you to add business-specific filtering without modifying the base code, keeping your customizations maintainable and upgrade-safe.
The example we've explored demonstrates how to add branch-based filtering to the AP Document Release screen. This same pattern can be adapted to filter data in any processing screen based on your business requirements.
📌 Key Takeaway: PXOverride with delegate-based method overriding provides a clean, non-intrusive way to customize Acumatica processing screens. Always prefer this approach over direct code modifications for better maintainability and upgrade compatibility.
🔍 Further Reading: Consider exploring the PXOverride attribute for other customization scenarios like overriding Persist methods, event handlers, or other graph operations.