freeeはBASEやSquareなど様々なサービスと連携しており、その取引明細を自動でfreeeに取り込むことができます。
BASE(ベイス) – 売上データを取り込む
Square (スクエア) – 売上データを取り込む
いろいろなサービスを連携することで日々の記帳入力作業が省略でき、まさに神機能です。
しかし、ある程度組織が大きくなってくると、店舗ごとや部門ごとの損益を管理したくなります。BASEを例にあげると、BASEから取り込まれる取引には自動で部門や取引先、品目などのタグを付与することはできません。
今回は、この自動同期して取得した取引に各種のタグを付与した上で更新するスクリプトを紹介したいと思います。
PUT(更新)は危険な処理であることを心得る
APIを使用してデータを更新することをPUTと呼びますが、このPUTの処理はもともとあったデータを変更してしまうため、操作を誤ったりスクリプトにバグがあると大きな問題となります。
そのため実装前には入念なチェックとテストを行うことをお勧めします。 当記事で紹介しているスクリプトやライブラリを利用して何か不具合があった場合も一切の責任を負いかねますので、予めご承知おきください。
しかし危険である分、リターンも大きいスクリプトでもあります。はじめは影響が限定的な範囲ではじめて、徐々に大胆に広げていきたいと思います。
事前準備
今回もfreee APIへのリクエストにはGAS x freeeAPIライブラリを使用します。こちらのライブラリの事前準備と使用にあたっての注意はこちらの記事をご確認ください。
事前準備を終えた上で、必要になってくるのは、いつもの通りアクセストークンと操作対象の事業所IDです。
事業所IDの取得方法は以下で紹介しています。
条件で指定した更新対象のfreee取引のみを配列で取得するサンプルコード
まずはコードの全体像です。今回は、
- reeeAPIライブラリの操作オブジェクトを取得する
- 前月初日からの取引に絞り込んで取得する
- 決済口座:BASE(ECサイト)・取引先:未選択 に該当する取引オブジェクトを抽出する
の3つのセクションまでを実装しています。
function renewBaseDeals01() {
/* GAS x freeeAPIライブラリの操作オブジェクトを取得する */
const accessToken = getService().getAccessToken(); // アクセストークンを取得
const company_id = Number(ScriptProperties.getProperty('COMPANY_ID')); // 事業所IDはプロパティストアに格納
const deals_freeeAPI = freeeAPI.deals(accessToken, company_id); // freeeAPIライブラリのdeals操作オブジェクトを作成
/* 前月初日からの取引に絞り込んで取得する */
const today = new Date(); // 今日のDateオブジェクト
const beginLastMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1); // 前月初日のDateオブジェクト
const start_issue_date = Utilities.formatDate(beginLastMonth, 'JST', 'yyyy-MM-dd'); // yyyy-MM-ddの文字列に変換
deals_freeeAPI.queries.start_issue_date = start_issue_date; // APIリクエストのパラメータの発生日に前月初日を代入
const allDeals = deals_freeeAPI.getAllDeals(); // 条件に合致する取引オブジェクトを全て取得する
/* 決済口座:BASE(ECサイト)・取引先:未選択 に該当するオブジェクトを抽出する */
const trgWalletableId = freeeAPI.walletables(accessToken, company_id).getIdByName('BASE(ECサイト)'); // 口座名から口座IDを取得
const trgDeals = allDeals.filter(deal => deal.partner_id === null && Array.isArray(deal.payments) && deal.payments.some(payment => payment.from_walletable_id === trgWalletableId));
console.log(trgDeals); // テストログ出力
}
更新対象の取引を絞り込む
簡単にECサイトを始められるBASE(ベイス)との連携を例に説明していきます。
以下の画像は、BASEから自動同期した取引の例です。freeeのタグは一切付与されていません。
まず前提として
- BASEの取引は「BASE(ECサイト)」という任意の名前の口座名で自動決済される
- 過去の取引には、取引先:BASE というタグが付与されている
- タグの付与は毎月行っている
として進めていきます。
上記の前提から、数ある取引から
- 決済口座:BASE(ECサイト)
- 取引先:未選択
- 発生日:前月初日以降
の取引のみをフィルタリングして取得できれば、個々の取引を更新することができます。
GAS x freeeAPIライブラリの操作オブジェクトを取得する
まずGAS x freeeAPIライブラリの操作オブジェクトを取得します。
const accessToken = getService().getAccessToken();
const company_id = Number(ScriptProperties.getProperty('COMPANY_ID'));
const deals_freeeAPI = freeeAPI.deals(accessToken, company_id);
- アクセストークンの取得
- プロパティストアに格納しておいてある事業所IDを取得
- freeeAPIライブラリのdeals操作オブジェクトを作成
を各行で行っています。
事業所IDをプロパティストアに格納する方法については以下の記事の「事業所IDをどう取得するか」のセクションを参考にしてください。
取得する取引の発生日を前月初日からに絞り込む
freeeAPIライブラリのdeals操作オブジェクトには、getAllDeals() – 指定した条件の全ての取引一覧を配列で取得するメソッドを用意しています。このメソッドを使って取引を取得するとデフォルトでは1年分の取引が取得されますが、今回の前提であれば前月初日からの取得で問題ありません。
前月初日のDateオブジェクトを取得したい
const today = new Date();
const beginLastMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1);
まず実行日を基準日に前月初日のDateオブジェクトを生成します。定数todayに今日のDateオブジェクトを代入し、月を-1・日付を1に設定して新たにDateオブジェクトを生成します。
このように
- 前月末日
- 当月末日
- 翌月末日
- 前月初日
- 当月初日
- 翌月初日
のような日付は会計操作をする上ではよく必要になってくるため、素早く生成できるようにクラス化しておくと便利です。
/**
* class CalDate
* カレンダーの色々な日付を生成するクラス
*
* プロパティ
* date - Dateオブジェクト
*
* メソッド
* lastSaturday() - 基準日の前回の土曜日のDateオブジェクトを返すメソッド
* nextSaturday() - 基準日の次回の土曜日のDateオブジェクトを返すメソッド
* endThisMonth() - 基準日月末日のDateオブジェクトを返すメソッド
* endNextMonth() - 基準日翌月末日のDateオブジェクトを返すメソッド
* endLastMonth() - 基準日前月末日のDateオブジェクトを返すメソッド
* beginThisMonth() - 基準日当月初日のDateオブジェクトを返すメソッド
* beginNextMonth() - 基準日翌月初日のDateオブジェクトを返すメソッド
* beginLastMonth() - 基準日前月初日のDateオブジェクトを返すメソッド
* aYearAgo() - 基準日と前年同日のDateオブジェクトを返すメソッド
* aWeekAgo() - 基準日の7日前のDateオブジェクトを返すメソッド
*
*/
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
class CalDate {
/**
* 基準日のDateオブジェクトを生成するコンストラクタ
* @constructor
* @params {Date} date デフォルトは実行日(今日)
*/
constructor(date = new Date()) {
this.date = new Date(date);
}
/**
* 基準日の前回の土曜日のDateオブジェクトを返すメソッド
* @return {Date} lastSaturday
*/
lastSaturday() {
const indexSat = 6
const indexToday = this.date.getDay();
if (indexToday === indexSat) { return new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate() - 7) };
if (indexToday < indexSat) {
const difference = indexSat - indexToday - 7;
return new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate() + difference);
};
}
/**
* 基準日の次回の土曜日のDateオブジェクトを返すメソッド
* @return {Date} nextSaturday
*/
nextSaturday() {
const indexSat = 6
const indexToday = this.date.getDay();
if (indexToday === indexSat) { return new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate() + 7) };
if (indexToday < indexSat) {
const difference = indexSat - indexToday;
return new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate() + difference);
};
}
/**
* 基準日月末日のDateオブジェクトを返すメソッド
* @return {Date} endThisMonth
*/
endThisMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0);
}
/**
* 基準日翌月末日のDateオブジェクトを返すメソッド
* @return {Date} endNextMonth
*/
endNextMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth() + 2, 0);
}
/**
* 基準日前月末日のDateオブジェクトを返すメソッド
* @return {Date} endLastMonth
*/
endLastMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth(), 0);
}
/**
* 基準日当月初日のDateオブジェクトを返すメソッド
* @return {Date} beginThisMonth
*/
beginThisMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth(), 1);
}
/**
* 基準日翌月初日のDateオブジェクトを返すメソッド
* @return {Date} beginNextMonth
*/
beginNextMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth() + 1, 1);
}
/**
* 基準日前月初日のDateオブジェクトを返すメソッド
* @return {Date} beginLastMonth
*/
beginLastMonth() {
return new Date(this.date.getFullYear(), this.date.getMonth() - 1, 1);
}
/**
* 基準日と前年同日のDateオブジェクトを返すメソッド
* @return {Date} aYearAgo
*/
aYearAgo() {
return new Date(this.date.getFullYear() - 1, this.date.getMonth(), this.date.getDate());
}
/**
* 基準日の7日前のDateオブジェクトを返すメソッド
* @return {Date} aWeekAgo
*/
aWeekAgo() {
return new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate() - 7);
}
}
Dateオブジェクトを文字列に変換してリクエストパラメータの発生日に指定する
前月初日が生成できたら、freee APIのリクエストに使えるように文字列に変換する必要があります。そして変換した前月初日を示す文字列をリクエストパラメータ(絞り込み条件)に代入します。
const start_issue_date = Utilities.formatDate(beginLastMonth,'JST', 'yyyy-MM-dd');
deals_freeeAPI.queries.start_issue_date = start_issue_date;
Dateオブジェクトの変換に関しては、以下の記事内の「DateオブジェクトをAPI POST用の文字列に変換する」のセクションをご参照ください。
reeeAPI.dealsで生成されたオブジェクトにはqueriesというプロパティを設定していて、会計リファレンスの各エンドポイントでパラメーター(≒ 絞り込み条件)として用意されているものは、このqueries以下のプロパティで指定できます。
getAllDeals() メソッドで取引を取得する
絞り込み条件を指定した後は、早速、getAllDeals()メソッドで取引を一括取得します。
const allDeals = deals_freeeAPI.getAllDeals();
console.log(allDeals); // 一度テストログ出力
一度テスト出力をしてみて、取引オブジェクトが取得されているか確認してみましょう。
無事ログ出力できました。
「決済口座:BASE(ECサイト)・取引先:未選択」に該当する取引IDの配列を作成する
前月からの取引は取得できたので、ここから「決済口座:BASE(ECサイト)・取引先:未選択」に該当する取引を取得します。
freee APIの操作の多くはは表示名でなくIDで指定する必要があるため、まずは絞り込み条件にしたい決済口座のIDを取得する必要があります。
const trgWalletableId = freeeAPI.walletables(accessToken, company_id).getIdByName('BASE(ECサイト)'); // 口座名から口座IDを取得
決済口座名 => 口座IDの変換をスムーズに行うためにreeeAPIライブラリのwalletables操作オブジェクトには、getIdByName(name) – 口座名からfreeeAPIのIDを取得するメソッドを準備しています。
これを使って口座IDを取得します。
続いて先程取得した取引オブジェクトを多数格納した配列であるallDealsに対して、条件に該当する要素だけから新たな配列を作成するためにfilter()メソッドを使用します。
const trgDeals = allDeals.filter(deal => deal.partner_id === null && Array.isArray(deal.payments) && deal.payments.some(payment => payment.from_walletable_id === trgWalletableId));
ワンライナーで書くにはやや長めのコードとなっていますが、3つの条件を同時に満たすかをテストしています。
- deal.partner_idがnullである=取引先:未選択
- deal.paymentsが配列である=何かしらの決済が登録されている
- deal.paymentsのいずれかの要素のfrom_walletable_idプロパティがfrom_walletable_idと一致する=決済口座:BASE(ECサイト)
の条件を満たす取引オブジェクトのみで新しく配列を生成し定数baseObjsに代入しています。
など配列に対して使用できる各メソッドはとても便利なので、ぜひ使いこなせるようになっておきたいですね。
シリーズ目次
- GAS x freeeAPIライブラリのトリセツ「自動同期で取得した取引に自動でタグを付与しよう」その1 – 条件で指定した更新対象のfreee取引のみ取得する
- GAS x freeeAPIライブラリのトリセツ「自動同期で取得した取引に自動でタグを付与しよう」その2 – 更新前に取引データをバックアップしよう
- GAS x freeeAPIライブラリのトリセツ「自動同期で取得した取引に自動でタグを付与しよう」その3 – 取引を加工してPUT(更新)しよう
Amazon欲しい物リスト公開しています。
開発者のモチベーションアップのためにAmazon欲しい物リストを公開しております。役に立ったよ!という方の感謝の気持ちで何かいただけるのであれば嬉しいです笑