2022年1月31日月曜日

プラグインのコンポーネント設定を参照する

 Flows for APEXを使って経費精算のアプリケーションを作っている際に、SELECT文を以下のように書いていました。

select 
    expe.expe_id
    , expe.expe_justification
    , expe.expe_amount
    , expe.expe_status
    , expe.expe_submitted_on
    , expe.expe_invoice_dd
    , expe.expe_purpose
    , inst.prcs_id
    , tibx.sbfl_id
from expe_expenses expe
    join flow_instances_vw inst on expe.expe_id = inst.prcs_business_ref
    left join flow_task_inbox_vw tibx on expe.expe_id = tibx.sbfl_business_ref
where inst.dgrm_name = '経費精算'
    and (tibx.sbfl_dgrm_name = '経費精算' or tibx.sbfl_dgrm_name is null)
    and expe.expe_submitted_by = :APP_USER

SELECT文にフロー・モデル名が直書きされています。フロー・モデル名をバインド変数に置き換える方法について考えてみます。フロー・モデル名をG_FLOW_NAMEというバインド変数に置き換え、結果として以下のSELECT文に置き換えます。

select 
    expe.expe_id
    , expe.expe_justification
    , expe.expe_amount
    , expe.expe_status
    , expe.expe_submitted_on
    , expe.expe_invoice_dd
    , expe.expe_purpose
    , inst.prcs_id
    , tibx.sbfl_id
from expe_expenses expe
    join flow_instances_vw inst on expe.expe_id = inst.prcs_business_ref
    left join flow_task_inbox_vw tibx on expe.expe_id = tibx.sbfl_business_ref
where inst.dgrm_name = :G_FLOW_NAME
    and (tibx.sbfl_dgrm_name = :G_FLOW_NAME or tibx.sbfl_dgrm_name is null)
    and expe.expe_submitted_by = :APP_USER

経費精算のアプリケーションが使用するフロー・モデルは、プラグインのコンポーネント設定Global Flowとして定義されています。

バインド変数として使用するG_FLOW_NAMEは、アプリケーション・アイテムとして定義します。

共有コンポーネントアプリケーション・アイテムを開きます。


作成をクリックし、アプリケーション・アイテムG_FLOW_NAMEの作成を始めます。


名前として、G_FLOW_NAMEを入力します。セキュリティセッション・ステート保護はデフォルトの制限付き - ブラウザから設定不可のままにします。一番、厳しい制限になります。以上の設定で、アプリケーション・アイテムの作成をクリックします。


アプリケーション・アイテムG_FLOW_NAMEが作成されます。


作成したアプリケーション・アイテムG_FLOW_NAMEに、フロー・モデル名を設定します。アプリケーション内でG_FLOW_NAMEを参照するときはいつでも、コンポーネント設定Global Flowの値を返すようにします。

共有コンポーネントアプリケーションの計算を開きます。


作成をクリックします。


計算アイテムとしてG_FLOW_NAMEを選択します。頻度の計算ポイントとして新規インスタンス(新規セッション)開始時を選択します。

この頻度であれば、コンポーネント設定Global Flowが変更されると、経費精算のアプリケーションは一旦サインアウトしてセッションを終了したのち、サインインをやり直して新規セッションを開始して初めて、変更されたGlobal FlowG_FLOW_NAMEに反映されます。実際にはGlobal Flowの変更はほとんど行わないので、一番頻度が少なく(つまり実行回数が少ない)データベースに負荷がかからない設定を選択します。

計算計算タイプファンクション本体を選択します。言語PL/SQLとして、以下のコードを計算に記述します。
declare
    l_pos integer;
    l_flow_name APEX_APPL_PLUGIN_SETTINGS.ATTRIBUTE_01%type;
begin
    select attribute_01 into l_flow_name
    from APEX_APPL_PLUGIN_SETTINGS
    where application_id = :APP_ID
      and plugin_code = 'PLUGIN_COM.FLOWS4APEX.MANAGE_INSTANCE.PROCESS';
    l_pos := instr(l_flow_name,',');
    if l_pos > 0 then
        -- カンマがあれば、それに続くバージョンを取り除く。
        l_flow_name := substr(l_flow_name,1,(l_pos-1));
    end if;
    return l_flow_name;
exception
    when no_data_found then
        /* 
         * Global Flowが設定されていないので、アプリケーション・アイテムは設定しない。
         */
        return null;
