CITIZEN×DEV～経費申請を自動化せよ～

# はじめに
この記事はYouTubeにアップロードされている動画の補足記事となります。
よろしければ以下のYouTubeも合わせて閲覧していただけますと幸いです。
https://www.youtube.com/watch?v=LbxDcXMk7Ng

# 概要
経費申請の以下の一連の流れを自動化します
1. 社員が経費申請の概要＋領収書の画像を登録
1. 社員が上司に経費申請の承認依頼
1. 上司が申請を承認/却下
1. 経理担当者がExcelに申請された金額などを転記


# Power Automateフロー
1. 社員がSharepointリストに以下の情報を登録（トリガー）
    - 経費申請のタイトル
    - 承認依頼をなげる上司のメールアドレス
    - レシートの画像
1. 各種変数にデフォルトの値を設定
1. レシートの画像をAI Builderが読み込み
1. 商品名と金額を以下のExcelに転記
    - 登録日、登録者、申請名（シート名）、レシート詳細情報をもつ **申請情報一覧** シート
    - レシートに記載されている商品名、金額をもつ **明細** シート
1. 上司のTeams宛に承認依頼
1. 申請の承認/却下の情報を申請者へ通知

## 1. 社員がSharepointリストに以下の情報を登録（トリガー）
今回は「領収書」とは全てレシートを指します。
「経費申請のタイトル」は、Excelの明細シートのシート名になります。

## 2．各種変数にデフォルトの値を設定
### 変数名：タイトル
承認依頼を送る際のタイトル
種類：文字列
設定値：```concat(triggerOutputs()?['body/Title'],'の申請依頼')```
### 変数名：シート名
Excelに追加する明細シートのシート名
種類：文字列
設定値：```concat(triggerOutputs()?['body/Title'],'の明細情報')```
### その他の変数
| 変数名 | 種類 | 設定値 |
|--|--|--|
|index|整数|0|
|レシート1行分のデータ|文字列||
|レシート詳細|文字列||
|分割用変数|アレイ||
|空文字|文字列||

## 3．レシートの画像をAI Builderが読み込み
Sharepointリストから添付ファイルを取得して、レシートの画像を取得し、AI Builderに読み込ませます。
[画像や PDF ドキュメントのテキストを認識する](https://learn.microsoft.com/ja-jp/ai-builder/flow-text-recognition)アクションを使用します。

## 4．商品名と金額を以下のExcelに転記
### 4.1　明細シート作成
シート名は「各種変数にデフォルトの値を設定」で作成した「シート名」変数を指定します。
### 4.2　明細シートにテーブルを作成
追加したシートのA1セルから始まるテーブルを作成します。
※表の範囲にシート名を指定しないと、先頭のシートにテーブルが追加されてしまいます
表の範囲
``` concat(variables('シート名'),'!A1')```
テーブル名
```concat(variables('シート名'),'のテーブル')```
列名
```品目;料金```
### 4.3　AI Builderで読み取った情報を整形してExcelに追加する
### 4.3.1 変数設定
- レシート1行分のデータ：現在行のtextを**追加**します
- index：linesの今見ている行の**次の**行数です。カウントアップします。
### 4.3.2　AI Builderで読み取った情報を1行ずつ整形する
レシートを読み取った情報は`results`変数内の`lines`変数に以下のように格納されています

|text|left|top|width|height|
|--|--|--|--|--|
|おみせのなまえ|0.416997354|0.088045635|0.282407407|0.033978175|
|2022年 9月 5日(月) 16:18 No:0001|0.212301587|0.285218254|0.54728836|0.027529762|
|商品名①|0.227843915|0.341269841|0.312830688|0.025545635|
|軽軽軽|0.577050265|0.341765873|0.029431217|0.081845238|
|¥111|0.691468254|0.34077381|0.069444444|0.022073413|
|商品名②|0.226851852|0.370039683|0.280092593|0.025297619|
|¥143|0.692791005|0.36780754|0.070767196|0.023313492|
|商品名③|0.223875661|0.398065476|0.284060847|0.026041667|
|¥173|0.692791005|0.396577381|0.077380952|0.02281746|

明細シートには以下のようにデータを格納したいので、整形します

|品目|料金|
|--|--|
|商品名①|¥111|
|商品名②|¥143|
|商品名③|¥173|


#### 4.3.2.1 分岐：1行分のデータが「レシート1行分のデータ」変数に入っているか
分岐条件（AND）は以下です。
- 「index」 が `length(items('Apply_to_each_3')?['lines'])` 未満
- `formatNumber(items('Apply_to_each_2')?['boundingBox/top'],'F2')` が `formatNumber(items('Apply_to_each_3')?['lines']?[variables('index')]?['boundingBox/top'],'F2')` に **等しくないこと**　

現在行と次の行のtopの座標を比較して、
一致していない場合は、「レシート1行分のデータ」変数に1行分のデータが格納されていると判断します。

#### 4.3.2.2 分岐：金額が記載されている行であるか
以下の条件で、「店名」など、明細の金額と関係ないデータであるかどうかを判断します
`indexOf(variables('レシート1行分のデータ'),'¥')`

金額以外のデータだった場合は、申請情報一覧シートに参考情報として記載するため、「レシート詳細」変数に**追加**します。

#### 4.3.2.3 1行のデータを品目と料金に分割
「分割用配列」変数に、以下の式を用いて、「レシート1行分のデータ」変数を¥記号で区切って品目と料金に分けたデータを格納します
`split(variables('レシート1行分のデータ'),'¥')`

### 4.3.3 Excelの表に行を追加
明細データを明細シートのテーブルに追加します。
「行」の指定されている式は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895455/0615eb52-185a-b9c0-28e9-4dc208d8ed2d.png)
- 品目：`variables('分割用配列')?[0]`
- 料金：`variables('分割用配列')?[1]`

### 4.3.4 「レシート1行分のデータ」を初期化
「レシート1行分のデータ」に「空文字」を**設定**します。

### 4.4 申請一覧情報シートに行を追加
以下の内容で行を追加します。
- 登録日：`addHours(triggerOutputs()?['body/Created'],9,'yyyy/MM/dd')`
- 申請名（シート名）：「シート名」変数
- レシート詳細：「レシート詳細」変数

## 5．上司のTeams宛に承認依頼、6．申請の承認/却下の情報を申請者へ通知
承認を作成し、Teamsでアダプティブカードを投稿しています。
※アダプティブカードについては[公式サイト](https://learn.microsoft.com/ja-jp/power-automate/overview-adaptive-cards)をご確認ください
　以前私が書いた記事[「アダプティブカードについて調べた」](https://qiita.com/snow_sch/items/12e9912dd495da3022e7)も参考になれば幸いです。

承認/却下の場合で、申請者への通知メッセージを変えるため、分岐では結果が承認かどうか ```Approve``` を分岐で設定しています。
詳しくはYouTubeをご確認ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895455/09dd6fa6-322b-ea7c-e04d-d8bf9a6f0301.png)

# おわりに
今後もPower Platformに関連したYouTube動画をアップロードしていきたいと思っていますので、ぜひご期待ください。