サポート > リポジトリ > ワークフロー > スクリプトによって承認者・決裁者を動的に決定する
ja | en

スクリプトを用いてワークフローの承認者・決裁者を動的に変更することができます。 R7.9

スクリプトを用いて承認者や決裁者を動的に決めることができます。ここでは、アカウント(juser)に割り当てられたプリンシパルを使って承認者や決裁者を算出する方法を紹介します。

スクリプト中は Dao, Service オブジェクトを使って他のモデルのデータを参照できます。検索絞り込みは Criteria を利用できます。詳細は「業務ロジック」をお読みください。

アカウント

次に示すアカウントを用意しておきます。

営業部

アカウント プリンシパル
amuro申請者
nakamura承認者
shinjo承認者
onaga決裁者
図2 営業部アカウント

プリンシパルはモデル毎に設定します。図3は、年休申請モデルに設定したプリンシパルです。

図3 年休申請モデルに設定したプリンシパル

アカウント amuro, nakamura, onaga に割り当てたプリンシパルを確認します。(図4,図5,図6)

図4 アカウントamuroのプリンシパル
図5 アカウントnakamuraのプリンシパル
図6 アカウントonagaのプリンシパル

通常、フロー参加者はユーザーまたはグループを指定します。しかし今回は「合議・順次・順次フロー」に対して次の設定を行います。

ノード 区分 説明
申請1 合議 技術部
申請2 合議 営業部
承認 順次 (承認者を決定するスクリプト:後述)
決裁 順次 (決裁者を決定するスクリプト:後述)

申請を合議としているため、技術部または営業部に所属している誰でも申請が可能となります。

図7 フロー参加者設定

ここで用いているフローパターンを確認します。申請時の合議のノード数は 1 としているため(グループに所属していれば)誰でも申請可能となっています。

図8 フローパターンの確認

承認者を決定するスクリプト

申請者と同一のグループに属するユーザで、かつプリンシパルに「承認者」が付与されているユーザを取得します。これを承認者として扱うようにします。このため、ユーザに付与するプリンシパルを変えることで、承認者が動的に変わります。

// 申請者の所属するグループの承認者を取得する
var getAdmitUsers = function(users) {
  stdout.println("getAdmitUsers users:["+users+"]");
  var admitUsers = "";
  if (!users || users.length == 0) {
    return admitUsers;
  }
  //stdout.println("承認者数:["+users.length+"]");
  //stdout.println("承認者1:["+users[0]+"]");
  admitUsers = users[0].getUserid();
  for (var i=1; i<users.length; i++) {
    //stdout.println("承認者"+(i+1)+":["+users[i]+"]");
    // 承認者が複数の場合は区切り文字「|」を付加して連結する
    admitUsers = admitUsers + "|" + users[i].getUserid();
  }
  return admitUsers;
};

var getApprovalPerson = function(applicant) {
  var groupid = applicant.getJgroupid();
  var juserEntityService = p.appctx.getBean("JuserEntityService");
  var juserMeta = new JuserMeta();
  var criteria = DetachedCriteria.forClass(juserMeta.entityClass());
  // 申請者の所属するグループを条件にする
  if (groupid && groupid.length > 0) {
    criteria.eq(juserMeta.jgroupid, groupid[0]);
  }
  // 承認者プリンシパルを条件にする
  criteria.eq(juserMeta.jprincipalId, 15);
  criteria.eq(juserMeta.jprincipalId, 19);
  return juserEntityService.find(criteria);
};

// 処理の本体。applicant は申請者を指す。
if (applicant == null) {
  return null;
}
stdout.println(applicant);
var admitUsers = getAdmitUsers(getApprovalPerson(applicant));
stdout.println(admitUsers);
return admitUsers;
stdout.println はデバッグ用です。本番運用時はコメントアウトしてください。
  • 2行目から17行目まで、関数 getAdmitUsers を定義しています。
  • 19行目から32行目まで、関数 getApprovalPerson を定義しています。
  • 本体は33行目以降です。暗黙変数 applicant は、申請者を示します。実体は juser です。
  • 39行目で次の承認者を求めています。まず申請者を引数にして関数 getApprovalPerson を呼び出します。これは申請者と同じグループに所属する他のアカウントを求めています。絞り込み条件は criteria を使って表記します。プリンシパルは ID を使うことに注意してください。Wagby ではプリンシパルIDは(削除しない限り)一度、割り当てられたものが使われ続けます。インポートエクスポートを行ってもプリンシパルIDは維持されます。
  • さらに getApprovalPerson の戻り値を使って、getAdmitUsers を呼び出します。この関数は引数の users が複数あった場合、各アカウントを "|" で区切った一つの文字列を返すものです。Wagbyのワークフロー処理では、複数アカウントは "|" を使って区切るようになっています。

