You are on page 1of 119

MỤC LỤC

MỤC LỤC................................................................................................................1
Kiến trúc ứng dụng .................................................................................................4
Tổng quan về kiến trúc ứng dụng. .................................................................................. 4
Mô hình phát triển và triển khai Oracle Application. ..................................................... 7
Các chuẩn cho việc Customize ứng dụng .............................................................8
Tổng quan về việc customize Oracle Applications......................................................... 8
Customization theo cách mở rộng. ................................................................................. 9
Customize theo cách mở rộng ......................................................................................... 9
Customize bằng cách chỉnh sửa .................................................................................... 11
Customize cơ sở dữ liệu Oracle Applications............................................................... 12
Nâng cấp và chỉnh sửa Oracle Applications ................................................................. 12
Tích hợp Custom Objects và Schemas ......................................................................... 12
Nâng cấp các form được customize lên Release 11i .................................................... 12
Tổng quan về Coding Standard trong ứng dụng ...............................................13
Theo dõi các thay đổi về dữ liệu với Record History ( WHO ) .................................... 13
Các ràng buộc khai báo ( declarative constraint ) : ....................................................... 15
View : ............................................................................................................................ 16
Sequence : ..................................................................................................................... 16
API đăng kí bảng : ........................................................................................................ 16
Tổng quan về việc sử dụng PL/SQL trong các ứng dụng : ........................................... 17
Thuật ngữ : .................................................................................................................... 17
Các chuẩn chung trong lập trình PL/SQL : ................................................................... 18
Định dạng mã PL/SQL : ............................................................................................... 19
Xử lý lỗi : ...................................................................................................................... 20
Một vài hướng dẫn khi coding SQL : ........................................................................... 21
Các trigger trong form : ................................................................................................ 22
Những sự thay thế cho các built-in trong Oracle Forms ............................................... 22
Lập trình các handler cho item, event và table : ........................................................... 23
Lập trình các handler cho item : ................................................................................... 24
Lập trình các handler cho event : .................................................................................. 25
Lập trình các handler cho table : ................................................................................... 25
Form TEMPLATE ................................................................................................40
Giới thiệu về form TEMPLATE : ................................................................................. 40
Các thư viện trong form TEMPLATE .......................................................................... 40
Các trigger trong form TEMPLATE............................................................................. 42
Thiết lập các thuộc tính của các đối tượng chứa(ContainerObject) ................49
Các đối tượng chứa : ..................................................................................................... 49
Module : ........................................................................................................................ 49
Window :....................................................................................................................... 49
Canvas : ......................................................................................................................... 51

1
Block : ........................................................................................................................... 51
Region : ......................................................................................................................... 54
Thiết lập các thuộc tính của các đối tượng Widget ...........................................55
Text Item : ..................................................................................................................... 55
Display Item : ................................................................................................................ 56
Poplist : ......................................................................................................................... 56
Option Group : .............................................................................................................. 56
Check Box :................................................................................................................... 56
Button ( Nút ) : .............................................................................................................. 56
List of Values ( LOV ) .................................................................................................. 57
Thiết lập các thuộc tính cho item : ................................................................................ 57
Một số lưu ý : ................................................................................................................ 60
Điều khiển hoạt động của Window, Block, và Region .......................................61
Điều khiển hoạt động của Window ............................................................................... 61
Lập trình cho các Tabbed Regions................................................................................ 69
Hành động của tabbed region : ..................................................................................... 70
3 mức khó trong lập trình : ........................................................................................... 70
Cho phép hoạt động truy vấn ..............................................................................73
Query Find : .................................................................................................................. 73
Triển khai Row-LOV .................................................................................................... 73
Triển khai Find Window ............................................................................................... 74
Lập trình các hành động cho item .......................................................................78
Mối quan hệ giữa các Item............................................................................................ 78
Item phụ thuộc có điều kiện .......................................................................................... 81
Các item đa phụ thuộc................................................................................................... 82
2 Master Item và 1 Dependent Item .............................................................................. 83
Kiểu phụ thuộc Cascading ............................................................................................ 85
Các item loại trừ lẫn nhau (Mutually Exclusive Items) ................................................ 86
Các item đồng hành với nhau (Mutually Inclusive Items) ............................................ 88
Mutually Inclusive Item liên hệ với Dependent Item ................................................... 89
Các item bắt buộc điều kiện (Conditionally Mandatory Items) .................................... 91
Các mặc định (Defaults) ............................................................................................... 93
Kiểm tra tính toàn vẹn (Integrity Checking) ................................................................. 94
Đối tượng Calendar ....................................................................................................... 97
Các lựa chọn cấp cao của Calendar .............................................................................. 98
Điều khiển Toolbar và Default Menu ...............................................................100
Pulldown Menu và Toolbar ........................................................................................ 100
Các lựa chọn có trên thanh công cụ ( toolbar ) : ......................................................... 101
Các mục chỉ có trong Menu ........................................................................................ 102
Điều khiển menu động ................................................................................................ 103
Tạo các biểu tượng trên toolbar cho các form bạn customize .................................... 104
Các menu đặc biệt ....................................................................................................... 105
Customize các Right–Mouse Menu (Popup Menus) .................................................. 105
Message Dictionary .............................................................................................108
Tổng quan về Message Dictionary ............................................................................. 108
Các điểm đặc trưng của Message Dictionary ............................................................ 108

2
Các bước cần tiến hành khi xác định Message Dictionary ......................................... 109
Thiết lập Message Dictionary ..................................................................................... 109
Phương pháp đối với Database Server–side Messaging. ............................................ 110
USER PROFILE .................................................................................................112
Các mức của User Profile: .......................................................................................... 112
Định nghĩa mới các tùy chọn của user profile ............................................................ 113
Thiết lập giá trị tùy chọn user profile.......................................................................... 113
Thiết lập user profile riêng của bạn ............................................................................ 113
Xác định trước tùy chọn user profile .......................................................................... 113
Profile Window ........................................................................................................... 114
FOLDER ..............................................................................................................116
Tổng quan về Folder. .................................................................................................. 116
Lập trình với Folder trên form ứng dụng. ................................................................... 116

3
Kiến trúc ứng dụng

Tổng quan về kiến trúc ứng dụng.


Kiến trúc ứng dụng của hệ thống Oracle Application theo mô hình tập trung 3 lớp,
đó là các lớp Desktop Client, Middle Tier (Form Server) và Data Base Server. Mọi thao
tác ở Client đều thực hiện dựa trên hệ thống Java nhúng. Dữ liệu nhập liệu được truyền
về Application Server, việc xử lí các chức năng được thực hiện ở Application Server.
Việc thao tác xử lí dữ liệu thực hiện ở Database Server. Kiến trúc tổng thể được mô tả
như hình vẽ dưới đây:

 Desktop Client :
• Giao diện đồ họa, sử dụng trên các Web browser chuẩn có hỗ trợ Java
nhúng chạy Jinitiator.
• Oracle JInitiator là phiên bản Oracle của JavaSoft‟s Java Plug-In, cho
phép xử lý JVM tại Web client thay vì dựa vào JVM default của browser.

4
• Có thể tương thích với mọi PC,network computer hoặc trên bất cứ giao
diện nào có Java.

 Middle Tier (Form Server):


• Xử lý các đáp ứng logic của Form.
• Là nơi lưu giữ các dữ liệu cache cục bộ.
• Trung gian giữa hai tầng.

5
 Database Server:
• Sử dụng các lời hàm từ xa (RPC) để giao tiếp với DB khi cần thiết (có thể
thực hiện nhiều DB action cùng một lúc – các câu lệnh SQL).
• Xử lý thao tác dữ liệu trên ứng dụng.
• Lưu các thủ tục trên DB nên giao tiếp giữa các stored procedure và DB
xảy ra trong bộ nhớ chứ không phải trên mạng.
• Tương thích với DB từ 8i trở lên.

6
Mô hình phát triển và triển khai Oracle Application.

Hiện tại tại trung tâm sử dụng môi trường Window để thiết kế giao diện, dịch Form bằng
Form Server trên hệ điều hành Linux.
Quá trình phát triển form bao gồm ba bước chính là:
• Build
• Generate
• Run/Test
Build Form :
Access to Libraries and Referenced Forms
Thiết lập FORMS60_PATH.
Referenced Objects and the ORACLE_APPLICATIONS V ariable
Generating Your Form : (dịch Form trên Forms Server)
Moving the File fmb
Dịch file : f60gen module=demo.fmb userid=apps/apps
Running Your Form for Testing : test trên môi trường Web chứ không phải trên Form
developer
Sau khi hoàn thành các bước trên chuyển đến Deployment : Nếu đang phát triển và triển
khai trên cùng một platform thì chỉ cần copy file .fmx đến đích còn không phải dịch file
trên platform đích.

7
Các chuẩn cho việc Customize
ứng dụng
Để có thể phát triển ứng dụng trên sản phẩm Oracle Applications bạn phải sử dụng Oracle
Application Object Library cùng với các công cụ khác như Form và Report.
Các chủ đề chính :
 Tổng quan về việc customize Oracle Applications
 Customize theo cách mở rộng
 Customize theo cách chỉnh sửa
 Customize cơ sở dữ liệu Oracle Applications
 Nâng cấp và chỉnh sửa Oracle Applications
 Nâng cấp Custom Forms lên Release 11i
 Upgrade Utility và Standards Compliance Checker: flint60

Tổng quan về việc customize Oracle Applications


Các công việc sau bạn có thể làm để phát triển trên ứng dụng :
 Thay đổi các Form trên ứng dụng :
– Giao diện (appearance)
– Mã kiểm tra (validation logic)
– Hành động (behavior)
 Thay đổi Report hay chương trình :
– Giao diện (appearance)
– Mã (logic)
 Thay đổi cơ sở dữ liệu của ứng dụng :
– Thêm vào các read–only schema
– Thêm mã vào các database trigger
 Biên dịch lại toàn bộ ứng dụng.

8
Customization theo cách mở rộng.
Phát triển các thành phần mới cũng như ứng dụng mới trên nền có sẵn sử dụng
Oracle Application Object Library.
Điều này có thể đơn giản bằng cách copy một thành phần có sẵn tới một thư mục
khác và tiến hành sửa đổi nó.
 Customization theo cách chỉnh sửa
Cách này gọi là thay đổi ngay tại chỗ. Tuy nhiên theo khuyến cáo ta nên
tránh cách làm này vì có thể gặp sự cố khi nâng cấp hoặc khi sửa đổi.
 Các thành phần (Component)
Component có thể là module code (như form, report hoặc SQL script)
hay các đối tượng Oracle Application Object Library (như menus,
responsibilities, messages) hay kể cả đối tượng CSDL(tables,
views, packages, or functions).
Một ứng dụng phát triển phải được đăng ký với Oracle Application Object
Library và phải có thư mục riêng cùng với component của nó.
 Các đối tượng cơ sở dữ liệu
Một table, index, view, sequence, database trigger, package, grant, hoặc
synonym.
 Application Short Name
Là tên tham chiếu của ứng dụng không có dấu cách.
 Application Basepath
Là tên của một biến môi trường được chuyển thành top directory của cây thư mục
của ứng dụng.
Oracle Application Object Library sẽ tìm các đường dẫn tới các thư mục ở mức dưới
để thực hiện các file chạy trong ứng dụng kể cả form file.
 Cấu trúc thư mục của Application
Là sự sắp sếp thứ tự các thư mục trong ứng dụng. Thủ mục của Oracle Applications
được tạo ra khi cài đặt ứng dụng hay khi nâng cấp ứng dụng.
Với các ứng dụng tự tạo bạn phải tạo riêng các thư mục cho nó.
 Các file môi trường (Environment Files) của ứng dụng
Xác định biến môi trường khi cài đặt ứng dụng. Biến môi trường bao gồm
<dbname>.env và adovars.env (đối với UNIX platforms).

Customize theo cách mở rộng


 Định nghĩa ứng dụng được customize của bạn

9
 Tạo cấu trúc thư mục cho ứng dụng được customize
 Thêm ứng dụng được customize vào trong file Environment của
ứng dụng
 Thêm các thành phần mới vào trong ứng dụng được customize của
bạn
 Lập tài liệu cho các thành phần mới
 Lập tài liệu cho các thành phần mới
 Với mỗi thành phần mới, lập tài liệu cho ít nhất là các nội dung sau :
 Mục đích
 Các tham số đầu vào (cho report và program)
 Các đầu ra ví dụ (cho report và program)
 Xử lý mã
 Các đối tượng CSDL được sử dụng và kiểu truy cập (select, update, insert,delete).
