freee × kintone:顧客情報を会計 freee に連携する

著者名:安藤 光昭(ビットリバー株式会社)

目次

こんにちは、kintoneエバンジェリストの安藤です。

このTipsは、クラウド会計ソフトの会計freeeとkintoneのデータを連携させるカスタマイズについて紹介します。
業務システムとして構築したkintoneのデータを会計に連携することでいろいろな可能性が広がります。

はじめに

会計 freee (External link) はkintoneと同様にさまざまな機能がAPIとして公開されています。
取引先や仕訳、請求データなどを外部から連携したり、B/SやP/Lなどの会計情報を取得して利用できます。

参考: freee Developers Community の会計 API リファレンス (External link)

この記事では、さまざまな取引の基本となる顧客情報をkintoneから会計freeeに連携させるカスタマイズを紹介します。

会計freeeは「取引先」を登録することで売上や仕入の管理に利用できます。
取引に取引先を登録すると、レポートで取引先毎の推移を見たり、取引一覧で取引先を検索できます。

このカスタマイズを応用すると、kintoneで管理する顧客のうち受注済顧客だけを会計freeeの取引先に連携させるなどの活用が可能となり、システム間の二重入力が解消されます。
この記事では、ステータスにかかわらず顧客情報を保存する際、取引先が作成されるところまでを解説します。

必要なもの

  • kintoneアカウント
  • freeeアカウント

準備

kintone アプリの作成

まず、連携元となるkintoneの顧客情報アプリを作成します。

今回は「顧客名(正式名称)」「顧客名(略称)」「電話番号」の3つのフィールドで作成します。

フィールド名とフィールドコードの設定
フィールド名 フィールドタイプ フィールドコード
顧客名(正式名称) 文字列(1行) customerName
顧客名(略称) 文字列(1行) customerNameShort
電話番号 リンク(電話番号) phone

アプリを作成したら、URLをメモします。後述するfreeeの設定で利用します。
アプリのURLは「https://sample.cybozu.com/k/ {アプリID} /」の形式です。

会計 freee の開発用テスト事業所の作成

freee Developers Community の freee API スタートガイド (External link) を参考に開発用テスト事業所を作成してください。

freee の API 認証情報を取得する

次に、API連携させるためにfreee側の準備をしていきます。

  1. 会計 freee (External link) にログインした後、「設定」>「データ設定」>「連携アプリ設定」を開きます。

  2. freeeアプリストアの開発者ページから「今すぐアプリを作成」をクリックします。

  3. 「アプリ名」と「概要」を入力し、利用規約に同意したら「作成」をクリックします。
    アプリ名や概要はご自由に決めていただくことができます。

  4. 作成されたアプリの「コールバックURL」に連携したいkintoneのアプリのURLを設定し、「Client ID」と「Client Secret」をメモしておきます。

    kintoneアプリのURLは末尾のスラッシュを忘れるとエラーになります。注意してください。
    「https://sample.cybozu.com/k/ {アプリID} /

    caution
    警告

    Client IDとClient Secretは重要な情報です。  
    絶対に外部へ公開しないよう注意してください。
    

  5. 「下書き保存」をクリックし、情報を保存します。

    「権限設定」は未設定のままでも動作しますが、適切な権限を割り振ってセキュリティの設計にご注意ください。
    「公開設定」は作成したfreeeアプリをストアで公開する場合に利用するため、今回は設定しません。

JavaScript カスタマイズの開発

freee側の準備が終わったら、いよいよkintone側のカスタマイズをスタートします。

この記事では、次の2つのストーリーでカスタマイズを作成します。

  • アプリの一覧画面を表示したタイミングでfreeeの認証情報と事業所情報を取得する。
  • レコードの保存時にfreeeの取引先を新規作成する。

まずはカスタマイズの内容について説明します。

freee から認証トークンを取得する

OAuth2.0を使って、会計freee APIから認証トークンを取得します。

caution
警告

この処理では freee の API 認証情報を取得するの5で取得した「Client ID」と「Client Secret」を利用する必要があります。
これらの情報は漏洩するとAPIを自由に実行できてしまうため、kintoneのJavaScriptの開発においても慎重に扱う必要があります。
cybozu develper networkでは、認証情報の秘匿にプラグインを利用する方法を推奨しています。
詳しくは以下の記事を確認してください。

OAuth2.0はサービス間で認証情報を連携するしくみです。
kintoneも外部からの連携のためにOAuth2.0の入口を用意しています(今回の記事とは逆パターン)。
参考: OAuth クライアント
OAuth2.0の理解には、Webサービスに関する基礎的な知識が必要なため、詳細な説明は省略します。

当記事では、会計freee APIから認証トークンを取得するエンドポイントの呼び出し例を抜粋します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/*
 * kinone x freee sample program
 * Copyright (c) 2020 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

const authUrl = 'https://accounts.secure.freee.co.jp/public_api/authorize';
const tokenUrl = 'https://accounts.secure.freee.co.jp/public_api/token';
const endPointUrl = 'https://api.freee.co.jp/api/1/';
// このアプリのURL
const callbackUrl = 'https://' + window.location.hostname + '/k/' + kintone.app.getId() + '/';
// freee連携用トークン
// TODO: 保管したトークンを取得する実装
// (注意) このままでは画面遷移時にトークンが破棄されるため動作しません
let freeeAccessToken = '';
const freeeCompanyId = '';

kintone.events.on('app.record.index.show', (event) => {
  // freeeからのコールバック時には /k/xxx/?code=認証コード という形式で返ってくる
  const queryString = location.search;
  // アクセストークンがない場合のみ取得処理にリダイレクトする
  if (!queryString && !freeeAccessToken) {
    // Client IDはプラグインで保存した情報を利用
    location.href = authUrl + '?response_type=code' +
            '&client_id=' + CONFIG.client_id +
            '&redirect_uri=' + encodeURIComponent(callbackUrl);
    return event;
  }
  // パラメータが設定されている場合認証コードを取得する
  if (queryString.substr(0, 6) === '?code=') {
    const authCode = queryString.substr(6);
    if (!authCode) {
      console.log('freeeの認証情報取得に失敗しました。');
      return event;
    }
    console.log(authCode);
    // 取得した認証コードを使ってアクセストークンを取得する
    const body = {
      // IDとSecretは kintone.plugin.app.setProxyConfig() で設定済み
      // 'client_id': clientId,
      // 'client_secret': clientSecret,
      grant_type: 'authorization_code',
      redirect_uri: callbackUrl,
      code: authCode
    };
    const header = {
      'Content-Type': 'application/json'
    };
    // アクセストークン取得のAPIを実行する
    // TODO: プラグインを利用したシークレットの隠蔽
    kintone.plugin.app.proxy(PLUGIN_ID, tokenUrl, 'POST', header, body).then((response) => {
      if (!response) return;
      console.log(response);
      // freeeから取得した認証情報をパースする
      const credentials = JSON.parse(response[0]);
      let accessToken = credentials.access_token;

      if (!accessToken) {
        console.log('freeeの認証情報取得に失敗しました。');
        accessToken = 'FAILED!!'; // リダイレクトループしないようにダミー
      }
      console.log(accessToken);
      // 取得したトークンを保存
      freeeAccessToken = accessToken;
      // TODO: 画面遷移後もトークンを保管する実装
      // (注意) このままでは画面遷移時にトークンが破棄されるため動作しません

      // TODO: 保存が終わったら再度リダイレクトして、事業所を取得する処理を追加(後述)

    }).catch((error) => {
      console.log(error);
      console.log('freeeの認証情報取得でエラーが発生しました。');
    });
  }
  return event;
});

上記のコードで取得したアクセストークンは、次のステップ以降で何度も利用します。

処理の流れは次のとおりです。2つのサービスを行き来することで正しい認証手続きということを担保しています。

  1. kintoneからfreee OAuthに認証情報を取得依頼を送る。
  2. freee側は認証のためのログイン画面を表示する。
  3. ログインに成功した場合、コールバックURLで指定されたページへリダイレクトする。
  4. リダイレクトされたkintone側でアクセストークンを取得する。

アクセストークンについて

上記のコードでは、取得したアクセストークンは画面が切り替わると無効化されてしまいます。
kintoneのログイン中のみトークンが利用可能となるようなしくみを実装する必要があります。

この場合、アプリにトークン情報を保存してkintoneの権限を設定することで管理者とログイン中のユーザ以外は参照不可にするなどの方法が考えられます。
今回の記事ではこの部分は省略します。

アクセストークンを使って事業所情報を取得する

アクセストークンの取得ができたら、次に「事業所ID」を取得します。

freeeとのAPI連携ではリクエストに必ず「事業所ID」を指定する必要があります。
freeeは1つのユーザIDで複数の事業所への所属が可能です。
そのため、どの事業所にAPI連携するかを特定する際、「事業所ID」が使用されます。

「事業所ID」はfreeeの管理画面では参照できないためAPIを使って取得する必要があります。

認証には、先ほど取得したアクセストークンを利用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
 * kinone x freee sample program
 * Copyright (c) 2020 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

// freeeの認証情報取得の処理の後半へ追加する

// 取得したアクセストークンを使ってヘッダを作成
const header = {
  Authorization: 'Bearer ' + freeeAccessToken,
  'Content-Type': 'application/json',
};
// 事業所の一覧取得APIを呼び出す
kintone.proxy(endPointUrl + '/companies', 'GET', header, {}).then((response) => {
  if (!response) return;
  console.log(response);
  // 結果をパースする
  const result = JSON.parse(response[0]);
  // 事業所一覧の配列から情報を取り出す
  for (let i = 0; i < result.companies.length; i++) {
    console.log(result.companies[i]);
  }
  // 1番目の事業所を利用する
  let freeeCompanyId = result.companies[0].id;
  if (!freeeCompanyId) {
    console.log('freeeの事業所ID取得に失敗しました。');
    freeeCompanyId = 'FAILED!!'; // リダイレクトループしないようにダミー
  }
  // 事業所IDが取得できた場合、セッションストレージに保存する
  window.sessionStorage.freeeCompanyId = freeeCompanyId;
}).catch((error) => {
  console.log(error);
  console.log('freeeの事業所取得でエラーが発生しました。');
});

freeeのAPIは、取得する情報の種類毎にリクエスト先のエンドポイント(URL)が異なります。
事業所の取得では「/companies」に接続しています。

取得した事業所の情報はセッションストレージに格納しています。

「事業所ID」の取得ができたら、もう少しです!

顧客情報を使って freee の取引先を新規作成する

これまでのステップで取得したアクセストークンと「事業所ID」を使って、いよいよfreeeに新規の取引先を作成していきます!

取引先の新規作成では「/partners」に接続します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
 * kinone x freee sample program
 * Copyright (c) 2020 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

kintone.events.on('app.record.create.submit', (event) => {
  if (!freeeAccessToken) return event;
  if (!freeeCompanyId) return event;
  // アクセストークンを使ってヘッダを作成
  const header = {
    Authorization: 'Bearer ' + freeeAccessToken,
    'Content-Type': 'application/json',
  };
  // 新規作成用のパラメータを作成
  const body = {
    company_id: Number(freeeCompanyId),
    name: event.record.customerNameShort.value,
    long_name: event.record.customerName.value,
    phone: event.record.phone.value,
  };
  // 取引先の新規作成APIを呼び出す
  return kintone.proxy(endPointUrl + '/partners', 'POST', header, body).then((response) => {
    if (!response) return event;
    console.log(response);
    // 結果をパースする
    const result = JSON.parse(response[0]);
    console.log(result.partner);

    return event;

  }).catch((error) => {
    console.log(error);
    console.log('freeeの取引先作成でエラーが発生しました。');

    return false;
  });
});

すでに freee に存在する取引先と同じ名称を使うとエラーになるのでこの点も注意が必要です。

カスタマイズの内容がおおよそわかったらkintoneアプリに設定しましょう。

プラグイン化

kintone プラグイン開発手順にしたがって、kintoneプラグインを作成します。

PC用JavaScriptファイルには次を指定します。

  • https://js.cybozu.com/jquery/3.4.1/jquery.min.js
  • これまでのステップで作成したカスタマイズJavaScriptのファイル

また、kintone.plugin.app.setProxyConfig()を使ってfreeeの「Client ID」と「Client Secret」を保存できる設定画面を作ります。
kintone.plugin.app.setProxyConfig()については、 プラグインの設定情報を取得するを参考にしてください。

プラグイン化が完了したら、kintoneにプラグインをインストールして、作成したkintoneアプリにプラグインを追加しましょう。

手順がわからない方は以下を参考にしてください。

連携を試す

開発した連携機能がうまく動いているかを試してみましょう。

作成したアプリを公開して、アプリを開きます。

設定に問題がなければ、freeeのログイン画面にリダイレクトされます。

freeeにログインすると、API認証の画面が表示されます。

「許可する」をクリックするとkintoneの画面に戻ります。

レコードを新規作成し、保存します。

連携に成功するとfreeeの取引先設定に新しい顧客情報が登録されていることを確認できます。

まとめ

会計freeeのAPIを使うことで、比較的簡単に会計freeeに情報を登録できました。
実際に作成された方はおわかりかと思いますがfreeeのAPIではOAuth2.0のしくみを利用します。
そのため、最も難易度が高いポイントは開発時にセキュリティを確保することです。

認証の問題をクリアできれば、あとはfreee APIには連携可能な情報が非常に多く用意されており、うまく使いこなすことで会計の手間を大幅に削減できます。

注意事項

この記事では、最も難しいポイントのOAuth2.0の認証やトークンの管理についての記載を省略しています。
そのため、記事中に記載したコードをコピーしただけでは正しく動作しません。

文責

安藤光昭(kintoneエバンジェリスト、 kintone 開発のキントバ (External link) 代表)

information

このTipsは、2020年4月時点の会計freee 、kintoneで動作を確認しています。