LoginSignup
0
2

More than 3 years have passed since last update.

定期的にWebサービスの請求書を自動でダウンロード&LINEで通知

Last updated at Posted at 2020-12-20

定期的に発行される請求書を自動でダウンロードする

副業や、サービスで利益を上げている場合は、確定申告をする必要があります。その中で、月額で費用がかかるものがあります。

僕の場合は

  • Heroku のサーバー費用
  • 仕事用の携帯代や、ネット回線料金

などがあります。

Heroku は請求書が永久に保存される(っぽい?)ので問題がないのですが、ソフトバンク光のネット回線や、ソフトバンクの携帯の請求書は、6ヶ月でダウンロードできなくなってしまうので、スクリプトで自動収集して、Googleドライブに保存しています。

この定期ダウンロードシステムを改善したい

これを改善して

  • 自分以外でも利用できるようにしたい
  • 請求書をダウンロードしたらLINEで通知されるようにしたい
    • 通知がきたら確定申告システムに手動で入力する

このシステム名

freee と invoice (請求書)をあわせて invoiceee という名前にしています。

GitHub リポジトリは以下です。Larvel のタスクスケジューラーが使いたいのと、 PHP が一番使い慣れている言語なので、 PHP Laravel を使って開発しています。

今回やったこと

  • freee 連携でログイン/アカウント作成
  • Heroku と連携して請求書をダウンロード
  • 簡易 LINE 連携

今回できなかったこと

  • LINE 連携でログイン/アカウント作成
  • LINE 連携&通知の作り込み
  • Google Drive などのストレージと連携し、そこに請求書を保存
  • 取得した請求書をもとに freee にデータを追加
  • デザインを整える
  • 動く環境にデプロイ
  • Laravel タスクスケジューラーをつかって自動収集
  • その他作り込み

主に時間の問題でできませんでした。

できること

デザインはできてないのでおおめに見てください。

最初のページは質素で、 freee と連携してアカウント作成します。アカウントがすでにあったらログインになります。

freee と連携します。

LINE で通知を受けるには、現状「LINE ユーザー ID を入力して連携」に自分の LINE ID を入力したうえで、LINE の invoiceee のアカウントと友達になる必要があります。ここは、もっと簡単にできるよう、改善したいです。

現状、Heroku とだけ連携できるので、「Herokuと連携」をクリックして、連携すると、「連携済みアカウント」に追加されます。

スクリーンショット 2020-12-20 3.32.08.png

この状態でバッチが実行すると、まだダウンロードされていない請求書が自動でダウンロードされます。バッチは php artisan invoice:collect で実行できます。

$ php artisan invoice:collect
請求書ファイルを収集します
[2020-12-19 17:58:30] local.INFO: 以下のLinkageについて処理 {"userId":1,"linkageServiceName":"heroku","linkageServiceAccountId":"85dace0d-405b-4cdf-a25c-2bed5a336f75","lastInvoiceDownloadedAt":null}
[2020-12-19 17:58:37] local.INFO: 請求書を処理します {"createdAt":"2020-04-01 00:00:00"}
[2020-12-19 17:58:37] local.INFO: 請求書をダウンロードします
[2020-12-19 17:58:39] local.INFO: 請求書を保存します {"name":"2020-04-01-heroku-0e93c5f2-fbd5-41ca-b1f6-6326f5cfd3f3.html"}
[2020-12-19 17:58:39] local.INFO: 請求書を保存しました
[2020-12-19 17:58:39] local.INFO: 請求書を処理します {"createdAt":"2019-03-01 00:00:00"}
[2020-12-19 17:58:39] local.INFO: 請求書をダウンロードします
[2020-12-19 17:58:42] local.INFO: 請求書を保存します {"name":"2019-03-01-heroku-17101b37-c27f-4616-9e92-9b27ca490d9f.html"}
[2020-12-19 17:58:42] local.INFO: 請求書を保存しました

今回できなかったことについて

LINE 連携でログイン/アカウント作成

freee を使っていない人のために、LINEでもアカウントを作成できるようにしたいです。

LINE 連携と通知の作り込み

今は自分の LINE ID を入力したうえで、invoiceee アカウントと友達になる必要があります。これを LINE 連携でいい感じにしたいです。

LINE 連携で LINE ID を取るようにします。

LINE 連携時に、 invoiceee アカウントと友達になることをオススメできるので、この機能をつかって invoiceee アカウントと友達になってもらいます。

Google Drive などのストレージ連携

今のところダウンロードした請求書をローカルに保存していたり、僕の Google Drive 決め打ちで保存していたりするので、 Google Drive 連携して、ユーザーの Google Drive に保存するようにします。

取得した請求書をもとに freee にデータを追加

