diff --git a/script/config.go b/script/config.go index f783ca0..c965b19 100644 --- a/script/config.go +++ b/script/config.go @@ -30,14 +30,21 @@ type Config struct { } type Account struct { - Acc string `json:"account"` - StartDate string `json:"startDate"` - Currency string `json:"currency,omitempty"` - MarketNumber string `json:"marketNumber,omitempty"` - MarketCurrency string `json:"marketCurrency,omitempty"` - MarketCurrencySymbol string `json:"marketCurrencySymbol,omitempty"` - EndDate string `json:"endDate,omitempty"` - Type *AccountType `json:"type,omitempty"` + Acc string `json:"account"` + StartDate string `json:"startDate"` + Currency string `json:"currency,omitempty"` + Positions []AccountPosition `json:"positions,omitempty"` + MarketNumber string `json:"marketNumber,omitempty"` + MarketCurrency string `json:"marketCurrency,omitempty"` + MarketCurrencySymbol string `json:"marketCurrencySymbol,omitempty"` + EndDate string `json:"endDate,omitempty"` + Type *AccountType `json:"type,omitempty"` +} + +type AccountPosition struct { + Number string `json:"number,omitempty"` + Currency string `json:"currency,omitempty"` + CurrencySymbol string `json:"currencySymbol,omitempty"` } type AccountType struct { @@ -371,11 +378,27 @@ func EqualServerSecret(secret string) bool { func GetCommoditySymbol(commodity string) string { switch commodity { case "CNY": - return "¥" + 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$" } - return "" + return commodity } func GetAccountPrefix(account string) string { diff --git a/service/accounts.go b/service/accounts.go index a3c098b..a85f52f 100644 --- a/service/accounts.go +++ b/service/accounts.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/beancount-gs/script" "github.com/gin-gonic/gin" + "regexp" "sort" "strings" "time" @@ -23,14 +24,15 @@ func QueryValidAccount(c *gin.Context) { } type accountPosition struct { - Account string `json:"account"` - Position string `json:"position"` + Account string `json:"account"` + MarketPosition string `json:"market_position"` + Position string `json:"position"` } func QueryAllAccount(c *gin.Context) { ledgerConfig := script.GetLedgerConfigFromContext(c) - bql := fmt.Sprintf("select '\\', account, '\\', sum(convert(value(position), '%s')), '\\'", ledgerConfig.OperatingCurrency) + bql := fmt.Sprintf("select '\\', account, '\\', sum(convert(value(position), '%s')) as market_position, '\\', sum(value(position)) as position, '\\'", ledgerConfig.OperatingCurrency) accountPositions := make([]accountPosition, 0) err := script.BQLQueryListByCustomSelect(ledgerConfig, bql, nil, &accountPositions) if err != nil { @@ -54,18 +56,51 @@ func QueryAllAccount(c *gin.Context) { key := account.Acc typ := script.GetAccountType(ledgerConfig.Id, key) account.Type = &typ - position := strings.Trim(accountPositionMap[key].Position, " ") - if position != "" { - fields := strings.Fields(position) + marketPosition := strings.Trim(accountPositionMap[key].MarketPosition, " ") + if marketPosition != "" { + fields := strings.Fields(marketPosition) account.MarketNumber = fields[0] account.MarketCurrency = fields[1] account.MarketCurrencySymbol = script.GetCommoditySymbol(fields[1]) } + position := strings.Trim(accountPositionMap[key].Position, " ") + if position != "" { + account.Positions = parseAccountPositions(position) + } result = append(result, account) } OK(c, result) } +func parseAccountPositions(input string) []script.AccountPosition { + // 使用正则表达式提取数字、货币代码和金额 + re := regexp.MustCompile(`(-?\d+\.\d+) (\w+)`) + matches := re.FindAllStringSubmatch(input, -1) + + var positions []script.AccountPosition + + // 遍历匹配项并创建 AccountPosition + for _, match := range matches { + number := match[1] + currency := match[2] + + // 获取货币符号 + symbol := script.GetCommoditySymbol(currency) + + // 创建 AccountPosition + position := script.AccountPosition{ + Number: number, + Currency: currency, + CurrencySymbol: symbol, + } + + // 添加到切片中 + positions = append(positions, position) + } + + return positions +} + func QueryAccountType(c *gin.Context) { ledgerConfig := script.GetLedgerConfigFromContext(c) accountTypes := script.GetLedgerAccountTypes(ledgerConfig.Id) diff --git a/service/transactions.go b/service/transactions.go index 056a7a1..fa5c320 100644 --- a/service/transactions.go +++ b/service/transactions.go @@ -171,11 +171,16 @@ func saveTransaction(c *gin.Context, addTransactionForm AddTransactionForm, ledg } else { line += fmt.Sprintf("\r\n %s %s %s", entry.Account, entry.Number.Round(2).StringFixedBank(2), account.Currency) } + zero := decimal.NewFromInt(0) // 判断是否涉及多币种的转换 if account.Currency != ledgerConfig.OperatingCurrency && entry.Account != ledgerConfig.OpeningBalances { - autoBalance = true + autoBalance = false + // 汇率值小于等于0,则不进行汇率转换 + if entry.Price.LessThanOrEqual(zero) { + continue + } // 根据 number 的正负来判断是买入还是卖出 - if entry.Number.GreaterThan(decimal.NewFromInt(0)) { + if entry.Number.GreaterThan(zero) { // {351.729 CNY, 2021-09-29} line += fmt.Sprintf(" {%s %s, %s}", entry.Price, ledgerConfig.OperatingCurrency, addTransactionForm.Date) } else {