Files
cgrates/accounts/apis_test.go
2025-10-19 13:15:57 +02:00

1035 lines
28 KiB
Go

/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
*/
package accounts
import (
"reflect"
"testing"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func TestAccountsRefundCharges(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
acc := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
var reply string
args := &utils.APIEventCharges{
Tenant: "cgrates.org",
EventCharges: &utils.EventCharges{
Abstracts: nil,
},
}
if err := acc.V1RefundCharges(context.Background(), args, &reply); err != nil {
t.Error(err)
}
if reply != utils.OK {
t.Errorf("Expected %v\n but received %v", utils.OK, reply)
}
}
func TestAccountsActionRemoveBalance(t *testing.T) {
engine.Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: data}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, nil)
fltr := engine.NewFilterS(cfg, nil, dm)
accnts := NewAccountS(cfg, fltr, nil, dm)
argsSet := &utils.ArgsActSetBalance{
AccountID: "TestV1ActionRemoveBalance",
Tenant: "cgrates.org",
Diktats: []*utils.BalDiktat{
{
Path: "*balance.AbstractBalance1.Units",
Value: "10",
},
},
Reset: false,
}
var reply string
if err := accnts.V1ActionSetBalance(context.Background(), argsSet, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error("Unexpected status reply", reply)
}
//remove it
args := &utils.ArgsActRemoveBalances{}
expected := "MANDATORY_IE_MISSING: [AccountID]"
if err := accnts.V1ActionRemoveBalance(context.Background(), args, &reply); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
args.AccountID = "TestV1ActionRemoveBalance"
expected = "MANDATORY_IE_MISSING: [BalanceIDs]"
if err := accnts.V1ActionRemoveBalance(context.Background(), args, &reply); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
args.BalanceIDs = []string{"AbstractBalance1"}
if err := accnts.V1ActionRemoveBalance(context.Background(), args, &reply); err != nil {
t.Errorf("Expected %+v, received %+v", nil, err)
}
}
func TestAccountsDebitConcretes(t *testing.T) {
engine.Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: data}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, nil)
fltr := engine.NewFilterS(cfg, nil, dm)
accnts := NewAccountS(cfg, fltr, nil, dm)
if err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "TestV1DebitAbstracts",
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 15,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance1": {
ID: "ConcreteBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(time.Minute), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 5,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(30*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
}, true); err != nil {
t.Error(err)
}
ev := &utils.CGREvent{
ID: "TestV1DebitID",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1004",
utils.Usage: "3m",
},
}
reply := utils.EventCharges{}
if err := accnts.V1DebitConcretes(context.Background(), ev, &reply); err != nil {
t.Errorf("Expected %+v, received %+v", nil, err)
}
}
func TestAccountsMaxConcretes(t *testing.T) {
engine.Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: data}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, nil)
fltr := engine.NewFilterS(cfg, nil, dm)
accnts := NewAccountS(cfg, fltr, nil, dm)
if err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "TestV1DebitAbstracts",
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 15,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance1": {
ID: "ConcreteBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(time.Minute), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 5,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(30*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
}, true); err != nil {
t.Error(err)
}
ev := &utils.CGREvent{
ID: "TestV1DebitID",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1004",
},
APIOpts: map[string]any{
utils.MetaUsage: "3m",
},
}
reply := utils.EventCharges{}
exEvCh := utils.EventCharges{
Concretes: utils.NewDecimal(int64(time.Minute+30*time.Second), 0),
Charges: []*utils.ChargeEntry{
{
ChargingID: "GENUUID1",
CompressFactor: 1,
},
{
ChargingID: "GENUUID2",
CompressFactor: 1,
},
},
Accounting: map[string]*utils.AccountCharge{
"GENUUID1": {
AccountID: "TestV1DebitAbstracts",
BalanceID: "ConcreteBalance1",
Units: utils.NewDecimal(int64(time.Minute), 0),
BalanceLimit: utils.NewDecimal(0, 0),
},
"GENUUID2": {
AccountID: "TestV1DebitAbstracts",
BalanceID: "ConcreteBalance2",
Units: utils.NewDecimal(int64(30*time.Second), 0),
BalanceLimit: utils.NewDecimal(0, 0),
},
},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"TestV1DebitAbstracts": {
Tenant: "cgrates.org",
ID: "TestV1DebitAbstracts",
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Type: utils.MetaAbstract,
Weights: []*utils.DynamicWeight{
{
Weight: 15,
},
},
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance1": {
ID: "ConcreteBalance1",
Weights: []*utils.DynamicWeight{
{
Weight: 25,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(0, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: []*utils.DynamicWeight{
{
Weight: 5,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(0, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
},
},
}
if err := accnts.V1MaxConcretes(context.Background(), ev, &reply); err != nil {
t.Error(err)
} else {
if !exEvCh.Equals(&reply) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply))
}
}
// check the account was not debited
extAccPrf := &utils.Account{
Tenant: "cgrates.org",
ID: "TestV1DebitAbstracts",
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Type: utils.MetaAbstract,
Weights: utils.DynamicWeights{
{
Weight: 15,
},
},
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance1": {
ID: "ConcreteBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(time.Minute), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 5,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(int64(30*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
}
if rplyAcc, err := dm.GetAccount(context.Background(), "cgrates.org", "TestV1DebitAbstracts"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rplyAcc, extAccPrf) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(extAccPrf), utils.ToJSON(rplyAcc))
}
}
func TestAccountsActionSetBalance(t *testing.T) {
cacheInit := engine.Cache
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
cfg.AccountSCfg().RateSConns = []string{"*internal"}
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
newCache := engine.NewCacheS(cfg, dm, connMgr, nil)
engine.Cache = newCache
if err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "test_ID1",
Opts: map[string]any{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 1),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
}, true); err != nil {
t.Errorf("expected <%+v>,\nreceived <%+v>", nil, err)
}
accS := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
var rpEv utils.EventCharges
ev := &utils.CGREvent{
ID: "TestMatchingAccountsForEvent",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1001",
},
APIOpts: map[string]any{},
}
if err := accS.V1DebitAbstracts(context.Background(), ev, &rpEv); err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
expRating := &utils.RateSInterval{
IntervalStart: nil,
Increments: []*utils.RateSIncrement{
{
RateIntervalIndex: 0,
RateID: "id_for_test",
CompressFactor: 1,
},
},
CompressFactor: 1,
}
for _, val := range rpEv.Rating {
val.Increments[0].RateID = "id_for_test"
if !reflect.DeepEqual(val, expRating) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expRating, val)
}
}
rpEv.Rating = map[string]*utils.RateSInterval{}
expEvAcc := &utils.EventCharges{
Abstracts: utils.NewDecimal(0, 0),
Accounting: map[string]*utils.AccountCharge{},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"test_ID1": {
Tenant: "cgrates.org",
ID: "test_ID1",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 1),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Opts: map[string]any{},
},
},
}
eql := rpEv.Equals(expEvAcc)
if eql != true {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", true, eql)
}
engine.Cache = cacheInit
}
func TestAccountsDebitAbstracts(t *testing.T) {
cacheInit := engine.Cache
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
cfg.AccountSCfg().RateSConns = []string{"*internal"}
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
newCache := engine.NewCacheS(cfg, dm, connMgr, nil)
accS := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
engine.Cache = newCache
err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "test_ID1",
Opts: map[string]any{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 0),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
}, true)
if err != nil {
t.Fatal(err)
}
var rpEv utils.EventCharges
ev := &utils.CGREvent{
ID: "TestMatchingAccountsForEvent",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1001",
},
APIOpts: map[string]any{},
}
err = accS.V1DebitAbstracts(context.Background(), ev, &rpEv)
if err != nil {
t.Error(err)
}
expRating := &utils.RateSInterval{
Increments: []*utils.RateSIncrement{
{
RateIntervalIndex: 0,
RateID: "id_for_test",
CompressFactor: 1,
},
},
CompressFactor: 1,
}
for _, val := range rpEv.Rating {
val.Increments[0].RateID = "id_for_test"
if !reflect.DeepEqual(val, expRating) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expRating), utils.ToJSON(val))
}
}
rpEv.Rating = map[string]*utils.RateSInterval{}
expEvAcc := &utils.EventCharges{
Abstracts: utils.NewDecimal(0, 0),
Accounting: map[string]*utils.AccountCharge{},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"test_ID1": {
Tenant: "cgrates.org",
ID: "test_ID1",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 0),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Opts: map[string]any{},
},
},
}
eql := rpEv.Equals(expEvAcc)
if eql != true {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", true, eql)
}
engine.Cache = cacheInit
}
func TestAccountsMaxAbstracts(t *testing.T) {
cacheInit := engine.Cache
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
cfg.AccountSCfg().RateSConns = []string{"*internal"}
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
newCache := engine.NewCacheS(cfg, dm, connMgr, nil)
engine.Cache = newCache
err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "test_ID1",
Opts: map[string]any{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 1),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
}, true)
if err != nil {
t.Fatal(err)
}
cfg.AccountSCfg().RateSConns = []string{"*internal"}
accS := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
var rpEv utils.EventCharges
ev := &utils.CGREvent{
ID: "TestMatchingAccountsForEvent",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1001",
},
APIOpts: map[string]any{},
}
err = accS.V1MaxAbstracts(context.Background(), ev, &rpEv)
if err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
expRating := &utils.RateSInterval{
IntervalStart: nil,
Increments: []*utils.RateSIncrement{
{
IncrementStart: nil,
RateIntervalIndex: 0,
RateID: "id_for_Test",
CompressFactor: 1,
Usage: nil,
},
},
CompressFactor: 1,
}
for _, val := range rpEv.Rating {
val.Increments[0].RateID = "id_for_Test"
if !reflect.DeepEqual(expRating, val) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expRating), utils.ToJSON(val))
}
}
rpEv.Rating = map[string]*utils.RateSInterval{}
expEvAcc := &utils.EventCharges{
Abstracts: utils.NewDecimal(0, 0),
Accounting: map[string]*utils.AccountCharge{},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"test_ID1": {
Tenant: "cgrates.org",
ID: "test_ID1",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
CostIncrements: []*utils.CostIncrement{
{
RecurrentFee: utils.NewDecimal(1, 1),
Increment: utils.NewDecimal(1, 1),
},
},
Units: utils.NewDecimal(0, 0),
},
},
Opts: map[string]any{},
},
},
}
eql := rpEv.Equals(expEvAcc)
if eql != true {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expEvAcc), utils.ToJSON(rpEv))
}
engine.Cache = cacheInit
}
func TestAccountsAccountsForEvent(t *testing.T) {
cacheInit := engine.Cache
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
newCache := engine.NewCacheS(cfg, dm, connMgr, nil)
engine.Cache = newCache
err := dm.SetAccount(context.Background(),
&utils.Account{
Tenant: "cgrates.org",
ID: "test_ID1",
Opts: map[string]any{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
}, true)
if err != nil {
t.Fatal(err)
}
accS := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
rpEv := make([]*utils.Account, 0)
ev := &utils.CGREvent{
ID: "TestMatchingAccountsForEvent",
Tenant: "cgrates.org",
Event: map[string]any{
utils.AccountField: "1001",
},
}
err = accS.V1AccountsForEvent(context.Background(), ev, &rpEv)
if err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
expEvAcc := []*utils.Account{
{
Tenant: "cgrates.org",
ID: "test_ID1",
Opts: map[string]any{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]any{
"Destination": 10,
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
if !reflect.DeepEqual(rpEv, expEvAcc) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expEvAcc), utils.ToJSON(rpEv))
}
engine.Cache = cacheInit
}
func TestV1GetAccount(t *testing.T) {
engine.Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: data}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, nil)
fltr := engine.NewFilterS(cfg, nil, dm)
accnts := NewAccountS(cfg, fltr, nil, dm)
arg := &utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{Tenant: "cgrates.org"},
}
var reply utils.Account
expected := "MANDATORY_IE_MISSING: [ID]"
err := accnts.V1GetAccount(context.Background(), arg, &reply)
if err == nil || err.Error() != expected {
t.Errorf("Expected %v, got %v", expected, err)
}
arg.TenantID.ID = "unknown_acc"
err = accnts.V1GetAccount(context.Background(), arg, &reply)
if err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Expected ErrNotFound, got %v", err)
}
acc := &utils.Account{
Tenant: "cgrates.org",
ID: "acc1",
}
if err := dm.SetAccount(context.Background(), acc, false); err != nil {
t.Fatalf("failed to create test account: %v", err)
}
arg.TenantID.ID = "acc1"
err = accnts.V1GetAccount(context.Background(), arg, &reply)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if reply.ID != acc.ID || reply.Tenant != acc.Tenant {
t.Errorf("expected %+v, got %+v", acc, reply)
}
}
func TestV1RefundCharges(t *testing.T) {
engine.Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
cfg.GeneralCfg().DefaultCaching = utils.MetaNone
connMgr := engine.NewConnManager(cfg)
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DbCfg().Items)
dbCM := engine.NewDBConnManager(map[string]engine.DataDB{utils.MetaDefault: dataDB}, cfg.DbCfg())
dm := engine.NewDataManager(dbCM, cfg, connMgr)
accnts := NewAccountS(cfg, &engine.FilterS{}, connMgr, dm)
ctx := context.Background()
var reply string
acc1 := &utils.Account{
Tenant: "cgrates.org",
ID: "acc1",
Balances: map[string]*utils.Balance{
"balance1": {ID: "balance1", Units: utils.NewDecimal(100, 0)},
},
}
acc2 := &utils.Account{
Tenant: "cgrates.org",
ID: "acc2",
Balances: map[string]*utils.Balance{
"balance2": {ID: "balance2", Units: utils.NewDecimal(50, 0)},
},
}
if err := dm.SetAccount(ctx, acc1, false); err != nil {
t.Fatalf("failed to create account1: %v", err)
}
if err := dm.SetAccount(ctx, acc2, false); err != nil {
t.Fatalf("failed to create account2: %v", err)
}
eventCharges := &utils.EventCharges{
Accounts: map[string]*utils.Account{
acc1.ID: acc1,
acc2.ID: acc2,
},
Charges: []*utils.ChargeEntry{
{ChargingID: "charge1"},
},
Accounting: map[string]*utils.AccountCharge{
"charge1": {
AccountID: "acc1",
BalanceID: "balance1",
Units: utils.NewDecimal(10, 0),
},
},
}
args := &utils.APIEventCharges{
Tenant: "cgrates.org",
EventCharges: eventCharges,
}
if err := accnts.V1RefundCharges(ctx, args, &reply); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if reply != utils.OK {
t.Fatalf("expected reply OK, got %v", reply)
}
acc1After, _ := dm.GetAccount(ctx, acc1.Tenant, acc1.ID)
expected := utils.NewDecimal(110, 0)
if acc1After.Balances["balance1"].Units.Big.Cmp(expected.Big) != 0 {
t.Errorf("expected balance1 %v, got %v", expected, acc1After.Balances["balance1"].Units)
}
acc2After, _ := dm.GetAccount(ctx, acc2.Tenant, acc2.ID)
expected2 := utils.NewDecimal(50, 0)
if acc2After.Balances["balance2"].Units.Big.Cmp(expected2.Big) != 0 {
t.Errorf("expected balance2 %v, got %v", expected2, acc2After.Balances["balance2"].Units)
}
}