GoogleAppsScript上でfreeeのAPIを叩くことで、スプレッドシート上にfreeeのデータを展開することができる。これにより、freeeの標準機能では足りない機能などを補うことができる。
例えば弊社で使用しているスプレッドシートとして、定期出金、定期入金がある。これは月額サービスにおける定期的な出金や、売電収入などの定期的な入金を1年先まで自動で登録できるものである。
freeeのアプリマーケットに定期出金アプリがあるが、これは翌月の登録を自動で行うものである。しかし資金繰りの視点で考えると、1年先まで登録があった方が嬉しい事が多い。
このように、GASからfreeeのAPIを叩くことでfreeeのかゆいところに手が届く機能を作成することができる。
今回この記事では、GoogleAppsScript上でfreeeのAPIを叩くライブラリを作成する。これを作成しておけば、各スプレッドシートからこのライブラリを呼び出すことで簡単にfreeeのデータを取得できるようになる。
目次
freeeアプリストアでアプリを作成してKEYを取得
- freeeアプリストアの開発者ページへ行き、「今すぐアプリを作成」をクリックする。
- アプリ名を新しいアプリを作成する
- 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は、スクリプトのプロパティに追加しておきましょう。
自由に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;
}