OracleのAnanya Chatterjeeさんによる以下の記事が、公式ブログに寄稿されています。
Implementing Multi-Approvals in Oracle APEX 22.1
APEXの承認コンポーネントのタスクは、承認または却下することによって完了します。一旦承認/却下するとタスクは完了し、それ以降の操作はできません。そのため、職制を通した承認といったフローを、ひとつのタスクで扱うことはできません。
Ananya Chatterjeeさんは直属の上司がタスクを承認するときに、その上の階層での承認が必要であれば、承認時に実行されるコードの中で新たにタスクを生成することにより多段階での承認を実装しています。
以前の記事で作成した休暇申請を行なうAPEXアプリケーションに、多段階承認を実装してみます。
APEX 22.1の承認コンポーネント(1) - 概要http://apexugj.blogspot.com/2022/07/new221-approvals-component-intro.html
APEX 22.1の承認コンポーネント(2) - 基本的なアプリケーションの作成
http://apexugj.blogspot.com/2022/07/new221-approvals-component-basicapp.html
APEX 22.1の承認コンポーネント(3) - ユーザー・データの利用
http://apexugj.blogspot.com/2022/07/new221-approvals-component-userdata.html
最初に承認の階層を定義します。アプリケーションのユーザーは、申請太郎、申請花子、承認太郎、承認花子、管理者です。
申請太郎の直属上司を承認太郎、承認太郎の上司を管理者とします。また、申請花子の直属上司は承認花子、その上司を管理者とします。
表UNI_USERSを作成し、上記の階層をデータとして入力します。SQLワークショップのSQLスクリプトより実行します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create table uni_users( | |
empno number primary key, | |
emp_name varchar2(80) not null, | |
mgr number | |
); | |
insert into uni_users values(10, '申請太郎', 30); | |
insert into uni_users values(20, '申請花子', 40); | |
insert into uni_users values(30, '承認太郎', 50); | |
insert into uni_users values(40, '承認花子', 50); | |
insert into uni_users values(50, '管理者', null); | |
commit; |
せっかく表UNI_USERSを作成したので、サインインのユーザーがハードコードされている認証スキームを更新します。
共有コンポーネントの認証スキームの固定ユーザー認証を開き、ソースを以下に置き換えます。登録されているユーザーに変更はないので、このソースの置き換えはアプリケーションに影響を与えません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function uni_auth ( | |
p_username in varchar2, | |
p_password in varchar2 ) | |
return boolean | |
is | |
l_count pls_integer; | |
begin | |
select count(*) into l_count from uni_users where emp_name = p_username; | |
if l_count = 1 then | |
return true; | |
end if; | |
return false; | |
end; |
共有コンポーネントのタスク定義の休暇申請を開きます。
参加者の潜在的所有者の定義を変更します。現在の定義は以下になっています。申請太郎の上司は承認太郎、申請花子の上司は承認花子です。それ以外、つまり承認太郎と承認花子の上司は管理者です。
begin
if :APEX$TASK_INITIATOR = '申請太郎' then
return '承認太郎';
elsif :APEX$TASK_INITIATOR = '申請花子' then
return '承認花子';
else
return '管理者';
end if;
end;
上記を表UNI_USERSを参照した定義に置き換えます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_mgr_name uni_users.emp_name%type; | |
begin | |
select m.emp_name as mgr_name into l_mgr_name | |
from uni_users u join uni_users m on u.mgr = m.empno | |
where u.emp_name = :APP_USER; | |
return l_mgr_name; | |
end; |
タスクの開始者(APEX$TASK_INITIATOR)ではなく、サインインしているユーザー(APP_USER)の上司を潜在的所有者としています。
アクションを更新します。タスクが完了したときのイベント処理で、結果が承認済みのときに実行されるコードを変更します。
イベント時が完了、結果が承認済のアクションを開きます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
r_request uni_requests%rowtype; | |
l_task_id number; | |
begin | |
select * into r_request from uni_requests where id = :APEX$TASK_PK; | |
if r_request.status is null then | |
-- STATUSがNULLなので、直接の上司が申請を受け取って承認した。 | |
if (r_request.end_date - r_request.start_date) <= 7 then | |
-- 期間が一週間以下であれば、この承認処理で完了。 | |
update uni_requests | |
set status = 'APPROVED' | |
, approver = :APEX$TASK_OWNER | |
, approve_date = sysdate | |
where id = :APEX$TASK_PK; | |
else | |
-- 一週間を超える場合は、上司に転送する。 | |
-- このタスク自体は、これで完了する。 | |
update uni_requests | |
set status = 'TRANSFERED' | |
, approver = :APEX$TASK_OWNER | |
, approve_date = sysdate | |
where id = :APEX$TASK_PK; | |
-- 上司に承認を求める、新たなタスクを生成する。 | |
l_task_id := apex_approval.create_task( | |
p_application_id => :APP_ID | |
, p_task_def_static_id => 'LEAVE_REQUEST' | |
, p_initiator => :REQUESTER | |
, p_detail_pk => :APEX$TASK_PK | |
); | |
end if; | |
elsif r_request.status = 'TRANSFERED' then | |
-- 転送された承認であれば、この承認で完了。 | |
update uni_requests | |
set status = 'APPROVED' | |
, approver = :APEX$TASK_OWNER | |
, approve_date = sysdate | |
where id = :APEX$TASK_PK; | |
end if; | |
end; |
以上で多段階での承認が実装できました。
動作を確認してみます。
申請太郎でサインインし、2022/12/01から2022/12/31までの休暇を申請します。
自分で開始を開くと、承認太郎にタスクがアサインされていることが確認できます。
承認太郎でサインインし私のタスクを開き、アサインされたタスクを承認します。
休暇申請一覧を開くと、表UNI_REQUESTSの列STATUSはTRANSFEREDになっていることが確認できます。
管理者でサインインし私のタスクを開き、アサインされたタスクを承認します。
休暇申請一覧を開くと、表UNI_REQUESTSの列STATUSはAPPROVEDになっていることが確認できます。
以上で多段階での承認の実装が確認できました。
タスクの詳細の更新
本記事での実装では、タスクのパラメータを使っていません。そのため、タスクの詳細のページの詳細に何も表示されません。
ページ・デザイナにてタスクの詳細のページを開き、リージョン詳細のソースを置き換えます。
ソースのSQL問合せを以下に置き換えます。
select reason, start_date, end_date
from uni_requests
where id = (
select detail_pk from apex_tasks
where task_def_static_id = 'LEAVE_REQUEST'
and application_id = :APP_ID
and task_id = :P5_TASK_ID
);
属性の外観のテンプレートをValue Attribute Pairs - RowからValue Attribute Pairs - Columnに変更します。
自分で開始の一覧の更新
直属上司の上司の承認をとった場合、自分で開始に該当する休暇申請のタスクが2行表示されます。
自分で開始のページを開き、リージョン自分で開始 - レポートのソースのSQL問合せを以下のSELECT文に置き換えます。
select *
from table ( apex_approval.get_tasks ( p_context => 'INITIATED_BY_ME' ) )
where task_id in (
select max(task_id)
from apex_tasks
where application_id = :APP_ID
and detail_pk in (
select id from uni_requests where requester = :APP_USER
)
)
同じ休暇申請の場合、最後に作成されたタスクを一覧の対象にしています。
レポートを実行すると、表示が1行になっていることが確認できます。
Oracle APEX 22.1の承認コンポーネントを使った、多段階承認の実装の紹介は以上になります。
複雑なワークフローの実装であれば、Flows for APEXの利用をお勧めします。しかし、Flows for APEXではBPMNによるワークフローの定義が必須です。BPMNによるワークフローの定義まではしたくないといった場合は、このように承認コンポーネントの複数のタスクを連結することでワークフローを実装できます。
今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/simple-approvals-component-multilevel.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完