Nếu các component tự của bạn là sửa từ bản copy của một component
trong ứng dụng bạn phải liệt kê chúng trong file applcust.txt ( nằm ở
$APPL_TOP/admin directory
Oracle Applications sẽ sử dụng file này trong quá trình patch hay upgrade

 Định nghĩa ứng dụng được customize của bạn


Sử dụng Applications window để đăng ký custom application (bao gồm
name và short name theo tiêu chuẩn đặt tên thông thường)

 Tạo cấu trúc thư mục cho ứng dụng được customize
Tự tạo cho ứng dụng của bạn một cấu trúc thư mục hợp lý.

 Sửa đổi Applications Environment File


Sửa đổi file biến môi trường cho hợp lý sau đó khởi động lại Forms Server
và Internal Concurrent Manager rồi chạy file biến môi trường để
Oracle Application Object Library tìm thấy các component.

 Thêm mới các thành phần


Mỗi khi tạo một component mới lưu ý là để chúng ở trong thư mục con
hợp lý của ứng dụng.
 Thêm một form mới
Sử dụng file Template khi bắt đầu tạo một form mới để có thể tương thích

10
với ứng dụng hoặc sửa đổi một form đã có sẵn trên ứng dụng rồi đăng ký lại
với ứng dụng.

Các bước tiếp theo là :


 Thêm một Report hoặc một Concurrent Program
 Thêm một Report Submission Form
 Thêm Online Help
 Thêm Menus
 Thêm Responsibilities
 Thêm các thông báo trong Message Dictionary

Customize bằng cách chỉnh sửa


Các bước tiến hành để sửa đổi một form có sẵn trong ứng dụng :
Với Release 11i, tất cả các form đêu đặt trong thư mục
$AU_TOP/forms/<language>. Copy Oracle Applications
form để tiến hành sử đổi ( Lưu ý không sửa đổi trực tiếp lên form).
Sử dụng Oracle Forms Developer and Oracle Application Object Library :

1. Xác định một file


2. Copy file vào trong custom application và đổi tên file
3. Bảo toàn file nguyên bản
4. Thực hiện các chỉnh sửa
5. Chú thích cho form
6. Dịch form
7. Đăng kí ứng dụng được customize trong applcust.txt
8. Lập tài liệu cho việc customize
 Chú thích cho form
Để ghi thông tin về ngày và người sửa của form sử dụng PRE–FORM trigger
Oracle Forms.
FND_STANDARD.FORM_INFO(‟$Revision: <Number>$‟,
‟<Form Name>‟,
‟<Application Shortname>‟,
‟$Date: <YY/MM/DD HH24:MI:SS> $‟,
‟$Author: <developer name> $‟);

11
Lưu ý để có thể sử dụng Help oline thì phải giữ nguyên Application short
Name .
 Chỉnh sửa một Report đã có sẵn
Các bước tiến hành đối với Oracle Reports .rdf file cũng tương tự như dưới đây :
1. Xác định file
2. Thực hiện chỉnh sửa
3. Chú thích cho report
4. Tạo 1 concurrent program sử dụng file của bạn

Customize cơ sở dữ liệu Oracle Applications


Nếu thực hiên việc này phải đặc biệt lưu ý không làm ảnh hưởng tới toàn bộ ứng dụng .

Nâng cấp và chỉnh sửa Oracle Applications


 Kiểm tra các chỉnh sửa đối với CSDL
 Xác định các chỉnh sửa cũ
 Luân chuyển các chỉnh sửa
 Chạy lại Grant và Synonym Scripts
 Test tất cả các sự sửa đổi

Tích hợp Custom Objects và Schemas


Để thực hiện điều này tốt nhất nên hỏi chuyên gia.

Nâng cấp các form được customize lên Release 11i

12
Tổng quan về Coding
Standard trong ứng dụng

Theo dõi các thay đổi về dữ liệu với Record History ( WHO )
 Tính năng Record History ( WHO ) cung cấp thông tin về người đã tạo mới hay cập
nhật các hàng trong các bảng Oracle Applications. Nếu bạn thêm các cột WHO đặc
biệt vào bảng và các mã WHO vào form và stored procedure, người dùng có thể theo
dõi được những thay đổi với dữ liệu của họ. Bạn sử dụng các trường ẩn ( hidden field
) trong mỗi block đại diện cho các cột WHO. Gọi FND_STANDARD.SET_WHO
trong các trigger PRE-INSERT, PRE-UPDATE để cung cấp giá trị cho các trường
này.
 Các cột WHO :

13
14
Các ràng buộc khai báo ( declarative constraint ) :
 NOT NULL
 DEFAULT
 UNIQUE
 CHECK
 PRIMARY KEY

Tránh tạo các bảng với kiểu dữ liệu : LONG, LONG RAW, RAW. Sử dụng kiểu
VARCHAR2(2000) để thay thế. Với các bảng có tên cột trùng với từ khoá, tạo view đến bảng đó với
tên cột được thay bằng tên khác không trùng từ khoá. Có thể thực hiện INSERT, UPDATE, DELETE
qua view kiểu này được.

15
View :
 Các block phức tạp thì dựa trên các view, các block đơn giản thì dựa trên các table. Bạn cũng
nên tạo các LOV dựa trên view.
 Cột đầu tiên trong view nên chọn là cột giả (pseudo-column) ROWID (đặt tên là ROW_ID),
rồi đến các cột của bảng ( kể cả các cột WHO ).
 Đặt thuộc tính Key Mode của block là Non-Updatable để tắt tham chiếu mặc định đến
ROWID của Oracle Forms cho các block dựa trên view. Đặt thuộc tính Primary Key của item
là True với item là khoá chính của view.
 Lập trình các trigger để thực hiện insert, update, delete và lock : khi tạo 1 block dựa trên
view, phải lập trình các trigger ON-INSERT, ON-UPDATE, ON-DELETE và ON-LOCK để
insert, update, delete và lock bảng gốc thay vì view.
 Với view trên 1 bảng, không cần đến các trigger để insert, update, delete hay lock. Đặt Key
Mode của block là Unique. Các view trên 1 bảng không cần đến cột ROW_ID.

Sequence :
 Tạo sequence : để cung cấp các giá trị ID không trùng nhau cho 1 cột của 1 bảng.
 Không nên giới hạn phạm vi của sequence ( không sử dụng CYCLE hoặc MAXVALUE ).
 Sử dụng kiểu dữ liệu Number để lưu các giá trị của sequence.
 Không sử dụng bảng FND_UNIQUE_IDENTIFIER_CONTROL

API đăng kí bảng :


 Bạn đăng kí các bảng ứng dụng tự tạo của mình bằng 1 PL/SQL routine trong package
AD_DD.
 Các bảng ( và mọi cột của nó ) chỉ phải đăng kí khi chúng sử dụng flexfield hoặc Oracle
Alert.
 Có thể sử dụng AD_DD API để xoá các đăng kí của bảng và cột
 Khi thay đổi cấu trúc bảng, đăng kí lại bằng cách xoá đăng kí cũ ( cột trước rồi đến bảng ),
sau đó đăng kí lại.
 AD_DD API không kiểm tra sự tồn tại của bảng cần đăng kí. Vì vậy, cần biết chắc bảng cần
đăng kí có tồn tại và mô tả đúng các định dạng của nó khi sử dụng AD_DD API.
 Không cần phải đăng kí cho view.
 Các thủ tục trong package AD_DD :

procedure register_table (p_appl_short_name in varchar2,


p_tab_name in varchar2,

16
p_tab_type in varchar2,
p_next_extent in number default 512,
p_pct_free in number default 10,
p_pct_used in number default 70);
procedure register_column (p_appl_short_name in varchar2,
p_tab_name in varchar2,
p_col_name in varchar2,
p_col_seq in number,
p_col_type in varchar2,
p_col_width in number,
p_nullable in varchar2,
p_translate in varchar2,
p_precision in number default null,
p_scale in number default null);
procedure delete_table (p_appl_short_name in varchar2,
p_tab_name in varchar2);
procedure delete_column (p_appl_short_name in varchar2,
p_tab_name in varchar2,
p_col_name in varchar2);

Ví dụ về sử dụng package AD_DD để đăng kí 1 bảng flexfield và các cột của nó :


EXECUTE ad_dd.register_table(‟FND‟, ‟CUST_FLEX_TEST‟, ‟T‟,
8, 10, 90);
EXECUTE ad_dd.register_column(‟FND‟, ‟CUST_FLEX_TEST‟,
‟APPLICATION_ID‟, 1, ‟NUMBER‟, 38, ‟N‟, ‟N‟);

Tổng quan về việc sử dụng PL/SQL trong các ứng dụng :


 Bạn có thể sử dụng các thủ tục PL/SQL như một phần của ứng dụng bạn xây dựng
nằm trong Oracle Applications. Bằng cách tuân theo các chuẩn lập trình, bạn có thể
tạo ra 1 thủ tục PL/SQL tích hợp hoàn toàn với ứng dụng.
 Bạn có thể sử dụng PL/SQL viết các đoạn mã mở rộng có tính thủ tục để custom
form và report. PL/SQL cũng giúp module hoá form code của bạn, hoặc phát triển
các chương trình chạy đồng thời ( concurrent program ).

Thuật ngữ :
 Server-side : chỉ các thủ tục lưu trên cơ sở dữ liệu Oracle .
 Client-side : chỉ các thủ tục chạy trong các chương trình là client của CSDL Oracle.

17
Các chuẩn chung trong lập trình PL/SQL :
 Luôn sử dụng package : định nghĩa các thủ tục PL/SQL trong package
 Kích thước package : mã nguồn của 1 đơn vị chương trình ( 1 package ) client-side
không được vượt quá 10K, và tổng kích thước source code và compiled code phải
nhỏ hơn 64K. Nếu 1 đơn vị chương trình quá lớn, có thể chia ra thành các đơn vị con
được liên kết với nhau. Server-side package không bị giới hạn về kích thước.
 Thêm các thủ tục mới vào các package đã tồn tại : thêm vào cuối của mỗi package.
Nếu thêm vào giữa package ( specification hay body ), phải dịch lại các form có tham
chiếu đến package, nếu không sẽ bị lỗi.
 Sử dụng tên trường trong các client-side package : luôn dùng tên trường đầy đủ (
BLOCK_NAME.FIELD_NAME ) để khoanh vùng tìm kiếm ( chỉ tìm trong block đó
), và tránh trường hợp xung đột khi có 2 trường trùng tên.
 Tên trường trong các tham số của thủ tục : không dùng kiểu tham số OUT hoặc IN
OUT vì có thể làm thay đổi các giá trị của trường truyền vào khi kết thúc thủ tục. Với
danh sách tham số quá dài, sử dụng “ => “ để truyền đúng tham số.
 Sử dụng DEFAULT : sử dụng DEFAULT để khởi tạo giá trị mặc định cho tham số
thay vì “:=”, để cho giá trị truyền vào có thể ghi đè lên giá trị mặc định. Ngược lại,
với hằng, sử dụng “:=” để giá trị không thể bị ghi đè lên.
 Sử dụng ID của object : các đoạn code thay đổi nhiều thuộc tính của 1 đối tượng
bằng SET_<OBJECT>_PROPERTY, nên sử dụng ID của đối tượng. Dùng
FIND_<OBJECT> để lấy ID, sau đó truyền ID vào thủ tục được dựng sẵn
SET_<OBJECT>_PROPERTY.
 Xử lý giá trị NULL : bất kì biểu thức so sánh nào có chứa phần tử NULL đều trả về
giá trị FALSE. Để kiểm tra một phần tử có NULL hay không, sử dụng “IS”.
 Các biến global : có 3 loại
. Oracle Form global : biến nằm trong pseudo-block ( khối giả ) “global” của form.
. PL/SQL package global : biến được định nghĩa trong package specification
. Oracle Form Parameter : biến được tạo như một tham số trong Oracle Forms
Designer.

18
Định dạng mã PL/SQL :
 Trong 1 package, định nghĩa các biến private trước, sau đó đến các thủ tục private,
cuối cùng là các thủ tục public.
 Luôn kết thúc thủ tục hoặc package bằng End Procedure_name; hoặc End
Package_name; để dễ theo dõi, nhận dạng.
 Hàng lệnh dưới lùi vào trong 2 dấu cách để dễ đọc code, ví dụ :

 Sử dụng “--“ để thêm dòng chú thích và “/* … */” để bao đoạn chú thích.
 Căn lề chú thích và lệnh được chú thích thẳng hàng.

19
 Sử dụng chữ hoa ( với các từ khoá ) và chữ thường ( các từ còn lại ) để dễ đọc code
( vì PL/SQL không phân biệt chữ hoa chữ thường ).
 Dùng IF-THEN-ELSIF thay cho các cấu trúc IF-THEN-ELSE lồng nhau.

 Chỉ tạo các khối PL/SQL lồng nhau trong 1 thủ tục khi phải xử lý những lỗi cụ thể
phát sinh.

Xử lý lỗi :
 Lỗi trong thủ tục PL/SQL trong Oracle Form : sử dụng FND_MESSAGE để hiển
thị thông báo lỗi, sau đó gọi RAISE FORM_TRIGGER_FAILURE để dừng việc
xử lý lại.

 Lỗi trong các stored procedure : sử dụng FND_MESSAGE.SET_NAME để hiển


thị thông báo lỗi, sau đó gọi APP_EXCEPTION.RAISE_EXCEPTION để dừng xử

20
 Kiểm tra FORM_SUCCESS, FORM_FAILURE và FORM_FATAL : các giá trị
của chúng có thể bị thay đổi bởi một trigger nào đó. Xem ví dụ sau :

 Tránh sử dụng RAISE_APPLICATION_ERROR vì nó gây xung đột trong quá


trình xử lý lỗi ở phía server.

Một vài hướng dẫn khi coding SQL :


 Sử dụng “select from DUAL” thay vì “select from SYS.DUAL”. Không sử dụng
SYSTEM.DUAL.
 Tất cả các lệnh SELECT nên sử dụng một cursor (con trỏ) tự định nghĩa từ trước.
Một lệnh SELECT bình thường thực hiện 2 xử lý : 1 để lấy dữ liệu và 1 để kiểm tra

21
có bị lỗi TOO_MANY_ROWS không. Ta có thể tránh điều này bằng việc chỉ lấy
về 1 bản ghi từ cursor mà ta định nghĩa trước.
 Nếu bạn muốn SELECT vào trong 1 tham số thủ tục, khai báo tham số là IN OUT,
cho dù có sử dụng hay không giá trị của tham số ( trừ trường hợp tham số là trường
).
 1 single-row SELECT khi không trả về hàng nào sẽ sinh ra lỗi
NO_DATA_FOUND. 1 INSERT, UPDATE, hay DELETE khi không tác động lên
hàng nào sẽ không báo lỗi. Bạn phải tự kiểm tra giá trị của SQL%NOTFOUND để
biết được có bị lỗi không.
 Để xử lý NO_DATA_FOUND, viết một đoạn bắt lỗi (exception handler), thay vì
dùng COUNT để đếm số hàng hiện thời.
 Khi kiểm tra giá trị của một trường hoặc một biến để bắt lỗi sai, kiểm tra trong
PL/SQL code, chứ không phải trong mệnh đề WHERE.

Các trigger trong form :


 Kiểu xử lý : Kiểu xử lý cho tất cả các trigger ở mức block hay field nên là Overide
(đè lên trigger mức form) hoặc Before (thực hiện trước trigger mức form). Thông
thường là sử dụng kiểu Before, vì phiên bản trigger ở mức form cũng cần được
thực hiện. Trường hợp ngoại lệ là khi bạn có một lời gọi flexfield trong trigger
POST-QUERY mức form, nhưng bạn đặt lại query status của block trong trigger
POST-QUERY ở mức block, thì bạn nên đặt kiểu xử lý cho trigger mức block là
After.
 Trigger WHEN-CREATE-RECORD vẫn kích hoạt khi block không cho phép
insert. Vì vậy, nên kiểm tra xem 1 block có cho phép insert không trước khi thực
hiện xử lý nào đó trong trigger này :

Những sự thay thế cho các built-in trong Oracle Forms


 Không sử dụng CALL_FORM : vì built-in này không tương thích với
OPEN_FORM (được sử dụng bởi các Oracle Application routine). Sử dụng
FND_FUNCTION.EXECUTE thay cho CALL_FORM hoặc OPEN_FORM khi
muốn mở form bằng lập trình.

22
 Những Oracle Forms built-in sau có các APPCORE routine tương đương với
chúng :
+ EXIT_FORM : các form Oracle Applications có xử lý đóng đặc biệt. Không
gọi trực tiếp EXIT_FORM, mà luôn gọi do_key(„EXIT_FORM‟). Để đóng toàn
bộ Oracle Applications, trước tiên gọi :
copy(‘Y’, ’GLOBAL.APPCORE_EXIT_FLAG’);
sau đó gọi : do_key(‘EXIT_FORM’);
+ SET_ITEM_PROPERTY : thay bằng
APP_ITEM_PROPERTY.SET_PROPERTY và
APP_ITEM_PROPERTY.SET_VISUAL_ATTRIBUTE.
Những APPCORE routine này đặt các thuộc tính trong Oracle Applications theo
chuẩn.Có một số thuộc tính sử dụng SET_ITEM_PROPERTY.
+ GET_ITEM_PROPERTY : sử dụng
APP_ITEM_PROPERTY.GET_PROPERTY khi lấy các thuộc tính cụ thể của
Oracle Applications. Khi đặt hoặc lấy các thuộc tính còn lại, sử dụng các built-in
của Oracle Forms.
+ OPEN_FORM : sử dụng FND_FUNCTION.EXECUTE để thay thế. Cả 2 cách
gọi này đều làm cho các trigger POST-RECORD và POST-BLOCK kích hoạt.
+ CLEAR_FORM : sử dụng do_key(„CLEAR_FORM‟). Routine này sẽ báo lỗi
FORM_TRIGGER_FAILURE nếu có 1 bản ghi không hợp lệ.
+ COMMIT : sử dụng do_key(„COMMIT_FORM‟). Routine này sẽ báo lỗi
FORM_TRIGGER_FAILURE nếu có 1 bản ghi không hợp lệ.
+ EDIT_FIELD / EDIT_TEXTITEM : sử dụng do_key(„edit_field‟). Routine
này sẽ gọi calendar khi item hiện tại là date.
+ VALIDATE : sử dụng APP_STANDARD.APP_VALIDATE để thay thế.
Routine này sẽ chuyển focus đến bất kì item nào làm phát sinh lỗi navigation.

Lập trình các handler cho item, event và table :


 Người lập trình có thể gọi các handler (chương trình xử lý) từ trong trigger để xử
lý các mã cần thiết để validate một item hoặc đảm bảo cho 1 hành động được thực
hiện đúng trong tình huống cụ thể.
 1 form điển hình có từng package cho mỗi block, và 1 package cho bản thân form.
Lập trình cho các thủ tục trong mỗi package, và gọi thủ tục (hay handler đó) từ các
trigger có liên quan. Với handler liên quan đến nhiều block hay đáp ứng cho
trigger mức form, đặt nó vào trong package của form.

23
 Việc viết các handler ( cho item, event, table ), và gọi chúng trong trigger sẽ giúp
cho khối lượng mã trong trigger ở mức tối thiểu.

Lập trình các handler cho item :


Các item handler là các thủ tục chứa đựng tất cả các đoạn mã dùng để validate một item cụ
thể nào đó. Một item handler package chứa tất cả các thủ tục dùng để validate các item trong 1 block
hoặc 1 form. Nên đặt tên package theo tên block ( hoặc tên form ) và đặt tên các thủ tục trong package
theo tên các item trong block đó (VD : block EMP, item EMPNO -> package EMP, procedure
EMPNO) để dễ xác định code nào đi với item nào. Mỗi item handler luôn có 1 tham số tên là EVENT,
kiểu là VARCHAR2, thường để truyền tên của trigger gọi item handler đó. Các EVENT thông dụng
và xử lý tương ứng là :
 PRE-RECORD : đặt lại các item attribute cho bản ghi mới. EVENT này thường
được sử dụng cho các APPCORE routine (loại enable hoặc disable các trường độc
lập). Bạn cũng có thể dùng WHEN-NEW-RECORD-INSTANCE ( thay cho PRE-
RECORD ) trong một vài trường hợp.
 INIT : khởi tạo ( initialize ) item. INIT chỉ thị cho item handler kiểm tra các điều
kiện hiện tại của form và đặt lại các giá trị mặc định và các thuộc tính động cho
item nếu cần thiết. EVENT này được gửi đi bởi các handler khác và là đầu vào cho
nhiều APPCORE routine. Trường hợp thông thường nhất là khi 1 item phụ thuộc
vào 1 item khác. Khi 1 master item thay đổi, handler của item phụ thuộc sẽ được
gọi với sự kiện INIT.
 VALIDATE : được sử dụng với nhiều APPCORE routine khi item cần được
validate. Sử dụng VALIDATE thay cho WHEN–VALIDATE–ITEM, WHEN–
CHECKBOX–CHANGED, WHEN–LIST–CHANGED, hoặc WHEN–RADIO–
CHANGED.

24
Lập trình các handler cho event :
 Event handler thực hiện các hành động phức tạp trên nhiều item có liên quan với
nhau, trong khi item handler thực hiện các hành động đơn giản trên 1 item. Trong
event handler, ta có thể gọi các item handler.
 Event handler chỉ xử lý 1 sự kiện ( trên nhiều item ), nên không cần tham số
EVENT, và cũng không cần bất kì tham số nào.
 Event handler được đặt tên theo trigger, nhưng thay dấu gạch ngang bằng dấu gạch
dưới (VD: trigger PRE-QUERY -> handler PRE_QUERY).
 Một số event handler thông dụng :
. PRE_QUERY : cung cấp các giá trị cần cho các item để lấy được các bản ghi mong
muốn.
. POST_QUERY : cung cấp giá trị cho các item không liên quan đến bảng dữ liệu.
. WHEN_CREATE_RECORD : cung cấp các giá trị mặc định khi tạo bản ghi mới (
khi mà sử dụng thuộc tính default value là chưa đủ )
. WHEN_VALIDATE_RECORD : kiểm tra các quan hệ phức tạp có trong item.

Lập trình các handler cho table :


 Một table handler là 1 server-side package hoặc 1 client-side package cung cấp
một API cho 1 bảng. Các table handler được sử dụng để insert, update, delete hoặc
lock một bản ghi, hoặc để kiểm tra xem 1 record ở bảng khác có tham chiếu đến
record ở trong bảng này ko. Vì hầu hết các form trong Oracle Applications đều dựa
trên các view nên cần phải có các table handler này để xử lý những tương tác với
các bảng có trong view.

25
 Các table handler chứa một vài hoặc tất cả các thủ tục sau :
. CHECK_UNIQUE : kiểm tra xem có giá trị lặp trong cột unique hay không
. CHECK_REFERENCES : kiểm tra tính toàn vẹn tham chiếu
. INSERT_ROW
. UPDATE_ROW
. DELETE_ROW
. LOCK_ROW
 INSERT_ROW, UPDATE_ROW, DELETE_ROW và LOCK_ROW thường được
sử dụng để thay thế xử lý giao dịch mặc định của Oracle Forms trong các trigger
ON-INSERT, ON-UPDATE, ON-DELETE và ON-LOCK.
 Trong thủ tục xử lý bảng INSERT_ROW, nếu một cột khoá chính cho phép giá trị
NULL, cần thêm “OR (primary_key IS NULL AND X_col IS NULL)” vào mệnh
đề WHERE của câu lệnh SELECT ROWID.
 Trong thủ tục xử lý bảng LOCK_ROW, nếu 1 cột không được phép NULL, gỡ bỏ
điều kiện ”OR (RECINFO.col IS NULL AND X_col IS NULL)” ra khỏi lệnh IF.
 Tác động lên 1 bảng thứ hai : để thực hiện 1 hành động trên 1 bảng khác, gọi thủ
tục xử lý tương ứng của bảng đó thay cho việc thực hiện hành động trực tiếp. Ví
dụ, trong thủ tục DELETE_ROW của bảng master, ta xoá bản ghi master và gọi
thủ tục DELETE_ROW của bảng detail để xoá các bản ghi detail tương ứng, chứ
không thực hiện lệnh DELETE trực tiếp xoá chúng trong handler của master.
 Ví dụ về client-side table handler : handler này cung cấp các thủ tục
INSERT_ROW, UPDATE_ROW, DELETE_ROW, and LOCK_ROW cho bảng
EMP. Bạn lập trình client–side table handler trực tiếp trong form

Package spec you would code for your EMP block


PACKAGE EMP IS
PROCEDURE Insert_Row;
PROCEDURE Lock_Row;
PROCEDURE Update_Row;
PROCEDURE Delete_Row;
END EMP;
Package body you would code for your EMP block
PACKAGE BODY EMP IS
PROCEDURE Insert_Row IS

26
CURSOR C IS SELECT rowid FROM EMP
WHERE empno = :EMP.Empno;
BEGIN
INSERT INTO EMP(
empno,
ename,
job,
mgr,
hiredate,
sal,
comm,
deptno
) VALUES (
:EMP.Empno,
:EMP.Ename,
:EMP.Job,
:EMP.Mgr,
:EMP.Hiredate,
:EMP.Sal,
:EMP.Comm,
:EMP.Deptno
);
OPEN C;
FETCH C INTO :EMP.Row_Id;
if (C%NOTFOUND) then
CLOSE C;
Raise NO_DATA_FOUND;
end if;
CLOSE C;
END Insert_Row;
PROCEDURE Lock_Row IS

27
Counter NUMBER;
CURSOR C IS
SELECT empno,
ename,
job,
mgr,
hiredate,
sal,
comm,
deptno
FROM EMP
WHERE rowid = :EMP.Row_Id
FOR UPDATE of Empno NOWAIT;
Recinfo C%ROWTYPE;
BEGIN
Counter := 0;
LOOP
BEGIN
Counter := Counter + 1;
OPEN C;
FETCH C INTO Recinfo;
if (C%NOTFOUND) then
CLOSE C;
FND_MESSAGE.Set_Name(‟FND‟,
‟FORM_RECORD_DELETED‟);
FND_MESSAGE.Error;
Raise FORM_TRIGGER_FAILURE;
end if;
CLOSE C;
if (
(Recinfo.empno = :EMP.Empno)

28
AND ( (Recinfo.ename = :EMP.Ename)
OR ( (Recinfo.ename IS NULL)
AND (:EMP.Ename IS NULL)))
AND ( (Recinfo.job = :EMP.Job)
OR ( (Recinfo.job IS NULL)
AND (:EMP.Job IS NULL)))
AND ( (Recinfo.mgr = :EMP.Mgr)
OR ( (Recinfo.mgr IS NULL)
AND (:EMP.Mgr IS NULL)))
AND ( (Recinfo.hiredate = :EMP.Hiredate)
OR ( (Recinfo.hiredate IS NULL)
AND (:EMP.Hiredate IS NULL)))
AND ( (Recinfo.sal = :EMP.Sal)
OR ( (Recinfo.sal IS NULL)
AND (:EMP.Sal IS NULL)))
AND ( (Recinfo.comm = :EMP.Comm)
OR ( (Recinfo.comm IS NULL)
AND (:EMP.Comm IS NULL)))
AND (Recinfo.deptno = :EMP.Deptno)
) then
return;
else
FND_MESSAGE.Set_Name(‟FND‟,
‟FORM_RECORD_CHANGED‟);
FND_MESSAGE.Error;
Raise FORM_TRIGGER_FAILURE;
end if;
EXCEPTION
When APP_EXCEPTIONS.RECORD_LOCK_EXCEPTION then
IF (C% ISOPEN) THEN
close C;

29
END IF;
APP_EXCEPTION.Record_Lock_Error(Counter);
END;
end LOOP;
END Lock_Row;
PROCEDURE Update_Row IS
BEGIN
UPDATE EMP
SET
empno = :EMP.Empno,
ename = :EMP.Ename,
job = :EMP.Job,
mgr = :EMP.Mgr,
hiredate = :EMP.Hiredate,
sal = :EMP.Sal,
comm = :EMP.Comm,
deptno = :EMP.Deptno
WHERE rowid = :EMP.Row_Id;
if (SQL%NOTFOUND) then
Raise NO_DATA_FOUND;
end if;
END Update_Row;
PROCEDURE Delete_Row IS
BEGIN
DELETE FROM EMP
WHERE rowid = :EMP.Row_Id;
if (SQL%NOTFOUND) then
Raise NO_DATA_FOUND;
end if;
END Delete_Row;
END EMP;

30
- Ví dụ về server-side table handler : handler này cung cấp các thủ tục INSERT_ROW,
UPDATE_ROW, DELETE_ROW và LOCK_ROW cho bảng EMP. Handler của bạn sẽ bao gồm 1
package trong form và 1 server–side package trong cơ sở dữ liệu. Package trong form sẽ gọi sever-
side package và truyền tất cả giá trị của các trường như là các đối số.

Package spec you would code in your form for your EMP
block
PACKAGE EMP IS
PROCEDURE Insert_Row;
PROCEDURE Update_Row;
PROCEDURE Lock_Row;
PROCEDURE Delete_Row;
END EMP;
Package body you would code in your form for your EMP
block
PACKAGE BODY EMP IS
PROCEDURE Insert_Row IS
BEGIN
EMP_PKG.Insert_Row(
X_Rowid => :EMP.Row_Id,
X_Empno => :EMP.Empno,
X_Ename => :EMP.Ename,
X_Job => :EMP.Job,
X_Mgr => :EMP.Mgr,
X_Hiredate => :EMP.Hiredate,
X_Sal => :EMP.Sal,
X_Comm => :EMP.Comm,
X_Deptno => :EMP.Deptno);
END Insert_Row;
PROCEDURE Update_Row IS
BEGIN

31
EMP_PKG.Update_Row(
X_Rowid => :EMP.Row_Id,
X_Empno => :EMP.Empno,
X_Ename => :EMP.Ename,
X_Job => :EMP.Job,
X_Mgr => :EMP.Mgr,
X_Hiredate => :EMP.Hiredate,
X_Sal => :EMP.Sal,
X_Comm => :EMP.Comm,
X_Deptno => :EMP.Deptno);
END Update_Row;
PROCEDURE Delete_Row IS
BEGIN
EMP_PKG.Delete_Row(:EMP.Row_Id);
END Delete_Row;
PROCEDURE Lock_Row IS
Counter Number;
BEGIN
Counter := 0;
LOOP
BEGIN
Counter := Counter + 1;
EMP_PKG.Lock_Row(
X_Rowid => :EMP.Row_Id,
X_Empno => :EMP.Empno,
X_Ename => :EMP.Ename,
X_Job => :EMP.Job,
X_Mgr => :EMP.Mgr,
X_Hiredate => :EMP.Hiredate,
X_Sal => :EMP.Sal,
X_Comm => :EMP.Comm,

32
X_Deptno => :EMP.Deptno);
return;
EXCEPTION
When APP_EXCEPTIONS.RECORD_LOCK_EXCEPTION then
APP_EXCEPTION.Record_Lock_Error(Counter);
END;
end LOOP;
END Lock_Row;
END EMP;
Package spec for the server–side table handler (SQL script)
SET VERIFY OFF
DEFINE PACKAGE_NAME=”EMP_PKG”
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
CREATE or REPLACE PACKAGE &PACKAGE_NAME as
/* Put any header information (such as $Header$) here.
It must be written within the package definition so that the
header information will be available in the package itself.
This makes it easier to identify package versions during
upgrades. */
PROCEDURE Insert_Row(X_Rowid IN OUT VARCHAR2,
X_Empno NUMBER,
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
);
PROCEDURE Lock_Row(X_Rowid VARCHAR2,
X_Empno NUMBER,

33
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
);
PROCEDURE Update_Row(X_Rowid VARCHAR2,
X_Empno NUMBER,
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
);
PROCEDURE Delete_Row(X_Rowid VARCHAR2);
END &PACKAGE_NAME;
/
show errors package &PACKAGE_NAME
SELECT to_date(‟SQLERROR‟) FROM user_errors
WHERE name = ‟&PACKAGE_NAME‟
AND type = ‟PACKAGE‟
/
commit;
exit;
Package body for the server–side table handler (SQL script)
SET VERIFY OFF
DEFINE PACKAGE_NAME=”EMP_PKG”

34
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
CREATE or REPLACE PACKAGE BODY &PACKAGE_NAME as
/* Put any header information (such as $Header$) here.
It must be written within the package definition so the
header information is available in the package itself.
This makes it easier to identify package versions during
upgrades. */
PROCEDURE Insert_Row(X_Rowid IN OUT VARCHAR2,
X_Empno NUMBER,
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
) IS
CURSOR C IS SELECT rowid FROM emp
WHERE empno = X_Empno;
BEGIN
INSERT INTO emp(
empno,
ename,
job,
mgr,
hiredate,
sal,
comm,
deptno
) VALUES (
X_Empno,

35
X_Ename,
X_Job,
X_Mgr,
X_Hiredate,
X_Sal,
X_Comm,
X_Deptno
);
OPEN C;
FETCH C INTO X_Rowid;
if (C%NOTFOUND) then
CLOSE C;
Raise NO_DATA_FOUND;
end if;
CLOSE C;
END Insert_Row;
PROCEDURE Lock_Row(X_Rowid VARCHAR2,
X_Empno NUMBER,
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
) IS
CURSOR C IS
SELECT *
FROM emp
WHERE rowid = X_Rowid
FOR UPDATE of Empno NOWAIT;

36
Recinfo C%ROWTYPE;
BEGIN
OPEN C;
FETCH C INTO Recinfo;
if (C%NOTFOUND) then
CLOSE C;
FND_MESSAGE.Set_Name(‟FND‟, ‟FORM_RECORD_DELETED‟);
APP_EXCEPTION.Raise_Exception;
end if;
CLOSE C;
if (
(Recinfo.empno = X_Empno)
AND ( (Recinfo.ename = X_Ename)
OR ( (Recinfo.ename IS NULL)
AND (X_Ename IS NULL)))
AND ( (Recinfo.job = X_Job)
OR ( (Recinfo.job IS NULL)
AND (X_Job IS NULL)))
AND ( (Recinfo.mgr = X_Mgr)
OR ( (Recinfo.mgr IS NULL)
AND (X_Mgr IS NULL)))
AND ( (Recinfo.hiredate = X_Hiredate)
OR ( (Recinfo.hiredate IS NULL)
AND (X_Hiredate IS NULL)))
AND ( (Recinfo.sal = X_Sal)
OR ( (Recinfo.sal IS NULL)
AND (X_Sal IS NULL)))
AND ( (Recinfo.comm = X_Comm)
OR ( (Recinfo.comm IS NULL)
AND (X_Comm IS NULL)))
AND (Recinfo.deptno = X_Deptno)

37
) then
return;
else
FND_MESSAGE.Set_Name(‟FND‟, ‟FORM_RECORD_CHANGED‟);
APP_EXCEPTION.Raise_Exception;
end if;
END Lock_Row;
PROCEDURE Update_Row(X_Rowid VARCHAR2,
X_Empno NUMBER,
X_Ename VARCHAR2,
X_Job VARCHAR2,
X_Mgr NUMBER,
X_Hiredate DATE,
X_Sal NUMBER,
X_Comm NUMBER,
X_Deptno NUMBER
) IS
BEGIN
UPDATE emp
SET
empno = X_Empno,
ename = X_Ename,
job = X_Job,
mgr = X_Mgr,
hiredate = X_Hiredate,
sal = X_Sal,
comm = X_Comm,
deptno = X_Deptno
WHERE rowid = X_Rowid;
if (SQL%NOTFOUND) then
Raise NO_DATA_FOUND;

38
end if;
END Update_Row;
PROCEDURE Delete_Row(X_Rowid VARCHAR2) IS
BEGIN
DELETE FROM emp
WHERE rowid = X_Rowid;
if (SQL%NOTFOUND) then
Raise NO_DATA_FOUND;
end if;
END Delete_Row;
END &PACKAGE_NAME;
/
show errors package body &PACKAGE_NAME
SELECT to_date(‟SQLERROR‟) FROM user_errors
WHERE name = ‟&PACKAGE_NAME‟
AND type = ‟PACKAGE BODY‟
/
commit;
exit;

39
Form TEMPLATE

Giới thiệu về form TEMPLATE :


 Form TEMPLATE là điểm khởi đầu cần có đối với mọi sự phát triển form mới. Bắt
đầu tạo 1 form mới bằng cách copy form TEMPLATE về 1 thư mục trong máy rồi
thay tên nó bằng một tên form mới
 Form TEMPLATE bao gồm :
 Các tham chiếu tới các nhóm đối tượng trong form APPSTAND
(STANDARD_PC_AND_VA, STANDARD_TOOLBAR, và
STANDARD_CALENDAR)
 Các kết nối (attachment) đến một số thư viện (FNDSQF, APPCORE, và
APPDAYPK)
 Một số trigger mức form cần phải thêm code.
 Các đơn vị chương trình, trong đó có package APP_CUSTOM
(specification và body), chứa các hành động mặc định cho các sự kiện
đóng và mở window. Bạn thường phải sửa code trong package này khi
phát triển form theo yêu cầu.
 Bảng màu của ứng dụng
 Rất nhiều đối tượng được tham chiếu ( nằm trong các nhóm đối tượng ),
để hỗ trợ cho calendar, toolbar, alternative region và menu. Ví dụ như các
LOV, block, parameter, property class.
 Một số đối tượng ví dụ đưa ra các item và layout điển hình. Để bỏ chúng
đi, xóa các đối tượng sau trong form :
Block : BLOCKNAME, DETAILBLOCK
Canvas : BLOCKNAME
Window : BLOCKNAME

Các thư viện trong form TEMPLATE


 Form TEMPLATE chứa các attachment đến một số thư viện. 3 thư viện được
attach trực tiếp là : FNDSQF, APPCORE, APPDAYPK. Các thư viện khác được
attach đến 3 thư viện này. Trong Oracle Forms, ta không biệt được thư viện được
attach theo kiểu nào.

40
 Thư viện APPCORE :
 Chứa các thủ tục nằm trong các package mà mọi form đều cần để hỗ trợ
menu, toolbar, và các hành động chuẩn theo yêu cầu.
 Chứa các package được gọi để lưu các hành động cụ thể khi đang chạy
ứng dụng.
 Chứa các package cung cấp các thủ tục để xử lý lỗi, thông báo theo các
mức…
 Các package trong APPCORE thường có tên bắt đầu bằng “APP”.
 Thư viện APPDAYPK : chứa các package xử lý tính năng Oracle Applications
Calendar.
 Thư viện FNDSQF :
 Chứa các thủ tục và package cho Message Dictionary, flexfield, profile,
xử lý đồng thời (concurrent processing).
 Cung cấp các tiện ích cho navigation, multicurrency, WHO
 Các package trong FNDSQF thường có tên bắt đầu bằng “FND”.
 Thư viện CUSTOM :
 Thư viện CUSTOM cho phép mở rộng các form của Oracle Applications
mà không phải thay đổi code trong Oracle Applications. Bạn có thể sử
dụng thư viện CUSTOM để customize, áp đặt các quy tắc (chẳng hạn tên
hãng phải viết hoa), hoặc disable những trường không cần.
 Bạn viết code trong thư viện CUSTOM, bên trong những procedure shell
được cung cấp. Oracle Applications gửi các sự kiện tới thư viện
CUSTOME. Những đoạn code bạn viết có hiệu lực dựa vào những sự
kiện này.
 Thư viện GLOBE : cho phép người phát triển Oracle Applications tập hợp các tính
năng chung hoặc riêng vào trong form Oracle Applications mà không phải thay đổi
form Oracle Applications gốc. Oracle Applications gửi các sự kiện tới thư viện
GLOBE. Các đoạn code bên trong có hiệu lực dựa vào các sự kiện này. Thư viện
GLOBE gọi đến các routine trong các thư viện JA, JE và JL.
 Thư viện JA : chứa code đặc trưng cho khu vực Asia/Pacific và được gọi bởi thư
viện GLOBE.
 Thư viện JE : chứa code đặc trưng cho khu vực EMEA (Europe/Middle
East/Africa) và được gọi bởi thư viện GLOBE.
 Thư viện JL : chứa code đặc trưng cho khu vực Latin America và được gọi bởi thư
viện GLOBE.

41
Các trigger trong form TEMPLATE

 Form TEMPLATE chứa một số trigger mức form. Các trigger này cần phải có để
các routine khác hoạt động đúng. Text trong trigger thường được giữ nguyên,
người sử dụng sẽ thêm các đoạn text của mình vào trước hoặc sau chúng.
 Các trigger chuẩn :
KEY–CLRFRM
KEY–COMMIT
KEY–DUPREC
KEY–EDIT
KEY–EXIT
KEY–HELP
KEY–LISTVAL
KEY–MENU
ON–ERROR
POST–FORM
PRE–FORM
WHEN–FORM–NAVIGATE
WHEN–NEW–BLOCK–INSTANCE
WHEN–NEW–FORM–INSTANCE
WHEN–NEW–ITEM–INSTANCE
WHEN–NEW–RECORD–INSTANCE
WHEN–WINDOW–CLOSED
WHEN–WINDOW–RESIZED
 Các trigger do người dùng định nghĩa :
ACCEPT
CLOSE_THIS_WINDOW
CLOSE_WINDOW
EXPORT
FOLDER_ACTION
FOLDER_RETURN_ACTION
LASTRECORD
MENU_TO_APPCORE
QUERY_FIND
STANDARD_ATTACHMENTS

42
ZOOM
 Các trigger thường phải chỉnh sửa :
 ACCEPT
APP_STANDARD.EVENT(‟ACCEPT‟);
Trigger này xử lý chức năng ”Action, Save and Proceed” trên
menu hoặc toolbar. Nó lưu những thay đổi và chuyển tới bản ghi
tiếp theo của block được xác định là First Navigation Block.
Thay thế code trong trigger này, hoặc tạo trigger mức block với
kiểu xử lý là „Override‟

 FOLDER_RETURN_ACTION null;
Trigger này cho phép customize các folder event xác định.
Thay thế text bởi code cần thiết để xử lý các hành động cho folder.

 KEY–DUPREC
APP_STANDARD.EVENT(‟KEY–DUPREC‟);
Trigger này disable tính năng nhân đôi bản ghi mặc định của
Oracle Forms.
Để xử lý tính năng ”Edit, Duplicate Record Above” trên menu
được đúng, tạo 1 trigger KEY–DUPREC mức block với kiểu xử lý
„Override‟. Viết code cho trigger này để nó thực hiện việc nhân đôi
bản ghi, sau đó validate hoặc xoá các trường cần thiết.

 KEY–CLRFRM
APP_STANDARD.EVENT(‟KEY–CLRFRM‟);
Trigger này validate bản ghi trước khi thử xoá form.
Thêm code cần thiết bên dưới code có sẵn. Thường thì bạn sẽ thêm
các lời gọi GO_BLOCK nếu có các alternative region trong form
của bạn, và cung cấp lại các giá trị cho region control poplist của
bạn sau hành động Clear Form.

 KEY–MENU

43
APP_STANDARD.EVENT(‟KEY–MENU‟);
Trigger này disable lệnh Block Menu của Oracle Forms.
Để enable hoạt động của Alternative Region bằng bàn phím từ 1
block cụ thể, tạo trigger KEY–MENU mức block với kiểu xử lý là
„Override‟. Trigger này nên mở ra 1 LOV với các sự lựa chọn
giống như Alternative Region control poplist.

 KEY–LISTVAL
APP_STANDARD.EVENT(‟KEY–LISTVAL‟);
Trigger này thực hiện các hoạt động của flexfield hoặc gọi LOV.
Tạo trigger mức block hoặc item với kiểu xử lý „Override‟ trên các
trường sử dụng đối tượng Calendar, hoặc các trường gọi flexfield
khi chương trình đang chạy.
 ON–ERROR
APP_STANDARD.EVENT(‟ON–ERROR‟);
Trigger này xử lý tất cả các lỗi, từ server hoặc từ client, sử dụng
các lời gọi của Message Dictionary.
Để bẫy các lỗi cụ thể, kiểm tra các lỗi cụ thể bạn mắc trước khi gọi
APP_STANDARD
declare
original_mess varchar2(80);
begin
IF MESSAGE_CODE = <your message number> THEN
original_mess := MESSAGE_TYPE||‟–‟||
to_char(MESSAGE_CODE)||‟: ‟||MESSAGE_TEXT;
––– your code handling the error goes here
message(original_mess);
ELSE
APP_STANDARD.EVENT(‟ON_ERROR‟);
END IF
end;

 POST–FORM
APP_STANDARD.EVENT(‟POST–FORM‟);
Trigger này được dành cho những sử dụng trong tương lai.

44
Thêm code cần thiết vào trước code có sẵn.

 PRE–FORM
FND_STANDARD.FORM_INFO(‟$Revision: <Number>$‟,
‟<Form Name>‟,
‟<Application Shortname>‟,
‟$Date: <YY/MM/DD HH24:MI:SS> $‟,
‟$Author: <developer name> $‟);
APP_STANDARD.EVENT(‟PRE–FORM‟);
APP_WINDOW.SET_WINDOW_POSITION(‟BLOCKNAME‟,
‟FIRST_WINDOW‟);
Trigger này khởi tạo các giá trị bên trong Oracle Applications và
menu. Các giá trị bạn nhập vào sẽ được nhìn thấy khi chọn ”Help,
About Oracle Applications” từ menu của Oracle Applications.
Bạn phải sửa lại short name của Application. Application
Shortname điều khiển file trợ giúp online nào của Application được
truy cập khi người dùng chọn nút Help trên toolbar.
Form name là tên form của người dùng. Nó chỉ có mục đích để bạn
tham khảo, và không được sử dụng ở chỗ nào khác nữa.
Oracle sử dụng 1 hệ thống điều khiển mã nguồn cho phép tự động
cập nhật các giá trị bắt đầu với “$”.
Bạn cũng phải sửa lời gọi APP_WINDOW để đưa tên block của
bạn vào.

 QUERY_FIND
APP_STANDARD.EVENT(‟QUERY_FIND‟);
Trigger này đưa ra 1 thông báo mặc định cho biết Query Find
không được dùng.
Sửa code trong trigger này, hoặc tạo trigger mức block với kiểu xử
lý „Override‟ khi bạn tạo 1 Find Window hoặc 1 Row-LOV trong
form của bạn
 WHEN–NEW–FORM–INSTANCE

45
FDRCSID(‟$Header: ... $‟);
APP_STANDARD.EVENT(‟WHEN–NEW–FORM–
INSTANCE‟);
–– app_folder.define_folder_block(‟template test‟,
‟folder_block‟, ‟prompt_block‟, ‟stacked_canvas‟,
‟window‟, ‟disabled functions‟);
–– app_folder.event(‟VERIFY‟);
Lời gọi APP_STANDARD.EVENT trong trigger này hỗ trợ chế độ
query-only được gọi bởi FND_FUNCTION.EXECUTE. Lời gọi
FDRCSID hỗ trợ hệ thống điều khiển mã nguồn của Oracle
Applications. Các lời gọi APP_FOLDER chỉ cho các sử dụng bên
trong của Oracle Applications. Các custom form không cần đến
FDRCSID hay APP_FOLDER, nhưng giữ lại chúng trong trigger
cũng không ảnh hưởng gì.
Thêm những code cần thiết trước code đã có.
 WHEN–NEW–RECORD–INSTANCE
APP_STANDARD.EVENT(‟WHEN–NEW–RECORD–
INSTANCE‟);
Trigger này quản lý trạng thái của menu và toolbar của Oracle
Applications
Tạo trigger mức block nếu cần ( kiểu xử lý „Before‟ )
 WHEN–NEW–BLOCK–INSTANCE
APP_STANDARD.EVENT(‟WHEN–NEW–BLOCK–
INSTANCE‟);
Trigger này quản lý trạng thái của menu và toolbar của Oracle
Applications
Tạo trigger mức block nếu cần ( kiểu xử lý „Before‟ )
 WHEN–NEW–ITEM–INSTANCE
APP_STANDARD.EVENT(‟WHEN–NEW–ITEM–INSTANCE‟);
Trigger này quản lý trạng thái của menu và toolbar của Oracle
Applications
Nếu thêm vào 1 lời gọi đến flexfields routine, thêm nó vào trước
lời gọi APP_STANDARD.EVENT. Nói chung không nên thêm các
code khác vào trong trigger này, vì sẽ tác động đến mọi item trong
form. Nếu cần thì tạo 1 trigger mức block hoặc item với kiểu xử lý
là „Before‟.

46
 Các trigger không được chỉnh sửa
 CLOSE_THIS_WINDOW
Trigger này gọi APP_CUSTOM.CLOSE_WINDOW khi chọn
“Action –> Close Window” trên menu.
 CLOSE_WINDOW
APP_CUSTOM.CLOSE_WINDOW(:SYSTEM.EVENT_WINDO
W);
Trigger này xử lý tất cả các sự kiện đóng window. Các code xử lý
nằm trong package APP_CUSTOM.CLOSE_WINDOW

 EXPORT
app_standard.event(‟EXPORT‟);
Trigger này xử lý lời gọi ”Action, Export” từ menu
 FOLDER_ACTION
app_folder.event(:global.folder_action);
Trigger này xử lý khi gọi các mục trên menu Folder.
 KEY–COMMIT
APP_STANDARD.EVENT(‟KEY–COMMIT‟);
Trigger này xử lý các commit trong các form bình thường hoặc các
form được gọi.
 KEY–EDIT
APP_STANDARD.EVENT(‟KEY–EDIT‟);
Trigger này thực hiện các hoạt động của flexfield, hoặc gọi
Calendar hay Editor.
 KEY–EXIT
APP_STANDARD.EVENT(‟KEY–EXIT‟);
Trigger này xử lý các sự kiện Close và rời khỏi chế độ enter-query.
 KEY–HELP
APP_STANDARD.EVENT(‟KEY–HELP‟);
Trigger này gọi hệ thống Window Help.

 LASTRECORD
APP_STANDARD.EVENT(‟LASTRECORD‟);

47
Trigger này xử lý sự kiện menu “Go–>Last Record”.

 MENU_TO_APPCORE
APP_STANDARD.EVENT(:global.menu_to_appcore);
Trigger này hỗ trợ menu Special

 STANDARD_ATTACHMENTS
atchmt_api.invoke;
Trigger này xử lý lời gọi của mục menu Attachments hoặc của nút
Attachments trên toolbar.

 WHEN–WINDOW–CLOSED
execute_trigger(‟CLOSE_WINDOW‟);
Trigger này tập trung các sự kiện đóng window từ Oracle
Applications hoặc menu Window Manager.

 WHEN–FORM–NAVIGATE
Bạn không thể sửa trigger này. Nó enable các hành động tiêu chuẩn
chính, như normalize 1 form đang được minimize khi form này
được navigate.
Để sử dụng sự kiện form này, gán cho biến global có tên là
GLOBAL.WHEN_FORM_NAVIGATE giá trị là tên của 1 trigger
do người dùng định nghĩa. Thường thì việc gán này được thực hiện
ngay trước khi gọi GO_FORM.

 ZOOM
appcore_custom.event(‟ZOOM‟);
Trigger này xử lý lời gọi của mục menu ”Action, Zoom” hoặc của
nút trên toolbar.

48
Thiết lập các thuộc tính của
các đối tượng
chứa(ContainerObject)

Các đối tượng chứa :


 module
 window ( modal và non-modal )
 canvas ( content và stacked )
 block
 region

Module :
 Lớp thuộc tính : form TEMPLATE tự động áp dụng lớp thuộc tính MODULE cho
module. Các thiết lập cho lớp này biến đổi tùy theo nền GUI.
 Tên module : tên module phải giống tên form. VD : tên module là GL01 thì tên
form là GL01.fmb
 Thuộc tính First Navigation Data Block : đặt cho thuộc tính này tên của block đầu
tiên mà người sử dụng tiếp xúc khi form chạy. ( không đặt theo tên của block
WORLD hay block CONTROL ). Thuộc tính này cũng quy định điểm đến của con
trỏ sau CLEAR_FORM hoặc sau hành động “Action -> Save and Proceed “ mặc
định.

Window :
 Window sẽ tự động kế thừa các chuẩn giao diện của nền GUI mà chúng đang
chạy trên đó từ form APPSTAND ( như các tính năng của frame, các font trên title
bar, các nút quản lý window ).

49
 ROOT_WINDOW là một window đặc biệt, không được sử dụng vì sẽ làm ảnh
hưởng đến toolbar và các đối tượng chuẩn khác của Oracle Application.
 Non-modal Window : cho phép người sử dụng tương tác với các window khác,
với thanh công cụ hay menu. Non-modal Window được dùng để thể hiện hầu hết
các thành phần trong ứng dụng.
 . Lớp thuộc tính : mọi non-modal window đều áp dụng lớp thuộc tính
WINDOW.
 . Thuộc tính Primary Canvas : nhập vào tên content canvas gắn với
window này.
 . Xác định tọa độ ( X,Y ) : lập trình định vị tọa độ window trong thủ tục
APP_CUSTOM.OPEN_WINDOW.
 . Tiêu đề ( Title ) : có thể thiết lập để thay đổi tùy theo nội dung window
hiển thị.
 . Kích thước : kích thước tối đa của window là 7.8 x 5 ( rộng x cao )
inches.
 . Đóng window : Bạn phải lập trình để thực hiện hành động đóng
window. Đóng window đầu tiên của một form sẽ đóng lại toàn bộ form
và các hành động khác. Lập trình hành động đóng này trong thủ tục
APP_CUSTOM.CLOSE_WINDOW.
 . Mở window : nếu bạn có đoạn mã nào muốn được thực hiện khi mở
window, đặt nó trong thủ tục APP_CUSTOM.OPEN_WINDOW. Bạn
phải thêm đoạn mã để điều khiển tọa độ block và định vị window. Khi
chuyển đến một khối nào đấy ( bằng GO_BLOCK ), window chứa block
đó sẽ tự động mở ra.
 . Nếu muốn tắt ( disable ) chức năng nào đó của menu, sử dụng
APP_SPECIAL.

 Modal Window : buộc người sử dụng chỉ thao tác trong cửa sổ đó (không thể
tương tác được với các cửa sổ khác), sau khi chấp nhận hoặc huỷ bỏ những thay
đổi đã thực hiện mới thoát được ra khỏi cửa sổ.
 . Lớp thuộc tính : sử dụng lớp thuộc tính WINDOW_DIALOG để tạo một
modal window.
 . Thuộc tính Primary Canvas : nhập vào tên content canvas gắn với
window này.
 . Vị trí window : modal window khi mở luôn ở chính giữa màn hình

50
 . Đóng window : modal window có thể đóng bằng cơ chế đóng cửa sổ
GUI ( kích chuột vào ô có dấu X góc trên bên phải ) hoặc đóng bằng lập
trình.

Canvas :
 Content Canvas :
 . Lớp thuộc tính : CANVAS
 . Kích thước : nên đặt kích thước canvas bằng với kích thước window
chứa nó.
 Stacked Canvas :
 . Lớp thuộc tính : CANVAS_STACKED
 . Thuộc tính Raise on Entry luôn đặt là Yes

Block :
 Lớp thuộc tính : BLOCK ( với những block trên non-modal window ),
BLOCK_DIALOG ( với những block trên modal window ).
 Nếu block dựa trên một bảng hoặc một view đơn ( view trên một bảng ), đặt thuộc
tính Key-Mode là Unique. Nếu block dựa trên view liên kết ( view trên nhiều bảng
), đặt Update Allowed là No. Phải có ít nhất một item trong block được đánh dấu là
primary key ( đặt thuộc tính Primary Key của nó là Yes ).
 Đặt thuộc tính Delete Allowed là No để không cho xoá trong block.
 Next and Previous Navigation Data Block : đặt các thuộc tính này của khối bằng
tên các khối có thứ tự duyệt sau ( next ) và trước ( previous ) khối đó. Với khối đầu
tiên, previous là chính nó, với khối sau cùng, next là chính nó.
 Context Block : được thể hiện trong các detail window, cung cấp ngữ cảnh và sao
chép các trường được thể hiện trong master window. Để tạo 1 context block, tạo
các display item trong cùng block giống như master block và đồng bộ trường
context theo trường master.
 Dialog Block : được thể hiện trong modal window, đòi hỏi user phải tương tác với
chúng trước khi chuyển qua cửa sổ khác.

51
 Xử lý các KEY – trigger : mặc dù trong modal window không thể tương tác với
menu và toolbar, ta vẫn có thể gọi một số tính năng bằng nhấn một số phím chức
năng trên bàn phím. Để tránh điều này, ta disable các Key – trigger cho block bằng
cách lập trình một KEY-OTHERS trigger gọi APP_EXCEPTION.DISABLED để
tắt mọi chức năng. Sau đó, ta có thể cho phép một vài chức năng có thể được thực
hiện bằng việc lập trình lại một số KEY – trigger, như :

( Với block cho phép nhiều bản ghi )

 . Ta cũng có thể để enable cho các KEY - trigger của block, và chỉ
disable một số bằng cách gọi APP_EXCEPTION.DISABLED trong
những KEY – trigger nào ta muốn disable.
 . Navigation ( điều hướng ): ngăn cản việc chuyển focus ra bên ngoài
modal window bằng cách : không được đặt Navigation Style là Change
Data Block, next và previous của block đặt là chính block đó.

52
 Data Block không có bảng cơ sở ( base table ) : sử dụng các trigger giao dịch (
ON-INSERT, ON-LOCK …) nếu các block này phải xử lý commit.
 Data Block một bản ghi : cho phép user xem được các bản ghi của một thực thể,
nhưng tại mỗi thời điểm chỉ nhìn thấy một bản ghi.
 Data Block nhiều bản ghi : cho phép user xem được các bản ghi của một thực thể,
nhưng tại mỗi thời điểm có thể thấy nhiều bản ghi.
 . Tạo Current Record Indicator : tạo một text item trong block không có
detail block ứng với nó. Thiết lập lớp thuộc tính cho nó là
CURRENT_RECORD_INDICATOR và tạo trigger WHEN-NEW-
ITEM-INSTANCE cho nó, trong trigger đó gọi
GO_ITEM(tên_block.tên_field). Mỗi lần indicator này được click thì con
trỏ sẽ chuyển đến trường đầu tiên của bản ghi tương ứng.
 . Tạo Drill-down Indicator : tương tự như Current Record Indicator
nhưng là cho block có một hoặc nhiều detail block ứng với nó.

 Combination Block : một kiểu định dạng các trường lai giữa kiểu định dạng đơn
bản ghi và đa bản ghi, trong đó mỗi kiểu định dạng tồn tại trên window riêng của
chúng, nhưng tất cả các trường của cả 2 kiểu định dạng nằm trong cùng một block.

 Quan hệ Master – Detail :


 . Đặt thuộc tính Coordination là Prevent Masterless Operation để các bản
ghi chi tiết luôn luôn tương ứng với bản ghi chính của nó.
 . Đặt thuộc tính Master Deletes là Non-Isolated nếu không cho phép xóa
các bản ghi ở cả master table và detail table, Isolated nếu chỉ cho xoá ở
bảng master, và Cascading nếu cho phép xoá ở cả 2 bảng. Tuy nhiên
không nên sử dụng Cascading mà nên dùng Isolated để xóa ở bảng
master, sau đó viết một thủ tục cho bảng master thực hiện lệnh xoá các
bản ghi detail tương ứng.
 . Nếu ( master ) block đầu tiên của form không tự động truy vấn, gọi
do_key(„execute_query‟); trong trigger WHEN-NEW-FORM-
INSTANCE.

53
 Thiết lập thuộc tính WHERE Clause động : mỗi lần truy vấn đưa vào điều kiện lọc
khác nhau.

Region :
 Region là 1 nhóm các trường ( field ). Hầu hết các region chỉ đơn thuần là sự trình
bày thẩm mĩ, ví như một frame ( box ) bao lấy nhóm các trường liên quan, hoặc
một frame ( line ) kẻ bên trên nhóm các trường có quan hệ với nhau. Khi con trỏ ở
trong một region, nó sẽ duyệt theo thứ tự đi qua tất cả các item trong region đó
trước khi chuyển qua các field khác ngoài region.
 . Tabbed Region : xuất hiện trên tab canvas
 . Alternative Region : xuất hiện trên stacked canvas
 . Overflow Region

54
Thiết lập các thuộc tính của
các đối tượng Widget

Text Item :
 Các lớp đối tượng :
 TEXT_ITEM : thường dùng nhất
 TEXT_ITEM_DISPLAY_ONLY : dùng cho các trường không cho phép
người dùng nhập vào
 TEXT_ITEM_MULTILINE
 TEXT_ITEM_DATE : dùng cho các trường date
 Thuộc tính Query Length : thiết lập độ dài cho xâu truy vấn.
 WHEN-VALIDATE-ITEM : trigger này kích hoạt khi giá trị của trường có sự thay
đổi.
 Các trường date : Các trường date người dùng nhập vào nên sử dụng Calendar.
 Kiểu dữ liệu : DATE ( user không cần nhập giờ phút ) , DATETIME (
user phải nhập cả ngày và giờ phút ), TIME ( user chỉ được nhập giờ ).
Đặt giá trị mặc định cho trường bằng ngày hiện tại mà không tính đến giờ
bằng $$DBDATE$$, đặt giá trị bằng cả ngày và giờ hiện tại bằng
$$DBDATETIME$$, đặt giá trị bằng giờ hiện tại mà bỏ qua ngày bằng
$$DBTIME$$.
 Độ dài trường : 11 kí tự ( chỉ nhập ngày ) và 20 kí tự ( nhập cả ngày và
giờ ). Oracle Forms mặc định kiểu định dạng ( format ) của trường dựa

55
theo biến môi trường NLS_DATE_FORMAT.
 Validation trường date : nên validate trường date ở mức bản ghi thay vì
mức item, nó sẽ giúp việc sửa lỗi dễ hơn.

Display Item :
Không cho phép người sử dụng tương tác với nó, chỉ đơn thuần hiển thị dữ liệu và không nhận focus.
Lớp thuộc tính : DYNAMIC_TITLE, DYNAMIC_PROMPT, DISPLAY_ITEM

Poplist : lưu dữ liệu dưới dạng danh sách ( kích cỡ nhỏ ) các giá trị có thể.
 Lớp thuộc tính : LIST
 Giới hạn : độ rộng của một phần tử list tối đa là 30 kí tự.
 Có thể tha đổi nội dung phần tử trong list khi chạy

Option Group :
Lớp thuộc tính : RADIO_GROUP ( cho nhóm ) và RADIO_BUTTON ( cho các đối tượng
trong nhóm )

Check Box :
Lớp thuộc tính : CHECKBOX ( thông dụng ), CHECKBOX_COORDINATION ( cho check
box tọa độ ).

Button ( Nút ) :
 Nút có thể là nút chữ, hoặc nút hình. Nút nên được đặt cùng block với các đối
tượng mà nó tương tác.
 Lớp thuộc tính : BUTTON ( nút chữ ) , BUTTON_ICONIC ( nút hình )
 Nút hình không thể kích hoạt từ bàn phím.
 Hầu hết các nút không thể kích hoạt trong chế độ Enter-Query
 Các nút nên gọi APP_STANDARD.APP_VALIDATE và truyền một scope ( vùng
validate ) trước khi thực hiện hành động của chúng. Điều này đảm bảo các bản ghi
được kiểm tra tính hợp lệ trước khi hành động được thực hiện, và nút thực hiện
hành động trên block mà nó mong muốn.

56
List of Values ( LOV )
 Lớp thuộc tính : LOV
 Nên tạo LOV theo view.
 Đặt title cho LOV theo tên đối tượng mà nó chứa. Độ rộng cột phải đủ để thể hiện
giá trị trường.
 Nếu một item có LOV, có thể đặt thuộc tính Validate from List của nó là Yes để
chỉ chấp nhận những giá trị nhập vào có trong LOV.
 Để LOV luôn tự cập nhật những giá trị mới mỗi khi được gọi, đặt Automatic
Refresh là Yes. Nếu LOV có nhiều bản ghi, đặt Filter Before Display là Yes để
nhắc user giới hạn phạm vi tìm kiếm mỗi lần gọi LOV.
 Để gọi được LOV trong chế độ Enter-Query, tạo 1 trigger KEY-LISTVAL trên đối
tượng gọi LOV:

Trong chế độ Enter-Query, giá trị trả về của LOV phải được trả về trường mà từ đó LOV được gọi

Thiết lập các thuộc tính cho item :


 Sử dụng APP_ITEM_PROPERTY.SET_PROPERTY : dùng để thiết lập các thuộc
tính : ALTERABLE, ALTERABLE_PLUS, ENTERABLE, DISPLAYED,
ENABLED, REQUIRED. Các thuộc tính khác dùng thủ tục gốc
SET_ITEM_PROPERTY của Oracle Form.
 Thuộc tính ALTERABLE cho phép ( hoặc không cho phép ) thay đổi một
instance ( hàng ) của item mặc cho bản ghi là mới hoặc là bản ghi truy
vấn từ CSDL.
. Thủ tục :
app_item_property.set_property ( itemid, ALTERABLE, PROPERTY_ON);
tương đương với
set_item_instance_property(itemid, CURRENT_RECORD,
INSERT_ALLOWED, PROPERTY_ON);
set_item_instance_property(itemid, CURRENT_RECORD, UPDATEABLE,
PROPERTY_ON);
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_ON);
set_item_property(itemid, UPDATEABLE, PROPERTY_ON);

