Playing with PXSelectorAttribute

Sometimes it’s necessary to add some columns to Selector to show different values , calculated based on complex formulas involving multiple tables. Usually these kind of tasks are requested by customers to show different quantities for item/warehouse selectors based on some simple or complex calculation rules.

For example, you are implementing custom availability based on some item parameters and need to show the quantity by warehouse.

Below I will describe one of the ways to implement this kind of field.

Let’s assume that we need to show some Available Quantity for the Warehouse in the Warehouse Selector on the Sales Order Line.

Below is the SiteID field definition from the SOLine object. As you can see, SiteAvailAttribute is used for Selector addition.

[SiteAvail(typeof(SOLine.inventoryID), typeof(SOLine.subItemID))]
[PXParent(typeof(Select<SOOrderSite, Where<SOOrderSite.orderType, Equal<Current<SOLine.orderType>>, And<SOOrderSite.orderNbr, Equal<Current<SOLine.orderNbr>>, And<SOOrderSite.siteID, Equal<Current2<SOLine.siteID>>>>>>),
 LeaveChildren = true, ParentCreate = true)]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIRequired(typeof(IIf<Where<SOLine.lineType, NotEqual<SOLineType.miscCharge>>, True, False>))]
[InterBranchRestrictor(typeof(Where2<SameOrganizationBranch<INSite.branchID, Current<SOOrder.branchID>>, 
Or<Current<SOOrder.behavior>, Equal<SOBehavior.qT>>>))]
public virtual int? SiteID
{
    get
    {
        return this._SiteID;
    }
    set
    {
        this._SiteID = value;
    }
}

SiteAvailAttribute has a constructor that is receiving the array of columns, which will be shown in the Selector, and we are going to use this constructor.

public SiteAvailAttribute(Type InventoryType, Type SubItemType, Type[] colsType)
        {
            this._inventoryType = InventoryType;
            this._subItemType = SubItemType;
            Type lookupJoin = BqlTemplate.OfJoin<LeftJoin<INSiteStatus, On<INSiteStatus.siteID, Equal<INSite.siteID>, And<INSiteStatus.inventoryID, Equal<Optional<SiteAvailAttribute.InventoryPh>>, And<INSiteStatus.subItemID, Equal<Optional<SiteAvailAttribute.SubItemPh>>>>>>>.Replace<SiteAvailAttribute.InventoryPh>(InventoryType).Replace<SiteAvailAttribute.SubItemPh>(SubItemType).ToType();
            this._Attributes[this._SelAttrIndex] = SiteAvailAttribute.CreateSelector(SiteAvailAttribute.Search, lookupJoin, colsType);
            this._Select = SiteAvailAttribute.BuildSelect(InventoryType);
        }

As we can see from the constructor , SiteAvailAttribute is using the INSiteStatus table, and we can use it too. Let’s define an unbound field in that table which will be used for showing the quantities:

public sealed class INSiteStatusExt : PXCacheExtension<INSiteStatus>
{
        #region AvailabilityField
        [PXDecimal(2)]
        [PXUIField(DisplayName = "Custom. Avail. Qty")]
        public decimal? AvailabilityField { get; set; }
        public abstract class availabilityField : BqlDecimal.Field<availabilityField> { }
        #endregion
}

Now we need to change the SiteAvailAttribute of the SiteID to show our “availabilityField” in the Selector:

[PXMergeAttributes(Method = MergeMethod.Replace)]
[SiteAvail(typeof(SOLine.inventoryID), typeof(SOLine.subItemID), new Type[] { typeof(INSite.siteCD),
                typeof(INSiteStatus.qtyOnHand),
                typeof(INSiteStatusExt.availabilityField),
                typeof(INSiteStatus.active),
                typeof(INSite.descr)})]
protected virtual void SOLine_SiteID_CacheAttached(PXCache sender)
{}

And the final step is to fulfill the value of the field based on some conditions. We can do it using the FieldSelecting event handler:

protected virtual void INSiteStatus_AvailabilityField_FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e, PXFieldSelecting baseMethod)
        {
            baseMethod?.Invoke(sender, e);
            if (e.Row is INSiteStatus row)
            {
                bool condition = row.SiteID % 2 == 0;

                if(condition)
                {
                    e.ReturnValue = 111.0m;
                }
                else
                {
                    e.ReturnValue = 777.0m;
                }
            }
        }

As a result, we will see the “Custom Avail. Qty” column in the SiteID selector as below:

Acumatica Selector With Dynamic Values

2 Replies to “Playing with PXSelectorAttribute”

  1. This is perfect. Our company needed this exact thing. You can do these steps without coding anything in the Customization Project Editor. This post is so helpful finding where to make these edits though. Thanks so much!

  2. Samuel,

    Thank you very much for sharing this. Although I am not a programmer, I can read it, and see that adding a selector column is quite easy for a programmer that has the basic knowledge of BQL and the xRP development tool. It will not take weeks to do it as it would in legacy ERPs.
    Keep posting, Thanks
    PS. Link to linkedin gave me problems.

Leave a Reply

Your email address will not be published. Required fields are marked *