end;
コンポーネント設定のGlobal Flowの値は、APEXの標準ビューAPEX_APPL_PLUGIN_SETTINGSの列ATTRIBUTE_01から取り出します。また、Global Flowはバージョンを含む場合があります。設定に, (カンマ)が含まれる場合は、バージョンの部分を取り除き、フロー・モデル名だけを取り出します。

以上の設定を行い、計算の作成を実行します。


アプリケーションの計算が作成されます。


以上でアプリケーション・アイテムG_FLOW_NAMEをバインド変数として扱うときはいつでも、コンポーネント設定のGlobal Flowが参照されるようになりました。

実際に設定されているかどうか確認するために、アプリケーションにサインインします。開発者ツール・バーより、セッションを実行します。


ビューとしてアプリケーション・アイテムを選択し設定をクリックすると、現在のセッションで設定されているG_FLOW_NAMEの値が表示されます。


バインド変数の設定は以上になります。

今回の作業中で気がついた点を追記しておきます。

プラグインを他のアプリケーションからコピーして作成する場合、コピーしますか?の指定で、はい(コピーのみ)とコピーおよびサブスクライブを選ぶことができます。

コピーしますか?はいを選択した画面です。


コピーおよびサブスクライブを選択した画面です。


コピーおよびサブスクライブを選択した場合、単にプラグインがコピーされるだけではなく、コピー元のプラグインに紐づけられた状態になります。

プラグインの設定画面のサブスクリプションマスター・プラグインの参照元として、コピーと元のプラグインが設定されます。コピー元のプラグインに変更があった場合、プラグインのリフレッシュを実行することにより、その変更をコピーとして作成されている、このプラグインに反映することができます。


コピーおよびサブスクライブを指定してプラグインを作成した場合、デフォルトではコンポーネント設定の画面で変更の適用のボタンが表示されません


サブスクライブしているプラグインで個別にコンポーネント設定を行うには、コンポーネント設定のサブスクライブOFFにします。


コンポーネント設定のサブスクライブOFFにすると、サブスクライブしているプラグインごとにコンポーネント設定を行うことができます。


今回の記事は以上です。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

2022年1月28日金曜日

Flows for APEXによる経費精算アプリの作成(8) - フロー・モニター

Flows for APEXでは、ワークフローの実行中に発生したエラーをフロー・モニターから確認することができます。エラーの原因を取り除いた後、エラーが発生したステップから再実行することもできます。

実際にエラーを発生させて、フロー・モニターの使用方法を確認します。

ステータスがdraftのフロー・ダイアグラムを開き、タスク従業員への通知PL/SQLコードをnull;から以下に変更します。このタスクが実行されるとき、つまり上司または部門長によって経費精算の申請が却下されたときに、タスク従業員への通知エラーが発生します。
begin
  raise_application_error(-20001,'エラー発生');
end;


変更の適用を実行し、フロー・ダイアグラムの変更を保存します。

APEXアプリケーション経費精算 - 開発中を実行します。従業員で経費精算を申請し、上司によって、その申請を却下します。ステータスはdelined_by_mgrになります。


declined_by_mgrをクリックし、ワークフローの進捗をビューワーで確認します。タスク従業員への通知が赤くマークされ、エラーが発生していることがわかります。


Flows for APEXのアプリケーションを実行し、インスタンスのステータスを確認します。

経費精算のバージョン2に、エラーが発生しているインスタンスが1つ、レポートされています。この数値をクリックします。


画面がフロー・モニターに移り、エラーが発生しているインスタンスの一覧とフロー・ダイアグラムが表示されます。詳細をクリックして、特定のインスタンスについてエラーの詳細を表示させます。


エラーが発生したワークフロー(プロセス・インスタンス)の詳細が表示されます。履歴の表示やフロー・ダイアグラムのタスクをクリックすると、エラーの詳細を確認できます。


履歴の表示の実行結果です。ユーザー定義例外の発生が報告されています。フロー・ダイアグラムで赤くなっている、タスク従業員の通知をクリックしても同じ表示ができます。


インスタンス・イベント変数より、プロセス変数の追加、変更、削除も可能です。画面には対話グリッドが使われています。


今回はPL/SQLコードのエラーなので、プロセス変数の編集は行いません。フロー・ダイアグラムを再度開き、タスク従業員への通知PL/SQLコードnull;に戻します。


変更の適用を実行し、フロー・モニターの画面に戻ります。

errorが発生しているプロセスの詳細を表示し、再起動を実行します。


確認画面が表示されるので、コメントを入力し確認をクリックします。


タスク従業員への通知が再実行されます。今度はエラーは発生しないので、フローはタスク申請の修正に移り、ステータスもrunningに変わります。