57
. Thủ tục :
app_item_property.set_property(itemid, ALTERABLE,PROPERTY_OFF);
tương đương với
set_item_instance_property(itemid, CURRENT_RECORD,
INSERT_ALLOWED, PROPERTY_OFF);
set_item_instance_property(itemid, CURRENT_RECORD, UPDATEABLE,
PROPERTY_OFF);

 Thuộc tính ALTERABLE_PLUS cho phép hoặc không cho phép thay
đổi tất cả các instance ( hàng ) của item, mặc cho bản ghi là mới hoặc
được truy vấn từ cơ sở dữ liệu.
. Thủ tục :
app_item_property.set_property(itemid, ALTERABLE_PLUS,
PROPERTY_ON);
tương đương với :
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_ON);
set_item_property(itemid, UPDATEABLE, PROPERTY_ON);
. Thủ tục :
app_item_property.set_property(itemid, ALTERABLE_PLUS,
PROPERTY_OFF);
tương đương với :
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_OFF);
set_item_property(itemid, UPDATEABLE, PROPERTY_OFF);

 Thuộc tính ENTERABLE dùng để enable hoặc disable một instance của
item, là sự mở rộng của ALTERABLE bằng việc điều khiển thêm thuộc
tính NAVIGALBE.
. Thủ tục :
app_item_property.set_property(itemid,ENTERABLE,
PROPERTY_ON);
tương đương với :
set_item_instance_property(itemid,CURRENT_RECORD,
INSERT_ALLOWED, PROPERTY_ON);
set_item_instance_property(itemid,CURRENT_RECORD,
UPDATEABLE, PROPERTY_ON);

