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.
publicoverridevoidInitialize()
{
//returns 7var joe = Base.Accessinfo.BranchID;
//returns jschaavar 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.
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.
publicvirtual 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)
{
yieldbreak;
}
bool found = false;
foreach (Contract item in Base.Items.Cache.Inserted)
{
found = true;
yieldreturn item;
}
if (found)
yieldbreak;
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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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.
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.
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.
publicvirtual 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)
{
yieldbreak;
}
bool found = false;
foreach (Contract item in Base.Items.Cache.Inserted)
{
found = true;
yieldreturn item;
}
if (found)
yieldbreak;
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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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 matchforeach (PX.SM.Branch branch in branches)
{
if (result.DefaultBranchID == branch.BranchID)
{
yieldreturn 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.
We use 3 different kinds of cookies. You can choose which cookies you want to accept. We need basic cookies to make this site work, therefore these are the minimum you can select. Learn more about our cookies.