Skip to main content
Solved

RestrictByUserBranches not working in a View override on Run Project Billing screen


Joe Schmucker
Captain II
Forum|alt.badge.img+2

On the Run Project Billing, if you open the screen and there is an item in the grid for a branch you are not part of, you get an error that the branch cannot be found.  I believe this is sort of a bug in Acumatica.  That screen should allow a user to run project billing for “their records” if they have permission to that screen.

I overrode the Initialize for that screen to restrict the three PXSelect’s to only include records (contracts) with branches that the user is a member of.

I have added a WhereAnd to the select statement for the grid on that screen that restricts the results to only records that have a branch that the user is a member of.

With no customization, the screen returns 3 records when you open it.  You have to be logged in as Admin to see them.  If you log in as Joe, you get the error that a branch cannot be found.  

Joe is in a branch for one of the Contracts in the grid.  It is BranchID = 7.

In my override, if I put a whereand for the current logged in Branch ID, Joe can view the one record for that Branch.  But I want to show ALL records for branches that Joe is a member of, not just the current logged in branch.  As such, I tried to use RestrictByUserBranches.

public override void Initialize()
{
    //returns 7
    var joe = Base.Accessinfo.BranchID;

    //returns jschaa
    var joe2 = Base.Accessinfo.UserName;

    //Base.ProjectsUnbilled.WhereAnd<Where<Contract.defaultBranchID, RestrictByUserBranches<Current<AccessInfo.userName>>>>();
    //Base.ProjectsRecurring.WhereAnd<Where<Contract.defaultBranchID, RestrictByUserBranches<Current<AccessInfo.userName>>>>();
    //Base.ProjectsProgressive.WhereAnd<Where<Contract.defaultBranchID, RestrictByUserBranches<Current<AccessInfo.userName>>>>();

    //branch id is 7
    Base.ProjectsUnbilled.WhereAnd<Where<Contract.defaultBranchID, Equal<Current<AccessInfo.branchID>>>>();
    Base.ProjectsRecurring.WhereAnd<Where<Contract.defaultBranchID, Equal<Current<AccessInfo.branchID>>>>();
    Base.ProjectsProgressive.WhereAnd<Where<Contract.defaultBranchID, Equal<Current<AccessInfo.branchID>>>>();
}

In the code where I use RestrictByUserBranches, no records get returned at all.  At a minimum, I think it should return one record.

If I just use the Equal<current branch>, it returns one record as expected.  

I don’t know why RestrictByUserBranches does not return the one record.  Am I misunderstanding the purpose of that code?

I don’t know of a way to debug RestrictByUserBranches to see why it is not doing what I expect.

I thought about doing my own inner join to those views that would join to a table where there is a listing of Branches that the User is included in.  But I can find no such table.  I found some code on the BranchMaint graph that seems to be able to get a list of employees belonging to the selected branch.  But an employee can be a member of many branches, so that is not the direction I need.

Edit:  I forgot to mention that Joe is a member of branchID 7.  

 

Best answer by Joe Schmucker

Hi @NicholasBova52 

Thanks for the time to assist me!  Unfortunately, it does not limit the records to the ones associated with the branch(es) associated with the particular user and I get the error message for the records in the grid that are in a branch the user is not in.

What I did to get around this was to do some really ugly code.  Basically I get a listing of the Branches linked to the user.  Then in each section that adds rows, loop through the branches for each record and see if it is linked to the user.  If it is, add it to the results.

        public virtual IEnumerable items()
        {
            //START CUSTOM
            Guid? currentUser = CommonServiceLocator.ServiceLocator.Current.GetInstance<ICurrentUserInformationProvider>().GetUserId();

            //get a list of the branches that the current user is linked to
            PXResultset<PX.SM.Branch> branches = SelectFrom<PX.SM.Branch>
                .InnerJoin<UsersInRoles>
                    .On<UsersInRoles.rolename.IsEqual<PX.SM.Branch.roleName>>
                .InnerJoin<Users>
                    .On<Users.username.IsEqual<UsersInRoles.username>>.Where<Users.pKID.IsEqual<@P.AsGuid>>
                .View.Select(Base, currentUser.Value);
            //END CUSTOM

            BillingFilter filter = Base.Filter.Current;
            if (filter == null)
            {
                yield break;
            }
            bool found = false;
            foreach (Contract item in Base.Items.Cache.Inserted)
            {
                found = true;
                yield return item;
            }
            if (found)
                yield break;

            PXSelectBase<Contract> selectUnbilled = Base.ProjectsUnbilled;

            if (Base.Setup.Current.CutoffDate == PMCutOffDate.Excluded)
            {
                selectUnbilled = Base.ProjectsUbilledCutOffDateExcluded;
            }
            if (filter.StatementCycleId != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
            }
            if (filter.CustomerClassID != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
            }
            if (filter.CustomerID != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
            }
            if (filter.TemplateID != null)
            {
                selectUnbilled.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
            }

            foreach (PXResult item in selectUnbilled.Select())
            {
                var result = CreateListItem(item);

                if (Base.Items.Locate(result) == null)
                {
                    //ORIGINAL
                    //if (Base.Items.Locate(result) == null)
                    //    yield return Base.Items.Insert(result);

                    //START CUSTOM
                    //loop through the list of branches linked to the user and only insert records where there is a match
                    foreach (PX.SM.Branch branch in branches)
                    {
                        if (result.DefaultBranchID == branch.BranchID)
                        {
                            yield return Base.Items.Insert(result);
                            break;
                        }
                    }
                    //END CUSTOM
                }
            }

            foreach (PXResult item in Base.ProjectsRecurring.Select())
            {
                var result = CreateListItem(item);

                //ORIGINAL
                //if (Base.Items.Locate(result) == null)
                //    yield return Base.Items.Insert(result);

                //START CUSTOM
                //loop through the list of branches linked to the user and only insert records where there is a match
                foreach (PX.SM.Branch branch in branches)
                {
                    if (result.DefaultBranchID == branch.BranchID)
                    {
                        yield return Base.Items.Insert(result);
                        break;
                    }
                }
                //END CUSTOM
            }

            foreach (PXResult item in Base.ProjectsProgressive.Select())
            {
                var result = CreateListItem(item);

                //ORIGINAL
                //if (Base.Items.Locate(result) == null)
                //    yield return Base.Items.Insert(result);

                //START CUSTOM
                //loop through the list of branches linked to the user and only insert records where there is a match
                foreach (PX.SM.Branch branch in branches)
                {
                    if (result.DefaultBranchID == branch.BranchID)
                    {
                        yield return Base.Items.Insert(result);
                        break;
                    }
                }
                //END CUSTOM

            }

            Base.Items.Cache.IsDirty = false;
        }

This is just a copy from the source code with some additional work.  This is extremely inefficient, but it is the only way I can find to get it to work.  The grid is not populated with hundreds of records, so performance is not really an issue for this customer.

View original
Did this topic help you find an answer to your question?

2 replies

NicholasBova52
Acumatica Employee
Forum|alt.badge.img+1
  • Acumatica Employee
  • 27 replies
  • August 27, 2024

HI @Joe Schmucker 

I would recommend trying the “Match” BQL class in the WhereAnd and see if that works. I don’t know about the functionality of “RestrictByUserBranches”, but “Match” will restrict the results of the table referenced first in the statement to only those the user has access rights to. I believe this should also restrict by BranchID as well.

 

Example:

public override void Initialize()
{
    Base.ProjectsUnbilled.WhereAnd(typeof(Where<Match<Current<AccessInfo.userName>>>));
    Base.ProjectsRecurring.WhereAnd(typeof(Where<Match<Current<AccessInfo.userName>>>));
    Base.ProjectsProgressive.WhereAnd(typeof(Where<Match<Current<AccessInfo.userName>>>));
}

 


Joe Schmucker
Captain II
Forum|alt.badge.img+2
  • Author
  • Captain II
  • 455 replies
  • Answer
  • August 27, 2024

Hi @NicholasBova52 

Thanks for the time to assist me!  Unfortunately, it does not limit the records to the ones associated with the branch(es) associated with the particular user and I get the error message for the records in the grid that are in a branch the user is not in.