58
set_item_instance_property(itemid,CURRENT_RECORD,
NAVIGABLE, PROPERTY_ON);
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_ON);
set_item_property(itemid, UPDATEABLE, PROPERTY_ON);
set_item_property(itemid, NAVIGABLE, PROPERTY_ON);
( đặt giá trị cho cả item và item-instance để tạo hiệu quả đồng nhất )
. Thủ tục :
app_item_property.set_property(itemid,ENTERABLE,
PROPERTY_OFF);
tương đương với :
set_item_instance_property(itemid,CURRENT_RECORD,
INSERT_ALLOWED, PROPERTY_OFF);
set_item_instance_property(itemid,CURRENT_RECORD,
UPDATEABLE, PROPERTY_OFF);
set_item_instance_property(itemid,CURRENT_RECORD,
NAVIGABLE, PROPERTY_Off);

 Thuộc tính DISPLAY điều khiển việc ẩn, hiện item cũng như reset lại
các thuộc tính cụ thể mà Oracle Form tự động thiết lập khi ẩn một item
nào đó.
. Thủ tục sau :
app_item_property.set_property(itemid, DISPLAYED,
PROPERTY_ON);
tương đương với :
set_item_property(itemid, DISPLAYED, PROPERTY_ON);
nếu item không phải là display item thì thiết lập thêm :
set_item_property(itemid, ENABLED, PROPERTY_ON);
set_item_property(itemid, NAVIGABLE, PROPERTY_ON);
nếu item không phải là display item hay nút, thiết lập thêm :
set_item_property(itemid, QUERYABLE, PROPERTY_ON);
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_ON);
set_item_property(itemid, UPDATEABLE, PROPERTY_ON);
. Thủ tục sau :
app_item_property.set_property(itemid, DISPLAYED,
PROPERTY_OFF);

59
tương đương với
set_item_property(itemid, DISPLAYED, PROPERTY_OFF);

 Thuộc tính ENABLE dùng để enable hay disable một item nào đó, xử lý
với APP_ITEM_PROPERTY.SET_PROPERTY khác với xử lý gốc (
native behavior ) của Oracle Forms ở chỗ khi re-enable thì sẽ reset lại các
thuộc tính liên quan đã được Oracle Forms đặt tự động khi disable.
. Thủ tục : app_item_property.set_property(itemid,
ENABLED,PROPERTY_ON);
tương đương với ( nếu item là text hoặc list ) :
set_item_property(itemid, INSERT_ALLOWED, PROPERTY_ON);
set_item_property(itemid, UPDATEABLE, PROPERTY_ON);
set_item_property(itemid, NAVIGABLE, PROPERTY_ON);
tương đương với ( nếu item là button ) :
set_item_property(itemid, ENABLED, PROPERTY_ON);

 Thuộc tính REQUIRED quyết đinh một item có bắt buộc phải được nhập
dữ liệu hay không, là một thuộc tính ở item-level, tức là tác động lên tất
cả các instance của item. Nếu chỉ muốn tác động lên một instance cụ thể
nào đó của item, ta có thể dùng thủ tục dựng sẵn của Oracle Forms là :
SET_ITEM_INSTANCE_PROPERTY.
. app_item_property.set_property(itemid, REQUIRED, PROPERTY_ON);
. app_item_property.set_property(itemid, REQUIRED, PROPERTY_OFF);

Một số lưu ý :
 Gọi APP_ITEM_PROPERTY.SET_PROPERTY tương đương với một tập các xử
lý thuộc tính có liên quan với nhau nếu thiết lập từng bước.
 Một số thuộc tính như ALTERABLE hay ENTERABLE chỉ có thể thiết lập khi
chạy ( runtime ) vì nó tác động lên từng instance.
 Hầu hết các Visual Attribute được triển khai tự động bởi các APPCORE routine,
trừ một số visual attribute sau ( mà người phát triển phải tự lập trình để thực hiện )
: DATA_DRILLDOWN, DATA_SPECIAL, DATA_REQUIRED

60
Điều khiển hoạt động của
Window, Block, và Region

Điều khiển hoạt động của Window


 Định vị window khi nó được mở :

 CASCADE : cửa sổ con chồng lên cửa sổ chính, lệch chéo xuống 0.3‟‟.
Thường dùng cho các cửa sổ detail.
 RIGHT, BELOW : cửa sổ con mở bên phải, hoặc bên dưới cửa sổ chính,
không che cửa sổ chính.
 OVERLAP : cửa sổ detail chồng lên cửa sổ chính, lệch xuống dưới 0.3‟‟.
 CENTER : cửa sổ mở chính giữa cửa sổ khác, thường dùng cho modal
window.
 FIRST_WINDOW : định vị cửa sổ ngay dưới toolbar, thường dùng cho
cửa sổ chính.

61
 Đóng Window :
 Các sự kiện đóng non-modal window ( không phải là modal window )
đều chuyển tới APP_CUSTOME.CLOSE_WINDOW. Code mặc định
được viết trong form TEMPLATE thực hiện những việc sau :
. Nếu form đang ở chế độ Enter-Query, APP_CUSTOM sẽ gọi :
APP_EXCEPTION.DISABLED.
. Trường hợp ngược lại, nếu con trỏ đang ở trong window chuẩn bị đóng,
APP_CUSTOM thực hiện do_key(„PREVIOUS_BLOCK‟) để đưa con
trỏ thoát khỏi window hiện tại.
. Cuối cùng, APP_CUSTOM ẩn window bằng
HIDE_WINDOW(„<name>‟)
 Nếu con trỏ vẫn nằm trong window, window sẽ tự động mở lại sau khi
được đóng. Để đóng window đầu tiên ( tức là đóng form ), gọi
APP_WINDOW.CLOSE_FIRST_WINDOW
Example :
In a form with windows ”Header,” ”Lines,” and ”Shipments,” where
Lines is a detail of Header, and Shipments is a detail of Lines, the logic
to close the windows is as follows:
PROCEDURE close_window (wnd VARCHAR2)
IS
IF wnd = ‟HEADER‟ THEN
––
–– Exit the form
––
app_window.close_first_window;
ELSIF wnd = ‟LINES‟ THEN
––
–– Close detail windows (Shipments)
––
app_custom.close_window(‟SHIPMENTS‟);
––
–– If cursor is in this window,
–– move it to the HEADER block

62
––
IF (wnd =
GET_VIEW_PROPERTY(GET_ITEM_PROPERT
Y(
:SYSTEM.CURSOR_ITEM,ITEM_CANVAS),
WINDOW_NAME)) THEN
GO_BLOCK(‟HEADER‟);
END IF;
ELSIF wnd = ‟SHIPMENTS‟ THEN
––
–– If cursor is in this window,
–– move it to the LINES block
––
IF (wnd =
GET_VIEW_PROPERTY(GET_ITEM_PROPERT
Y(
:SYSTEM.CURSOR_ITEM, ITEM_CANVAS),
WINDOW_NAME)) THEN
GO_BLOCK(‟LINES‟);
END IF;
END IF;
––
–– THIS CODE MUST REMAIN HERE. It ensures
–– the cursor is not in the window that will
–– be closed by moving it to the previous block.
––
IF (wnd =
GET_VIEW_PROPERTY(GET_ITEM_PROPERT
Y(
:SYSTEM.CURSOR_ITEM, ITEM_CANVAS),
WINDOW_NAME)) THEN

63
DO_KEY(‟PREVIOUS_BLOCK‟);
END IF;
––
–– Now actually close the designated window
––
HIDE_WINDOW(wnd);
END close_window;
 Thiết lập title động cho window :

 Nếu muốn thay đổi base title của một window, gọi :
SET_WINDOW_PROPERTY(…TITLE…). Bất kì lời gọi
APP_WINDOW.SET_TITLE nào trong tương lai sẽ bảo toàn base title
mới đó.
 Điều khiển hoạt động của Block
 Lập trình cho các quan hệ Master-Detail : Khi detail block và master
block nằm trong 2 cửa sổ khác nhau (đều là non-modal window), detail
block phải cung cấp một cơ cấu cho phép user chuyển đổi giữa
coordination tức thì và coordination trì hoãn. Khi detail block là visible,
chọn coordination tức thì sẽ cho phép các detail record thay đổi khi
master record thay đổi. Còn khi detail block là không visible, nên chọn
coordination là trì hoãn. Sử dụng thủ tục
APP_WINDOW.SET_COORDINATION để coordinate các block.
Ví dụ : trong ví dụ sử dụng các đối tượng sau :
• Master block ORDERS, trong window ORDERS
• Detail Block LINES, trong window LINES
• Relation : ORDERS_LINES

64
• Coordination check box : CONTROL.ORDERS_LINES
• Nút để navigate tới LINES block : CONTROL.LINES
+ Bước 1 : tạo 1 nút để navigate tới detail block
+ Bước 2 : tạo 1 coordination check box ( đặt trong control block )
trong cửa sổ detail cho phép người dùng chọn coordination tức thì
hoặc coordination trì hoãn khi cửa sổ được mở.
+ Bước 3 : tạo 1 thủ tục xử lý item như sau :
PACKAGE BODY control IS
PROCEDURE lines(EVENT VARCHAR2)
IS
BEGIN
IF (EVENT = ‟WHEN–BUTTON–
PRESSED‟) THEN
app_custom.open_window(‟LINES‟);
END IF;
END lines;
PROCEDURE orders_lines(EVENT
VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–CHECKBOX–
CHANGED‟) THEN
APP_WINDOW.SET_COORDINATION(E
VENT,
:control.orders_lines, ‟ORDERS_LINES‟);
END IF;
END orders_lines;
END control;
 Bước 4 : sửa package APP_CUSTOM như sau :

65
 Bước 5 : Gọi các thủ tục xử lý sự kiện và trường đã viết ở trên trong các
trigger :

 Triển khai một Combination Block : Mỗi item trong 1 block có thuộc tính Number
of Items Display của riêng nó, nên bạn có thể tạo một single block chứa vài item
là các single-record ( detail ) và vài item khác là multi-record ( Summary ). Khi
triển khai một combination block, hầu hết các item xuất hiện 2 lần, nên
coordination của các giá trị trong các item này phải được quản lý. Thuộc tính
Synchronize with Item tự động thực hiện điều này. Bạn điều khiển việc navigate
tới các phần của block trong các tình huống khác nhau bằng cách sử dụng một
trường gọi là Switcher, là trường được navigate đầu tiên trong block. Khi con trỏ
chuyển tới Switcher, nó ngay lập tức sẽ được chuyển đến item đầu tiên trong phần
Detail hoặc phần Summary của block.
Các bước triển khai :
 Bước 1 : Thiết lập Combination Block
Tạo 2 cửa sổ và các canvas để chứa các phần khác nhau của block của bạn.
Với phần Summary, sử dụng các non-mirror item. Nhân đôi các item này để
tạo phần Detail. Phần Detail của Combination Block nên có thứ tự đầu tiên.

66
Như thế khi user không điền vào 1 required item và thử commit block, Oracle
Forms sẽ đặt con trỏ vào item đó trong block Detail.
 Bước 2 : Thiết lập các thuộc tính cho item
. Với các đối tượng ảnh (là bản sao của đối tượng gốc), đổi tên chúng để phán
ánh mối quan hệ với đối tượng gốc (ví dụ đối tượng gốc tên là status thì đối
tượng ảnh tên là status_mir). Thiết lập thuộc tính Synchronize with Item
property và đảm bảo là thuộc tính Database Item được đặt là Yes nếu các đối
tượng được đồng bộ ứng với các cột của bảng cơ sở.
. Thiết lập thuộc tính Number of Records Displayed ở mức block cho phần
Summary. Các item trong block sẽ cùng nhận giá trị này, nếu như không đặt
lại thuộc tính đó của chúng. Đặt lại thuộc tính Number of Records Displayed
bằng 1 cho các đối tượng trong phần Detail.
. Để ngăn người dùng chuyển tab ra khỏi Detail và vào trong Summary, thiết
lập thuộc tính Previous Navigation Item cho đối tượng Detail đầu tiên và
thuộc tính Next Navigation Item cho đối tượng Detail cuối cùng.
. Để chuyển tab đồng thời với chuyển bản ghi trong 1 block nhiều bản ghi, gọi
APP_COMBO.KEY_PREV_ITEM trong trigger KEY–PREV–ITEM của đối
tượng đầu tiên trong Summary và gọi next_record trong trigger KEY–NEXT–
ITEM của đối tượng cuối cùng của phần Summary.
. Nếu chuyển đổi 1 block đã có thành combination block, phải thay đổi các
tham chiếu trong các trigger đã có, vì bây giờ mỗi trường đều tồn tại 2 phiên
bản.
 Bước 3 : Drilldown Record Indicator
Thêm 1 Drilldown Record Indicator thực hiện lệnh :
execute_trigger(‟SUMMARY_DETAIL‟);
 Bước 4 : Tham số Record Count
. Tạo 1 tham số để lưu số bản ghi của phần block (Summary hay Detail) mà
bạn đang ở trong. Đặt tên tham số là <block>_RECORD_COUNT, trong đó
<block> là tên của combination block. Chuẩn đặt tên này có liên quan đến
code trong APPCORE. Kiểu dữ liệu của tham số là number, và giá trị mặc
định là 2 (để con trỏ ban đầu đặt trong Summary) hoặc 1 (để con trỏ ban đầu
đặt trong Detail).
. Tạo trigger mức block WHEN–NEW–ITEM–INSTANCE (Execution
Hierarchy: Before) chứa code :
:PARAMETER.<block>_RECORD_COUNT :=

67
GET_ITEM_PROPERTY(:SYSTEM.CURSOR_ITEM,
RECORDS_DISPLAYED);
 Bước 5 : Switcher
Tạo 1 text item và gán cho nó lớp thuộc tính SWITCHER. Nó là item được
navigate đầu tiên trong block. Đặt nó vào trong toolbar canvas. Tạo 1 trigger
WHEN–NEW–ITEM–INSTANCE mức item cho nó (Execution Hierarchy :
Override) chứa code :

IF(:PARAMETER.<block>_RECORD_COUNT > 1)
THEN
GO_ITEM(‟<first Summary field>‟);
ELSE
APP_WINDOW.SET_WINDOW_POSITION(‟<Detail
window>‟,
‟OVERLAP‟, ‟<Summary window>‟);
GO_ITEM(‟<first Detail field>‟);
END IF;
 Bước 6 : Summary/Detail Menu Item
. Tạo 1 trigger SUMMARY_DETAIL mức block (Execution Hierarchy:
Override) chứa code :
IF GET_ITEM_PROPERTY(:SYSTEM.CURSOR_ITEM,
RECORDS_DISPLAYED) > 1 THEN
:PARAMETER.<block>_RECORD_COUNT := 1;
ELSE
:PARAMETER.<block>_RECORD_COUNT := 2;
END IF;
GO_ITEM(‟<block>.Switcher‟);
Đoạn code này thay đổi giá trị trong tham số <block>_RECORD_COUNT
để Switcher chuyển con trỏ tới phần còn lại trong block. Nó được thực thi
khi người dùng chọn “Go -> Summary/Detail”.
. Tạo 1 trigger mức block PRE–BLOCK (Execution Hierarchy:
Override) chứa code :

68
APP_SPECIAL.ENABLE(‟SUMMARY_DETAIL‟,
PROPERTY_ON);
. Cuối cùng, tạo 1 trigger mức form PRE–BLOCK (Execution
Hierarchy:Override) chứa code :
APP_SPECIAL.ENABLE(‟SUMMARY_DETAIL‟,
PROPERTY_OFF);
. Nếu tất cả các block đều là combination, bật SUMMARY_DETAIL ở
mức form, bỏ qua trigger mức block. Nếu có nhiều block là combination,
bật SUMMARY_DETAIL ở mức form, và tắt nó ở mức block với các
block không phải combination.
 Bước 7 : Định vị window và con trỏ khi mở form
Nếu combination block của bạn là block đầu tiên trong form, định vị 2 cửa sổ
của nó trong trigger PRE-FORM với những lời gọi sau :
APP_WINDOW.SET_WINDOW_POSITION(’<Summary window>’,
’FIRST_WINDOW’);
APP_WINDOW.SET_WINDOW_POSITION(’<Detail window>’,
’OVERLAP’, ’<Summary window>’);
Thường thì người dùng vào Summary trước, tuy nhiên nếu muốn vào Detail
trước, thiết lập tham số <block>_RECORD_COUNT bằng 1 trong trigger
PRE-FORM.

Lập trình cho các Tabbed Regions


 Một số khái niệm :
 Tabbed Region : một nhóm các tab liên quan với nhau, còn gọi là tab
canvas.
 Tab Page : trang tab trong tabbed region, nơi thể hiện một nhóm các item
liên quan.
 Topmost tab page : trang tab trên cùng, hay trang tab đang được chọn và
đang thể hiện.
 Fixed Field : là trường hay item xuất hiện trên nhiều, hoặc trên tất cả, các
tab page.
 Alternative Region Field : là trường chỉ xuất hiện duy nhất trên môt tab
page nào đó và không có mặt trên các tab page khác.

69
 Control : là cách gọi khác cho field, item hay widget.

Hành động của tabbed region :


Hành động mong muốn là mở ra một tab page và chuyển focus tới một trường thích hợp khi
tab đó được click. Hành động này cần được lập trình vì hành động mặc định của Oracle Forms là mở
tab và đặt focus trên chính đối tượng tab đó.
 Keyboard-only Operation : người dùng truy cập vào tab qua phím nóng
trên keyboard.
 Dynamic Tab Layouts : ẩn hay hiện một tab linh động tuỳ theo dữ liệu
 Other Behavior : các tab nên vận hành được trong chế độ enter-query.

3 mức khó trong lập trình :


 Simple (đơn giản) : không cần scrollbar, không có fixed field. Mỗi tab sẽ tương
ứng với 1 block riêng biệt trong form.
 Medium (trung bình) : có scrollbar, nhưng không có fixed field. Mỗi tab sẽ có một
thanh cuốn ngang để xem các trường và thanh cuốn dọc để xem tất cả các bản ghi.
Mỗi tab sẽ tương ứng với một multi-row block riêng biệt.
 Difficult ( khó ) : có fixed field ( và có hoặc không có scrollbar ) : một multi-row
block có thể dàn trải trên nhiều tab page. Với fixed field, nên đặt các item vào
trong stacked-canvas nằm bên trên tab page.

 Các bước triển khai tabbed region :


 Bước 1 : Tạo tab canvas. Đặt tên cho tab canvas theo chuẩn
TAB_ENTITY_REGIONS (ví dụ với thực thể LINES, đặt tên cho tab
canvas là TAB_LINES_REGIONS). Thiết lập lớp thuộc tính là
TAB_CANVAS. Thiết lập thuộc tính Window cho tab canvas để đặt nó
vào đúng cửa sổ. Nếu đặt sai, bạn sẽ không sử dụng được “View ->
Stacked Views” trong Form Builder để hiển thị tab canvas trên content
canvas.
 Bước 2 : Điều chỉnh tab canvas. Thiết lập thứ tự của tab canvas sau
content canvas và trước bất kì stacked canvas nào sẽ xuất hiện đằng trước
nó. Điều chỉnh viewport của tab canvas trong Layout Editor. Hiển thị
content canvas cùng lúc để dễ định vị tab canvas.

70
 Bước 3 : Tạo các tab page. Với mức trung bình và mức khó, tên của các
tab page phải phù hợp với tên của các stacked canvas “alternative region”
tương ứng với chúng.
 Bước 4 : Hiệu chỉnh các tab page. Thiết lập lớp thuộc tính là
TAB_PAGE. Đặt label cho mỗi tab page. Thiết lập thứ tự cho các tab
page trong Object Navigator.
 Bước 5 : Riêng với mức khó, tạo fixed field stacked canvas. Đặt tên nó là
tab_canvas_FIXED. Thiết lập thứ tự cho nó sau tab canvas nhưng trước
bất kì stacked canvas “alternative region” nào mà bạn tạo cho mức khó.
Thiết lập lớp thuộc tính cho nó là
CANVAS_STACKED_FIXED_FIELD. Chỉnh để viewport của fixed
field canvas nằm trong viewport của tab canvas.
 Bước 6 : Với mức trung bình và mức khó, tạo các stacked canvas
“alternative region”. Tất cả các canvas này phải có cùng vị trí và kích
thước viewport. Kiểm tra thuộc tính Visible của các stacked canvas
“alternative region”, chỉ để canvas nào xuất hiện đầu tiên có thuộc tính
này là Yes.
Với mức khó, các canvas “alternative region” này sẽ che khuất một phần
(chứ không phải là tất cả) của canvas fixed field. Cần đảm bảo là vị trí và
kích thước viewport của alternative region canvas liên hệ phù hợp với fixed
field canvas. )
 Bước 7 : Đặt các item của bạn vào các tab page hay stacked canvas thích
hợp. Đặt các scrollbar của block (nếu có) ở gần cạnh phải canvas. Nếu
đang sử dụng stacked canvas, đảm bảo rằng stacked canvas không chồng
lên các trường được đặt trực tiếp vào trong tab page. Tương tự, các
stacked canvas “alternative region” cũng không được chồng lên các item
trong stacked canvas fixed field.
 Bước 8 : Hiệu chỉnh layout của bạn. Đặt các tiêu đề tương ứng cho các
trường. Khi hiệu chỉnh, lưu ý căn chỉnh các đối tượng hợp lý để đảm bảo
tính thẩm mĩ, dễ nhìn.
 Bước 9 : Lập trình cho tab handler. Oracle cung cấp 2 file mẫu giúp lập
trình cho handler dễ hơn :
. FNDTABS.txt cho mức dễ và mức trung bình
. FNDTABFF.txt cho trường hợp fixed field (mức khó)
Hai file này nằm trong thư mục Resource (trong thư mục FND). Copy text
từ file vào trong form rồi sửa lại code cho phù hợp với các đối tượng và các

71
hành động trong form. Tham khảo các comment có trong file để sửa code
được dễ hơn.
 Bước 10 : Gọi các tab handler từ trigger. Tạo 1 trigger mức form
WHEN–TAB–PAGE–CHANGED, và gọi handler từ trigger này. Trigger
nên truyền sự kiện WHEN–TAB–PAGE–CHANGED tới handler, ví dụ :
MY_PACKAGE.TAB_MY_ENTITY_REGIONS(‟WHEN–
TAB–PAGE–CHANGED‟);
Tạo 1 trigger mức block (Execution Hierarchy Style: Before) WHEN–
NEW–ITEM–INSTANCE để gọi tới handler của bạn, ví dụ :
MY_PACKAGE.TAB_MY_ENTITY_REGIONS(‟WHEN–
NEW–ITEM–INSTANCE‟);

72
Cho phép hoạt động truy vấn

Query Find :
 Có 2 hình thức triển khai cho Query Find. Một sẽ hiển thị một Row-LOV trong đó