決裁者を決定するスクリプト

申請者と同一のグループに属するユーザで、かつプリンシパルに「決裁者」が付与されているユーザを取得します。これを決裁者として扱うようにします。このため、ユーザに付与するプリンシパルを変えることで、決裁者は動的に変わります。

// 申請者の所属するグループの決裁者を取得する
var getAdmitUsers = function(users) {
  stdout.println("getAdmitUsers users:["+users+"]");
  var admitUsers = "";
  if (!users || users.length == 0) {
    return admitUsers;
  }
  //stdout.println("承認者数:["+users.length+"]");
  //stdout.println("承認者1:["+users[0]+"]");
  admitUsers = users[0].getUserid();
  for (var i=1; i<users.length; i++) {
    //stdout.println("承認者"+(i+1)+":["+users[i]+"]");
    // 承認者が複数の場合は区切り文字「|」を付加して連結する
    admitUsers = admitUsers + "|" + users[i].getUserid();
  }
  return admitUsers;
};

var getApprovalPerson = function(applicant, principalIds) {
  var groupid = applicant.getJgroupid();
  var juserEntityService = p.appctx.getBean("JuserEntityService");
  var juserMeta = new JuserMeta();
  var criteria = DetachedCriteria.forClass(juserMeta.entityClass());
  // 申請者の所属するグループを条件にする
  if (groupid && groupid.length > 0) {
    criteria.eq(juserMeta.jgroupid, groupid[0]);
  }
  // 決裁者プリンシパルを条件にする
  criteria.eq(juserMeta.jprincipalId, 17);
  criteria.eq(juserMeta.jprincipalId, 21);
  return juserEntityService.find(criteria);
};
if (applicant == null) {
  return null;
}
stdout.println(applicant);
var admitUsers = getAdmitUsers(getApprovalPerson(applicant));
stdout.println(admitUsers);
return admitUsers;
stdout.println はデバッグ用です。本番運用時はコメントアウトしてください。
スクリプトの内容は「承認者を決定するスクリプト」と類似しているため、説明を割愛します。

申請者 amuro でログオンし、ワークフローを申請した例を図9に示します。スクリプトの実行によって、次の処理保留者が nakamura と shinjo となっていることがわかります。(次の処理保留者は WF_USERID 関数で求めています。)

図9 アカウントamuroによる申請後

次の承認者 nakamura が承認した例を図10に示します。スクリプトの実行によって、次の処理保留者(決裁者)は onaga となっていることがわかります。

図10 アカウントnakamuraによる承認処理後

ワークフロー参加者に設定するスクリプト内でモデルID(で示されるオブジェクト)を利用できます。例えばワークフローを利用するモデルが leave であればスクリプト中に次のように記述することができます。

var reason = leave.reason;

標準では、この変数(オブジェクト)は参照連動や自動計算の処理を行っていません。これはパフォーマンスを優先しているためです。参照連動項目を解決し、計算式の値を取得する場合は、次のように EntityService を経由してください。

var entityService = p.appctx.getBean("LeaveEntityService");
var leave = entityService.findById(modelpkey);

ここで変数modelpkeyも、このスクリプトで暗黙的に利用できます。対象モデルの主キーを保持するため、findById の引数として利用できます。

  • フロー参加者スクリプトのデータベースの型は、各データベースの CLOB に相当する型を用いるようにしています。スクリプトのサイズの最大長は、データベースの CLOB 型の上限値となります。例えば Oracle では NCLOB となります。詳細は、自動生成された jfcparticipant_setting.ddl をご確認ください。
  • スクリプトで参照可能な暗黙変数 applicant の実体は juser オブジェクトです。
  • このスクリプトは、ワークフロー処理の仮定で複数回、実行されることがあります。何回実行されるかはフロー設定により変わるため、複数回実行されても結果が変わらないようにしてください。(具体的には、N回呼び出されることを前提としたり、N回目の呼び出しのときに処理を変える、というような手順を加えないようにしてください。)