1. スクリプトタスクの活用シーンについて、概要を理解する
- 1. データ代入
- ECMA スクリプトで生成した日付や数値などを自動的に代入させる
- 2. データ加工
- 入力済みの数値や文字列を加工し、新たなデータとして代入する
- “ECMA スクリプト”とは、JavaScript と JScript の共通部分をベースに標準化されたスクリプト言語です
2. スクリプトタスクで利用できるクラスについて、概要を理解する
- a. 推奨される JavaScript
- “ECMA-262, Edition 3” (JavaScript 1.5) に規定された全てのクラス
- b. 利用可能な JavaScript
- “ECMA-262, Edition 5” (JavaScript 1.7/1.8) の多くのクラス
- c. 利用可能な Java クラス
- 業務データへのアクセスに必要な Java クラス、他
- JavaScript と Java の基礎的な知識が必要になります
R2300 スクリプトタスクで利用できる Java クラス
3. スクリプトタスクを設定する
- 1. ECMA コードを登録する
- データ参照、データ加工、データ代入などの処理コードを記入します
- 業務データの代入や更新は、スクリプト処理完了後に一括して行われます
- エラー発生時には代入更新は行われません (次の処理に進みます)
- スクリプトの処理時間は最長で30秒に制限されます (負荷状況により若干変動します)
//// == Data Retrieving == var dataA = engine.findDataByNumber("0") + ""; // 業務データ0を参照 var dataB = engine.findDataByName("Data B") + ""; // 「Data B」という項目名の業務データを参照 // convert java.lang.String → javascript string //// == Calculating == var newData = dataA + dataB; //// == Data Updating == engine.setDataByNumber("3", newData ); //業務データ代入
R2301 Scriptデータ取得/代入
R2252 OAuth トークン取得手順
X. ワークフローサンプル
- 2017-04-24 (請求書発行プロセス-滞留): 第532話:他システムへの記録、急がば回れ(改善編)
- 2017-04-17 (テレビ番組のキーワード検索): 第531話:自動的にテレビ番組表を検索する
- 2017-04-10 (送金プロセス): 第530話:「更新系API」で支払業務の自動化
- 2017-04-03 (PayPal請求プロセス): 第529話:PayPal業務のサブルーチン化
- 2017-03-27 (エントリ受付システム-ペイパル請求~入金確認): 第528話:自動工程で PayPal ステータスの自動確認
- 2017-03-21 (エントリ受付システム): 第527話:自動工程で PayPal Invoicing API を呼ぶ
- 2017-03-13 (証明書発行フロー-和暦変換アドオン): 第526話:自動生成 PDF の「証明書発行日」を和暦で!(改善編)
- 2017-03-06 (請求書送信プロセス): 第525話:自動工程から OAuth2 リクエストを送出させる方法
- 2016-12-19 (内閣答弁作成プロセス): 第514話:政治家こそ「生産性向上」を実践して見せよ!
- 2016-11-28 (請求書発行プロセス): 第511話:振替伝票ファイルを自動生成させる(Excel-CSV)
- 2016-09-12 (前受金登録フロー): 第500話:振替伝票は手作業??
- 2016-08-15 (翻訳プロセス-アドオン): 第496話:自動工程におけるデータ加工、アレコレ(その3)
- 2016-08-08 (文字数カウンタ): 第495話:自動工程におけるデータ加工、アレコレ(その2)
- 2016-08-01 (文字数カウンタ): 第494話:自動工程におけるデータ加工、アレコレ(その1)
- 2016-07-25 (共有パスワード問合): 第493話:共有パスワードの利用を管理する(Sheets API v4)
- 2016-07-19 (顧客マスタ同期プロセス): 第492話:取引先マスタ Spreadsheet を 参照する(Sheets API v4)
- 2016-07-11 (入出金のログ登録): 第491話:銀行 CSV を Google Sheets に流し込む
- 2016-06-20 (販売報告プロセス): 第488話:クラウド会計と連携させる(その3)
- 2016-06-13 (販売報告プロセス): 第487話:クラウド会計と連携させる(その2)
- 2016-06-06 (販売報告プロセス): 第486話:クラウド会計と連携させる(その1)
- 2016-05-30 (資料請求対応業務): 第485話:「カタログ送付先リスト」に対して自動追記する(kintone API)
- 2016-05-23 (与信管理フロー): 第484話:新しい取引先を kintone API で追加する
- 2016-04-25 (請求書発行フロー): 第480話:自動工程の直後に「10分滞留」を配置する意味
- 2016-04-18 (請求書発行フロー): 第479話:スクリプト工程に「日割り計算」をさせるときの注意
- 2016-02-29 (出退勤報告フロー): 第472話:業務システムでインフルの兆候をつかむ?
- 2016-02-15 (上司評価の投票(無記名投票)): 第470話:チームリーダーの評価を「無記名投票」で!
- 2016-02-08 (社員個人情報の申請受付): 第469話:住所変更届(社員マスターの自動更新付)
- 2016-01-25 (証明書発行フロー): 第467話:自動生成 PDF の「証明書発行日」を和暦表示する
- 2016-01-12 (出退勤報告フロー): 第465話:勤怠管理もクラウド型ワークフローで!
- 2016-01-04 (立替金精算フロー): 第464話:立替金精算依頼を回す(基本業務パック)
- 2015-12-14 (取引先マスタ登録商号の自動チェック): 顧客マスタを「法人番号システム Web-API」でクリーニング(改良版)
- 2015-12-07 (取引先マスタ登録商号の自動チェック): 顧客マスタを「法人番号システム Web-API」でクリーニング
- 2015-10-19 (営業日報プロセス): 日報プロセスに「GPS情報」も記録する
- 2015-10-13 (問合対応プロセス): 取引先マスターを参照するクレーム管理
- 2015-10-05 (営業日報フロー): 取引先マスターを参照する営業日報
- 2015-09-28 (見積書作成業務): 取引先マスターを参照する見積書作成フロー
- 2015-09-21 (取引先マスターのメンテナンス業務): 法人番号を使った取引先マスターの管理(一括更新編)
- 2015-09-14 (取引口座開設業務): 法人番号を使った取引先マスターの管理(追加更新編)
- 2015-08-31 (Check Digit サンプル): マイナンバー制度における「チェックディジット」の役割
- 2015-05-11: 申請された立替データを、直接修正しない!
- 2015-05-04: テーブル型の立替データから、必要項目の CSV を出力する
- 2015-04-27: 請求書発行フローと会計システムの連携
- 2015-03-30: 「テンプレ文の整備」で効率化される業務
- 2015-03-23: 相見積審査の可視化と省力化
- 2015-03-16: 在宅就労システム、無料クラウドでココまで出来る!
- 2015-03-09: 「稟議力」をキタエル(?)、不思議な業務プロセス
- 2014-12-08: 「電力使用率」などの外部環境変化で開始されるワークフローその2
- 2014-12-01: 「電力使用率」などの外部環境変化で開始されるワークフロー
- 2014-11-25: 過去の稟議記録を一括インポートする
- 2014-11-04: 溜まるハズの「日報」が、溜まらない仕組みを作れ!
- 2014-09-22: リモートワーク、「就労時間管理」も意外と大切デス
- 2014-08-25: 決裁に要している時間、平均で何時間?
- 2014-07-22: 自動処理スクリプトで、案件タイトルをセット
- 2014-04-28: 採用プロセスの標準化、注意すべきポイント
- 2014-04-07: 「取締役会議事録を電子化する」と言う ≪大変革≫ の意義
- 2014-02-17: 社外からの通報、どう対応しているの? (回答業務フロー)
Y. 関連マニュアル
- M207 データ項目 データ項目の初期値があらかじめ入力されているように設定する
- M227 自動工程 業務データの結合や四則演算が自動実行されるように設定する
- M405 データ項目 業務データを加工変換した文字列が途中セットされるように設定する(文字列の加工例)
- M406 データ項目 ユニークな “ドキュメントID” が途中生成されるように設定する(文字列の生成例)
- M407 データ項目 業務の流れ 挿し込みメールが繰り返し送信されるように設定する
- M408 データ項目 引受ルール 引受担当者が当番式に自動決定されるように設定する
- M415 自動工程 業務プロセス定義で利用可能な自動工程を追加する
- M416 自動工程 業務プロセス定義で利用可能な自動工程を自作する
Z. 追加情報: スクリプト実行エンジン
- a. Rhino エンジン
- [スクリプト工程]は、スクリプト実行エンジン “Rhino” (ライノゥ/原意:動物のサイ)によって処理されます。(サーバーサイド)
- b. Rhino の特徴
- プロセスモデル設計者は “ECMAScript” (JavaScript) による自動処理スクリプトだけでなく “Java メソッド” による自動処理スクリプトも設定できます(Scripting Java)。たとえば
new java.lang.String("kyoto")
のような書式でオブジェクトを生成すれば、replaceFirst()
といった Java String クラスのメソッドが使用できるようになります。 - c. ワークフローに流れるデータの参照
- “請求日” や “見積額” といった業務データを参照するには、特別なメソッド
data.get("♦項目ID♦")
engine.findDataByNumber("♦項目ID♦")
を利用します。Java インスタンスとして呼び出されるため JavaScript string として扱いたい場合はvar text = data.get("♦項目ID♦") + "";
var text = engine.findDataByNumber("♦項目ID♦") + "";
などの明示的な型変換が推奨されます。/// TYPEOF test - for Rhino ECMA engine var workflowData = data.get("0") ; var teststring = ""; teststring += "-- primitive Number -- \n"; teststring += typeof 99 + "\n"; // 'number' teststring += typeof 9.99 + "\n"; teststring += typeof Infinity + "\n"; teststring += typeof NaN + "\n"; teststring += typeof Number(9) + "\n"; teststring += "-- primitive String -- \n"; teststring += typeof "" + "\n"; // 'string' teststring += typeof "Questetra" + "\n"; teststring += typeof (typeof 99) + "\n"; teststring += typeof String("ECMA") + "\n"; teststring += "-- Object -- \n"; teststring += typeof new Number(9) + "\n"; // 'object' teststring += typeof new String("ECMA") + "\n"; teststring += typeof new java.lang.String("ECMA") + "\n"; teststring += typeof workflowData + "\n"; teststring += typeof data.get("0") + "\n"; teststring += typeof new com.questetra.bpms.core.model.formdata.ListArray() + "\n"; teststring += "-- XML -- \n"; teststring += typeof <foo bar="BAR">FOO</foo> + "\n"; // 'xml' teststring += typeof XML('<foo bar="BAR">FOO</foo>') + "\n"; teststring += typeof new XML('<foo bar="BAR">FOO</foo>') + "\n"; teststring += "--- additional info --- \n"; teststring += typeof true + "\n"; // 'boolean' teststring += typeof undefined + "\n"; // 'undefined' teststring += typeof [1, 2, 4] + "\n"; // 'object' teststring += typeof /s/ + "\n"; // 'object' teststring += typeof null + "\n"; // 'object' (not 'null') teststring += typeof function(){} + "\n"; // 'function' // teststring += typeof Symbol() + "\n"; // ERROR (not 'symbol') retVal.put( "0", teststring );
testX <- String("BPMS") testX is NOT instanceof String testX is NOT instanceof java.lang.String testY <- new String("ECMA") testY is instanceof String testY is NOT instanceof java.lang.String testZ <- new java.lang.String("JAVA") testZ is instanceof String testZ is instanceof java.lang.String test1 <- data.get( "8" ) test1 is instanceof String test1 is instanceof java.lang.String test1b <- data.get( "8" ) + "" test1b is NOT instanceof String test1b is NOT instanceof java.lang.String test2 <- data.get( "9" ) // Select test2 is NOT instanceof String test2 is NOT instanceof java.lang.String test2 is instanceof java.util.ArrayList
- d. ワークフローに流れるデータの更新
- スクリプト工程にて演算された値を、ワークフローに流れる業務データとして代入するには、特殊なメソッド
retVal.put("♦項目ID♦","♦新しい値♦")
engine.setDataByNumber("♦項目ID♦","♦新しい値♦")
を利用します。(ECMA/JavaScript には数値に関する型が "number型" しか存在しないため、スクリプト内で演算された結果をワークフロー側に戻す際に "java.math.BigDecimal" を明示的に記述する必要があります) - e. 業務に役立つ関数およびサンプルコード
//////// == 演算 / Calculating == var myrand = Math.floor( Math.random() * 5 ) ; // 0 or 1 or 2 or 3 or 4 //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", java.math.BigDecimal(myrand) );
//// == ワークフローデータの参照 / Retrieving == var timestart = data.get("♦DataDefID♦"); // 日時型:プロセス開始時刻 var timesent = data.get("♦DataDefID♦"); // 日時型:回答メール送信時刻 //// == 演算 / Calculating == var conciergesec = timesent.getTime() - timestart.getTime(); var conciergehour = java.math.BigDecimal( Math.floor( conciergesec / (1000 * 60 * 60) )); // Math.floor 切り捨て //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦",conciergehour); var daystart = timestart.getDay(); // 問い合わせ発生曜日のメモ if (daystart == 0) retVal.put("♦DataDefID♦","日曜日"); if (daystart == 1) retVal.put("♦DataDefID♦","月曜日"); if (daystart == 2) retVal.put("♦DataDefID♦","火曜日"); if (daystart == 3) retVal.put("♦DataDefID♦","水曜日"); if (daystart == 4) retVal.put("♦DataDefID♦","木曜日"); if (daystart == 5) retVal.put("♦DataDefID♦","金曜日"); if (daystart == 6) retVal.put("♦DataDefID♦","土曜日");
//// == ワークフローデータの参照 / Retrieving == var mynumber = data.get("♦DataDefID♦") + ""; //// == 演算 / Calculating == if( mynumber.length == 13 ){ var mysum = 0; for( i=1; i<13; i++){ mysum += parseInt( mynumber.charAt(i) ) * (i % 2 + 1); } var checkdigitnum = 9 - mysum % 9; var typedcd = parseInt( mynumber.charAt(0) ); //// == ワークフローデータへの代入 / Updating == if( typedcd == checkdigitnum ){ retVal.put("♦DataDefID♦", "OK" ); } else { retVal.put("♦DataDefID♦", "ERROR" ); } }
//// == ワークフローデータの参照 / Retrieving == var weatherjson = JSON.parse(data.get("♦DataDefID♦")); // 中間イベント等で取得済の想定 //// == 演算 / Calculating == var mydesc = weatherjson.list[0].weather[0].description; var mytemp = java.math.BigDecimal(weatherjson.list[0].temp.max - 273.15); //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", mydesc ); retVal.put("♦DataDefID♦", mytemp );
//// == ワークフローデータの参照 / Retrieving == var fromaddr = data.get("♦DataDefID♦") + ""; var inq = data.get("♦DataDefID♦") + ""; //// == 演算 / Calculating == var inquirywithmark = inq.replace(/(^.*$)/gm, "> "+"$1"); // 行頭リダイレクトマーク //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", fromaddr + '\n' + inquirywithmark );
//////// == ワークフローデータの参照 / Retrieving == var csv_text = data.get("♦DataDefID♦"); // 文字列型複数行のCSVデータ(4列)を前提 // ex) // Nakagyo-ku, Kyoto-shi, Kyoto-pref, Japan // Malibu, Los Angeles County, California, USA //// == 演算 / Calculating == var csvObj = new String( csv_text ); // String オブジェクト (JavaScript) var tmpTable = new com.questetra.bpms.core.model.formdata.ListArray(); // テーブル型データ var lineArray = csvObj.split("\n"); // 改行毎に分割し String[] 配列に格納 for (var i=0; i < lineArray.length; i++){ var tmpRow = new com.questetra.bpms.core.model.formdata.ListArray.ListRow(); // 追加行(横列) var cellstrArray = lineArray[i].split(","); // カンマ毎に分割し格納 tmpRow.addCol( cellstrArray[0] ); tmpRow.addCol( cellstrArray[1] ); tmpRow.addCol( cellstrArray[2] ); tmpRow.addCol( cellstrArray[3] ); tmpTable.addRow( tmpRow ); // 行追加 } //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", tmpTable );
//// == ワークフローデータの参照 / Retrieving == // mytable: com.questetra.bpms.core.model.formdata.ListArray var mytable = data.get("♦DataDefID♦"); // テーブル型データを取得 //// == 演算 / Calculating == var i=0; var n = mytable.size(); var texttsv = ""; for (i=0; i < n; i++){ texttsv += mytable.get(i, 0) + "\t"; texttsv += mytable.get(i, 1) + "\t"; texttsv += mytable.get(i, 3) + "\t"; texttsv += mytable.get(i, 4) + "\n"; } //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", texttsv );
//// == ワークフローデータの参照 / Retrieving == var quserEmail = data.get("♦DataDefID♦") + ""; // 文字列データに "example@example.net" が格納されている前提 //// == 演算 / Calculating == // com.questetra.bpms.core.event.scripttask.QuserDaoWrapper var quser = quserDao.findByEmail(quserEmail); //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", quser);
//// == ワークフローデータの参照 / Retrieving == optionsList = itemDao.findAll("value-display-list.xml", true); // M319 Options-XML //// == 演算 / Calculating == optionsNum = optionsList.size(); var value_id_list = ""; var display_label_list = ""; for (i=0; i < optionsNum; i++){ value_id_list += optionsList.get(i).getValue() + "\n"; display_label_list += optionsList.get(i).getDisplay() + "\n"; } //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", value_id_list); retVal.put("♦DataDefID♦", display_label_list);
//// == ワークフローデータの参照 / Retrieving == optionsList = itemDao.findAll("value-display-list.xml", true); // M319 Options-XML //// == 演算 / Calculating == var tmpTable = new com.questetra.bpms.core.model.formdata.ListArray(); // テーブル型データ optionsNum = optionsList.size(); for (i=0; i < optionsNum; i++){ var tmpRow = new com.questetra.bpms.core.model.formdata.ListArray.ListRow(); // 追加行(横列) tmpRow.addCol( optionsList.get(i).getValue() ); tmpRow.addCol( optionsList.get(i).getDisplay() ); tmpTable.addRow( tmpRow ); // 行追加 } //// == ワークフローデータへの代入 / Updating == retVal.put("♦DataDefID♦", tmpTable );