You are on page 1of 33

Oracle Applications: Minimize Customizations with the Custom Library

Presented by Mike Swing/TruTek Training Days 2003

Introduction
Would you like to have a LOV on any field? How about running selected reports with the click of a mouse without
changing forms? Enhancements like these can be done without modifying Applications code using the CUSTOM
library. Learn how the CUSTOM library can help make you more productive.

Although the limits to the customizations of Oracle Applications are virtually endless, they can be
impractical and expensive to implement. Oracle, however, has provided for some fairly simple yet powerful ways to
enhance standard functionality without really customizing at all. Many of these enhancements can be achieved
through modifications to the CUSTOM library.

The CUSTOM library allows extension of Oracle Applications without modification of the actual Oracle Applications
code. Initially the CUSTOM library is an empty shell into which custom code then gets placed. Oracle Applications,
in its default behavior, checks the CUSTOM library after certain .events. to see if there are any specified actions that
need to take place. The code in the CUSTOM library can even be .turned off and on. on a session-by-session basis
with the click of mouse, thus not conflicting with an Oracle supported form. Enhancements such as Zoom, enforcing
business rules, adding Special Menu items, and creating dynamic LOV can all be accomplished using this tool.

While most executives hate the word customize, the CUSTOM library offers a way to enhance standard functionality
without really customizing.
.
More About the CUSTOM Library

The CUSTOM library is a body of PL/SQL code that is attached to and shared by Oracle Applications forms. A form
.communicates. with the CUSTOM library whenever certain user invoked actions and resulting form actions take
place. For example, when a user scrolls through records displayed in a form, the form .checks. with the CUSTOM
package each time a new record is navigated to .see. if there are any additional custom actions that should take place.
This user invoked action, or .event. is called .WHEN-NEW-RECORD-INSTANCE.. In addition, each time a record is
navigated from, the form checks to see if the data in the record is valid, an .event. called .WHEN-VALIDATE-
RECORD.. Whenever these and handful of other events take place, the form checks with the CUSTOM library for
any actions that should take place upon execution of those events. Not all form actions or events result in the form
.checking. with the CUSTOM library for additional desired operations, which limits what it can be used for. For
example, when a button is pressed no check is made with the CUSTOM library for additional actions to be taken. This
means that event cannot be .seen. by the CUSTOM library and execution of custom code cannot be initiated by this
event.

The CUSTOM library comes delivered with the Applications as an empty program. It’s up to the
developers to put the code into it. Whether empty or full Oracle forms continue to check with the
CUSTOM library for code that should be executed upon the occurrence of specified events. Default functionality of
the Applications normally occurs first and then a check is made to see if custom code exists. In this way the
CUSTOM package sits on top of Applications code, not replacing it nor altering. In fact, it is even possible to turn the
CUSTOM library on and off on a user-by-user basis. Before a form checks with the CUSTOM library for code that
should be executed, it checks to see if it should even check!
Figure 1 . Turning On and Off the CUSTOM package.

By setting this menu option to .OFF. any unexpected or undesirable effects caused by the execution of code in the
CUSTOM package can be halted immediately without changing the default functionality of Oracle Applications.

Enforcing Business Rules

The CUSTOM library allows for the enforcement of specific business rules. Many Oracle Applications form fields are
not required nor validated for data consistency, although a business’s needs would be better met if they were. For
example, in an effort to maintain standards you can enforce that customer names be entered in upper case by using the
CUSTOM library. You may also wish to not display an item that is not used, or make items required that otherwise
are not.

Perhaps a business does not use item revision or wishes to enforce Applications default functionality and use only the
most current revision and prevent the user from changing the default item revision on a purchase order line. Using the
CUSTOM library, when the Purchase Order form is opened, the property of the Item Revision field can be changed
dynamically from the default of .Updateable. to .Not Updateable.. The result is seen in the following included screen
shots, Figures 2a and 2b. You see in Figure 2a that the user can choose form different item revisions while in figure
2b the field has been .grayed-out. and a warning is returned when an attempt is made to change the value.
Figures 2a and 2b . Changing the Item Revision to .Not Updateable. using the CUSTOM library.

Zooms
The Zoom feature allows the user to open a second standard or custom form and pass values to it. For example, you
may want to allow access to the Customers form from within the Order Entry form while the user is in the Sales Order
Header section of that form. You can enable Zoom for just the Header section, and when the user invokes it, you can
open the Customers form. Another application of the Zoom might be to automatically email or fax a purchase order
right from the Purchase Orders form. By pressing the Zoom icon in the menu toolbar a custom form is called that
allows the user to input or verify fax and email information, select the method the purchase order should be sent to the
vendor, press the .Send. button and away it goes!
Figures 3a and 3b - Using Zoom to automatically fax or email a purchase order.

Special Menu

Another readily .customizable. feature is the Special Menu. These menu items allow a user to navigate to another
form, run a report, or execute a standard or custom concurrent process by selecting options from the main menu. The
main menu can be dynamically controlled at runtime from the CUSTOM package, meaning a developer can put
different items on the menu for different users, responsibilities, and forms. Each of these custom menu items could be
a link to another form, open up the .Submit Requests. window, or silently submit a concurrent process in the
background.

Consider the user who wants to run the requisition import process for outside processing items from the WIP Discrete
Jobs form. Instead of navigating to the Purchasing responsibility (or having the process be registered in the Work in
Process responsibility), Requests, Run the user could simply pull down the special menu and choose .Requisition
Import. and have the process submitted. Or perhaps a user wants the ability to print a purchase order right from the
Purchase Order form. In response to selecting this custom menu item, the .Submit Requests. window would open and
bring up the parameters form for the Printed Purchase Order concurrent program (Figures 4a and b).
Figures 4a and 4b . Navigating directly from Purchase Orders to Print Purchase Orders via Special Menu.

Custom LOV s

A LOV, or list of values. is a drop down list that allows users to select the data to be input rather than, annually keying
it in. They greatly reduce the time needed to enter data and eliminate the occurrence of data entry errors. However
LOVs only exist on certain fields in Oracle Applications forms and, until 11i, they couldn’t be generated dynamically.
This is because an LOV is a structure that must exist in the form executable file itself in order to be used; it cannot be
created through the CUSTOM library. The only way to create a true LOV prior to 11i would have been to modify the
form itself, leaving the customization open to being overwritten with the application of patches, or potentially lost in
the occurrence of the regeneration of the form.

In 11i Oracle has provided an LOV in each form that, while not provided for this particular reason, can be
momentarily hijacked for custom use. The actual purpose of this standard LOV is to allow for the capability to ZOOM
to multiple destinations from any given form. In previous versions of the Applications only one form was allowed as a
destination when activating the ZOOM button. The ZOOM button would be pressed and navigation would proceed to
the predetermined form. In 11i, however, it is possible to ZOOM to any number of different forms by pressing the
same single ZOOM button.

