SharePoint と Power Automate で稟議書を実装してみたメモ 5

経緯

前回の SharePoint と Power Automate で稟議書を実装してみたメモ 4 では、承認ルートの階層分繰り返す処理に入り、承認ルートがなくなった時に抜ける処理まで説明しました

今回は少し長いですが、承認ルートがあった時に下記の処理を行うところを説明します

  1. 確認者にメールを送り
  2. 承認者に承認依頼を送り、承認されたときと否認された情報を登録し
  3. 承認数が設定を越えていたら、次の承認ルートに進み、越えていなかったら否認として処理する

グループマスタリストから、アイテムを取得

申請経路に設定されたグループの参照先を取得し、登録されている承認者と確認者を取得します

この処理を SharePoint コネクタの「項目の取得」 で行います

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

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

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

つまり、グループマスタのグループ名「グループ1」のアイテムを取得するという処理です

確認者分メールを送る

確認者として登録されたユーザーに確認メールを送ります
繰り返し処理を、コントロールコネクタの「Apply to each」で行います

Apply to each を使うことにより、設定された値(コレクション)の分処理を行いますが、便利なことに、値が空だと処理は行われません

以前の手順から出力を選択は、動的コンテンツから「グループマスタリストから、アイテムを取得」の「確認者」を選びます

続いて、右にある ・・・ をクリックして、設定をクリックします

コンカレンシー制御をオンにして、並列処理の次数を 20 としています
これにより、メール送信を待たずに確認者に登録されたユーザーへどんどんメールを送ることが可能となります

確認メールの送信

次に、Office 365 Outlook コネクタの「メールの送信(V2)」を使って、メールを送信します

  • 宛先は「確認者 Email」としています
  • 件名、本文、は適当に作成しています
    本文例

    <p>@{triggerBody()?['Author']?['DisplayName']} さんからワークフローが届いています<br>
    <br>
    @{triggerBody()?['Title']}<br>
    <br>
    <a href="@{triggerBody()?['{Link}']}">申請文はこちら</a> </p>
  • 差出人は「登録者 Email」としています

承認者分メールとチャットを送る

続いて、承認者として登録されたユーザーに承認依頼(メール)と通知するためにチャットを送りますが、こちらは、コントロールコネクタの「Apply to each」 を並列分岐として追加します

以前の手順から出力を選択は、動的コンテンツから「グループマスタリストから、アイテムを取得」の「承認者」を選びます

こちらも先程と同様に、右にある ・・・ をクリックして、設定をクリックして、コンカレンシー制御をオンにして、並列処理の次数を 20 としています

この設定を行わないと、順次処理になってしまい、A さんが承認、または、否認をしたら B さんの承認依頼が作成されて、というように一人づつの処理になってしまいます

承認を作成

次に 承認コネクタの「承認を作成」 を使って、承認を作成します

  • Assigned to は「承認者 Email」としています
  • Title, Details は適当に作成しています
    Details 例
## @{triggerBody()?['Author']?['DisplayName']} さんからワークフローが届いています
* @{triggerBody()?['Title']}
  • Item link は「申請ワークフローリストにアイテムが追加されたとき」の「アイテムへのリンク」を使います

依頼のメールは次のように届き、メールで承認や拒否を行うことができます

メッセージをフローボットとしてユーザーに投稿する

承認依頼が届いていることを、チャットでも通知すると親切と思います

Microsoft Teams コネクタの「メッセージをフローボットとしてユーザーに投稿する」 を使います

  • Recipient は「承認者 Email」としています
  • Message は適当に作成しています
    Message 例
* タイトル  
  @{body('承認を作成')?['title']}

* [承認依頼はこちら](@{body('承認を作成')?['respondLink']})
* [申請文はこちら](@{body('承認を作成')?['itemLink']})
  • 詳細オプションを表示して、IsAlert を「はい」にしています

承認を待機する

承認を作成したら、ユーザーのアクションを待つ必要があるので、承認コネクタの「承認を待機」を使います

承認 ID は、「承認を作成」の Approval ID を使います

承認アクション時、登録されたアイテムの最新状態を取得

ユーザーからのアクションがあったとき、登録されたアイテムの最新状態から更新したいので、アイテムを取得します

承認結果を判定

ユーザーのアクションが承認だったかどうかの判定を行います

「承認を待機」の結果が「承認」、または、「Approve」かどうかを判定しています

「または」を使っているのは、言語設定の問題などを考慮したつもりです

また、今回試したフローでは、はいの場合といいえの場合の違いは、承認数に値を加えるかどうかだけですので、次の項目からは並行して説明します

現在の承認数に +1 、現在の否認数に +1

先程「承認アクション時、登録されたアイテムの最新状態を取得」で取得した承認数、または否認数をカウントアップする処理です

変数コネクタの「変数の設定」を使います

「現在の承認数に +1」の時

@{add(int(body('承認アクション時、登録されたアイテムの最新状態を取得')?[variables('動的列名用オブジェクト')['PathAcceptTitle']]),1)}

「現在の否認数に +1」の時

@{add(int(body('承認アクション時、登録されたアイテムの最新状態を取得')?[variables('動的列名用オブジェクト')['PathRejectTitle']]),1)}

動的列名用オブジェクトから、列名を取得している部分ですが、1 周目だと下記の文字列になります

  • variables('動的列名用オブジェクト')['PathAcceptTitle'] には「Path1Accept」
  • variables('動的列名用オブジェクト')['PathRejectTitle'] には「Path1Reject」

最新状態のアイテム情報から、その列名の値を取得して整数(int)に変換後、式 add を使って 1 足しています

承認ログと承認コメントの生成、否認ログと否認コメントの生成

