forked from casdoor/casdoor
132 lines
4.4 KiB
Go
132 lines
4.4 KiB
Go
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package object
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/casdoor/casdoor/i18n"
|
|
)
|
|
|
|
func validateBalanceForTransaction(transaction *Transaction, amount float64, lang string) error {
|
|
currency := transaction.Currency
|
|
if currency == "" {
|
|
currency = "USD"
|
|
}
|
|
|
|
if transaction.Tag == "Organization" {
|
|
// Validate organization balance change
|
|
return validateOrganizationBalance("admin", transaction.Owner, amount, currency, true, lang)
|
|
} else if transaction.Tag == "User" {
|
|
// Validate user balance change
|
|
if transaction.User == "" {
|
|
return errors.New(i18n.Translate(lang, "general:User is required for User category transaction"))
|
|
}
|
|
if err := validateUserBalance(transaction.Owner, transaction.User, amount, currency, lang); err != nil {
|
|
return err
|
|
}
|
|
// Validate organization's user balance sum change
|
|
return validateOrganizationBalance("admin", transaction.Owner, amount, currency, false, lang)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateOrganizationBalance(owner string, name string, balance float64, currency string, isOrgBalance bool, lang string) error {
|
|
organization, err := getOrganization(owner, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if organization == nil {
|
|
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 newBalance float64
|
|
if isOrgBalance {
|
|
newBalance = AddPrices(organization.OrgBalance, convertedBalance)
|
|
// Check organization balance credit limit
|
|
if newBalance < organization.BalanceCredit {
|
|
return fmt.Errorf(i18n.Translate(lang, "general:Insufficient balance: new organization balance %v would be below credit limit %v"), newBalance, organization.BalanceCredit)
|
|
}
|
|
} else {
|
|
// User balance is just a sum of all users' balances, no credit limit check here
|
|
// Individual user credit limits are checked in validateUserBalance
|
|
newBalance = AddPrices(organization.UserBalance, convertedBalance)
|
|
}
|
|
|
|
// In validation mode, we don't actually update the balance
|
|
return nil
|
|
}
|
|
|
|
func validateUserBalance(owner string, name string, balance float64, currency string, lang string) error {
|
|
user, err := getUser(owner, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if user == nil {
|
|
return fmt.Errorf(i18n.Translate(lang, "general:The user: %s is not found"), fmt.Sprintf("%s/%s", owner, name))
|
|
}
|
|
|
|
// Convert the balance amount from transaction currency to user's balance currency
|
|
balanceCurrency := user.BalanceCurrency
|
|
var org *Organization
|
|
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)
|
|
|
|
// Calculate new balance
|
|
newBalance := AddPrices(user.Balance, convertedBalance)
|
|
|
|
// Check balance credit limit
|
|
// User.BalanceCredit takes precedence over Organization.BalanceCredit
|
|
var balanceCredit float64
|
|
if user.BalanceCredit != 0 {
|
|
balanceCredit = user.BalanceCredit
|
|
} else {
|
|
// Get organization's balance credit as fallback
|
|
if org == nil {
|
|
org, err = getOrganization("admin", owner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if org != nil {
|
|
balanceCredit = org.BalanceCredit
|
|
}
|
|
}
|
|
|
|
// Validate new balance against credit limit
|
|
if newBalance < balanceCredit {
|
|
return fmt.Errorf(i18n.Translate(lang, "general:Insufficient balance: new balance %v would be below credit limit %v"), newBalance, balanceCredit)
|
|
}
|
|
|
|
// In validation mode, we don't actually update the balance
|
|
return nil
|
|
}
|