To allow for multiple forms ZOOM functionality Oracle created the APPCORE_ZOOM LOV in every form with the
intention that it be .dynamically populated. through code placed in the CUSTOM library. What .dynamically
populated. means in this sense is that a developer would supply code to the CUSTOM package that would identify the
form from which the ZOOM button was pressed and then perform a lookup to see which forms had been setup as
possible destinations. Next, the developer would pass this .list. to the APPCORE_ZOOM LOV in the current form
and display it to the user. Finally, when the user has chosen from the list the selected value now resides in a form
parameter that the developer can now capture and determine to which form the user intends to go.

Figures 5a and 5b . User Description field without and with a custom LOV

Perhaps more valuable is the availability of the APPCORE_ZOOM LOV for other uses, namely, providing a way to
add an LOV to any form item. While other LOVs will most likely exist in any form, the values selected from their
lists are .hard coded. to be passed to the items that they have been originally assigned to in the form. In essence, while
it would be possible to dynamically generate the values seen in these LOVs, it would not be possible to change to what
item(s) the chosen value(s) are returned to. What makes the APPCORE_ZOOM LOV unique is that it returns its value
to a hidden parameter in the form.

Once a value is chosen the developer simply puts the code in place to copy the value from this parameter to the field
desired. All of these steps can now be done entirely through the CUSTOM package.

Note: Using the CUSTOM library to alter Oracle code at runtime may bypass important validation logic and may
jeopardize the integrity of your data. The form item that the LOV is to be assigned to must be .told. that is going to be
assigned that particular LOV. Do not assign the APPCORE_ZOOM LOV to an item that already has a default LOV.

A final word about creating custom LOVs and the values they can display. The values in the list may be derived from
a static list, generally no more than a few items that don’t change, or the list itself can be dynamic. This could be
accomplished by the developer passing a SQL query from the CUSTOM package to the APPCORE_ZOOM LOV,
which would execute the query and display the results as choices in the list. In addition, dynamic lists can be created
by referencing Oracle Applications defined value sets.

Automatic Querying of Related Records After Form Navigation

Previously discussed in this paper were various methods of navigating from one form to another to allow for greater
productivity. Ordinarily after successful navigation to the desired form the user would then execute a query to find the
related record in the new form. Or, if the navigation were to the .Submit Requests. form, the desired report or other
concurrent process would still then have to be selected before submission. However, yet another timesaver available
through the CUSTOM package is the ability to automatically query newly opened Oracle forms based upon certain
criteria that you decide upon. Basically, specific item values or attributes from the originating form can be used to
query up a precise record in the destination form. Or, in the case of navigating by ZOOM or Special Menu to the
.Submit Requests. form it is possible to automatically .query up. a desired concurrent process (see Figures 4a and b).

Developer’s to the Rescue


Normally each and every time you wanted to take advantage of the any of the previously mentioned customizations
using the CUSTOM library, a developer would need to be told exactly what you wanted done, the form you’re starting
from, the form or concurrent process you wish to navigate to or execute, possibly the .BLOCK. and .FIELD. name
depending on what you wanted done and so on. Even if each of these customizations takes about an hour, the time can
add up. With an up front investment in a developer, however, you could make many of these customizations yourself,
in matter of minutes, without knowledge or need of PL/SQL code or Oracle Forms developer tools.

A developer can build for you a custom form that would integrate with the Applications and allow you to simply enter
in basic information about what you want to happen and when. For example, to create a custom LOV all you would
need to know is the name of the .FORM., the name of the .FIELD. you wish to have the LOV, and the name of the
.BLOCK. that the item resides in. A .BLOCK. is basically a section of the form containing logically related data.
These three pieces of information can be obtained easily from the .Help. menu item. To obtain the name of the
.FORM. pull down the help menu and select .About Oracle Applications.. In the window that appears scroll down
until you see .Form Name. (Figure 6a).
Figure 6a . Obtaining the name of the current form.

To obtain the name of the .BLOCK. and .FIELD. is just as simple. Place the cursor in the field where you want to
have the LOV and go back to the help menu. Pull down the .Help. menu and click on .Diagnostics.. When submenu
opens choose .Examine. (Figure 7a). A window will open and display the name of the field that the focus is currently
on and the name of the block that the field belongs to (Figure 7b). It is possible to have the two different blocks with
the fields of the same name which is why the name of the block must also be specified.
Figures 7a and 7b . Finding .BLOCK. and .FIELD. information.
Multiple Zooms
How to code Zooms has been extensively documented. The Application Developer's Guide is a good reference, plus,
there are excellent white papers on the topic. Sometimes, however, there may be a need for the user to choose from
more than one function at a Zoom. The procedure for doing this is similar to that of a single function Zoom but with
just a few extra steps. Without going into detail, the steps involved in coding a single Zoom are (1) make the Zoom
available for the desired block and (2) execute the appropriate function for the Zoom event. For a multiple Zoom, in
order to determine the appropriate function to execute, the following steps are required:

(1) create a record group and populate it with the desired function names
(2) attach this record group to the APPCORE ZOOM LOV
(3) display the LOV to the user and capture the selected value
(4) use this selected value to determine which function to execute

Of course, code samples are always nice to ensure the understanding of a process, therefore I have included a sample
below, as well as a detailed explanation of each of the steps.

First, there are two basic ways to create record group. You can either use the built-in Create_Group_From_Query or
Create_Group. For this example, I am using Create_Group and populating it with two sets of values. However the
record group is created, each record must return two character values because that is what the Zoom LOV is mapped
to. The first value should be the text which is displayed, and the second, the value which is used to determine which
function to execute.

In this example, two selections are provided, both opening from the AR Standard Customer form, and from there
providing access to a custom form and the standard AR Customer Accounts form. The custom form has a form
parameter, p_customer_id, and uses the passed parameter to autoquery on the given customer. The standard form,
since its opening block is a Find block, is populated with customer information from the calling Customer form. The
user must then press Find, to access the records for the given customer.

DECLARE
rg_name VARCHAR2(40) := 'Cust_Zoom';
rg_id RecordGroup;
errcode NUMBER;
BEGIN
/*
* Make sure the record group does not already exist.
*/
rg_id := Find_Group(rg_name);
/*
* If it does not exist, create it; add the two necessary columns to it.
*/
IF Id_Null(rg_id) THEN
/*
* Create and populate group
*/
rg_id := CREATE_GROUP( rg_name)
/*
* Add two character columns to the record group
*/
gc_id := Add_Group_Column(rg_id, 'custom form', 'custom form');
gc_id := Add_Group_Column(rg_id, 'Customer Accounts',
'AR_ARXCWMAI_MAI');

