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 (
|
require (
|
||||||
github.com/gin-gonic/gin v1.7.4
|
github.com/gin-gonic/gin v1.7.4
|
||||||
github.com/shopspring/decimal v1.3.1
|
github.com/shopspring/decimal v1.3.1
|
||||||
|
golang.org/x/text v0.3.7
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
@ -21,7 +22,6 @@ require (
|
||||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
|
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
|
||||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // 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
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // 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 {
|
func BeanReportAllPrices(ledgerConfig *Config) string {
|
||||||
beanFilePath := ledgerConfig.DataPath + "/index.bean"
|
beanFilePath := GetLedgerPriceFilePath(ledgerConfig.DataPath)
|
||||||
|
|
||||||
LogInfo(ledgerConfig.Mail, "bean-report "+beanFilePath+" all_prices")
|
LogInfo(ledgerConfig.Mail, "bean-report "+beanFilePath+" all_prices")
|
||||||
cmd := exec.Command("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 ledgerConfigMap map[string]Config
|
||||||
var ledgerAccountsMap map[string][]Account
|
var ledgerAccountsMap map[string][]Account
|
||||||
var ledgerAccountTypesMap map[string]map[string]string
|
var ledgerAccountTypesMap map[string]map[string]string
|
||||||
|
var ledgerCurrencyMap map[string][]LedgerCurrency
|
||||||
var whiteList []string
|
var whiteList []string
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
|
@ -52,6 +53,12 @@ type AccountType struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LedgerCurrency struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
}
|
||||||
|
|
||||||
func GetServerConfig() Config {
|
func GetServerConfig() Config {
|
||||||
return serverConfig
|
return serverConfig
|
||||||
}
|
}
|
||||||
|
|
@ -253,6 +260,10 @@ func LoadLedgerAccountsMap() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = LoadLedgerCurrencyMap(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -375,6 +386,41 @@ func EqualServerSecret(secret string) bool {
|
||||||
return serverSecret == secret
|
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 {
|
func GetCommoditySymbol(commodity string) string {
|
||||||
switch commodity {
|
switch commodity {
|
||||||
case "CNY":
|
case "CNY":
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ func GetLedgerAccountTypeFilePath(dataPath string) string {
|
||||||
return dataPath + "/.beancount-gs/account_type.json"
|
return dataPath + "/.beancount-gs/account_type.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLedgerCurrenciesFilePath(dataPath string) string {
|
||||||
|
return dataPath + "/.beancount-gs/currency.json"
|
||||||
|
}
|
||||||
|
|
||||||
func GetLedgerPriceFilePath(dataPath string) string {
|
func GetLedgerPriceFilePath(dataPath string) string {
|
||||||
return dataPath + "/price/prices.bean"
|
return dataPath + "/price/prices.bean"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ func RegisterRouter(router *gin.Engine) {
|
||||||
authorized.POST("/account/balance", service.BalanceAccount)
|
authorized.POST("/account/balance", service.BalanceAccount)
|
||||||
authorized.POST("/account/refresh", service.RefreshAccountCache)
|
authorized.POST("/account/refresh", service.RefreshAccountCache)
|
||||||
authorized.POST("/commodity/price", service.SyncCommodityPrice)
|
authorized.POST("/commodity/price", service.SyncCommodityPrice)
|
||||||
|
authorized.GET("/commodity/currencies", service.QueryAllCurrencies)
|
||||||
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/payee", service.StatsPayee)
|
authorized.GET("/stats/payee", service.StatsPayee)
|
||||||
|
|
|
||||||
|
|
@ -306,5 +306,11 @@ func RefreshAccountCache(c *gin.Context) {
|
||||||
InternalError(c, err.Error())
|
InternalError(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 加载货币缓存
|
||||||
|
err = script.LoadLedgerCurrencyMap(*ledgerConfig)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(c, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
OK(c, nil)
|
OK(c, nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/beancount-gs/script"
|
"github.com/beancount-gs/script"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncCommodityPriceForm struct {
|
type SyncCommodityPriceForm struct {
|
||||||
|
|
@ -30,3 +32,68 @@ func SyncCommodityPrice(c *gin.Context) {
|
||||||
}
|
}
|
||||||
OK(c, syncCommodityPriceForm)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// add currency cache
|
||||||
|
err = script.LoadLedgerCurrencyMap(ledgerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &ledgerConfig, nil
|
return &ledgerConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue