diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go
index 65e58f2f0..e6061f24f 100644
--- a/accounts/abstractbalance.go
+++ b/accounts/abstractbalance.go
@@ -55,8 +55,8 @@ func (aB *abstractBalance) costIncrement(tnt string, ev utils.DataProvider) (cos
}
// nothing matched, return default
costIcrm = &utils.CostIncrement{
- Increment: decimal.New(1, 0),
- RecurrentFee: decimal.New(-1, 0)}
+ Increment: &utils.Decimal{decimal.New(1, 0)},
+ RecurrentFee: &utils.Decimal{decimal.New(-1, 0)}}
return
}
@@ -74,7 +74,7 @@ func (aB *abstractBalance) unitFactor(tnt string, ev utils.DataProvider) (uF *ut
}
// nothing matched, return default
uF = &utils.UnitFactor{
- Factor: decimal.New(1, 0),
+ Factor: &utils.Decimal{decimal.New(1, 0)},
}
return
}
diff --git a/accounts/concretebalance.go b/accounts/concretebalance.go
index d4e5f4d46..86c5492a9 100644
--- a/accounts/concretebalance.go
+++ b/accounts/concretebalance.go
@@ -55,8 +55,8 @@ func (cB *concreteBalance) costIncrement(tnt string, ev utils.DataProvider) (cos
}
// nothing matched, return default
costIcrm = &utils.CostIncrement{
- Increment: decimal.New(1, 0),
- RecurrentFee: decimal.New(-1, 0)}
+ Increment: &utils.Decimal{decimal.New(1, 0)},
+ RecurrentFee: &utils.Decimal{decimal.New(-1, 0)}}
return
}
@@ -74,7 +74,7 @@ func (cB *concreteBalance) unitFactor(tnt string, ev utils.DataProvider) (uF *ut
}
// nothing matched, return default
uF = &utils.UnitFactor{
- Factor: decimal.New(1, 0),
+ Factor: &utils.Decimal{decimal.New(1, 0)},
}
return
}
@@ -137,8 +137,8 @@ func (cB *concreteBalance) debitUnits(dUnts *decimal.Big, incrm *decimal.Big,
var hasUF bool
if uF.Factor.Cmp(decimal.New(1, 0)) != 0 {
- dUnts = utils.MultiplyBig(dUnts, uF.Factor)
- incrm = utils.MultiplyBig(incrm, uF.Factor)
+ dUnts = utils.MultiplyBig(dUnts, uF.Factor.Big)
+ incrm = utils.MultiplyBig(incrm, uF.Factor.Big)
hasUF = true
}
@@ -162,7 +162,7 @@ func (cB *concreteBalance) debitUnits(dUnts *decimal.Big, incrm *decimal.Big,
rmain = utils.AddBig(rmain, blncLmt)
}
if hasUF {
- dbted = utils.DivideBig(dUnts, uF.Factor)
+ dbted = utils.DivideBig(dUnts, uF.Factor.Big)
} else {
dbted = dUnts
}
diff --git a/accounts/concretebalance_test.go b/accounts/concretebalance_test.go
index bbe4b3fe6..9a87ba91f 100644
--- a/accounts/concretebalance_test.go
+++ b/accounts/concretebalance_test.go
@@ -38,7 +38,7 @@ func TestCBDebitUnits(t *testing.T) {
},
UnitFactors: []*utils.UnitFactor{
{
- Factor: decimal.New(100, 0), // EuroCents
+ Factor: &utils.Decimal{decimal.New(100, 0)}, // EuroCents
},
},
Value: 500, // 500 EURcents
diff --git a/apier/v1/accountprofiles.go b/apier/v1/accountprofiles.go
index d39fc8d78..941ba1e2f 100644
--- a/apier/v1/accountprofiles.go
+++ b/apier/v1/accountprofiles.go
@@ -108,10 +108,6 @@ func (apierSv1 *APIerSv1) SetAccountProfile(ap *AccountProfileWithCache, reply *
if err := apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheAccountProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
- if err := apierSv1.CallCache(ap.Cache, ap.Tenant, utils.CacheAccountProfiles,
- ap.TenantID(), &ap.FilterIDs, nil, ap.Opts); err != nil {
- return utils.APIErrorHandler(err)
- }
*reply = utils.OK
return nil
}
@@ -133,10 +129,6 @@ func (apierSv1 *APIerSv1) RemoveAccountProfile(arg *utils.TenantIDWithCache, rep
if err := apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheAccountProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
- if err := apierSv1.CallCache(arg.Cache, tnt, utils.CacheAccountProfiles,
- utils.ConcatenatedKey(tnt, arg.ID), nil, nil, arg.Opts); err != nil {
- return utils.APIErrorHandler(err)
- }
*reply = utils.OK
return nil
}
diff --git a/apier/v1/accountprofiles_it_test.go b/apier/v1/accountprofiles_it_test.go
new file mode 100644
index 000000000..f0ec8bf0e
--- /dev/null
+++ b/apier/v1/accountprofiles_it_test.go
@@ -0,0 +1,346 @@
+// +build integration
+
+/*
+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 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package v1
+
+import (
+ "net/rpc"
+ "path"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/ericlagergren/decimal"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+var (
+ accPrfCfgPath string
+ accPrfCfg *config.CGRConfig
+ accSRPC *rpc.Client
+ accPrfDataDir = "/usr/share/cgrates"
+ accPrf *AccountProfileWithCache
+ accPrfConfigDIR string //run tests for specific configuration
+
+ sTestsAccPrf = []func(t *testing.T){
+ testAccountSInitCfg,
+ testAccountSInitDataDb,
+ testAccountSResetStorDb,
+ testAccountSStartEngine,
+ testAccountSRPCConn,
+ testAccountSLoadFromFolder,
+ testAccountSGetAccountProfile,
+ testAccountSPing,
+ testAccountSSettAccountProfile,
+ testAccountSGetAccountProfileIDs,
+ testAccountSGetAccountProfileIDsCount,
+ testAccountSUpdateAccountProfile,
+ testAccountSRemoveAccountProfile,
+ testAccountSKillEngine,
+ }
+)
+
+//Test start here
+func TestAccountSIT(t *testing.T) {
+ switch *dbType {
+ case utils.MetaInternal:
+ accPrfConfigDIR = "tutinternal"
+ case utils.MetaMySQL:
+ accPrfConfigDIR = "tutmysql"
+ case utils.MetaMongo:
+ accPrfConfigDIR = "tutmongo"
+ case utils.MetaPostgres:
+ t.SkipNow()
+ default:
+ t.Fatal("Unknown Database type")
+ }
+ for _, stest := range sTestsAccPrf {
+ t.Run(accPrfConfigDIR, stest)
+ }
+}
+
+func testAccountSInitCfg(t *testing.T) {
+ var err error
+ accPrfCfgPath = path.Join(accPrfDataDir, "conf", "samples", accPrfConfigDIR)
+ accPrfCfg, err = config.NewCGRConfigFromPath(accPrfCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testAccountSInitDataDb(t *testing.T) {
+ if err := engine.InitDataDb(accPrfCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Wipe out the cdr database
+func testAccountSResetStorDb(t *testing.T) {
+ if err := engine.InitStorDb(accPrfCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Start CGR Engine
+func testAccountSStartEngine(t *testing.T) {
+ if _, err := engine.StopStartEngine(accPrfCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Connect rpc client to rater
+func testAccountSRPCConn(t *testing.T) {
+ var err error
+ accSRPC, err = newRPCClient(accPrfCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testAccountSLoadFromFolder(t *testing.T) {
+ var reply string
+ acts := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutaccounts")}
+ if err := accSRPC.Call(utils.APIerSv1LoadTariffPlanFromFolder, acts, &reply); err != nil {
+ t.Error(err)
+ }
+ time.Sleep(100 * time.Millisecond)
+}
+
+func testAccountSGetAccountProfile(t *testing.T) {
+ expected := &utils.AccountProfile{
+ Tenant: "cgrates.org",
+ ID: "1001",
+ FilterIDs: []string{},
+ Weight: 20,
+ Balances: []*utils.Balance{
+ &utils.Balance{
+ ID: "MonetaryBalance",
+ FilterIDs: []string{},
+ Weight: 10,
+ Type: utils.MONETARY,
+ CostIncrements: []*utils.CostIncrement{
+ &utils.CostIncrement{
+ FilterIDs: []string{"fltr1", "fltr2"},
+ Increment: &utils.Decimal{decimal.New(13, 1)},
+ FixedFee: &utils.Decimal{decimal.New(23, 1)},
+ RecurrentFee: &utils.Decimal{decimal.New(33, 1)},
+ },
+ },
+ CostAttributes: []string{"attr1", "attr2"},
+ UnitFactors: []*utils.UnitFactor{
+ &utils.UnitFactor{
+ FilterIDs: []string{"fltr1", "fltr2"},
+ Factor: &utils.Decimal{decimal.New(100, 0)},
+ },
+ &utils.UnitFactor{
+ FilterIDs: []string{"fltr3"},
+ Factor: &utils.Decimal{decimal.New(200, 0)},
+ },
+ },
+ Value: 14,
+ },
+ &utils.Balance{
+ ID: "VoiceBalance",
+ FilterIDs: []string{},
+ Weight: 10,
+ Type: utils.VOICE,
+ CostIncrements: []*utils.CostIncrement{},
+ CostAttributes: []string{},
+ UnitFactors: []*utils.UnitFactor{},
+ Value: 3600000000000,
+ },
+ },
+ ThresholdIDs: []string{utils.META_NONE},
+ }
+ if *encoding == utils.MetaGOB {
+ expected.FilterIDs = nil
+ for i := range expected.Balances {
+ expected.Balances[i].FilterIDs = nil
+ }
+ }
+ var reply *utils.AccountProfile
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfile,
+ utils.TenantIDWithOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "1001"}}, &reply); err != nil {
+ t.Fatal(err)
+ } else if !reflect.DeepEqual(expected, reply) {
+ t.Errorf("Expecting : %+v \n received: %+v", utils.ToJSON(expected), utils.ToJSON(reply))
+ }
+}
+
+func testAccountSPing(t *testing.T) {
+ var resp string
+ if err := accSRPC.Call(utils.AccountSv1Ping, new(utils.CGREventWithOpts), &resp); err != nil {
+ t.Error(err)
+ } else if resp != utils.Pong {
+ t.Error("Unexpected reply returned", resp)
+ }
+}
+
+func testAccountSSettAccountProfile(t *testing.T) {
+ accPrf = &AccountProfileWithCache{
+ AccountProfileWithOpts: &utils.AccountProfileWithOpts{
+ AccountProfile: &utils.AccountProfile{
+ Tenant: "cgrates.org",
+ ID: "id_test",
+ Weight: 10,
+ Balances: []*utils.Balance{
+ &utils.Balance{
+ ID: "MonetaryBalance",
+ FilterIDs: []string{},
+ Weight: 10,
+ Type: utils.MONETARY,
+ CostIncrements: []*utils.CostIncrement{
+ &utils.CostIncrement{
+ FilterIDs: []string{"fltr1", "fltr2"},
+ Increment: &utils.Decimal{decimal.New(13, 1)},
+ FixedFee: &utils.Decimal{decimal.New(23, 1)},
+ RecurrentFee: &utils.Decimal{decimal.New(33, 1)},
+ },
+ },
+ CostAttributes: []string{"attr1", "attr2"},
+ UnitFactors: []*utils.UnitFactor{
+ &utils.UnitFactor{
+ FilterIDs: []string{"fltr1", "fltr2"},
+ Factor: &utils.Decimal{decimal.New(100, 0)},
+ },
+ &utils.UnitFactor{
+ FilterIDs: []string{"fltr3"},
+ Factor: &utils.Decimal{decimal.New(200, 0)},
+ },
+ },
+ Value: 14,
+ },
+ &utils.Balance{
+ ID: "VoiceBalance",
+ FilterIDs: []string{},
+ Weight: 10,
+ Type: utils.VOICE,
+ CostIncrements: []*utils.CostIncrement{},
+ CostAttributes: []string{},
+ UnitFactors: []*utils.UnitFactor{},
+ Value: 3600000000000,
+ },
+ },
+ ThresholdIDs: []string{utils.META_NONE},
+ },
+ Opts: map[string]interface{}{},
+ },
+ }
+ var result string
+ expErr := utils.ErrNotFound.Error()
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
+ TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &result); err == nil || err.Error() != expErr {
+ t.Errorf("Expected error: %v received: %v", expErr, err)
+ }
+ var reply string
+ if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, accPrf, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Error("Unexpected reply returned", reply)
+ }
+ var reply2 *utils.AccountProfile
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
+ TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &reply2); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(accPrf.AccountProfile, reply2) {
+ t.Errorf("Expecting : %+v, received: %+v", accPrf.AccountProfile, reply2)
+ }
+
+}
+
+func testAccountSGetAccountProfileIDs(t *testing.T) {
+ expected := []string{"id_test", "1001"}
+ var result []string
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfileIDs, utils.PaginatorWithTenant{}, &result); err != nil {
+ t.Error(err)
+ } else if len(expected) != len(result) {
+ t.Errorf("Expecting : %+v, received: %+v", expected, result)
+ }
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfileIDs, utils.PaginatorWithTenant{Tenant: "cgrates.org"}, &result); err != nil {
+ t.Error(err)
+ } else if len(expected) != len(result) {
+ t.Errorf("Expecting : %+v, received: %+v", expected, result)
+ }
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfileIDs, utils.PaginatorWithTenant{
+ Tenant: "cgrates.org",
+ Paginator: utils.Paginator{Limit: utils.IntPointer(1)},
+ }, &result); err != nil {
+ t.Error(err)
+ } else if 1 != len(result) {
+ t.Errorf("Expecting : %+v, received: %+v", 1, result)
+ }
+
+}
+
+func testAccountSGetAccountProfileIDsCount(t *testing.T) {
+ var reply int
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfileIDsCount,
+ &utils.TenantWithOpts{Tenant: "cgrates.org"}, &reply); err != nil {
+ t.Error(err)
+ } else if reply != 2 {
+ t.Errorf("Expecting: 2, received: %+v", reply)
+ }
+
+}
+
+func testAccountSUpdateAccountProfile(t *testing.T) {
+ var reply string
+ accPrf.Weight = 2
+ accPrf.Balances[0].CostIncrements[0].FixedFee = &utils.Decimal{decimal.New(1234, 1)}
+ if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, accPrf, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Error("Unexpected reply returned", reply)
+ }
+ var reply2 *utils.AccountProfile
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
+ TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &reply2); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(accPrf.AccountProfile, reply2) {
+ t.Errorf("Expecting : %+v, received: %+v", accPrf.AccountProfile, reply2)
+ }
+}
+
+func testAccountSRemoveAccountProfile(t *testing.T) {
+ var reply string
+ if err := accSRPC.Call(utils.APIerSv1RemoveAccountProfile, &utils.TenantIDWithCache{Tenant: "cgrates.org", ID: "id_test"}, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Error("Unexpected reply returned", reply)
+ }
+ var reply2 *utils.AccountProfile
+ expErr := utils.ErrNotFound.Error()
+ if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
+ TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &reply2); err == nil || err.Error() != expErr {
+ t.Errorf("Expected error: %v received: %v", expErr, err)
+ }
+ if err := accSRPC.Call(utils.APIerSv1RemoveAccountProfile, &utils.TenantIDWithCache{Tenant: "cgrates.org", ID: "id_test"}, &reply2); err == nil || err.Error() != expErr {
+ t.Errorf("Expected error: %v received: %v", expErr, err)
+ }
+}
+
+func testAccountSKillEngine(t *testing.T) {
+ if err := engine.KillEngine(100); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/data/conf/samples/tutinternal/cgrates.json b/data/conf/samples/tutinternal/cgrates.json
index 2928b145b..d48ae4a0b 100644
--- a/data/conf/samples/tutinternal/cgrates.json
+++ b/data/conf/samples/tutinternal/cgrates.json
@@ -115,6 +115,11 @@
},
+"accounts": {
+ "enabled": true
+},
+
+
"filters": {
"apiers_conns": ["*internal"]
}
diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json
index 6542a1189..fcfc6f076 100644
--- a/data/conf/samples/tutmongo/cgrates.json
+++ b/data/conf/samples/tutmongo/cgrates.json
@@ -125,6 +125,11 @@
},
+"accounts": {
+ "enabled": true
+ },
+
+
"filters": {
"apiers_conns": ["*internal"],
},
diff --git a/data/conf/samples/tutmongojson/cgrates.json b/data/conf/samples/tutmongojson/cgrates.json
index 430f0d77e..699bf98ef 100644
--- a/data/conf/samples/tutmongojson/cgrates.json
+++ b/data/conf/samples/tutmongojson/cgrates.json
@@ -1,33 +1,139 @@
{
-// CGRateS Configuration file
+ // CGRateS Configuration file
-"general": {
- "log_level": 7,
- "reply_timeout": "30s",
- "dbdata_encoding": "json",
-},
+ "general": {
+ "log_level": 7,
+ "dbdata_encoding": "json",
+ "reply_timeout": "30s",
+ },
-"listen": {
- "rpc_json": ":2012",
- "rpc_gob": ":2013",
- "http": ":2080",
-},
+ "listen": {
+ "rpc_json": ":2012",
+ "rpc_gob": ":2013",
+ "http": ":2080",
+ },
-"data_db": {
- "db_type": "mongo",
- "db_name": "11",
- "db_port": 27017,
-},
+ "data_db": {
+ "db_type": "mongo",
+ "db_name": "11",
+ "db_port": 27017,
+ },
-"stor_db": {
- "db_type": "mongo",
- "db_name": "cgrates2",
- "db_port": 27017,
-},
+ "stor_db": {
+ "db_type": "mongo",
+ "db_name": "cgrates2",
+ "db_port": 27017,
+ },
-}
\ No newline at end of file
+ "rals": {
+ "enabled": true,
+ "thresholds_conns": ["*internal"],
+ "max_increments":3000000,
+ },
+
+
+ "schedulers": {
+ "enabled": true,
+ "cdrs_conns": ["*localhost"],
+ "stats_conns": ["*localhost"],
+ },
+
+
+ "cdrs": {
+ "enabled": true,
+ },
+
+
+ "chargers": {
+ "enabled": true,
+ "attributes_conns": ["*internal"],
+ },
+
+
+ "resources": {
+ "enabled": true,
+ "store_interval": "1s",
+ "thresholds_conns": ["*internal"]
+ },
+
+
+ "stats": {
+ "enabled": true,
+ "store_interval": "1s",
+ "thresholds_conns": ["*internal"],
+ },
+
+
+ "thresholds": {
+ "enabled": true,
+ "store_interval": "1s",
+ },
+
+
+ "routes": {
+ "enabled": true,
+ "stats_conns": ["*localhost"],
+ "resources_conns": ["*localhost"],
+ "rals_conns": ["*internal"],
+ },
+
+
+ "attributes": {
+ "enabled": true,
+ "stats_conns": ["*localhost"],
+ "resources_conns": ["*localhost"],
+ "apiers_conns": ["*localhost"]
+ },
+
+
+ "sessions": {
+ "enabled": true,
+ "rals_conns": ["*internal"],
+ "cdrs_conns": ["*internal"],
+ "chargers_conns": ["*internal"],
+ },
+
+
+ "migrator": {
+ "out_datadb_type": "mongo",
+ "out_datadb_port": "27017",
+ "out_datadb_name": "10",
+ "out_stordb_type": "mongo",
+ "out_stordb_port": "27017",
+ "out_stordb_name": "cgrates",
+ "users_filters":["Account"],
+ },
+
+
+ "apiers": {
+ "enabled": true,
+ "scheduler_conns": ["*internal"],
+ },
+
+
+ "rates": {
+ "enabled": true
+ },
+
+
+ "actions": {
+ "enabled": true
+ },
+
+
+ "accounts": {
+ "enabled": true
+ },
+
+
+ "filters": {
+ "apiers_conns": ["*internal"],
+ },
+
+
+}
diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json
index 49dfdd1b0..d0014bfba 100644
--- a/data/conf/samples/tutmysql/cgrates.json
+++ b/data/conf/samples/tutmysql/cgrates.json
@@ -5,6 +5,7 @@
"general": {
"log_level": 7,
+ //"dbdata_encoding": "*json",
"reply_timeout": "50s",
},
diff --git a/data/conf/samples/tutmysqljson/cgrates.json b/data/conf/samples/tutmysqljson/cgrates.json
index 10993496d..6aa731592 100644
--- a/data/conf/samples/tutmysqljson/cgrates.json
+++ b/data/conf/samples/tutmysqljson/cgrates.json
@@ -1,30 +1,135 @@
{
-// CGRateS Configuration file
-//
+ // CGRateS Configuration file
-"general": {
- "log_level": 7,
- "dbdata_encoding": "json", // encoding used to store object data in strings:
-},
+ "general": {
+ "log_level": 7,
+ "dbdata_encoding": "json",
+ "reply_timeout": "50s",
+ },
-"listen": {
- "rpc_json": ":2012",
- "rpc_gob": ":2013",
- "http": ":2080",
-},
+ "listen": {
+ "rpc_json": ":2012",
+ "rpc_gob": ":2013",
+ "http": ":2080",
+ },
-"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
- "db_type": "redis", // data_db type:
- "db_port": 6379, // data_db port to reach the database
- "db_name": "11", // data_db database name to connect to
-
-},
+ "data_db": { // database used to store runtime data (eg: accounts, cdr stats)
+ "db_type": "redis", // data_db type:
+ "db_port": 6379, // data_db port to reach the database
+ "db_name": "11", // data_db database name to connect to
+ },
-"stor_db": {
- "db_password": "CGRateS.org",
-},
+ "stor_db": {
+ "db_password": "CGRateS.org",
+ },
-}
\ No newline at end of file
+ "rals": {
+ "enabled": true,
+ "thresholds_conns": ["*internal"],
+ "max_increments":3000000,
+ },
+
+
+ "schedulers": {
+ "enabled": true,
+ "cdrs_conns": ["*internal"],
+ "stats_conns": ["*localhost"],
+ },
+
+
+ "cdrs": {
+ "enabled": true,
+ "chargers_conns":["*internal"],
+ },
+
+
+ "attributes": {
+ "enabled": true,
+ "stats_conns": ["*localhost"],
+ "resources_conns": ["*localhost"],
+ "apiers_conns": ["*localhost"]
+ },
+
+
+ "chargers": {
+ "enabled": true,
+ "attributes_conns": ["*internal"],
+ },
+
+
+ "resources": {
+ "enabled": true,
+ "store_interval": "1s",
+ "thresholds_conns": ["*internal"]
+ },
+
+
+ "stats": {
+ "enabled": true,
+ "store_interval": "1s",
+ "thresholds_conns": ["*internal"],
+ },
+
+ "thresholds": {
+ "enabled": true,
+ "store_interval": "1s",
+ },
+
+
+ "routes": {
+ "enabled": true,
+ "prefix_indexed_fields":["*req.Destination"],
+ "stats_conns": ["*internal"],
+ "resources_conns": ["*internal"],
+ "rals_conns": ["*internal"],
+ },
+
+
+ "sessions": {
+ "enabled": true,
+ "routes_conns": ["*internal"],
+ "resources_conns": ["*internal"],
+ "attributes_conns": ["*internal"],
+ "rals_conns": ["*internal"],
+ "cdrs_conns": ["*internal"],
+ "chargers_conns": ["*internal"],
+ },
+
+
+ "migrator":{
+ "out_stordb_password": "CGRateS.org",
+ "users_filters":["Account"],
+ },
+
+
+
+ "apiers": {
+ "enabled": true,
+ "scheduler_conns": ["*internal"],
+ },
+
+
+ "rates": {
+ "enabled": true
+ },
+
+
+ "actions": {
+ "enabled": true
+ },
+
+
+ "accounts": {
+ "enabled": true
+ },
+
+
+ "filters": {
+ "apiers_conns": ["*internal"],
+ },
+
+
+}
diff --git a/engine/datamanager.go b/engine/datamanager.go
index 5fa9cdfa4..6cdc28bb2 100644
--- a/engine/datamanager.go
+++ b/engine/datamanager.go
@@ -79,7 +79,6 @@ var (
utils.RateFilterIndexPrfx: {},
utils.FilterIndexPrfx: {},
utils.MetaAPIBan: {}, // not realy a prefix as this is not stored in DB
- utils.AccountProfilePrefix: {},
}
)
@@ -231,9 +230,6 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b
case utils.ActionProfilePrefix:
tntID := utils.NewTenantID(dataID)
_, err = dm.GetActionProfile(tntID.Tenant, tntID.ID, false, true, utils.NonTransactional)
- case utils.AccountProfilePrefix:
- tntID := utils.NewTenantID(dataID)
- _, err = dm.GetAccountProfile(tntID.Tenant, tntID.ID, false, true, utils.NonTransactional)
case utils.AttributeFilterIndexes:
var tntCtx, idxKey string
if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil {
@@ -3816,15 +3812,6 @@ func (dm *DataManager) checkFilters(tenant string, ids []string) (brokenReferenc
func (dm *DataManager) GetAccountProfile(tenant, id string, cacheRead, cacheWrite bool,
transactionID string) (ap *utils.AccountProfile, err error) {
- tntID := utils.ConcatenatedKey(tenant, id)
- if cacheRead {
- if x, ok := Cache.Get(utils.CacheAccountProfiles, tntID); ok {
- if x == nil {
- return nil, utils.ErrNotFound
- }
- return x.(*utils.AccountProfile), nil
- }
- }
if dm == nil {
err = utils.ErrNoDatabaseConn
return
@@ -3844,23 +3831,9 @@ func (dm *DataManager) GetAccountProfile(tenant, id string, cacheRead, cacheWrit
}
}
if err != nil {
- err = utils.CastRPCErr(err)
- if err == utils.ErrNotFound && cacheWrite {
- if errCh := Cache.Set(utils.CacheAccountProfiles, tntID, nil, nil,
- cacheCommit(transactionID), transactionID); errCh != nil {
- return nil, errCh
- }
-
- }
return nil, err
}
}
- if cacheWrite {
- if errCh := Cache.Set(utils.CacheAccountProfiles, tntID, ap, nil,
- cacheCommit(transactionID), transactionID); errCh != nil {
- return nil, errCh
- }
- }
return
}
diff --git a/engine/model_helpers.go b/engine/model_helpers.go
index 8a3a9d044..2e615db56 100644
--- a/engine/model_helpers.go
+++ b/engine/model_helpers.go
@@ -27,8 +27,6 @@ import (
"strings"
"time"
- "github.com/ericlagergren/decimal"
-
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
@@ -3745,10 +3743,22 @@ func APItoAccountProfile(tpAp *utils.TPAccountProfile, timezone string) (ap *uti
ap.Balances[i].CostIncrements = make([]*utils.CostIncrement, len(bal.CostIncrement))
for j, costIncrement := range bal.CostIncrement {
ap.Balances[i].CostIncrements[j] = &utils.CostIncrement{
- FilterIDs: costIncrement.FilterIDs,
- Increment: new(decimal.Big).SetFloat64(*costIncrement.Increment),
- FixedFee: new(decimal.Big).SetFloat64(*costIncrement.FixedFee),
- RecurrentFee: new(decimal.Big).SetFloat64(*costIncrement.RecurrentFee),
+ FilterIDs: costIncrement.FilterIDs,
+ }
+ if costIncrement.Increment != nil {
+ if ap.Balances[i].CostIncrements[j].Increment, err = utils.NewDecimalFromFloat64(*costIncrement.Increment); err != nil {
+ return
+ }
+ }
+ if costIncrement.FixedFee != nil {
+ if ap.Balances[i].CostIncrements[j].FixedFee, err = utils.NewDecimalFromFloat64(*costIncrement.FixedFee); err != nil {
+ return
+ }
+ }
+ if costIncrement.RecurrentFee != nil {
+ if ap.Balances[i].CostIncrements[j].RecurrentFee, err = utils.NewDecimalFromFloat64(*costIncrement.RecurrentFee); err != nil {
+ return
+ }
}
}
}
@@ -3763,7 +3773,9 @@ func APItoAccountProfile(tpAp *utils.TPAccountProfile, timezone string) (ap *uti
for j, unitFactor := range bal.UnitFactors {
ap.Balances[i].UnitFactors[j] = &utils.UnitFactor{
FilterIDs: unitFactor.FilterIDs,
- Factor: new(decimal.Big).SetFloat64(unitFactor.Factor),
+ }
+ if ap.Balances[i].UnitFactors[j].Factor, err = utils.NewDecimalFromFloat64(unitFactor.Factor); err != nil {
+ return
}
}
}
diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go
index 69340d4c4..2771a8606 100644
--- a/engine/storage_mongo_datadb.go
+++ b/engine/storage_mongo_datadb.go
@@ -29,6 +29,8 @@ import (
"sync"
"time"
+ "github.com/ericlagergren/decimal"
+
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/guardian"
"github.com/cgrates/cgrates/utils"
@@ -103,7 +105,8 @@ var (
CostLow = strings.ToLower(utils.COST)
CostSourceLow = strings.ToLower(utils.CostSource)
- tTime = reflect.TypeOf(time.Time{})
+ tTime = reflect.TypeOf(time.Time{})
+ decimalType = reflect.TypeOf(utils.Decimal{})
)
func TimeDecodeValue1(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
@@ -123,6 +126,33 @@ func TimeDecodeValue1(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val ref
return nil
}
+func DecimalEncoder(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
+ if val.Kind() != reflect.Struct {
+ return bsoncodec.ValueEncoderError{Name: "DecimalEncoder", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
+ }
+ d, ok := val.Interface().(utils.Decimal)
+ if !ok {
+ return fmt.Errorf("cannot cast <%+v> to ", val.Interface())
+ }
+ return vw.WriteString(d.String())
+}
+
+func DecimalDecoder(ec bsoncodec.DecodeContext, vw bsonrw.ValueReader, val reflect.Value) error {
+ if !val.CanSet() || val.Type() != decimalType {
+ return bsoncodec.ValueEncoderError{Name: "DecimalDecoder", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
+ }
+ str, err := vw.ReadString()
+ if err != nil {
+ return err
+ }
+ dBig, ok := new(decimal.Big).SetString(str)
+ if !ok {
+ return fmt.Errorf("cannot set string: <%s> to decimal.Big", str)
+ }
+ val.Set(reflect.ValueOf(utils.Decimal{dBig}))
+ return nil
+}
+
// NewMongoStorage givese new mongo driver
func NewMongoStorage(host, port, db, user, pass, mrshlerStr, storageType string,
cdrsIndexes []string, ttl time.Duration) (ms *MongoStorage, err error) {
@@ -140,10 +170,13 @@ func NewMongoStorage(host, port, db, user, pass, mrshlerStr, storageType string,
}
ctx := context.Background()
url = "mongodb://" + url
- reg := bson.NewRegistryBuilder().RegisterDecoder(tTime, bsoncodec.ValueDecoderFunc(TimeDecodeValue1)).Build()
+ reg := bson.NewRegistryBuilder()
+ reg.RegisterDecoder(tTime, bsoncodec.ValueDecoderFunc(TimeDecodeValue1))
+ reg.RegisterTypeEncoder(decimalType, bsoncodec.ValueEncoderFunc(DecimalEncoder))
+ reg.RegisterTypeDecoder(decimalType, bsoncodec.ValueDecoderFunc(DecimalDecoder))
opt := options.Client().
ApplyURI(url).
- SetRegistry(reg).
+ SetRegistry(reg.Build()).
SetServerSelectionTimeout(ttl).
SetRetryWrites(false) // set this option to false because as default it is on true
diff --git a/engine/tpreader.go b/engine/tpreader.go
index e327256ef..8bcaf136c 100644
--- a/engine/tpreader.go
+++ b/engine/tpreader.go
@@ -2628,7 +2628,6 @@ func (tpr *TpReader) ReloadCache(caching string, verbose bool, opts map[string]i
utils.DispatcherHostIDs: dphIDs,
utils.RateProfileIDs: ratePrfIDs,
utils.ActionProfileIDs: actionPrfIDs,
- utils.AccountProfileIDs: accountPrfIDs,
},
}
diff --git a/loaders/loader.go b/loaders/loader.go
index 92a75dc2f..0b27d6f69 100644
--- a/loaders/loader.go
+++ b/loaders/loader.go
@@ -682,7 +682,6 @@ func (ldr *Loader) storeLoadedData(loaderType string,
if err := ldr.dm.SetAccountProfile(acp, true); err != nil {
return err
}
- cacheArgs[utils.AccountProfileIDs] = ids
}
}
}
@@ -1039,7 +1038,6 @@ func (ldr *Loader) removeLoadedData(loaderType string, lds map[string][]LoaderDa
tntIDStruct.ID, utils.NonTransactional, true); err != nil {
return err
}
- cacheArgs[utils.AccountProfileIDs] = ids
}
}
}
diff --git a/utils/accountprofile.go b/utils/accountprofile.go
index c329993ca..de6fbef72 100644
--- a/utils/accountprofile.go
+++ b/utils/accountprofile.go
@@ -21,8 +21,6 @@ package utils
import (
"sort"
"time"
-
- "github.com/ericlagergren/decimal"
)
// AccountProfile represents one Account on a Tenant
@@ -54,9 +52,9 @@ type Balance struct {
// CostIncrement enforces cost calculation to specific balance increments
type CostIncrement struct {
FilterIDs []string
- Increment *decimal.Big
- FixedFee *decimal.Big
- RecurrentFee *decimal.Big
+ Increment *Decimal
+ FixedFee *Decimal
+ RecurrentFee *Decimal
}
// Clone returns a copy of the CostIncrement
@@ -69,31 +67,13 @@ func (cI *CostIncrement) Clone() (cIcln *CostIncrement) {
}
}
if cI.Increment != nil {
- cIcln.Increment = new(decimal.Big).Copy(cI.Increment)
+ cIcln.Increment = new(Decimal).Copy(cI.Increment)
}
if cI.FixedFee != nil {
- cIcln.FixedFee = new(decimal.Big).Copy(cI.FixedFee)
+ cIcln.FixedFee = new(Decimal).Copy(cI.FixedFee)
}
if cI.RecurrentFee != nil {
- cIcln.RecurrentFee = new(decimal.Big).Copy(cI.RecurrentFee)
- }
- return
-}
-
-//Clone return a copy of the CostAttributes
-func (cA *CostAttributes) Clone() (cstAtr *CostAttributes) {
- cstAtr = new(CostAttributes)
- if cA.FilterIDs != nil {
- cstAtr.FilterIDs = make([]string, len(cA.FilterIDs))
- for i, value := range cA.FilterIDs {
- cstAtr.FilterIDs[i] = value
- }
- }
- if cA.AttributeProfileIDs != nil {
- cstAtr.AttributeProfileIDs = make([]string, len(cA.AttributeProfileIDs))
- for i, value := range cA.AttributeProfileIDs {
- cstAtr.AttributeProfileIDs[i] = value
- }
+ cIcln.RecurrentFee = new(Decimal).Copy(cI.RecurrentFee)
}
return
}
@@ -108,7 +88,7 @@ func (uF *UnitFactor) Clone() (untFct *UnitFactor) {
}
}
if uF.Factor != nil {
- untFct.Factor = new(decimal.Big).Copy(uF.Factor)
+ untFct.Factor = new(Decimal).Copy(uF.Factor)
}
return
}
@@ -116,7 +96,7 @@ func (uF *UnitFactor) Clone() (untFct *UnitFactor) {
// UnitFactor is a multiplicator for the usage received
type UnitFactor struct {
FilterIDs []string
- Factor *decimal.Big
+ Factor *Decimal
}
func (aP *AccountProfile) TenantID() string {
@@ -190,9 +170,9 @@ func (bL *Balance) Clone() (blnc *Balance) {
}
}
if bL.CostAttributes != nil {
- blnc.CostAttributes = make([]*CostAttributes, len(bL.CostAttributes))
+ blnc.CostAttributes = make([]string, len(bL.CostAttributes))
for i, value := range bL.CostAttributes {
- blnc.CostAttributes[i] = value.Clone()
+ blnc.CostAttributes[i] = value
}
}
if bL.UnitFactors != nil {
diff --git a/utils/accountprofile_test.go b/utils/accountprofile_test.go
index eaeb49bbe..7297f3b14 100644
--- a/utils/accountprofile_test.go
+++ b/utils/accountprofile_test.go
@@ -39,21 +39,16 @@ func TestCloneBalance(t *testing.T) {
CostIncrements: []*CostIncrement{
{
FilterIDs: []string{"*string:~*req.Account:1001"},
- Increment: decimal.New(1, 1),
- FixedFee: decimal.New(75, 1),
- RecurrentFee: decimal.New(20, 1),
- },
- },
- CostAttributes: []*CostAttributes{
- {
- FilterIDs: []string{"*string:~*req.Account:1001"},
- AttributeProfileIDs: []string{"ID1"},
+ Increment: &Decimal{decimal.New(1, 1)},
+ FixedFee: &Decimal{decimal.New(75, 1)},
+ RecurrentFee: &Decimal{decimal.New(20, 1)},
},
},
+ CostAttributes: []string{"attr1", "attr2"},
UnitFactors: []*UnitFactor{
{
FilterIDs: []string{"*string:~*req.Account:1001"},
- Factor: decimal.New(20, 2),
+ Factor: &Decimal{decimal.New(20, 2)},
},
},
Value: 1.25,
@@ -89,21 +84,16 @@ func TestCloneAccountProfile(t *testing.T) {
CostIncrements: []*CostIncrement{
{
FilterIDs: []string{"*string:~*req.Account:1001"},
- Increment: decimal.New(1, 1),
- FixedFee: decimal.New(75, 1),
- RecurrentFee: decimal.New(20, 1),
- },
- },
- CostAttributes: []*CostAttributes{
- {
- FilterIDs: []string{"*string:~*req.Account:1001"},
- AttributeProfileIDs: []string{"ID1"},
+ Increment: &Decimal{decimal.New(1, 1)},
+ FixedFee: &Decimal{decimal.New(75, 1)},
+ RecurrentFee: &Decimal{decimal.New(20, 1)},
},
},
+ CostAttributes: []string{"attr1", "attr2"},
UnitFactors: []*UnitFactor{
{
FilterIDs: []string{"*string:~*req.Account:1001"},
- Factor: decimal.New(20, 2),
+ Factor: &Decimal{decimal.New(20, 2)},
},
},
Value: 1.25,
diff --git a/utils/consts.go b/utils/consts.go
index 25fc1a2f5..9fd8191ea 100755
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -196,7 +196,6 @@ var (
DispatcherHostIDs: DispatcherHostPrefix,
RateProfileIDs: RateProfilePrefix,
ActionProfileIDs: ActionProfilePrefix,
- AccountProfileIDs: AccountProfilePrefix,
TimingIDs: TimingsPrefix,
AttributeFilterIndexIDs: AttributeFilterIndexes,
@@ -237,7 +236,6 @@ var (
DispatcherHostIDs: CacheDispatcherHosts,
RateProfileIDs: CacheRateProfiles,
ActionProfileIDs: CacheActionProfiles,
- AccountProfileIDs: CacheAccountProfiles,
TimingIDs: CacheTimings,
AttributeFilterIndexIDs: CacheAttributeFilterIndexes,
@@ -1470,9 +1468,11 @@ const (
APIerSv1SetTPRateProfile = "APIerSv1.SetTPRateProfile"
APIerSv1GetTPRateProfileIds = "APIerSv1.GetTPRateProfileIds"
APIerSv1RemoveTPRateProfile = "APIerSv1.RemoveTPRateProfile"
- APIerSv1GetTPAccountProfile = "APIerSv1.GetTPAccountProfile"
- APIerSv1SetTPAccountProfile = "APIerSv1.SetTPAccountProfile"
- APIerSv1RemoveTPAccountProfile = "APIerSv1.RemoveTPAccountProfile"
+ APIerSv1SetAccountProfile = "APIerSv1.SetAccountProfile"
+ APIerSv1GetAccountProfile = "APIerSv1.GetAccountProfile"
+ APIerSv1GetAccountProfileIDs = "APIerSv1.GetAccountProfileIDs"
+ APIerSv1RemoveAccountProfile = "APIerSv1.RemoveAccountProfile"
+ APIerSv1GetAccountProfileIDsCount = "APIerSv1.GetAccountProfileIDsCount"
APIerSv1GetTPAccountProfileIDs = "APIerSv1.GetTPAccountProfileIDs"
)
@@ -2597,7 +2597,6 @@ const (
RateProfileIDs = "RateProfileIDs"
ActionProfileIDs = "ActionProfileIDs"
TimingIDs = "TimingIDs"
- AccountProfileIDs = "AccountProfileIDs"
AttributeFilterIndexIDs = "AttributeFilterIndexIDs"
ResourceFilterIndexIDs = "ResourceFilterIndexIDs"
StatFilterIndexIDs = "StatFilterIndexIDs"
diff --git a/utils/decimal.go b/utils/decimal.go
index 7e8026ef0..3afe33081 100644
--- a/utils/decimal.go
+++ b/utils/decimal.go
@@ -18,7 +18,13 @@ along with this program. If not, see
package utils
-import "github.com/ericlagergren/decimal"
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+
+ "github.com/ericlagergren/decimal"
+)
func DivideBig(x, y *decimal.Big) *decimal.Big {
return new(decimal.Big).Quo(x, y)
@@ -35,3 +41,47 @@ func AddBig(x, y *decimal.Big) *decimal.Big {
func SubstractBig(x, y *decimal.Big) *decimal.Big {
return new(decimal.Big).Sub(x, y)
}
+
+func NewDecimalFromFloat64(f float64) (*Decimal, error) {
+ d, canSet := new(decimal.Big).SetString(strconv.FormatFloat(f, 'f', -1, 64))
+ if !canSet {
+ return nil, fmt.Errorf("cannot convert float64 to decimal.Big")
+ }
+ return &Decimal{d}, nil
+}
+
+type Decimal struct {
+ *decimal.Big
+}
+
+func (d *Decimal) UnmarshalBinary(data []byte) (err error) {
+ if d == nil {
+ d = &Decimal{new(decimal.Big)}
+ }
+ if d.Big == nil {
+ d.Big = new(decimal.Big)
+ }
+ return d.Big.UnmarshalText(data)
+}
+
+func (d *Decimal) MarshalBinary() ([]byte, error) {
+ if d.Big == nil {
+ d.Big = new(decimal.Big)
+ }
+ return d.Big.MarshalText()
+}
+
+func (d *Decimal) UnmarshalJSON(data []byte) (err error) {
+ return d.UnmarshalBinary(data)
+}
+
+func (d *Decimal) MarshalJSON() ([]byte, error) {
+ x, err := d.MarshalText()
+ return bytes.Trim(x, `"`), err
+}
+
+func (d *Decimal) Copy(d2 *Decimal) *Decimal {
+ d.Big = new(decimal.Big)
+ d.Big.Copy(d2.Big)
+ return d
+}