END IF;
END;
The new record group is attached to the APPCORE_ZOOM using the set_lov_property built-in. The
APPCORE_ZOOM is an LOV provided by the APPCORE library and accessible from all Oracle forms, as well as
custom forms built using the TEMPLATE form.

set_lov_property('APPCORE_ZOOM',GROUP_NAME,rg_name);

Call show_lov to display the LOV to the user. If a value is chosen, it is accessed from the APPCORE parameter,
APPCORE_ZOOM_VALUE.

/*
* Populate the record group
*/
errcode := Populate_Group(rg_id);

/*
* Built-in: SHOW_LOV: Display a names List of Values (LOV)
*/
DECLARE
a_value_chosen BOOLEAN;
returned_value varchar2(250);
BEGIN
a_value_chosen := Show_Lov('APPCORE_ZOOM');
IF NOT a_value_chosen THEN
Bell;
RAISE Form_Trigger_Failure;
ELSE
returned_value := name_in('PARAMETER.APPCORE_ZOOM_VALUE');
END IF;
END;

Use the returned value to determine which function to execute. Execute the appropriate function, in this example,
passing the current customer_id as a parameter to the target form.

param_to_pass1 := name_in('CUST.customer_id');

IF returned_value = '<custom form>' THEN -- Open custom form

fnd_function.execute(FUNCTION_NAME=>'<custom form>',
OPEN_FLAG=>'Y', SESSION_FLAG=>'Y',
OTHER_PARAMS=>'p_customer_id=‘'||param_to_pass1||'‘');

ELSIF returned_value = 'AR_ARXCWMAI_MAI' THEN -- Open the Customer Account form

copy(name_in('CUST.CUSTOMER_NAME'),'GLOBAL.XOTC_CUSTOMER_NAME');
fnd_function.execute(FUNCTION_NAME=>'AR_ARXCWMAI_MAI',
OPEN_FLAG=>'Y', SESSION_FLAG=>'Y',
OTHER_PARAMS=>'ART_BILL_TO_CUST_ID=‘'||param_to_pass1||'‘');
END IF;

Pass parameters to a Find block


Many of the main functions in Financials are accessible only through Find blocks. In other words, the user must either
.Find,. or request, a specific record to make that record available for update, or the user must request a new record for
data entry. Because of this, forms such as Customer Information, Customer Transactions, Purchase Orders, etc., are
not designed to accept a parameter and automatically open to that specific record.
The example below is code which works around the limitations described above. In this scenario, the user is given
the option of opening the Customer Accounts form from the Standard Customer form. The customer id is passed as a
parameter, but more information is needed by this particular form to open to the desired record. Therefore, a global
variable is used to simulate the entry of the customer name in the Find block. Elsewhere in the CUSTOM library,
within the WHEN-NEW-FORM-INSTANCE event code section, code is written to take this global variable and
perform this simulation

The system message level is adjusted to keep the form from failing if the global variable is not found. When the
Customer Account form is opened from the menu, the global variable will not exist, the form_success attribute will be
false, the message level will be reset to its previous condition, and the form will open without any of the Find fields
populated. However, if the form is opened from the Zoom, the Find fields will be populated with the Customer Name
from the Customer form. The user can then simply press the Find button and retrieve the Account records for the
current customer.

IF (form_name = 'ARXCWMAI') THEN

l_msg_level := name_in('system.message_level');
copy('25','system.message_level');
item_name := name_in('GLOBAL.XOTC_CUSTOMER_NAME');

IF (form_success) THEN
copy(name_in('GLOBAL.XOTC_CUSTOMER_NAME'),'VAMAI_QF.CUSTOMER_NAME_LOW');
copy(name_in('GLOBAL.XOTC_CUSTOMER_NAME'),'VAMAI_QF.CUSTOMER_NAME_HIGH');
copy('ALL','VAMAI_QF.CUSTOMER_STATUS');
END IF;

copy(l_msg_level,'system.message_level');
copy('','GLOBAL.XOTC_CUSTOMER_NAME');

END IF;

Add Context Tip to Zoom Button

When there is only a single zoom, the only way the user can know what form the Zoom opens is by executing the
Zoom (or by experience). To add a context tip to the Zoom button, the following code can be added to the WHEN-
NEW-BLOCK-INSTANCE event code.

IF block_name = '<block name>' then


set_menu_item_property('VIEW.ZOOM',label,'<preferred label>');
END IF;

Change the Values in an LOV


The multiple ZOOM procedure is dependent on creating a record group and linking it to the appropriate LOV. This
could be done, as needed, with any LOV on any given form, providing the user has access to the source code of the
form to determine what values are expected by the LOV. Examine the mapped values, and create a record group
returning the same datatypes. Then set the record group property on the LOV to the new record group.

One example of where we have used this functionality, is on the Customer Class LOV on the Standard Customer form.
There is a seeded value in AR Lookups which is useless for our situation. This value, however, cannot be disabled
within the application. Therefore, to work around this limitation, I have used the code below to change the record
group and omit the seeded code.

/*
****** Change Customer Class LOV ******
*/
DECLARE
rg_name VARCHAR2(40) := 'Class_RG';
rg_id RecordGroup;
errcode NUMBER;
BEGIN
/*
* Make sure the record group does not already exist.
*/
rg_id := Find_Group(rg_name);
/*
* If it does not exist, create it and add the two necessary columns to it.
*/
IF Id_Null(rg_id) THEN
/*
* Populate group with a query.
*/
rg_id := Create_Group_From_Query( rg_name,
'SELECT LOOKUP_CODE, MEANING FROM AR_LOOKUPS ' ||
' WHERE LOOKUP_TYPE = ''CUSTOMER CLASS'''||
' AND LOOKUP_CODE <> ''PUBLIC SECTOR COMPANIES'''||
' AND ENABLED_FLAG = ''Y''');
/*
* Populate the record group
*/
errcode := Populate_Group( rg_id );

set_lov_property('CUST_CLASS',GROUP_NAME,rg_name);

END IF;
END;

I must include a warning, though. After an upgrade, or even a patch, the functionality, or even the existence, of a
form's LOV could change. Making this type of modification, even though possible, should be weighed against the
possibility of changes taking place within the application as time goes on.

Unwanted Tabs
In some cases, unwanted tabs can be removed by excluding functions from a responsibility. When this is not an
option, the tabs may be controlled by setting tab page properties. But sometimes additional precautions must be taken,
as these properties may not function entirely as expected. The first thing to do is to set the VISIBLE and ENABLED
properties of the undesired tab page to false. Be sure, however, to check the navigation between remaining tabs. If the
fields on the ‘disabled’ tab page appear upon tab navigation from a previous tab page, it may be necessary to control
the navigation by setting a NEXT_NAVIGATION_ITEM property on the last item of the visible tab page.

