Oracle Applications開発者ガイド リリース12 E06048-01 | 目次 | 前へ | 次へ |
複合フォームには、Oracle Applicationsのフィールド・レベル検証モデルに準ずるため、または特定のビジネス・ルールを適用するため、実行時に動的に行う必要のある多くの動作があります。
これらの例にならって、フォームの項目ハンドラおよびイベント・ハンドラをモデリングしてください。
ほとんどの項目関連で、項目は動的に無効化および有効化されます。無効な項目について、Oracle Formsのコーディングに関する次の問題に注意してください。
新しいレコード上の各フィールドをユーザーが最初にタブ移動すると、変更が加えられていない場合であっても、必ずWHEN-VALIDATE-ITEMが起動します。これは、Oracle Formsの内部で、値が不明からNULLに変更されたと記録され、WHEN-VALIDATE-ITEMが起動されるためです。ユーザーが値を非NULL値からNULL値へ変更した場合も、WHEN-VALIDATE-ITEMが起動します。
さらに、ユーザーが必須フィールドをNULLのままにしておく可能性は常にあります(レコード・レベルでのみトラップ可能)。したがって、WHEN- VALIDATE-ITEMトリガーによりNULLのフィールド値をすべて検出して、それに応じた動作をする必要があります。ユーザーが値をNULLに変更したのか、またはOracle Formsの最初の設定がNULL値であるかは識別できないため、どちらの場合でもユーザーが変更したものとして扱う必要があります。
ほとんどの場合、無効にされた項目にはNULL値が入っています。前述の問題によるNULL値が想定されるため、特に問題ではありません。稀に、無効にされたフィールドに、その値が無効な間に設定された値が存在し、そのフィールドが未検証の場合があります。その場合、WHEN-VALIDATE-ITEMが動作しないようにロジックを追加する必要があります。
マスター項目が移入されたときにのみ有効となるテキスト項目、チェック・ボックス、またはポップリストを作成するには、プロシージャAPP_FIELD.SET_ DEPENDENT_FIELDを使用します。このルーチンにより次の動作が実行されます。
マスター項目が変更された場合、従属項目は消去されるか、無効になる。
マスター項目がNULLか、条件がFALSEの場合、従属項目が無効となる。
次の手順に従って項目ハンドラ・プロシージャを作成し、特定のトリガーからプロシージャをコールします。
重要: 表示専用のテキスト項目には、これらのルーチンは適用されません。条件によって表示専用のテキストをグレー表示するには、ルーチンAPP_ITEM_PROPERTY.SET_VISUAL_ ATTRIBUTEを使用します。
関連項目: APP_ITEM_PROPERTY:プロパティ・ユーティリティ
この例では、ブロックorderには項目item_typeとitem_nameがあるものとします。Item_nameはitem_typeに従属しているため、item_nameはitem_typeがNULLではない場合にのみ使用可能です。
項目ハンドラ・プロシージャを次のように作成します。
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
マスター項目および従属項目が複数行ブロックにある場合や、マスター・ブロックの詳細である単一行ブロックにある場合は、POST-QUERYイベントにSET_DEPENDENT_FIELDをコールする必要もあります。
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;
次の場所で項目ハンドラ・プロシージャをコールします。
Trigger: POST-QUERY
ORDER.ITEM_NAME('POST-QUERY');
重要: マルチ・レコード・ブロックで、従属項目がレコードの最後の項目である場合、マスターからタブ移動すると次のレコードにカーソルがナビゲートします。この動作に対処するために、VALIDATE(Item_scope)を行ってからNEXT_ITEMを実行するKEY-NEXT-ITEMトリガーをコーディングします。
重要: 従属項目が必須リストまたはオプション・グループの場合は、APP_FIELD.SET_DEPENDENT_FIELDへのコールで、無効なパラメータをTRUEに設定します。このフラグがTRUEに設定されていると、従属項目は消去されずに無効のマークが付けられます。
条件付き従属項目は、マスター項目の特定の値に応じて有効、無効が決まります。この例では、ブロックorderに項目item_typeおよびitem_sizeがあり、Item_sizeはitem_typeが「SHOES」の場合にのみ有効となるものとします。
項目ハンドラ・プロシージャを次のように作成します。この項目ハンドラ・プロシージャは、マスターおよび従属の場合と非常に似ていますが、マスター項目名ではなく条件を指定する点に注意してください。
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;
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 IF;
END size;
END order;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
1つのマスター項目に複数の項目が従属していることがあります。たとえば、一定のitem_typesでのみ色やサイズを指定するという場合です。この場合、色のフィールドとサイズのフィールドはマスター・フィールドitem_typeに従属し、item_typeがRAINCOATのときにのみ有効となります。
項目ハンドラ・プロシージャを次のように作成します。
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');
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
1つの項目が2つのマスター項目に従属しているということもあります。たとえば、サイズの違うセーターが色違いで売られているとします。この場合、item_typeとsizeの両方に値を入力した後で、初めてセーターの色を指定できます。block.dependentの検証はmaster_1とmaster_2の内容によって制御されます。
項目ハンドラ・プロシージャを次のように作成します。
PACKAGE BODY order IS
PROCEDURE item_type(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = 'WHEN-VALIDATE-ITEM') THEN
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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):
order.color('PRE-RECORD');
カスケード従属とは、item_3がitem_2に従属し、さらにそれがitem_1に従属しているというものです。通常は、すべての項目が同じブロック内にあります。
たとえば、ブロックorderにvendor、siteおよびcontactの各項目があるとします。
有効なサイト・リストは、ベンダーによって決まります。
ベンダーを変更すると、サイトは消去されます。
ベンダーがNULLの場合は、サイトは無効です。
有効な連絡先リストは、現行サイトによって決まります。
サイトが変更されると、連絡先は消去されます。
サイトがNULLの場合は、連絡先は無効です。
次の手順に従って、これらの従属項目を正確に動作させるコードを作成します。
項目ハンドラ・プロシージャを次のように作成します。
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
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
VENDORフィールドが検証されると、常に次のような一連のイベントが発生することに注意してください。
VENDORが検証されると、SITE ('INIT')がコールされる。
SITE ('INIT')によりSITEの状態が変わり、CONTACT ('INIT')がコールされます。
CONTACT ('INIT')によりCONTACTの状態が変化します。
プロシージャAPP_FIELD.SET_EXCLUSIVE_FIELDを使用して、同時に1つの項目しか有効になることのできない2つの項目を設定します。
相互排他項目の項目ハンドラ・プロシージャをコーディングする際に重要なのは、2つの相互排他的項目は論理的には1つの項目であるという点です。相互排他項目の一方の項目がある項目に従属しているか、ある項目からの従属を受けているという場合、その関連はもう一方の項目にも適用されます。他の項目との関連は、どちらも常に同一です。したがって、1つの論理項目に対する単一の項目ハンドラ・プロシージャをコーディングします。
相互排他項目が両方ともNULLの場合は、どちらの項目もナビゲート可能です。一方の項目のみに値が入力されている場合、もう一方の項目にはナビゲートされず(ただし、そこでクリックすることは可能)、その項目にある値はすべて消去されます。
どちらかの項目をNULL以外にする必要がある場合は、Oracle Forms Developerで両方の項目のREQUIREDプロパティを「Yes」に設定します。どちらもNULLでよい場合は、両方の項目のREQUIREDプロパティを「No」に設定します。APP_FIELD.SET_ EXCLUSIVE_FIELDは、初期REQUIREDプロパティを読み取り、両方の項目のREQUIREDプロパティを動的に管理します。
さらに、3つの項目で構成される相互排他項目にも、プロシージャAPP_FIELD.SET_EXCLUSIVE_FIELDを使用できます。4つ以上の項目の場合は、独自のカスタム・ロジックを作成する必要があります。
重要: 相互に排他的なチェック・ボックスや必須リストでは、マウス操作が必要となります。
たとえば、ブロックlinesに相互排他項目creditとdebitがあるとします。
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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;
項目ハンドラ・プロシージャを次のように作成します。
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');
WHEN-CREATE-RECORDトリガーは、相互排他フィールドの結果が必須である場合にのみ必要です。初期値では、このトリガーは必須とされているセットのすべての相互排他フィールドに設定されています。必要に応じて、値を入力してフィールドを再設定します。
NULLではない項目が存在する場合に、すべて必須である項目のセットをコーディングするには、APP_FIELD.SET_INCLUSIVE_FIELDを使用します。
項目値の入力はどの順番でもかまいません。すべての項目がNULLの場合、その項目はオプションとなります。
プロシージャAPP_FIELD.SET_INCLUSIVE_FIELDでは、最大5つの項目を含む相互包含項目を設定できます。セット内の項目を6つ以上にする場合は、独自のカスタム・ロジックをコーディングする必要があります。
次の例では、ブロックpayment_infoに相互包含項目payment_typeとamountがあります。
項目ハンドラ・プロシージャを次のように作成します。
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
fnd_message.debug('Invalid event to
payment_info.payment_type_ amount: ' || EVENT);
END IF;
END payment_type_amount;
END payment_info;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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に相互包含項目payment_typeおよびamountがあります。ブロックには2つのリージョンも含まれており、それぞれ小切手情報用とクレジット・カード情報用です。小切手情報の項目はcheck_numberのみです。クレジット・カード情報にはcredit_type、card_holder、number、expiration_dateおよびapproval_codeの5項目があります。
支払タイプには現金、小切手またはクレジット・カードがあります。
支払タイプが「小切手」の場合は、「小切手情報」リージョンが有効となります。
支払タイプが「クレジット・カード」の場合は、「クレジット・カード情報」リージョンが有効となります。
項目ハンドラ・プロシージャを次のように作成します。
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',
'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');
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
プロシージャAPP_FIELD.SET_REQUIRED_FIELDを使用して、ある条件を満たした場合にのみ必須となる項目をコーディングします。この項目では、条件がFALSEの場合はその従属項目はオプションとなり、従属項目内の値は消去されません。ある項目が条件付きで必須であり、かつ従属項目である場合には、APP_FIELD.SET_REQUIRED_FIELDをコールする前にAPP_FIELD.SET_DEPENDENT_FIELDをコールします。
次に示すのは、APP_FIELD.SET_REQUIRED_FIELDの使用例です。
ブロックpurchase_orderに、項目totalとvp_approvalがあるとします。Vp_approvalは合計金額が10,000ドルを超えた場合に必須となります(注意: quantity * unit_price = total)。
項目ハンドラ・プロシージャを次のように作成します。
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;
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;
次のトリガーを使用して、項目ハンドラ・プロシージャをコールします。
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');
新規レコードの作成時にデフォルトの設定値を適用するには、Oracle Forms Designerのデフォルト値プロパティを使用します。より複雑なデフォルト動作を設定するには、次の例に従います。
イベント・ハンドラ・プロシージャを次のように作成します。
PACKAGE block IS
PROCEDURE WHEN_CREATE_RECORD IS
BEGIN
:block.item1 := default_value1;
:block.item2 := default_value2;
...
END WHEN_CREATE_RECORD;
END block;
次のトリガーを使用して、イベント・ハンドラ・プロシージャをコールします。
Trigger: WHEN-CREATE-RECORD:
block.WHEN_CREATE_RECORD;
有効性が別の項目に依存している項目のデフォルトを設定する場合(マスター値を変更した場合にデフォルトを適用する場合など)は、従属項目のINITイベント内でデフォルト値を設定します。
この項では、次の項目の処理方法を説明します。
キーの一意性チェックを行うには、WHEN-VALIDATE-ITEMによってコールされるSELECT文を使用します。
WHEN-VALIDATE-ITEMで実行される一意性チェックでは、コミットされていない行の重複は検出されない点に注意してください(たとえば、詳細ブロックにコミットされていない重複行を入力した場合など)。これは、WHEN-VALIDATE-ITEMが起動してレコードがコミットされるまでの間に別のユーザーが同一のキーをコミットするのと同様、データベース制約によって検出されます。そのため、PRE-UPDATEまたはPRE-INSERTに一意性チェックを書き込む必要はありません。
単一の一意キー・フィールドがある場合は、常にそのフィールドにWHEN-VALIDATE-ITEMからCHECK_UNIQUEパッケージをコールします。
複数のフィールドから構成される一意の組合せの場合は、WHEN-VALIDATE- RECORDトリガーからCHECK_UNIQUEパッケージをコールします。
例:
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;
項目ハンドラ・プロシージャを次のように作成します。
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;
レコードを削除する場合、そのレコードが他のレコードによって参照されている可能性を考慮する必要があります。たとえば、ある項目がすでに発注上で参照されており、その項目を削除する場合、次の3つの対処方法が考えられます。
項目の削除を許可しない。
発注も同時に削除する。
項目の削除を許可して、発注の参照欄を空白にする。
ほとんどの項目では、最初の方法が最も実用的かつ合理的です。これを適用するには、参照の有無を検出して例外を呼び出すプロシージャを作成します。
詳細レコードを削除する前に警告を出すには、詳細レコードが存在する場合はFALSEを返すファンクションとしてCHECK_REFERENCESを作成します。(参照整合性エラーが発生する行を削除する場合でも、CHECK_REFERENCESは例外を呼び出します。)
表にサブタイプが含まれている場合は、CHECK_REFERENCESプロシージャは1つあればよいのか、各サブタイプに1つずつCHECK_REFERENCESプロシージャが必要なのかを判断する必要があります。
サブタイプが、外部キー参照のほとんどをサブタイプ固有の外部キー参照と共有している場合は、最初のパラメータがサイブタイプ弁別子のCHECK_REFERENCESプロシージャを1つ作成します。
サブタイプが直交している場合は、各サブタイプにCHECK_subtype_REFERENCESプロシージャを作成します。
表ハンドラ・プロシージャを次のように作成します。
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
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;
イベント・ハンドラ・プロシージャを次のように作成します。
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;
イベント・ハンドラをコールします。
Trigger: KEY-DELETE:
block.dey_delete;
ヒント: ON-DELETEトリガーで同じステップを再実行します。これは、削除の要求が出されてから実際にトランザクションが保存されるまでの間に別の場所にレコードが入力されて、参照整合性の問題が発生する可能性があるためです。ユーザーによる削除の開始に呼応してKEY-DELETEが起動しますが、この時点で実際に削除が行われるわけではないことに注意してください。この時点では削除するものとしてレコードにフラグが立てられ、画面から消去されるのみです。実際の削除は、コミット時にON-DELETEトリガーが起動した時点で行われます。
カレンダ・オブジェクトは、カレンダから日付および時間の値を選択するための標準オブジェクトです。さらに、開発者は有効な日付のみを選択可能にする検証規則を指定することもできます。どの日付フィールドでも、リスト機能や編集機能でカレンダを起動できます。
フォーム内の各日付フィールドに、ユーザーがカレンダ機能をコールするのに必要なコードを作成します。ただし、カレンダはフィールド内にあるデータの検証の代替機能にはなりません。
カレンダは、自動的にTEMPLATEフォームに含められます。
カレンダのユーザー・インタフェース標準の詳細は、『Oracle Applicationsフォーム・ベース製品のユーザー・インタフェース標準』を参照してください。
日付および日時フィールドでは、「リスト」ランプが有効になっています。これらのフィールド上でリストを実行すると、フォームに「カレンダ」ウィンドウが開きます。
日付フィールドには、ENABLE_LIST_LAMP LOVを使用する必要があります。これはTEMPLATEフォーム内にあります。この設定によって、日付フィールドのメニューと「ツールバー値リスト」エントリが使用可能になります。このLOVを使用するフィールドでは、「リストで妥当性チェック」を「No」に設定します。「リストで妥当性チェック」を「Yes」のままにしておくと、LOVに列が表示されません。
フォーム内のすべての日付フィールドに、次のコーディングを行う必要があります。
Trigger: KEY-LISTVAL:
calendar.show([first_date]);
デフォルトでは、カレンダを最初に開くと日付フィールドの値(値がある場合)の月が表示されます。フィールドに日付がない場合は、現在の月のカレンダが表示されます。
フィールドの有効性検査が強制されてしまうので、現行フィールドをパラメータとしてCALENDAR.SHOWに渡さないでください。現行フィールドは、デフォルトとして使用されます。通常、KEY-LISTVALのコードは次のとおりです。
calendar.show;
重要: カレントの日付フィールドを、引数としてCALENDAR.SHOWに渡さないでください。カレンダは実際にはすべてのOracle Forms有効性検査を一時的に使用不可にするため、無効な日付を入力すると即時にカレンダが起動し、PL/SQLエラーが発生します。引数が渡されていない場合は、このような状況はSHOWによって自動的に処理されます。
KEY-LISTVALトリガーの実行階層は「オーバーライド」とし、問合せ入力モードでは起動しないようにします。
関連項目: CALENDAR: カレンダ・パッケージ
カレンダは、表示専用モードでも起動できます。その場合、特定の日付を選択するというより、選択済の複数の日付を表示するために使用されます。たとえば、ある従業員が休暇を取った日をすべて表示できます。
このモードでは、カーソルがあるフィールドの特性は無視されます。すべてのユーザーができる操作は、表示する月や年を変更することと、「OK」を押してウィンドウを閉じることのみです(値がフォームに書き込まれることはありません)。
このモードを起動するには、前述のものに加えて次のコールが必要です。
Trigger: KEY-LISTVAL:
calendar.setup('DISPLAY');
calendar.setup('TITLE', null, null,
'<translated text for window title>');
日付を選択されたものとして表示するには、これらの2つに加えてCALENDAR.SETUPコールが必要です。
カレンダのコールにオプション機能を組み込むこともできます。オプション・コールを使用する場合は、必ずcalendar.showの必須コールの前に配置します。
次の例では、カレンダをカスタマイズして特定の日付を表示または使用不可にします。
週末(ここでは土曜日と日曜日として定義)を使用不可にするには、次のようにコーディングします。
calendar.setup('WEEKEND');
ハードコードされているか、フォームの他のフィールドで参照されている特定の日付範囲を使用不可にするには、次のようにコーディングします。
calendar.setup(<30 char identifying name>, <low_date>,
<high_date>);
このコールは必要な回数繰り返すことができます。NULL値のLOW_DATEは期間の開始として、NULL値のHIGH_DATEが期間の終了として処理されます。
表にある特定の日付範囲を使用不可にするには、次のようにコーディングします。
calendar.setup(<30 char identifying name>, null, null, <SQL>);
このコールをフィールドに対し1回実行した場合でも、複数の行が返される場合があります。NULL値のLOW_DATEは期間の開始として、NULL値のHIGH_DATEは期間の終了として処理されます。この動作を行わないようにする場合は、SQL文でNVLを使用します。
UNION SQL文を使用すると、複数の表からの制約を実行できます。選択した列に、LOW_DATEおよびHIGH_DATEという別名を付ける必要があります。
ヒント: LOW_DATE列の順序付けを行うと、パフォーマンスが向上する場合があります。同様に、予想される選択値を含む狭い範囲を返すように日付を制限することも、パフォーマンスの向上に繋がります。
DATEまたはDATETIMEとして明示的に宣言されていないフィールドからカレンダを有効化できる必要がある場合(たとえば、文脈によって様々な目的に使用されるCHARテキスト項目など)でも、通常どおりカレンダのコールを記述します。カレンダはDATEフィールドから起動したときと同様に機能し、ユーザーが値を選択すると、日付は「DD-MON-YYYY」の書式でフィールドに書き込まれます。
その後、ユーザー命名トリガーCALENDAR_WROTE_DATEが起動します。トリガーを項目レベルで作成し、値処理に必要なコードを追加します(通常は、マスクを適用する必要があります)。
この例では、現在DATE項目に表示されている日付か、日付が表示されていない場合は現在月を表示するカレンダを開きます。さらに、週末(土曜日と日曜日)を使用不可にします。
トリガー: KEY-LISTVAL:
calendar.setup('WEEKEND');
calendar.show;
フィールドSHIP_BY_DATEのフォームでカレンダを開き、次のようにカスタマイズします。
ORG_HOLIDAYS表で定義されているすべての休日を使用不可にする。
週末を使用不可にする。
カレンダを開いたときに、フィールドLINES.NEED_BY_DATEの日付に対応する月を表示する。
これを実装するコードは次のとおりです。
トリガー: KEY-LISTVAL:
calendar.setup('WEEKEND');
calendar.setup('Manufacturing Holidays', null, null,
'select action_date LOW_DATE,
action_date HIGH_DATE '||
'from org_holidays where
date_type = ''HOLIDAY''');
calendar.show(:lines.need_by_date);
フィールドNEED_BY_DATEのフォームで、フォールドLINES.CREATED_DATEの日付から30日後の日付に対応する月のカレンダを表示するとします。さらに、LINES.CREATED_DATEの日付とそれ以前のすべての日付を使用不可にします。
これを実装するコードは次のとおりです。
トリガー: KEY-LISTVAL:
calendar.setup('After created date', null,
lines.created_date);
calendar.show(:lines.need_by_date + 30);
フォームで「休日」というボタンを使用して、すべての製造休業日を表示します。最初に現在の月が表示され、次にORG_DATES表で選択された日付が検索されます。
これを実装するコードは次のとおりです。
トリガー: HOLIDAYS上のWHEN-BUTTON-PRESSED:
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;
フォームへカレンダ情報をコーディングする標準的な方法とコーディング例は、「カレンダ」を参照してください。
PROCEDURE show (first_date date default null);
このコールによりカレンダが表示されます。現行フィールドの値をshowに渡さないでください。この値はデフォルト値として使用されます。
PROCEDURE setup (new_type varchar2,
low_date date DEFAULT null,
high_date date DEFAULT null,
sql_string varchar2 DEFAULT null);
重要: WEEKEND引数は土曜日と日曜日としてハードコードされています。そのため、週末を金曜日と土曜日としている国などでは適用できません。
PROCEDURE event (event varchar2);