The purpose of this lesson is to teach you how the iDempiere Organization helps you manage multiple sets of book. This lesson also teaches you how to ensure the right people and roles can see the right records and execute the right processes.
Organization and Role - Introduction
If there are Organization and/or Role related features or topics that are not covered here that you believe should be addressed, please let me know by creating a comment below.
Illustration of how to better represent GardenWorld's Organization structure to support consolidated financials.
General Notes about Roles
You do not want the Access Advanced check box checked. This is only for power users/roles.
Review the Role window => Allow Info check boxes. These check boxes give user access to search records inside the respective tables. For Example, Most users do not need Allow Info Account (search the GL).
You do want the Manual check box checked for most roles. If unchecked, that role will automatically get new Windows, Processes, etc...
You do want the Maintain Change Log check box checked. Change Logs are good.
You do want the Preference Level = Organization. Setting it to Client means the user
Can see the Change Log. Change Log visibility can compromise record visibility/security.
Can save global advanced searches.
The User Preference window => record created by the system for each User is created with the * Org. This means that if your Role does not have write access to the * Org, they will not be able to modify their own preferences.
If you want to create a Role that cannot be used during log in (log on/logon), simply do not give it any Organizations. If there are no attached Organizations, the Org will not show in the Login => Org field.
Organization Tree Structure and Global Summary Consolidation
This discussion occurred during an open discussion. It shows you how to modify GardenWorlds' default Organization structure and create a more meaningful consolidation structure.
Link to google groups post shown in video.
2015-06-11 Composite Master Role Example
If you have multiple master roles, access to windows, forms, etc.. is determined based on Sequence No of included Master Roles. The Master Role with the lowest sequence has the most power. The merge process starts with the Master Roles with the greatest sequence number and adds additional Master Roles working toward the Master Role with the lowest sequence. If permissions conflict, the permission on the Master Role with the lower sequence wins.
Included Roles sequencing: org.compiere.model.MRole.loadChildRoles(boolean)
Window Access determined by window configuration on first included role which contains selected window
You have one menu for IT. This menu will inherently be unintelligible to anyone else.
You have one menu for everyone else. This menu needs to be nicely formatted and logical.
New windows, processes, etc... will automatically land on the IT menu. IT must deliberately add the new window to the menu for everyone else. See the following video for more details.
Role - Org Access
It is common for people to want to use the Role window => Org Access subtab to drive who can see what records. Doing so seems obvious because limiting a role's org limits Users of that Role from seeing records of other Orgs.
Unfortunately, doing so is a bad idea for the following reasons:
Using this strategy is unforgiving. There are no exceptions with this implementation.
Limiting a Role's Org access not only limits what records a User can see, it also limits what field values they can see.
Said another way using an example, if you 'BP A' of Org1 with a Payment Term from Org2. a User who does not have access or Org2 will see 'BP A'; however, the Payment Term will appear blank. If the user saves the record with the null Payment Term, the data is now contaminated.
A better strategy is to use the Window, Tab and Field => Tab subtab => SQL Where field to limit what records show based on your desired logic.
Here is an example implementation:
Any given tab is backed by a table (example: C_SomeTable). This is true for all tabs.
Using Window, Tab and Field => Tab subtab => SQL Where field is just like adding a where clause to limit what users can see. See the Sales Order window => Tab subtabs for examples.
If you were to add a custom field named IsChuboeCanView to the Role window => Org Access table (ad_role_orgaccess) named, you could designate what roles can view what orgs.
You would add the below bolded text to the Window, Tab and Field => Tab subtab => SQL Where field
select * from c_sometable where ad_org_id in (select ad_org_id from ad_role_orgaccess where ischuboecanview = ‘Y’ and ad_role_id = @AD_Role_ID@)
I realize this is not a trivial concept to understand; however, once you understand the idea, the implementation is quite easy and powerful. Do not hesitate to join the open discussion to review in more detail.
Track Cost Center or Department profit and lot reporting
Role Access Visibility
Includes:
Pack In to help know what objects are linked to directly from the main menu.
SQL to Disable Menu Processes for a Specific Role.
Removing window access for a specific role is easy and obvious. You simply deactivate the record in Role => Window Access. If you deactivate all windows, the user will not show any windows the next time they log in. Process access is a little challenging. Simply deactivating all process access from a role can have unintended consequences. There are situations where the system will not perform as expected (fail), and it may not be obvious as to why. For example, if you disable all processes for a user, they will not be able to print because print formats are executed through "Report & Process".
It would be very convenient to know what processes are directly linked to from the main menu (AD_Menu). This discussion includes a plugin that does two things:
Tells you what processes, workflows, etc.. are linked to from the main menu.
Tells you the menu name for the process - note they are often not the same. This fact makes mapping harder. The plugin makes this process much easier.
In addition to adding the Menu name to the Process Access list, you can deactivate only the processes that are called directly from the menu. The below SQL will help you accomplish this task. Simply replace the XXXXXX with the ad_role_id of your role and execute the below statement. You can find the role id by:
opening the Role window
navigating to the desired role
clicking on the X/X row count in the upper right corner of the window
the popup window will tell you the ad_role_id
--remove all processes linked to by the menu
update AD_Process_Access
set isactive = 'N'
where ad_role_id = XXXXXX
and ad_process_id in
(
select ad_process_id from ad_menu
)
;
When creating roles according to the pattern described here, you should have a Master Role called "Must Have" that includes all the access needed just to operate iDempiere. The purpose of this section is to describe how to create the "Must Have" Master Role:
Log into your client with that client's Admin role
Open the Role window
Create a new Role called "Must Haves". Make sure the Manual checkbox is NOT checked. Make sure the Master Role checkbox is checked. Save the record. Because the Manual is not checked, the system will automatically give this role access to everything.
In the top-right corner of the Role window, click on the X/X link and take note of the Role's ID in the Change Log popup.
Copy the below "Must Have Update SQL" script to a text editor.
Use search and replace to replace "XXXX" with your role ID from the previous step.
Now that you have a role that represents the absolute minimum needed to log into iDempiere, create a new role (with Manual checkbox checked), and add your "Must Have" role to the newly created role's Included Role sub-tab.
Once you have executed the below SQL, remove the manual checkbox to that future windows are not added to the Must Have role.
Must Have SQL
Used when first creating the must have role.
update ad_role
set ismanual='Y'
where AD_Role_ID=XXXX;
delete from AD_Window_Access
where AD_Role_ID=XXXX;
delete from AD_Process_Access
where ad_role_id = XXXX
and ad_process_id in
(
select ad_process_id from ad_menu
)
;
delete from AD_Form_Access
where ad_role_id = XXXX
and ad_form_id in
(
select ad_form_id from ad_menu
)
;
delete from AD_workflow_Access
where ad_role_id = XXXX
and ad_workflow_id in
(
select ad_workflow_id from ad_menu
)
;
Must Have SQL Update
Over time, you will add new processes to iDempiere. Adding a new window with a print format is an example. The below SQL will help you keep the Must Have role => Process Access subtab up to date.
Note: the below code is now located here. This code is referenced automatically when using this deployment script.
INSERT INTO AD_Process_Access
(AD_Process_ID, AD_Role_ID,
AD_Client_ID, AD_Org_ID, IsActive, Created, CreatedBy, Updated, UpdatedBy, IsReadWrite)
SELECT DISTINCT p.AD_Process_ID, r.AD_Role_ID,
r.ad_client_id, 0, 'Y', now(), 100, now(), 100, 'Y'
FROM AD_Process p
LEFT JOIN AD_Role r on r.AD_Role_ID = XXXXXXXXXX --SET ROLE HERE--
WHERE p.AD_Process_ID NOT IN
(
SELECT AD_Process_ID FROM AD_Menu WHERE AD_Process_ID IS NOT NULL
)
AND p.AD_Process_ID NOT IN
(
SELECT AD_Process_ID FROM AD_Process_Access where AD_Role_ID = r.AD_Role_ID
)
;
Role - Prevent Close on All Document Types Except Orders
There is no value in closing documents other than orders. The below SQL prevents the 'Close' option from showing for all Roles and all Document Actions except for Sales Orders and Purchase Orders.
Notes:
Be sure to test this query on a test server before deploying on production.
You may need to execute this query more than once over time as more roles are added.
update
ad_document_action_access da
set isactive = 'N'
where da.ad_ref_list_id in (select ad_ref_list_id from ad_ref_list where lower(name) = 'close')
and da.c_doctype_id in (select c_doctype_id from c_doctype where docbasetype not in ('SOO','POO'))
;
SQL to validate details
select * from
ad_document_action_access da
join ad_ref_list rl on da.ad_ref_list_id = rl.ad_ref_list_id
join c_doctype dt on da.c_doctype_id = dt.c_doctype_id
where da.ad_ref_list_id in (select ad_ref_list_id from ad_ref_list where lower(name) = 'close')
and da.c_doctype_id in (select c_doctype_id from c_doctype where docbasetype not in ('SOO','POO'))
order by dt.name
;