とーますメモ

Ruby on Rails / Goなどの学習メモ

【Rails】Quickbooks Web Connector(QBWC)を使って、RailsとQuickBooks Desktopを接続してみた

中小企業会計ソフトの分野で、日本ではfreeeやマネーフォワードが普及しているが
海外ではQuickbooksが広く普及している。
このQuickbooks内に外部からデータをRailsアプリ経由で追加することで入力作業を省き、業務効率を上げようという話になった。

前提としてQuickbooks Onlineではなく、Quickbooks DesktopというWindowsアプリを使う。Onlineを使用している方にはこの記事は不要。
Quickbooks Onlineだと、すごく充実したREST APIドキュメント
あるので開発も簡単だが、Quickbooks Desktopでは「Quickbooks Web Connector(以降QBWC)」を使う。

色々と調べる中で、当たり前だが日本語の情報が壊滅的になかったので、将来の自分用に調べた内容をこの記事に残す。

QBWCの使い方

・QBWCは、QuickBooks Desktopがインストールされている端末にインストールする。
・APIはRESTではなく、SOAPという古いタイプのAPIで、XMLをやり取りすることでリクエストを行う。

以下のPDF内で、なぜQBWCは、シンプルなWeb APIではないのかについて説明があるが
一言でいうと、セキュリティを確保するため、不特定多数が使用するインターネット上からのアクセスを防ぎたいという意図があった模様。
※だったら、QuickBooks Onlineはどうなんだという疑問はあるが。
https://developer-static.intuit.com/qbSDK-current/doc/PDF/QBWC_proguide.pdf

・Railsとのやり取りの流れは以下
1)RailsでSOAP APIへのリクエスト(Job)を作成する
2)QBWC側からRailsにアクセスし、Jobがあればそれを実行する。
つまりRails側からJob実行のキューは送れない。Job実行のトリガーは必ずQBWCから。

・RailsでQBWCとやり取りするには、qbwcのgemを使用する。
github.com

Rails gem(qbwc)の使い方

・基本的な設定や使い方については上記の公式サイトを参照
・作成できるJobは「読込」と「書込」のどちらも可能
・Job作成にあたり、リクエスト用のHashを作成するのだが、それには以下のドキュメントを使用する。
しかし使いにくいし、説明不足感が否めない。

developer-static.intuit.com

このドキュメントを使用し、リクエストHashを作成する上で大事な点は以下
・Railsで使用するフォーマットは「qbXML」。
・QBEditionsは使用するQuickBooks Desktopの国を設定すること。
ドキュメントのXMLの「順番」は必ずそのとおりにすること。普通のHashで書くように、KEYの順番を入れ替えて作成すると「Parse Error」を返す。
・書込の際に「AMTTYPE」の値を送信する場合は、小数点第二位まで含んだ文字列を設定する必要がある。
※ ドキュメントにも書いてない。

✗: 123.4
○: 123.40

https://help.developer.intuit.com/s/question/0D50f00004rTfc6CAC/qbxml-amount-invalid-cant-convert
https://help.developer.intuit.com/s/question/0D5G000004Dk7HIKAZ/invoice-amount-error-3040-what-am-i-doing-wrong

・参照系のリクエストを送るときに、膨大なデータをリクエストするときは、一度にリクエストを送らず「Iterator」を使用したコードを作成すること。

自分は使用してはいないが、恐らく以下の記事を見ると、

最初のリクエストは以下のようにiteratorにStartを指定し

...
:sales_order_query_rq => {
  {:xml_attributes => { 'iterator'  => "Start" }}
}
...

それ以降のリクエストでは、iteratorにContinueを指定し、最初のリクエストの返り値であると思われるIteratorIDを設定する模様。

...
:sales_order_query_rq => {
  {:xml_attributes => { 'iterator'  => "Continue", 'iterator_id' => iteratorID }}
}
...

https://github.com/consolibyte/quickbooks-php/blob/master/docs/web_connector/example_web_connector_import.php#L214
https://github.com/Natejd04/QBWC_Test/blob/d23b42738eae05844e0e23375621fa48809ddb77/app/workers/z-customer_order_worker.rb
https://stackoverflow.com/questions/21757478/iteration-samples-in-quick-books-using-web-connector


未確認だが、使用する際に試したい。

・Mod系のAPI使用時に注意する点
例えば、Invoiceの内容を変更するInvoiceModを使用するとしよう。その時前回に送ったInvoiceのItemLine内容に、新しいItemLineを追加する必要があるとする。
InvoiceAddのAPIならば、InvoiceLineAddがあり名前の通りに、Itemを追加するだけでよいが
InvoiceModのAPIは、InvoiceLineModという変更前提のものしかない。。。それでどうするか。。。

「TxnLineIDを-1」に設定すれば良い
言わずもがなドキュメントにはこの記載はない。

またこのInvoiceModを使用時には、以前登録したデータも追加しないと、前のデータを上書きするみたいな内容になるので注意。

https://help.developer.intuit.com/s/question/0D50f00005gIodbCAC/how-can-i-get-txnid-and-editsequence-by-same-inovice-date-invoice-on-qb-for-checking-whether-add-new-invoice-or-add-new-line-in-same-invoice-like-an-attachment-and-how-can-i-add-new-line-in-same-invoiceaspnet-c
https://stackoverflow.com/questions/32817070/how-to-modify-an-invoice-in-quickbooks-using-qbxml-and-qbsdk13

・処理が遅いとき・・・
Rails側からデータを送信したときに、リクエストをQBWC側で受け取るのは早いが、それからの処理がものすごい遅いことがあった。
レジストリをいじって、キャッシュやログ出力の抑制などを試したが、あまり効果がなく、色々試して最後に効果があったのが
できるだけ、リクエストに必要なパラメータは全て送ること。

試したのは、InvoiceAddのAPIに、InvoiceLineAddで50個のデータを追加して送るとなんと3分もかかっていた。
またアイテムを追加するたびにn²で遅くなって行く模様。。。
このとき追加した情報はItemRef, Quantity, Amountの3つ。
そしてここにSalesTaxCodeRefを"E"で追加したら、20秒で処理が終わった。
恐らく送れるパタメータはできるだけ送ったほうが、QuickBooks Desktop側での処理をしなくてもよい?のかもしれない。