タイマー・イベントが有効であると、1分後にはワークフローは完了します。


ワークフローの処理の途中でエラーが発生した際、それまでに行われた処理をすべてキャンセルしてやり直すのは、現実的で無い場合も多いです。そのため、それぞれのステップでエラーを修正し、そのステップからワークフローを再実行できるのは、とても有用です。

Flows for APEXによる経費精算アプリの作成(7) - タイマー・イベント

BPMN 2.0に含まれるタイマー・イベントを使用してみます。

タイマー・イベントを使用するには、Flows for APEXのZIPファイルのApplications/Enable_Timers以下に含まれるenable_times.sqlを実行し、DBMS_SCHEDULERのジョブを開始する必要があります。

enable_timers.sqlをAPEXワークスペースで実行するには、ワークスペースのスキーマにCREATE JOB権限が必要です。以下のコマンドにて、権限を付与します。

grant create job to <ワークスペース・スキーマ>;

Autonomous Databaseの場合、ユーザーADMINデータベース・アクションに接続し、SQLの画面より実行します。


APEXに戻り、SQLワークショップSQLスクリプトを開き、ファイルenable_timers.sqlアップロードし、実行します。


Flows for APEX 22.2に添付されているenable_timers.sqlの内容です。FLOW_TIMERS_PKG.STEP_TIMERS10秒ごとに実行しています。

-- Enable timers in BPMN --
--
-- execute in your workspace schema
--
-- Make sure you have the privilege "create job"
-- If not, execute the following statement as sys first:
-- grant create job to <my_workspace_schema>;

begin
dbms_scheduler.create_program
( program_name => 'APEX_FLOW_STEP_TIMERS_P'
, program_type => 'STORED_PROCEDURE'
, program_action => '"FLOW_TIMERS_PKG"."STEP_TIMERS"'
, number_of_arguments => 0
, enabled => true
, comments => 'Update timers status and move the flow forward.'
);

dbms_scheduler.create_job
( job_name => 'APEX_FLOW_STEP_TIMERS_J'
, program_name => 'APEX_FLOW_STEP_TIMERS_P'
, job_style => 'LIGHTWEIGHT'
, start_date => systimestamp
, repeat_interval => 'FREQ=SECONDLY;INTERVAL=10'
, enabled => true
);
end;

以上の設定にて、フロー・ダイアグラムに含まれるタイマー・イベントが有効になります。

フロー・ダイアグラムを修正します。ステータスがdraftのバージョンのフロー・ダイアグラムをフロー・モデラーで開きます。今までの記事通りに作業をされていると、フロー・モデル経費精算のバージョン2がステータスdraftで編集可能になっているので、それを開きます。

上司部門長による申請のレビューにて却下された申請はタスク申請の修正へ回され、従業員による再提出待ち(タスク申請の修正)になります。このとき、一定の時間までに再提出されない場合は経費精算の申請を破棄(ステータスをabandonedに変更)し、ワークフローを完了します。

ツール・バーより中間境界イベントを作成を選択し、タスク申請の修正の上に配置します。


配置したイベントのタイプの変更(レンチのアイコン)より、タイマー境界イベントを選択します。


タイマー境界イベントのプロパティを設定します。名前再申請の待機とします。詳細タイマー定義タイプ日付または期間のどちらかを選択できます。今回は期間を選択します。どちらも書式にOracleまたはISO 8601を選択できます。

タイマー定義タイプとして期間(ISO 8601)を選択します。

タイマー定義にはISO 8601に従った値を指定します。今回はPT1Mとし、1分以内に再申請がなければ申請を破棄します。(PはPeriod - 期間、TはTime - 時間、1Mで1分の意味です)。


タイマー境界イベント再申請の待機の操作ツールよりタスクを追加を実行します。作成されたタスクのタイプスクリプトタスクに変更し、タスクの名前申請の破棄とします。


PL/SQLタブを開き、PL/SQLコードとして以下を記述します。



タスク申請の破棄の操作ツールより終了イベントを追加を実行します。作成された終了イベント名前支払いせずに完了とします。


以上でタイマー・イベントを使ったフロー・ダイアグラムに変更されました。変更の適用を実行して変更を保存します。

変更したフロー・ダイアグラムはバージョンのステータスをreleasedにするまで、稼働中のアプリケーションでは使用できません。とはいえreleasedに変更すると、フロー・ダイアグラムに間違いがあったときにバージョンをあげる必要があります。

こちらの記事で作成した経費精算 - 開発中のアプリケーションは、ステータスがdraftのバージョン2を使うように作られています。このアプリケーションを使って動作を確認します。

