freee APIアドカレには初めて投稿します。ネット広告専門の広告代理店のシステム開発部にて、普段は主にPHPでWebサービスや社内ツールを開発しています。
起きたこと
いつものようにPHPと戯れていたある日、管理部から質問を受けました。
「RPAで大量のPDFファイルの内容を読み取りたいんですけど、管理部でネット見ながらコピペとかで実現できるものですか?PRA業者に頼むとどれぐらいが相場ですかね?」
「!?」
弊社では、たくさんの広告主様に毎月運用手数料を請求させていただくのですが、その際freeeで定期作成された下書き請求書を印刷して、 各広告主様の担当コンサルタントに配布し、内容のチェックを受けてから正式な請求書を作り、送付するというフローになっていました。
昨今のリモートワーク化を受けて、物理的に紙の請求書を大量に印刷→担当者別に仕分け→配布→チェック結果をfreeeに入力…という物理的な紙を使う
フローをやめたい、というのが管理部の要望です。そのために、案件名・担当者名・金額…のような請求書の明細行に載っているデータをGoogleスプレッドシートのデータとして見たい、とのことでした。
よくよく聞いてみると、紙請求書のチェックは印刷→仕分け→チェック結果入力をする管理部が大変なだけでなく、各担当コンサルタントにとっても
紙と画面の突き合わせを毎月かなりの時間をかけて行う負担の大きい仕事であることがわかりました。
さて、やりたいことがわかったところで、問題はやり方です。PDFの読み取り…完全に守備範囲外です。うっすらOCRでできる気がする、という程度。なにせ単なるPHPerなので(笑)
ただ、私自身、過去に開発部向けの申請ツールを作ろうとして調べたことがあり、freeeにはAPIがあることは知っていました。そこで、「APIがあるなら、むしろPDFを経由しないほうが楽なのでは?」と思ったわけです。
「たぶんRPAでなくAPIでできると思うから作らせてくれ!」と言って、freee APIドキュメントを読み込み、スキマ時間で実装しました。毎月のデータ作成をいちいち開発部に依頼せずに管理部だけで完結できるよう、Google Apps Scriptを利用しました。(本当はSlackから起動させたかったんですが、GASがSlack側の規定時間内にレスポンスを返せず断念)
新しいフローは、【管理部がスプレッドシートを作成→スプレッドシートをコンサルティング部に共有→コンサルタントは自分の名前で絞り込んでデータチェック→管理部はスプレッドシート上のチェック結果を見てfreeeに入力】となりました。PDFを読み取るRPA導入検討は消滅しました
Googleドライブの所定のフォルダに増えていくチェック用スプレッドシートを観察していたところ、印刷→仕分けという物理作業がいらない分、月に1回だけでなく何回かチェックもできるようになったようです。
作ったもの
freee APIから所定の条件(弊社内で毎月チェックの対象になる)を満たす下書き状態の請求書データを取り出して、Googleスプレッドシートに一覧を書き出すGoogle Apps Scriptです。
freeeのInvoices APIからデータを取得し、必要な形に整形したうえで、当月チェック用のGoogleスプレッドシートファイルを作成して一覧を書き込みます。ほぼCSVのような装飾のないシートですが、エクセルで言うオートフィルタ機能を使って絞り込んだり並べ替えたりして活用されています。
工夫したところ1: リフレッシュトークンの扱い
私が普段触っている各広告媒体のAPIだと、OAuth認証して取得したリフレッシュトークンは1つのリフレッシュトークンから何度でも(敢えて無効化ボタンをポチしない限り)新しいアクセストークンを作れる仕様になっていることが多いです。
この仕様の場合、リフレッシュトークンだけ保存しておけば、アクセストークンは使い捨て可能です。(セキュリティ的には良くないですが)社内向けの小さなスクリプトでは1回取得したリフレッシュトークンをスクリプト内にハードコードしておくことができます。
しかし、freee APIではリフレッシュトークンは1回リフレッシュすると死んでしまい、今回取得したアクセストークンに付属してくる新たなリフレッシュトークンを次に備えて保持しないといけません。
今回、実行環境としてGoogle Apps Scriptを選択したため、このトークンの仕様には随分悩まされました。毎月のデータ作成を管理部だけで完結したい(いちいち開発部に依頼しなくてもデータ出せるようにしたい)ので、毎月トークン取得してスクリプトを編集する仕様はNGなのです。
結局、GoogleドライブにGoogleドキュメントの形でアクセストークンjsonを保存し、Google Apps Script側で実行時にGoogleドキュメントから読み取ったものをJSON.parse()して使うことで解決しました。
工夫したところ2(freee APIの仕様のおかげで工夫しなくてもよかったところ): 明細行がほしいがN+1したくない
最初にスクリプトの構成を考えたとき、Google Apps Scriptの実行時間制限の範囲内で、大量のAPIコール(N+1のAPIコール)は避けたいな、なにか方法はないかな?とぼんやり考えていました
ドキュメントを見るとfreee APIではInvoiceをGETすると明細行のコレクションが一気についてくるので、この心配はしなくて良いことがわかりました。
おまけ
会社の規定上、開発部は会計freeeの請求書データを見る権限がなく請求データ上の金額が税抜か税込みか不明だったので、一旦管理部にそのままデータを渡したところ「全部1割引になってます!」という指摘を受けました。
freee API ドキュメントに対しプルリクエストを出しました。 https://github.com/freee/freee-api-schema/pull/122