có các hàng để bạn chọn một. Một sẽ mở ra cửa sổ tìm kiếm ( Find window ), trong
đó có các trường mà người sử dụng có thể muốn dùng để chọn dữ liệu. Chỉ sử
dụng 1 hình thức triển khai cho mỗi block cụ thể. Tất cả các block có thể truy vấn
trong form nên hỗ trợ Query Find.
 Gọi Query Find khi mở form : nếu muốn một Row-LOV hoặc Find Window hiện
ngay lập tức khi mở form, gọi EXECUTE_TRIGGER( „QUERY_FIND‟ ); ở cuối
trigger WHEN-NEW-FORM-INSTANCE.

Triển khai Row-LOV


 Để triển khai một Row-LOV, tạo 1 LOV để chọn ra khoá chính của hàng (mà
người sử dụng muốn) để đưa vào trong 1 tham số form, sau đó copy giá trị này vào
trong trường khoá chính của block chứa kết quả truy vấn ngay trước lúc thực hiện
truy vấn.
 Xét 1 ví dụ với block DEPT dựa trên bảng DEPT với các cột DEPTNO, DNAME,
LOC. Các bước triển khai như sau :
 Bước 1 : Tạo 1 tham số cho khoá chính.
Tạo 1 tham số form để lưu khoá chính chọn từ LOV. Nếu Row-LOV là dành
cho detail block, bạn không cần tạo tham số để lưu khoá ngoại, mà hãy thêm
vào mệnh đề WHERE của nhóm bản ghi ( sẽ được tạo ở bước sau ) tên cột kết
nối. Thiết lập kiểu dữ liệu và độ dài thích hợp cho tham số.
Ví dụ ta tạo tham số DEPTNO_QF tương ứng với block DEPT.
 Bước 2 : Tạo 1 LOV
Tạo 1 LOV chứa các cột cần thiết để người dùng có thể xác định đuợc hàng
mình muốn chọn. Nếu Row-LOV là cho detail block, thêm cột kết nối ( khoá
ngoại ) vào mệnh đề WHERE của nhóm bản ghi ứng với LOV. Khoá chính (
chọn từ LOV ) sẽ được trả về cho tham số.
Ví dụ ta tạo 1 LOV là DEPT_QF chứa 2 cột là DEPTNO và DNAME. Đặt

73
đối tượng nhận giá trị trả về của DEPTNO là DEPTNO_QF.
 Bước 3 : Tạo 1 trigger PRE-QUERY
Tạo 1 trigger PRE-QUERY ở mức block (Execution Hierarchy: Before) chứa
đoạn mã sau :
IF :parameter.G_query_find = ‟TRUE‟ THEN
<Primary Key> := :parameter.<Your parameter>;
:parameter.G_query_find := ‟FALSE‟;
END IF;
Với khoá chính gồm nhiều thành phần, bạn cần nhiều lệnh gán cho khoá
chính. Tham số G_query_find đã có sẵn trong form TEMPLATE.
Ví dụ ta tạo trigger PRE-QUERY chứa đoạn mã sau :
IF :parameter.G_query_find = ‟TRUE‟ THEN
:DEPT.DEPTNO := :parameter.DEPTNO_QF
:parameter.G_query_find := ‟FALSE‟;
END IF;
 Bước 4 : Tạo 1 trigger QUERY_FIND
Cuối cùng, tạo 1 trigger ( loại trigger tự tạo ) mức block tên là
QUERY_FIND (Execution Hierarchy: Override) chứa mã :
APP_FIND.QUERY_FIND(‟<Your LOV Name>‟);
Ví dụ ta tạo trigger chứa : APP_FIND.QUERY_FIND(‟DEPT_QF‟);

Triển khai Find Window


 Để triển khai 1 Find Window, tạo thêm 1 window chứa các trường mà người dùng
thường hay chọn khi bắt đầu thực hiện tìm kiếm và copy tất cả các giá trị của item
từ block đó vào trong block chứa kết quả truy vấn ngay trước khi thực hiện truy
vấn.
 Trong ví dụ mà ta sẽ xem xét, có 1 block dựa trên bảng EMP, là block chứa kết quả
truy vấn. Khoá chính của bảng EMP là EMPNO. Block còn chứa một trường kiểu
date là HIREDATE. Find Window được thiết kế để xác định các bản ghi bằng
EMPNO hoặc HIREDATE.
 Các bước triển khai :
 Bước 1 : Copy nhóm đối tượng QUERY_FIND từ form APPSTAND
. Copy nhóm đối tượng QUERY_FIND từ form APPSTAND vào form của
bạn. Nó chứa 1 window, 1 block và 1 canvas mà từ đó xây dựng nên Find
Window của bạn.

74
. Sau khi copy, xoá nhóm đối tượng QUERY_FIND đi. Window, canvas và
block vẫn còn, và bạn lại có thể copy lại nhóm đối tượng nếu cần thêm Find
Window nữa.
 Bước 2 : Đổi tên block, canvas và window
. Đổi tên block, canvas và window. Đặt thuộc tính queryable của block là No.
. Trong ví dụ, đổi tên block, canvas và window thành : EMP_QF,
EMP_QF_CANVAS, and EMP_QF_WINDOW.
 Bước 3 : Viết code cho trigger của nút NEW
. Viết code cho trigger WHEN–BUTTON–PRESSED của nút NEW trong
block của Find Window để nó truyền đi tên của block Result như 1 tham số.
Thông tin này cho phép Oracle Applications chuyển con trỏ tới block Result
và đặt con trỏ tại vị trí bản ghi mới. Sở dĩ có nút NEW là bởi vì khi bạn mở 1
form, Find Window có thể tự động mở ra, và nếu bạn muốn thêm mới ngay 1
bản ghi thì chỉ việc chọn nút NEW.
. Trong ví dụ, sửa dòng code app_find.new(‟<Your results blockname
here>‟); trong trigger thành app_find.new(‟EMP‟);
 Bước 4 : Viết code cho trigger của nút FIND
. Viết code cho trigger WHEN–BUTTON–PRESSED của nút FIND để nó
truyền đi tên của block Results. Thông tin này cho phép Oracle Applications
chuyển focus tới block Results và thực hiện truy vấn.
. Trong ví dụ, sửa dòng code app_find.find (‟ <Your results blockname here>
‟); thành app_find.find(‟EMP‟);
. Nếu bạn cần phải validate các item trong Find Window, đặt đoạn code của
bạn trước lời gọi APP_FIND.FIND. Bạn có thể đưa ra lời nhắc nếu người
dùng chưa nhập điều kiện lọc, hoặc điều kiện lọc đó có thể phải mất nhiều
thời gian để xử lý.
 Bước 5 : Thiết lập thuộc tính Navigation Data Block
. Thiết lập thuộc tính Previous Navigation Data Block của block Find là block
Results. Điều này cho phép người dùng thoát khỏi Find Window mà không
cần thực hiện truy vấn.
. Từ block Result, next và previous data block của nó là các đối tượng khác,
chứ không bao giờ quay về Find Window.
 Bước 6 : Viết code cho trigger KEY–NXTBLK
Viết code cho trigger KEY–NXTBLK của block Find để nó có tính năng
giống như nút FIND. Khi người dùng chọn “Go–>Next
Block”, hành động xảy ra giống như khi nhấn nút FIND.

75
 Bước 7 : Đặt title cho Find Window
Đặt title cho Find Window. Trong ví dụ, đặt title là “Find Employees”.
 Bước 8 : Tạo các item cần thiết
. Tạo các item mà người dùng truy vấn trong block Find Window. Đơn giản
nhất là copy các item từ block Result vào block Find Window.
. Các thao tác với những item trong Find Window :
> Đặt thuộc tính Required là No
> Đặt giá trị mặc định là NULL
> Nếu bạn copy các item từ block Results, đặt thuộc tính Database Item là
No, và loại bỏ các trigger kèm với chúng. Nếu cần giữ lại 1 trigger nào đấy,
cần sửa các tham chiếu của nó tới các trường trong block Find Window
> Thông thường item trong block Find Window có LOV gắn với nó để
người dùng luôn có thể chọn đúng giá trị hợp lệ cho item. Các trường date
có thể sử dụng Calendar và trigger KEY-LISTVAL có liên quan.
> Các item là check box hay option group trong block Results nên chuyển
thành poplist trong block Find Window. Khi chúng NULL, truy vấn không
chịu một giới hạn nào.
 Bước 9 : Căn chỉnh Find Window trong form
Điều chỉnh Find Window của bạn : chỉnh lại kích thước, vị trí, các trường…
 Bước 10 : Lập trình trigger PRE-QUERY
. Tạo trigger PRE-QUERY cho block Results (Execution Hierarchy :
Before) để copy điều kiện lọc truy vấn từ block Find Window sang block
Results (là nơi truy vấn thực sự xảy ra).
. Bạn có thể sử dụng built-in COPY của Oracle Forms để copy giá trị hoặc
có thể gán giá trị trực tiếp bằng “ := ”.
IF :parameter.G_query_find = ‟TRUE‟ THEN
COPY (<find Window field>,‟<results field>‟);
:parameter.G_query_find := ‟FALSE‟;
END IF;
. Một kiểu lọc thường dùng đó là truy vấn trong phạm vi các số (hoặc các
ngày, hoặc các kí tự) nào đó. Có thể sử dụng thủ tục
APP_FIND.QUERY_RANGE để thực hiện điều này. Tham số một và hai
là giá trị thấp và giá trị cao, tham số ba là tên của trường dữ liệu được truy
vấn thực sự.
. Trong ví dụ :
IF :parameter.G_query_find = ‟TRUE‟ THEN

76
COPY(:EMP_QF.EMPNO, ‟EMP.EMPNO‟);
APP_FIND.QUERY_RANGE(:EMP_QF.Hiredate_from,
:EMP_QF.Hiredate_to, ‟EMP.Hiredate‟);
:parameter.G_query_find := ‟FALSE‟;
END IF;
 Bước 11 : Tạo trigger QUERY_FIND
. Tạo trigger QUERY_FIND (loại trigger tự tạo) cho block Results
(Execution Hierarchy: Override) chứa code :
APP_FIND.QUERY_FIND(‟<results block window>‟,
‟<Find window>‟, ‟<Find window block>‟);
. Trong ví dụ :
APP_FIND.QUERY_FIND(‟EMP_WINDOW‟, ‟EMP_QF_WINDOW‟,
‟EMP_QF‟);

77
Lập trình các hành động cho
item
Các chủ đề chính
 Mối quan hệ các Item
 Defaults
 Kiểm tra tính toàn vẹn
 Calendar
 CALENDAR: Calendar Package

Mối quan hệ giữa các Item


 Các Item phụ thuộc.
 Các Item phụ thuộc vào điều kiện.
 Các Item đa phụ thuộc.
 Hai Master Items & Một Dependent Item
 Phụ thuộc tầng.
 Các Item loại trừ lẫn nhau.
 Các Item bao gồm lẫn nhau.
 Mutually Inclusive Items with Dependents
 Các Item có tính điều kiện bắt buộc.
Các hành động chính đối với các Item như sau:
Disabled Items and WHEN–VALIDATE–ITEM Trigger
Trong hầu hết mối quan hệ giữa các Item bạn phải tự động enable hoặc
disable các Item.
WHEN–VALIDATE–ITEM luôn xảy ra tại thời điểm đầu tiên khi một
user di chuyển qua mỗi trường của một record mới, thậm chí không thay
đổi giá trị gì
 Các item phụ thuộc
Để tạo một text item, check box, hoặc poplist mà chỉ enabled khi một
master item được tính toán, sử dụng procedure APP_FIELD.SET_

78
DEPENDENT_FIELD. Điều này cho phép :
- Các item phụ thuộc hoặc được clear hoặc là invalid khi master thay đổi.
- Nếu master item là NULL hoặc điều kiện là FALSE, thì item phụ thuộc
disabled.

Trong ví dụ dưới đây ta có hai item là item_type và item_name.


Item_name phụ thuộc vào item_type, do đó item_name chỉ enable khi
item_type là NOT NULL.

Bước 1 Tạo một thủ tục điều khiển procedures như dưới đây:
PACKAGE BODY ORDER IS
PROCEDURE ITEM_TYPE(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
-- Any validation logic goes here.
ITEM_NAME(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_TYPE: ‟ || EVENT);
END IF;
END ITEM_TYPE;
PROCEDURE ITEM_NAME(EVENT VARCHAR2) IS
BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟)) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
‟ORDER.ITEM_TYPE‟,
‟ORDER.ITEM_NAME‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_NAME: ‟ || EVENT);
END IF;
END ITEM_NAME;
END ORDER;
Bước 2: Gọi thủ tục điều khiển item trong :

79
Trigger: WHEN–VALIDATE–ITEM on item_type:
order.item_type(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD on order (Fire in Enter–Query Mode: No):
order.item_name(‟PRE–RECORD‟);
Bước 3 :
Nếu master và dependent item đều trong một multi–row block, hoặc chúng
là các items trong một single–row block là detail của một master block, ta
phải gọi SET_DEPENDENT_FIELD cho sự kiện POST–QUERY thay vào đó.
PROCEDURE ITEM_NAME(EVENT VARCHAR2) IS
BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) OR
(EVENT = ‟POST–QUERY‟)) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
‟ORDER.ITEM_TYPE‟,
‟ORDER.ITEM_NAME‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_NAME: ‟ || EVENT);
END IF;
END ITEM_NAME;
Thêm một điều khiển trong:
ORDER.ITEM_NAME(’POST–QUERY’);

Chú ý : Trong một multi–record block, nếu item phụ thuộc là


Item cuối cùng của record, con trỏ chuột đến record tiếp theo
Khi di chuyển từ master. Để làm việc với điều khiển này
, thêm vào KEY–NEXT–ITEM trigger mà xảy ra một
VALIDATE(Item_scope) tiếp theo là NEXT_ITEM.
Chú ý: Nếu item phụ thuộc là một required list hoặc option
group, thiết lập ”invalidate” parameter trong lời gọi
APP_FIELD.SET_DEPENDENT_FIELD thành TRUE. Khi
flag là TRUE, item phụ thuộc được thiết lập như là invalid hơn
là cleared.

80
Item phụ thuộc có điều kiện
Trong ví dụ này , block orderc có hai là item_type và item_size.
Item_size is enabled chỉ khi item_type là ”SHOES.”
Bước 1:
Tạo một thủ tục điều khiển item dưới đây . Tương tự như trong trường hợp
simple master/dependent, nhưng phải thiết lập điều kiện thay vì tên của
master item.
PACKAGE BODY order IS

PROCEDURE ITEM_TYPE(EVENT VARCHAR2) IS


BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
size(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_TYPE: ‟ || EVENT);
END IF;
END item_type;
END IF;
END size;

PROCEDURE size(EVENT VARCHAR2) IS


BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟)) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
(:order.item_type = ‟SHOES‟),
‟ORDER.SIZE‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.SIZE: ‟ || EVENT);
END order;

81
Bước 2 Gọi thủ tục điều khiển trong :
Trigger: PRE–RECORD on order (Fire in Enter–Query Mode: No):
order.item_size(‟PRE–RECORD‟);
Trigger: WHEN–VALIDATE–ITEM on item_type:
order.item_type(‟WHEN–VALIDATE–ITEM‟);

Các item đa phụ thuộc