せっかく自動で取得できるので、freee に自動で経費を追加したいのですが、請求書の形式によっては、金額が取れなかったりするので難しいです。現状は LINE で通知をうけて手動で freee(や他の会計ソフト)に入れる必要があります。

デザインを整える

別に綺麗なデザインにしなくても、全然使えるので、後回しですが、綺麗にしたいです。

動く環境にデプロイ

本当は、NTTPCが提供している、格安で話題のサーバー「indigo」にデプロイする予定でしたが、まさかの NTT 側のリソース不足により、インスタンスが建てられませんでした。

【2020.11.20更新】Indigo Linuxインスタンスの在庫不足
https://web.arena.ne.jp/news/2020/1027.html

12月中旬に設備追加が完了する予定になっているのですが、間に合いませんでした。他の VPS を使うという手もありましたが、 indigo を使ってみたい、というのが目的の一つでしたし、まだ完成度がそこまで高くないので、もう少し待ちます。

image.png

Laravel タスクスケジューラーをつかって自動収集

Laravel にはタスクスケジューラー機能があるので、indigo のインスタンスができたら、こちらを利用して動かしてみたいです。

タスクスケジュール 5.7 Laravel
https://readouble.com/laravel/5.7/ja/scheduling.html

その他作り込み

まだ Heroku しか連携できないなど、機能として不足しているので、ガンガン機能を追加していきたいです。

また、ユニットテストなどもまだ不足しているので改善したいです。

技術的な話

GitHub Actions で コーディング規約チェック

PHPCS でのコーディング規約チェックを GitHub Actions でします。PHPCS についてはブログに記事を書いています。

PSR-2 に変わって新しく制定された PSR-12 のチェックを PHP_CodeSniffer で行う
https://www.utakata.work/entry/php/phpcs-psr12-intellij-jenkins

↑の記事だと PHPCS ですが、 GitHub Actions でやってみると、結構いい感じに表示されることがわかりました。詳細別記事で書こうと思います。

image.png

image.png

コードの抽象化をして処理をわかりやすく

例えばこのコード、Heroku のアカウント連携をするためのコードなのですが

  • invoiceee でログイン状態じゃなかったら index ページに飛ばす
    • ログインしていない時は index ページにログインボタンが表示されるからです
  • ログインしていたら、OAuth2 の code をリクエストパラメータ取得し、 Heroku の api token を取得する。成功したら連携完了。 index ページに飛ばす
    • ログインしている時は index ページに連携状態一覧が表示されるからです

class Controller
{
    public function auth(Request $request)
    {
        // userResolver セッションからユーザー情報を解決するモジュール
        $user = $this->userResolver->getUser($request);
        if ($user === null) {
            return redirect()->route('index');
        }

        // OAuth2 の code から Heroku の api token を取得
        $code = $request->input('code');
        $token = $this->heroku->getToken($code);
        $this->userAccountLinker->createHerokuLinkage($user, $token);
        return redirect()->route('index');
    }
}

このコードだと、どちらの分岐でも index ページに飛んでいるので、非常に見づらいです。そこで、以下のように抽象化しています。

class Controller
{
    public function auth(Request $request)
    {
        // userResolver セッションからユーザー情報を解決するモジュール
        $user = $this->userResolver->getUser($request);
        if ($user === null) {
            return $this->loginPage();
        }

        // OAuth2 の code から Heroku の api token を取得
        $code = $request->input('code');
        $token = $this->heroku->getToken($code);
        $this->userAccountLinker->createHerokuLinkage($user, $token);
        return $this->successPage();
    }

    private function loginPage()
    {
        return redirect()->route('index');
    }

    private function successPage()
    {
        return redirect()->route('index');
    }
}

loginPage()successPage() も中身は同じですが、意図が違うコードからわかり、読みやすくなります。もしログインページを別にした場合も対応しやすいです。

$user === null は、ログインしていない状態を判定しているんですが、これを例えば $this->isLogin($user) にしたり、 userResolver で null を返すのをやめて、 $user->isLogin() みたいにしても、コードの意図がわかりやすくなって良いかと思います。

Eloquent::chunk で DB からちょっとづつデータをフェッチ

全部のアカウント連携のデータを all() 等のメソッド一気にDBから引っ張ってくると、メモリが足りません。Laravel で使われているクエリビルダー Eloquet には cursor() や chunk() といったメソッドがあるので、これを使います。

Laravel(Eloquent): chunk() vs cursor() - Qiita
https://qiita.com/ryo511/items/ebcd1c1b2ad5addc5c9d

まとめ

freee は API が公開されているので、こういう自動化が簡単にできるのが良いですね。

freeeは「オープンプラットフォーム」を合言葉に、各種サービスのAPIを公開しています。

今回作ったシステムは、個人的にも非常に便利なシステムになっているので、仕事と副業の間に頑張って開発し、完成させたいと思います。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2