beancount-gs/service/stats.go

233 lines
7.4 KiB
Go
Raw Normal View History

2021-11-19 09:54:02 +00:00
package service
import (
2021-11-22 14:50:10 +00:00
"fmt"
2021-11-19 09:54:02 +00:00
"github.com/beancount-gs/script"
"github.com/gin-gonic/gin"
2021-11-24 15:45:45 +00:00
"strconv"
2021-11-22 14:50:10 +00:00
"strings"
2021-11-19 09:54:02 +00:00
)
2021-11-22 08:47:49 +00:00
type YearMonth struct {
Year string `bql:"distinct year(date)" json:"year"`
Month string `bql:"month(date)" json:"month"`
}
2021-11-19 09:54:02 +00:00
2021-11-22 08:47:49 +00:00
func MonthsList(c *gin.Context) {
2021-11-21 14:37:13 +00:00
ledgerConfig := script.GetLedgerConfigFromContext(c)
2021-11-22 08:47:49 +00:00
yearMonthList := make([]YearMonth, 0)
err := script.BQLQueryList(ledgerConfig, nil, &yearMonthList)
2021-11-19 09:54:02 +00:00
if err != nil {
2021-11-22 08:47:49 +00:00
InternalError(c, err.Error())
2021-11-19 09:54:02 +00:00
return
}
2021-11-22 08:47:49 +00:00
months := make([]string, 0)
for _, yearMonth := range yearMonthList {
months = append(months, yearMonth.Year+"-"+yearMonth.Month)
2021-11-21 14:37:13 +00:00
}
OK(c, months)
2021-11-19 09:54:02 +00:00
}
2021-11-22 14:50:10 +00:00
2021-11-24 15:45:45 +00:00
type StatsResult struct {
Key string
Value string
2021-11-22 14:50:10 +00:00
}
func StatsTotal(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
queryParams := script.GetQueryParams(c)
selectBql := fmt.Sprintf("SELECT '\\', root(account, 1), '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency)
2021-11-24 15:45:45 +00:00
accountTypeTotalList := make([]StatsResult, 0)
2021-11-22 14:50:10 +00:00
err := script.BQLQueryListByCustomSelect(ledgerConfig, selectBql, &queryParams, &accountTypeTotalList)
if err != nil {
InternalError(c, err.Error())
return
}
result := make(map[string]string, 0)
for _, total := range accountTypeTotalList {
2021-11-24 15:45:45 +00:00
fields := strings.Fields(total.Value)
2021-11-22 14:50:10 +00:00
if len(fields) > 1 {
2021-11-24 15:45:45 +00:00
result[total.Key] = fields[0]
2021-11-22 14:50:10 +00:00
}
}
OK(c, result)
}
2021-11-24 15:45:45 +00:00
type StatsQuery struct {
Prefix string `form:"prefix" binding:"required"`
Year int `form:"year"`
Month int `form:"month"`
Level int `form:"level"`
Type string `form:"type"`
}
type AccountPercentResult struct {
Account string `json:"account"`
Amount string `json:"amount"`
OperatingCurrency string `json:"operatingCurrency"`
}
func StatsAccountPercent(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
var statsQuery StatsQuery
if err := c.ShouldBindQuery(&statsQuery); err != nil {
BadRequest(c, err.Error())
return
}
queryParams := script.QueryParams{
AccountLike: statsQuery.Prefix,
Year: statsQuery.Year,
Month: statsQuery.Month,
Where: true,
}
var bql string
if statsQuery.Level != 0 {
prefixNodeLen := len(strings.Split(strings.Trim(statsQuery.Prefix, ":"), ":"))
bql = fmt.Sprintf("SELECT '\\', root(account, %d) as subAccount, '\\', sum(convert(value(position), '%s')), '\\'", statsQuery.Level+prefixNodeLen, ledgerConfig.OperatingCurrency)
} else {
bql = fmt.Sprintf("SELECT '\\', account, '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency)
}
statsResultList := make([]AccountPercentResult, 0)
err := script.BQLQueryListByCustomSelect(ledgerConfig, bql, &queryParams, &statsResultList)
if err != nil {
InternalError(c, err.Error())
return
}
for idx, result := range statsResultList {
fields := strings.Fields(result.Amount)
statsResultList[idx].Amount = fields[0]
statsResultList[idx].OperatingCurrency = fields[1]
}
OK(c, statsResultList)
}
type AccountTrendResult struct {
Date string `json:"date"`
Amount float64 `json:"amount"`
OperatingCurrency string `json:"operatingCurrency"`
}
func StatsAccountTrend(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
var statsQuery StatsQuery
if err := c.ShouldBindQuery(&statsQuery); err != nil {
BadRequest(c, err.Error())
return
}
queryParams := script.QueryParams{
AccountLike: statsQuery.Prefix,
Year: statsQuery.Year,
Month: statsQuery.Month,
Where: true,
}
var bql string
if statsQuery.Type == "avg" {
bql = fmt.Sprintf("SELECT '\\', date, '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency)
} else if statsQuery.Type == "sum" {
bql = fmt.Sprintf("SELECT '\\', date, '\\', convert(balance, '%s'), '\\'", ledgerConfig.OperatingCurrency)
} else {
OK(c, new([]string))
return
}
statsResultList := make([]StatsResult, 0)
err := script.BQLQueryListByCustomSelect(ledgerConfig, bql, &queryParams, &statsResultList)
if err != nil {
InternalError(c, err.Error())
return
}
result := make([]AccountTrendResult, 0)
for _, stats := range statsResultList {
fields := strings.Fields(stats.Value)
amount, _ := strconv.ParseFloat(fields[0], 32)
result = append(result, AccountTrendResult{Date: stats.Key, Amount: amount, OperatingCurrency: fields[1]})
}
OK(c, result)
}
2021-11-25 07:41:28 +00:00
type MonthTotalBQLResult struct {
Year int
Month int
Value string
}
type MonthTotal struct {
Type string `json:"type"`
Month string `json:"month"`
Amount float64 `json:"amount"`
OperatingCurrency string `json:"operatingCurrency"`
}
func StatsMonthTotal(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
monthSet := make(map[string]bool)
queryParams := script.QueryParams{
AccountLike: "Income",
Where: true,
OrderBy: "year, month",
}
// 按月查询收入
queryIncomeBql := fmt.Sprintf("select '\\', year, '\\', month, '\\', neg(sum(convert(value(position), '%s'))), '\\'", ledgerConfig.OperatingCurrency)
monthIncomeTotalResultList := make([]MonthTotalBQLResult, 0)
err := script.BQLQueryListByCustomSelect(ledgerConfig, queryIncomeBql, &queryParams, &monthIncomeTotalResultList)
if err != nil {
InternalError(c, err.Error())
return
}
monthIncomeMap := make(map[string]MonthTotalBQLResult)
for _, income := range monthIncomeTotalResultList {
month := fmt.Sprintf("%d-%d", income.Year, income.Month)
monthSet[month] = true
monthIncomeMap[month] = income
}
// 按月查询支出
queryParams.AccountLike = "Expenses"
queryExpensesBql := fmt.Sprintf("select '\\', year, '\\', month, '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency)
monthExpensesTotalResultList := make([]MonthTotalBQLResult, 0)
err = script.BQLQueryListByCustomSelect(ledgerConfig, queryExpensesBql, &queryParams, &monthExpensesTotalResultList)
if err != nil {
InternalError(c, err.Error())
return
}
monthExpensesMap := make(map[string]MonthTotalBQLResult)
for _, expenses := range monthExpensesTotalResultList {
month := fmt.Sprintf("%d-%d", expenses.Year, expenses.Month)
monthSet[month] = true
monthExpensesMap[month] = expenses
}
monthTotalResult := make([]MonthTotal, 0)
// 合并结果
var monthIncome, monthExpenses MonthTotal
for month := range monthSet {
if monthIncomeMap[month].Value != "" {
fields := strings.Fields(monthIncomeMap[month].Value)
amount, _ := strconv.ParseFloat(fields[0], 64)
monthIncome = MonthTotal{Type: "收入", Month: month, Amount: amount, OperatingCurrency: fields[1]}
} else {
monthIncome = MonthTotal{Type: "收入", Month: month, Amount: 0, OperatingCurrency: ledgerConfig.OperatingCurrency}
}
monthTotalResult = append(monthTotalResult, monthIncome)
if monthExpensesMap[month].Value != "" {
fields := strings.Fields(monthExpensesMap[month].Value)
amount, _ := strconv.ParseFloat(fields[0], 64)
monthExpenses = MonthTotal{Type: "支出", Month: month, Amount: amount, OperatingCurrency: fields[1]}
} else {
monthExpenses = MonthTotal{Type: "支出", Month: month, Amount: 0, OperatingCurrency: ledgerConfig.OperatingCurrency}
}
monthTotalResult = append(monthTotalResult, monthExpenses)
monthTotalResult = append(monthTotalResult, MonthTotal{Type: "结余", Month: month, Amount: monthIncome.Amount - monthExpenses.Amount, OperatingCurrency: ledgerConfig.OperatingCurrency})
}
OK(c, monthTotalResult)
}