子フロー：営業日判定

# きっかけ
私のPowerAutomateの主な用途はタスク管理系で、Teams通知を多用してます。祝日の通知はイケテナイ、やりたくないということでこのフローを作りました。
今まで書いた記事は全部前置きで、ご本尊がこの子フローです。Qiita記事を書こうと思ったのもこの仕組みをシェアしたかったからだったりします。

この子フローは以下のシーンで活用できます。
* 平日のみ通知
* 第〇営業日〆手続きの周知
* 翌営業日が〇曜日の事前周知
　例）火曜定例会：通常は月曜に周知、月曜休みなら金曜周知、火曜休みなら周知スキップ

＜親フロー処理例＞
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/38dd813e-d3de-dd84-6a53-6f7d155e9e59.png">


＜実行結果＞
平日かつ翌営業日が火曜日の10:00にTeamsメッセージを投稿（それ以外の日は何もしない）

---
# 子フロー全体像
各パートの詳細内容は後述します。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/47ec114a-5575-ebf5-f947-b11745071438.png">

---
# ①トリガ設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/b7b240ef-dc0b-4cb2-2a8c-6e37817085a6.png">

親フローからは1つの引数を渡します。

[任意：数値] 入力日付
年月日情報を「yyyy-MM-dd」形式で指定します。指定がない場合は当日日付で処理されるようオプション設定にします。

---
# ②変数初期化
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/e1c85989-9370-1d00-4561-b3ba02f86a06.png">

『変数を初期化する』で5つの変数を設定します。初期値設定するのは2つです。

* 対象日付
本日日付を初期値として設定します。
`@{convertTimeZone(utcNow(),'UTC','Tokyo Standard Time','yyyy-MM-dd')}`

* 営業日位置
「-1」を初期値として設定します。

---
# ③入力日付＝空値？
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/15e25527-5576-e996-63ae-5af9fd05422d.png">

『条件』で入力日付の空値判定をします。

* 左辺： (式)triggerBody()?['date']
* 条件：次の値に等しい
* 右辺： (式)null

条件分岐以下の構成は以下の通りです。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/02202bb8-c987-d1de-5e25-c66ad74cb8af.png">

---
### ③-2) 対象日付変数の設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/b8cdff5a-698e-ccf8-7a21-1cd3130813c6.png">

『変数の設定』で入力日付を対象日付に設定します。
* 値：`@{triggerBody()['date']}`

:::note warn
入力チェックはしてないので必要に応じて加えてください。
:::

---
# ④子フロー：営業日配列取得の実行
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/1657a9d3-b188-cbf6-32f5-97ede4fbdd21.png">

『子フローの実行』で[子フロー：月間営業日配列取得](https://qiita.com/shutaro_y/items/2a569409801d51f2e88f) を呼び出します。
* 子フロー：`サブ：営業日配列取得`
* 対象年月：`@{int(formatDateTime(variables('対象日付'),'yyyyMM','ja-jp'))}`

:::note warn
子フローの名前は環境に合わせて適宜直してください
:::

---
# ⑤スコープ：営業日位置設定
構成は以下の通りです。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/40f81282-8cfe-5ba8-02a5-453ddf0189e5.png">

---
### ⑤-1) 営業日配列を設定する
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/c2c06db0-d6b8-389a-cc65-4ad345643b4e.png">

『変数の設定』で④子フロー：営業日配列取得の実行で取得した値を設定します。
* 名前：営業日配列
* 値：`@{json(body('子フロー：営業日配列取得の実行')?['営業日配列'])}`

---
### ⑤-2) 営業日？
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/c472b214-cd13-0dd4-9d20-2b1690519b0f.png">

『条件』で対象日付が営業日配列に含まれるか判定します。
* 条件
  * 左辺：(式)`@variables('営業日配列')`
  * 条件：次の値を含む
  * 右辺：(式)`@variables('対象日付')`

---
### ⑤-3) 対象日以前の営業日抽出
『アレイのフィルター処理』で対象日付と営業日配列値の日付差がゼロ以下の値を抽出します。
dateDifferenceの返り値が「`XX.hh:mm:ss`」形式、差の絶対値が1日未満だと「XX.」がないことを踏まえ、文字列置換して日数差をとれるようにします。
* 差出人：`@variables('営業日配列')`
* 左辺：`int(replace(dateDifference(variables('対象日付'), item()), ':00:00', ''))`
* 条件：次の値以下
* 右辺：0

---
### ⑤-4) 営業日位置設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/80cdcd3b-76c3-99fb-1d91-1d7da8e2a17e.png">

『変数の設定』で営業日配列における対象日の位置（第〇営業日）を設定します。
* 名前：営業日配列
* 値：`length(body('対象日以前の営業日抽出'))`

---
# ⑥スコープ：前営業日設定
構成は以下の通りです。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/b56984a1-d437-15a1-f47e-d3b259f493c6.png">

---
### ⑥-1) 対象日付未満の営業日抽出
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/896745a1-c7b6-d1ea-b0fa-15b3057f750b.png">

『アレイのフィルター処理』で対象日付と営業日配列値の日付差が負の値を抽出します。
dateDifferenceの返り値が「`XX.hh:mm:ss`」形式、差の絶対値が1日未満だと「XX.」がないことを踏まえ、文字列置換して日数差をとれるようにします。
* 差出人：`@variables('営業日配列')`
* 左辺：`int(replace(dateDifference(variables('対象日付'), item()), ':00:00', ''))`
* 条件：次の値未満
* 右辺：0

---
### ⑥-2) 対象日付未満の営業日あり？
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/88372f40-c35e-f1d1-93ee-38a387c559d3.png">

『条件』で対象日付が営業日配列に含まれるか判定します。
* 条件
  * 左辺：(式)`length(body('対象日付未満の営業日抽出'))`
  * 条件：次の値より大きい
  * 右辺：0

---
### ⑥-3) 前営業日設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/7446b0f3-911f-b932-0669-27656bc10fe5.png">

『変数の設定』で前営業日を当月過去営業日配列の最後の値で設定します。
* 名前：前営業日
* 値：`@{last(body('対象日付未満の営業日抽出'))}`

---
### ⑥-4) 前月年月作成
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/a1ed690d-9af4-b1f2-b3f6-6ea5d1bda131.png">

『作成』で年マタギを考慮した前月年月数値を作成します。
* 値：`@{sub(int(formatDateTime(variables('対象日付'),'yyyyMM','ja-jp')),if(equals(int(formatDateTime(variables('対象日付'),'MM','ja-jp')),1),89,1))}`

---
### ⑥-5) 子フロー：前営業日配列取得
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/a9bd800e-f04a-2830-7ad5-900d77098aa8.png">

『子フローの実行』で[子フロー：月間営業日配列取得](https://qiita.com/shutaro_y/items/2a569409801d51f2e88f) を呼び出します。
* 子フロー：`サブ：営業日配列取得`
* 対象年月：`@{outputs('前月年月作成')}`

:::note warn
子フローの名前は環境に合わせて適宜直してください
:::

---
### ⑥-6) 前営業日設定(前月)
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/df0b5023-1332-5d97-27b3-cca2fde02635.png">

『変数の設定』で前営業日を前月営業日配列の最後の値で設定します。
* 名前：前営業日
* 値：`@{last(json(outputs('子フロー：前営業日配列取得')?['Body']?['営業日配列']))}`

---
# ⑦スコープ：翌営業日設定
構成は以下の通りです。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/a3be91be-b65a-5319-3d9a-af70bc07e592.png">

---
### ⑦-1) 対象日付より大きいの営業日抽出
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/3cbc7470-d882-0baa-0665-aaba00a2148f.png">

『アレイのフィルター処理』で対象日付と営業日配列値の日付差が正の値を抽出します。
dateDifferenceの返り値が「`XX.hh:mm:ss`」形式、差の絶対値が1日未満だと「XX.」がないことを踏まえ、文字列置換して日数差をとれるようにします。
* 差出人：`@variables('営業日配列')`
* 左辺：`int(replace(dateDifference(variables('対象日付'), item()), ':00:00', ''))`
* 条件：次の値より大きい
* 右辺：0

---
### ⑦-2) 対象日付より大きい営業日あり？
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/534854b7-361b-87c9-e621-afd72af983d3.png">

『条件』で対象日付が営業日配列に含まれるか判定します。
* 条件
  * 左辺：(式)`length(body('対象日付より大きいの営業日抽出'))`
  * 条件：次の値より大きい
  * 右辺：0

---
### ⑦-3) 翌営業日設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/1ceba02c-bcf1-6138-cf50-c3c95936f5c8.png">

『変数の設定』で翌営業日を当月未来営業日配列の最初の値で設定します。
* 名前：翌営業日
* 値：`@{first(body('対象日付より大きいの営業日抽出'))}`

---
### ⑦-4) 翌月年月作成
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/801e4380-7fb7-82b9-93d9-4a540230dcab.png">

『作成』で年マタギを考慮した翌月年月数値を作成します。
* 値：`@{add(int(formatDateTime(variables('対象日付'),'yyyyMM','ja-jp')),if(equals(int(formatDateTime(variables('対象日付'),'MM','ja-jp')),12),89,1))}`

---
### ⑦-5) 子フロー：翌営業日配列取得
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/fa1918da-884c-c46c-8a7c-a66b3242b610.png">

『子フローの実行』で[子フロー：月間営業日配列取得](https://qiita.com/shutaro_y/items/2a569409801d51f2e88f) を呼び出します。
* 子フロー：`サブ：営業日配列取得`
* 対象年月：`@{outputs('翌月年月作成')}`

:::note warn
子フローの名前は環境に合わせて適宜直してください
:::

---
### ⑦-6) 翌営業日設定(翌月)
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/b136051b-abdd-0903-66de-4ef97454f719.png">

『変数の設定』で翌営業日を翌月営業日配列の最初の値で設定します。
* 名前：翌営業日
* 値：`@{first(json(outputs('子フロー：翌営業日配列取得')?['Body']?['営業日配列']))}`

---
# ⑧PowerApp または Flow に応答する
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681410/d1f29a2f-c8d8-e03a-6141-2157ecafad43.png">

『PowerApp または Flow に応答する』で作成した値を返り値として設定します。

* 対象日付：`@variables('対象日付')`
* 営業日位置：`@int(variables('営業日位置'))`
* 前営業日：`@variables('前営業日')`
* 翌営業日：`@variables('翌営業日')`
* 営業日配列：`@concat('["',join(sort(variables('営業日配列')),'","'),'"]')`

:::note warn
* 営業日位置は整数型変数で定義してますが、intにキャストしないと親フロー側では文字列として扱われてしまうため、数値の大小比較ができなくなってしまいます。
* 営業日配列は応答値に配列型設定できないため、配列形式の文字列で設定します。親フロー側で扱う場合はjson関数で変換する必要があります。
:::