0
votes

While it is easy in thought to just limit records to INSite.branchID = AccessInfo.branchID, the need is a bit more complex. I thought that I found a simple solution when looking at the DAC for INTran to find:

    #region SiteID
    public abstract class siteID : PX.Data.BQL.BqlInt.Field<siteID> { }
    protected Int32? _SiteID;
    [IN.SiteAvail(typeof(INTran.inventoryID), typeof(INTran.subItemID))]
    [PXDefault(typeof(INRegister.siteID))]
    [PXForeignReference(typeof(FK.Site))]
    [InterBranchRestrictor(typeof(Where<SameOrganizationBranch<INSite.branchID, Current<INRegister.branchID>>>))]
    public virtual Int32? SiteID
    {
        get
        {
            return this._SiteID;
        }
        set
        {
            this._SiteID = value;
        }
    }
    #endregion

which has an intriguing attribute for InterBranchRestrictor. After a little digging, I found this attribute actually is used rather widely in Acumatica, but it appears to be limited to only Report Graphs and enabling the feature for Inter-Branch Transactions. Easy enough, I enabled the feature and tried an Inventory Issue again. No luck. I still could select a site id for a different branch.

So far, I only have limited control by creating a graph extension on INIssueEntry to set and validate the site ID. But what I really want is to limit the selector to only site id's of the current branch.

    protected void _(Events.FieldDefaulting<INTran.siteID> e)
    {

        PXResultset<INSite> Results = PXSelect<INSite, Where<INSite.branchID, Equal<Current<AccessInfo.branchID>>>>.Select(Base);
        if (Results.Count == 1)
        {
            foreach (PXResult<INSite> result in Results)
            {
                INSite site = result;
                e.NewValue = site.SiteID;
                e.Cancel = true;
            }
        }
    }

    protected void _(Events.FieldVerifying<INTran.siteID> e)
    {
        int? siteID = (int?)e.NewValue;
        INTran row = (INTran)e.Row;

        INSite site = PXSelect<INSite, Where<INSite.siteID, Equal<Required<INSite.siteID>>,
            And<INSite.branchID, Equal<Current<AccessInfo.branchID>>>>>.Select(Base, siteID);

        if(siteID != null && site?.SiteID == null)
        {
            PXUIFieldAttribute.SetError<INTran.siteID>(e.Cache, row, "Invalid Warehouse for Branch");
        }
    }

I really want to leverage what it seems like

[InterBranchRestrictor(typeof(Where<SameOrganizationBranch<INSite.branchID, Current<INRegister.branchID>>>))]

does, but clearly I just don't understand what it does. Alternatively, if I could add a where clause to

[IN.SiteAvail(typeof(INTran.inventoryID), typeof(INTran.subItemID))]

then I could restrict the list to the current branch that way, but I'm struggling to make that work as well. (Problems around implementing the PXForeignReference attribute in the extension needed to override the field definition.)

How can I restrict (in a manner that can be replicated efficiently throughout Acumatica) branch specific records to only site ID's of the current branch?

1

1 Answers

1
votes

The InterBranchRestrictorAttribute is checking the graph to be working from a Report or the Inter-Branch Transactions feature to be turned on in the IsReportOrInterBranchFeatureEnabled method, so you need to remove this from your implementation. You can write your own PXResrictorAttribute in the way shown in the example below:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = true)]
public class CustomRestrictorAttribute: PXRestrictorAttribute
{
    public CustomRestrictorAttribute(Type where) : base(CustomRestrictorAttribute.EmptyWhere, "Restrictor Message.", Array.Empty<Type>())
    {
      this._interBranchWhere = where;
    }

    protected override BqlCommand WhereAnd(PXCache sender, PXSelectorAttribute selattr, Type Where)
    {
      return base.WhereAnd(sender, selattr, this._interBranchWhere);
    }

    private static readonly Type EmptyWhere = typeof(Where<True, Equal<True>>);

    protected Type _interBranchWhere;
}

And apply it to the DAC field like below:

[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>>>))]
[CustomInterBranchRestrictor(typeof(Where<INSite.branchID,Equal<Current<SOOrder.branchID>>>))]
protected virtual void SOLine_SiteID_CacheAttached(PXCache cache)
{

}