What I did to get around this was to do some really ugly code.  Basically I get a listing of the Branches linked to the user.  Then in each section that adds rows, loop through the branches for each record and see if it is linked to the user.  If it is, add it to the results.

        public virtual IEnumerable items()
        {
            //START CUSTOM
            Guid? currentUser = CommonServiceLocator.ServiceLocator.Current.GetInstance<ICurrentUserInformationProvider>().GetUserId();

            //get a list of the branches that the current user is linked to
            PXResultset<PX.SM.Branch> branches = SelectFrom<PX.SM.Branch>
                .InnerJoin<UsersInRoles>
                    .On<UsersInRoles.rolename.IsEqual<PX.SM.Branch.roleName>>
                .InnerJoin<Users>
                    .On<Users.username.IsEqual<UsersInRoles.username>>.Where<Users.pKID.IsEqual<@P.AsGuid>>
                .View.Select(Base, currentUser.Value);
            //END CUSTOM

            BillingFilter filter = Base.Filter.Current;
            if (filter == null)
            {
                yield break;
            }
            bool found = false;
            foreach (Contract item in Base.Items.Cache.Inserted)
            {
                found = true;
                yield return item;
            }
            if (found)
                yield break;

            PXSelectBase<Contract> selectUnbilled = Base.ProjectsUnbilled;

            if (Base.Setup.Current.CutoffDate == PMCutOffDate.Excluded)
            {
                selectUnbilled = Base.ProjectsUbilledCutOffDateExcluded;
            }
            if (filter.StatementCycleId != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.statementCycleId, Equal<Current<BillingFilter.statementCycleId>>>>();
            }
            if (filter.CustomerClassID != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.customerClassID, Equal<Current<BillingFilter.customerClassID>>>>();
            }
            if (filter.CustomerID != null)
            {
                selectUnbilled.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Customer.bAccountID, Equal<Current<BillingFilter.customerID>>>>();
            }
            if (filter.TemplateID != null)
            {
                selectUnbilled.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
                Base.ProjectsRecurring.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
                Base.ProjectsProgressive.WhereAnd<Where<Contract.templateID, Equal<Current<BillingFilter.templateID>>>>();
            }

            foreach (PXResult item in selectUnbilled.Select())
            {
                var result = CreateListItem(item);

                if (Base.Items.Locate(result) == null)
                {
                    //ORIGINAL
                    //if (Base.Items.Locate(result) == null)
                    //    yield return Base.Items.Insert(result);

                    //START CUSTOM
                    //loop through the list of branches linked to the user and only insert records where there is a match
                    foreach (PX.SM.Branch branch in branches)
                    {
                        if (result.DefaultBranchID == branch.BranchID)
                        {
                            yield return Base.Items.Insert(result);
                            break;
                        }
                    }
                    //END CUSTOM
                }
            }

            foreach (PXResult item in Base.ProjectsRecurring.Select())
            {
                var result = CreateListItem(item);

                //ORIGINAL
                //if (Base.Items.Locate(result) == null)
                //    yield return Base.Items.Insert(result);

                //START CUSTOM
                //loop through the list of branches linked to the user and only insert records where there is a match
                foreach (PX.SM.Branch branch in branches)
                {
                    if (result.DefaultBranchID == branch.BranchID)
                    {
                        yield return Base.Items.Insert(result);
                        break;
                    }
                }
                //END CUSTOM
            }

            foreach (PXResult item in Base.ProjectsProgressive.Select())
            {
                var result = CreateListItem(item);

                //ORIGINAL
                //if (Base.Items.Locate(result) == null)
                //    yield return Base.Items.Insert(result);

                //START CUSTOM
                //loop through the list of branches linked to the user and only insert records where there is a match
                foreach (PX.SM.Branch branch in branches)
                {
                    if (result.DefaultBranchID == branch.BranchID)
                    {
                        yield return Base.Items.Insert(result);
                        break;
                    }
                }
                //END CUSTOM

            }

            Base.Items.Cache.IsDirty = false;
        }

This is just a copy from the source code with some additional work.  This is extremely inefficient, but it is the only way I can find to get it to work.  The grid is not populated with hundreds of records, so performance is not really an issue for this customer.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings