Skip to content

Commit

Permalink
feat: currency account add excahnge rate value and currency flag
Browse files Browse the repository at this point in the history
  • Loading branch information
BaoXuebin committed Dec 7, 2023
1 parent 512a679 commit 89f287f
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 103 deletions.
154 changes: 126 additions & 28 deletions script/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"`
Expand All @@ -54,9 +59,13 @@ type AccountType struct {
}

type LedgerCurrency struct {
Name string `json:"name"`
Currency string `json:"currency"`
Symbol string `json:"symbol"`
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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -414,35 +441,106 @@ func LoadLedgerCurrencyMap(config Config) error {
}
ledgerCurrencyMap[config.Id] = currencies
LogSystemInfo(fmt.Sprintf("Success load [%s] account type cache", config.Mail))
// 刷新汇率
RefreshLedgerCurrency(&config)
return nil
}

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
}
Expand Down
34 changes: 29 additions & 5 deletions service/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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++ {
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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{
Expand Down Expand Up @@ -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)
}

Expand Down
67 changes: 5 additions & 62 deletions service/commodity.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"
"github.com/beancount-gs/script"
"github.com/gin-gonic/gin"
"strings"
"time"
)

type SyncCommodityPriceForm struct {
Expand All @@ -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)
}
Loading

0 comments on commit 89f287f

Please sign in to comment.