add stats api impl

This commit is contained in:
BaoXuebin 2021-11-24 23:45:45 +08:00
parent 16155985ac
commit 47c21de613
3 changed files with 110 additions and 9 deletions

View File

@ -16,7 +16,8 @@ type QueryParams struct {
Month int `bql:"month ="` Month int `bql:"month ="`
Tag string `bql:"in tags"` Tag string `bql:"in tags"`
Account string `bql:"account ="` Account string `bql:"account ="`
AccountType string `bql:"account ~"` AccountLike string `bql:"account ~"`
GroupBy string `bql:"group by"`
OrderBy string `bql:"order by"` OrderBy string `bql:"order by"`
Limit int `bql:"limit"` Limit int `bql:"limit"`
Path string Path string
@ -44,7 +45,7 @@ func GetQueryParams(c *gin.Context) QueryParams {
hasWhere = true hasWhere = true
} }
if c.Query("type") != "" { if c.Query("type") != "" {
queryParams.AccountType = c.Query("type") queryParams.AccountLike = c.Query("type")
hasWhere = true hasWhere = true
} }
if c.Query("account") != "" { if c.Query("account") != "" {
@ -138,7 +139,7 @@ func bqlRawQuery(ledgerConfig *Config, selectBql string, queryParamsPtr *QueryPa
case reflect.String: case reflect.String:
val := valueField.String() val := valueField.String()
if val != "" { if val != "" {
if typeField.Name == "OrderBy" { if typeField.Name == "OrderBy" || typeField.Name == "GroupBy" {
// 去除上一个条件后缀的 AND 关键字 // 去除上一个条件后缀的 AND 关键字
bql = strings.Trim(bql, " AND") bql = strings.Trim(bql, " AND")
bql = fmt.Sprintf("%s %s %s", bql, typeField.Tag.Get("bql"), val) bql = fmt.Sprintf("%s %s %s", bql, typeField.Tag.Get("bql"), val)

View File

@ -54,6 +54,8 @@ func RegisterRouter(router *gin.Engine) {
authorized.GET("/account/type", service.QueryAccountType) authorized.GET("/account/type", service.QueryAccountType)
authorized.GET("/stats/months", service.MonthsList) authorized.GET("/stats/months", service.MonthsList)
authorized.GET("/stats/total", service.StatsTotal) authorized.GET("/stats/total", service.StatsTotal)
authorized.GET("/stats/account/percent", service.StatsAccountPercent)
authorized.GET("/stats/account/trend", service.StatsAccountTrend)
authorized.GET("/transaction", service.QueryTransactions) authorized.GET("/transaction", service.QueryTransactions)
authorized.GET("/transaction/payee", service.QueryTransactionPayees) authorized.GET("/transaction/payee", service.QueryTransactionPayees)
authorized.GET("/transaction/template", service.QueryTransactionTemplates) authorized.GET("/transaction/template", service.QueryTransactionTemplates)

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/beancount-gs/script" "github.com/beancount-gs/script"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"strconv"
"strings" "strings"
) )
@ -27,16 +28,16 @@ func MonthsList(c *gin.Context) {
OK(c, months) OK(c, months)
} }
type statsAccountTypeTotal struct { type StatsResult struct {
AccountType string Key string
Amount string Value string
} }
func StatsTotal(c *gin.Context) { func StatsTotal(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c) ledgerConfig := script.GetLedgerConfigFromContext(c)
queryParams := script.GetQueryParams(c) queryParams := script.GetQueryParams(c)
selectBql := fmt.Sprintf("SELECT '\\', root(account, 1), '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency) selectBql := fmt.Sprintf("SELECT '\\', root(account, 1), '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency)
accountTypeTotalList := make([]statsAccountTypeTotal, 0) accountTypeTotalList := make([]StatsResult, 0)
err := script.BQLQueryListByCustomSelect(ledgerConfig, selectBql, &queryParams, &accountTypeTotalList) err := script.BQLQueryListByCustomSelect(ledgerConfig, selectBql, &queryParams, &accountTypeTotalList)
if err != nil { if err != nil {
InternalError(c, err.Error()) InternalError(c, err.Error())
@ -45,11 +46,108 @@ func StatsTotal(c *gin.Context) {
result := make(map[string]string, 0) result := make(map[string]string, 0)
for _, total := range accountTypeTotalList { for _, total := range accountTypeTotalList {
fields := strings.Fields(total.Amount) fields := strings.Fields(total.Value)
if len(fields) > 1 { if len(fields) > 1 {
result[total.AccountType] = fields[0] result[total.Key] = fields[0]
} }
} }
OK(c, result) OK(c, result)
} }
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)
}