In the example below, the Order Management tab is unwanted in the Standard Customer form. The Visible and
Enabled properties of the Order Management tab page are set to False. However, if these are the only changes made,
when the user tabs out of the last field on the visible Classification tab page, the next block of fields which become
visible are still the fields on the Order Management tab page. To keep this from happening, this code has set the Next
Navigation Item for the last field on the Classification block to the Customer flexfield item.

For the record, the control of navigation is not always this simple. Often there is code within the form module which
overrides the navigation written into the CUSTOM library.

/*
* Remove unused tab: Order Management
* Simply removing tabs did not prevent tabbing to fields on the tab canvas;
* therefore navigation from Classification is forced to the Customer Flex Field
*/
SET_TAB_PAGE_PROPERTY('ORDER_MANAGEMENT',VISIBLE,PROPERTY_FALSE);
SET_TAB_PAGE_PROPERTY('ORDER_MANAGEMENT',ENABLED,PROPERTY_FALSE);

SET_ITEM_PROPERTY('CUST.CUSTOMER_CATEGORY_MEANING_MIR',
NEXT_NAVIGATION_ITEM,'CUST.DESC_FF_MIR');

Change a Default Where Clause


One can easily change the default where clause of a block. It is simply a matter of setting the appropriate block
property to the desired SQL string. However, one should be aware that, if a new version of the form has a where
clause defined within the form, this CUSTOM library code will not take effect.

In the following example, the purpose of changing the Where Clause is to filter the address records of AR Customers
by Site Use Code. First, I changed the record group populating the Zoom LOV in the Customer folder block. Then,
once a selection is made from it by the user, the selection is used to filter the customer’s addresses. The code below
shows only the change to the where clause of the block.

SET_BLOCK_PROPERTY('ADDR',DEFAULT_WHERE,
'WHERE customer_id = :CUST.customer_id '||
' and address_id in '||
' (select address_id from AR_SITE_USES_V '||
' where customer_id = :CUST.customer_id ' ||
' and SITE_USE_CODE = :PARAMETER.APPCORE_ZOOM_VALUE)');

I also put an appropriate label on the block to remind the user that the records are filtered. The procedure,
xotc_tr_pkg.find_business_meaning, takes the selected value, queries AR Lookups for its meaning, and returns the
meaning back to the CUSTOM library to be used in the prompt.

SET_ITEM_PROPERTY('ADDR.CONCATENATED_ADDRESS',PROMPT_TEXT,
'Address << filtered by Business Purpose: '||
xotc_tr_pkg.find_business_meaning(name_in('PARAMETER.APPCORE_ZOOM_VALUE'))||
' >>');

Instance Site Name On Window Title

The procedures required to customize the title bar to display the instance name have been documented for other
versions, but there are a few slight modifications required for 11i. I have found the following code to work.

ELSIF (event_name = 'WHEN-NEW-BLOCK-INSTANCE ') then


/*
* Display instance site name on window title in application
*/
DECLARE
lv_item_id item := find_item(name_in('system.cursor_item'));
lv_canvas_name VARCHAR2(50):= get_item_property(lv_item_id,item_canvas);
lv_app_title VARCHAR2(100);
lv_win_title VARCHAR2(100);
lv_event_window VARCHAR2(50);
lv_site_name VARCHAR2(100);
lv_site_length NUMBER;
lv_title_length NUMBER;
BEGIN
IF not id_null(lv_item_id) THEN
IF lv_canvas_name IS NOT NULL THEN
lv_event_window := get_view_property(lv_canvas_name,window_name);
IF lv_event_window != 'ROOT_WINDOW' THEN
lv_win_title := get_window_property(lv_event_window,TITLE);
END IF;
END IF;
END IF;
IF fnd_profile.defined('SITENAME')=TRUE THEN
fnd_profile.get('SITENAME',lv_site_name);
lv_app_title := '<'||lv_site_name||'>';
lv_site_length := length(lv_app_title);
lv_title_length := length(lv_win_title);
/**
*** Add code to control appended titles ***
**/
END IF;
END;

If the site name is not displayed, check the profile setting: Site Name. I also found that, when navigating from block
to block in the same form, sometimes the same form title would be repeated. To prevent this, there is code included in
the indicated position which compares the text in the last window title to the current block title before setting the
window property.

/*
* Compare the last segment appended to the window title to the current form title.
* Only set the window property is the form title has changed.
*/
IF substr(lv_win_title,lv_title_length + 1 - lv_site_length) <> lv_app_title THEN
set_window_property(lv_event_window,TITLE,lv_win_title||' '||lv_app_title);
END IF;

Validation
A very powerful way to use the CUSTOM library is for validation. In the example below, we are ensuring that the
taxpayer id is entered according to the standard format of a social security number. If the entry cannot be validated,
data entry is halted until the entry is corrected. A separate stored procedure, validate_ssn, actually does all this
validation. The example code in the CUSTOM library simply calls this procedure, and receives values to be used to
complete the process, halting the form if the value is invalid, giving the user a warning, and returning the cursor to the
taxpayer id for correction.

ELSIF (event_name = 'WHEN-VALIDATE-RECORD') then

DECLARE
vValue varchar2(250);
vValid boolean;

BEGIN

vValue := name_in('CUST.TAXPAYER_ID');
validate_ssn(p_cust_account_id => name_in('CUST.CUSTOMER_ID'),
p_current_id => vValue, l_valid => vValid);
/*
* If the validation procedure determines the taxpayer id is invalid, inform the
* user and stop the form from saving the record
*/
IF not(vValid) then
fnd_message.set_string('Enter the social security as NNN-NN-NNNN.');
fnd_message.show;
Bell;
RAISE Form_Trigger_Failure;
ELSE
copy('Validated ' || vValue,'CUST.ATTRIBUTE20');
END IF;
END;

To limit execution of this code to cases where the taxpayer id has been updated, after the value is accepted as valid,
text is inserted into an unused attribute field. This way the code, before being performed again, can check to see if the
id has actually changed since it was last validated. This technique may be commonly required for validation
procedures, especially since the WHEN-VALIDATE-RECORD trigger could be executed multiple times during a
commit, depending on the activity taking place within the form.

Call a Work Flow procedure

One of the most powerful tools an Oracle Applications developer has for enforcing business rules is Work Flow. Why
not develop a Work Flow process, and call it from the CUSTOM library? The example below describes how to this.

DECLARE
l_itemtype varchar2(10):= 'TAXIDLOG';
l_customer_id number := to_number(name_in('CUST.CUSTOMER_ID'));
l_customer_name varchar2(50):= name_in('CUST.CUSTOMER_NAME');
l_taxpayer_id varchar2(20):= name_in('CUST.TAXPAYER_ID');
l_taxpayer_id_type varchar2(4) := RTRIM(name_in('CUST.ATTRIBUTE1'));

BEGIN

XOTC_TAXIDLOG_WF.taxidlog_wf( l_itemtype ,
l_customer_id ,
l_customer_name,
l_taxpayer_id,
l_taxpayer_id_type);
END;
Application users need varying levels of access to the employee information defined within the US HRMS Manager
Responsibility. Some users only need to view the form while others need to be able change the information in the
form. Within the System Administrator Responsibility it is possible to grant access to a form as view-only or as full
access. It is not possible to make only specific fields viewable or changeable. To give a user the ability to perform
limited tasks it was necessary to define a custom form with a new Task Flow that would limit the forms the user could
access, and to use Custom Library to make fields within the form secure. The same functionality was required to create
a system of checks and balances for applications administrators. These checks and balances ensured that proper
procedures and approvals were always followed, and enabled better auditing of the system.

The IT Department's system administrators are responsible for setting up a new employees or contractor's access to the
company's information systems. To do this, the system administrators must be able to enter each employee's email
address once it has been assigned by our email administrators, link the employee's record to a user name, and grant the
employee access to Oracle Applications. The email address is entered on the PEOPLE form from the US HRMS
Manager menu. Grants and linking of the user name are entered on the USERS form from the System Administration
menu.

Creating Custom Forms


Under the US HRMS Manager Responsibility, one of the security options available is to create a custom form. This
allows the user to specify which form they are going to customize. In Oracle HR/Payroll the following forms can be
customized:

The first step in creating a custom form is to identify the form being customized and to give it a new name. This is
done by navigating to the Security menu under US HRMS Manager Responsibility and selecting the Custom Form. A
screen similar to the one displayed in Figure 1 will appear. Select the name of the form to be customized from the
drop-down list, and then enter the new name that you want for the custom form. The standard title and query title
appear on the form in the application. In the bottom block of the form you can choose to restrict its view. You can
restrict viewing by Person Function or by person Type, as shown below:
Figure 1
Each HRMS form has an associated Task Flow. Each delivered form has other forms that can be accessed from it. For
example, the delivered PEOPLE: ENTER AND MAINTAIN form opens on the PEOPLE form. From that form the
user can navigate to the ADDRESS form, the ASSIGNMENT form, or other forms using buttons. This sequence of
forms the user can access is called a Task Flow. For each customizable form, users can access a predetermined set of
nodes. For most custom forms, define a new node for the opening form with a custom name, and then define the
delivered nodes on that form you want to limit user access to.
For example, you must create a custom node for the PEOPLE form to define the starting point for the Task Flow. To
define this new node, navigate to the Task Flow option under the Security menu of the US HRMS Manager
Responsibility.
Figure 2
The table below displays all information in Figure 2 above. Name refers to the name of the custom node. The Form
name is selected from a list of values and defines the form the node refers to.

Once the custom starting node has been defined, the Task Flow can be defined. This step links all of the nodes that can
be accessed through this new custom form. In the example above, only one node will be accessed because the user
needs access only to the PEOPLE form.

To define the Task Flow, access the Task Flow Definition option under the Security menu in the SHRMS Manager
responsibility. A screen as shown in Figure 3 will appear. Each node that can be accessed by the Task Flow is defined
in the Node Block of this form. To add another node, arrow down while your cursor is in the Node Name field. Select
the name of the node from the list of values. For each Task Flow, there is only one Top Node, indicated by the check
box on the form. To select a node in the navigation options for a Task Flow, the node must be defined and saved in the
node block.
Figure 3
In the previous example, there was only one node because navigation was limited to the PEOPLE form. In this case,
there are no navigation options defined. If you want to define a more complex Task Flow with access to multiple
forms, the DEFINE TASK FLOW form might look something like Figure 4.

For the workflow above, four are nodes defined. The TEMPS node is a custom node based on the PEOPLE form.
From the TEMPS node, you can navigate to the ASSIGNMENT, ADDRESS, and TERMINATE nodes. All four of
these nodes have been defined in the node Block of the above form. If you were to put your cursor on the node Name
field and arrow down, you would see definitions of each node in the navigation options block. None of the other nodes
have navigation options. Once the Task Flow is defined, you must design a custom function to access it. To define a
custom function, change to the System Administrator Responsibility. Navigate to the Function option under the
Application menu. A form like Figure 5 will appear.

Figure 5
The Function is the name you will assign to the menu to place this within a responsibility. The name must be unique.
The User Function Name is selected from a list of values and is the name of the Task Once the CUSTOM.pll is
compiled and the responsibilities are defined, you can assign the responsibilities to users. For example, The CSI
Sysadmin Responsibility looks like this:

Figure 10

The PEOPLE form under that responsibility looks like this:

We used a spreadsheet to gather information about what access was required for the various user responsibilities. The
spreadsheet listed names of the forms the users wanted to control and the names of the fields on each form. For each
field, the users specified the responsibilities they wanted us to create: ‘view-only,’ ‘updateable,’ or ‘hidden.’ We used
this information to modify the CUSTOM.pll and the custom forms.
Some lessons learned:
Make sure the CUSTOM.pll that is being changed is on the forms server for your installation.
You cannot set the properties of flex fields using custom library.
You must use ‘else null’ as the last condition in the CUSTOM.pll logic. Otherwise, your users will get lots of error
messages.
 Use an ASCII editor with search and replace capabilities to type the code for the CUSTOM.pll and copy and paste it
into the FORMS interface.
Appendix B . Output of the applcust.txt file
About to Display customized files changed by patch: Wed Jan 30 2002 14:24:42
Reading customized files list (if any)...
**
** This patch will replace the following customized files
** if you run it without ‘Apply=No’:
**
** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following files are registered as customized by extension,
and the source files will be replaced by this patch. After this patch
has been applied, the source files will contain the changes required
for this bug fix. However, your customized copies (target files)
will not contain the changes required for this bug fix.
You may need to merge the fixes to these files into your customized copies.
Product Subdirectory / Library File Name
------- ------------------------------ ---------
Source: gl reports/US GLRTR1.rdf
Target: bvpgl reports BVPGLTBD.rdf
Source: pa forms/US PAXINRVW.fmb
Target: pa forms/US BVPPAINRVW.fmb
Source: ar reports/US ARXAGM.rdf
Target: bvpar reports BVPARAGM.rdf
Source: pa forms/US PAXINEVT.fmb
Target: pa forms/US BVPINEVT.fmb
Source: ar reports/US ARXCOA2.rdf
Target: bvpar reports BVPARCOA2.rdf
Source: pa patch/115/import/US pa115v.ldt
Target: bvppa sql bvppa_expend_items_adjust2_v.sql
Source: pa forms/US PAXTRAPE.fmb
Target: pa forms/US BVPPATRAPE.fmb
Source: ar reports/US ARXSGPO.rdf
Target: bvpar reports BVPARSG.rdf
Source: pa patch/115/import/US PAAPWEBX.wft
Target: bvppa workflow bvppa_expense_report_account_generator.wft
** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Done Displaying customized files changed by patch: Wed Jan 30 2002 14:24:43
When entering a Return we can make sure that an Invoice number is not selected in the Lines
section, as we don't want RMA's credited to a specific invoice for an order.

