Zaim APIとGASで作る月次精算botと、”FamTech”について
我が家の家計は僕が取りまとめていて、新婚以来スプレッドシートを使ってほぼ手作業で管理してきました。
が、それもいい加減だるいぞ、ということに結婚8年目にして気づきまして。長年使っていたZaimを活用してこの辺を極力自動化できないかな、と重い腰を上げていろいろ考えてみたのが今日のお話になります。
ヒガシさんちの家計の考え方と手法
最初に、現状どんな感じにやっているかを説明します。
登場人物と役割分担
以下のように役割分担しています。妻は人の財布の中身にあまり興味を持たないタイプなので、金勘定は宿命的に僕の仕事です。お金は大事だよ。。
・家計の担い手① 兼 取りまとめ役 …夫(ぼく)
・家計の担い手②...(妻)
家計の考え方と手法
端的に説明すると「必要経費を収入比で按分した額を拠出し、口座にプールしておく」という感じになります。具体的な流れはこんな感じです。
我々夫婦は共働きで、二人ともサラリーマンです。月の最初におおよその必要経費(預金含む)を見積もって、収入比に応じてこれを按分します。一旦これを暫定妻負担分とします。
同時に、前月の見積もりとの差分を計算してこれもまた収入費で按分し、そして、前月に妻が建て替えた費用を上述の暫定妻負担分から相殺した額を求めます。この額を真の妻負担額とします。真の妻負担額が計上できたら、その金額を振り込んでもらうべく夫婦Slackに通知します。
※我が家は夫婦でSlackのワークスペースを持っていまして、そこでは予定を調整したり、買い物メモを残したり、レシピを共有したり、娘がbotとして跋扈していたりします。
支出のログはZaim(夫婦で共同のアカウントを運用)に残しており、買い物をしたらそれぞれが都度アプリやWebから計上します。そうやって日々の買い物記録を溜めて行ったのちに、毎月初毎にZaimのログから前月の生活費の実績を計算して、上記の真の妻負担額を計算します。(僕の負担額は当然ながら「必要経費総額-真の妻負担額」です)
で、真の妻負担額を僕の口座に振り込んでもらい、月々の支払いをしていきます。月々の必要経費とその費用計算は全てExcelに残しておき、根拠を求められた際にはスッと出せるようにしておきます。(が、運用開始以来開示請求はきていません。)
毎月の作業をできるだけ自動化したい
という感じのことを、結婚以来毎月やっておりました。仕組み自体は破綻がなく、家計は順調に回っています。しかし、育児の忙しさも相まって最近どうにも面倒になり、15日過ぎに支払いの足音に急かされてようやくモゾモゾと精算を始めることも増えてきました。
なんといっても、zaimから数字を抜いて計算するのがめんどくさい。だから、入力は最低限で、あとは自動化してよしなにやってくれる何かを開発したい意欲がむくむくと湧いてきたのでした。
必要なものはZaim APIとGAS、そしてSlack
Zaimには幸い、REST APIがありました。これを使って必要な数字をうまいことぶっこぬくことを画策しました。
APIの呼び出し元はGASです。GASにした理由は以下の3つです。
①:現在、金額を記録・集計しているスプレッドシートから起動したい
②:プログラムの権限管理を考える必要がない(自分だけが使えればいい)
③:サーバを用意する必要がない(これが一番大きい!)
雑にこの仕組みのシーケンス図を書くとこんな感じです。
Zaim APIとGASを使って、上述の真の妻負担額を算出してスプレッドシートに埋め込むのがこのプログラムのメイン部分です。(残りは算出額をSlackに流したり、OAuthの認証だったりという、手続き的なもの。)
具体的な実装方法
Zaimでの前準備
実装する前に、Zaim Developerにアプリケーションを登録して、APIを使う準備をしましょう。登録が完了すると、コンシューマIDとシークレットが振り出されます。
スプレッドシートの仕込み
Zaim側の準備が終わったら、こんな感じのスプレッドシートを用意します。「集計したい期間の初日と最終日の日付」と「収入額」、「予算」を記入します。金額の合計や按分のところは数式を埋め込んでおくと便利です。加えて、半角英数字オンリーとする入力規則をセルにかけておけば、数字をGASで扱う段での事故を防げます。(数字は仮ですよ!念のため!)
一見こういった入力もGASだけで自動化できちゃいそうに見えますが、結局なんらかの形でその月の収入額を入力しなきゃいけないので、スプレッドシートを最大限活かす方向で作り込みます(四則計算程度はスプレッドシート側でやります)。また、どうせ入力するので、入力したらスプレッドシートから処理を走らせるようにボタンも置いておきます。(「Go!」のやつ)
収入額を記入するので、ついでに月初と月末の日付も記入しちゃうことにしました。Zaim APIに日付をパラメータとして渡す際、「YYYY-MM-DD」形式にしないといけないので、このセルは文字列として入力します。
次に、その月の予算を入力していきます。これも前月のセルをコピーして云々自動化することもできるんですが、毎月の予算にはゆらぎが出がちなのであえて手入力です。ちなみに我が家ではここで預金額も計上しています。(貯めておくお金を最初に確保するのは、マネーリテラシーの基本です)
ここまで入力したら予め埋め込んだ数式から暫定妻負担分が出ます。ここでいよいよお楽しみのボタンポチーです。
ボタンをクリックするとGASのrun()が走るように仕込んでおきます。
GASのコード
ボタンから呼び出される処理のコードはこんな感じです。(本物のコードにはコメントで個人名や生々しいメモが書いてあったりするので、公開しているコードはところどころ改変してます。)最後まで走るとSlackに通知が飛びます。
var service = getService();
/**
* Authorizes and makes a request to the Zaim API.
*/
function run() {
if (service.hasAccess()) {
//スプレッドシート
var sheet = SpreadsheetApp.getActiveSheet();
//スプレッドシートの最終列+1
var input_column = sheet.getLastColumn();
//今月分の開始・終了日
var startDate = sheet.getRange(1,input_column).getValue();
var endDate = sheet.getRange(2,input_column).getValue();
//API投入用のパラメータ文字列
var dateParam = '&start_date='+ startDate + '&end_date=' + endDate + '&mode=payment';
/**
* カテゴリ番号の配列化
*/
//食料品
var grocery_cat_arr = ['101'];
//食料品と光熱費以外の生活費で、ヒガシ家が計上しているもの
var living_cat_arr = ['102','103','104','106','107','108','109','110','111','199'];
//光熱費
var util_cat_arr = ['105'];
//妻支出のジャンル番号
var wife_payment_arr = ['2512219'];
sheet.getRange(20,input_column).setValue(settlement(grocery_cat_arr,dateParam,true));
sheet.getRange(21,input_column).setValue(settlement(living_cat_arr,dateParam,true));
sheet.getRange(22,input_column).setValue(settlement(util_cat_arr,dateParam,true));
sheet.getRange(25,input_column).setValue(settlement(wife_payment_arr,dateParam,false));
slackInform(sheet.getRange(27,input_column).getValue());
} else {
var authorizationUrl = service.authorize();
Logger.log('次のURLを開いてZaimで認証したあと、再度スクリプトを実行してください。: %s',
authorizationUrl);
}
}
/**
* Zaim APIから支払いデータを取ってくる関数
* @param String dateparam
*/
function settlement(catArr,dateParam,cat_flag){
//そのセグメントの合計金額
var total = 0;
//ZaimAPIのURL
var url = 'https://api.zaim.net/v2/home/money?mapping=1';
//カテゴリかジャンルかの判別
if(cat_flag){
url = url + '&category_id=';
}else{
url = url + '&genre_id=';
}
catArr.forEach(function (catNum) {
//カテゴリごとに算出
var param = catNum + dateParam;
var urlp = url+param;
var response = service.fetch(urlp, {
method: 'get'
});
var result = JSON.parse(response.getContentText());
total += getTotalPay(result);
});
return total;
}
/**
* 合計金額を取得する関数
* @param JsonObject result
*/
function getTotalPay(result){
var sum = 0;
for(var i = 0; i< result.money.length; i++){
var num = result.money[i].amount;
sum += num;
}
return sum;
}
/**
* 合計金額をSlackに流す
* @param {*} amount
*/
function slackInform(amount){
amount = Math.round(amount);
//夫婦Slackの#generalに算出金額を送る
var slackToken = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
var slackApp = SlackApp.create(slackToken);
var channelId = '#general';
var message = '今月の精算: `¥'+amount+'` です!よろしくね!';
var response = slackApp.postMessage(channelId,message);
コードの全貌はこちら。これをそのまま使う方はあまりいないかと思いますが、ZaimAPIをGASで扱う参考材料としては割と使えると思うので、どうぞご自由に参照・改変ください。
また、僕はコーポレートITエンジニアで、コードをバリバリ書くタイプのエンジニアではない(書くは書くけどそれが本職ではない※)ので、クールな指摘や修正を優しくしてくれる方が現れたら泣いて喜びます。
※むしろ、最近は極力書かないのがイケてる感じ。しかし、書かないためには日頃からきちんと書き続けなければならないのがエンジニアリングのいけずなところ。
注意点(結構大事)
Zaimの仕様上、クレジットカード連携でZaimに渡された金額をAPIで取ることはできません。上述の方法で精算をする場合、全てアプリorWebから計上する必要があるので、ご注意を!(これは本当になんとかならないものか、と思う点)
追記:2021/03/01
課金すればクレジットカード連携の値も取得できるとのこと!
仕事で得た知識を"FamTech"として昇華しよう
こんな感じで作った仕組みを使って、ヒガシさんちでは毎月それなりに快適に経費精算と帳簿づけをやっています。こんな感じに"FamTech"を志向すれば、無味乾燥な家事も多少はクリエイティブに彩られたものになるんじゃないかな、と思っています。
ちなみに"FamTech"というのは、技術を使って家庭生活を快適にしようという試みを指す言葉で、さっき僕が作りました。流行らせるつもりは特にありません。「Family Tech」の略です。一応の補足です。
※大丈夫だとは思いますが、「Femtech」の文脈を謗る意図は一切ありません。あのワードこそが世にはばかって議論を喚起してほしいし、応援しています。一応の補足です。
少しだけ主語が大きい話をすると、この数年で社会は不可逆に変わると思っていて、特に「仕事とプライベートの距離」が激変すると思うんです。これまでは「ON/OFFをばっちり切り替えよう!」という価値観がありましたが、今後は「必要に応じてリモートワークを取り入れよう!」という流れになっていくと思います。※
※ただし大きな潮流であるからといって、それが必ずしもいいこととは考えていません。こちらの記事でも書きましたが、リモートワークは人を選びます。
結果的に、仕事とプライベートがヌルッとシームレスに切り替わるように意識がシフトしていくんじゃないかと。よく使われている言葉を使うと「ワークライフバランスからワークアズライフへ」という感じでしょうか。それを超えて「生活の一部としての仕事」の色彩がより強くなっていく気もしますが。
そんな状況では「私と仕事!どっちが大事なの!?」みたいな古典的な問いがあまり意味を為さなくなる一方、目に見える形でうまいことバランスしていく必要があると思うんです。特に家庭を持っている人間としては。
そんな状況で、に"FamTech"を使った家庭内カイゼンを回すことができれば、仕事で得られた知識の恩恵を家庭にもたらすこともできるし、普通に勉強になるから仕事にフィードバックすることもできるし、家庭生活も安全かつ便利になるからみんなハッピーだし、と、とてもいい感じで仕事と家庭のバランスを取れるようになるんじゃないかな、と思います。
プログラミングを仕事でしない人だって、"FamTech"は可能です。つまるところ、営業でもマーケでも人事労務経理総務その他職種は問わず、自分が仕事で培った知識や技術を家庭生活にフィットさせる形で活かすのは、結構クリエイティブな営みなんじゃないの?というのがここで言いたいことです。
おわりに
銀河系並みに肥大化した主語を自分に引き戻して強引に話をまとめると、我が家では上述のように家計処理をやっています。
GASを使うかどうかは置いといて「収入比で預金も含めた必要経費を按分してプールする手法」は割とぐうの音が出ない公平感があり、しかも自動的にお金も貯まっていく(重要!)ので、二馬力ではベストのやり方だと思っています。
もちろん取りまとめ役のモラルが破綻していないことが前提ですが、支出が全くコントロールできずお金も貯まらんという諸氏におかれましては、どうぞ真似していただいてOKです!
より長く走るための原資か、娘のおやつ代として使わせていただきます。