従業員にて経費精算の申請を行い、上司が却下をします。その状態で1分待ちます。もう一つ、経費精算の申請を行い部門長が却下します(金額は100米ドルより高額にします)。

両方の申請ともに、ステータスはabandonedになります。


上司に却下された後、再申請が時間切れになったフローをビューワーで確認します。


部門長に却下されたフローです。


どちらも期待通りのフローになっています。

変更したフロー・ダイアグラムのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/20221221-2347_%E7%B5%8C%E8%B2%BB%E7%B2%BE%E7%AE%97_draft_2.bpmn

Flows for APEXによる経費精算アプリの作成(6) - アプリケーションの更新

 リリース済みのフロー・モデルを変更する場合、最初にステータスがdraftの新バージョンを作成します。通常、APEXアプリケーションは、ステータスがreleasedのフロー・モデルのバージョンを選択するため、そのままではdraftのバージョンのワークフローを開始することはできません。



フロー・モデルの新バージョンのステータスがdraftの間は、稼働中のAPEXアプリケーションはreleasedのフロー・モデルのバージョン(上記の画面のスナップショットではバージョン1)を使い続けます。

経費精算のフロー・モデルのバージョン2を作成します。ステータスはdraftです。フロー・モデルの新しいバージョンに対応した変更をAPEXアプリケーションに対して実施するために、アプリケーションをコピーします。

アプリケーション・ビルダーにて稼働中のAPEXアプリケーションを開き、このアプリケーションのコピーを実行します。


新規アプリケーション名には、開発中であることがわかる名前を付けます。以下では経費精算 - 開発中としています。へ進みます。


確認画面が表示されます。アプリケーションのコピーを実行します。


アプリケーションのコピーが作成されます。


コピーしたアプリケーションがフロー・モデルのバージョン2を扱うように、設定を変更します。

プラグインFlows for APEX - Manage Flow Instance [プラグイン]コンポーネント設定に含まれるGlobal Flowを、バージョン番号を加えた経費精算,2に変更します。

変更の適用をクリックします。


ページ番号のページ経費精算の申請にあるプロセスF4A:ワークフローの開始を選択します。プロパティFlow (Diagram) selection based onをNameからName & Versionに変更します。その後に、変更を保存します。


アプリケーションをコピーする際に、ユーザーとロールの割り当てはコピーされません。

共有コンポーネントアプリケーション・アクセス制御を開き、ユーザー・ロール割当ての追加をクリックします。


ユーザー名を入力し(記事通りに作業を行なっていると、ワークスペースにサインインしているユーザー名になります)、アプリケーション・ロール上司従業員管理者経理部門長チェックを入れます。割当ての作成をクリックします。


ユーザー・ロール割当てが作成されます。


フロー・モデルのステータスがdraftのバージョンのフロー・ダイアグラムを編集します。

フロー・モデラーで該当のバージョンのフロー・ダイアグラムを開き、ユーザータスクのAPEXページのApplication IDを空白にします。


ワークフロー開始時に、プロセス変数APPLICATION_IDにアプリケーションID(&APP_ID.)を設定します。ユーザータスクのApplication IDが無指定の場合、プロセス変数APPLICATION_IDの設定が使用されます。

Set Process Variables?のJSONの記述をを以下に変更します。
[
    {
	    "name": "EXPE_AMOUNT",
	    "type": "number",
	    "value": &P3_EXPE_AMOUNT.
	},
    {
        "name": "APPLICATION_ID",
        "type": "number",
        "value": "&APP_ID."
    }
]
以上でフロー・モデルの変更は完了です。変更したフロー・ダイアグラムを保存します。

経費申請 - 開発中のアプリケーションを実行し、経費精算の申請を一通り実施します。

その後、Flows for APEXのアプリケーションを開きます。

フロー・モデルのバージョン2(ステータスはdraft)のインスタンスが増えています。コピーしたAPEXアプリケーションにて開始されたワークフローは、フロー・モデルのバージョン2に基づいていることが確認できます。


これ以降は通常のAPEXアプリケーションの開発作業になります。開発が完了したら、稼働中のアプリケーションと入れ替えます。

入れ替え後にコンポーネント設定Global Flow経費精算,2から経費精算、プロセス・プロパティFlow (Diagram) selection based onName & VersionからNameに戻します。

開発が完了している時点で、フロー・モデルのバージョン2のステータスはreleasedになっているはずです。そのため、この変更によって選択されるバージョンはどちらも4で変わりません。この変更はアプリケーションの利用を開始した後でも、問題なく実行できます。