opti: multi currency appi
This commit is contained in:
parent
4ffe60112c
commit
512a6799c5
2
go.mod
2
go.mod
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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, ¤cies)
|
||||
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":
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue