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 で動作を確認しています。