担当者ごとにPlannerタスクを抽出してフォローするフロー

# はじめに
Plannerのタスクは自動で担当者に通知が届く機能がありますね。
今日はそれだけでは満足できない場合、特に上司・管理者がメンバーの状況をフォローしたいときのフローです。

動作イメージはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/276173d6-10d7-7f49-3ec9-812f38398b3c.png)

メンバーそれぞれにメンションを付けて、まだ完了していない割り当てタスクをフォローします。
# フローの解説
フローの全体像です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/a36fe983-5cb9-d011-3133-612dfe5d4579.png)

<details><summary>各アクションを展開したものがこちら</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/06ad7d7c-12c7-b07b-cd0d-6d23b219381a.png)
</details>


チームのメンバーとプランのタスク一覧を取得して、タスクの完了状況や割り当てメンバーでフィルターし、各メンバーにTeamsでメンションつきフォローメッセージを送ります。

残りタスクがない場合を考慮して条件分岐を追加しています。

# このフローの肝となる部分
Plannerタスクの割り当てでフィルター処理を行うのは、普通にやろうとするとかなりの手間がかかります。

特に複数のタスクを扱うには手間のかかる作業ですが、ちょっとした工夫で簡単にできるようにするのが今回の内容です。

## 一般的な手法？
特定のユーザーに、このタスクが割り当てられているかどうかを判断するためには、普通にやろうとすると、これくらいの手間がかかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/e304988b-d5f6-f75e-2f84-47e3019cb8d9.png)

1つのタスクについて調べるのに、これだけの手間がかかるとすると、複数のタスクを扱うときには…あまり考えたくないですね。


## 2種類の割り当て
先の煩わしさを解消するために、先にPlannerタスクから取得できる情報について解説しておきます。

Plannerの割り当てを示すプロパティには何故か2種類あり、形は違うものの中身はどちらも同じ内容です。

```json:① _assignments (配列形式)
"_assignments": [
    {
        "userId": "割り当てられたユーザーのId",
        "value": {
            "@odata.type": "#microsoft.graph.plannerAssignment",
            "assignedDateTime": "割り当てられた日時",
            "orderHint": "並び順を示す文字列",
            "assignedBy": {
                "user": {
                    "id": "割り当てたユーザーのId"
                },
                "application": {
                    "displayName": null,
                    "id": "{$applicationId}"
                }
            }
        }
    }
]
```
```json:② assignments (ディクショナリ形式)
"assignments": {
    "割り当てられたユーザーのId": {
        "@odata.type": "#microsoft.graph.plannerAssignment",
        "assignedDateTime": "割り当てられた日時",
        "orderHint": "並び順を示す文字列",
        "assignedBy": {
            "user": {
                "displayName": null,
                "id": "割り当てたユーザーのId"
            },
            "application": {
                "displayName": null,
                "id": "{$applicationId}"
            }
        }
    }
}
```
どちらも割り当てられたユーザーのIdが含まれていますが、それを配列として表現しているか、ディクショナリとして表現しているかの違いがあります。

ちなみに、動的なコンテンツ"割り当て"で指定できるのは、①配列形式の`_assignments`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/2a7b64ac-038b-dbd6-5e60-29d0e4d0b5cb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/46461941-0d45-3031-eade-0c1b79ed09fe.png)

この配列形式の`_assignments`は、普段Power Automate で扱っている馴染みのあるオブジェクト構造なのですが、いま必要としている`割り当てられたユーザーのId`が、奥の方にしまい込まれているため、フィルター処理に使うために一度浅いところまで引っ張り出すという作業が必要になってしまっています。

## 解決法：keyを条件にする
そこで、浅い場所に`割り当てられたユーザーのId`がある**② `assignments` (ディクショナリ形式)** を使用します。

フローではこの部分で行っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/b53c5a32-a67a-dc89-c35b-b0e24e440d09.png)

アレイのフィルター処理の差出人には一覧取得したタスクを指定します。
このフローでは事前に完了済みのタスクを省いているので表示が異なりますが、下図と同じ扱いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/cef4d6f0-fcc0-60d6-52c2-44705b3ee01d.png)


条件の左辺には、先ほどの`assignments`を指定します。
ただし、動的なコンテンツからは直接指定できないので、数式の入力から以下のように指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/e5da54a6-8ca8-deca-0971-22e6d5128f0f.png)
```powerfx:assignments
item()?['assignments']
```

残りは、右辺にフィルター対象のユーザーID、条件は「次の値を含む」とすればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/0f6a07ba-1a4c-bc18-38f4-f5bd9a48de9b.png)

## 「次の値を含む」で絞り込めるわけ
この条件を詳細モードで確認すると、`contains`関数が使用されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/4cbe9abe-ed27-1d0e-ed83-2ede5b3d2f67.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/46cb2c73-c57e-828b-0cda-a56cd5eaab16.png)
```powerfx:詳細な条件式
@contains(item()?['assignments'],items('Apply_to_each')?['id'])
```

`contains`関数は、引数1の中に引数2が**含まれる**かどうかを調べる関数です。
では、この関数の詳しい仕様を確認してみましょう。

関数のリファレンス ガイドは、式を入力する画面からfxボタンを押すと確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/cbdb9dde-c01f-5bcd-db91-45d76dafa9dd.png)


https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#contains

大事なのはココ。
ディクショナリ形式のキーに対しても、検索が有効となっている点です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/4c72b2d6-f1b6-5aae-1e75-fc9e74820a86.png)

この仕様を有効に使うことで、Plannerタスクの割り当てフィルター処理を簡単に行うことができました。

# おわりに
今回はPower Automate で初心者がつまずきがちなポイント、配列やjsonの扱い、さらに関数の使用まで行いました。

ローコードと信じて入ってきた人には少し酷かもしれませんが、乗り越えられると本当にできることの幅が広がるので、ぜひ挑戦してほしいものです😄

今回は見た目にはこだわりませんでしたが、テーブルのスタイルを変更してキレイな表にしてみたり、日付の書式を変更してわかりやすくするとさらに使い勝手がよくなると思います。

https://wataruf.hatenablog.com/entry/2022/04/24/000000

https://blog-tips.sekenkodqx.jp/2022/05/16/power-automate-function-formatdatetime/

解説は以上です。