はじめに
基幹・会計システムのデータ分析・連係の需要はまだまだ尽きることがありませんが、各種アプリケーションが対応しているBIツールやETL/EAIツールは少ないのが実情かと思います。
そこで今回はPCAの会計ソフト、会計DXが公開しているWeb APIを用いて、CData ODBC REST Driver経由でBIツールのTableauとの連係を実現してみました。
PCA会計DXとは
ピー・シー・エー株式会社が提供する一般企業様向け会計ソフトです。
詳しくは以下のURLからどうぞ。
また、今回使用するPCA クラウド Web APIについては、以下のWebサイトで詳しく記載されています。
実現イメージ
各BIツール(Tableau、QlikSence、PowerBI)からはODBCインタフェースでSQL(Select文)を発行するとCData REST ODBC Driverが、PCA会計DXのWebAPIのエンドポイントに対してHTTPリクエストでGetメソッドを発行します。
Jsonフォーマットで返ってきたデータセットをCData REST ODBC DriverがODBCインタフェースのResultsetに変換してBIツールに返します。
これにより、BIツールからアドホックにSQLによるリクエストがあったタイミングで最新のデータをPCA会計DXから取得することが可能です。
前提条件
本記事では以下のサービスや製品を使用しています。
- PCA 会計DX クラウド版 (あらかじめインストールしておいてください)
- CData REST ODBC Driver ※30日間の評価版あり
- Tableau Desktop ※無料トライアル版あり
- Googleアカウント(OAuth用アプリケーション登録をするために必要となります)
手順
PCA Web API 利用準備
PCA Web APIを利用する場合は、あらかじめ利用申請等が必要になるので、以下のWeb Siteから実施しておきます。
申請後PCAクラウドアプリケーション利用用アカウントとして、ServiceユーザーIDとパスワード、招待コードが送られてくるので、控えておきましょう。
その上で、以下Webサイトにアクセスし、OAuthの認証を通すためにアプリケーション登録を行います。
Webサイトにアクセスすると、以下のような画面が表示されるので、任意のGoogleアカウントでログインします。
一番最初はアカウント登録をする必要があるので、各種情報を招待コードを入力し、[登録]をクリックします。
登録完了後、アプリケーションの管理画面へ遷移します。
この画面からOAuth認証用のアプリケーション登録を行い、認証に必要なClientID・ClientSecretを取得します。
それでは実際に[新規アプリケーションの作成]をクリックし、アプリケーション登録を行います。
以下の情報をそれぞれ入力し、[登録]をクリックします。
- アプリケーション名 : 任意のアプリケーション名を入力します。
- 会社名 : 任意の会社名を入力します。
- 説明 : 任意の説明文を入力します。
- リダイレクトURL : http://localhost:33333 (33333ポートを別なアプリケーションで使用している場合は違うポートを指定してください)
- アプリケーションURL : http://localhost:33333
- プログラムID : cdata等任意のプログラムIDを入力します。
- 使用するPCAのAPI : 「PCA会計DX」を選択します。
登録完了後、クライアントIDとクライアントシークレットが表示されるので、控えておきます。
以上でアプリケーション登録は完了です。
REST データ RSDファイル
続いて、PCAのWeb APIをCData ODBC REST DeiverがSQLとして解釈できるように設定ファイルを作成します。
サンプルとしてPCA会計DXの仕訳伝票 (InputSlip)のデータを取得するための設定ファイルを作成していますので、以下のXMLを[InputSlip.rsd]というファイル名で保存して、利用してみてください。
保存先フォルダは後ほど使用するので「C:\CData_REST\PCA」といった書き込み可能な任意のフォルダに配置してください。
以下、InputSlip.rsdのサンプルです。
<rsb:script xmlns:rsb="http://www.rssbus.com/ns/rsbscript/2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- See Column Definitions to specify column behavior and use XPaths to extract column values from JSON. -->
<rsb:info title="JSONData" desc="Generated schema file." xmlns:other="http://www.rssbus.com/ns/rsbscript/2/other">
<!-- You can modify the name, type, and column size here. The name must match the values in the rsb:script block below -->
<attr name="BEVersion" xs:type="integer" readonly="false" other:xPath="BEVersion" />
<attr name="CrBankTransferState" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/CrBankTransferState" />
<attr name="CrBuId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrBuId" />
<attr name="CrHojoId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrHojoId" />
<attr name="CrId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrId" />
<attr name="CrKmkId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrKmkId" />
<attr name="CrMoney" xs:type="double" readonly="false" other:xPath="{SubRepeatElement}/CrMoney" />
<attr name="CrReserve1" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrReserve1" />
<attr name="CrReserve2" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrReserve2" />
<attr name="CrReserve3" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrReserve3" />
<attr name="CrStamp" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/CrStamp" />
<attr name="CrTaxCalcMode" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/CrTaxCalcMode" />
<attr name="CrTaxClassId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrTaxClassId" />
<attr name="CrTaxKmkId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/CrTaxKmkId" />
<attr name="CrTaxMoney" xs:type="double" readonly="false" other:xPath="{SubRepeatElement}/CrTaxMoney" />
<attr name="DrBankTransferState" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/DrBankTransferState" />
<attr name="DrBuId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrBuId" />
<attr name="DrHojoId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrHojoId" />
<attr name="DrId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrId" />
<attr name="DrKmkId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrKmkId" />
<attr name="DrMoney" xs:type="double" readonly="false" other:xPath="{SubRepeatElement}/DrMoney" />
<attr name="DrReserve1" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrReserve1" />
<attr name="DrReserve2" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrReserve2" />
<attr name="DrReserve3" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrReserve3" />
<attr name="DrStamp" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/DrStamp" />
<attr name="DrTaxCalcMode" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/DrTaxCalcMode" />
<attr name="DrTaxClassId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrTaxClassId" />
<attr name="DrTaxKmkId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/DrTaxKmkId" />
<attr name="DrTaxMoney" xs:type="double" readonly="false" other:xPath="{SubRepeatElement}/DrTaxMoney" />
<attr name="JournalHeaderId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/JournalHeaderId" />
<attr name="LabelId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/LabelId" />
<attr name="LabelString" xs:type="unknown" readonly="false" other:xPath="{SubRepeatElement}/LabelString" />
<attr name="LineNumber" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/LineNumber" />
<attr name="Number1" xs:type="unknown" readonly="false" other:xPath="{SubRepeatElement}/Number1" />
<attr name="Number2" xs:type="unknown" readonly="false" other:xPath="{SubRepeatElement}/Number2" />
<attr name="RemId" xs:type="integer" readonly="false" other:xPath="{SubRepeatElement}/RemId" />
<attr name="Summary" xs:type="string" readonly="false" other:xPath="{SubRepeatElement}/Summary" />
<attr name="CrBankTransferState" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrBankTransferState" />
<attr name="CrBuId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrBuId" />
<attr name="CrHojoId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrHojoId" />
<attr name="CrId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrId" />
<attr name="CrKmkId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrKmkId" />
<attr name="CrMoney" xs:type="double" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrMoney" />
<attr name="CrReserve1" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrReserve1" />
<attr name="CrReserve2" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrReserve2" />
<attr name="CrReserve3" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrReserve3" />
<attr name="CrStamp" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrStamp" />
<attr name="CrTaxCalcMode" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrTaxCalcMode" />
<attr name="CrTaxClassId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrTaxClassId" />
<attr name="CrTaxKmkId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrTaxKmkId" />
<attr name="CrTaxMoney" xs:type="double" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/CrTaxMoney" />
<attr name="DrBankTransferState" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrBankTransferState" />
<attr name="DrBuId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrBuId" />
<attr name="DrHojoId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrHojoId" />
<attr name="DrId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrId" />
<attr name="DrKmkId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrKmkId" />
<attr name="DrMoney" xs:type="double" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrMoney" />
<attr name="DrReserve1" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrReserve1" />
<attr name="DrReserve2" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrReserve2" />
<attr name="DrReserve3" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrReserve3" />
<attr name="DrStamp" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrStamp" />
<attr name="DrTaxCalcMode" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrTaxCalcMode" />
<attr name="DrTaxClassId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrTaxClassId" />
<attr name="DrTaxKmkId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrTaxKmkId" />
<attr name="DrTaxMoney" xs:type="double" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/DrTaxMoney" />
<attr name="JournalHeaderId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/JournalHeaderId" />
<attr name="LabelId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/LabelId" />
<attr name="LabelString" xs:type="unknown" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/LabelString" />
<attr name="LineNumber" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/LineNumber" />
<attr name="Number1" xs:type="unknown" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/Number1" />
<attr name="Number2" xs:type="unknown" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/Number2" />
<attr name="RemId" xs:type="integer" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/RemId" />
<attr name="Summary" xs:type="string" readonly="false" other:xPath="InputSlipDataList/BEInputSlipData/Summary" />
<attr name="ApprovalAreaUserId1" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/ApprovalAreaUserId1" />
<attr name="ApprovalAreaUserId2" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/ApprovalAreaUserId2" />
<attr name="ApprovalAreaUserId3" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/ApprovalAreaUserId3" />
<attr name="ApprovalAreaUserId4" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/ApprovalAreaUserId4" />
<attr name="Date_SerializeTarget" xs:type="string" readonly="false" other:xPath="InputSlipHeader/Date/SerializeTarget" />
<attr name="HsId" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/HsId" />
<attr name="Id" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/Id" />
<attr name="InputAreaUserId" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/InputAreaUserId" />
<attr name="InputModuleName" xs:type="unknown" readonly="false" other:xPath="InputSlipHeader/InputModuleName" />
<attr name="JournalClass" xs:type="string" readonly="false" other:xPath="InputSlipHeader/JournalClass" />
<attr name="LockType" xs:type="string" readonly="false" other:xPath="InputSlipHeader/LockType" />
<attr name="ManageClass" xs:type="string" readonly="false" other:xPath="InputSlipHeader/ManageClass" />
<attr name="Number" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/Number" />
<attr name="OldId" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/OldId" />
<attr name="OrgId" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/OrgId" />
<attr name="Reserve1" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/Reserve1" />
<attr name="Reserve2" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/Reserve2" />
<attr name="Reserve3" xs:type="integer" readonly="false" other:xPath="InputSlipHeader/Reserve3" />
<attr name="ReserveMoney1" xs:type="double" readonly="false" other:xPath="InputSlipHeader/ReserveMoney1" />
<attr name="ReserveMoney2" xs:type="double" readonly="false" other:xPath="InputSlipHeader/ReserveMoney2" />
<attr name="ReserveMoney3" xs:type="double" readonly="false" other:xPath="InputSlipHeader/ReserveMoney3" />
<attr name="ReserveString1" xs:type="unknown" readonly="false" other:xPath="InputSlipHeader/ReserveString1" />
<attr name="ReserveString2" xs:type="unknown" readonly="false" other:xPath="InputSlipHeader/ReserveString2" />
<attr name="ReserveString3" xs:type="unknown" readonly="false" other:xPath="InputSlipHeader/ReserveString3" />
<attr name="State" xs:type="string" readonly="false" other:xPath="InputSlipHeader/State" />
<attr name="UpdateTime" xs:type="datetime" readonly="false" other:xPath="InputSlipHeader/UpdateTime" />
<attr name="VanishState" xs:type="boolean" readonly="false" other:xPath="InputSlipHeader/VanishState" />
<attr name="MainDrCrMode" xs:type="string" readonly="false" other:xPath="MainDrCrMode" />
<attr name="PermanentId" xs:type="integer" readonly="false" other:xPath="PermanentId" />
<attr name="SlipState" xs:type="string" readonly="false" other:xPath="SlipState" />
<attr name="TaxOrgMoneyCalcedByAs" xs:type="boolean" readonly="false" other:xPath="TaxOrgMoneyCalcedByAs" />
</rsb:info>
<rsb:set attr="outer.uri" value="[_connection.ServerURL][_connection.ApiVersion]/[_connection.ProductCode]/SelectDataArea" />
<rsb:set attr="outer.Method" value="POST"/>
<rsb:set attr="outer.ContentType" value="application/json" />
<rsb:set attr="outer.encodepostdata" value="false" />
<rsb:set attr="outer.Data">
{
"DataArea":"[_connection.DataAreaID]"
}
</rsb:set>
<rsb:set attr="outer.EnablePaging" value="True" />
<rsb:set attr="inner.uri" value="[_connection.ServerURL][_connection.ApiVersion]/[_connection.ProductCode]/Find/InputSlip" />
<rsb:set attr="inner.RepeatElement" value="/ArrayOfBEInputSlip/BEInputSlip" />
<rsb:set attr="inner.SubRepeatElement" value="/ArrayOfBEInputSlip/BEInputSlip/InputSlipDataList/BEInputSlipData" />
<rsb:set attr="inner.ContentType" value="application/json" />
<rsb:set attr="inner.header:name" value="Accept" />
<rsb:set attr="inner.header:value" value="application/json" />
<!-- The GET method corresponds to SELECT. Within the script block, you can see the URI modified to append a query string parameter. The results of processing are pushed to the schema's output. See SELECT Execution for more information. -->
<rsb:script method="GET">
<rsb:call op="jsonproviderGet" input="outer" output="firstOut">
</rsb:call>
</rsb:script>
<!-- The GET method corresponds to SELECT. Within the script block, you can see the URI modified to append a query string parameter. The results of processing are pushed to the schema's output. See SELECT Execution for more information. -->
<rsb:script method="GET">
<rsb:call op="jsonproviderGet" input="inner">
<rsb:push/>
</rsb:call>
</rsb:script>
</rsb:script>
RSDファイルの詳しい設定方法は下記URLのヘルプページに記載しています。
CData ODBC REST Driverのインストール
TableauとPCA会計クラウドのAPIを繋ぐために必要となるCData ODBC REST Driverをインストールします。
CData REST ODBC Driverの30日間の評価版をダウンロードします。ダウンロードの際には、Emailの登録が必要となります。
ダウンロードしたsetup.exeファイルをBIツールがインストールされているマシンにインストールします。インストールウィザードに従い、EULAを確認したうえでインストールを完了します。
※途中、ライセンスサーバーへのオンラインアクティベーションが行われるためネットワーク環境に接続されている必要があります。
インストールが完了すると、ODBCのDSN設定のウィンドウが立ち上がります。
以下の項目をセットします。
-
OAuth
- OAuth Version : 2.0
- Callback URL :
- OAuth Access Token URL : https://east02.pcawebapi.jp/v1/Acc20/Auth/Token
- OAuth Authorization URL : https://east02.pcawebapi.jp/v1/Acc20/Auth/Authorize
- OAuth Client Id : PCA Developers Console で取得したクライアントID
- OAuth Client Secret : PCA Developers Console で取得したクライアントシークレット
- OAuth Grant Type : CODE
- OAuth Refresh Token UL : https://east02.pcawebapi.jp/v1/Acc20/Auth/Token
-
Schema
- Location : 先程RSDファイルを配置したフォルダパス(例:C:\CData_REST\PCA)
-
その他
- Other : ProductCode=Acc20;ServerURL=https://east02.pcawebapi.jp/;ApiVersion=v1;DataAreaID=P20V01C081ACC0001;
OtherのProductCodeは会計DXの設定値を置いていますが、違うPCAアプリケーションを利用する場合は都度適切な値に書き換えてください。
また、DataAreaIDは試用版の環境となっているので、こちらも都度適切な値へ書き換えてください。
各種URLの接続先はEast02に設定しています。
「接続のテスト」ボタンをクリックするとOAuth認証のため事前に登録したアプリケーションの認証画面がブラウザで立ち上がります。
配布されている[サービスユーザーID][パスワード]を入力し、サービス認証をクリックします。
次に、PCA会計DXのユーザーアカウントの情報を入力し、ログオンを行います。
アクセス許可画面が表示されるので、内容を確認の上[データの利用を許可する]をクリックします。
OAuth Authorization Successful!の画面が表示されれば、認証完了です。
Tableauでの接続確認
Tableau Desktopを起動して、データ接続より「サーバーへ」>「詳細」>「その他データベース(ODBC)」を選択します。
「その他のデータベース(ODBC)」設定ウィンドウが開いたら、接続手段内のDSNから「CData REST Source」を選択して「サインイン」します。
「データソース」画面が開くので、左側のペインで、表「InputSlip (REST.InputSlip) (CData))」を選択して、右上のエリアにドラッグ&ドロップします。抽出を行い、右下のデータプレビューにPCA会計DXの仕訳伝票が表示されることを確認します。
あとはTableauの機能を利用して、各種グラフやマトリクスを作成することが可能です。