GoogleAppsScriptから会計ソフトfreeeのAPIを叩いてみた

GoogleAppsScript上でfreeeのAPIを叩くことで、スプレッドシート上にfreeeのデータを展開することができる。これにより、freeeの標準機能では足りない機能などを補うことができる。

例えば弊社で使用しているスプレッドシートとして、定期出金定期入金がある。これは月額サービスにおける定期的な出金や、売電収入などの定期的な入金を1年先まで自動で登録できるものである。

freeeのアプリマーケットに定期出金アプリがあるが、これは翌月の登録を自動で行うものである。しかし資金繰りの視点で考えると、1年先まで登録があった方が嬉しい事が多い。

このように、GASからfreeeのAPIを叩くことでfreeeのかゆいところに手が届く機能を作成することができる。

今回この記事では、GoogleAppsScript上でfreeeのAPIを叩くライブラリを作成する。これを作成しておけば、各スプレッドシートからこのライブラリを呼び出すことで簡単にfreeeのデータを取得できるようになる。

freeeアプリストアでアプリを作成してKEYを取得

  1. freeeアプリストアの開発者ページへ行き、「今すぐアプリを作成」をクリックする。
  2. アプリ名を新しいアプリを作成する
  3. Client ID、Client Secretをメモしておく
2. アプリ名を新しいアプリを作成する
3. Client ID、Client Secretをメモしておく

freeeのAPIを叩く前にfreeeの認証を通す必要がある

取引データや勘定科目データを取得、登録する作業の前には必ず認証が必須です。まずは認証するためのメソッドを用意しておきましょう。

/*
参照ライブラリ
title OAuth2
project_key 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
*/
 
//連携アプリ情報
var Client_ID     = PropertiesService.getScriptProperties().getProperty("CLIENT_ID");
var Client_Secret = PropertiesService.getScriptProperties().getProperty("CLIENT_SECRET");
var COMPANY_ID    = PropertiesService.getScriptProperties().getProperty("COMPANY_ID");
var LIMIT         = 100;

function Auth() {
  
  //freeeAPIのサービスを取得
  var service = getService();
  
  //スクリプトへのアクセスを許可する認証URLを取得
  var authUrl = service.getAuthorizationUrl();
  
  Logger.log(authUrl);//取得した認証用URLをログ出力
  
}

//freeeAPIのサービスを取得する関数
function getService() {
  return OAuth2.createService('freee')
      .setAuthorizationBaseUrl('https://accounts.secure.freee.co.jp/public_api/authorize')
      .setTokenUrl('https://accounts.secure.freee.co.jp/public_api/token')
      .setClientId(Client_ID)
      .setClientSecret(Client_Secret)
      .setCallbackFunction('authCallback')
      .setPropertyStore(PropertiesService.getUserProperties())
}
 
//認証コールバック関数
function authCallback(request) {
  Logger.log(request);
  var service = getService();
  var isAuthorized = service.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('認証に成功しました。タブを閉じてください。');
  } else {
    return HtmlService.createHtmlOutput('認証に失敗しました。');
  };
}

CLIENT_ID、CLIENT_SECRET、COMPANY_IDは、スクリプトのプロパティに追加しておきましょう。

1. プロジェクトのプロパティを開く
2. スクリプトのプロパティを設定する

自由にfreeeのAPIを叩いて値を取得、登録する

基本的には全件取得のメソッドを作成しているが、{ id: value }の値を返すメソッドも作成しておいた方が色々便利かと思う。基本的にリレーショナルな構造になっているので、取引データから勘定科目名を出したいときなど、idから辿ることになるので、必要に応じてメソッドを追加していく。

取引(Deals)

function getDeals(offset, limit, search={}) {
  //freeeAPIのサービスからアクセストークンを取得
  const accessToken = getService().getAccessToken();
  
  //リクエストを送る時に付与するパラメータ
  const params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/deals?';
  url += "company_id=" + COMPANY_ID;
  url += "&accruals=with";
  url += "&offset=" + offset;
  url += "&limit=" + limit;
  if (search.type)           { url += "&type=" + search.type; }
  if (search.status)         { url += "&status=" + search.status; }
  if (search.start_due_date) { url += "&start_due_date=" + search.start_due_date; }
  if (search.end_due_date)   { url += "&end_due_date=" + search.end_due_date; }
  
  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).deals
}

function postDeals(deals) {
  //freeeAPIのサービスからアクセストークンを取得
  var accessToken = getService().getAccessToken();
  
  //リクエストを送る時に付与するパラメータ
  var params = {
    "method" : "POST",
    "contentType":"application/json",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15",
    },
    "payload": JSON.stringify(deals),
  };
  
  var url = 'https://api.freee.co.jp/api/1/deals?';
  var response = UrlFetchApp.fetch(url, params)
  return JSON.parse(response)
}

取引先(Partners)

function getPartnerMap(){
  var offset = 0;
  var limit  = 3000;
  while(1) {
    allPartners = getAllPartners(offset, limit);
    if (allPartners.length <= 0) { break }

    partnerMap = {};
    allPartners.forEach(function(partner) {
      partnerMap[partner.id] = partner.name
    })
    offset += limit;
  }
  return partnerMap;
}

function getAllPartners(offset, limit) {
  var accessToken = getService().getAccessToken();
  var params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/partners?';
  url += "company_id=" + COMPANY_ID;
  url += "&offset=" + offset;
  url += "&limit=" + limit;
  
  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).partners;
}

品目(Item)

function getItemMap(){
  var itemMap = {};
  var offset = 0;
  var limit  = 3000;
  while(1) {
    allItems = getAllItems(offset, limit);
    if (allItems.length <= 0) { break }
    allItems.forEach(function(item) {
      itemMap[item.id] = item.name
    })
    offset += limit
  }
  return itemMap;
}

function getAllItems(offset, limit) {
  var accessToken = getService().getAccessToken();
  var params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/items?';
  url += "company_id=" + COMPANY_ID;
  url += "&offset=" + offset;
  url += "&limit=" + limit;

  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).items;
}

勘定科目(AccountItems)

function getAccountItemMap(){
  var accountItemMap = {};
  accountItems = getAllAccountItems();
  accountItems.forEach(function(accountItem) {
    accountItemMap[accountItem.id] = accountItem.name
  })
  return accountItemMap;
}

function getAllAccountItems() {
  var accessToken = getService().getAccessToken();
  var params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/account_items?';
  url += "company_id=" + COMPANY_ID;
  
  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).account_items;
}

タグ(tags)

function getTagMap(){
  var offset = 0;
  var limit  = 3000;
  while(1) {
    allTags = getAllTags(offset, limit);
    if (allTags.length <= 0) { break }

    tagMap = {};
    allTags.forEach(function(tag) {
      tagMap[tag.id] = tag.name
    })
    offset += limit;
  }
  return tagMap;
}

function getAllTags(offset, limit) {
  var accessToken = getService().getAccessToken();
  var params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/tags?';
  url += "company_id=" + COMPANY_ID;
  url += "&offset=" + offset;
  url += "&limit=" + 3000;

  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).tags;
}

税区分(tax)

function getAllTaxes(offset, limit) {
  var accessToken = getService().getAccessToken();
  var params = {
    "method" : "GET",
    "headers" : {
      "Authorization" :"Bearer " + accessToken,
      "X-Api-Version" : "2020-06-15"
    }
  };

  var url = 'https://api.freee.co.jp/api/1/taxes/codes?';

  var response = UrlFetchApp.fetch(url, params).getContentText();
  return JSON.parse(response).taxes;
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です