応答はコレクションになっているため、コントロールコネクタの「Apply to each」 を使って値を取得します

以前の手順から出力を選択に、「承認を待機」の応答を設定します

承認ログの生成、否認ログの生成

だれが承認(or 否認)したというログを残したいので、ログの生成を行います

変数コネクタの「変数の設定」を使います

違いは、利用する動的コンテンツと文言が微妙に違うだけです

「承認ログの生成」の時

[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] @{items('承認ログと承認コメントの生成')?['responder']?['displayName']}さんが承認しました
@{body('承認アクション時、登録されたアイテムの最新状態を取得')?['Log']}

「否認ログの生成」の時

[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] @{items('否認ログと否認コメントの生成')?['responder']?['displayName']}さんが否認しました
@{body('承認アクション時、登録されたアイテムの最新状態を取得')?['Log']}

承認コメントの生成、否認コメントの生成

承認(or 否認)時のコメントを残したいので、コメントの生成を行います
こちらも、変数コネクタの「変数の設定」を使います

「承認コメントの生成」の時

[@{convertFromUtc(body('承認を待機')?['completionDate'], 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}]  @{items('承認ログと承認コメントの生成')?['responder']?['displayName']}さんが承認しました
@{items('承認ログと承認コメントの生成')?['comments']}

@{body('承認アクション時、登録されたアイテムの最新状態を取得')?[variables('動的列名用オブジェクト')['PathCommentTitle']]}

「否認コメントの生成」の時

[@{convertFromUtc(body('承認を待機')?['completionDate'], 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] @{items('否認ログと否認コメントの生成')?['responder']?['displayName']}さんのコメント
@{items('否認ログと否認コメントの生成')?['comments']}

@{body('承認アクション時、登録されたアイテムの最新状態を取得')?[variables('動的列名用オブジェクト')['PathCommentTitle']]}

現在のコメントを取得している部分で、動的列名用オブジェクトから列名を取得している部分ですが、 1 周目だと下記の文字列になります

  • variables('動的列名用オブジェクト')['PathCommentTitle'] には「Path1Comment」

承認登録データ、否認登録データ

登録処理はまとめて行うので、登録データを生成しています

「承認登録データ生成」の時

{
  "Log": "@{variables('ログ')}",
  "CountResult": @{variables('承認数一時保持変数')},
  "CountResultTitle": "@{variables('動的列名用オブジェクト')['PathAcceptTitle']}",
  "Comment": "@{variables('コメント一時保持変数')}",
  "CommentResultTitle": "@{variables('動的列名用オブジェクト')['PathCommentTitle']}"
}

「否認登録データ生成」の時

{
  "Log": "@{variables('ログ')}",
  "CountResult": @{variables('承認数一時保持変数')},
  "CountResultTitle": "@{variables('動的列名用オブジェクト')['PathRejectTitle']}",
  "Comment": "@{variables('コメント一時保持変数')}",
  "CommentResultTitle": "@{variables('動的列名用オブジェクト')['PathCommentTitle']}"
}

オブジェクトのプロパティを説明すると次のようになります

  • Log には、生成されたログ
  • CountResult には、カウントアップ後の承認数(or 否認数)
  • CountResultTitle には、カウントアップ後の数値を更新する列名
  • Comment には、ユーザーが記入したコメント
  • CommentResultTitle には、コメントを更新する列名

承認・否認データの更新

更新は今まで同様に、SharePoint コネクタの「SharePoint に HTTP 要求を送信します」を使います

今までとの違いはボディだけですが、周回や条件(承認 or 否認)により、登録する列が違うため、更新する列名も動的に作られているのは今までと違います

ボディの例

{
    '__metadata': {'type': 'SP.Data.ApplyListItem'},
    'Log': '@{variables('登録用データ')['Log']}',
    '@{variables('登録用データ')['CountResultTitle']}': '@{variables('登録用データ')['CountResult']}',
    '@{variables('登録用データ')['CommentResultTitle']}': '@{variables('登録用データ')['Comment']}'
}

これで承認者分のメールとチャットを送る部分は終わりです

承認数が設定値以上の時、次の承認経路へ進む

最新の情報を取得

承認ルートに設定されたすべての承認者のアクションが終わった後、承認した人数が、必要承認数を越えているかの判定を行います

まずはその前に、今まで同様、最新のアイテムを取得する必要があります

承認数が設定値以上か

承認数が設定値以上か判定します

左辺は、最新のアイテムから、現在周回の承認数を取得しています

@body('最新の情報を取得')?[variables('動的列名用オブジェクト')['PathAcceptTitle']]

右辺は、承認ルートの設定から、必要承認数を取得しています

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

はいの場合

ログを生成して、ログを更新しています

ログに設定している値の例

[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] 承認されたので次の承認経路に移ります
@{body('最新の情報を取得')?['Log']}

更新時のボディの例

{
    '__metadata': {'type': 'SP.Data.ApplyListItem'},
    'Log': '@{variables('ログ')}'
}

いいえの場合

いいえの場合は、否認とみなしてステータスとログを更新後、終了フラグに true を設定しています

ログに設定している値の例

[@{convertFromUtc(utcNow(), 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')}] 承認数が足りないため否認されました
@{body('最新の情報を取得')?['Log']}

更新時のボディの例

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

承認ルートのループカウンターを 1 プラス

「承認ルートの階層分繰り返す」処理の最後に、変数の承認ルートカンターに 1 足します

変数コネクタの「変数の値を増やす」を使います

これで、承認されている時には次のループに移ることができます

次回予告

改めて見直すと直したいところが多数ありますが、気にせず次回は終了処理部分の説明を行います