Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
File Name:
Version: 1.0
Status: For Review
Page 1 of 70
Company Confidential
Contents
0 1................................................................................................................................................Introduction
4
1.1 Access Control.........................................................................................................................4
0 2............................................................................................................................................Business Needs
7
2.1.1 Organization Security Overview....................................................................................7
0 3...............................................................................................................Functional Feature Descriptions
8
3.1 Access Control - Foundations..................................................................................................8
3.1.1 Defining Security based on Hierarchy or a List of Operating Units.............................8
3.1.4 Process Flow...................................................................................................................9
3.1.5 Assign MO: Security Profile to Application Responsibility........................................10
3.2 Specifications to Oracle Forms..............................................................................................11
3.2.1 Select Operating Unit For Setup and Transaction Forms...........................................11
3.2.3 Operating Unit Default................................................................................................16
3.4 Reporting................................................................................................................................17
3.4.1 Single Org Reports.......................................................................................................17
3.4.2 Cross Org Reports........................................................................................................17
3.4.3 Define Concurrent Programs Window........................................................................18
3.5 Concurrent Programs (others than reports)...........................................................................18
3.5.1 Single Org Concurrent Programs................................................................................18
3.6 Public APIs.................................................................................................................................19
3.7 Workflows..................................................................................................................................19
Page 2 of 70
Page 3 of 70
A profile option, “MO: Security Profile”, is used to associate predefined security profile to a user
responsibility.
The following two process flows illustrate current and new models for defining Multi-Org.
Page 4 of 70
D e fin e O p e r a tin g D e f in e O p e r a t in g
U n it s U n its
STEP 1 Is th e re a n
D e fin e Yes O U h ie r a r c h ic a l
O r g a n iz a tio n s tru c tu re ?
H ie r a r c h y
No
STEP 2
STEP 1 D e fin e S e c u r it y
STEP 2 D e fin e P r o f ile & R u n
D e fin e S e c u r ity O r g a n iz a tio n S e c u r it y L is t
P r o f il e H ie r a r c h y M a in te n a n c e
P ro g ra m
STEP 3 STEP 3
R u n S e c u r it y L is t S e t M O : S e c u r ity
M a in te n a n c e P r o file
P ro g ra m
STEP 4 STEP 4
S e t M O : S e c u r ity S e t U s e r D e fa u lt
P r o f il e O U
STEP 5
R un A ccess
V a lid a tio n R e p o r t
Page 5 of 70
S e tu p D a ta
T r a n s a c tio n D a ta
C o n c u rre n t P ro g ra m s
S c re e n
O U2
R e s p o n s ib ility ------------------------ S e tu p D a ta
------------------------ T r a n s a c tio n D a ta
------------------------ C o n c u rre n t P ro g ra m s
O U3
S e tu p D a ta
T r a n s a c tio n D a ta
C o n c u rre n t P ro g ra m s
Page 6 of 70
2.1 Background
Multi-Org Operating Unit access is intended to work similarly to other kinds of organization security
implemented in the E-Business Suite. For this reason, it is helpful to understand how the various types
of organization security work in the applications.
When you define an organization, you must first indicate the organization type of either internal or
external, and then assign multiple organization classifications to that organization. There exists no
validation between ‘organization classification' and a type of 'internal or external’. Below is a list of all
internal organization types and the products using them:
Page 7 of 70
The Human Resources product team currently maintains both the Organization Hierarchy and Security
Profile forms. The Security Profile form needs to be enhanced to support the additional Operating Unit
access features.
Users want to base security on an organization hierarchy or a list of organizations. The following
diagram shows a hypothetical enterprise structures:
This is a simple enterprise structure. There is no hierarchical structure of organizations, since the ledger
is not considered an organization in the subledgers. In this case, the user will want to gain access to
OU1, OU2, or OU1 & OU2, all of which are lists of organizations, and not based on a hierarchy. Also, a
user might have a simple hierarchical structure with a few numbers of organizations. A user can still
base the security on a list of organizations by selecting all parent and subordinate Operating Units in the
list. For security profiles based on hierarchies, the user must complete set up Step 1 - Define
Organization Hierarchy.
Page 8 of 70
The following process flow lists the steps to implement Operating Unit security. This process flow
applies to all of the cases listed above.
Page 9 of 70
Is th e re a n
Yes O U h ie r a r c h ic a l
s tru c tu re ?
N o
STEP 2
STEP 1 D e fin e S e c u r ity
D e fin e P r o file & R u n
O r g a n iz a tio n S e c u r ity L is t
H ie r a r c h y M a in te n a n c e
P ro g ra m
STEP 3
S e t M O : S e c u r ity
P r o file
STEP 4
S e t U s e r D e fa u lt
O U
STEP 5
R un A ccess
V a lid a t io n R e p o r t
The last step is to assign a security profile to user responsibility via System Profile Values window.
Page 10 of 70
Selecting an Operating Unit for setup data and transactions provides the ability to users to enter
transactions and query data for multiple Operating Units with one responsibility and from within one
screen. The Operating Unit will be added as a field on all product forms with which users query or
update Multi-Org-striped data. This includes all transactions and setup data that are Operating Unit
specific. Setup forms not affected are those through which users access global data, such as AP payment
terms, AP calendars and AR receipt classes.
Adding the Operating Unit to all Multi-Org forms will assure that the user will only need one
responsibility for both transaction and setup data for the Operating Units that a user has access. It has
been considered to not provide this feature for setup data, since the volume and/or frequency of adding
or updating setup data can be small. If we did not provide this feature, however, the user would be
forced to create additional responsibilities solely for setup data, which would defeat a main objective of
decreasing the overall number of responsibilities.
The user will enter the setup and transaction forms, select the Operating Unit in the first field, and then
enter the data for the specific Operating Unit. The list of values for the Operating Unit field will be
restricted to the Operating Unit organizations to which the user's application responsibility has access.
There exist several benefits of providing the Operating Unit field on Multi-Org setup and transaction
screens.
A user can query setup and transaction data for all the Operating Units to which the user has access.
The user does not need to know the Operating Unit by which data might be partitioned.
A user can make use of the duplicate record feature in forms (from the Edit menu) where applicable,
to copy data from one Operating Unit to another.
A user will be able to easily tell whether or not setup data is Multi-Org partitioned or not. If data
accessed through a particular setup screen is not org striped, then the Operating Unit field will not
appear in the screen. Currently, the user must refer to the product user's guide or navigate between
Operating Units to see if the setup data are the same for all Operating Units (global) or Operating
Unit specific.
General recommendations:
The Operating Unit field should be placed in the top left corner of the form
Page 11 of 70
If user responsibility allows access to one Operating Unit only, then value for the Operating Unit
field and its dependent attributes should be defaulted
Placement of the Operating Unit field on the window is dependent on the type of window. Child
windows must display the Operating Unit name only in the window title bar in the context of a saved
parent record.
When determining whether to place the Operating Unit on the screens, you should consider various types
of forms. There are two general form models in the applications: single record and multi-record format.
Single record formats allow the maximum number of fields for a single record to be displayed at one
time. Multi-record formats allow the maximum number of records for a single database entity to be
displayed at one time.
Page 12 of 70
Figure 8 - Single record format with tabs example: Receivables Transaction Workbench
Page 13 of 70
Figure 10 - Single record format example with tab regions: Payables Financials Options
Page 14 of 70
To better facilitate data entry, a user can optionally set up a default Operating Unit value. A new profile
option, "MO: Default Operating Unit," is used to define defaulting Operating Unit, and it can be set at
Responsibility and User levels. The Operating Unit user defines in this profile option must be a valid
Page 15 of 70
Also, an Operating Unit value is defaulted when user's security profile contains access to one Operating
Unit only. This eliminates user to explicitly define Operating Unit when he can only access to one
organization.
3.4 Reporting
Reports that are impacted by Multi-Org Access Control feature can be classified into 2 broad categories
Single Org reports are the reports that display data for one Operating Unit only. Today (Multi-Org using
CLIENT_INFO) these reports show data for the Operating Unit specified by “MO: Operating Unit”
profile option. With Multi-Org Access Control, a responsibility could have access to one or more
Operating Units. Even with opening up access, the business requirement is that these reports should
continue to report data for one Operating Unit only at a time. This implies that the user needs the ability
to select an Operating Unit and submit the report. For example, if the profile option “MO: Security
Profile” gives access to 3 Operating Units, the user should have the ability to choose one Operating Unit
from the available three and submit the report.
If the user has access to only one Operating Unit, then that value should be defaulted for Operating Unit.
If user has access to multiple Operating Units, then defaulting should happen if the profile “MO: Default
Operating Unit” is set and is valid.
Cross Org Reports introduced in Release 11i, are reports that report data for one or multiple Operating
Units. The Cross Org report executables and valuesets use the unsecured Multi-Org tables. Currently,
there are two parameters – Reporting Level and Reporting Context to determine at what level a user can
submit a report for (single Operating Unit, or all Operating Units under a Legal Entity, or all Operating
Units under a Set of Books). The valuesets for these parameters will be modified for MOAC project to
take “MO: Security Profile” profile option into consideration. Also Ledgers will replace Set of Books for
the Reporting Level as part of Ledger uptake.
Although there is no functional impact to Cross Org reports by Multi-Org Access Control feature, a
minor security enhancement is made. Security enhancement will list valid values for Reporting Level
and Reporting Context based on security access privilege. This is a change from today where profile
“MO: Operating Unit” is considered for security and not “MO: Security Profile” profile.
A user will be able to report at the Ledger level only if all the Operating Units under the current ledger
are encompassed by the security profile and the value of “MO: Top Reporting Level” profile is Ledger.
A user will be able to report at the Legal Entity level only if all the Operating Units under at least 1 legal
entity are encompassed by the security profile and the value of “MO: Top Reporting Level” profile is
Legal Entity or Ledger. The available reporting contexts are the Legal Entities that have the Operating
Units encompassed by the current security profile.
A user will always be able to report at the Operating Unit level. The available reporting contexts are the
Operating Units that are encompassed by the current security profile.
At submission time, when Cross Org reports are selected, the temporary table is initialized with one or
multiple Operating Units based on “MO: Security Profile” profile option. The temporary table controls
the data the users sees for the Reporting Level and Reporting Context parameters. For this special
processing of Multi-Org initialization, Cross-Org reports need to be flagged as MULTIPLE in the Define
Concurrent Programs form for the Operating Unit mode.
Page 16 of 70
The Define Concurrent Programs form is modified to include a new field “Operating Unit
mode” that would allow users to categorize the concurrent programs for Multi-Org Access
Control feature uptake. The concurrent programs can be categorized into SINGLE, MULTIPLE
or NULL. By default the value of this new field is NULL or blank. A poplist allows users to
change the value. The concurrent program category is used to execute the Multi-Org
initialization and also determine when to expose Operating Unit field in the Submit Requests
window and Schedule Requests window.
Single Org concurrent programs are non-report programs that report or process data for one Operating
Unit only. Today (Multi-Org using CLIENT) these programs show data for the Operating Unit specified
by “MO: Operating Unit” profile option. With Multi-Org Access Control, a responsibility could have
access to one or more Operating Units. Even with opening up access, the business requirement is that
these concurrent programs should continue to report or process data for one Operating Unit only at a
time. This implies that the user needs the ability to select an Operating Unit and submit the program.
These programs are treated in the same way as the Single Org Reports and should be flagged as
SINGLE category for Operating Unit mode in the Define Concurrent Programs window.
Special processing is done for these programs in the SRS window and the Schedule Requests pages to
initialize the temporary table and expose Operating Unit special parameter.
Figure below shows SRS screen with the Operating Unit parameter added for the Payables Open
Interface Import program. Users may choose to enter a value for the Operating Unit field and thus
submit the request for only the specified organization, or they may leave the field blank and process
invoices for all the Operating Units within the current security profile.
Page 17 of 70
Multiple Org Concurrent programs require that the Multi-Org temporary table be populated
with one or multiple Operating Units depending upon the profile option “MO: Security Profile”.
These programs should be flagged as MULTIPLE for Operating Unit mode in the Define
Concurrent Programs so that the Multi-Org temporary table is initialized when the user selects
the program.
The executables for such concurrent programs should be modified to utilize the Operating Unit
parameter to avoid Cartesian joins and process or report data correctly for the specified
Operating Units.
No special processing is done for such concurrent programs at runtime, since the executables are
modified to handle multiple Operating Units access. The Multi-Org initialization populates the
temporary table with one or multiple Operating Units based on the access enabled status of the product
owning the concurrent program at runtime.
3.6 APIs
Public APIs that are affected by Multi-Org Access Control should accept Operating Unit as input either
as parameter or by defaulting from “MO: Default Operating Unit” profile option similar to the Forms UI
or the Framework Pages. Prior to Multi-Org Access Control, the APIs process data for one Operating
Unit only controlled by “MO: Operating Unit” profile.
With Multi-Org Access Control, the processing should validate that Operating Unit is passed as
input and it is valid (included within the user responsibility profile “MO: Security Profile”). If
a user is trying to process data for an Operating Unit that (s)he does not have access to, critical
error should be raised and further processing stopped.
3.7 Workflows
Workflows that are affected by Multi-Org Access Control should allow users to initiate the process for
any Operating Unit that (s)he has access to without having to switch responsibility. Also, workflow
administrators should be able to perform administrative tasks like Abort Process or Expedite Process
irrespective of the access to the Operating Unit the workflow is initiated for.
Workflows submitted from UI pages, would have the Operating Unit validated upstream, since the LOV
would allow users to pick an Operating Unit that (s)he has access to. Similarly, workflows submitted
within Public APIs would have the Operating Unit validated before the workflow process is initiated.
The Operating Unit (ORG_ID) should be captured as part of the activity to be processed and should be
used to set the Multi-Org VPD policy context. For example, the ORG_ID of the item keys like Credit
Memo Request Id, Expense Report Header Id etc. The profile options “MO: Default Operating Unit”,
“MO: Security Profile” or “MO: Operating Unit” should not be relied upon for workflows, since the
Page 18 of 70
6.
Page 19 of 70
Multiple Organization Architecture was first introduced in Release 10.6, for data security by Operating
Unit. In Release 10.7, we added a column, ORG_ID, to each base table that requires ”partitioning” by
Operating Units. All the tables that are partitioned are renamed with suffix, ‘_ALL’, and their
corresponding secured views are created in APPS schema. The diagram given below shows the single
organization view in the applications (APPS) schema.
Multi-Org views restrict data access by filtering records for a single Operating Unit set by application
responsibility level profile, ““MO: Operating Unit”.” The value for the profile option is cached in
Application Context, and is initialized whenever FND initialization routine is called. All Multi-Org
views as well as any SQL statements that require Multi-Org security contains FND CLIENT_INFO
predicate. FND_CLIENT_INFO function retrieves ORG_ID value stored in the application context. The
value is valid during a session unless it is explicitly changed by procedure calls.
To retrieve all information regardless of the Operating Unit, the _ALL table should be used in the SQL
statement. Cross-Organization reports are good example in which the query statements are performed
against _ALL tables rather than Multi-Org secured views. Most Oracle Financials reports generate
outputs from a single Operating Unit, and the query statements are performed against Multi-Org views.
In order to increase flexibility and performance in Multi-Org environment while providing the same
level data security, Virtual Private Database (VPD) feature introduced in Oracle 8i RDBMS will replace
usage of CLIENT_INFO function in Multi-Org Access Control.
The Virtual Private Database feature allows developers to enforce security by attaching a security policy
to tables and views in Oracle8i, and to synonyms in Oracle 9i Release2. It attaches predicates for the
security policies to every SQL statement against the database objects where policies are applied. When a
user directly or indirectly accesses a table with a security policy, the RDBMS dynamically rewrites user’s
SQL statement to include conditions set by security policy transparently to the user. The conditions can
be expressed in, or returned by a function.
Page 20 of 70
AP Schema
APPS Schema
AP_INVOICES_ALL table
ORG_ID INVOICE_ID
AP_INVOICES_ALL (synonym to the 1 1000
AP_INVOICES_ALL table) 1 1001
1 1002
2 1003
AP_INVOICES (synonym with the 2 1004
security policy attached that gives
access to ORG_ID 1 and 2)
The single organization views that have the CLIENT_INFO predicate attached to them should be made
obsolete and synonyms should be created to replace them. A security policy function should be attached
to the Multi-Org synonyms during install time. The security is in place, no matter whatever tools is used
to access the secured synonyms.
The security policy function returns different predicate based on the number of Operating Units access.
An application context attribute “ACCESS_MODE” is set based on the Operating Units access. The
policy function is dynamic, as it is reparsed, whenever a SQL statement is executed. The reason to opt
for dynamic security policy function is to minimize the coding impact. The Multi-Org code today works
in the context of one Operating Unit. Majority of the code can be reused if the policy predicate can
change dynamically. For example, you open a form from a responsibility that has access to multiple
Operating Units. After an Operating Unit is selected, the Operating Unit context is established and the
code that is used for validation from that point onwards need not be modified if the synonyms return
data for the Operating Unit selected.
When the access_mode is Multiple (M), the policy predicate issues an EXISTS sub-query against a
global temporary table. The global temporary table is a new feature introduced in Oracle 8i. It allows
table to store and manipulate data specific to a SESSION or TRANSACTION. When the access_mode
is Single, a simple equality predicate is used for performance reasons, since it is cost effective compared
to using the temporary table. An access mode of All (A) is incorporated for future purposes where the
security is bypassed for functionalities that need full table access. If the access_mode is not set, then a
simple predicate that uses the CLIENT_INFO value for ORG_ID is used for the policy predicate. This is
to support the backward compatibility for products, which have not enabled the Multi-Org Access
Control feature, but have made the datamodel changes.
MO_GLOBAL.Org_Security function:
FUNCTION org_security(obj_schema VARCHAR2,
obj_name VARCHAR2) RETURN VARCHAR2
Page 21 of 70
For example, any select statement on RA_CUSTOMER_TRX (synonym to which the security policy is
attached) will be dynamically modified to make use of the policy predicate.
SELECT trx_number from ra_customer_trx
Page 22 of 70
SELECT trx_number from ra_customer_trx
WHERE (EXISTS (SELECT 1
FROM mo_glob_org_access_tmp oa
WHERE oa.organization_id = org_id))
or will be modified at runtime if the responsibility has access to one Operating Unit with access control
enabled for the module as:
SELECT trx_number from ra_customer_trx
ORG_ID = sys_context('multi_org2','current_org_id')
Multi-Org Access Control feature is developed and delivered in phases by financials products first
followed by other products. The Multi-Org global temporary table is populated based on either “MO:
Security Profile” or “MO: Operating Unit” profile option. The profile option “MO: Security Profile”
takes precedence over “MO: Operating Unit”. Until Access Control is turned on for a product, the
profile option “MO: Security Profile” is ignored and only “MO: Operating Unit” is honored.
Products at different levels, access control enabled and not enabled (in transition) can be combined
together under one application menu. Under such case, the Multi-Org initialization should be based on
the application of the calling module and not based on the application tied to the responsibility, since the
profile Option “MO: Security Profile” should be ignored for products who have not enabled access or in
the transition phase.
A new table (MO_PRODUCT_INIT) is introduced for product teams to register their application after
they have opened up access for their product. An entry in this table indicates that the product is Multi-
Org Access Control enabled. The Multi-Org initialization API makes use of the module owner calling
the initialization to initialize the temporary table appropriately with one or multiple Operating Units
depending upon the product status.
Product teams must seed an entry in the Multi-Org table when they are ready to turn on Multi-
Org Access Control for their product.
Table FND_MO_PRODUCT_INIT
When Payables (XXXCHR) opens up access, they must seed a row in the Multi-Org table to indicate that
access is turned on. CRM foundation (JTF) has Multi-Org Access Control turned on already.
Application_Short_Name
JTF
XXXCHR
A loader file must be delivered to the customer to populate this information at the site. Please contact
Shared Services team for the loader file. A loader configuration file afmoinit.lct is available for
extracting the loader file.
Initially the plan was to use register Multi-Org initialization in AOL Callout tables. Since the AOL
Callout routines use the application tied to the responsibility for initialization, the module information
stored in the V$SESSION was planned to be used in the Multi-Org initialization. However there are
certain limitations with this approach:
Module information is not guaranteed to be set for all modules, especially Self Service
Applications, where there is no strong tie between functions and pages.
Page 23 of 70
AOL Initialization will be executed only when there is a responsibility change (validateSession
routine is optimized to execute only under a context change). When accessing different pages
from within the same responsibility, the pages belonging to different applications (access enabled
and not enabled), the initialization is done one way which does not work when navigating from a
page that is not enabled access to a page that is enabled or vice versa.
Due to the above reasons, Multi-Org initialization will not be registered in the AOL Callout tables
anymore. Instead, it will be executed only when called explicitly by the products.
2. Populates a global temporary table used in the UIs and the security policy function.
Functions are available to access data from the temporary table. You should not access the global
temporary table directly in their code. You should use the PL/SQL functions instead.
MO_GLOBAL.Init Procedure
PROCEDURE init(p_appl_short_name VARCHAR2)
IS
l_security_profile_id
fnd_profile_option_values.profile_option_value%TYPE := NULL;
l_org_id
fnd_profile_option_values.profile_option_value%TYPE := NULL;
NO_APPL_NAME EXCEPTION;
BEGIN
IF is_multi_org_enabled = 'Y' THEN
IF p_appl_short_name IS NULL THEN
RAISE NO_APPL_NAME; Seed a new mesg ???
ELSE
Get the profile values and call set_org_access API
fnd_profile.get('XLA_MO_SECURITY_PROFILE_LEVEL',
l_security_profile_id);
fnd_profile.get('ORG_ID', l_org_id);
set_org_access(l_org_id,
l_security_profile_id,
p_appl_short_name);
END IF;
END IF; MultiOrg is enabled
EXCEPTION
…
END init;
MO_GLOBAL.Set_Org_Access Procedure
This API can be called to execute Multi-Org initialization outside of Applications. For example, to
execute Multi-Org initialization from tools like SQL*Plus, TOAD etc.
PROCEDURE set_org_access(p_org_id_char VARCHAR2,
p_sp_id_char VARCHAR2,
Page 24 of 70
l_current_org_id hr_operating_units.name%TYPE;
l_view_all_orgs VARCHAR2(1);
NO_SP_OU_FOUND EXCEPTION;
NO_ORG_ACCESS_FOUND EXCEPTION;
BEGIN
IF is_multi_org_enabled <> 'Y' THEN
RETURN;
END IF;
IF p_org_id_char IS NULL AND p_sp_id_char IS NULL THEN
RAISE NO_SP_OU_FOUND;
END IF;
Replace this code with 10g shared globals
BEGIN
SELECT nvl(mpi.status, 'N')
INTO l_access_ctrl_enabled
FROM fnd_mo_product_init mpi
WHERE mpi.application_short_name = p_appl_short_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_access_ctrl_enabled := 'N';
WHEN OTHERS THEN
generic_error('MO_GLOBAL.SET_ORG_ACCESS', sqlcode, sqlerrm);
END;
Delete temporary table data first for all products access
enabled or not
delete_orgs;
For all products, when the access control feature is enabled,
1. Use the MO: Security Profile if it is set.
2. Use the MO: Operating Unit if “MO: Security Profile” is not
set
IF (l_access_ctrl_enabled = 'Y') THEN
IF l_security_profile_id IS NOT NULL THEN
l_org_id := null;
END IF;
Populate temp table
populate_orgs(l_org_id,
l_security_profile_id,
l_current_org_id,
l_view_all_orgs);
Check if you have access to at least one Operating Unit.
Page 25 of 70
commit;
EXCEPTION
…
END set_org_access;
New Tables
MO_GLOB_ORG_ACCESS_TMP
This is a session-specific global temporary table that stores the Operating Units contained in the current
responsibility's (or site level) “MO: Security Profile” profile option. If the profile option, “MO: Security
Profile” is not defined then, the Operating Unit contained in current responsibility’s (or site level) “MO:
Operating Unit” profile option is stored in the table. It is populated with records from the tables/views
PER_ORGANIZATION_LIST and HR_OPERATING_UNITS. It is used in the Multi-Org security
policy initialization.
Column Name Type Null? Unique? Column Translatable?
Description
ORGANIZATION_ID Number(15) Not Yes Operating No
Null Unit
identifier
NAME Varchar2(240) null Name of the Yes
Operating
Unit
FND_MO_PRODUCT_INIT
Page 26 of 70
Prior to opening up access, upon choosing a responsibility, the CLIENT_INFO org predicate was
initialized to the Operating Unit the responsibility has access. The new profile option, “MO: Security
Profile,” will be used in Multi-Org Access Control feature. This profile option can be set at Site and
Responsibility levels.
There is also a new profile option available for defaulting Operating Unit in setup and transaction forms.
This profile option is set at Site, Responsibility and User levels.
Page 27 of 70
User can optionally set this profile option to default an Operating Unit and other Multi-Org dependent
values in user windows. Defaulting will occur only if user’s security profile includes the Operating Unit
specified in this profile option.
MO_GLOBAL.Check_Access Function
This function checks if a particular ORG is available in the temporary table populated by the
set_org_access API. If found the function returns flag ‘Y’, otherwise ‘N’.
FUNCTION check_access(p_org_id NUMBER)
RETURN VARCHAR2 IS
BEGIN
SELECT 'Y'
INTO l_org_exists
FROM mo_glob_org_access_tmp
WHERE organization_id = p_org_id;
RETURN 'Y';
END;
Page 28 of 70
MO_GLOBAL.get_ou_name function
This function returns the Operating Unit name for a given ORG_ID, if it exists in the temporary table
populated by the set_org_access API.
FUNCTION get_ou_name(p_org_id NUMBER)
RETURN VARCHAR2 IS
BEGIN
SELECT organization_name
INTO l_ou_name
FROM mo_glob_org_access_tmp
WHERE organization_id = p_org_id;
RETURN l_ou_name;
END;
This function can be used to display the Operating Unit name in the form block record groups, caching
SQL etc.
MO_GLOBAL.check_valid_org function
This function checks if an ORG_ID exists in the temporary table. It is equivalent to the check_access
function but also posts an error message if the specified Operating Unit is null or not in the access list.
The calling application can check the returned value of the function and raise an error if it is 'N'.
FUNCTION check_valid_org(p_org_id NUMBER)
RETURN VARCHAR2
IS
BEGIN
IF (p_org_id is null) THEN
Post an error message and return:
fnd_message.set_name('FND', 'MO_ORG_REQUIRED');
FND_MSG_PUB.ADD;
RETURN 'N';
END IF;
IF (check_access(p_org_id) = 'Y') THEN
RETURN 'Y';
END IF;
Post an error message and return:
fnd_message.set_name('FND', 'MO_ORG_INVALID');
FND_MSG_PUB.ADD;
RETURN 'N';
END;
This API can be used in the Public APIs for validating ORG_ID input.
Page 29 of 70
MO_GLOBAL.set_policy_context Procedure
This API sets the application context attributes - current org id and the access mode, which are used in
the Multi-Org security policy function org_security. The current_org_id context can also be used in the
product specific server side validation APIs.
Multi-Org code available today, works within the context of one Operating Unit. To reuse the code, the
application context attribute access_mode can be set to single, so that validation APIs can continue to
work within the context of one Operating Unit without any change. This API can be used to set the
policy context in the different triggers in the forms.
MO_GLOBAL.get_current_org_id Function
This function returns the current_org_id attribute value stored in the application context.
FUNCTION get_current_org_id
RETURN NUMBER IS
BEGIN
RETURN to_number(g_current_org_id
END;
MO_GLOBAL.get_access_mode Function
This function returns the access_mode attribute value stored in the application context.
FUNCTION get_access_mode
RETURN VARCHAR2 IS
BEGIN
RETURN (g_access_mode);
END;
FND_MO_PRODUCT_INIT_PKG.register_application Procedure
This API populates an entry in the FND_MO_PRODUCT_INIT_PKG indicating that a product is Multi-
Org Access Control enabled.
FND_MO_PRODUCT_INIT_PKG.remove_application Procedure
Page 30 of 70
If the profile option “MO: Security Profile” is set and gives access to one Operating
Unit, the default Operating Unit will return this value even if “MO: Default Operating
Unit” is set to a different value.
If the profile option “MO: Security Profile” is set and gives access to multiple Operating
Units, then the profile value “MO: Default Operating Unit” if set is validated against the
list of Operating Units in “MO: Security Profile”. If the Operating Unit is included in
the security profile then it is returned as the default value. Otherwise there is no
Operating Unit default. Also, if the Profile Option “MO: Default Operating Unit” is not
set, then there is o default Operating Unit.
MO_UTILS.Get_Default_OU Procedure
MO_UTILS.get_default_org_id Function
This API returns the default Operating Unit ORG_ID for a given responsibility. The default ORG_ID
could be NULL, if there is no valid default Operating Unit, which is determined by the defaulting rules.
The Multi-Org views can be divided into two categories, single organization views and reference views.
Single Organization views are views based on the _ALL, _ALL_B or_ ALL_TL Multi-Org tables and
have the single org predicate attached to them to return data for the current Operating Unit specified by
the CLIENT_INFO environment variable. The tables’ _ALL_B and _ALL_TL were introduced for
Multi-Lingual Support (MLS).
Page 31 of 70
The changes that need to be done to single organization views and reference views are explained in
detail here.
Example 1:
The view definition of single organization view RA_BATCHES is shown below in the example.
CREATE OR REPLACE VIEW RA_BATCHES AS
SELECT "BATCH_ID",
“LAST_UPDATE_DATE",
"LAST_UPDATED_BY",
"CREATION_DATE",
...
"ORG_ID" ,
"PURGED_CHILDREN_FLAG" ,
"ISSUE_DATE" ,
"MATURITY_DATE" ,
"SPECIAL_INSTRUCTIONS" ,
"BATCH_PROCESS_STATUS" ,
"SELECTION_CRITERIA_ID"
FROM RA_BATCHES_ALL
WHERE
NVL(ORG_ID,NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),
' ',NULL,SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)) =
NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),' ',NULL,
SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)
This single organization view RA_BATCHES must be replaced by a synonym as given below:
CREATE SYNONYM RA_BATCHES FOR AR.RA_BATCHES_ALL
The summary of changes that must be done for single organization views joined to single _ALL table
are given below:
Example 2:
The view definition of simple single organization view AR_VAT_TAX_B is shown below in the
example.
CREATE OR REPLACE VIEW AR_VAT_TAX_B AS
SELECT "VAT_TAX_ID",
"SET_OF_BOOKS_ID",
"TAX_CODE",
...
"ORG_ID",
...
FROM AR_VAT_TAX_ALL_B
Page 32 of 70
This single organization view AR_VAT_TAX_B must be replaced by a synonym with the security policy
attached.
CREATE SYNONYM AR_VAT_TAX_B FOR AR.AR_VAT_TAX_ALL_B
A Multi-Org utility is available to list single organization views by product. Click here to access the
utility.
You can access the utility from the following URL:
http://www-apps.us.oracle.com/ssa/utils/multi-org-views.html
Example 3:
The view example of AP_CARD_SUPPLIERS is as given below. This view uses ROWID alias for
ROW_ID column of the underlying AP_CARD_SUPPLIERS_ALL table.
CREATE OR REPLACE VIEW AP_CARD_SUPPLIERS AS
SELECT ROWID,
CARD_ID,
VENDOR_ID,
ORG_ID,
...
FROM AP_CARD_SUPPLIERS_ALL
WHERE
NVL(ORG_ID,NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),
' ', NULL,SUBSTRB(USERENV('CLIENT_INFO'),1 ,10))), -99)) =
NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),' ',NULL,
SUBSTRB(USERENV('CLIENT_INFO'),1,10))),-99)
This single organization view AP_CARD_SUPPLIERS must be replaced by a synonym with the security
policy attached.
CREATE SYNONYM AP_CARD_SUPPLIERS FOR
AP.AP_CARD_SUPPLIERS_ALL
When the view is replaced with a synonym, the code that is dependent on ROWID column becomes
INVALID as the synonym AP_CARD_SUPPLIERS does not have this column. Such code using
incorrect column alias should be fixed.
The AR single organization view AR_TA_CR_AGEN_INF_V has the similar issue i.e. uses alias
ROWID for ROW_ID column. The dependent objects referencing the ROWID alias should be fixed.
Example 4:
The view definition of single organization view AR_PAYMENT_SCHEDULES_V is shown below in
the example. This is a special case, where the CLIENT_INFO predicate is coded in the view definition,
for performance reasons (the union clause in this view definition makes it non mergeable, so, using base
tables instead of views in the FROM clause is preferred)
CREATE OR REPLACE VIEW AR_PAYMENT_SCHEDULES_V AS
SELECT PS.ROWID ,
PS.PAYMENT_SCHEDULE_ID ,
PS.TRX_NUMBER ,
...
FROM ar_lookups al_status,
Page 33 of 70
Page 34 of 70
Page 35 of 70
The CLIENT_INFO predicate must be removed from the Where Clause, ORG_ID column must be
added to the view, ORG_ID filter added for tables with ORG_ID as part of the composite key (as in
setup tables that contain seed data replicated to every org) or ORG_ID is the driving key for the table
(as in product system options tables) and the driving table for the view is replaced by a secured synonym
(AR_PAYMENT_SCHEDULES):
CREATE OR REPLACE VIEW AR_PAYMENT_SCHEDULES_V AS
SELECT PS.ROWID ,
PS.PAYMENT_SCHEDULE_ID ,
PS.TRX_NUMBER ,
...
PS.ORG_ID
FROM ar_lookups al_status,
ar_collectors ar_coll,
ar_cons_inv_all cons,
ra_cust_trx_types_all ctt,
ra_batch_sources_all bs,
ra_customer_trx_all ct,
hz_cust_site_uses_all su,
hz_cust_accounts cust_acct,
hz_parties party,
ar_payment_schedules ps
WHERE PS.CUSTOMER_ID = CUST_ACCT.CUST_ACCOUNT_ID
AND CUST_ACCT.PARTY_ID = PARTY.PARTY_ID
AND PS.CUSTOMER_SITE_USE_ID = SU.SITE_USE_ID
AND PS.CUSTOM ER_TRX_ID = CT.CUSTOMER_TRX_ID
AND CT.BATCH_SOURCE_ID = BS.BATCH_SOURCE_ID
AND CT.ORG_ID = BS.ORG_ID
AND CT.CUST_TRX_TYPE_ID = CTT.CUST_TRX_TYPE_ID
AND CT.ORG_ID = CTT.ORG_ID
AND PS.STATUS = AL_STATUS.LOOKUP_CODE
AND AL_STATUS.LOOKUP_TYPE = 'INVOICE_TRX_STATUS'
AND PS.COLLECTOR_LAST = AR_COLL.COLLECTOR_ID (+)
AND PS.CONS_INV_ID = CONS.CONS_INV_ID (+)
AND PS.STATUS = NVL(ARP_VIEW_CONSTANTS.GET_STATUS,PS.ST ATUS)
UNION ALL
SELECT PS.ROWID,
PS.PAYMENT_SCHEDULE_ID,
PS.TRX_NUMBER,
...
PS.ORG_ID
Page 36 of 70
Click here to run the utility script that lists the Multi-Org tables that include ORG_ID as part of the
composite key. You can access the utility from the following URL:
http://www-apps.us.oracle.com/ssa/utils/composite-index.html
Example 5:
The view definition of single organization view RA_ADDRESSES is shown below in the example.
This is a special case. The view is based on RA_ADDRESSES_ALL synonym and includes
CLIENT_INFO filter. The synonym RA_ADDRESSES_ALL in turn is based on
RA_ADDRESSES_MORG view. RA_ADDRESSES_MORG view is based on several HZ tables
(HZ_CUST_ACCT_SITES_ALL, HZ_LOC_ASSIGNMENTS, HZ_LOCATIONS and
HZ_PARTY_SITES). This is done for backward compatibility for customer migration to TCA.
CREATE OR REPLACE VIEW RA_ADDRESSES AS
SELECT ROW_ID ,
KEY_ACCOUNT_FLAG ,
ORG_ID ,
FROM RA_ADDRESSES_ALL WHERE
NVL(ORG_ID,NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1 ,1),
' ',NULL,SUBSTRB(USERENV('CLIENT_INFO'), 1,10))),
-99)) = NVL(TO_NUMBER(DECODE( SUBSTRB(USERENV('CLIENT_INFO'),1,1), '
Page 37 of 70
This single organization view RA_ADDRESSES must be rewritten as a reference view following the
guidelines of reference views given in the next section. Basically RA_ADDRESSES must remain as a
view based on HZ_CUST_ACCT_SITES (secured synonym), HZ_LOC_ASSIGNMENTS,
HZ_LOCATIONS and HZ_PARTY_SITES and the CLIENT_INFO predicate must be removed from the
view.
There are two additional cases, single organization views that have either MLS logic or MRC logic
embedded in the where clause in addition to single org predicate.
Example:
CREATE OR REPLACE VIEW AR_VAT_TAX_VL AS
SELECT B.ROWID ROW_ID,
B.ADJ_NON_REC_TAX_CCID,
B.EDISC_NON_REC_TAX_CCID,
B.UNEDISC_NON_REC_TAX_CCID,
...
B.ENABLED_FLAG,
B.TAX_CLASS,
B.DISPLAYEDED_FLAG,
B.TAX_CONSTRAINT_ID
FROM AR_VAT_TAX_ALL_TL T,
AR_VAT_TAX_ALL_B B
WHERE B.VAT_TAX_ID = T.VAT_TAX_ID
AND NVL(B.ORG_ID, 99) = NVL(T.ORG_ID, 99)
AND NVL(B.ORG_ID,NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),
1 ,1),' ', NULL, SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)) =
NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),' ', NULL,
SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)
AND T.LANGUAGE = userenv('LANG')
The above view definition in addition to CLIENT_INFO predicate includes filter condition for MLS
logic, which needs to stay. Hence, the single organization view should be converted to a reference view
as given below:
CREATE OR REPLACE VIEW AR_VAT_TAX_VL AS
SELECT B.ROWID ROW_ID,
B.ADJ_NON_REC_TAX_CCID,
B.EDISC_NON_REC_TAX_CCID,
Page 38 of 70
The summary of changes that must be done for single organization views with MLS logic are given
below:
Note: In the above example, ORG_ID filter in the Where Clause is removed, since it is not part of the
composite index for the tables joined.
CREATE OR REPLACE VIEW AR_BATCHES_MRC_V AS
SELECT MC.BATCH_ID ,
MC.SET_OF_BOOKS_ID,
LAST_UPDATED_BY ,
...
TRANSMISSION_ID ,
BANK_DEPOSIT_NUMBER ,
ORG_ID ,
PURGED_CHILDREN_FLAG
FROM AR_BATCHES_ALL B,
AR_MC_BATCHES MC
WHERE MC.BATCH_ID=B.BATCH_ID
AND MC.SET_OF_BOOKS_ID = NVL(TO_NUMBER(SUBSTRB(USERENV('CLIENT_INFO'),
45,10)),99)
AND NVL(ORG_ID,NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),
1 ,1),' ', NULL, SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)) =
NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),' ', NULL,
SUBSTRB(USERENV('CLIENT_INFO'),1,10))),99)
The above view definition in addition to CLIENT_INFO predicate includes filter condition for MRC
logic, which needs to stay. Hence, the single organization view should be converted to a reference view
as given below:
Page 39 of 70
45,10)),99)
The summary of changes that must be done for single organization views with MRC are given below:
Reference Views
The reference views join one or more single organization views. These views must be modified to
include just one secured synonym in the join condition. The _ALL tables must be used for the reference
to the rest of the single organization views. The criteria to pick the secured synonym are a) is a driving
table and b) has small volume of data (typically a setup table as opposed to a transaction table).
ORG_ID filter must be added to the WHERE Clause condition to avoid Cartesian products for tables
that include ORG_ID as part of the composite index (as in tables that contain seed data replicated to
every org) or ORG_ID is the driving key for the table (as in product system options tables).
Important: Every reference view should have only one secured synonym. Limiting the number of
secured synonyms to only one improves performance.
Example 1:
Page 40 of 70
The view definition is modified for Multi-Org Access Control replacing reference to single organization
views with _ALL tables for all except one object RA_CUSTOMER_TRX which is the driving table so
kept as secured synonym as given below:
CREATE OR REPLACE VIEW RA_CUSTOMER_TRX_PARTIAL_V AS
SELECT CT.ROWID "ROW_ID",
CT.CUSTOMER_TRX_ID "CUSTOMER_TRX_ID",
CT.TRX_NUMBER "TRX_NUMBER",
CT.OLD_TRX_NUMBER "OLD_TRX_NUMBER",
CT_REL.TRX_NUMBER "CT_RELATED_TRX_NUMBER",
ARPT_SQL_FUNC_UTIL.get_salesrep_name_number(CT.PRIMARY_SALESREP_ID,'NA
ME'’, CT.ORG_ID
) "RAS_PRIMARY_SALESREP_NAME",
ARPT_SQL_FUNC_UTIL.get_salesrep_name_number(CT.PRIMARY_SALESREP_ID,'NU
MBE
R', CT.ORG_ID) "RAS_PRIMARY_SALESREP_NUM",
CT.ORG_ID,
…
FROM RA_CUST_TRX_LINE_GL_DIST_ALL GD,
RA_CUSTOMER_TRX CT,
…
RA_SITE_USES_ALL SU_BILL,
RA_CUSTOMERS RAC_PAYING,
RA_CUSTOMERS RAC_BILL
RA_SITE_USES_ALL SU_BILL,
Page 41 of 70
The summary of changes that must be done for reference views are given below:
Example 2:
Page 42 of 70
The view definition is modified for Multi-Org Access Control as given below (ORG_ID column is added
to view definition, all single org views reference replaced by _ALL tables keeping
RA_CUSTOMER_TRX_LINES (CTL_TAX) which is the driving table, as secured synonym):
CREATE OR REPLACE VIEW AR_TAX_LINES_V AS
SELECT CTL_TAX.ROWID ,
CTL_TAX.CUSTOMER_TRX_ID ,
CTL_TAX.CUSTOMER_TRX_LINE_ID ,
CTL_TAX.PREVIOUS_CUSTOMER_TRX_ID ,
CTL_TAX.PREVIOUS_CUSTOMER_TRX_LINE_ID ,
CTL_TAX.LINK_TO_CUST_TRX_LINE_ID ,
...
CTL_TAX.ORG_ID
FROM RA_CUSTOMER_TRX_LINES_ALL CTL_INV_LINE,
RA_CUSTOMER_TRX_LINES_ALL CTL_INV_TAX,
AR_VAT_TAX_ALL INV_VAT,
RA_CUSTOMER_TRX_LINES_ALL CTL_LINE,
RA_CUSTOMER_TRX_LINES CTL_TAX,
AR_VAT_TAX_ALL VAT
WHERE CTL_TAX.LINK_TO_CUST_TRX_LINE_ID =
CTL_LINE.CUSTOMER_TRX_LINE_ID
AND CTL_TAX.LINE_TYPE = 'TAX'
AND CTL_TAX.VAT_TAX_ID = VAT.VAT_TAX_ID(+)
AND CTL_TAX.PREVIOUS_CUSTOMER_TRX_LINE_ID =
CTL_INV_TAX.CUSTOMER_TRX_LINE_ID (+)
AND CTL_INV_TAX.LINK_TO_CUST_TRX_LINE_ID =
CTL_INV_LINE.CUSTOMER_TRX_LINE_ID (+)
AND CTL_INV_TAX.VAT_TAX_ID = INV_VAT.VAT_TAX_ID (+)
BEGIN
FND_ACCESS_CONTROL_UTIL.Add_Policy
( p_object_schema => '&&1', Apps user name
p_object_name => 'FINANCIALS_SYSTEM_PARAMETERS',
p_policy_name => 'ORG_SEC’,
p_function_schema => '&&1', Apps user name
Page 43 of 70
The ADD_POLICY API checks if the policy is attached to the object. If it is attached, then drops the
policy and then reattaches. The first two parameters to this procedure are the schema where the object
to which policy is attached resides and the name of the object. The next three parameters are the policy
name, the schema where the policy function is available and the policy function name. The next three
parameters are the statement type (DML) to which policy applies, a flag to check the policy against any
inserted or updated value and a flag to indicate whether the policy is enabled or not. The last parameter
is to indicate static or dynamic policy available in Oracle 9iR2.
The existing registration should be cleaned up. For example, the dependency of Payables on Multi-Org
is seeded in the following table:
FND_PRODUCT_INIT_DEPENDENCY
To remove dependency:
FND_PRODUCT_INITIALIZATION_PKG.RemoveDependency('XXXCHR','MO');
Product teams must register their product in the Multi-Org table FND_MO_PRODUCT_INIT to indicate
that Multi-Org Access Control is enabled when they are ready to turn on. This information is needed for
module based initialization, to ignore “MO: Security Profile” or not.
Table FND_MO_PRODUCT_INIT
When Payables (XXXCHR) opens up access, they must seed a row in the Multi-Org table to indicate that
access is turned on. CRM foundation (JTF) has Multi-Org Access Control turned on already.
Application_Short_Name
JTF
XXXCHR
Use the API provided by Shared Services to register the access enabled status.
Page 44 of 70
Use the FNDLOAD utility to extract the seed data in FND_MO_PRODUCT_INIT table. A loader file
must be delivered to the customer to populate this information at the site. Please contact Shared
Services team for the loader file. A loader configuration file afmoinit.lct is available for extracting the
loader file.
The following section details the changes that must be done by the product teams in the setup and
transaction forms for Multi-Org Access Control:
Every form modified for Multi-Org Access Control should include, the call to Multi-Org initialization
API (MO_GLOBAL.init) in the Pre-Form trigger. The Application Short Name passed to the API is
used to determine the access enabled status of the product in order to populate the temporary table
accordingly. Also the application contexts used in the VPD security policy are initialized. The
Application short name should correspond to the data registered in FND_APPLICATION table.
For example, a Payables form modified to open up access, should include the following code as given
below in the PRE-FORM trigger:
BEGIN
APP_STANDARD.EVENT(‘PRE-FORM’);
MO_GLOBAL.init (‘XXXCHR’);
END;
In the above example, XXXCHR is the application short name for Payables.
If AP has opened up access in 11ix, the above code would populate the temporary table with multiple
Operating Units if the profile option “MO: Security Profile” is set for multiple access. Also the access
mode will be set to “MULTIPLE” or “ALL” depending upon the number of Operating Units the user has
access to.
Page 45 of 70
The record group query for Operating Unit field should be coded as given below:
select hr.organization_id org_id
, hr.name operating_unit
FROM hr_operating_units hr
WHERE mo_global.check_access(hr.organization_id) =
‘Y’
Create a LOV based on this record group. LOV window size 3 x 3 inches. The Operating Unit name
must be displayed in the LOV window.
Pre-Form trigger
DECLARE
l_default_org_id number;
l_default_ou_name varchar2(240);
l_ou_count number;
BEGIN
...
mo_utils.get_default_ou(l_default_org_id, l_default_ou_name,
l_ou_count);
:PARAMETER.mo_default_org_id) := l_default_org_id;
:PARAMETER.mo_default_ou_name := l_default_ou_name;
:PARAMETER.mo_ou_count := l_ou_count;
Page 46 of 70
...
END;
END IF;
IMPORTANT: Setting the current org in the different triggers given below SHOULD NOT be used for
new forms that you are building. For new code, you should use _ALL tables and include form block
ORG_ID to restrict data to the Operating Unit that the user selected.
The Multi-Org security policy function uses a dynamic predicate to handle simple predicate when the
access is limited to one Operating Unit vs. complex predicate (exists sub-query) when the access is
multiple. The predicate is based on the application context attribute value for access_mode.
To salvage the existing code, depending upon whether the forms uses Select Operating Unit or Derive
Operating Unit feature, the access_mode can be set to single or multiple in the different triggers given
below:
END IF;
IF :<your block name.org_id> is not null
IF :<block name.org_id> <> nvl(:<parameter.old_org_id>,99) THEN
Get the cache for current org
END IF;
ELSE
Refresh the cache
…
END IF;
Note: The defaulting API will return data even if the “MO: Default Operating Unit” Profile is not set
when the responsibility has access to one operating. So the ELSE condition for setting the policy
context need not check the parameter.ou_count value.
Page 47 of 70
This trigger is needed only if your form allows multi record commit.
IF (:<your block name.org_id> IS NOT NULL ) THEN
IF :<block name.org_id> <> nvl(:<parameter.old_org_id>,99) THEN
mo_global.set_policy_context('S', :block.org_id);
Get the cache for the current org
END IF;
ELSE :block.org_id is null, so set the context to multiple
mo_global.set_policy_context('M', null);
Refresh the cache
END IF;
Page 48 of 70
Pre-Update Trigger
This trigger is needed if your form allows multi record commits where the records could be in different
Operating Units.
IF (:<your block name.org_id> IS NOT NULL ) THEN
IF :<block name.org_id> <> nvl(:<parameter.old_org_id>,99) THEN
mo_global.set_policy_context('S', :block.org_id);
Get the cache for the current org
END IF;
END IF;
For product teams that need server side caching to be initialized for validations on the server, you could
get the current_org_id by calling the Multi-Org API mo_global.get_current_org_id provided you set the
dynamic policy context correctly.
When_Create-Record trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the default OU is available.
If so, copy default OU to form block
IF :parameter.mo_default_org_id is not null and
:block.org_id is null then
:block.org_id = :parameter.mo_default_org_id;
:block.operating_unit := :parameter.mo_default_ou_name;
END IF;
Check if the block org is set. Then check if the operating
unit available as default is the same as the one available in
parameter or a non base table block. If same, then do not copy
again from cache. This ensures that you do not refresh the
parameter or a non base table block if you continue to enter
transactions for the org which is same as the default org.
Page 49 of 70
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
-- Other Code --
...
END;
Step 5: Modify the WHEN-VALIDATE-ITEM trigger of the Operating Unit field (as well as Operating
Unit specific fields used in derive operating feature)
After the user selects an Operating Unit, the current Operating Unit record must be copied from the
cache to the parameter or non base table block.
For product teams that need server side caching to be initialized for validations on the server, you could
get the current_org_id by calling the Multi-Org API mo_global.get_current_org_id provided you set the
dynamic policy context correctly.
Note: For forms that support Derive Operating Unit feature, the code to copy the cache to the parameter
or non base table block should be included not only in the When-Validate-Item trigger of the Operating
Unit field, but also in the When-Validate-Item triggers of the Operating Unit specific fields that could be
used to derive the Operating Unit. Please see “Derive Operating Unit feature” section for more details.
When-Validate-Item Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the new Operating Unit selected by the user is the same
as the old Operating Unit that is available in the parameter or
a non base table block. If same then do not copy again from
cache
Page 50 of 70
Get the current Org attributes from client side cache
l_gr := xx_mo_local_cache.get_org_attributes(:<<your block
name>>.org_id);
Copy from cache to parameter block or a non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
:parameter.ledger_id := l_gr.ledger_id;
:parameter.ledger_name := l_gr.ledger_name;
:parameter.currency_code := l_gr.currency_code;
/* << Begin productspecific assignments >> */
Additional assignments...
:parameter.<column1> := l_gr.column1;
/* << End productspecific assignments >> */
Copy the block org_id to parameter.old_org_id
:parameter.old_org_id := <:block name.org_id>;
END IF;
ELSE
Copy null to parameter columns
END IF;
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Step 6: Modify the block level When-New-Record-Instance trigger of the Operating Unit field block
When the user tries to modify any attribute of a transaction after it is saved, the current operating record
must be copied from the cache to the parameter or non base table block, to use it for validations as well
as for controlling the display properties of the items in the record. The parameter or non base table
block will be populated with the current org cache when the user navigates for one record to another
after the records are queried up.
For product teams that need server side caching to be initialized for validations on the server, you could
get the current_org_id by calling the Multi-Org API mo_global.get_current_org_id provided you set the
dynamic policy context correctly.
The when-new-record-instance trigger must be used to detect the updates and accordingly refresh the
cache.
When-New-Record-Instance Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the new Operating Unit selected by the user is the
same as the old Operating Unit that is available in the
parameter or non base table block. If same then do not copy
again from cache
Page 51 of 70
Get the current Org attributes from client side cache
l_gr := xx_mo_local_cache.get_org_attributes(:<<your block
name>>.org_id);
Copy from cache to parameter block or non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
:parameter.ledger_id := l_gr.ledger_id;
:parameter.ledger_name := l_gr.ledger_name;
:parameter.currency_code := l_gr.currency_code;
/* << Begin productspecific assignments >> */
Additional assignments...
:parameter.<column1> := l_gr.column1;
/* << End productspecific assignments >> */
Copy the block org_id to parameter.old_org_id
:parameter.old_org_id := <:block name.org_id>;
END IF;
END IF;
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Step 7: Modify the block level Post-Query trigger of the Operating Unit field block
IMPORTANT: Post-Query trigger fires for every record, when you do a blind query and hence
you should consider rewriting your SQL to use _ALL tables and use ORG_ID join condition (based
on the form block ORG_ID). You are not required to synchronize the cache in the post-query
trigger. The WNRI will synchronize the cache.
In forms, where some of the Operating Unit specific display fields are populated in the post query
trigger, you must synchronize the cache based on the record’s Operating Unit.
For product teams that need server side caching to be initialized for validations on the server, you could
get the current_org_id by calling the Multi-Org API mo_global.get_current_org_id provided you set the
dynamic policy context correctly.
Post-Query Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the new Operating Unit selected by the user is the
same as the old Operating Unit that is available in the
parameter or non base table block. If same then do not copy
again from cache
IF :<block name.org_id> is not null THEN
Page 52 of 70
Get the current Org attributes from client side cache
l_gr := xx_mo_local_cache.get_org_attributes(:<<your block
name>>.org_id);
Copy from cache to parameter block or non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
:parameter.ledger_id := l_gr.ledger_id;
:parameter.ledger_name := l_gr.ledger_name;
:parameter.currency_code := l_gr.currency_code;
/* << Begin productspecific assignments >> */
Additional assignments...
:parameter.<column1> := l_gr.column1;
/* << End productspecific assignments >> */
Copy the block org_id to parameter.old_org_id
:parameter.old_org_id := <:block name.org_id>;
END IF;
END IF;
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Step 8: Modify the block level Pre-Insert trigger of the Operating Unit field block
You need this trigger only if your form allows multi-record commit, where you must synchronize the
cache.
Pre-Insert Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the new Operating Unit selected by the user is the
same as the old Operating Unit that is available in the
parameter or non base table block. If same then do not copy
again from cache
IF :<block name.org_id> is not null THEN
IF :<block name.org_id> <> nvl(:<parameter.old_org_id>, 99)
THEN
Get the current Org attributes from client side cache
l_gr := xx_mo_local_cache.get_org_attributes(:<<your block
name>>.org_id);
Copy from cache to parameter block or non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
Page 53 of 70
Copy the block org_id to parameter.old_org_id
:parameter.old_org_id := <:block name.org_id>;
END IF;
END IF;
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Step 9: Modify the block level Pre-Update trigger of the Operating Unit field block
You need this trigger only if your form allows multi-record commit, where you must synchronize the
cache.
Pre-Update Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Check if the new Operating Unit selected by the user is the
same as the old Operating Unit that is available in the
parameter or non base table block. If same then do not copy
again from cache
IF :<block name.org_id> is not null THEN
IF :<block name.org_id> <> nvl(:<parameter.old_org_id>, 99)
THEN
Get the current Org attributes from client side cache
l_gr := xx_mo_local_cache.get_org_attributes(:<<your block
name>>.org_id);
Copy from cache to parameter block or non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
:parameter.ledger_id := l_gr.ledger_id;
:parameter.ledger_name := l_gr.ledger_name;
:parameter.currency_code := l_gr.currency_code;
/* << Begin productspecific assignments >> */
Additional assignments...
:parameter.<column1> := l_gr.column1;
/* << End productspecific assignments >> */
Copy the block org_id to parameter.old_org_id
:parameter.old_org_id := <:block name.org_id>;
END IF;
Page 54 of 70
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Note: For forms like AR Receipt Workbench, ON_LOCK trigger may be needed as opposed to Pre-
Update (Feedback from AR).
Step 10: Modify the block level Pre-Record trigger of the Operating Unit field block
You need this trigger only if your form forces users to commit the record before navigating to the next
record.
Pre-Record Trigger
DECLARE
l_gr xx_mo_cache_utils.GlobalsRecord;
BEGIN
Get the current Org attributes from client side cache
org stored in the parameter.old_org_id
l_gr :=
xx_mo_local_cache.get_org_attributes(:parameter.old_org_id);
Copy from cache to parameter block or non base table block
You can replace parameter block shown here
with any non base table block
:parameter.chart_of_accounts_id := l_gr.chart_of_accounts_id;
:parameter.ledger_id := l_gr.ledger_id;
:parameter.ledger_name := l_gr.ledger_name;
:parameter.currency_code := l_gr.currency_code;
/* << Begin productspecific assignments >> */
Additional assignments...
:parameter.<column1> := l_gr.column1;
/* << End productspecific assignments >> */
END IF;
END IF;
Pass the ORG_ID to server code to use the server cache for the
current org for the record validations
Get Batch Source Header Defaults
arp_trx_defaults.get_header_defaults(param1, param2,
…,:block.org_id);
Other code
END;
Page 55 of 70
Example 1
The LOV is always enabled. If the Operating Unit field is left blank, the current org is not set and the
access mode is set to multiple. So the record group SQL will return data for multiple Operating Units.
If the Operating Unit is selected, the current org is set and the access mode is single and the same LOV
will return data for the selected Operating Unit.
Note: In the above example, ORG_ID filter is added to avoid Cartesian join.
Example 2
select ci.cons_billing_number,
ci.customer_id,
Page 56 of 70
Note: Here it is not necessary to add ORG_ID filter in the Where Clause to join RA_SITE_USES and
AR_CONS_INV views, since site_use_id is unique and sufficient to determine the ORG.
Example 3
select max(tc.name) name,
lc.displayed_field type,
tc.description
from ap_lookup_codes lc,
ap_tax_codes tc
where lc.lookup_type = 'TAX TYPE'
and tc.tax_type != 'OFFSET'
and tc.tax_type != 'AWT'
and lc.lookup_code = tc.tax_type
and nvl(tc.enabled_flag,'Y')='Y'
group by tc.name, lc.displayed_field, tc.description
Note 1: It is left to the product teams to implement select Operating Unit or derive Operating Unit for
the record groups based on the business logic. There is no difference to the record group SQL for select
Operating Unit vs derive Operating Unit, since setting the policy context should take care of that.
Note 2: For forms that support select Operating Unit, since the Operating Unit dependent fields are
greyed out, until an Operating Unit is selected, the records groups of these fields could be based on
_ALL tables instead of secured synonym.
The above select statement could be rewritten to use the ALL tables instead of secured synonyms,
passing the form block ORG_ID as given below:
select max(tc.name) name,
lc.displayed_field type,
tc.description
from ap_lookup_codes lc,
ap_tax_codes_ALL tc
where lc.lookup_type = 'TAX TYPE'
and tc.tax_type != 'OFFSET'
and tc.tax_type != 'AWT'
and lc.lookup_code = tc.tax_type
and nvl(tc.enabled_flag,'Y')='Y'
and tc.org_id = :<block_name.org_id>
group by tc.name, lc.displayed_field, tc.description
Page 57 of 70
Example 1:
BEGIN
SELECT
NVL(copy_doc_number_flag, 'N')
INTO
l_copy_doc_number_flag
FROM
ra_batch_sources
WHERE
batch_source_id = l_ct_rec.batch_source_id
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_copy_doc_number_flag := 'N';
END;
Example 2:
With opening up access, a responsibility may have access to multiple Operating Units. You must not
rely on the RDBMS default value for ORG_ID column since it will not be set anymore. The value for
ORG_ID column must be specified explicitly in the table handlers.
Note: Product teams should not modify the RDBMS default value for ORG_ID to use the current org.
The current_org is introduced mainly to minimize the code change for the product code that always gets
Page 58 of 70
Please refer to upgrade section to see an example of script to remove RDBMS default value for ORG_ID
column.
For insert statements the ORG_ID column value must be passed to the table handlers. For update
statements, if you use a primary key column in your selection criteria, then ORG_ID value is not
required in the table handler. The examples given below demonstrate this:
Example 1:
An insert statement
insert into <table*>
(<column1>
<column2>
…
<org_id>)
values ( <value1>,
<value2>,
…
p_org_id)
* the table indicated here is the synonym to which Multi-Org security policy is attached.
Example 2:
An update statement
update <table>
set <column1> = <value1>
where primary_key = <value>
Example 3:
A delete statement
DELETE FROM ra_customer_trx
WHERE customer_trx_id = p_customer_trx_id;
In the example above, the primary key is used for the update and the delete statements, hence ORG_ID
filter is not added.
Page 59 of 70
Note: Table handlers could use ALL tables instead of secured synonyms, provided you have validated the
ORG_ID upstream. It is important that you validate the ORG_ID, since you should not be able to do any
DML for an Operating Unit that you do not have access to.
FND_ACCESS_CONTROL_UTIL.Get_Org_Name
FUNCTION Get_Org_Name( p_org_id NUMBER )
RETURN VARCHAR2
IS
l_return hr_all_organization_units_tl.name%TYPE;
BEGIN
SELECT name
INTO l_return
FROM hr_all_organization_units_tl
WHERE organization_id = p_org_id
AND language = userenv('LANG');
IF SQL%NOTFOUND
THEN
l_return := NULL;
END IF;
RETURN l_return;
END Get_Org_Name;
Forms that wish to enable the Query Enter functionality for the Operating Unit name need to modify the
PRE-QUERY trigger of the Operating Unit block. The trigger must dynamically modify the
DEFAULT_WHERE property of the block to append a LIKE sub-query that examines the
hr_operating_units view for records whose name matches the string entered in the Operating Unit field.
Note: Queries on the hr_operating_units view take into account the user's current language context.
DECLARE
block_id Block := FIND_BLOCK('<block name>');
sub_where VARCHAR2(512);
def_where VARCHAR2(512);
Page 60 of 70
RETURN NULL;
END;
BEGIN
sub_where := NULL;
END;
4.3.13 Handle Flexfields
There is no way to know the ledger ID and chart of accounts ID at forms opening if the responsibility
has access to multiple Operating Units. It is determined only after an Operating Unit is selected or
derived.
To enable access control for accounting flexfields, the following changes must be done:
1. Add a new item CHART_OF_ACCOUNTS_ID to your form block that is a base block of your
canvas. Use this instead of parameter.chart_of_accounts_id, which reduces the number of calls of
fnd_key_flex.define.
2. Call the fnd_key_flex.define in the following triggers:
Block Level When-Create-Record
Item Level When-Validate-Item on Operating Unit field and also on Operating Unit specific
fields used in the “derive Operating Unit” feature.
Block Level Post-Query
Block Level Pre-Query (if you need to allow querying on accounting flexfields)
Page 61 of 70
For example, the following code defines the key flexfield structure for inserts, updates and queries.
IF :<block name.org_id> <>
nvl(:<parameter.old_org_id>, 99) THEN
However, if you need the ability to query on accounting flexfields, then you should add additional logic
in the block level pre-query trigger to handle enter query. The accounting flexfield must be used in the
query only if the Operating Unit is specified. In other words, the accounting flexfield field should be
made dependent on Operating Unit field. However, during enter-query, we cannot control item
properties to set dependent items. Instead, a message must be displayed to the users asking them to
enter a unique Operating Unit when they execute enter-query.
The following table lists the scenarios when the message should be displayed to the user:
Operating Unit Field Accounting Flexfield Result
Field
Page 62 of 70
END;
l_gr := ap_mo_local_cache.get_org_attributes(l_org_id);
:invoices_folder.chart_of_accounts_id :=
l_gr.chart_of_accounts_id;
fnd_key_flex.define(
BLOCK=>'INVOICES_FOLDER',
FIELD=>'LIABILITY_ACCOUNT',
DESCRIPTION=>'LIABILITY_DESCRIPTION',
ID=>'ACCTS_PAY_CODE_COMBINATION_ID',
…
fnd_flex.event('PRE-QUERY');
END IF;
END IF;
EXCEPTION
WHEN l_no_ou_found THEN
NULL;
WHEN OTHERS THEN
RAISE FORM_TRIGGER_FAILURE;
END;
For master-detail blocks, where accounting flexfield is present in both the master and detail blocks, the
pre-query trigger in the master block must have the call to define key flexfields. You must not call the
define flexfields in the detail block’s pre-query trigger. However, the pre-query trigger in the detail
block should have code to update the block’s chart of accounts ID and call to fnd_flex.event as given
below:
:<block name>.chart_of_account_id :=
l_gr.chart_of_account_id;
fnd_flex.event(‘Pre-Query’);
END IF;
END IF;
The user should be allowed to change the Operating Unit at any point of time before the record is
committed to the database. After the record is committed in the database, the Operating Unit field should
be disabled, preventing users from updating it.
app_item_property.set_property(‘BLOCK_NAME.OPERATING_UNIT’, ENABLED,
PROPERTY_OFF);
The Operating Unit field should not be enabled for the queried records.
app_item_property.set_property(‘BLOCK_NAME.OPERATING_UNIT’, ENABLED,
PROPERTY_OFF);
This section details the changes for Single Org and Cross Org reports
Page 64 of 70
The Operating Unit is a requires field and default value is derived from the
Cross Org Reports should be flagged as ‘MULTIPLE’ for the Operating Unit mode in the “Define
Concurrent Programs” form. The special parameter – Operating Unit will not be available for Cross
Org Reports. The security for Cross Org Reports is modified to take into consideration the “MO:
Security Profile” profile.
Cross Org Reports currently have 2 parameters – Reporting Level and Reporting Context. The valuesets
of these parameters are modified to include MO_GLOB_ORG_ACCESS_TMP table. Also, The Cross
Org APIs that are called in the report executables are modified to include “MO: Security Profile”. The
changes are transparent to the product teams, since Multi-Org product owns the valuesets and the Cross
Org APIs.
At runtime the Multi-Org initialization populates the temporary table with one or multiple Operating
Units based on the access enabled status of the product owning the cross org report.
You should not refer to CLIENT_INFO logic anywhere in the reports. Also NVL function for ORG_ID
should be removed, as Multi-Org is mandatory for R12
This section details the changes for single org and multiple org concurrent programs.
Single Org Concurrent Programs should be flagged as ‘SINGLE’ for the Operating Unit mode in the
“Define Concurrent Programs” form.
The Operating Unit is a requires field and default value is derived from the
MO_URILS.get_default_org_id() API.
Multiple Org Concurrent Programs should be flagged as ‘MULTIPLE’ for the Operating Unit mode in
the “Define Concurrent Programs” form. The ATG Enhancement (ER 2420755) would allow Multi-Org
temporary table MO_GLOB_ORG_ACCESS_TMP to be populated when the user select such concurrent
programs. The special parameter – Operating Unit will not be available for these programs. Instead
product teams should expose Operating Unit parameter as a program parameter. This is an optional
parameter that allows user to submit the concurrent program for a single Operating Unit or for the
Operating Units specified in “MO: Security Profile” profile.
Note: You should not reference the Multi-Org temporary table in the concurrent program seed data or in
Page 65 of 70
business activity
A process, defined by development, performed by applications users that creates and maintains business
transactions or reference data. Examples of business transactions include, but are not limited to:
requisitions, purchase orders, receipts, inventory transfers, invoices, and payments. Examples of
reference data include customer, supplier and bank account information.
business group
An organization which represents the consolidated enterprise, a major division, or an operation
company. This entity partitions Human Resources information and business group level data is secured
by security groups. A business group (BG) is a highest level in an organization hierarchy.
business unit
An organizational group within an enterprise. (See also: organization).
intercompany invoice
An automatically generated statement that eliminates intercompany profit. This transaction may occur
between organizations in the same or different legal entities.
inventory organization
An organization that tracks inventory transactions and balances, and/or that manufactures or distributes
products.
legal entity ( Replace LE definition from LE document when it becomes available. 5/4/2001)
An organization that represents a legal company that you control financial statements and taxes
(whether it is income tax, sales tax or any other fiscal liability). All tax related documents should be
linked to the appropriate legal entity to grant audit trail required by fiscal authority. Legal reports should
be available at legal entity level. A legal entity is comprised of one or more Operating Units. A legal
entity is represented in General Ledger as one or more balancing segment values within a ledger.
multiple installations
Refers to installing subledger products (AP, AR, PO, OE) multiple times for data partitioning purpose.
This is no longer necessary under a Multi–Org implementation.
Page 66 of 70
Organization
An organization is an autonomous business unit of an enterprise, such as a plant, warehouse, division,
or department. Organizations are categorized by organization classification.
organization classification
An organization classifications are a set of system-defined attributes that categorize an organization. For
example, classifications include, but are not limited to: Operating Unit, project expenditure
organization, inventory organization and human resources organization. For more information, please
refer to Error! Bookmark not defined..
organization hierarchy
An organization hierarchies shows hierarchical relationships among organizations in enterprise.
Organization hierarchies are used to construct security profiles.
Responsibility
Determines the data, forms, menus, reports, and concurrent programs you can access in Oracle
Applications. It is linked directly to a data group. Several users can share the same responsibility, and a
single user can have multiple responsibilities.
In Release 11i and prior releases, a profile option controlled the Operating Unit to which the
responsibility was assigned.
In Release 12, a responsibility is assigned to a security profile to control access to one or more Operating
Units is assigned to a responsibility. This allows a user to access data in multiple Operating Units
without changing his responsibility.
security group
Used to secure data within one business group. If installation only has one business group, there is only
one security group.
security profile
A security profile represents a list of one or more Operating Units to which a user has access for inquiry,
reporting and transaction and data entry. Every application user is assigned an organization security
profile by way of their responsibility. Security profiles are defined based on organization hierarchies.
Page 67 of 70
A financial reporting entity that partitions General Ledger information and uses a particular chart of
accounts (Accounting Flexfield structure), functional currency, and accounting calendar. You must
define at least one ledger for each enterprise.
Page 68 of 70