Use the following code in the 'WHEN-VALIDATE-RECORD' event in the custom library:

if (form_name = 'OEXOEMOE') then


if (block_name = 'RMA_LINES') then
copy('','RMA_LINES.CREDIT_TO_INVOICE');
end if;
end if;

This should blank out the invoice number that someone has mistakenly entered here. I also tried
putting this in.

if (form_name = 'OEXOEMOE') then


if (block_name = 'RMA_LINES') then
fnd_message.set_string ('Invoice');
fnd_message.show;
RAISE form_trigger_failure;
end if;
end if;
Upgrading Custom Forms to Release 11i

This section covers upgrading custom forms built with Oracle Forms 4.5, the Oracle Applications
coding standards, and Oracle Application Object Library. It applies to custom forms built to
integrate with Releases 10SC, 10.7 NCA, and 11.

Upgrading your custom forms to Release 11i consists of the following


basic steps:

1. On your developer client machine convert your Oracle Forms 4.5 forms to Oracle Forms 6i
using the Oracle Forms 6i Form Generator and make any required changes related to converting to
PL/SQL 8

If you have any library files which you attached to your form you must first convert the library
files prior to attempting to upgrade your form module. To convert your 4.5 form to a 6i form load
a copy of your 4.5 form into 6i form builder and save 'only', DO NOT re-compile it. By loading
the library or form module the developer will perform a number of steps to prepare the files for the
new developer environment once successfully saved you may proceed the the next steps outlined
below.

2. Move the newly converted 6i form to the Forms server in the $AU_TOP/forms/US
directory. Use the Oracle Applications upgrade utility (flint60) on the Oracle Forms 6i .fmb file to
apply changes that help your form conform to Release 11i standards.

Release 11i of applications provides an upgrade utility called flint60 which performs a number
changes to custom forms previously developed for Oracle Applications 10.7SC/NCA and 11.0.x.
The changes include 11i enhancements and applications coding standards verification. The utility
may be run multiple times against the custom developed form during the development process.

**** This utility is only for the form module. There


**** is no such utility provide nor needed for custom
**** developed library files.

NOTE: Flint60 is a 32 bit utility that runs on your forms server tier (i.e. it will not run on any
machine that is not certified as a forms server like ... Windows95 or Windows 3.11 )

To successfully run the flint60 utility, the flint60.ora file must be created and contain proper
values.

Setting Up the Configuration File

The flint60 utility requires a configuration file, flint60.ora, to hold the database username and
password and other information. The flint60.ora file is a simple text file that should have the
following information:
server_host=your_web_server_name
message_file=location_of_the_message_help_file_on_web_server
connect=[y|n]
userid=database_username_and_password

The web server host name that will be used to access the .html log files the virtual path and
filename of the message descriptions file, fnderr.html boolean that indicates whether to verify
blocks against the database if database=y, then this is the ORACLE username and password to use
to connect to the database.

Note that when attempting to connect to the database, flint60 uses the table
ACCESSIBLE_COLUMNS (actually a public synonym for SYS.ALL_TAB_COLUMNS) to
determine the constraints (data type, length, null allowed) for a database item’s column. If
ACCESSIBLE_COLUMNS is inaccessible, flint60 will generate multiple fatal errors in the log
file (if the option to connect to the
database is selected).

Example:

server_host=www-apps.us.oracle.com
message_file=/r115/fnderr.html
connect=y
userid=apps/apps@devdb

You must set an environment variable, FLINT60_CONFIG (for Unix) that points to the flint60.ora
configuration file. If the FLINT60_CONFIG environment variable is not set then flint60 will
search for the file flint60.ora in the current directory. If you see the message ?LRM-00109: could
not open parameter file ?<file>? ? when you try to
run flint60, then the configuration file could not be loaded. If you run the flint60 utility without the
configuration file, the .html log file will not be able to provide context-sensitive links to the help
file that describes each of the messages generated by flint60, and the utility may be unable to
connect to the database (which would create additional
errors in the log file).

Verify Your Environment

It is important to verify that you are pointing to the correct versions of Oracle Forms and Oracle
Applications before running the upgrade utility, or you may get spurious or misleading error
messages. For example, your environment must point to the correct versions of APPSTAND.fmb
and APPCORE.pll. Ensure that the environment is
configured properly and is pointing to an Oracle Forms 6i environment. Verify that the
FORMS60_PATH (Unix environment variable, or NT registry setting) points to the directories that
hold the correct versions of APPSTAND.fmb and APPCORE.pll.

Ensure the DISPLAY environment variable is set and valid (for Unix
only).
To run flint60 utility the command line execution would look like the following:

Command line switches

The flint60 utility can accept one, two, or no switches on the command line, as shown:

flint60 -u <module1>.fmb <module2>.fmb ...


flint60 -uc <module1>.fmb <module2>.fmb ...
flint60 <module1>.fmb <module2>.fmb ...

-u Parameter: This is the ?upgrade? mode. Include the –u (?upgrade?) switch if you want the
flint60 utility to write a new .fmb file with any required changes.

-c Parameter: Include the -c switch if you want the flint60 utility to not clear out hint text. Use the -
c switch when you are running flint60 again after the initial upgrade and you have added hint text
that you do not want the utility to clear out (of the new file
written by the utility because of the -u switch). If you have not added hint text manually, you do
not need to use this switch. The -c switch is ignored if the -u switch is not present.

If no values or switches are passed to the flint60 utility then this is the ?standards compliance
checker? mode. If you do not use the -u switch, the flint60 utility
simply performs various checks on your form and writes out a log file listing any standards
compliance errors or warnings.

Form name arguments


The flint60 utility expects form names on the command line:
flint60 -uc <module1>.fmb <module2>.fmb ...

The filenames can be fully qualified with paths and/or environment variables (for Unix):

flint60 $fnd/forms/US/<module1>.fmb
/custgldev/custgl/11.5/forms/US/<module2>.fmb ...

To run flint60 for all forms in the current directory (if using an appropriate Unix shell that expands
file wildcards, such as tcsh):

flint60 *.fmb

To run flint60 for all forms in a specific directory (if using an appropriate Unix shell that expands
file wildcards, such as tcsh):

flint60 $fnd/forms/US/*.fmb
If you are running the flint60 utility on Windows NT, you may need to create a .bat script to run
multiple commands because NT does not support expanding command line wildcards.

Reviewing flint60 Log File Output

The flint60 utility provides a detailed log file of messages as it goes through your form. The log
file is called form_filename.fmb.html, and you can read it using any standard browser. The utility
provides one log file for each form, located in the current directory.

The message types are:


Status: an informational message
Action: each action taken by the flint60 utility, such as changing a
piece of boilerplate to an associated prompt

3. Correct any errors found by the upgrade utility, and run the utility
again to verify your changes

When utilizing the forms upgrade utility an HTML output file is created
which provides detail of the changes made to the form module. Additionally,
the output file provides warning and suggested changes that should be
considered for custom form development which if followed will ensure
custom form is 11i Oracle look and feel.

4. Perform any required manual changes that may be necessary, such


as changes to internal menu names

Performing Required Manual Changes on Your Forms

Menu calls

If you have hardcoded calls in your form that modify the default (pulldown) menu, such as calls
that enable or disable menu entries, you may need to modify your menu calls because the internal
names of the menu names have changed to be consistent with the rearranged menu.

You can typically find these calls by using the ?Find and Replace PL/SQL? feature in the Oracle
Forms 6i Form Builder (under the Program menu choice) to search for the following strings (do
not search as case sensitive):

SET_MENU_ITEM_PROPERTY
GET_MENU_ITEM_PROPERTY
FIND_MENU_ITEM
APP_SPECIAL.ENABLE

These calls must be evaluated and changed if necessary.


Toolbar block calls

If you have code in your form that calls anything in the pre-11i toolbar, such as calls to enable or
disable toolbar buttons, you must modify your code. Behind the scenes, the toolbar has been re-
implemented to not use a distinct TOOLBAR block. It is now part of the menu, and toolbar icons
are now enabled and disabled automatically when you programmatically enable or disable menu
entries using the APP_SPECIAL routines.

APP_SPECIAL: Menu and Toolbar Control

You can typically find these calls by using the ?Find and Replace PL/SQL? feature in the Oracle
Forms 6i Form Builder (under the Program menu choice) to search for the string (including the
single quote and the period):

TOOLBAR.

Note that the TOOLBAR canvas has not been removed, because it serves as a holding area for
certain Oracle Applications fields (such as switcher fields).

5. Perform optional manual changes, such as converting alternative regions to tabbed regions and
enhancing special menus, as desired

6. Use the Oracle Forms 6i generator to generate the .fmx file for your upgraded form

Ctrl-T will compile and generate your form. Should first be performed on you development
environment to ensure that all the code compiles and has been resolved prior to loading the form
into the production environment.

7. Test your upgraded form within Oracle Applications 11i To test your form you will need to run
the form within the applications environment only. It is possible to run the form stand alone using
the forms server and the static login html file whereas the following line in the html file would
initially look like:

serverArgs="module=Q:\oa\appltst\fnd\11.0.28\forms\US\FNDSCSGN
userid=applsyspub/pub@VD11 fndnam=apps"

serverArgs="module=Q:\oa\appltst\fnd\11.0.28\forms\US\FNDSCSGN
userid=apps/apps@VD11"

Note: While it is technically possible to skip the first step and go directly to the Oracle
Applications upgrade utility step, we recommend that you do the first step separately to better
isolate the changes to your form should there be any problem with either upgrade step.
• .Flexfield. is assumed to reference descriptive flexfields, not key flexfields.
• .Form. is an application screen.
• .Flexfield window. is the flexfield pop-up window in the form.
• .Segment. is one field within a flexfield window (excluding the context field).
• .Structure. is the combination of all flexfield segments appearing in the flexfield window,
including global and context sensitive segments.

The below SQL served as basis for this report and may be helpful to your installation in
maintaining descriptive flexfields:

SELECT substr(d.application_short_name,1,3) app,


substr(a.title,1,23) desc_title,
substr(a.application_table_name,1,23) tbl,
substr(b.descriptive_flex_context_code,1,18) desc_context,
substr(c.end_user_column_name,1,23) seg_name,
substr(c.application_column_name,1,28) col,
substr(b.global_flag,1,2) gbl
FROM FND_DESCRIPTIVE_FLEXS a,
FND_DESCR_FLEX_CONTEXTS b,
FND_DESCR_FLEX_COLUMN_USAGES c,
FND_APPLICATION d

Value Sets
Value set definition is the most important step in descriptive flexfield set-up. Value sets
provide the primary mechanism to validate and restrict data entered by users. Value sets are used by key
flexfields, descriptive flexfields, and report parameters. The same value set may be used by more than one
segment or report parameter. Value sets may be defined by clicking the .Value Set. button or navigating to
the Value Sets form (Setup/Financials/Flexfields/Validation/Sets).

Oracle offers several seeded value sets. You may use seeded value sets for your flexfield segments but do
not change the definition of an Oracle seeded value set since it may already be used by Standard Report
Submission or another flexfield. If a custom value set is needed, name your value set with a common
identifier. At CRL, all custom value set names were preceded with .CRL_.. In addition, extended
flexfield functionality provides the ability to reference previously user-entered flexfield values by keying
on the value set name used in the previous flexfield. Do not include spaces, quotes, special characters, or
the string .$FLEX$. as part of the value set name. It is recommended that a consistent case be used across all custom
defined value sets. CRL used all uppercase characters.

Oracle offers many configurable features when defining a value set:

.Security Available. is checked if Flexfield Value Security rules have been defined and want to be
used. Flexfield Value Security will not be addressed in this paper.
.Enable Longlist. requires the user to enter a partial segment value before the entire list of available
values is displayed. Enable Longlist may not be enabled for a value set with validation of .None..
.Format type. relates to the data type of the entered segment value (e.g. character, number, date, or
time). If table validation is used, the format type relates to the .Value. column of the table definition,
not .Hidden ID. if one is used. Table validation will be discussed later in this document.
.Maximum Size. is the maximum character size (length) of the entered data. Do not select a size
greater than the underlying attribute column (usually 150 or 240 characters). If using table validation,
the maximum size should reflect the size of the .Value. column. Also consider the display size of the
flexfield segment field. If the value set maximum size is greater than the flexfield display field, users
may have to scroll through flexfield field to see entire value. This may slow data entry. In addition, if
the maximum size of the value set is greater than the segment display size, an cautionary message will
appear when saving your flexfield segment definition. Click .ok..
For numeric format types, .Precision. relates to how many places should appear after the decimal
point.
.Numbers only. is just that -- users can enter only 0-9, minus signs, and periods. If you want to restrict
users from entering a negative sign for a value set where you do not allow alphabetic characters, you
should enter zero (0) as the value set.s minimum value.
.Uppercase Only. is used for character format type and enforces a uniform character case.
.Right-justify and Zero-fill. affects values that include the characters 0-9, regardless of whether you
select the .Numbers Only. option. This option is usually used to ensure character values that appear to
be numbers will be sorted and appear in the correct order as if they were actually number values. Most
often this feature is used for the key Accounting Flexfield segments so the length of the entire
Accounting Flexfield is the same across all combinations.
.Min. and .Max. values can be used for numbers (e.g. 0-100), dates (e.g. 01-JAN-2001, 31-DEC-
2001), or characters. If min and max values are used for Character formatted value sets, most
platforms will use ASCII to determine character order (numbers are less than alpha.s) but some
platforms will use EBCDIC where numbers are greater than alpha.s. Both fields can be left blank and
take the minimum and maximum value for the particular value set. For example, if the value set
maximum size is 3 (Numbers only), the implicit minimum value is -999 and the implicit maximum
value is 999.
.Validation Type. specifies how entered values will be validated. Oracle offers six validation types:

1. None
2. Independent
3. Dependent
4. Special
5. Pair
6. Table

Oracle prevents the validation type from being changed from .None to Independent. and .None to
Table.. However, Oracle does allow validation type changes from .Independent to None., .Table to
None., and .Dependent to None..

In general, do not change a descriptive flexfield definition. You run the risk of creating inconsistencies
with existing attribute column data and users may receive error messages when querying records in a
particular form. However, changing business needs may require a change to a flexfield, specifically
the underlying value set. You can define a new value set, with a new validation type, and attach this
new value set to an existing flexfield segment. Keep in mind this can still present problems if existing
data does not pass the new validation.

Table validation creates a .select. statement whose result set becomes the list-of-values quickpick for a
flexfield segment. The .select. statement can be used to query data that is already maintained within your
Oracle Applications (e.g. order numbers, transaction type names, item names, etc.). You can select from
more than one Application table but use aliases in the Table Name field and aliases with the columns you
select, constrain by, or order by. If multiple Application tables are used, leave the Table Application field
blank since it will effectively be ignored. You may also use database views or synonyms instead of
database tables.

The constructed .select. statement can also query against custom tables. It is not a requirement to register a custom
table with the Application Object Library but an available columns quickpick will not be provided
and data types will not default in. To register a table in the 11.0.3 environment, use the following standard
Oracle packages to register a custom table and its related columns.

ad_dd.register_table
ad_dd.register_column

If the custom table is not created under the APPS schema, create a synonym with the same name as the
custom table in the APPS schema and grant SELECT privileges to the APPS schema.

Table validation functionality can be extended through the use of bind variables. Bind variables introduce a
dynamic element to the .select. statement. Similar to the .Reference. field, bind variables evaluate a piece
of data at the time the query is executed. Three types of bind variables are commonly used:

1. :$FLEX$.Value_Set_Name: Use this bind variable to reference a value that has already been entered
within the same flexfield window. Value_Set_Name first refers to the name of the value set
supporting the prior segment or, if not found, then refers to the name of the prior segment. Proper
value set and segment naming becomes important (no spaces, same case, etc.).

When :$FLEX$.Value_Set_Name is used, Oracle will by default use the ID value (not the .Value. or
.Meaning. values) of the referenced value set. If the referenced ID field is blank, Oracle will next use
the .Value. column of the referenced value set. For clarity, it is recommended that you explicitly state
which data element you wish to evaluate -- the .Value., .Meaning., or .ID.. Append the appropriate
.Output. value to :$FLEX$.Value_Set_Name where Output can be .VALUE., .DESCRIPTION.
(used for the .Meaning. field), or .ID.. Refer to the above screen-shot for an example.

2. :$PROFILES$.Option_Name: Use this bind variable to reference a user profile option value. User
profile options are assigned values in the System Administration responsibility.

3. :block.field: Use this bind variable in the same way as discussed for the .Reference. field. The same
:block.field must exist in every form where this value set is used for a flexfield segment. Keep in mind
that when upgrading, the :block.field reference may become invalid with a newer form version.

All three bind variables can be used in the .Meaning., .Where/Order By., and .Additional Columns. fields
of the Validation Table Information form. Bind variables cannot be used in the .Value. or .Hidden ID.
fields. Additionally, do not use Security Rules when using bind variables. Security rules will ignore the
bind variable values and therefore may give your end-users unintended results.

Other comments regarding the Validation Table Information fields:

.Meaning.: The description of the .Value. field. .Meaning. is shown in the flexfield window.
.Hidden ID.: If used, the hidden id value will be passed to the database attribute column, not the
.Value. column.
.Additional Columns.: You can provide more information in the list-of-values quickpick by
specifying additional columns to select. Type the database column name with an alias name if desired.
The alias name is used as the column heading in the list-of-values quickpick. Also add the column
width of the additional column. Use an asterisk .(*). to allow Oracle to automatically determine the
display width based on the maximum width of existing values. You can specify multiple additional
columns by separating each column name with a comma. Refer to the above screen shot for an
example
.Where/Order by.: Use the word .WHERE. as first word for the .where. clause. Similarly, use the
phrase .ORDER BY. as the first words for the .order by. clause.

Custom Validation
Validation and security are integral parts of any well-built application. As discussed, Oracle provides a
number of methods to control what and how data is entered through descriptive flexfields.

Value Set Definition Flexfield Definition


Format type Context required
Maximum size Default value
Uppercase only Override allowed
Right justify, zero-fill Reference field
Min/Max values Segment value required/displayed
Validation type Segment default value

Not all of s validation requirements were met by the above methods. As a result, CRL implemented a
custom validation routine using a trigger placed on the ship confirm table wsh_deliveries. When a user
attempted to ship confirm a shipment, PL/SQL blocks were executed to perform additional validation on
the committed attribute, or flexfield, columns. The pre-commit trigger provided procedural logic that
otherwise is not available by Oracle.s standard validation methods. If validation failed, the Oracle package
RAISE_APPLICATION_ERROR was called, sending an error message to the form, and interrupting the
ship confirm commit. In addition to added validation, the wsh_deliveries trigger also inserted the slip id
information into a custom kit track table.

You might also like