opti: multi currency appi

This commit is contained in:
BaoXuebin 2023-12-07 01:24:24 +08:00
parent 4ffe60112c
commit 512a6799c5
8 changed files with 131 additions and 2 deletions

2
go.mod
View File

@ -5,6 +5,7 @@ go 1.17
require (
github.com/gin-gonic/gin v1.7.4
github.com/shopspring/decimal v1.3.1
golang.org/x/text v0.3.7
)
require (
@ -21,7 +22,6 @@ require (
github.com/ugorji/go/codec v1.2.6 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

View File

@ -105,7 +105,7 @@ func BQLQueryListByCustomSelect(ledgerConfig *Config, selectBql string, queryPar
}
func BeanReportAllPrices(ledgerConfig *Config) string {
beanFilePath := ledgerConfig.DataPath + "/index.bean"
beanFilePath := GetLedgerPriceFilePath(ledgerConfig.DataPath)
LogInfo(ledgerConfig.Mail, "bean-report "+beanFilePath+" all_prices")
cmd := exec.Command("bean-report", beanFilePath, "all_prices")

View File

@ -15,6 +15,7 @@ var serverConfig Config
var ledgerConfigMap map[string]Config
var ledgerAccountsMap map[string][]Account
var ledgerAccountTypesMap map[string]map[string]string
var ledgerCurrencyMap map[string][]LedgerCurrency
var whiteList []string
type Config struct {
@ -52,6 +53,12 @@ type AccountType struct {
Name string `json:"name"`
}
type LedgerCurrency struct {
Name string `json:"name"`
Currency string `json:"currency"`
Symbol string `json:"symbol"`
}
func GetServerConfig() Config {
return serverConfig
}
@ -253,6 +260,10 @@ func LoadLedgerAccountsMap() error {
if err != nil {
return err
}
err = LoadLedgerCurrencyMap(config)
if err != nil {
return err
}
}
return nil
}
@ -375,6 +386,41 @@ func EqualServerSecret(secret string) bool {
return serverSecret == secret
}
func LoadLedgerCurrencyMap(config Config) error {
path := GetLedgerCurrenciesFilePath(config.DataPath)
if !FileIfExist(path) {
err := CreateFile(path)
if err != nil {
return err
}
err = WriteFile(path, "[{\"name\":\"人民币\",\"symbol\":\"¥\",\"currency\":\"CNY\"},{\"name\":\"美元\",\"symbol\":\"$\",\"currency\":\"USD\"},{\"name\":\"欧元\",\"symbol\":\"€\",\"currency\":\"EUR\"},{\"name\":\"英镑\",\"symbol\":\"£\",\"currency\":\"GBP\"},{\"name\":\"日元\",\"symbol\":\"¥\",\"currency\":\"JPY\"},{\"name\":\"加拿大元\",\"symbol\":\"$\",\"currency\":\"CAD\"},{\"name\":\"澳大利亚元\",\"symbol\":\"$\",\"currency\":\"AUD\"},{\"name\":\"瑞士法郎\",\"symbol\":\"CHF\",\"currency\":\"CHF\"},{\"name\":\"俄罗斯卢布\",\"symbol\":\"₽\",\"currency\":\"RUB\"}]")
if err != nil {
return err
}
}
fileContent, err := ReadFile(path)
if err != nil {
return err
}
var currencies []LedgerCurrency
err = json.Unmarshal(fileContent, &currencies)
if err != nil {
LogSystemError("Failed unmarshal config file (" + path + ")")
return err
}
if ledgerCurrencyMap == nil {
ledgerCurrencyMap = make(map[string][]LedgerCurrency)
}
ledgerCurrencyMap[config.Id] = currencies
LogSystemInfo(fmt.Sprintf("Success load [%s] account type cache", config.Mail))
return nil
}
func GetLedgerCurrency(ledgerId string) []LedgerCurrency {
return ledgerCurrencyMap[ledgerId]
}
func GetCommoditySymbol(commodity string) string {
switch commodity {
case "CNY":

View File

@ -40,6 +40,10 @@ func GetLedgerAccountTypeFilePath(dataPath string) string {
return dataPath + "/.beancount-gs/account_type.json"
}
func GetLedgerCurrenciesFilePath(dataPath string) string {
return dataPath + "/.beancount-gs/currency.json"
}
func GetLedgerPriceFilePath(dataPath string) string {
return dataPath + "/price/prices.bean"
}

View File

@ -68,6 +68,7 @@ func RegisterRouter(router *gin.Engine) {
authorized.POST("/account/balance", service.BalanceAccount)
authorized.POST("/account/refresh", service.RefreshAccountCache)
authorized.POST("/commodity/price", service.SyncCommodityPrice)
authorized.GET("/commodity/currencies", service.QueryAllCurrencies)
authorized.GET("/stats/months", service.MonthsList)
authorized.GET("/stats/total", service.StatsTotal)
authorized.GET("/stats/payee", service.StatsPayee)

View File

@ -306,5 +306,11 @@ func RefreshAccountCache(c *gin.Context) {
InternalError(c, err.Error())
return
}
// 加载货币缓存
err = script.LoadLedgerCurrencyMap(*ledgerConfig)
if err != nil {
InternalError(c, err.Error())
return
}
OK(c, nil)
}

View File

@ -4,6 +4,8 @@ import (
"fmt"
"github.com/beancount-gs/script"
"github.com/gin-gonic/gin"
"strings"
"time"
)
type SyncCommodityPriceForm struct {
@ -30,3 +32,68 @@ func SyncCommodityPrice(c *gin.Context) {
}
OK(c, syncCommodityPriceForm)
}
type CommodityCurrency struct {
Name string `json:"name"`
Currency string `json:"currency"`
Symbol string `json:"symbol"`
Current bool `json:"current"`
ExRate string `json:"exRate"`
Date string `json:"date"`
}
func QueryAllCurrencies(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
// 查询货币获取当前汇率
output := script.BeanReportAllPrices(ledgerConfig)
statsPricesResultList := make([]StatsPricesResult, 0)
lines := strings.Split(output, "\n")
// foreach lines
for _, line := range lines {
if strings.Trim(line, " ") == "" {
continue
}
// split line by " "
words := strings.Fields(line)
statsPricesResultList = append(statsPricesResultList, StatsPricesResult{
Date: words[0],
Commodity: words[2],
Value: words[3],
Currency: words[4],
})
}
// statsPricesResultList 转为 map
existCurrencyMap := make(map[string]StatsPricesResult)
for _, statsPricesResult := range statsPricesResultList {
existCurrencyMap[statsPricesResult.Commodity] = statsPricesResult
}
result := make([]CommodityCurrency, 0)
currencies := script.GetLedgerCurrency(ledgerConfig.Id)
for _, c := range currencies {
current := c.Currency == ledgerConfig.OperatingCurrency
var exRate string
var date string
if current {
exRate = "1"
date = time.Now().Format("2006-01-02")
} else {
value, exists := existCurrencyMap[c.Currency]
if exists {
exRate = value.Value
date = value.Date
}
}
result = append(result, CommodityCurrency{
Name: c.Name,
Currency: c.Currency,
Symbol: c.Symbol,
Current: current,
ExRate: exRate,
Date: date,
})
}
OK(c, result)
}

View File

@ -272,6 +272,11 @@ func createNewLedger(loginForm LoginForm, ledgerId string) (*script.Config, erro
if err != nil {
return nil, err
}
// add currency cache
err = script.LoadLedgerCurrencyMap(ledgerConfig)
if err != nil {
return nil, err
}
return &ledgerConfig, nil
}