社内の取引管理シート（ほぼ無法地帯）をGASで治安改善したよ

昔々あるところに、外部へ何かを発注をする人は必ず記入が必要な社内共有スプレッドシートがありました。発注先、発注内容や金額、発注日、納品日を順次記入して、最終的に経理担当が請求書と合っているか確認するためのリストです。
特にスクリプトなどを使わないプレーンなスプレッドシートで運用されています。

社内で業務圧縮が必要になったため、このシートの管理効率化業務が私のところに来ました。
本記事はその改善業務の過程を振り返るもので、実際のコードや技術というよりRPA業務改善のやり方についてまとめたものになります。
ちなみに実際には昔々ではなく数か月前の話で、今も改善したフローで社内で順調に運用されています。

## まずは現状のフローとその問題点の把握

![スクリーンショット 2021-03-13 124824.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/ea325605-927d-16f9-3cdd-5ac82e81ea8e.png)

簡略化していますが、実際に以前運用されていたのはこんな感じでした。
まず外部と取引したい人が黄色い項目を分かるところまで埋めて、その後管理部が青色の部分を埋めていくという流れです。`取引番号`は取引先名に紐づくID、`枝番`は取引ごとの連番、`管理チェック`は反社会的勢力かどうかなどの確認です。

全員が完璧にフローを守っていれば特に「管理」というものは発生しないような表ですが、実際には無法地帯であり、かなりマメに管理部が手入れしないと体をなさないために管理コストが多く発生していました。

実際に1週間ほど自分で管理担当をやってみて、下記の問題点が挙がりました

1. **管理チェックは1社につき初回登録の1度だけで良いのだが、現状、申請されたときに初回か既存かが分からない。**
2. **なので過去の履歴を毎回参照するが、記入者により表記ゆれや別の名称を使う人がいて難しい場合がある**
3. **最初に記入した後、納品日などの追記を忘れてしまう人が多い（個別リマインドが必要）**

1.2に関しては今まで継続して担当していた社員の記憶に依ってある程度省力化されていましたが、引継ぎの省力化も業務改善の重要なポイントです。


## GAS等を使った改善立案

挙がった問題を、出来るだけ記入者の負担にならない、理想は記入者の手順もより簡単になる方法で解決できないか考えます。
この際、**最初に聞かされていない前提がボンボン出てくる**ので、思いつき段階から管理側の担当者と意見を交換していくことが大切です。マジで。

#### 取引先が初回か既存か分からない & 記入者による表記ゆれ

これはどちらも、管理部側で「取引先一覧表」を用意することで解決します。
まずは申請者にそのリストを見てもらって、無ければ新規登録の手順に移行する、あればそのままそのリストの内容で管理シートに記入する、というフローに出来ればシートにあるのは既に管理チェック済みの取引先だけになります。

ただ問題は、「リストを見ずに記入する」「リストを見ても自分の書き方で記入する」タイプの人が3人に1人くらいはいるという現実です。
そこで最初の申請記入は、管理部が用意する「取引先番号」を入力必須にしたバリデーション付きのフォームから行うということにしました。後の項で詳細な方法や機能を説明します

#### 記入漏れのリマインド

今までは管理担当者が漏れを発見したら逐一手動でリマインドしていました。
今後は、初回の記入に必要な項目はフォームで必須項目にすることで、
納品日などの後から追記するものは「最初に記入させた『納品予定日』から3日後も記入されなかったらメールでのリマインドする」スクリプトを組むことで、極力手動リマインドの手間を省くことにしました。

## フローチャートを作り使用部門に提案

今までの手順を全く変えずに自動化だけを実装できる場合は「こういう技術を使えば諸々の手順が楽になる」という説明だけで良いと思いますが、
「フロー自体をこういう風に変えれば、RPAがより効果的になる」という提案になる方が現実は多いと思います。
その場合はやはりフローチャートは便利です。RPA推進において「現場がそのフローに納得している」という状態が無いと、どんなに良いと思うものを作ってもアッサリ使われずに終わることもありますから、出来るだけ丁寧に説得力のある資料を作ることも重要です。
あと作っていて自分でも思いついたフローに無駄が無いかを検証できますしね。

というわけで今回はこんな感じで作りました
[draw.io](https://app.diagrams.net/)を愛用しています。
![Copy of 取引管理シートフロー のコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/010f7a5f-d51d-5373-6a4c-c04c8320f3e9.jpeg)

効率化が一目瞭然！とまでは行きませんが、管理部から申請者側への矢印であらわされる「チェック→差し戻し」のフローが改善後は1つ減っているということを明確にできています。

## 実装

提案した大まかな方法とフローで社内の合意が取れたらやっと実装です。（提案の前に簡単なモックは作っていましたが）
挙げてみると当たり前の事ですが**「申請しやすさ」「メンテナンス性」「管理しやすさ」**を軸に実装する機能を考えていきます

### 申請フォーム

スプレッドシートに連携するフォームを考えると、Googleフォームがその専用アプリなので真っ先に考えられますが、「別のファイルを開かなければいけない」というのは（シートにリンクを張ったとしても）結構な心理的障害なので、今回はシート上で実装できるフォームを考えます。

シートに直接申請書を作る方法は、頑張ってセルの構成やデザインを考えれば出来ないこともないでしょうが、前の人の書きかけが残ったりセルに設定したバリデーションがいつのまにか上書きされてたりとか碌なことが無さそうなので除外します。

ダイアログとかでなんとかできないかなと調べていたら、サイドバーというシートプラグインとか使う時に出てくる枠を自分で作れることが分かりました
[Google Apps Scriptでサイドバーを作る方法のはじめの一歩の概要編](https://tonari-it.com/gas-sidebar-ovreview/)
方法はこちらの記事が丁寧に教えてくれているので助かりました。

- 横に出てくるので取引先一覧表シートを参照しながら記入しやすい
- 基本HTML5準拠のフォームを実装できるので、入力タイプや制限が付与できる

などの点からサイドバーを使うのが一番良さそうです。
実際にサイドバーを開くと、下図のように右側にニュッとフォームが登場します。

![Inkedスクリーンショット 2021-03-14 131300_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/b1aa665a-fb87-3633-dc94-f9ac8eae8d8e.jpeg)

なおフォーム起動のトリガーですが、今回はcreateMenu()を使ってスプレッドシートメニュー（赤い印の部分）にトリガーを設置しました。
この方法は特にシートの使用に慣れない人には見つけにくいという弱点があり、その点ではシート上にスイッチを設置する方が良いのですが、
このスイッチ（というか図形）が、スクロール固定バー（正式な名前が分からないけど、上図の灰色の少し太い罫線）と相性が悪く、一緒に使うと変な位置に勝手に移動したりするので止む無くメニューに設置しています。

必要項目を入力して「申請」ボタンを押すと、申請部門ごとのリストに以下のように自動的に項目が追加されます。

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/28353117-23e4-7ab1-1ac8-ddce26612f09.png)
**↓↓↓↓↓↓↓↓↓↓↓↓↓↓**
![スクリーンショット 2021-03-14 133205.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/293dc42c-862d-db52-7d15-964f94041829.png)


### シート入力内容の制限

さてフォームを設置したので、その旨をアナウンスすればもうこれで運用はOK、というわけにはいきません。
なぜならアナウンスを見てなかったり忘れてて今まで通りシートに直接書き込もうとする人が100%の確率で現れるので。

そのあたりを制限するために提供されている下記の機能を活用していきます。
- セルの保護
- セルの入力規則設定
- シート関数

#### セルの保護

この範囲はシートオーナー権限が無いと編集できないよ、というような指定ができます。
取引先一覧表のような申請者が操作する必要のないシートは全面保護を掛けておくのはもちろんのこと、フォーム入力内容から転記されるセルは直接好き勝手な内容を入れられないよう保護しておきたいですよね。
しかしここで結構ピンチな問題が発生しました

##### フォーム内容の転記はスクリプト起動者の権限で行われる！！

つまりオーナーじゃない普通の申請者がフォームから申請しても、保護を掛けた範囲にはスクリプトから転記が出来ない。
これでは直接入力を禁止しつつのスクリプトからは書き込めるようにするという計画が崩壊する、けど直接入力OKにしたらまた無法地帯になるのは目に見えている…
というわけで少しトリッキーではありますがワークアラウンドを思いつきました。

1.まず転記先のシートの一番右端に保護を掛けていないセルを作りそこにスクリプトで転記します

![スクリーンショット 2021-03-14 143556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/d3337634-f3cc-7ed0-5221-d21a85f9ce91.png)

2.実際に申請者が見る部分にはシート関数でその端っこのセルを参照するように設定し、保護を掛けます

![スクリーンショット 2021-03-14 144037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304716/f9b1aa67-e827-228c-b820-d96f7b901036.png)

3.最後に右端のセルがある列は非表示にします。

…これで社内で使う、悪意の編集者がいないという想定であれば解決ということでいいでしょう…多分

#### セルの入力規則設定

入力規則については以前書いた記事でカスタム方法を紹介しています。
これで日付用のセルに文字列を入れさせない、などの入力縛りが出来ます。
[Google Spread Sheetでカスタムバリデーション](https://qiita.com/herishiro/items/562ecf961ffa7bedb0f4)

なお上の記事でその理由を説明していますが、シートUIからではなくGASから各規則や保護を設定するにあたって、DataValidationBuilderクラスなどを使用してGASのスクリプトで直接指定するのではなく、入力規則保存シートを作成して、そこに手動で指定したセルをGASで必要な範囲にコピーアンドペーストすることで自動設置を実装しています。

## 最後に

実際に運用を始めてみるとやはり想像を超えた自分ルールで記入してくる人はいるものの、それも新たに入力規則で禁止操作に追加したりと改善していくことで、すぐに特に管理側から口うるさく言わなくとも運用されるようになりました。

ただそもそも不特定多数にこういうシートに記入させるという方法に無理があるというのは最初から感じていて、稟議申請（現在別ツールで行っていて統合できない）で同じような内容を入力しているはずなので、そこから一気貫通で、申請が下りたらシートは自動入力されるようなフローが理想的だと思います。

そのために、そちらも一部運用にこぎつけてるのですが、Slack内で稟議申請フローを行って、その結果がシートに反映されたらいいな～と思いながら色々勉強したのでその辺もそのうち記事にまとめたい。

俺たちの業務改善はこれからだ！