承認者マスターを使ったSharePoint承認ワークフロー


#概要
- 今更ですがSharePointリストとPowerAutomateを使った承認ワークフローの作成方法のまとめ。
- 承認依頼先はフローに埋め込みではなく、承認者マスターから選択できるようにしました。
- アイテムの新規投稿時/変更時をトリガーとして、承認フローを実行します。
- Teamsの承認アプリも活用しつつ動作を確認。

#その前に承認機能の仕様まとめ
##SharePointの承認
- リストのバージョン設定→「送信されたアイテムに対してコンテンツの承認を必須にする」を有効にすると利用可能。
- すると、「承認の状況」「承認者のコメント」列が有効になる。　※ビューの設定で表示が必要。<br>
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/8a64274f-b46f-9b05-3bd9-71a55df2729f.png)
- リストへ新規投稿するか、アイテムを編集すると自動的に承認待ちとなる。コメントは自動でクリアされる。
- SharePointのアクセス権で「アイテムの承認」権限がある人は、アイテムを選択→…→承認で承認設定可能。
- 既定では、サイトの所有者は承認権限があり承認可能。メンバー以下は承認権限がない。→[アクセス権の設定はこちら](https://qiita.com/Rambosan/items/e5b9fe32ffbd727f5e38)
- 既定では、承認待ち/否認アイテムは投稿者か承認権限保有者のみ表示可能で、それ以外のメンバーには最新の承認済みアイテムが表示される。(設定で変更可)<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/81aa4180-42e7-8fe1-ab4a-0155f1bb27ec.png)
- そして、承認待ち/否認のアイテムを他のユーザーが編集しようとすると、SharePointの標準機能によりブロックされる。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/d2f4da06-485a-074f-3646-932296b6d1f3.png)

##PowerAutomateの承認
- 「承認を開始して待機」アクションで承認依頼と応答取得を自動化できる。
- 既定では、承認の依頼者はフローの接続情報のユーザーとなる。
    - 「選択したアイテム場合」トリガーのようなインスタントフローなら実行者が依頼者となる。
- 今回のクラウドフローのように所有者の接続情報が利用される場合、フローの所有者が依頼者となる。
    - その場合、詳細オプションで要求元メールアドレスを設定すると依頼者を変更可能。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/f4e89cf5-23d1-7d17-c3c7-f334ff26e5ab.png)
- 応答が承認されたかどうかは、結果(Outcome)がApproveかどうかで判定する。
- SharePointへの承認状態反映は、「承認状態の設定」アクションで明示的に設定する必要あり。<br>
　※フローの接続ユーザーに承認権限があることが必要。
- ただしアイテムのSharePointの更新者列がフローの接続ユーザーとなり誰が投稿したか分からなくなる。あとで投稿者が分かるよう投稿者列を用意してセットするとよい。
- 承認状態を設定した後に「項目の更新」アクションで値を更新すると承認待ち状態に戻ってしまう。値を更新したい場合は承認状態の設定より前に更新アクションを行う。

##Teamsの承認
- Teamsの承認アプリが登場→https://docs.microsoft.com/ja-jp/microsoftteams/approval-admin
- Teamsのサイドバー・・・→承認でアプリ追加可。右クリック→固定で常に表示されるようにする。
- 承認依頼がきたらTeamsに通知され、Teams画面上から承認可能。再割り当ても可能になりました。
    - ただしメールも同時にくるので鬱陶しい。<br>
   　→PowerAutomateの設定で通知OFFにするとメールもTeams通知もきません。
- 承認依頼本文はMarkdown書式に対応。
- 承認依頼者の承認アプリでは「送信済み」に登録され、申請のキャンセルやフォローアップが可能。
- 承認されると要求元にもTeams通知される。
    - 要求元を正しく設定しないとフローの所有者に来るので鬱陶しいことになりますｗ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/df153644-091b-363c-cf16-dc78ab502c3c.png)


#承認ワークフローの作成方法
##構成
フローの仕様上、①SharePoint、②PowerAutomateに加え、③PowerAppsが必要です。

##SharePoint側の設定

###承認者グループマスターの設定
まずは承認者グループのマスターを作成します。
SharePointリストを新規作成し、以下の列を準備する。

|     列名     |        データ型        |                          備考                          |
|:------------:|:----------------------:|:------------------------------------------------------:|
| 承認グループ | 1行テキスト            | Title列の名前を変更                                    |
| 承認者リスト | ユーザーまたはグループ | ・ユーザーとグループ      ・入力必須      ・複数選択可 |

###メインテーブルの設定
・SharePointリストを新規作成する。
・リストの設定→バージョン設定で承認機能を有効にする。
・詳細設定→[クイック編集] と [詳細] ウィンドウ～の設定をいいえに設定。
　※プレビュー画面での意図しない変更を抑制します。
・任意の列に加えて以下の列を準備

|      列名      |   データ型  |                                 備考                                 |
|:--------------:|:-----------:|:--------------------------------------------------------------------:|
| Flowからの変更 | はい/いいえ | Flowから更新する場合Trueにし、無限ループを防止。   既定値はいいえ |
| 承認ルート     | 参照列      | 承認グループマスターのグループ名列を参照                 |
| 投稿者         | 1行テキスト | フローから投稿者名を記録。                                          |



##PowerAutomateの設定
- フロー全体は以下の通り
- メインテーブル(SharePointリスト)への新規投稿又は変更をトリガーとします。
- 変更をトリガーとする場合、フロー内からの変更でもフローが走ってしまうため、無限ループ対策が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/f0c84afe-ac9b-728f-a6b2-b3811f0d0307.png)

###ポイントを絞って説明
①条件：Flowからの変更を無視
・「Flowからの変更」がtrueか、「コンテンツの承認の状態」がPending以外なら終了します。
・これをやらないと、後のアクションである承認状態の設定や項目の更新によりフローが実行され、無限ループが発生してしまいます。
・いいえの場合の処理は書かず、次のステップから書いていくとフローの可読性が高まります。
　※if(result.HasError){return;}みたいにネストを減らす書き方と同じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/04793e10-98d5-943e-6a9d-c88599751d10.png)

②承認者リストの取得
・承認ルートIDをキーに承認者マスターからアイテムを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/09635a0d-d8ea-2ac2-0f9e-63320941ad44.png)

③承認者のメールリスト
・ここでは承認者のメールアドレスを;区切りで生成します。
・まず「変数の初期化」アクションで、文字列型の「承認者のメールリスト」変数を作成。
・次に「文字列変数に追加」アクションで、動的なコンテンツ「承認者リストEmail」 + ;を設定。
・すると勝手にApply to eachがつき(こいつに最初は発狂した)人数分ループして文字列を結合します。
→JSONを見ると分かるのですが、[]で配列になっている属性は普通には取り出せないためfirstなどのコレクションの操作関数を使用するか、Apply to Eachを使用して取り出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/c48795da-c57b-6f52-3c4c-f77ee7e83f37.png)

④承認
・今回は承認者の誰か一人が応答すれば良いパターンに設定します。
・担当者には③の変数を入れる。
・タイトル(メール件名)や詳細(メール本文)は、何の申請か分かりやすいよう適切に設定。詳細はMarkdown使用可。
・詳細オプションを開いて要求元に「更新者のEmail」を設定します。　すると承認要求の要求元の名前が投稿者に設定され、Teamsの承認アプリの送信履歴にも追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/e6e80e2d-35fc-8786-3f4c-fd7bc27f3e3d.png)
・タイムアウトや失敗した場合の処理を行いたい場合、フローの次の「＋」→「並列分岐の追加」で任意のアクションを追加し、実行条件の構成で失敗した場合にこちらのフローが走るようにします。承認のタイムアウト時間は承認アクションの設定からカスタムできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/6d453c8e-01b1-b28b-f056-04961c12ccb5.png)

⑤承認前後のバージョン確認とキャンセル判定

- 承認待ち中に内容変更し「二重に承認依頼」がいってしまったときと、自ら「承認依頼をキャンセル」した場合のフローキャンセル処理です。
- 「二重に承認依頼」は、後からきた依頼に承認し、次に先にきていた(古い方)承認を行うとフロー内容によっては古いデータで上書きされてしまいます。こちらは画像のように「承認の前後でバージョン一致確認」をして、違っていればその後のアクションをキャンセルします。
- 条件の左側には「アイテムが作成または変更されたとき」のバージョン番号を、右側には「項目の取得：承認前後のバージョン確認」のバージョン番号を設定。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/ff20954a-5b25-ba8c-4535-91e8ea741d56.png)
・もう一つ、「承認依頼をキャンセル」はTeamsの承認アプリで操作できる「承認リクエストのキャンセル」を行った場合の対応です。　キャンセルされると承認の「応答」が空となりフローが進みます。
- 画像のように条件を追加し```empty(outputs('開始して承認を待機')?['body/outcome'])　次に等しい true```としてキャンセルされたかどうか判定します。
- 「はい」の場合のキャンセルされた通知は任意のアクションを設定します。


⑥応答一覧
・ここでは承認記録をつけるため、承認者の名前-コメント-承認日を結合した文字列を生成します。
※応答の概要でもいいのですが応答コメントが記録できないので。
・まず変数の初期化で、文字列「応答一覧」を設定。
・後は画像のように設定。「文字列変数に追加」アクションで「応答 コメント」などをクリックすると勝手にApply to Eachが付きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/42807a7c-aeb7-e75f-17e8-bddb69762512.png)

⑦項目の更新：投稿者の設定
・この後の「承認状態の設定」を行うと、アイテムの更新者がFlowの所有者で上書きされ投稿者が分からなくなるため、追加した「投稿者」列に更新者を記録しておきます。
・Flowからの変更：はいに設定(無限ループ防止)
・投稿者：更新者 DisplayName
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/6e316b05-d1a0-15ab-dc7f-e820ce550c6d.png)


⑧承認状態の設定
・画像のように条件分岐により承認状態の設定を行います。
・結果(Outcome)がApproveなら「承認」が選択されています。
・その後、任意でメールやTeamsなどで承認されたことを通知するアクションを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/e555f9e3-7d85-bf1f-89df-487b72fff1b9.png)

##PowerAppsの設定
フローの仕様上、「Flowによる変更」がいいえ(false)の場合にしかフローが動かないので、入力フォームでfalseが設定されるようにします。
Power Appsの編集フォームでは「Flowによる変更」列は以下のようなコントロールになるので、
切り替えコントロールのDefaultをfalse、DisplayModeをDisabledに設定します。
すると、SubmitFormで登録する際には「Flowによる変更」が「false」になり承認フローが動きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/6717178e-667e-020a-66e6-84c1ad8d3b11.png)
フォームのカスタマイズでも、キャンバスアプリでも同じです。

##その他、下書き状態で保存したい場合
- 上記の方法は、承認フローの実行を任意でコントロールできません。 無償プランではPowerAutomateが5分間隔で変更をチェックして自動でフローを実行します。　※もちろんフロー実行までに何度編集してもフローの実行は最新アイテムの一回のみ。
- 一旦下書きで保存しフローの実行を保留したい場合は、PowerApps側で下書きボタン、申請ボタンを設置し、下書きの場合は「Flowによる変更」をTrueにし、申請ステータス列を追加し、「下書き」、「申請中」など値を設定すると良いです。


##PowerAppsトリガーを使ったフローにする場合
もう一つの方法です。PowerAppsボタンで承認フローを走らせれば無限ループへの考慮などは不要です。
ただしPowerApps V2トリガーを使ってトリガーする必要があります。

トリガー部分は以下のようにパラメータでItemIDを受け取って、SharePointリストからIDでレコードを取得し処理を進めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/10b30e9c-26c5-657a-b2f1-4b0ba6e97d8b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9a253377-cd53-3917-80de-411d215f678c.png)

重要な設定として、フロー設定の「接続のみのユーザー」→「編集」から設定できる接続情報を編集する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/abb8d825-28df-8733-b7d1-acf4912f9193.png)
以下のように、SharePointの接続は、「この接続(所有者)を使用する」を選択します。
こうしておかないと「SharePointの承認状態の設定」アクションで失敗します。
フロー実行者には(通常)アイテムの承認権限がないためですね。
※PowerApps(V1)でやると強制的にフロー実行者の接続情報が使用されてしまいますので必ずV2を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/93113a0a-949f-8008-d724-46738f429a50.png)


#あとがき
- PowerAutomateの承認ワークフローを解説する記事は既に沢山あったのですが、アイテム変更時をトリガーとするものが少なかったので気をつける点を含めて記事にしてみました。
- アクションの名前は、元のアクション名に続けて：アクションの説明としています。この方が元アクションが分かりやすく読みやすいのでおすすめです。　「スコープ」を使って処理をまとめるのもありです。変数の初期化だけは外に出す必要がありますが。
- 今の所このフローで安定しています。 不具合等あればご指摘下さい。


#補足1
###Power Automateの承認種類を「すべてのユーザーの承認が必要」に変更する場合
承認結果の判定に少し工夫が必要です。
承認の結果(Outcome)の中身が下の画像のように「Approve,Approve」と複数人の承認結果がカンマ区切りで格納されています・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9ad3dc83-aedf-9357-f62c-1b56363f15d6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/b765e09e-9060-97b8-0fab-f702523216c2.png)

簡単な対応方法としては、条件処理を以下のようにします。
①結果にRejectを含まない (結果にRejectがなければ全員がApproveだということ)
and条件で
②empty(結果) = falseである
(申請者が承認依頼をキャンセルした場合は結果が空で、①のRejectを含まないがTrueになるため、emptyかどうかをチェックする。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/6fa7bcb0-5988-8a10-d871-6d7904d88bb6.png)