この記事ではRuby on Railsを使い、Misocaで請求書をAPI経由で作ってメールに添付し、請求するまでの流れを説明しています。この流れで実装したコードを展開して、筆者が開発している「進行表さん(β版)」というサービスに実装しました。なお、本記事登場のソースコードの実装環境はRuby2系、Ruby on Rails(4系)です。
背景
Webアプリでの決済の場合、WebPayやSPIKEなどの決済サービスを利用する機会は一般的には多いかと思います。しかしながら企業間における決済方法は、BtoBクレジットカード決済サービスなどのFintech系電子化の波が来ているとはいえ、請求書での銀行振り込みがいまだ主流です。
法人間の決済においてカード払いが採用されている割合は0.2%(※1)で、かつ決済サービスを利用して手数料払うほど余裕じゃないスタートアップ的な規模のBtoBWebアプリにおける決済方法として、今回紹介するような方法も1つありではないかと思い、書いてみました。ユーザビリティとしてはまあ、どうなのかな〜という感じですが…e-文書法においてはデジタルデータで保存可能な書類なので、法的効力については問題ないかと思います。
実装までの流れ
今回は請求書作成サービス「Misoca(ミソカ)」 のAPIを使わせていただきます。
なぜMisocaなのか?
長くなるので、実装が知りたい方はこの章は飛ばしてください。
1つめの理由としてはクラウドを利用すると請求管理が楽という点です。PDFをwkhtmltopdfなどを使って作っても請求書を送ることはできるのですが、運用上はその管理が非常に面倒くさいです。
- 誰に発行したのか
- いつ発行したのか
- 消し込みは?…etc
といった経理系のデータはDBに保存せずWebアプリのデータと分けたいかな、と。メインのサービスを楽しくハックしていきたいのに、バックエンド業務のシステムのDevOpsをしなければならないなんて、楽しくないですよね(筆者自身は、楽しくないと感じます)。好きなことで、生きていく(笑)
続いて、いくつかある請求書管理クラウドサービスと比較したときにMisocaを選ぶ理由は、取引先がいくつ増えても月額無料であり、APIで作成できる請求書の数に制限が特にないこと。個人的に、取引先が増えると月額料金も上がってしまうサービスは、Win-Winな感じがしませんのであまり好きではないです。また、他の経理ソフトと連携可能なのもイケてます。
そして最大の理由は、Misocaは筆者が日頃の業務にて使い慣れているというのもあるからなのですが、なにより筆者は
Misoca大好きマン
だからです。MisocaはBtoBツールで、ネーミングが特に最高です。このようなビジネスモデルは、チャリンチャリンな感じがして、スタートアップ好きな筆者としては個人的に金井憧れ(※2)。
会計ソフト大手の弥生株式会社さんの出資を受けられているので、創業者の方がそのへん意識されているのかな〜、とか邪推。
会員つくろう〜(※3)
さて本題からずれましたが、まずはMisocaのトップページから普通に会員登録します。アカウントを取得したらAPIドキュメント http://doc.misoca.jp/ に記載の手順で進めます。
アプリケーションつくろう〜
まずはアプリケーションの登録を行います。登録すると以下のようになります。Twitter・Facebookアプリを作ったことがある方はご理解いただけるかと思いますが、こんな感じです。
Redirect URIはconfig/routes.rbで設定したコールバックURIを記載します。2行目はステージング兼開発サーバー(リーン・スタートアップ笑)なのでモザイクです。get 'users/misoca/callback' => 'users/misoca#index' #(※4)
アプリケーションIDとシークレットメモろ〜
登録し終わったら、アプリの画面で
- Application Id
- Secret
をメモします。これらはアプリケーション管理画面にて、以下のように記載されています。
続いてOAuth2.0でアクセストークンを取得して、請求書を作るプログラムを組みます。
どうして、OAuthするの〜
ここで!認証エンドポイントにおける、トークン取得API(/token)にリクエスト時の必須パラメータがドキュメント見ても何のことや?という感じだったので、
Misocaサポート様に聞いてみましたが、ググれとのこと(※4)だったのでググってみましたところ、kossacksさんのGoogle APIのトークン取得方法の記事やMFクラウドさんと同じだと分かったので(OAuth2.0なんだから当たり前やろ!という話ですが笑、筆者は分からず…サポート様お手数お掛けしまして誠に申し訳ございませんでした)解決しました。
コーディングしよう〜
基本情報の設定(※5)
まずはOAuth2.0でAPIを利用するのに必要な環境を整えます。
dotenvとoauth2のgemを使います。
gem 'dotenv-rails' # 有名ですね
gem 'oauth2' # 名前の通りOAuthを楽にしてくれるGem
MISOCA_APPLICATION_ID='MisocaアプリのApplication Id'
MISOCA_APP_SECRET_KEY='MisocaアプリのSecret'
MISOCA_END_POINT='https://app.misoca.jp/api/v1/'
MISOCA_AUTHORIZE_URI='https://app.misoca.jp/oauth2/authorize'
MISOCA_TOKEN_URI='https://app.misoca.jp/oauth2/token'
さて、実際Ruby on Rails(4系)で使用するコードですが、ググりまして株式会社Misocaの代表取締役、豊吉さんのサンプルコードを参考にさせていただきました。代表自らコードを書かれるとは、すばらしいですね!ありがたく部分コピペ(笑)サンガツ(弥生と掛けています)。
def new
authorize_url = get_misoca_oauth2_client.auth_code.authorize_url(redirect_uri: get_misoca_redirect_uri, scope: 'write')
redirect_to authorize_url
end
protected
def get_misoca_redirect_uri
redirect_uri = request.protocol + request.host_with_port + users_misoca_callback_path
end
def get_misoca_oauth2_client
@client = OAuth2::Client.new(
ENV['MISOCA_APPLICATION_ID'],
ENV['MISOCA_APP_SECRET_KEY'],
site: ENV['MISOCA_END_POINT'],
authorize_url: ENV['MISOCA_AUTHORIZE_URI'],
token_url: ENV['MISOCA_TOKEN_URI'],
)
end
end
やっていることとしては、newアクションにアクセスがあると https://app.misoca.jp/oauth2/authorize にリダイレクトされて認証画面が表示されるということです。scopeは権限です。請求書を作るにはwrite権限が必要なので記載。redirect_uriは本番だとhttpsがデフォだと思うのでhostからuriを組み立てています。
そして、承認を押すと請求書が発行されてメールに請求書が添付されて飛んでいくアクションが以下。先に設定したRedirect URIがルーティングされているアクションです。
def index
@client = get_misoca_oauth2_client
@access_token = @client.auth_code.get_token(
params[:code],
redirect_uri: get_misoca_redirect_uri
)
@misoca = OAuth2::AccessToken.new(@client, @access_token.token)
result = @misoca.post('/api/v1/invoice/', { body: {
'invoice[issue_date]' => Time.zone.now.strftime("%Y/%m/%d"),
'invoice[payment_due_on]' => 7.days.from_now.strftime("%Y/%m/%d"), #(※7)
'invoice[recipient_name]' => "クリストフ", # @user.nameとかですね
'invoice[recipient_title]' => "様",
'invoice[invoice_items_attributes][0][name]' => "プレミアム会員プラン",
'invoice[invoice_items_attributes][0][quantity]' => "1",
'invoice[invoice_items_attributes][0][unit_price]' => '10000'
}})
@invoice = JSON.parse(result.body)
result = @misoca.get("/api/v1/invoice/#{@invoice['id']}/pdf")
@pdf = JSON.parse(result.body)
MisocaMailer.send_invoice(current_user, @pdf).deliver_later
end
パラメーターのinvoice[issue_date]以外は必須ではないはずです。
result = @misoca.get("/api/v1/invoice/#{@invoice['id']}/pdf")
の部分で、Misoca APIからbase64エンコードされたpdfデータがもらえます。
MailerとMailerのview(メール本文)も作っておきましょう。
def send_invoice(user, pdf)
@user = user
attachments["#{pdf['id']}.pdf"] = {
mime_type: 'application/pdf',
encoding: 'base64',
content: pdf['pdf']
}
mail(to: @user.email, subject: 'お支払い頂く請求書をお送りいたします。')
end
attachmentsで添付ファイルを指定しますが、今回の場合はすでにbase64エンコードされているので、encodingにはbase64を指定します(※8)。
<%= @user.name %>様<br/><br/>
「進行表さん」運営でございます。<br/>
ご請求書をお送りいたしますので、ご多用の中大変恐れ入りますが、<br/>
お手続きのほどどうぞよろしくお願いいたします。<br/>
内容は各自カスタマイズしましょう。
このコードから送信されたメールが以下。
10,000円(税別)も請求されてしもた。がんばれジャンヌ!
今回のコードは改変して(※9)本記事冒頭でちょっと触れました、進行表(タイムテーブル)が作れる「進行表さん」というサービスに実装してみました。どういうサービスかというと、サクッと、きれいな進行表がつくれるサービスです。まあまあ便利ですので、ハッカソンなどのイベントを企画される方はぜひ使ってみて下さいね。まだまだバグも多くて恐縮ですが…作った進行表はATNDやDoorkeeper、everevo、こくちーずなどの各イベント系サイトにも埋め込み可能です。
プレミアム会員プランにアップグレードすると、ご登録いただいているメールアドレスに請求書を送ります。
OAuth2.0で多少苦戦はしたものの(知識があれば無問題ですね、そもそもプロトコルレベルの話です)、Misoca APIは非常に使いやすいと思います。Misocaサポート様、誠にありがとうございました。
※1 http://www.paymentnavi.com/paymentnews/36980.html
※2 あこがれる、の意味。北海道放送の女性アナウンサー
※3 h2の見出しはアナ雪っぽくいきますwなんと2年遅れでハマりました。
※4 callbackはcallbackアクションにすべきかと思ったのですが、DHHが言ってたやり方をしてみました。
※5 要約しすぎですかね…汗 ごめんなさい。実際いただいたメールはこちらです。
※6 アナ雪見出しは飽きましたので普通にしましたw
※7 2016/04/01現在、APIドキュメントに記載はないのですが、パラメータ入れると動くそうです。エイプリルフールではないです。
※8 http://edgeguides.rubyonrails.org/action_mailer_basics.html
※9 今回の実装だと、請求書発行するたびにユーザーがMisocaに登録しなければならないので、改変しています。サーバーが自動で請求書を発行できるようにするために、特定のアカウントでアクセストークンを発行し、DBやファイルなど任意の場所に保存しておきます。アクセストークンの有効期限は90日なので、バッチ処理などで更新しましょう。ブラウザではなく、サーバーが直接アクセスする際はリダイレクト先のHTMLのフォームにMisocaのメールアドレスとパスワードを入力してログインが必要(※10)な処理を実装しなければならないので、面倒です。この点については今後Misocaさんに相談させて頂こうと思っています。
※10 MisocaのOAuth認証、https://app.misoca.jp/oauth2/authorize にサーバーからリクエストした場合のレスポンス(抜粋)
"<html><body>You are being <a href=\"https://app.misoca.jp/api_login\">redirected</a>.</body></html>"