前回の記事では、承認コンポーネントを利用して休暇申請の承認と却下のフローを実装しました。しかし、これだけではアプリケーションとして動作はしますが、データとしては何も残りません。
休暇申請を保存する表を作成し、申請とその結果を保存するようにします。
SQLワークショップのユーティリティに含まれているクイックSQLを使って、以下のモデルから表UNI_REQUETSを作成します。
uni_requests
reason vc160
start_date
end_date
status vc10
requestor vc80
request_date
approver vc80
approve_date
上記のモデルをクイックSQLに記述し、SQLの生成、SQLスクリプトの保存、レビューおよび実行を順次実施します。
共有コンポーネントのタスク定義休暇申請を開き、タスクにたいして実施する操作をユーザーが用意した表UNI_REQUESTSに反映されるよう、設定を変更します。
設定のアクション・ソースとして、表UNI_REQUESTSを指定します。
アクション・ソースとして表を選択します。表の所有者はデフォルトの解析対象スキーマ、表名としてUNI_REQUESTS(表)を選択します。アクション表の主キー列として、表UNI_REQUESTSの主キー列である、ID(Number)を選択します。
この設定は、アクション・ソースにSQL問合せを選択し、アクションSQL問合せとして以下を記述したことと同じです。
select * from uni_requests where id = :APEX$TASK_PK
アクション・ソースに複数の表を含めたい場合などは、アクション・ソースとしてSQL問合せを選びます。
設定の件名は、変更したアクション・ソースを使うようにします。
&REASON. &START_DATE. - &END_DATE. &REQUESTER.
この後に定義済みのパラメータをすべて削除するため、&AC_REASON.、&AC_START_DATE.および&AC_END_DATE.の代わりに表UNI_REQUESTSから得られる値&REASON.、&START_DATE.および&END_DATE.を使います。標準の置換文字列である&APEX$TASK_INITIATOR.は有効ですが、表UNI_REQUESTSに登録されている申請者を確認できるように、表UNI_REQUESTSに保存されている値である&REQUESTER.を使います。
参加者の潜在的所有者を、静的な割り当てからPL/SQLのファンクション本体による割り当てに変更します。実用面を考慮すると、潜在的所有者を静的に割り当てるケースは稀でしょう。
今回は簡単に、申請花子さんの休暇申請は承認花子さんが承認者(所有者 - Actual Owner)、申請太郎さんの休暇申請の承認者は承認太郎さんが承認者となるようにします。それ以外は管理者が承認します。
以下のコードを実装します。
begin
if :APEX$TASK_INITIATOR = '申請太郎' then
return '承認太郎';
elsif :APEX$TASK_INITIATOR = '申請花子' then
return '承認花子';
else
return '管理者';
end if;
end;
パラメータはすべて削除します。
今回は、全てのパラメータを永続的に保存することにしました。タスクの作成から完了まで値を保持できればよく、タスクの完了後にタスクとともにパージされて問題がなければ、パラメータを利用します。
タスクが承認されたとき、または却下されたときに実行されるアクションを作成します。
アクションの追加をクリックします。
休暇申請が承認されたときに実行するコードを登録します。
アクションの名前は承認、タイプとしてコードを実行を選択します。コードの実行の他に電子メールの送信を選ぶこともできます。アクションが実行されるタイミングであるイベント時として、完了を選択します。完了以外に、タスクにたいして行われる操作に対応した、作成、要求、委任、取消、リリース、コメントの更新、優先順位の更新も選択することができます。結果として承認済を選択します。
コードには以下を記述します。
begin
update uni_requests
set status = 'APPROVED'
, approver = :APEX$TASK_OWNER
, approve_date = sysdate
where id = :APEX$TASK_PK;
commit;
end;
以上の設定で、タスクが承認されたときに表UNI_REQUESTSに保存されている休暇申請の列STATUSがAPPROVEDとして更新されます。それと同時に承認者(APPROVER)と承認日(APPROVE_DATE)も更新されます。
却下のアクションでは、結果に却下済を選択し、コードは列STATUSにREJECTEDを更新するようにします。
begin
update uni_requests
set status = 'REJECTED'
, approver = :APEX$TASK_OWNER
, approve_date = sysdate
where id = :APEX$TASK_PK;
end;
Autonomous Databaseの場合、SYSDATEはUTCでの時刻を返します。ローカル(例えば東京)の時刻を扱う場合は、セッション・パラメータSYSDATE_AT_DBTIMEZONEが有効になるように構成します。このような場合にアクションのコード中でSYSDATEを扱う際には、SYSDATE_AT_DBTIMEZONEを明示的に有効にする必要があるかもしれません。
begin
execute immediate 'alter session set sysdate_at_dbtimezone = true';
update uni_requests
set status = 'APPROVED'
, approver = :APEX$TASK_OWNER
, approve_date = sysdate
where id = :APEX$TASK_PK;
commit;
end;
タイムゾーン付きの日付データ型(TIMESTAMP WITH LOCAL TIME ZONE, TIMESTAMP WITH TIME ZONE)を使用している場合は、こういった考慮は不要になります。
休暇申請を行うページを修正します。タスクの生成に加えて、表UNI_REQUESTSへの休暇申請の書き込みを行い、生成したタスクと紐づけます。
ページ・デザイナでホーム・ページを開きます。
リージョン休暇申請を選択し、作成済みのページ・アイテムをすべて選択し削除します。ボタンB_SUBMITはそのまま残します。
リージョン休暇申請の識別のタイプを、静的コンテンツからフォームへ変更します。その後、ソースの表名としてUNI_REQUESTSを選択します。
ページ・アイテムP1_IDを選択し、識別のタイプを非表示に変更します。ソースの主キーはONにします。このページ・アイテムが、作成した休暇申請(表UNI_REQUESTSに含まれる1行)を一意に特定する値を保持します。
ページ・アイテムP1_STATUS、P1_APPROVER、P1_APPROVE_DATEを選択し、ビルド・オプションを使ってコメント・アウトします。これらのページ・アイテムに対応する列STATUS、APPROVER、APPROVE_DATEはタスクのアクションによって設定され、画面からは設定しません。
ページ・アイテムP1_REQUESTERを選択し、タイプを非表示にします。デフォルトのタイプにアイテムを選択し、アイテムにAPP_USERを指定します。休暇申請の申請者は、かならずサインインをしているユーザーになります。
ページ・アイテムP1_REQUEST_DATEにも同様にデフォルト値を設定します。識別のタイプを非表示にし、デフォルトのタイプとして式、言語にSQLを選択し、SQL式としてsysdateを記述します。
select task_id, subject, detail_pk from apex_tasks where task_def_static_id = 'LEAVE_REQUEST' and detail_pk is not null;
フォームを処理するプロセスを追加します。プロセスを新たに作成し、休暇申請の上に配置します。
識別の名前をプロセス - フォーム休暇申請とします。タイプとしてフォーム - 行の自動処理(DML)を選択し、フォーム・リージョンとして休暇申請を選びます。サーバー側の条件のボタン押下時にB_SUBMITを指定します。
以上で、一通りの実装は完了しました。
表UNI_REQUESTSの内容を確認するために、対話モード・レポートのページを作成します。
ページ作成ウィザードを起動し、対話モード・レポートを選択します。
名前は休暇申請一覧とします。ページ・モードは標準、編集はしないのでフォーム・ページを含めるはOFFです。データ・ソースの表/ビューの名前としてUNI_REQUESTSを選択します。このページをサイド・メニューから呼び出せるように、ナビゲーションはONにし、ナビゲーションのプリファレンスとして、エントリを新規作成しますを選択します。
おおむね以上の設定にて、ページの作成を実行します。
作成したページを実行すると、以下のように表示されます。
承認コンポーネント単体で複雑な処理フローを実装できるわけではありませんが、タスク定義を作成することにより、画面上のボタンを押したときに実行する処理を、プロセスとしてページに作成する以外に、タスク定義のアクションとして作成することができるようになりました。結果として、複数のページより実行する処理を、タスク定義のアクションにまとめることが可能になっています。今回の例でいうと、私のタスクから休暇申請を承認できるし、タスク詳細のページから休暇申請を承認することもできますが、実行されるコードはタスク定義のアクションとして記述されています。アクションのコードを変更すると、どのページで承認を行うかにかかわらず、すべての承認処理が変更されます。
今回作成したAPEXアプリケーションを以下に起きました。
https://github.com/ujnak/apexapps/blob/master/exports/simple-approvals-component-ud.sql
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完