Power Automate で稟議書を実装してみた4 (Power Automate 編2)

## 経緯

[前回](https://qiita.com/miyamiya/items/35ca2d1cd05bc77396ce) は、Power Automate の前半部分、利用する変数の紹介を行いました

今回はメインの処理部分に入りますが、やってることは大したことないのにアクションの量が多いので、分けて説明します
今回は下図の赤枠の部分を説明します
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h59_28-211x300.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h59_28.png)

## 上部の赤枠の説明

### 作成されたアイテムに設定された承認ルートを取得

申請ワークフローリストに登録した時、申請経路を設定します
その申請経路に設定された承認ルートを取得する処理です
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h16_21-300x169.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h16_21.png)

この処理を **SharePoint コネクタの「項目の取得」** で行います
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_00h51_28-300x178.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_00h51_28.png)
ID にセットする値は、承認経路 Id を使います (承認経路は参照列になっているので ID が取得できます)

### 承認ルートの階層分繰り返す

承認経路にあるグループを、順次承認処理を通していきます
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h33_19-300x226.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h33_19.png)

これを**コントロールコネクタの「Do until」**を使って、次のように表します
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h46_58-213x300.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h46_58.png)

ループの条件は「承認ルートカウンターが 20 以上、または、終了フラグが true になったら抜ける」としています
それを条件式で表すと次のようになります

```json
@or(greater(variables('承認ルートカウンター'), 20), equals(variables('終了フラグ'), true))
```

ループ回数はデフォルトのままで 60 、タイムアウトは 7 日間としています
続きまして、「承認ルートの階層分繰り返す」の中に、繰り返し処理を設定していきます

### 動的列名を設定

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h49_22-300x165.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_01h49_22.png)
現在の承認経路が参照する列名やプロパティ名を動的に組み立てています

組み立てには、式 `concat` を使って文字列を結合しています
なぜ全てを変数として作らないのか？というのは、先に説明した[ワークフローのアクション数の制限](https://1bed.allright.life/?p=3276)の通りです

各プロパティの説明は次の通りです

* PathTitle は承認経路マスタの経路の内部列名  
  `concat('Path', variables('承認ルートカウンター'))`
* PathApprovalsTitle は承認経路マスタの経路必要承認数の内部列名  
  `concat('Path', variables('承認ルートカウンター'),'Approvals')`
* PathAcceptTitle は申請ワークフローの経路承認数の内部列名  
  `concat('Path', variables('承認ルートカウンター'),'Accept')`
* PathRejectTitle は申請ワークフローの経路否認数の内部列名  
  `concat('Path', variables('承認ルートカウンター'),'Reject')`
* PathCommentTitle は申請ワークフローの経路コメントの内部列名  
  `concat('Path', variables('承認ルートカウンター'),'Comment')`
* Route はステータス用オブジェクトのプロパティ名  
  `concat('Route', variables('承認ルートカウンター'))`

各リストに設定された内部列名は [Power Automate で稟議書を実装してみた1 (GUI で環境準備編)](https://qiita.com/miyamiya/items/2f8290fa4541cc3eb953) で記載した通りになっています

内部的には次のようになっています

```json
{
  "PathTitle": "@{concat('Path', variables('承認ルートカウンター'))}",
  "PathApprovalsTitle": "@{concat('Path', variables('承認ルートカウンター'),'Approvals')}",
  "PathAcceptTitle": "@{concat('Path', variables('承認ルートカウンター'),'Accept')}",
  "PathRejectTitle": "@{concat('Path', variables('承認ルートカウンター'),'Reject')}",
  "PathCommentTitle": "@{concat('Path', variables('承認ルートカウンター'),'Comment')}",
  "Route": "@{concat('Route', variables('承認ルートカウンター'))}"
}
```

### ログの出力とステータスの更新

ログの出力とステータスの更新 (申請ワークフローに登録されたアイテムの更新時) は次の手順で行います
1. アイテムの最新状態を取得
2. 最新状態を加味した値を変数に設定
3. アイテムの更新

まずは、申請ワークフローで、今回登録されたアイテムの最新状態を取得します
**SharePoint コネクタの「項目の取得」**を使います

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h18_39-300x121.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h18_39.png)

続いて、ログ変数に出力するログを設定します

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h27_16-300x97.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h27_16.png)

日時を利用する時には、日本時間にしたいので、次のように式 convertFromUtc を使って、日本時間に変換しています

```json
convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')
```

値の中はこのようになっており、今回のログに過去のログを付けるようにしています

```json
[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] 承認ルート @{variables('承認ルートカウンター')} 回目の処理が開始されました
@{body('登録されたアイテムの最新状態を取得')?['Log']}
```

最後にログとステータスをアイテムに書き込みます
項目直撃で更新したいので、**SharePoint コネクタの「SharePoint に HTTP 要求を送信します」**を使います

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h28_57-300x247.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_02h28_57.png)

ポイントは次の通り

* 方法を POST にします
* URI を下記のようにします(※ リストの内部名ではなく、表示名を使います)
* 
```
_api/web/lists/getByTitle('申請ワークフロー')/Items(@{variables('アイテムID')})
```

* ヘッダーを次のようにします

```json
{
  "IF-MATCH": "*",
  "X-HTTP-Method": "MERGE",
  "Accept": "application/json;odata=verbose",
  "Content-Type": "application/json;odata=verbose"
}
```
ヘッダーは、右にある T というアイコンをクリックすると JSON を直接入力できるようになるので、上記コードをコピペで OK です

* ボディで更新するリストの内部名(Apply)の最後に ListItem とつけて、メタデータにセットします

```json
{
    '__metadata': {'type': 'SP.Data.ApplyListItem'},
    'Log': '@{variables('ログ')}',
    'Status': '@{variables('ステータス用オブジェクト')[variables('動的列名用オブジェクト')['Route']]}'
}
```

ステータスは少しややこしいことになっていますが、1 周目だと、 `variables('動的列名用オブジェクト')['Route']` は **「Route1」**という文字列になり、 `variables('ステータス用オブジェクト')['Route1']` は **「第１承認経路で確認中です」**という文字列になります

### 次の承認ルートがあるか確認
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h03_12-300x40.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h03_12.png)
承認ルートを 1 -> 2 -> 3 ... と続けていき、設定がされていない時にループを抜けるようにします

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h45_16-300x84.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h45_16.png)

左辺は下記のようになっています

```
@body('作成されたアイテムに設定された承認ルートの取得')?[variables('動的列名用オブジェクト')['PathTitle']]?['Id']
```

1 週目だと `variables('動的列名用オブジェクト')['PathTitle']` は「Path1」という文字列になり、`body('作成されたアイテムに設定された承認ルートの取得')?['Path1']` で参照列の値「グループ1」となり、`グループ1?['Id']` で参照列の ID を取得しています

その ID が `null` かどうかを判定しています

## 左の赤枠の説明

### 次の承認ルートがない時

[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h21_40-300x235.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h21_40.png)

承認ルートがない時は、次の手順を設定しました
1. アイテムの最新状態を取得
2. 最新状態を加味した値を変数に設定
3. アイテムの更新
4. 終了フラグを true にすることでループを抜ける

アイテムの最新状態を取得は、前回と同じです
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h50_37-300x120.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h50_37.png)

最新状態を加味した値を変数に設定もほぼ同じです
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h51_40-300x85.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h51_40.png)

値はこの様になっています

```json
[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] 承認ルートないためループ処理を終了します
@{body('承認ルートが無い時、登録されたアイテムの最新状態を取得')?['Log']}
```

アイテムの更新もほぼ同じで、ボディの値だけが違います
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h52_55-300x254.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h52_55.png)

ボディはこの様になっています

```json
{
    '__metadata': {'type': 'SP.Data.ApplyListItem'},
    'Log': '@{variables('ログ')}',
    'Status': '@{variables('ステータス用オブジェクト')['Completed']}'
}
```
ステータスを `variables('ステータス用オブジェクト')['Completed']` としており、文字列で**「申請が承認されました」**となります


最後に終了フラグを true にして、次のループで抜けるようにしていますが、現在のところ、Power Automate ではループ処理を抜ける break がないので必要な方法です
[![](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h56_14-300x71.png)](https://1bed.allright.life/wp-content/uploads/2020/05/2020-05-05_03h56_14.png)

## 考察

ループに入りログを残す部分と、承認ルートがなくなり正常終了する部分の説明を行いました
次回は、承認処理部分の説明となります

## 関連記事

自分のためのメモに近い記事なのですが、長いのでインデックスつけます

* [Power Automate で稟議書を実装してみた1 (GUI で環境準備編)](https://qiita.com/miyamiya/items/2f8290fa4541cc3eb953)
* [Power Automate で稟議書を実装してみた2 (CUI で環境準備編)](https://qiita.com/miyamiya/items/9d28749ed9bdec8a6cee)
* [Power Automate で稟議書を実装してみた3 (Power Automate 編1)](https://qiita.com/miyamiya/items/35ca2d1cd05bc77396ce)
* Power Automate で稟議書を実装してみた4 (Power Automate 編2)
* [Power Automate で稟議書を実装してみた5 (Power Automate 編3)](https://qiita.com/miyamiya/items/3b60c57653e20a7a6ff0)
* [Power Automate で稟議書を実装してみた6 (Power Automate 編4)](https://qiita.com/miyamiya/items/5f5a81b16901ed9e61cc)