Đây là trường hợp mà nhiều item phụ thuộc vào một master
item. Ví dụ, item_types chắc chắn có thể định rõ color và size.
Do đó, trường color và size là phụ thuộc vào the master field
item_type, và chỉ enabled khi item_type là ”RAINCOAT.”
Bước 1
Tạo các thủ tục xử lý item như sau :
PACKAGE BODY order IS
PROCEDURE item_type(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
color(‟INIT‟);
size(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_TYPE: ‟ || EVENT);
END IF;
END item_type;
PROCEDURE color(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
(:order.item_type = ‟RAINCOAT‟),
‟ORDER.COLOR‟);

82
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.COLOR: ‟ || EVENT);
END IF;
END color;
PROCEDURE size(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
(:order.item_type = ‟RAINCOAT‟),
‟ORDER.SIZE‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.SIZE: ‟ || EVENT);
END IF;
END size;
END order;
Bước 2 Gọi các thủ tục trong :
Trigger: WHEN–VALIDATE–ITEM on order.item_type:
order.item_type(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD (Fire in Enter–Query Mode: No):
order.color(‟PRE–RECORD‟);
order.size(‟PRE–RECORD‟);

2 Master Item và 1 Dependent Item


Giả sử các size khác nhau của những chiếc mũ tương ứng với các color khác nhau.
Bạn không thể điền vào color của chiếc mũ đến khi nào bạn đã điền vào cả hai
item_type và size. Sự hợp lệ của block phụ thuộc được điều khiển bởi nội dung
của cả hai master_1 and master_2.
Bước 1 Tạo các thủ tục dưới đây :
PACKAGE BODY order IS
PROCEDURE item_type(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN

83
color(‟INIT‟):
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.ITEM_TYPE: ‟ || EVENT);
END IF;
END item_type;
PROCEDURE size(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
color(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.SIZE: ‟ || EVENT);
END IF;
END size;
PROCEDURE color(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
((:order.item_type IS NOT NULL) AND
(:order.size IS NOT NULL)),
‟ORDER.COLOR‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.COLOR: ‟ || EVENT);
END IF;
END color;
END order;
Bước 2 Gọi các thủ tục điều khiển trong :
Trigger: WHEN–VALIDATE–ITEM on order.item_type:
order.item_type(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on order.size:
order.size(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD (Fire in Enter–Query Mode: No):

84
order.color(‟PRE–RECORD‟);

Kiểu phụ thuộc Cascading


Với kiểu phụ thuộc cascading, item_3 phụ thuộc vào item_2, item_2
phụ thuộc vào item_1. Thông thường tất cả các item trong cùng một block.
Ví dụ , block order bao gồm các items vendor, site, và contact.
Danh sách list tương ứng của sites phụ thuộc vào vendor hiện tại .
- Khi vendor được thay đổi, site bị cleared.
- Bất cứ khi nào vendor là null, site là disabled.
Danh sách list của các contacts phụ thuộc vào site hiện tại.
- Bất cứ khi nào site thay đổi, contact là cleared.
- Bất cứ khi nào site là null, contact là disabled.
Bước 1 Tạo thủ tục dưới đây :
PACKAGE BODY order IS
PROCEDURE vendor(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
SITE(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.VENDOR: ‟ || EVENT);
END IF;
END VENDOR;
PROCEDURE SITE(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
CONTACT(‟INIT‟);
ELSIF (EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
‟ORDER.VENDOR‟,
‟ORDER.SITE‟);
CONTACT(EVENT);
ELSE
fnd_message.debug(‟Invalid event passed to

85
ORDER.SITE: ‟ || EVENT);
END IF;
END SITE;
PROCEDURE CONTACT(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
‟ORDER.SITE‟,
‟ORDER.CONTACT‟);
ELSE
fnd_message.debug(‟Invalid event passed to
ORDER.CONTACT: ‟ || EVENT);
END IF;
END CONTACT;
END ORDER;

Bước 2 Gọi các thủ tục trong :


Trigger: WHEN–VALIDATE–ITEM on vendor:
order.vendor(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on site:
order.site(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD on order (Fire in Enter–Query Mode: No):
order.site(‟PRE–RECORD‟);
order.contact(‟PRE–RECORD‟);

Trường VENDOR được validate như sau:


- VENDOR được validate, gọi SITE (‟INIT‟).
- SITE (‟INIT‟) làm trạng thái của SITE thay đổi và gọi CONTACT (‟INIT‟).
- CONTACT (‟INIT‟) làm trạng thái của CONTACT thay đổi.

Các item loại trừ lẫn nhau (Mutually Exclusive Items)


Sử dụng thủ tục APP_FIELD.SET_EXCLUSIVE_FIELD để viết mã 2
item khi mà chỉ 1 item là hợp lệ tại một thời điểm.

86
Nếu một item không được null, đặt thuộc tính REQUIRED của cả 2 item
là Yes trong Oracle Forms Developer. Nếu cả 2 item có thể là null, đặt
thuộc tính REQUIRED của cả 2 item là No. APP_FIELD.SET_
EXCLUSIVE_FIELD đọc thuộc tính REQUIRED bên trong và tự động
thay đổi thuộc tính REQUIRED của cả 2 item.
Bạn cũng có thể sử dụng APP_FIELD.SET_EXCLUSIVE_FIELD
với tập hợp của 3 mutually exclusive item. Nếu là nhiều hơn 3 item,
bạn phải tự viết mã logic cho chúng.

Chú ý : Các mutually exclusive check box và required list


đều yêu cầu được kích hoạt bằng chuột.

Ví dụ, một block lines có các mutually exclusive items là credit & debit.
Bước 1
PACKAGE BODY lines IS
PROCEDURE credit_debit(EVENT VARCHAR2) IS
BEGIN
IF ((EVENT = ‟WHEN–VALIDATE–ITEM‟) OR
(EVENT = ‟PRE–RECORD‟)) THEN
APP_FIELD.SET_EXCLUSIVE_FIELD(EVENT,
‟LINES.CREDIT‟,
‟LINES.DEBIT‟);
ELSIF (EVENT = ‟WHEN–CREATE–RECORD‟) THEN
SET_ITEM_PROPERTY(‟lines.credit‟, ITEM_IS_VALID,
PROPERTY_TRUE);
SET_ITEM_PROPERTY(‟lines.debit‟, ITEM_IS_VALID,
PROPERTY_TRUE);
ELSE
fnd_message.debug(‟Invalid event passed to
Lines.credit_debit: ‟ || EVENT);
END IF;
END credit_debit;
END lines;
Bước 2

87
Trigger: WHEN–VALIDATE–ITEM on credit:
lines.credit_debit(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on debit:
lines.credit_debit(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD on lines (Fire in Enter–Query Mode: No):
lines.credit_debit(‟PRE–RECORD‟);
Trigger: WHEN–CREATE–RECORD on lines:
lines.credit_debit(‟WHEN–CREATE–RECORD‟);
Bạn chỉ cần trigger WHEN–CREATE–RECORD nếu kết quả của một trong
trường mutually–exclusive được yêu cầu. Trigger này vào lúc đầu thiết lập
tất cả các trường mutually–exclusive của tập hợp thành required. Tất cả
các trường được reset thích hợp mỗi lần một user nhập giá trị vào một trong các
trường đó.

Các item đồng hành với nhau (Mutually Inclusive Items)


Sử dụng APP_FIELD.SET_INCLUSIVE_FIELD để viết mã của tập hợp các
item trong trường hợp nếu bất cứ item nào là không null, thì tất cả các item là required.
Giá trị của các item được nhập vào theo bất cứ thứ tự nào. Nếu tất cả các item là
null, thì các item là tùy ý không bất buộc.
Bạn có thể dùng APP_FIELD.SET_INCLUSIVE_FIELD đối với không quá
5 mutually inclusive items. Nếu số item là lớn hơn 5 bạn phải tự viết mã logic.
Ví dụ dưới gồm 1 block payment_info với các mutually inclusive items là
payment_type và amount.
Bước 1:
PACKAGE BODY payment_info IS
PROCEDURE payment_type_amount(EVENT VARCHAR2) IS
BEGIN
IF ((EVENT = ‟WHEN–VALIDATE–ITEM‟) OR
(EVENT = ‟PRE–RECORD‟)) THEN
APP_FIELD.SET_INCLUSIVE_FIELD(EVENT,
‟PAYMENT_INFO.PAYMENT_TYPE‟,
‟PAYMENT_INFO.AMOUNT‟);
ELSE

88
fnd_message.debug(‟Invalid event to
payment_info.payment_type_ amount: ‟ || EVENT);
END IF;
END payment_type_amount;
END payment_info;
Bước 2:
Trigger: WHEN–VALIDATE–ITEM on payment_info.payment_type:
payment_info.payment_type_amount(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on payment_info.amount:
payment_info.payment_type_amount(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD on payment_info (Fire in Enter–Query Mode:
No):
payment_info.payment_type_amount(‟PRE–RECORD‟);

Mutually Inclusive Item liên hệ với Dependent Item


Đây là trường hợp các items là phụ thuộc vào master items, trong khi
master items là mutually inclusive.
Ví dụ dưới với block payment_info với các mutually inclusive items là
payment_type and amount, như trong ví dụ trước, Block này bao gồm
2 regions, một cái cho check information và 1 cho credit
card information. Check Information has a single item, check_number.
Credit Card Information gồm 5 item: credit_type, card_holder, number,
expiration_date, and approval_code.

Payment Type có thể là Cash, Check, hoặc Credit


- Khi Payment Type là Check, thì Check Information region được enabled.
- When Payment Type là Credit, the Credit Card Information region được enabled.
Bước 1 :
PACKAGE BODY payment_info IS
PROCEDURE payment_type_amount(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
APP_FIELD.SET_INCLUSIVE_FIELD(EVENT,
‟PAYMENT_INFO.PAYMENT_TYPE‟,

89
‟PAYMENT_INFO.AMOUNT‟);
IF (:SYSTEM.CURSOR_ITEM =
‟payment_info.payment_type‟) THEN
check_info(‟INIT‟);
credit_info(‟INIT‟);
END IF;
ELSIF (EVENT = ‟PRE–RECORD‟) THEN
APP_FIELD.SET_INCLUSIVE_FIELD(EVENT,
‟PAYMENT_INFO.PAYMENT_TYPE‟,
‟PAYMENT_INFO.AMOUNT‟);
ELSE
fnd_message.debug(‟Invalid event in
payment_info.payment_type_amount: ‟ || EVENT);
END IF;
END payment_type_amount;
PROCEDURE check_info IS
BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟)) THEN
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
(:payment_info.payment_type = ‟Check‟),
‟PAYMENT_INFO.CHECK_NUMBER‟);
ELSE
fnd_message.debug(‟Invalid event in
payment_info.check_info: ‟ || EVENT);
END IF;
END check_info;
PROCEDURE credit_info IS
CONDITION BOOLEAN;
BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟)) THEN
CONDITION := (:payment_info.payment_type = ‟Credit‟);
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
CONDITION,
‟PAYMENT_INFO.CREDIT_TYPE‟);

90
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
CONDITION,
‟PAYMENT_INFO.NUMBER‟);
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
CONDITION,
‟PAYMENT_INFO.CARD_HOLDER‟);
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
CONDITION,
‟PAYMENT_INFO.EXPIRATION_DATE‟);
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
CONDITION,
‟PAYMENT_INFO.APPROVAL_CODE‟);
ELSE
fnd_message.debug(‟Invalid event in
payment_info.credit_info: ‟ || EVENT);
END IF;
END credit_info;
END payment_info;
Bước 2
Trigger: WHEN–VALIDATE–ITEM on payment_info.payment_type:
payment_info.payment_type_amount(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on payment_info.amount:
payment_info.payment_type_amount(‟WHEN–VALIDATE–ITEM‟);
Trigger: PRE–RECORD on payment_info (Fire in Enter–Query Mode:
No):
payment_info.payment_type_amount(‟PRE–RECORD‟);
payment_info.check_info(‟PRE–RECORD‟);
payment_info.credit_info(‟PRE–RECORD‟);

Các item bắt buộc điều kiện (Conditionally Mandatory Items)


Sử dụng APP_FIELD.SET_REQUIRED_FIELD nếu 1 item yêu cầu cả 2 điều kiện và
Phụ thuộc, thì gọi APP_FIELD.SET_DEPENDENT_FIELD trước
APP_FIELD.SET_REQUIRED_FIELD.

91
Trong ví dụ sau một block purchase_order bao gồm 2 item total và vp_approval.
Vp_approval được yêu cầu khi total lớn hơn $10,000. (Chú ý :
quantity * unit_price = total.)
Bước 1: Viết thủ tục sau :
PACKAGE BODY purchase_order IS
PROCEDURE vp_approval(EVENT VARCHAR2) IS
BEGIN
IF ((EVENT = ‟PRE–RECORD‟) OR
(EVENT = ‟INIT‟)) THEN
APP_FIELD.SET_REQUIRED_FIELD(EVENT,
(:purchase_order.total > 10000),
‟PURCHASE_ORDER.VP_APPROVAL‟);
ELSE
fnd_message.debug(‟Invalid event in
purchase_order.vp_approval: ‟ || EVENT);
END IF;
END vp_approval;
PROCEDURE total(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟INIT‟) THEN
:purchase_order.total := :purchase_order.quantity *
:purchase_order.unit_price;
vp_approval(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event in purchase_order.total:
‟ || EVENT);
END total;
PROCEDURE quantity(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
total(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event in
purchase_order.quantity: ‟ || EVENT);
END IF;

92
END quantity;
PROCEDURE unit_price(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
total(‟INIT‟);
ELSE
fnd_message.debug(‟Invalid event in
purchase_order.unit_price: ‟ || EVENT);
END IF;
END unit_price;
END purchase_order;
Bước 2: Gọi các thủ tục sau trong :
Trigger: PRE–RECORD on purchase_order (Fire in Enter–Query
Mode: No):
purchase_order.vp_approval(‟PRE–RECORD‟);
Trigger: WHEN–VALIDATE–ITEM on quantity:
purchase_order.quantity(‟WHEN–VALIDATE–ITEM‟);
Trigger: WHEN–VALIDATE–ITEM on unit_price:
purchase_order.unit_price(‟WHEN–VALIDATE–ITEM‟);

Các mặc định (Defaults)


Các mặc định trên 1 bản ghi mới
Để thiết lập giá trị mặc định khi user tạo một bản ghi, sử dụng
thuộc tính Default values trong the Oracle Forms Designer. Với những
Default phức tạp hơn có thể tham khảo tại đây:
Bước 1: Khai báo Package
PACKAGE block IS
PROCEDURE WHEN_CREATE_RECORD IS
BEGIN
:block.item1 := default_value1;
:block.item2 := default_value2;
...
END WHEN_CREATE_RECORD;

93
END block;
Bước 2: Gọi trong trigger sau :
Trigger: WHEN–CREATE–RECORD:
block.WHEN_CREATE_RECORD;

Áp dụng các Default khi đang truy cập vào bản ghi
Khi muốn thiết lập giá trị mặc định cho một item mà phụ thuộc và một item
khác thì thiết lập giá trị mặc định trong item phụ thuộc sử dụng sự kiện INIT.

Kiểm tra tính toàn vẹn (Integrity Checking)


 Kiểm tra tính duy nhất (Uniqueness Checks)
 Kiểm tra toàn vẹn tham chiếu (Referential Integrity Checks)

Kiểm tra tính duy nhất


Trường hợp này có thể thấy khi duplicate một hàng của block dữ liệu.
Ta dùng WHEN–VALIDATE–ITEM cho trường đó.
PROCEDURE CHECK_UNIQUE(X_ROWID VARCHAR2,
pkey1 type1, pkey2 type2, ...) IS
DUMMY NUMBER;
BEGIN
SELECT COUNT(1)
INTO DUMMY
FROM table
WHERE pkeycol1 = pkey1
AND pkeycol2 = pkey2
...
AND ((X_ROWID IS NULL) OR (ROWID != X_ROWID));
IF (DUMMY >= 1) then
FND_MESSAGE.SET_NAME(‟prod‟, ‟message_name‟);
APP_EXCEPTION.RAISE_EXCEPTION;
END IF;
END CHECK_UNIQUE;

Tạo thủ tục xử lý item như sau :

94
PACKAGE BODY block IS
PROCEDURE item(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ‟WHEN–VALIDATE–ITEM‟) THEN
table_PKG.CHECK_UNIQUE(:block.row_id,
:block.pkey1, :block.pkey2, ...);
ELSE
message(‟Invalid event in block.item‟);
END IF
END item;
END block;

Kiểm tra toàn vẹn tham chiếu


Khi xóa một record, ta phải chú ý đến các record mà có thể tham chiếu
đến record đó . Các giải pháp được đưa ra là:
- Không cho phép xóa item đó.
- Xóa đồng thời item mà nó tham chiếu đến.
- Cho phép xóa item , và đặt item tham chiếu đến nó là null..
Thông thường ta sẽ xử ly theo cách đầu.
Đưa ra cảnh báo trước khi xoá các bản ghi detail
Để cảnh báo khi xóa một detail record, tạo
CHECK_REFERENCES là 1 hàm trả lại giá trị FALSE nếu các bản ghi detail
tồn tại (CHECK_REFERENCES cần phải raise 1 exception nếu
khi xóa một hàng mà có liên quan đến lỗi tham chiếu).
Ví dụ :
Bước 1 :
CREATE OR REPLACE PACKAGE BODY table_PKG AS
PROCEDURE CHECK_REFERENCES(pkey1 type1, pkey2 type2, ...)
IS
MESSAGE_NAME VARCHAR2(80);
DUMMY credit;
BEGIN
MESSAGE_NAME := ‟message_name1‟;
SELECT 1 INTO DUMMY FROM DUAL WHERE NOT EXISTS
(SELECT 1 FROM referencing_table1

95
WHERE ref_key1 = pkey1
AND ref_key2 = pkey2
...
);
MESSAGE_NAME := ‟message_name2‟;
SELECT 1 INTO DUMMY FROM DUAL WHERE NOT EXISTS
(SELECT 1 FROM referencing_table2
WHERE ref_key1 = pkey1
AND ref_key2 = pkey2
...
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
FND_MESSAGE.SET_NAME(‟prod‟, MESSAGE_NAME);
APP_EXCEPTION.RAISE_EXCEPTION;
END CHECK_REFERENCES;
END table_PKG;
Bước 2 :
PACKAGE BODY block IS
PROCEDURE key_delete IS
BEGIN
––
–– First make sure its possible to delete this record.
–– An exception will be raised if its not.
––
table_PKG.CHECK_REFRENCES(pkey1, pkey2, ...);
––
–– Since it is possible to delete the row, ask the
–– user if they really want to,
–– and delete it if they respond with ‟OK‟.
––
app_record.delete_row;
END key_delete;
END block;
Bước 3 :

96
Trigger: KEY–DELETE:
block.dey_delete;

Gợi ý : Bạn cần phải làm các bước tương tự với trigger
ON–DELETE. Có thể xảy ra tình huống là trong khoảng thời gian
1 user yêu cầu delete, thậm chí đã saved giao dịch, một
record được đưa vào ở đâu đó sẽ gây ra lỗi tham chiếu .
Cần phải nhớ rằng KEY–DELETE thực hiện tại thời điểm
đầu tiên khi một user thực hiện delete, nhưng không thực sự
thực hiện hành động delete; nó chỉ đánh dấu record nào sé xóa và
clear nó trên màn hình . Trigger ON–DELETE thực hiện tại thời
điểm commit và mới thực sự thực hiện xóa .

Đối tượng Calendar


Calender là một đối tượng cho phép lựa chọn ngày tháng một cách trực quan
Đối tượng này có sẵn ở trong form template.
Để có thể sử dụng đối tượng này ta phải khai báo một số thủ tục trong các
trigger tương ứng
 LOV cho các trường Date và Datetime
Trường date và datetime phải đặt thuộc tính List lamp. Khi user mở
list của trường đó form sẽ mở Calendar window.
Trường date phải sử dụng ENABLE_LIST_LAMP LOV, trong
TEMPLATE form. Đặt ‟Validate fromList” to No cho trường
mà sử dụng LOV. Nếu để ”Validate from
List” là Yes, bạn sẽ thấy LOV sẽ không có cột nào.
Các lời gọi cần phải có
Mỗi trường date trong form phải sử dụng lời gọi sau :
Trigger: KEY–LISTVAL:
calendar.show([first_date]);
hoặc
calendar.show;

97
Các lựa chọn cấp cao của Calendar
Một số thuộc tính của Calendar có thể thực hiện thêm như sau :
Không hiển thị các ngày cuối tuần trong cửa sổ Calendar
Để không hiện ngày cuối tuần (Chú ý ở đây là Thứ 7 và CN), gọi
calendar.setup(‟WEEKEND‟);
Không hiển thị một chuỗi các ngày nào đó
calendar.setup(<30 char identifying name>, <low_date>,
<high_date>);
Không hiển thị một chuỗi các ngày nào đó lấy từ 1 bảng
calendar.setup(<30 char identifying name>, null, null,
<SQL>);
Gọi đối tượng Calendar từ các trường non–DATE
Có thể gọi Calendar trên các trường không phải là kiểu date-time như kiểu char
,text.Cách gọi vẫn như bình thường. Khi lựa chọn giá trị ngày tháng sẽ trả về
trường dưới format dạng ”DD–MON–YYYY.”
Tạo một trigger ở mức item và thêm các lệnh để xử lý giá trị đó.
Một số ví dụ về Calendar
Ví dụ : Chỉ hiển thị những ngày làm việc trong tuần ( thứ 2 -> thứ 6 )
Trigger: KEY–LISTVAL:
calendar.setup(‟WEEKEND‟);
calendar.show;
Ví dụ : Chỉ hiển thị những ngày làm việc trong năm ( không tính thứ 7, chủ
nhật, các ngày lễ )
Giả sử có trường SHIP_BY_DATE trong một form, bạn muốn dùng
Calendar và đặt tùy chọn cho nó :
- Không hiển thị tất cả holiday được xác định trong bảng ORG_HOLIDAYS
- Không hiển thị 2 ngày nghỉ cuối tuần
- Hiện tháng tương ứng với ngày trong trường “LINES.NEED_BY_DATE” khi mở Calendar
Trigger: KEY–LISTVAL:
calendar.setup(‟WEEKEND‟);
calendar.setup(‟Manufacturing Holidays‟, null, null,
‟select action_date LOW_DATE,
action_date HIGH_DATE ‟||
‟from org_holidays where

98
date_type = ‟‟HOLIDAY‟‟‟);
calendar.show(:lines.need_by_date);
Ví dụ : Hiển thị một chuỗi các ngày
Trong trường NEED_BY_DATE, bạn muốn Calendar hiện ra tháng
tương ứng với ngày trong trong trường LINES.CREATED_DATE + 30 days
Bạn đồng thời cũng disable tất cả các ngày
trước đó kể cả: LINES.CREATED_DATE.
Trigger: KEY–LISTVAL:
calendar.setup(‟After created date‟, null,
lines.created_date);
calendar.show(:lines.need_by_date + 30);
Ví dụ : Chỉ hiển thị Calendar để xem
Trên form có một nút HOLIDAYS chỉ ra tất cả các ngày nghỉ cho phép.
Tháng hiện tại được cho trước đó, và calendar tìm
những ngày này trong ORG_DATES table.
Trigger: WHEN–BUTTON–PRESSED on HOLIDAYS:
calendar.setup(‟TITLE‟, null, null,
‟<translated text for ”Manufacturing Holidays”>‟);
calendar.setup(‟Manufacturing Holidays‟, null, null,
‟select action_date LOW_DATE, action_date HIGH_DATE ‟||
‟from org_dates where date_type = ‟‟HOLIDAY‟‟‟);
calendar.show;

99
Điều khiển Toolbar và Default
Menu
Trong chương này sẽ đề cập đến cách custom menu, toolbar, pupup menu trên form.
Các thuộc tính này đều có ở form Template.
Các mục chính :
 Menu kéo xuống (Pulldown Menu) và Toolbar
 Các menu đặc biệt
 Customize loại menu xuất hiện khi click chuột phải (Popup Menu, hay Right–
Mouse Menu )
 APP_POPUP: Điều khiển Right–Mouse Menu
 APP_SPECIAL: Điều khiển Menu và Toolbar

Pulldown Menu và Toolbar

Menu bar

Tool bar

100
Các lựa chọn có trên thanh công cụ ( toolbar ) :

Các lựa chọn và các trigger tương ứng với nó ( theo thứ tự xuất hiện trên toolbar ) :
 New (Thêm mới bản ghi) (WHEN–NEW–BLOCK–INSTANCE)
Có hiệu lực nếu block cho phép insert.
 Find... (WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực khi block cho phép truy vấn và chưa ở trong chế độ enter–query.
 Show Navigator (WHEN–NEW–RECORD–INSTANCE)
 Save
Luôn có hiệu lực.
 Next Step
 Print...
Luôn có hiệu lực.
 Close Form
 Cut/Copy/Paste
Các đối tượng menu và toolbar sau được xử lý bởi Oracle Forms
 Clear Record
Luôn có hiệu lực.
 Delete Record (tương ứng với Edit / Delete trên menu)
(WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực khi block cho phép xoá.
 Edit Field... (WHEN–NEW–ITEM–INSTANCE)
Có hiệu lực khi item hiện tại là text item.
 Zoom (WHEN–NEW–BLOCK–INSTANCE)
Có hiệu lực nếu khách hàng định nghĩa 1 zoom cho block hiện tại
 Translations
Mặc định là không có hiệu lực. Người phát triển có thể enable/disable nó theo yêu
cầu bằng cách sử dụng APP_SPECIAL.ENABLE.
 Attachments (WHEN–NEW–RECORD–INSTANCE và
WHEN–NEW–BLOCK–INSTANCE)
 Folder Tools

101
Có hiệu lực nếu con trỏ ở trong 1 folder block; người phát triển phải viết code
trong combination folder block.
 • Window Help
Luôn có hiệu lực.

Các mục chỉ có trong Menu


• Clear Form
Luôn có hiệu lực.
• Summary/Detail
Mặc định là không có hiệu lực. Người phát triển có thể enable/disable theo
yêu cầu bằng cách sử dụng APP_SPECIAL.ENABLE.
• Save and Proceed
Luôn có hiệu lực.
• File / Exit Oracle Applications
(WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực nếu không ở trong chế độ enter–query.
• Edit / Duplicate / Field Above (WHEN–NEW–ITEM–INSTANCE)
Có hiệu lực nếu bản ghi hiện tại không phải là bản ghi đầu tiên
• Edit / Duplicate / Record Above
(WHEN–NEW–RECORD–INSTANCE)
hiệu lực nếu bản ghi hiện tại không phải là bản ghi đầu tiên và trạng thái bản
ghi là ‟NEW‟. Người phát triển phải customize hành động Duplicate
Record trong trigger KEY–DUPREC mức form hoặc mức block.
• Edit, Clear, Field (WHEN–NEW–ITEM–INSTANCE)
Có hiệu lực khi item hiện tại là text item.
• Edit, Clear, Block (WHEN–NEW–ITEM–INSTANCE)
Luôn có hiệu lực
• Edit, Clear, Form (WHEN–NEW–ITEM–INSTANCE)
Luôn có hiệu lực
• Edit, Select All
• Edit, Deselect All
• Edit, Preferences, Change Password
• View, Find All (WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực nếu block cho phép truy vấn và chưa ở trong chế độ enter–
query.

102
• View, Query by Example, Enter
(WHEN–NEW–BLOCK–INSTANCE)
Có hiệu lực nếu block cho phép truy vấn.
• View, Query by Example, Run
(WHEN–NEW–BLOCK–INSTANCE)
Có hiệu lực nếu block cho phép truy vấn.
• View, Query by Example, Cancel
(WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực nếu ở trong chế độ enter-query
• View, Query by Example, Show Last Criteria
(WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực nếu ở trong chế độ enter-query
• View, Query by Example, Count Matching Records
(WHEN–NEW–RECORD–INSTANCE)
Có hiệu lực nếu block cho phép truy vấn.
• View, Record, First
Có hiệu lực nếu bản ghi hiện tại không phải là bản ghi đầu tiên
• View, Record, Last
Có hiệu lực nếu bản ghi hiện tại không phải là bản ghi đầu tiên
• View, Requests
• Window, Cascade
• Window, Tile Horizontally
• Window, Tile Vertically
• Help, Oracle Applications Library
• Help, Keyboard Help
• Help, Diagnostics

Điều khiển menu động


Để có thể tự điều khiển các menu trong các trường hợp đặc biệt
Sử dụng thủ tục sau app_special.enable.
Thủ tục này được thêm vào trong các trigger PRE–BLOCK hoặc
WHEN–NEW–BLOCK–INSTANCE, WHEN–NEW–RECORD– INSTANCE
WHEN–NEW–ITEM–INSTANCE

103
app_standard.event(‟TRIGGER_NAME‟);
app_special.enable(‟Menu_item‟, PROPERTY_OFF|ON);
Ví dụ : app_special.enable(‟CLEAR.FIELD‟, PROPERTY_OFF);
Ví dụ :
Giả sử bạn có một chức năng là ‟Book Order‟mà bạn muốn thêm vào
Menu và toolbar.
Để thêm ‟Book Order‟là mục đầu tiên tương ứng với 1 icon trên toolbar
Mà chỉ có hiệu lực với block Header trên form :

Bước 1
Sửa trong trigger PRE–FORM mức form:
PRE–FORM
app_special.instantiate(‟SPECIAL1‟, ‟&Book Order‟, ‟bkord‟);
Bước 2
Thêm 1 trigger PRE–BLOCK mức form:
PRE–BLOCK
app_special.enable(‟SPECIAL1‟,PROPERTY_OFF);
Bước 3
Thêm 1 trigger PRE–BLOCK mức block trong block nào bạn muốn
enable các mục menu mới của bạn :
PRE–BLOCK trong HEADER block
app_special.enable(‟SPECIAL1‟,PROPERTY_ON);
Bước 4
Thêm 1 trigger SPECIAL (loại tự định nghĩa) mức block chứa code thực
hiện chức năng ‟Book Order ‟ của bạn. Nó sẽ được thực thi khi người dùng
chọn mục menu chức năng này.
Các item sẽ được reset lại trong các block khác bởi default menu
Mà ta không phải tự reset mỗi khi rời một block, record, item

Tạo các biểu tượng trên toolbar cho các form bạn customize
Ta cũng có thể tạo icon riêng cho menu bằng các file .gif đặt tại thư mục
Được tạo bởi virtual directory OA_MEDIA

104
Các menu đặc biệt

Cut
Copy
Paste
––––––
Folder
––––––
Help

Disable các menu đặc biệt


Để disable tất cả các mục đặc biệt trên menu( như trong trường hợp query–mode)
Sử dụng APP_SPECIAL.ENABLE(‟SPECIAL‟,PROPERTY_OFF);

Customize các Right–Mouse Menu (Popup Menus)


Thêm các mục vào Right–Mouse Menu
Dạng default của menu popup là như sau :

Ta hoàn toàn có thể thay đổi dạng mặc định của menu popup bằng cách thêm

105
Vào các entry mới gồm cả các đường ngăn cách như sau :

Sử dụng thủ tục sau :


procedure APP_POPUP.INSTANTIATE(
option_name varchar2, ---
„POPUP1‟=>‟POPUP10‟
txt varchar2, --- tên nhãn
initially_enabled boolean default true, ----
„TRUE‟/‟FALSE‟
separator varchar2 default null); -------
„LINE‟)

Cut
Copy
Paste
––––––––––––
Folder
––––––––––––
First Entry
Second Entry
––––––––––––
Third Entry
––––––––––––
Help

Các entry sẽ được thêm vào sau FOLDER và trước HELP.


Ví dụ :
Bước 1

106
––––––––––––
Cut
Copy
Paste
––––––––––––
Folder
––––––––––––
First Entry
––––––––––––
Second Entry
Third Entry (disabled, so greyed
out)
––––––––––––
Help
––––––––––––

Sửa trigger PRE–POPUP–MENU mức item trên trường Requisition


Number (Execution Hierarchy : After).
app_popup.instantiate(‟POPUP1‟, ‟Approve‟);
Bước 2
Thêm 1 trigger POPUP1 mức item (loại tự tạo) chứa code thực hiện chức
năng của bạn.
Nó thực thi khi user chọn mục menu tương ứng.
Ví dụ
APP_POPUP.INSTANTIATE(‟POPUP1‟,‟First Entry‟);
APP_POPUP.INSTANTIATE(‟POPUP2‟,‟Second Entry‟, TRUE,
‟LINE‟);
APP_POPUP.INSTANTIATE(‟POPUP3‟,‟Third Entry‟, FALSE);
Kết quả sẽ là như sau :

107
Message Dictionary
Tổng quan về Message Dictionary
 Thiết lập về Message Dictionary
 Message Dictionary API đối với PL/SQL Procedures
 Message Window.

Tổng quan về Message Dictionary


Cho phép phân loại các message sẽ được đưa ra của form hay của ứng dụng
Với Message Dictionary bạn có thể làm :
- Xác định các message tiêu chuẩn mà form hay ứng dụng sử dụng đến.
- Cung cấp một cách nhìn và cảm nhận thống nhất đối với các message
trong và giữa các ứng dụng.
- Xác định các messge động có thể bao gồm context–sensitive variable
text
- Giúp dế dàng thay đổi và mà không phải biên dịch lại nội dung message
trong ứng dụng.

Các điểm đặc trưng của Message Dictionary

 Có thể sửa đổi nội dung của message:


- Dễ dang thay đổi thay đổi nội dung message trên một form duy nhất.
- Các message có thể hiển thị dưới dạng dialog box hoặc dòng.
 Dễ dàng biên dịch
 Chuẩn hóa message
- Mỗi lần xác định một message trong Message Dictionary bạn có thể quy
cho một form, concurrent
Program hoặc module trong ứng dụng khác sử dụng tên message mà bạn đã
xác định. Bạn có thể gọi
Message bao nhiêu lần tùy ý và từ bất cứ nơi nào trong ứng dụng. Nếu bạn
cần thay đổi nội dung message
Bạn chỉ cần thay đổi ngay tại chỗ.
 Message text động

108
- Message có thể chấp nhận biến text động như trường hoặc tên module

Các bước cần tiến hành khi xác định Message Dictionary

 Tên Message.
 Message(<1800 ký tự)
 Số Message : Số sẽ xuất hiện cùng với message. Nếu bạn xác định một
message number khác không
Cho message , Dictionary ẽ thêm vào message tiền tố APP-
 Mã thông báo biến : Một từ khóa bạn tạo ra để miêu tả một giá trị khi
bạn xác định một message.
Bạn chỉ rõ cùng một mã thông báo biến và giá trị của nó, khi gọi
Message Dictionary từ một form
hay một module chương trình.
Message Dictionary sẽ thay thế mỗi mã thông báo biến trong message
với giá trị hiện tại bạn đã
Chỉ rõ sau đó là hiện ra thông báo.

Thiết lập Message Dictionary


1.Tạo các thư mục message
2.Xác định message.
3. Tạo các file message
Bước1 : Vào Application Developer responsibility vào cửa sổ Submit Requests
Bước2: Chọn Generate Messages trong trường Name.
Bước3: Trong cửa sổ Parameters, chọn ngôn ngữ cho file cần tạo.
Bước4: Chọn tên ứng dụng tương ứng với file cần tạo. Mỗi ứng dụng đều phải có file
message riêng của nó.
Bước5: Chọn kiểu cho chương trình. Để tạo file message lúc runtime chọn
DB_TO_RUNTIME.
Bước6: Để trống Filename Parameter, message generator sẽ tạo một file với tên mặc
định tiêu chuẩn trong thư mục mesg đối với ứng dụng trên phía server.
Bước7: Copy file vừa tạo đến thư mục mesg hợp của ứng dụng trên mỗi máy cần
thiết(concurrent processing servers, forms server machines). Tên file phải giữ nguyên
tại mọi nơi.
4.Viết mã cài đặt các message.

109
Từ tạo một message và đưa tới người sử dụng gồm hai quá trình : đầu tiên phải cài đặt
message( phía client) hoặc gọi nó từ phía server, sau đó trình bày tới người dùng (hoặc viết ra
file đối với một concurrent program).
Các hàm API phía client cho việc gọi và cài đặt các message:
Các hàm này nằm trong package FND_MESSAGE.
SET_NAME Gọi message từ Message Dictionary và đặt nó trong message stack
SET_STRING Lấy một input string và đặt nó trong message stack..
SET_TOKEN Thay thế một message token bằng giá trị bạn đã tạo.
RETRIEVE Gọi một message từ buffer message phía server dịch và thay thế các
token và đặt nó vào message stack.
GET(hàm) Gọi một message từ stack message và trả về giá trị VARCHAR2.
CLEAR Clear message stack.
Các hàm API phía server:
Chỉ có một message được đặt trong bộ đệm phía server.
SET_NAME Đặt một tên message trong khu vực global.
SET_TOKEN Thêm một cặp token/value vào khu vực global.
CLEAR Clear message stack.
5. Viết mã display message.
Mỗi lần bạn cài đặt hoặc gọi message và thay thế bất cứ token nào, tiếp theo display tới
người dùng (trên form) hoặc viết ra file (database phía server đối với một concurrent
program).
Các hàm API để trình bày các message ở Form Server.
Các hàm sau dùng trong các PL\SQL thủ tục trong form và trong các thư viện để trình bày
các message : FND_MESSAGE.SET_NAME, FND_MESSAGE.RETRIEVE. Nếu cần thêm
các icon để trình bày dùng các hàm sau : FND_MESSAGE.ERROR,
FND_MESSAGE.SHOW, FND_MESSAGE.WARN, FND_MESSAGE.QUESTION

Phương pháp đối với Database Server–side Messaging.

Có 3 phương pháp khác nhau không thể thay đổi để trình bày các message được thiết lập phía
server:
Phương pháp1 : Đặt một message error phía server, sẽ được trình bày phía client form mà
gọi thủ tục phía server.

110
Trên phía server, sử dụng FND_MESSAGE.SET_NAME và
FND_MESSAGE.SET_TOKEN để thiết lập message. Sau đó gọi
APP_EXCEPTION.RAISE_EXCEPTION. Các lỗi này được trả về trigger ON–ERROR phía
client.
Phương pháp 2 : Đặt một message phía server, được trả về phía client
Trên phía server sử dụng FND_MESSAGE.SET_NAME,
FND_MESSAGE.SET_TOKEN. Phía client sử dụng FND_MESSAGE.RETRIEVE để lấy
message từ phía server, đặt message lên message stack của client. Tiếp đó client gọi
FND_MESSAGE.ERROR, FND_MESSAGE.SHOW, FND_MESSAGE.HINT,
FND_MESSAGE.WARN để trình bày message hoặc FND_MESSAGE.GET để đặt message
vào một buffer.
Phương pháp 3 :Lấy một message vào một buffer trên server.
Sử dụng FND_MESSAGE.SET_NAME, FND_MESSAGE.SET_TOKEN,
FND_MESSAGE.GET để lấy một message vào một buffer hoặc
FND_MESSAGE.GET_STRING để lấy một message đơn vào một sâu.

111
USER PROFILE
User profile là tập hợp các tùy chọn có thể thay đổi làm ảnh hưởng đến cách thực hiện
chương trình. Oracle Application Object Library đưa ra một giá trị cho mỗi tùy chọn trong một
profile người dùng khi người dùng log on hoặc khi thay đổi Responsibility.
Người dùng có thể thay đổi giá trị của tùy chọn profile bất cứ khi nào.
Với tư cách là một nhà phát triển bạn thậm chí có thể xác định thêm các tùy chọn. Bởi vì có
thể bạn không muốn người dùng có khả năng ghi đè giá trị lên giá trị bạn đã xác định, do đó bạn có
thể xác định tùy chọn tại một trong các mức sau : Site, Application, Responsibility và User.

User
Application
User
Responsibility
System
Administrator
Application

Site

Các mức của User Profile:


User có mức thứ thự cao nhất.
Giá trị tùy chọn ở mức cao hơn thì ghi đè lên mức dưới nó.
Mỗi tùy chọn user profile thông thường có ở tất cả các mức. Ví dụ Oracle Application Object Library
cung cấp tùy chọn mức site cũng như mức Application là Printer. Do đó nếu mức Site Printer có giá
trị là “New York” nhưng mức User có giá trị là “Boston” thì báo cáo sẽ được in ở Boston printer.

112
Định nghĩa mới các tùy chọn của user profile
Sử dụng Profile Window

Thiết lập giá trị tùy chọn user profile


Sử dụng System Administrator responsibility.

Thiết lập user profile riêng của bạn


Sử dụng form Update Personal Profile Options

Xác định trước tùy chọn user profile


 Database Profile Options
Oracle Application Object Library cung cấp nhiều tùy chọn user profile mà Oracle
System Administrator hoặc người dùng có thể nhìn thấy cũng như cập nhật.

 Các tùy chọn profile nội tại


Bạn có thể thay đổi giá trị của các tùy chọn profile trong Oracle Application
Object Library ở form hay chương trình tuy nhiên các ngoại trừ các profile
CONC_PRINT_OUTPUT và CONC_PRINT_STYLE kể cả System
administrators.
USERNAME Tên user Oracle Application Objec Library của
user hiện tại.
USER_ID user id
RESP_ID responsibility ID hiện tại của user.
APPL_SHRT_NAME short name của ứng dụng liên kết nối tới
responsibility.
RESP_APPL_ID application ID của ứng dụng kệt nối tới
responsibility hiện tại.
FORM_NAME tên của form hiện tại. Không tồn tại đối với
concurrent programs.
FORM_APPL_ NAME application ID của ứng dụng mà form được đăng

FORM_APPL_ID.
LOGON_DATE.
LAST_LOGON_

113
DATE.
LOGIN_ID
CONC_REQUEST_ID. equest ID tương ứng với một thể hiện của chương
trình hiện tại. Chỉ có thể dùng tùy chọn này trong
một concurrent program
CONC_PROGRAM_ID program ID tương ứng với một chương trình đang
chạy. Chỉ có thể dùng tùy chọn này trong một
concurrent program.
CONC_ PROGRAM_APPLICATION_ID
CONC_LOGIN_ID giá trị YES hoặc NO trong trường Print Output khi
đăng ký một concurrent program.
CONC_PRINT_ STYLE kiểu in đầu ra của concurrent program khi bạn
nhập vào trường Print Style khi đăng ký một
concurrent program.

Profile Window

114
115
FOLDER
Tổng quan về Folder.
Forlder là một chức năng hết sức đặt biệt trên form ứng dụng cho phép
người sử dụng thiết lập các thuộc tính riêng. Nó sẽ lưu giữ một profile cụ thể để
trình bày tên các promt cho các trường dữ liệu trên form bằng ngôn ngữ bản địa
có sử dụng được Unicode. Một chức năng thứ hai là tự động sắp xếp các trường
dữ liệu tự động (order by).

Lập trình với Folder trên form ứng dụng.


Cụ thể các bước để có thể sử dụng được chức năng này như sau :
 Attach thư viện APPFLDR.
 Thêm vào form chuẩn STANDARD_FOLDER Object group.
 Tạo <BLOCKNAME>_RECORD_COUNT parameter: trong đó
BLOCKNAME là tên của Block chứa cột dữ liệu cần thể hiện,
Data Type là Number và giá trị default gán bằng 2.
 Tạo 2 canvas : một cái là contain(VD đặt tên là FOLDER) một cái
là stack(VD đặt tên là STACK). Cả hai canvas này có cùng một
Window.
 Tạo Block :
Block chính (BLOCKNAME) chứa các cột dữ liệu trong database.
Tạo các thủ tục trong các trigger tương ứng với block này như sau :
WHEN-NEW-BLOCK-INSTANCE
app_folder.event('WHEN-NEW-BLOCK-INSTANCE');

KEY-PREV-ITEM
if (:parameter.<blockname>_record_count = 1) then
previous_item;
else

116
app_folder.event('KEY-PREV-ITEM');
end if;

KEY-NEXT-ITEM
if (:parameter.<blockname>_record_count = 1) then
next_item;
else
app_folder.event('KEY-NEXT-ITEM');
end if;
PROMPT Block: tạo một block PROMPT ( đặt trên stack là
PROMPT_STACK kiểu là stack) chứa các promt cho các cột dữ liệu
trong block chính đã tạo ở trên. Trong block này chứa các item có tên
trùng với các tên cột trong block trên.
Các item này có property class là :
Ngoài ra cần phải tạo thêm các item khác là :
Item Name: FOLDER_OPEN, Item Type: Button, Canvas:
PROMPT_STACK
Item Name: FOLDER_DUMMY, Item Type: Text Item , Canvas:
TOOLBAR
Item Name: FOLDER_TITLE, Item Type: Display Item, Canvas:
PROMPT_STACK
Item Name: ORDER_BY1, Item Type: Button, Canvas:
PROMPT_STACK
Item Name: ORDER_BY2, Item Type: Button, Canvas:
PROMPT_STACK
Item Name: ORDER_BY3, Item Type: Button, Canvas:
PROMPT_STACK.
 Trên trigger mức Form :
FOLDER_ACTION
--
-- Remove the message and uncomment the line after it

117
-- to activate the folder actions
--
-- message('You must modify the FOLDER_ACTION trigger in your
form!');
app_folder.event(:global.folder_action);
WHEN-NEW-FORM-INSTANCE
app_folder.define_folder_block('BLOCKNAME', -- 'Object Name'
'BLOCKNAME', -- 'folder_block',
'PROMPT', -- 'ten prompt_block',
' PROMPT_STACK, --'ten stacked_canvas',
„WINDOW1‟, --' ten window',
NULL); --'disabled functions');
Tuy nhiên khi sử dụng chức năng này của form thi khi di chuyển ra ngoài View port của
BLOCKNAME rồi mới thực hiện chức năng order by thi hệ thống sẽ báo lỗi và ta không
làm gì được nữa. (Qua tìm hiểu đây là lỗi của tất cả các Form trên ứng dụng sử dụng
chức năng này.

118
ATTACHMENTS
Đặc tính của Attachments
Attachments cho phép người dùng liên kết những dữ liệu không có cấu trúc như là ảnh,
tài liệu word, bảng tính, hoặc dữ liệu text với những dữ liệu của ứng dụng.

119

You might also like