【UiPath】ReFrameworkベースで交通費検索ロボットを作ってみる

UiPath公式のフレームワークとして**「ReFramework」**というものがあります。
ロボットの数が増えてきたときに、どのロボットも同じフレームワークで開発されていると保守が幾分楽になりますし、ロボットの設計/開発もやりやすくなると思います。
今回は前回作成した「交通費検索」ロボットをReFrameworkベースに作り直し、その中でReFrameworkがどのような仕組みになっているのかをまとめてみました。

##ロボットの処理概要
交通費検索をするにあたって、ロボットを「キュー登録」と「本処理」の2つに分けます。

###交通費検索_キュー登録

####Mainページ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/2c472128-26d1-cf6e-0f0b-44d5dbf98c9b.png)

####プロジェクト構成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/efdffb08-d29d-e4d8-d6cb-2a4196b949df.png)

#####1. configファイル読込
Dataフォルダ内に配置されているConfigファイルを読み込み、Directory型の配列に格納し、Mainに返却します。
Configファイルは3つのシート**「Settings」「Constants」「Assets」**に分かれています。
Settings、ConstantsはConfigファイルで定義した定数、AssetsはOrchestratorで定義した定数です。
Assetsシートに記載された定数に関しては、Orcehstratorのアセットに定義された定数と名前が合致していれば配列に格納します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/2f4ca9d6-16a5-0d99-f2cb-538f44bcc18d.png)

#####2. アップロードフォルダから交通費ファイルを取得し、キューに登録
[【UiPath】交通費検索ロボットを作ってみる](https://qiita.com/irohamaru/items/1a71000c650089ccd41d)
と同様、各社員が交通費検索用のファイルを配置するという運用を仮定します。
共有フォルダ（本記事ではローカルフォルダ）に、各社員が自身の社員番号のフォルダに交通費検索用のファイルを配置します。
ロボットはそれらのファイルを社員の数分取得し、内容を読み取り、Orchestratorの「キュー」という場所にデータを格納します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/0bc47b09-bf4f-d70f-b2f5-f543a4d84031.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/6237ca15-57f7-2cb7-d10e-b7ffd691921a.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/3ea2f8f7-9987-30b6-12d3-5a4d9679126b.png)

キューは以下のように登録されます。
今回、**「交通費検索_ヘッダーキュー」「交通費検索_明細キュー」**の2つのキューを用意します。

ヘッダーキューには読み込んだファイル、明細キューは読み込んだファイルの内容を登録する仕様とします。
例えば、「10000000_交通費.xlsx」に4ルート記載があった場合は、ヘッダーキューは1件、明細キューは4件登録されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/641a2154-d311-b74b-ef64-d1e052337e47.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/5391215f-f475-649c-f5fa-9c393ff470c8.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/b50f9837-6386-e7d1-81c5-5b850e3ff98e.png)

明細キューには、出発/到着駅、片道・往復、経路（優先ルートの指定）など、路線検索の詳細も登録します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/fe169287-b7d9-d983-5c77-d35bd77bca5f.png)

###交通費検索_本登録

基本的な動作は[【UiPath】交通費検索ロボットを作ってみる](https://qiita.com/irohamaru/items/1a71000c650089ccd41d)と同じですが、データの取得元が「交通費検索_キュー登録」ロボットで登録したキューになります。

####Mainページ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/2298c650-fb2b-9ab6-b33f-821bacc1ce6d.png)

####プロジェクト構成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/db26c487-e4c3-f498-ab7a-499b46ddf667.png)

#####1.  Configファイル読込
「交通費検索_キュー登録」ロボットと同じ処理です。
Mainページの**「Init」**の中で呼び出している**「InitAllSettings.xaml」**でConfigファイルを読み込みます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/60533ba9-b75f-2a9a-d843-5ca630afcde9.png)

#####2. 起動しているプロセスを強制終了する
InitAllSettingsの後、**「KillAllProcesses.xaml」**にて指定したプロセスを強制終了します。
今回はChromeを強制終了するようにします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/9ba9db4a-c13a-3a6b-188c-be45076eb1d0.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/befce2cc-7a3f-b1ba-bcc3-cd8f4676ab56.png)

#####3. Chromeブラウザを起動し、Yahoo!路線検索を開く
KillAllProcessesの後、**「InitAllapplications.xaml」**にてChromeでYahoo!路線検索を開きます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/214f630f-4893-b1dd-f771-f84686d34c66.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/cf3692cb-5c54-e9ca-0ff0-00f9c585b086.png)

#####3. ヘッダーキューからデータ取得
Mainページの**「Get Transaction Data」**の中のアクティビティ「Get Transaction Item」でヘッダーキューを1件取得します。取得するのはキューステータスが「新規」となっているデータのみです。「完了」となっているキューデータは取得対象外です。
この「Get Transaction Data」と、この後の処理「Process Transaction」はヘッダーキューに登録されたキューデータの件数分ループして実行されます。
つまり、Get Transaction DataとProcess Transactionは1セットで実行されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/1910a446-1d21-9245-7a0b-c6178ef6a52d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/4c27a26b-774a-ecd6-0ee4-fd06158a5cee.png)

#####4. 明細キューからデータ取得
Mainページの**「Process Transaction」**の中で呼び出されている**「Process.xaml」**にて、ヘッダーキューに紐付く明細キューデータを全件取得します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/1cbc4dc7-cd6f-8cc0-4445-3bb198ab1183.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/3dcc0e30-69c6-e1f9-5e91-d17339602957.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/ff9ede4c-42af-bc18-289b-9a3785fbc611.png)
ヘッダーキューと明細キューを紐付けるキーは、ヘッダーキューの「参照」とします。
今回の場合、ファイル名がキーとなって、そのファイルに記載された4ルート（＝明細キュー4件）が取得できるようにしています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/c68b80d3-0e4c-a796-db11-6ed5b8e2df85.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/e82468e1-19f5-f789-d3b8-5ffccfb7ebee.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/c21da5e5-61c6-b746-f426-2defe4480eee.png)

#####5. Yahoo!路線検索で路線検索＆交通費を取得
**「交通費記入.xaml」**にて明細キュー1件ずつ路線検索を行い、交通費をファイルに記入していきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/ab2e3155-d617-243f-eaf7-61b9a305dbd4.png)

路線検索とファイル記入が正常に完了したら、明細キューのステータスを「成功」に更新します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/e6e5c235-ed3b-6b5f-893f-eb9eccf63e8f.png)

#####6. ヘッダーキューステータス更新
Process Transactionの処理完了後（＝1ファイルに記載された全てのルートの路線検索＆交通費記入が完了した後）、「SetTransactionStatus.xaml」にてヘッダーキューのステータスを「成功」に更新します。
Process Transactionの処理を眺めると分かるのですが、Try~Catch~FinallyのTryの中で「Process.xaml」が呼び出され、Finallyで「SetTransactionStatus.xaml」が呼び出されています。
Process.xamlの処理中に発生したエラーが「BusinessRuleException」としてキャッチされる分類のエラーであれば、キュー定義時に指定したリトライ回数上限まで、再度Get Transaction Dataから処理を実行し直します。
「BusinessRuleException」以外のエラーの場合は、Initから実行し直します。
※このあたりの例外制御については、後日追記します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/86007146-7716-261d-d82f-bec5c9dbd428.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/4ebaec96-b161-5849-e4b5-4a2e2bd8d591.png)

#####7. アプリケーションを閉じる
Mainページの**「End Process」**の中で呼び出している**「CloseAllApplications.xaml」**にてアプリケーションを閉じます。
今回は、ChromeをショートカットキーAlt+F4で閉じるという実装を入れます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/ce7fb6c6-41ce-0510-d2df-c580e5d3d56a.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/8a6b1b8c-c415-e3ae-c971-74ca32237183.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/186221/601ed928-681b-3eba-91b6-9c5274583ceb.png)

##まとめ
比較的規模の大きいロボット向けのフレームワークということもあり、Orchestratorの導入が前提の実装となっている印象です。
Orchestratorを利用するメリットは[【UiPath】Orchestratorことはじめ](https://qiita.com/irohamaru/items/a2bbfb4e647f2cb9146b)を読んでいただければと思います。
それ以外のReFrameworkの特徴で注目したいポイントは以下のとおりです。

###リトライ処理
Process Transactionで例外発生時、リトライ処理を行なうことも可能となっていますが、リトライを正常に行える状態に戻す処理を工夫する必要があるかもしれません。
例えば、ファイル移動後に例外発生した場合はファイルを戻す処理が必要ですし、キューの状態を戻す処理や操作対象のアプリケーションの再起動などを考慮する必要があります。

###テストフレームワーク
RPAは仕様変更/改修が比較的容易にできる半面、デグレを起こしやすいとも言えます。
また、操作対象の基幹システム、Webサイト等に画面改修が入った場合、正常に動作しない可能性が高いです。
なので、テスト効率を上げるというのはRPAにおいてはかなり重要です。テスト品質を落とさず、時短で実施できなければRPA導入のメリットを享受できません。（時間がかかるならシステム改修するわ、ってなってしまう。。。）
まだ詳しく実装を見ていないのですが、うまく活用したい仕組みです。

###エラー発生時のスクリーンキャプチャ
RPAの特徴でもあるのですが、エラー発生時に何が原因なのかがわかりづらい場合があります。
例えば、本番環境と検証環境でロボットの挙動に差がある場合もあり、本番環境で何が起きたのかをキャプチャでエビデンスとして保存できるのは助かります。
エラーログからボタン押下に失敗したのか、そもそもブラウザやアプリの起動に失敗しているのか判別できないことも想定されます。（カーナビで目的地周辺で音声案内を終了される感じですねｗ）

##本記事で作成したプロジェクト
https://github.com/kktrip/UiPath/tree/master/reframework