forked from casdoor/casdoor
feat: Add exchange rate conversion for balance calculations (#4534)
This commit is contained in:
@@ -589,7 +589,7 @@ func (org *Organization) GetInitScore() (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateOrganizationBalance(owner string, name string, balance float64, isOrgBalance bool, lang string) error {
|
||||
func UpdateOrganizationBalance(owner string, name string, balance float64, currency string, isOrgBalance bool, lang string) error {
|
||||
organization, err := getOrganization(owner, name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -598,12 +598,19 @@ func UpdateOrganizationBalance(owner string, name string, balance float64, isOrg
|
||||
return fmt.Errorf(i18n.Translate(lang, "auth:the organization: %s is not found"), fmt.Sprintf("%s/%s", owner, name))
|
||||
}
|
||||
|
||||
// Convert the balance amount from transaction currency to organization's balance currency
|
||||
balanceCurrency := organization.BalanceCurrency
|
||||
if balanceCurrency == "" {
|
||||
balanceCurrency = "USD"
|
||||
}
|
||||
convertedBalance := ConvertCurrency(balance, currency, balanceCurrency)
|
||||
|
||||
var columns []string
|
||||
if isOrgBalance {
|
||||
organization.OrgBalance = AddPrices(organization.OrgBalance, balance)
|
||||
organization.OrgBalance = AddPrices(organization.OrgBalance, convertedBalance)
|
||||
columns = []string{"org_balance"}
|
||||
} else {
|
||||
organization.UserBalance = AddPrices(organization.UserBalance, balance)
|
||||
organization.UserBalance = AddPrices(organization.UserBalance, convertedBalance)
|
||||
columns = []string{"user_balance"}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,11 @@ func notifyPayment(body []byte, owner string, paymentName string) (*Payment, *pp
|
||||
}
|
||||
|
||||
if payment.IsRecharge {
|
||||
err = UpdateUserBalance(payment.Owner, payment.User, payment.Price, "en")
|
||||
currency := payment.Currency
|
||||
if currency == "" {
|
||||
currency = "USD"
|
||||
}
|
||||
err = UpdateUserBalance(payment.Owner, payment.User, payment.Price, currency, "en")
|
||||
return payment, notifyResult, err
|
||||
}
|
||||
|
||||
|
||||
@@ -323,16 +323,36 @@ func BuyProduct(id string, user *User, providerName, pricingName, planName, host
|
||||
|
||||
if provider.Type == "Dummy" {
|
||||
payment.State = pp.PaymentStatePaid
|
||||
err = UpdateUserBalance(user.Owner, user.Name, payment.Price, "en")
|
||||
currency := payment.Currency
|
||||
if currency == "" {
|
||||
currency = "USD"
|
||||
}
|
||||
err = UpdateUserBalance(user.Owner, user.Name, payment.Price, currency, "en")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else if provider.Type == "Balance" {
|
||||
if product.Price > user.Balance {
|
||||
// Convert product price to user's balance currency for comparison
|
||||
productCurrency := product.Currency
|
||||
if productCurrency == "" {
|
||||
productCurrency = "USD"
|
||||
}
|
||||
userBalanceCurrency := user.BalanceCurrency
|
||||
if userBalanceCurrency == "" {
|
||||
// Get organization's balance currency as fallback
|
||||
org, err := getOrganization("admin", user.Owner)
|
||||
if err == nil && org != nil && org.BalanceCurrency != "" {
|
||||
userBalanceCurrency = org.BalanceCurrency
|
||||
} else {
|
||||
userBalanceCurrency = "USD"
|
||||
}
|
||||
}
|
||||
convertedPrice := ConvertCurrency(product.Price, productCurrency, userBalanceCurrency)
|
||||
if convertedPrice > user.Balance {
|
||||
return nil, nil, fmt.Errorf("insufficient user balance")
|
||||
}
|
||||
transaction.Amount = -transaction.Amount
|
||||
err = UpdateUserBalance(user.Owner, user.Name, -product.Price, "en")
|
||||
err = UpdateUserBalance(user.Owner, user.Name, -product.Price, productCurrency, "en")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -178,19 +178,24 @@ func (transaction *Transaction) GetId() string {
|
||||
}
|
||||
|
||||
func updateBalanceForTransaction(transaction *Transaction, amount float64, lang string) error {
|
||||
currency := transaction.Currency
|
||||
if currency == "" {
|
||||
currency = "USD"
|
||||
}
|
||||
|
||||
if transaction.Tag == "Organization" {
|
||||
// Update organization's own balance
|
||||
return UpdateOrganizationBalance("admin", transaction.Owner, amount, true, lang)
|
||||
return UpdateOrganizationBalance("admin", transaction.Owner, amount, currency, true, lang)
|
||||
} else if transaction.Tag == "User" {
|
||||
// Update user's balance
|
||||
if transaction.User == "" {
|
||||
return fmt.Errorf(i18n.Translate(lang, "general:User is required for User category transaction"))
|
||||
}
|
||||
if err := UpdateUserBalance(transaction.Owner, transaction.User, amount, lang); err != nil {
|
||||
if err := UpdateUserBalance(transaction.Owner, transaction.User, amount, currency, lang); err != nil {
|
||||
return err
|
||||
}
|
||||
// Update organization's user balance sum
|
||||
return UpdateOrganizationBalance("admin", transaction.Owner, amount, false, lang)
|
||||
return UpdateOrganizationBalance("admin", transaction.Owner, amount, currency, false, lang)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1479,7 +1479,7 @@ func GenerateIdForNewUser(application *Application) (string, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func UpdateUserBalance(owner string, name string, balance float64, lang string) error {
|
||||
func UpdateUserBalance(owner string, name string, balance float64, currency string, lang string) error {
|
||||
user, err := getUser(owner, name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1487,7 +1487,21 @@ func UpdateUserBalance(owner string, name string, balance float64, lang string)
|
||||
if user == nil {
|
||||
return fmt.Errorf(i18n.Translate(lang, "general:The user: %s is not found"), fmt.Sprintf("%s/%s", owner, name))
|
||||
}
|
||||
user.Balance = AddPrices(user.Balance, balance)
|
||||
|
||||
// Convert the balance amount from transaction currency to user's balance currency
|
||||
balanceCurrency := user.BalanceCurrency
|
||||
if balanceCurrency == "" {
|
||||
// Get organization's balance currency as fallback
|
||||
org, err := getOrganization("admin", owner)
|
||||
if err == nil && org != nil && org.BalanceCurrency != "" {
|
||||
balanceCurrency = org.BalanceCurrency
|
||||
} else {
|
||||
balanceCurrency = "USD"
|
||||
}
|
||||
}
|
||||
convertedBalance := ConvertCurrency(balance, currency, balanceCurrency)
|
||||
|
||||
user.Balance = AddPrices(user.Balance, convertedBalance)
|
||||
_, err = UpdateUser(user.GetId(), user, []string{"balance"}, true)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,72 @@ package object
|
||||
|
||||
import "math"
|
||||
|
||||
// Fixed exchange rates (temporary implementation as per requirements)
|
||||
// All rates represent how many units of the currency equal 1 USD
|
||||
// Example: EUR: 0.92 means 1 USD = 0.92 EUR
|
||||
var exchangeRates = map[string]float64{
|
||||
"USD": 1.0,
|
||||
"EUR": 0.92,
|
||||
"GBP": 0.79,
|
||||
"JPY": 149.50,
|
||||
"CNY": 7.24,
|
||||
"AUD": 1.52,
|
||||
"CAD": 1.39,
|
||||
"CHF": 0.88,
|
||||
"HKD": 7.82,
|
||||
"SGD": 1.34,
|
||||
"INR": 83.12,
|
||||
"KRW": 1319.50,
|
||||
"BRL": 4.97,
|
||||
"MXN": 17.09,
|
||||
"ZAR": 18.15,
|
||||
"RUB": 92.50,
|
||||
"TRY": 32.15,
|
||||
"NZD": 1.67,
|
||||
"SEK": 10.35,
|
||||
"NOK": 10.72,
|
||||
"DKK": 6.87,
|
||||
"PLN": 3.91,
|
||||
"THB": 34.50,
|
||||
"MYR": 4.47,
|
||||
"IDR": 15750.00,
|
||||
"PHP": 55.50,
|
||||
"VND": 24500.00,
|
||||
}
|
||||
|
||||
// GetExchangeRate returns the exchange rate from fromCurrency to toCurrency
|
||||
func GetExchangeRate(fromCurrency, toCurrency string) float64 {
|
||||
if fromCurrency == toCurrency {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// Default to USD if currency not found
|
||||
fromRate, fromExists := exchangeRates[fromCurrency]
|
||||
if !fromExists {
|
||||
fromRate = 1.0
|
||||
}
|
||||
|
||||
toRate, toExists := exchangeRates[toCurrency]
|
||||
if !toExists {
|
||||
toRate = 1.0
|
||||
}
|
||||
|
||||
// Convert from source currency to USD, then from USD to target currency
|
||||
// Example: EUR to JPY = (1/0.92) * 149.50 = USD/EUR * JPY/USD
|
||||
return toRate / fromRate
|
||||
}
|
||||
|
||||
// ConvertCurrency converts an amount from one currency to another using exchange rates
|
||||
func ConvertCurrency(amount float64, fromCurrency, toCurrency string) float64 {
|
||||
if fromCurrency == toCurrency {
|
||||
return amount
|
||||
}
|
||||
|
||||
rate := GetExchangeRate(fromCurrency, toCurrency)
|
||||
converted := amount * rate
|
||||
return math.Round(converted*1e8) / 1e8
|
||||
}
|
||||
|
||||
func AddPrices(price1 float64, price2 float64) float64 {
|
||||
res := price1 + price2
|
||||
return math.Round(res*1e8) / 1e8
|
||||
|
||||
Reference in New Issue
Block a user