blogs

Zaim APIとGoを用いて、ZaimのデータをCSV出力する

以前投稿した 「Zaim API と Go を用いて、Zaim のデータを CSV 出力する」 という記事の Go 版です。

https://zenn.dev/hidaka/articles/zaim-backup-python

目的

  • Zaim のデータを CSV に出力する仕組みを作る
  • バックアップデータは、Zaim のファイル出力機能で出力されるものと同じ内容にする(カラム名を揃える)

手順

API 登録・トークン取得

API 登録、トークン取得は以前の記事を参考にしてください。

コードを実装

Zaim のデータを取得・操作するパッケージを追加する

ターミナル
go get github.com/s-sasaki-0529/go-zaim

https://github.com/s-sasaki-0529/go-zaim

データを取得するコードを追加する

env ファイルに取得したトークン情報を記載する

.envファイルを作成し、取得したトークンを記載します。

.env
CONSUMER_KEY=
CONSUMER_SECRET=
ACCESS_TOKEN=
ACCESS_SECRET=

データを取得するコードを追加する

トークン情報を読み込むconfig.goとデータを取得するzaim.go、各処理を呼び出すmain.goを実装します。

config.go
package main

import (
	"fmt"
	"os"

	gozaim "github.com/s-sasaki-0529/go-zaim"

	"github.com/joho/godotenv"
)

func GetClient() *gozaim.Client {
	err := godotenv.Load(".env")

	if err != nil {
		fmt.Printf("読み込み出来ませんでした: %v", err)
	}

	c := gozaim.NewClient(
		os.Getenv("CONSUMER_KEY"),
		os.Getenv("CONSUMER_SECRET"),
		os.Getenv("ACCESS_TOKEN"),
		os.Getenv("ACCESS_SECRET"),
	)

	return c
}
zaim.go
package main

import (
	"fmt"
	"net/url"

	gozaim "github.com/s-sasaki-0529/go-zaim"
)

type ZaimData struct {
	money      []gozaim.Money
	categories []gozaim.Category
	genres     []gozaim.Genre
	accounts   []gozaim.Account
}

// Zaimのデータを取得する
func GetZaimData(c *gozaim.Client) ZaimData {

	// データ一覧の取得
	m, err := c.FetchMoney(url.Values{})
	if err != nil {
		fmt.Println("Failed to get money", err)
	}

	msg := fmt.Sprintf("%d 件のデータを取得しました。\n", len(m))
	fmt.Println(msg)

	// カテゴリ一覧取得
	ca, err := c.FetchCategories()
	if err != nil {
		fmt.Println("Failed to get categories", err)
	}

	// ジャンル一覧取得
	g, err := c.FetchGenres()
	if err != nil {
		fmt.Println("Failed to get genres", err)
	}

	// 口座一覧取得
	a, err := c.FetchAccounts()
	if err != nil {
		fmt.Println("Failed to get accounts", err)
	}

	result := ZaimData{
		m,
		ca,
		g,
		a,
	}

	return result
}
main.go
package main

import "fmt"

func main() {

	// クライアント設定
	c := GetClient()

	// データ取得
	d := GetZaimData(c)
	fmt.Println(d)

}

データが取得できましたが、カテゴリや口座等は ID しか記載されていません。
そのため、ID をもとに各種名称を付与する処理を実装します。

ID をもとに、名称を付与する

名称を付与する処理を追記します。

zaim.go
type MoneyJP struct {
	Date         string `csv:"日付"`
	Mode         string `csv:"方法"`
	Category     string `csv:"カテゴリ"`
	Genre        string `csv:"カテゴリの内訳"`
	From         string `csv:"支払元"`
	To           string `csv:"入金先"`
	Name         string `csv:"品目"`
	Comment      string `csv:"メモ"`
	Place        string `csv:"お店"`
	CurrencyCode string `csv:"通貨"`
	Income       int    `csv:"収入"`
	Payment      int    `csv:"支出"`
	Transfer     int    `csv:"振替"`
}

// 種別IDをもとに、種別名を付与する
func ConvertData(datas ZaimData) []MoneyJP {
	var money []MoneyJP

	for _, v := range datas.money {
		p, i, t := GetAmount(v.Mode, v.Amount)
		cm := MoneyJP{
			v.Date,
			v.Mode,
			GetCategoryName(v.CategoryID, datas.categories),
			GetGenreName(v.GenreID, datas.genres),
			GetAccountName(v.FromAccountID, datas.accounts),
			GetAccountName(v.ToAccountID, datas.accounts),
			v.Name,
			v.Comment,
			v.Place,
			v.CurrencyCode,
			p,
			i,
			t,
		}

		money = append(money, cm)

	}
	return money
}

// IDに紐づくカテゴリ名を返却
func GetCategoryName(id int, categories []gozaim.Category) string {
	for _, v := range categories {
		if v.ID == id {
			return v.Name
		}
	}
	return ""
}

// IDに紐づくジャンル名を返却
func GetGenreName(id int, genres []gozaim.Genre) string {
	for _, v := range genres {
		if v.ID == id {
			return v.Name
		}
	}
	return ""
}

// IDに紐づく口座名を返却
func GetAccountName(id int, accounts []gozaim.Account) string {
	for _, v := range accounts {
		if v.ID == id {
			return v.Name
		}
	}
	return "-"
}

// 方法に応じた額を返却
func GetAmount(mode string, amount int) (int, int, int) {
	var p, i, t int

	switch mode {
	case "payment":
		p = amount
	case "income":
		i = amount
	case "transfer":
		t = amount
	default:
	}

	return p, i, t

}
main.go
// 種別名を付与する
cd := ConvertData(d)
fmt.Println(cd)

続いてカラム名を日本語に変更し、CSV 出力する処理を実装します。

データを出力するコードを追加

カラム名を日本語に変更し、ユーザ ID など不要なデータを除去します。
続いて、整頓されたデータを CSV 出力します。

zaim.go
// CSV出力
func OutputCSV(money []MoneyJP) {
	file, _ := os.OpenFile("zaim-backup.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)
	defer file.Close()

	// csvファイルを書き出し
	gocsv.MarshalFile(&money, file)

}
main.go
// CSV出力する
OutputCSV(cd)

これでコードの実装は完了です。

実装したコードを実行する

ターミナルなどシェルスクリプトが実行できるアプリケーションで、下記コマンドを実行します。

ターミナル
% go run *.go

コンソールに取得件数が表示され、zaim-backup.csvというファイルが生成されます。

まとめ

今回実装したコードは下記リポジトリで公開しています。

https://github.com/ryohidaka/zaim-backup-go

参考文献

https://zenn.dev/a_ichi1/articles/c9f3870350c5e2

https://qiita.com/nkumag/items/ef372ea35dcfbfa19310

https://itsakura.com/go-switch