feat: currency account add excahnge rate value and currency flag
This commit is contained in:
parent
512a6799c5
commit
89f287fe90
148
script/config.go
148
script/config.go
|
|
@ -6,12 +6,14 @@ import (
|
|||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var serverSecret string
|
||||
var serverConfig Config
|
||||
var serverCurrencies []LedgerCurrency
|
||||
var ledgerConfigMap map[string]Config
|
||||
var ledgerAccountsMap map[string][]Account
|
||||
var ledgerAccountTypesMap map[string]map[string]string
|
||||
|
|
@ -33,7 +35,10 @@ type Config struct {
|
|||
type Account struct {
|
||||
Acc string `json:"account"`
|
||||
StartDate string `json:"startDate"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
Currency string `json:"currency,omitempty"` // 货币
|
||||
CurrencySymbol string `json:"currencySymbol,omitempty"` // 货币符号
|
||||
ExRate string `json:"exRate,omitempty"` // 汇率
|
||||
ExDate string `json:"exDate,omitempty"` // 汇率日期
|
||||
Positions []AccountPosition `json:"positions,omitempty"`
|
||||
MarketNumber string `json:"marketNumber,omitempty"`
|
||||
MarketCurrency string `json:"marketCurrency,omitempty"`
|
||||
|
|
@ -57,6 +62,10 @@ type LedgerCurrency struct {
|
|||
Name string `json:"name"`
|
||||
Currency string `json:"currency"`
|
||||
Symbol string `json:"symbol"`
|
||||
IsCurrent bool `json:"isCurrent,omitempty"` // 是否是货币(非货币的为投资单位)
|
||||
Current bool `json:"current,omitempty"`
|
||||
ExRate string `json:"exRate,omitempty"`
|
||||
Date string `json:"date,omitempty"`
|
||||
}
|
||||
|
||||
func GetServerConfig() Config {
|
||||
|
|
@ -194,7 +203,7 @@ func GetAccountType(ledgerId string, acc string) AccountType {
|
|||
// 默认取最后一个节点
|
||||
Name: accNodes[len(accNodes)-1],
|
||||
}
|
||||
var matchKey string = ""
|
||||
var matchKey = ""
|
||||
for key, name := range accountTypes {
|
||||
if strings.Contains(acc, key) && len(matchKey) < len(key) {
|
||||
matchKey = key
|
||||
|
|
@ -386,14 +395,32 @@ func EqualServerSecret(secret string) bool {
|
|||
return serverSecret == secret
|
||||
}
|
||||
|
||||
func LoadServerCurrencyMap() {
|
||||
if serverCurrencies == nil {
|
||||
serverCurrencies = make([]LedgerCurrency, 0)
|
||||
}
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "人民币", Currency: "CNY", Symbol: "¥"})
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "美元", Currency: "USD", Symbol: "$"})
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "欧元", Currency: "EUR", Symbol: "€"})
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "日元", Currency: "JPY", Symbol: "¥"})
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "加拿大元", Currency: "CAD", Symbol: "$"})
|
||||
serverCurrencies = append(serverCurrencies, LedgerCurrency{Name: "俄罗斯卢布", Currency: "RUB", Symbol: "₽"})
|
||||
}
|
||||
|
||||
func LoadLedgerCurrencyMap(config Config) error {
|
||||
LoadServerCurrencyMap()
|
||||
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\"}]")
|
||||
|
||||
bytes, err := json.Marshal(serverCurrencies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = WriteFile(path, string(bytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -414,6 +441,8 @@ func LoadLedgerCurrencyMap(config Config) error {
|
|||
}
|
||||
ledgerCurrencyMap[config.Id] = currencies
|
||||
LogSystemInfo(fmt.Sprintf("Success load [%s] account type cache", config.Mail))
|
||||
// 刷新汇率
|
||||
RefreshLedgerCurrency(&config)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -421,28 +450,97 @@ func GetLedgerCurrency(ledgerId string) []LedgerCurrency {
|
|||
return ledgerCurrencyMap[ledgerId]
|
||||
}
|
||||
|
||||
func GetCommoditySymbol(commodity string) string {
|
||||
switch commodity {
|
||||
case "CNY":
|
||||
return "¥"
|
||||
case "USD":
|
||||
return "$"
|
||||
case "EUR":
|
||||
return "€"
|
||||
case "JPY":
|
||||
return "¥"
|
||||
case "GBP":
|
||||
return "£"
|
||||
case "AUD":
|
||||
return "$"
|
||||
case "CAD":
|
||||
return "$"
|
||||
case "INR":
|
||||
return "₹"
|
||||
case "RUB":
|
||||
return "₽"
|
||||
case "BRL":
|
||||
return "R$"
|
||||
type CommodityPrice struct {
|
||||
Date string `json:"date"`
|
||||
Commodity string `json:"commodity"`
|
||||
Currency string `json:"operatingCurrency"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func RefreshLedgerCurrency(ledgerConfig *Config) []LedgerCurrency {
|
||||
// 查询货币获取当前汇率
|
||||
output := BeanReportAllPrices(ledgerConfig)
|
||||
statsPricesResultList := make([]CommodityPrice, 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, CommodityPrice{
|
||||
Date: words[0],
|
||||
Commodity: words[2],
|
||||
Value: words[3],
|
||||
Currency: words[4],
|
||||
})
|
||||
}
|
||||
|
||||
// statsPricesResultList 转为 map
|
||||
existCurrencyMap := make(map[string]CommodityPrice)
|
||||
for _, statsPricesResult := range statsPricesResultList {
|
||||
existCurrencyMap[statsPricesResult.Commodity] = statsPricesResult
|
||||
}
|
||||
|
||||
result := make([]LedgerCurrency, 0)
|
||||
currencies := 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, LedgerCurrency{
|
||||
Name: c.Name,
|
||||
Currency: c.Currency,
|
||||
Symbol: c.Symbol,
|
||||
Current: current,
|
||||
ExRate: exRate,
|
||||
Date: date,
|
||||
})
|
||||
}
|
||||
// 刷新账本货币缓存
|
||||
ledgerCurrencyMap[ledgerConfig.Id] = result
|
||||
return result
|
||||
}
|
||||
|
||||
func GetLedgerCurrencyMap(ledgerId string) map[string]LedgerCurrency {
|
||||
currencyMap := make(map[string]LedgerCurrency)
|
||||
currencies := GetLedgerCurrency(ledgerId)
|
||||
if currencies == nil {
|
||||
return currencyMap
|
||||
}
|
||||
for _, currency := range currencies {
|
||||
currencyMap[currency.Currency] = currency
|
||||
}
|
||||
return currencyMap
|
||||
}
|
||||
|
||||
func GetCommoditySymbol(ledgerId string, commodity string) string {
|
||||
currencyMap := GetLedgerCurrencyMap(ledgerId)
|
||||
if currencyMap == nil {
|
||||
return commodity
|
||||
}
|
||||
if _, ok := currencyMap[commodity]; !ok {
|
||||
return commodity
|
||||
}
|
||||
return currencyMap[commodity].Symbol
|
||||
}
|
||||
|
||||
func GetServerCommoditySymbol(commodity string) string {
|
||||
for _, currency := range serverCurrencies {
|
||||
if currency.Currency == commodity {
|
||||
return currency.Symbol
|
||||
}
|
||||
}
|
||||
return commodity
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,21 @@ import (
|
|||
func QueryValidAccount(c *gin.Context) {
|
||||
ledgerConfig := script.GetLedgerConfigFromContext(c)
|
||||
allAccounts := script.GetLedgerAccounts(ledgerConfig.Id)
|
||||
currencyMap := script.GetLedgerCurrencyMap(ledgerConfig.Id)
|
||||
result := make([]script.Account, 0)
|
||||
for _, account := range allAccounts {
|
||||
if account.EndDate == "" {
|
||||
// 货币实时汇率(忽略账本主货币)
|
||||
if account.Currency != ledgerConfig.OperatingCurrency && account.Currency != "" {
|
||||
// 从 map 中获取对应货币的实时汇率和符号
|
||||
currency, ok := currencyMap[account.Currency]
|
||||
if ok {
|
||||
account.CurrencySymbol = currency.Symbol
|
||||
account.ExRate = currency.ExRate
|
||||
account.ExDate = currency.Date
|
||||
account.IsAnotherCurrency = true
|
||||
}
|
||||
}
|
||||
result = append(result, account)
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +57,7 @@ func QueryAllAccount(c *gin.Context) {
|
|||
accountPositionMap[ap.Account] = ap
|
||||
}
|
||||
|
||||
currencyMap := script.GetLedgerCurrencyMap(ledgerConfig.Id)
|
||||
accounts := script.GetLedgerAccounts(ledgerConfig.Id)
|
||||
result := make([]script.Account, 0, len(accounts))
|
||||
for i := 0; i < len(accounts); i++ {
|
||||
|
|
@ -53,6 +66,17 @@ func QueryAllAccount(c *gin.Context) {
|
|||
if account.EndDate != "" {
|
||||
continue
|
||||
}
|
||||
// 货币实时汇率(忽略账本主货币)
|
||||
if account.Currency != ledgerConfig.OperatingCurrency && account.Currency != "" {
|
||||
// 从 map 中获取对应货币的实时汇率和符号
|
||||
currency, ok := currencyMap[account.Currency]
|
||||
if ok {
|
||||
account.CurrencySymbol = currency.Symbol
|
||||
account.ExRate = currency.ExRate
|
||||
account.ExDate = currency.Date
|
||||
account.IsAnotherCurrency = true
|
||||
}
|
||||
}
|
||||
key := account.Acc
|
||||
typ := script.GetAccountType(ledgerConfig.Id, key)
|
||||
account.Type = &typ
|
||||
|
|
@ -61,18 +85,18 @@ func QueryAllAccount(c *gin.Context) {
|
|||
fields := strings.Fields(marketPosition)
|
||||
account.MarketNumber = fields[0]
|
||||
account.MarketCurrency = fields[1]
|
||||
account.MarketCurrencySymbol = script.GetCommoditySymbol(fields[1])
|
||||
account.MarketCurrencySymbol = script.GetCommoditySymbol(ledgerConfig.Id, fields[1])
|
||||
}
|
||||
position := strings.Trim(accountPositionMap[key].Position, " ")
|
||||
if position != "" {
|
||||
account.Positions = parseAccountPositions(position)
|
||||
account.Positions = parseAccountPositions(ledgerConfig.Id, position)
|
||||
}
|
||||
result = append(result, account)
|
||||
}
|
||||
OK(c, result)
|
||||
}
|
||||
|
||||
func parseAccountPositions(input string) []script.AccountPosition {
|
||||
func parseAccountPositions(ledgerId string, input string) []script.AccountPosition {
|
||||
// 使用正则表达式提取数字、货币代码和金额
|
||||
re := regexp.MustCompile(`(-?\d+\.\d+) (\w+)`)
|
||||
matches := re.FindAllStringSubmatch(input, -1)
|
||||
|
|
@ -85,7 +109,7 @@ func parseAccountPositions(input string) []script.AccountPosition {
|
|||
currency := match[2]
|
||||
|
||||
// 获取货币符号
|
||||
symbol := script.GetCommoditySymbol(currency)
|
||||
symbol := script.GetCommoditySymbol(ledgerId, currency)
|
||||
|
||||
// 创建 AccountPosition
|
||||
position := script.AccountPosition{
|
||||
|
|
@ -294,7 +318,7 @@ func BalanceAccount(c *gin.Context) {
|
|||
result["date"] = accountForm.Date
|
||||
result["marketNumber"] = accountForm.Number
|
||||
result["marketCurrency"] = ledgerConfig.OperatingCurrency
|
||||
result["marketCurrencySymbol"] = script.GetCommoditySymbol(ledgerConfig.OperatingCurrency)
|
||||
result["marketCurrencySymbol"] = script.GetCommoditySymbol(ledgerConfig.Id, ledgerConfig.OperatingCurrency)
|
||||
OK(c, result)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"github.com/beancount-gs/script"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SyncCommodityPriceForm struct {
|
||||
|
|
@ -30,70 +28,15 @@ func SyncCommodityPrice(c *gin.Context) {
|
|||
InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
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"`
|
||||
// 刷新货币最新汇率值
|
||||
script.RefreshLedgerCurrency(ledgerConfig)
|
||||
OK(c, syncCommodityPriceForm)
|
||||
}
|
||||
|
||||
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)
|
||||
currency := script.RefreshLedgerCurrency(ledgerConfig)
|
||||
OK(c, currency)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func ImportAliPayCSV(c *gin.Context) {
|
|||
result := make([]Transaction, 0)
|
||||
|
||||
currency := "CNY"
|
||||
currencySymbol := script.GetCommoditySymbol(currency)
|
||||
currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)
|
||||
|
||||
for {
|
||||
lines, err := reader.Read()
|
||||
|
|
@ -124,7 +124,7 @@ func ImportWxPayCSV(c *gin.Context) {
|
|||
result := make([]Transaction, 0)
|
||||
|
||||
currency := "CNY"
|
||||
currencySymbol := script.GetCommoditySymbol(currency)
|
||||
currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)
|
||||
|
||||
for {
|
||||
lines, err := reader.Read()
|
||||
|
|
@ -173,7 +173,7 @@ func ImportICBCCSV(c *gin.Context) {
|
|||
result := make([]Transaction, 0)
|
||||
|
||||
currency := "CNY"
|
||||
currencySymbol := script.GetCommoditySymbol(currency)
|
||||
currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)
|
||||
|
||||
id := 0
|
||||
for {
|
||||
|
|
@ -226,7 +226,7 @@ func ImportABCCSV(c *gin.Context) {
|
|||
result := make([]Transaction, 0)
|
||||
|
||||
currency := "CNY"
|
||||
currencySymbol := script.GetCommoditySymbol(currency)
|
||||
currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)
|
||||
|
||||
id := 0
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ func OpenOrCreateLedger(c *gin.Context) {
|
|||
resultMap["ledgerId"] = ledgerId
|
||||
resultMap["title"] = userLedger.Title
|
||||
resultMap["currency"] = userLedger.OperatingCurrency
|
||||
resultMap["currencySymbol"] = script.GetCommoditySymbol(userLedger.OperatingCurrency)
|
||||
resultMap["currencySymbol"] = script.GetServerCommoditySymbol(userLedger.OperatingCurrency)
|
||||
resultMap["createDate"] = userLedger.CreateDate
|
||||
OK(c, resultMap)
|
||||
return
|
||||
|
|
@ -176,7 +176,7 @@ func OpenOrCreateLedger(c *gin.Context) {
|
|||
resultMap["ledgerId"] = ledgerId
|
||||
resultMap["title"] = userLedger.Title
|
||||
resultMap["currency"] = userLedger.OperatingCurrency
|
||||
resultMap["currencySymbol"] = script.GetCommoditySymbol(userLedger.OperatingCurrency)
|
||||
resultMap["currencySymbol"] = script.GetCommoditySymbol(ledgerId, userLedger.OperatingCurrency)
|
||||
resultMap["createDate"] = userLedger.CreateDate
|
||||
OK(c, resultMap)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ func StatsMonthCalendar(c *gin.Context) {
|
|||
Account: queryRes.Account,
|
||||
Amount: json.Number(fields[0]),
|
||||
Currency: fields[1],
|
||||
CurrencySymbol: script.GetCommoditySymbol(fields[1]),
|
||||
CurrencySymbol: script.GetCommoditySymbol(ledgerConfig.Id, fields[1]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func QueryTransactions(c *gin.Context) {
|
|||
}
|
||||
// 格式化金额
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
symbol := script.GetCommoditySymbol(transactions[i].Currency)
|
||||
symbol := script.GetCommoditySymbol(ledgerConfig.Id, transactions[i].Currency)
|
||||
transactions[i].CurrencySymbol = symbol
|
||||
transactions[i].CostCurrencySymbol = symbol
|
||||
if transactions[i].Price != "" {
|
||||
|
|
|
|||
Loading…
Reference in New Issue