diff --git a/apier/v1/apier.go b/apier/v1/apier.go index d04e670b4..b674dbcb1 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -1027,7 +1027,7 @@ func (self *ApierV1) LoadCache(args utils.AttrReloadCache, reply *string) (err e if args.FlushAll { cache.Flush() } - var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string + var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string if args.DestinationIDs == nil { dstIDs = nil } else { @@ -1128,8 +1128,13 @@ func (self *ApierV1) LoadCache(args utils.AttrReloadCache, reply *string) (err e } else { fltrIDs = *args.FilterIDs } + if args.LCRProfileIDs == nil { + lcrPrfIDs = nil + } else { + lcrPrfIDs = *args.LCRProfileIDs + } - if err := self.DataManager.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs); err != nil { + if err := self.DataManager.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK @@ -1276,6 +1281,13 @@ func (self *ApierV1) FlushCache(args utils.AttrReloadCache, reply *string) (err cache.RemKey(utils.FilterPrefix+key, true, utils.NonTransactional) } } + if args.LCRProfileIDs == nil { + cache.RemPrefixKey(utils.LCRProfilePrefix, true, utils.NonTransactional) + } else if len(*args.LCRProfileIDs) != 0 { + for _, key := range *args.LCRProfileIDs { + cache.RemKey(utils.LCRProfilePrefix+key, true, utils.NonTransactional) + } + } *reply = utils.OK return @@ -1302,6 +1314,7 @@ func (self *ApierV1) GetCacheStats(attrs utils.AttrCacheStats, reply *utils.Cach cs.Thresholds = cache.CountEntries(utils.ThresholdPrefix) cs.ThresholdProfiles = cache.CountEntries(utils.ThresholdProfilePrefix) cs.Filters = cache.CountEntries(utils.FilterPrefix) + cs.LCRProfiles = cache.CountEntries(utils.LCRProfilePrefix) if self.CdrStatsSrv != nil { var queueIds []string @@ -1691,6 +1704,25 @@ func (v1 *ApierV1) GetCacheKeys(args utils.ArgsCacheKeys, reply *utils.ArgsCache } } + if args.LCRProfileIDs != nil { + var ids []string + if len(*args.LCRProfileIDs) != 0 { + for _, id := range *args.LCRProfileIDs { + if _, hasIt := cache.Get(utils.LCRProfilePrefix + id); hasIt { + ids = append(ids, id) + } + } + } else { + for _, id := range cache.GetEntryKeys(utils.LCRProfilePrefix) { + ids = append(ids, id[len(utils.LCRProfilePrefix):]) + } + } + ids = args.Paginator.PaginateStringSlice(ids) + if len(ids) != 0 { + reply.LCRProfileIDs = &ids + } + } + return } @@ -1727,6 +1759,7 @@ func (self *ApierV1) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, path.Join(attrs.FolderPath, utils.StatsCsv), path.Join(attrs.FolderPath, utils.ThresholdsCsv), path.Join(attrs.FolderPath, utils.FiltersCsv), + path.Join(attrs.FolderPath, utils.LCRCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/apier/v1/lcrs.go b/apier/v1/lcrs.go new file mode 100644 index 000000000..280041407 --- /dev/null +++ b/apier/v1/lcrs.go @@ -0,0 +1,67 @@ +/* +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 ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +// GetLCRProfile returns a LCDR configuration +func (apierV1 *ApierV1) GetLCRProfile(arg utils.TenantID, reply *engine.LCRProfile) error { + if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing + return utils.NewErrMandatoryIeMissing(missing...) + } + if rcfg, err := apierV1.DataManager.GetLCRProfile(arg.Tenant, arg.ID, false, utils.NonTransactional); err != nil { + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err + } else { + *reply = *rcfg + } + return nil +} + +//SetLCRProfile add a new LCR configuration +func (apierV1 *ApierV1) SetLCRProfile(res *engine.LCRProfile, reply *string) error { + if missing := utils.MissingStructFields(res, []string{"Tenant", "ID"}); len(missing) != 0 { + return utils.NewErrMandatoryIeMissing(missing...) + } + if err := apierV1.DataManager.SetLCRProfile(res); err != nil { + return utils.APIErrorHandler(err) + } + *reply = utils.OK + return nil +} + +//RemResourceProfile remove a specific resource configuration +func (apierV1 *ApierV1) RemLCRProfile(arg utils.TenantID, reply *string) error { + if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing + return utils.NewErrMandatoryIeMissing(missing...) + } + if err := apierV1.DataManager.RemoveLCRProfile(arg.Tenant, arg.ID, utils.NonTransactional); err != nil { + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err + } + *reply = utils.OK + return nil +} diff --git a/apier/v1/smgenericv1_it_test.go b/apier/v1/smgenericv1_it_test.go index 593d32c0a..926f31c3f 100644 --- a/apier/v1/smgenericv1_it_test.go +++ b/apier/v1/smgenericv1_it_test.go @@ -103,7 +103,7 @@ func TestSMGV1CacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := smgV1Rpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) diff --git a/apier/v2/apier.go b/apier/v2/apier.go index cd455dbc8..047d3daf0 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -144,6 +144,7 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, path.Join(attrs.FolderPath, utils.StatsCsv), path.Join(attrs.FolderPath, utils.ThresholdsCsv), path.Join(attrs.FolderPath, utils.FiltersCsv), + path.Join(attrs.FolderPath, utils.LCRCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) @@ -184,7 +185,8 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, - utils.FilterPrefix} { + utils.FilterPrefix, + utils.LCRProfilePrefix} { loadedIDs, _ := loader.GetLoadedIds(prfx) if err := self.DataManager.CacheDataFromDB(prfx, loadedIDs, true); err != nil { return utils.NewErrServerError(err) diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index 7994eb181..3a0c398a3 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -43,7 +43,7 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) - var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string + var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string if cCfg, has := cfg.CacheConfig[utils.CacheDestinations]; !has || !cCfg.Precache { dstIDs = make([]string, 0) // Don't cache any } @@ -104,9 +104,12 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC if cCfg, has := cfg.CacheConfig[utils.CacheFilters]; !has || !cCfg.Precache { fltrIDs = make([]string, 0) } + if cCfg, has := cfg.CacheConfig[utils.CacheLCRProfiles]; !has || !cCfg.Precache { + lcrPrfIDs = make([]string, 0) + } // ToDo: Add here timings - if err := dm.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs); err != nil { + if err := dm.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs); err != nil { utils.Logger.Crit(fmt.Sprintf(" Cache rating error: %s", err.Error())) exitChan <- true return diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 920012514..69325d674 100755 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -148,6 +148,7 @@ func main() { path.Join(*dataPath, utils.StatsCsv), path.Join(*dataPath, utils.ThresholdsCsv), path.Join(*dataPath, utils.FiltersCsv), + path.Join(*dataPath, utils.LCRCsv), ) } diff --git a/cmd/cgr-tester/cgr-tester.go b/cmd/cgr-tester/cgr-tester.go index 30dbb0acd..82ab90eac 100644 --- a/cmd/cgr-tester/cgr-tester.go +++ b/cmd/cgr-tester/cgr-tester.go @@ -67,7 +67,7 @@ func durInternalRater(cd *engine.CallDescriptor) (time.Duration, error) { } defer dm.DataDB().Close() engine.SetDataStorage(dm) - if err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil { + if err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil { return nilDuration, fmt.Errorf("Cache rating error: %s", err.Error()) } log.Printf("Runnning %d cycles...", *runs) diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index 797245dd1..671e5f08e 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -46,6 +46,7 @@ // "derived_chargers": {"limit": 10000, "ttl":"0s", "precache": false}, // control derived charging rule caching // "resource_limits": {"limit": 10000, "ttl":"0s", "precache": false}, // control resource limits caching // "timings": {"limit": 10000, "ttl":"0s", "precache": false}, // control timings caching +// "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, // control lcr_rofiles caching // }, diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json index 640c89286..cc6f6d257 100644 --- a/data/conf/samples/tutmongo/cgrates.json +++ b/data/conf/samples/tutmongo/cgrates.json @@ -49,6 +49,7 @@ "thresholds": {"limit": 10000, "ttl":"0s", "precache": true}, "threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, "filters": {"limit": 10000, "ttl":"0s", "precache": true}, + "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, }, diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json index 3468f3e06..6b5be1e22 100644 --- a/data/conf/samples/tutmysql/cgrates.json +++ b/data/conf/samples/tutmysql/cgrates.json @@ -42,6 +42,7 @@ "thresholds": {"limit": 10000, "ttl":"0s", "precache": true}, "threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, "filters": {"limit": 10000, "ttl":"0s", "precache": true}, + "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, }, diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 36553caa1..042fc24d9 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -487,6 +487,30 @@ CREATE TABLE tp_filters ( UNIQUE KEY `unique_tp_filters` (`tpid`,`tenant`, `id`, `filter_type`, `filter_field_name`) ); +-- +-- Table structure for table `tp_lcr` +-- + +DROP TABLE IF EXISTS tp_lcrs; +CREATE TABLE tp_lcrs ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `tpid` varchar(64) NOT NULL, + `tenant` varchar(64) NOT NULL, + `id` varchar(64) NOT NULL, + `filter_ids` varchar(64) NOT NULL, + `activation_interval` varchar(64) NOT NULL, + `strategy` varchar(32) NOT NULL, + `strategy_params` varchar(64) NOT NULL, + `supplier_id` varchar(32) NOT NULL, + `ratingplan_ids` varchar(64) NOT NULL, + `stat_ids` varchar(64) NOT NULL, + `weight` decimal(8,2) NOT NULL, + `created_at` TIMESTAMP, + PRIMARY KEY (`pk`), + KEY `tpid` (`tpid`), + UNIQUE KEY `unique_tp_lcr` (`tpid`,`tenant`, `id`,`filter_ids` ) +); + -- -- Table structure for table `versions` -- @@ -497,5 +521,5 @@ CREATE TABLE versions ( `item` varchar(64) NOT NULL, `version` int(11) NOT NULL, PRIMARY KEY (`id`), - UNIQUE KEY `item` (`item`) + UNIQUE KEY `id_item` (`id`,`item`) ); diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 749ff012c..2a99637ae 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -480,7 +480,28 @@ CREATE TABLE tp_filters ( CREATE INDEX tp_filters_idx ON tp_filters (tpid); CREATE INDEX tp_filters_unique ON tp_filters ("tpid","tenant", "id", "filter_type", "filter_field_name"); + -- + -- Table structure for table `tp_resources` + -- + DROP TABLE IF EXISTS tp_lcrs; + CREATE TABLE tp_lcrs ( + "pk" SERIAL PRIMARY KEY, + "tpid" varchar(64) NOT NULL, + "tenant"varchar(64) NOT NULL, + "id" varchar(64) NOT NULL, + "filter_ids" varchar(64) NOT NULL, + "activation_interval" varchar(64) NOT NULL, + "strategy" varchar(32) NOT NULL, + "strategy_params" varchar(64) NOT NULL, + "supplier_id" varchar(32) NOT NULL, + "ratingplan_ids" varchar(64) NOT NULL, + "stat_ids" varchar(64) NOT NULL, + "weight" decimal(8,2) NOT NULL, + "created_at" TIMESTAMP WITH TIME ZONE + ); + CREATE INDEX tp_lcrs_idx ON tp_lcrs (tpid); + CREATE INDEX tp_lcrs_unique ON tp_lcrs ("tpid", "tenant", "id", "filter_ids"); -- -- Table structure for table `versions` @@ -491,5 +512,5 @@ CREATE TABLE versions ( "id" SERIAL PRIMARY KEY, "item" varchar(64) NOT NULL, "version" INTEGER NOT NULL, - UNIQUE (item) + UNIQUE ("id","item") ); diff --git a/data/tariffplans/tutorial/Filters.csv b/data/tariffplans/tutorial/Filters.csv index 4c1f4ffa0..180334d4a 100644 --- a/data/tariffplans/tutorial/Filters.csv +++ b/data/tariffplans/tutorial/Filters.csv @@ -3,6 +3,7 @@ cgrates.org,FLTR_1,*string,Account,1001;1002,2014-07-29T15:00:00Z cgrates.org,FLTR_1,*string_prefix,Destination,10;20, cgrates.org,FLTR_1,*rsr_fields,,Subject(~^1.*1$);Destination(1002), cgrates.org,FLTR_ACNT_1007,*string,Account,1007,2014-07-29T15:00:00Z +cgrates.org,FLTR_ACNT_dan,*string,Account,dan,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_DE,*destinations,Destination,DST_DE,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_NL,*destinations,Destination,DST_NL,2014-07-29T15:00:00Z cgrates.org,FLTR_ACNT_BALANCE_1,*string,Account,1001;1002,2014-07-29T15:00:00Z diff --git a/engine/libtest.go b/engine/libtest.go index 62d0ffda2..3810f0078 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -135,6 +135,7 @@ func LoadTariffPlanFromFolder(tpPath, timezone string, dm *DataManager, disable_ path.Join(tpPath, utils.StatsCsv), path.Join(tpPath, utils.ThresholdsCsv), path.Join(tpPath, utils.FiltersCsv), + path.Join(tpPath, utils.LCRCsv), ), "", timezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index e0f0e924a..c83839f7e 100755 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -289,6 +289,10 @@ cgrates.org,FLTR_1,*rsr_fields,,Subject(~^1.*1$);Destination(1002), cgrates.org,FLTR_ACNT_dan,*string,Account,dan,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_DE,*destinations,Destination,DST_DE,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_NL,*destinations,Destination,DST_NL,2014-07-29T15:00:00Z +` + lcrProfiles = ` +#Tenant,ID,FilterIDs,ActivationInterval,Strategy,StrategyParams,SupplierID,RatingPlanIDs,StatIDs,Weight +cgrates.org,LCR_1,FLTR_ACNT_dan;FLTR_DST_DE,2014-07-29T15:00:00Z,*lowest_cost,,supplier1,RPL_1,,20 ` ) @@ -296,7 +300,7 @@ var csvr *TpReader func init() { csvr = NewTpReader(dm.dataDB, NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resProfiles, stats, thresholds, filters), testTPID, "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resProfiles, stats, thresholds, filters, lcrProfiles), testTPID, "") if err := csvr.LoadDestinations(); err != nil { log.Print("error in LoadDestinations:", err) @@ -358,9 +362,12 @@ func init() { if err := csvr.LoadThresholds(); err != nil { log.Print("error in LoadThresholds:", err) } + if err := csvr.LoadLCRProfiles(); err != nil { + log.Print("error in LoadThresholds:", err) + } csvr.WriteToDatabase(false, false, false) cache.Flush() - dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) } func TestLoadDestinations(t *testing.T) { @@ -1439,7 +1446,6 @@ func TestLoadResourceProfiles(t *testing.T) { } else if !reflect.DeepEqual(eResProfiles[resKey], csvr.resProfiles[resKey]) { t.Errorf("Expecting: %+v, received: %+v", eResProfiles[resKey], csvr.resProfiles[resKey]) } - } func TestLoadStatProfiles(t *testing.T) { @@ -1612,6 +1618,32 @@ func TestLoadFilters(t *testing.T) { } } +func TestLoadLCRProfiles(t *testing.T) { + eLCRprofiles := map[utils.TenantID]*utils.TPLCRProfile{ + utils.TenantID{Tenant: "cgrates.org", ID: "LCR_1"}: &utils.TPLCRProfile{ + TPid: testTPID, + Tenant: "cgrates.org", + ID: "LCR_1", + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-29T15:00:00Z", + }, + Strategy: "*lowest_cost", + StrategyParams: nil, + SupplierID: "supplier1", + RatingPlanIDs: []string{"RPL_1"}, + StatIDs: nil, + Weight: 20, + }, + } + resKey := utils.TenantID{Tenant: "cgrates.org", ID: "LCR_1"} + if len(csvr.lcrProfiles) != len(eLCRprofiles) { + t.Errorf("Failed to load LCRProfiles: %s", utils.ToIJSON(csvr.lcrProfiles)) + } else if !reflect.DeepEqual(eLCRprofiles[resKey], csvr.lcrProfiles[resKey]) { + t.Errorf("Expecting: %+v, received: %+v", eLCRprofiles[resKey], csvr.lcrProfiles[resKey]) + } +} + func TestLoadResource(t *testing.T) { eResources := []*utils.TenantID{ &utils.TenantID{ diff --git a/engine/loader_it_test.go b/engine/loader_it_test.go index ad6c89f55..f66a8bb6b 100755 --- a/engine/loader_it_test.go +++ b/engine/loader_it_test.go @@ -108,6 +108,7 @@ func TestLoaderITLoadFromCSV(t *testing.T) { path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.StatsCsv), path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.ThresholdsCsv), path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.FiltersCsv), + path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.LCRCsv), ), "", "") if err = loader.LoadDestinations(); err != nil { @@ -164,6 +165,9 @@ func TestLoaderITLoadFromCSV(t *testing.T) { if err = loader.LoadThresholds(); err != nil { t.Error("Failed loading thresholds: ", err.Error()) } + if err = loader.LoadLCRProfiles(); err != nil { + t.Error("Failed loading lcr profiles: ", err.Error()) + } if err := loader.WriteToDatabase(true, false, false); err != nil { t.Error("Could not write data into dataDb: ", err.Error()) } @@ -353,6 +357,20 @@ func TestLoaderITWriteToDatabase(t *testing.T) { t.Errorf("Expecting: %v, received: %v", sts, rcv) } } + + for tenatid, th := range loader.lcrProfiles { + rcv, err := loader.dm.GetLCRProfile(tenatid.Tenant, tenatid.ID, true, utils.NonTransactional) + if err != nil { + t.Errorf("Failed GetLCRProfile, tenant: %s, id: %s, error: %s ", th.Tenant, th.ID, err.Error()) + } + sts, err := APItoLCRProfile(th, "UTC") + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(sts, rcv) { + t.Errorf("Expecting: %v, received: %v", sts, rcv) + } + } } // Imports data from csv files in tpScenario to storDb diff --git a/engine/model_helpers.go b/engine/model_helpers.go index decc8b6bc..8a621ad91 100755 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -2419,9 +2419,9 @@ func FilterToTPFilter(f *Filter) (tpFltr *utils.TPFilter) { return } -type TpLCRProfiles []*TpLCRProfile +type TpLCRs []*TpLCR -func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { +func (tps TpLCRs) AsTPLCRProfile() (result []*utils.TPLCRProfile) { mst := make(map[string]*utils.TPLCRProfile) for _, tp := range tps { th, found := mst[tp.ID] @@ -2440,8 +2440,8 @@ func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { th.StrategyParams = append(th.StrategyParams, strategyParam) } } - if tp.RatingPlanIDs != "" { - ratingPlansIDsSplit := strings.Split(tp.RatingPlanIDs, utils.INFIELD_SEP) + if tp.RatingplanIDs != "" { + ratingPlansIDsSplit := strings.Split(tp.RatingplanIDs, utils.INFIELD_SEP) for _, ratingPlanID := range ratingPlansIDsSplit { th.RatingPlanIDs = append(th.RatingPlanIDs, ratingPlanID) } @@ -2483,10 +2483,10 @@ func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { return } -func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRProfiles) { +func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRs) { if st != nil { for i, fltr := range st.FilterIDs { - mdl := &TpLCRProfile{ + mdl := &TpLCR{ Tenant: st.Tenant, Tpid: st.TPid, ID: st.ID, @@ -2503,9 +2503,9 @@ func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRProfiles) { } for i, val := range st.RatingPlanIDs { if i != 0 { - mdl.RatingPlanIDs += utils.INFIELD_SEP + mdl.RatingplanIDs += utils.INFIELD_SEP } - mdl.RatingPlanIDs += val + mdl.RatingplanIDs += val } for i, val := range st.StatIDs { if i != 0 { diff --git a/engine/models.go b/engine/models.go index 8af59b9aa..2a035f367 100755 --- a/engine/models.go +++ b/engine/models.go @@ -525,7 +525,7 @@ type TpFilter struct { CreatedAt time.Time } -type TpLCRProfile struct { +type TpLCR struct { PK uint `gorm:"primary_key"` Tpid string Tenant string `index:"0" re:""` @@ -535,7 +535,7 @@ type TpLCRProfile struct { Strategy string `index:"4" re:""` StrategyParams string `index:"5" re:""` SupplierID string `index:"6" re:""` - RatingPlanIDs string `index:"7" re:""` + RatingplanIDs string `index:"7" re:""` StatIDs string `index:"8" re:""` Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time diff --git a/engine/storage_csv.go b/engine/storage_csv.go index d6e3fc9da..7dad38c77 100755 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -33,26 +33,26 @@ type CSVStorage struct { readerFunc func(string, rune, int) (*csv.Reader, *os.File, error) // file names destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn, - sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string + sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string } func NewFileCSVStorage(sep rune, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, - actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string) *CSVStorage { + actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string) *CSVStorage { c := new(CSVStorage) c.sep = sep c.readerFunc = openFileCSVStorage c.destinationsFn, c.timingsFn, c.ratesFn, c.destinationratesFn, c.destinationratetimingsFn, c.ratingprofilesFn, - c.sharedgroupsFn, c.lcrFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn, c.cdrStatsFn, c.usersFn, c.aliasesFn, c.resProfilesFn, c.statsFn, c.thresholdsFn, c.filterFn = destinationsFn, timingsFn, - ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn + c.sharedgroupsFn, c.lcrFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn, c.cdrStatsFn, c.usersFn, c.aliasesFn, c.resProfilesFn, c.statsFn, c.thresholdsFn, c.filterFn, c.lcrProfilesFn = destinationsFn, timingsFn, + ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn return c } func NewStringCSVStorage(sep rune, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, - actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string) *CSVStorage { + actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string) *CSVStorage { c := NewFileCSVStorage(sep, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, - ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn) + ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn) c.readerFunc = openStringCSVStorage return c } @@ -705,6 +705,34 @@ func (csvs *CSVStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return tpFilter.AsTPFilter(), nil } +func (csvs *CSVStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile, error) { + csvReader, fp, err := csvs.readerFunc(csvs.lcrProfilesFn, csvs.sep, getColumnCount(TpLCR{})) + if err != nil { + //log.Print("Could not load lcr profiles file: ", err) + // allow writing of the other values + return nil, nil + } + if fp != nil { + defer fp.Close() + } + var tpResLimits TpLCRs + for record, err := csvReader.Read(); err != io.EOF; record, err = csvReader.Read() { + if err != nil { + log.Printf("bad line in %s, %s\n", csvs.lcrProfilesFn, err.Error()) + return nil, err + } + if tpResLimit, err := csvLoad(TpLCR{}, record); err != nil { + log.Print("error loading LCRProfiles: ", err) + return nil, err + } else { + tpLimit := tpResLimit.(TpLCR) + tpLimit.Tpid = tpid + tpResLimits = append(tpResLimits, &tpLimit) + } + } + return tpResLimits.AsTPLCRProfile(), nil +} + func (csvs *CSVStorage) GetTpIds(colName string) ([]string, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 7dce8dec6..04cfb013f 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1253,7 +1253,7 @@ func (ms *MongoStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile filter["id"] = id } var results []*utils.TPLCRProfile - session, col := ms.conn(utils.TBLTPLCRProfiles) + session, col := ms.conn(utils.TBLTPLcr) defer session.Close() err := col.Find(filter).All(&results) if len(results) == 0 { @@ -1266,7 +1266,7 @@ func (ms *MongoStorage) SetTPLCRProfiles(tpTHs []*utils.TPLCRProfile) (err error if len(tpTHs) == 0 { return } - session, col := ms.conn(utils.TBLTPLCRProfiles) + session, col := ms.conn(utils.TBLTPLcr) defer session.Close() tx := col.Bulk() for _, tp := range tpTHs { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index b1b1a5eab..a765e20b8 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -107,7 +107,8 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, utils.TBLTPDerivedChargers, utils.TBLTPUsers, utils.TBLTPAliases, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPThresholds, - utils.TBLTPFilters, utils.TBLSMCosts, utils.TBLCDRs, utils.TBLTPActionPlans, utils.TBLVersions, + utils.TBLTPFilters, utils.TBLSMCosts, utils.TBLCDRs, utils.TBLTPActionPlans, + utils.TBLVersions, utils.TBLTPLcr, } for _, tbl := range tbls { if self.db.HasTable(tbl) { @@ -126,7 +127,7 @@ func (self *SQLStorage) GetTpIds(colName string) ([]string, error) { qryStr := fmt.Sprintf(" (SELECT tpid FROM %s)", colName) if colName == "" { qryStr = fmt.Sprintf( - "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", + "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, @@ -146,7 +147,8 @@ func (self *SQLStorage) GetTpIds(colName string) ([]string, error) { utils.TBLTPStats, utils.TBLTPThresholds, utils.TBLTPFilters, - utils.TBLTPActionPlans) + utils.TBLTPActionPlans, + utils.TBLTPLcr) } rows, err = self.Db.Query(qryStr) if err != nil { @@ -234,7 +236,7 @@ func (self *SQLStorage) RemTpData(table, tpid string, args map[string]string) er if len(table) == 0 { // Remove tpid out of all tables for _, tblName := range []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans, utils.TBLTPRateProfiles, utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, - utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPFilters} { + utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPFilters, utils.TBLTPLcr} { if err := tx.Table(tblName).Where("tpid = ?", tpid).Delete(nil).Error; err != nil { tx.Rollback() return err @@ -689,18 +691,18 @@ func (self *SQLStorage) SetTPFilters(ths []*utils.TPFilter) error { return nil } -func (self *SQLStorage) SetTPLCRProfile(ths []*utils.TPLCRProfile) error { - if len(ths) == 0 { +func (self *SQLStorage) SetTPLCRProfiles(sts []*utils.TPLCRProfile) error { + if len(sts) == 0 { return nil } tx := self.db.Begin() - for _, th := range ths { + for _, stq := range sts { // Remove previous - if err := tx.Where(&TpLCRProfile{Tpid: th.TPid, ID: th.ID}).Delete(TpLCRProfile{}).Error; err != nil { + if err := tx.Where(&TpLCR{Tpid: stq.TPid, ID: stq.ID}).Delete(TpLCR{}).Error; err != nil { tx.Rollback() return err } - for _, mst := range APItoModelTPLCRProfile(th) { + for _, mst := range APItoModelTPLCRProfile(stq) { if err := tx.Save(&mst).Error; err != nil { tx.Rollback() return err @@ -1689,6 +1691,22 @@ func (self *SQLStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return aths, nil } +func (self *SQLStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile, error) { + var rls TpLCRs + q := self.db.Where("tpid = ?", tpid) + if len(id) != 0 { + q = q.Where("id = ?", id) + } + if err := q.Find(&rls).Error; err != nil { + return nil, err + } + arls := rls.AsTPLCRProfile() + if len(arls) == 0 { + return arls, utils.ErrNotFound + } + return arls, nil +} + // GetVersions returns slice of all versions or a specific version if tag is specified func (self *SQLStorage) GetVersions(itm string) (vrs Versions, err error) { q := self.db.Model(&TBLVersion{}) diff --git a/engine/storage_test.go b/engine/storage_test.go index 000accc23..9f455e4c6 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -102,7 +102,7 @@ func TestStorageCacheRefresh(t *testing.T) { dm.DataDB().GetDestination("T11", false, utils.NonTransactional) dm.DataDB().SetDestination(&Destination{"T11", []string{"1"}}, utils.NonTransactional) t.Log("Test cache refresh") - err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if err != nil { t.Error("Error cache rating: ", err) } diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 90acbcff6..72fa71a1b 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -1782,7 +1782,7 @@ func (tpr *TpReader) LoadLCRProfilesFiltered(tag string) (err error) { } else if !has { tpr.lcrTntID = append(tpr.lcrTntID, &utils.TenantID{Tenant: tntID.Tenant, ID: tntID.ID}) } - // index resource for filters + // index lcr profile for filters if _, has := tpr.lcrIndexers[tntID.Tenant]; !has { if tpr.lcrIndexers[tntID.Tenant], err = NewReqFilterIndexer(tpr.dm, resIndxrKey); err != nil { return @@ -2212,7 +2212,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err } if verbose { - log.Print("LCRProfiles:") + log.Print("LCR Profiles:") } for _, tpTH := range tpr.lcrProfiles { th, err := APItoLCRProfile(tpTH, tpr.timezone) @@ -2300,7 +2300,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err } if verbose { - log.Print("Indexing LCRProfiles") + log.Print("Indexing LCR Profiles") } for tenant, fltrIdxer := range tpr.lcrIndexers { if err := fltrIdxer.StoreIndexes(); err != nil { diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 01332eb22..733ccd30e 100755 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -61,6 +61,7 @@ var fileHandlers = map[string]func(*TPCSVImporter, string) error{ utils.StatsCsv: (*TPCSVImporter).importStats, utils.ThresholdsCsv: (*TPCSVImporter).importThresholds, utils.FiltersCsv: (*TPCSVImporter).importFilters, + utils.LCRCsv: (*TPCSVImporter).importLCR, } func (self *TPCSVImporter) Run() error { @@ -85,6 +86,7 @@ func (self *TPCSVImporter) Run() error { path.Join(self.DirPath, utils.StatsCsv), path.Join(self.DirPath, utils.ThresholdsCsv), path.Join(self.DirPath, utils.FiltersCsv), + path.Join(self.DirPath, utils.LCRCsv), ) files, _ := ioutil.ReadDir(self.DirPath) for _, f := range files { @@ -397,3 +399,14 @@ func (self *TPCSVImporter) importFilters(fn string) error { } return self.StorDb.SetTPFilters(sts) } + +func (self *TPCSVImporter) importLCR(fn string) error { + if self.Verbose { + log.Printf("Processing file: <%s> ", fn) + } + rls, err := self.csvr.GetTPLCRProfiles(self.TPid, "") + if err != nil { + return err + } + return self.StorDb.SetTPLCRProfiles(rls) +} diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index ea8cafa04..6b45644d5 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -57,15 +57,16 @@ ENABLE_ACNT,*enable_account,,,,,,,,,,,,,,false,false,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dbAcntActs.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadAll(); err != nil { t.Fatal(err) } csvr.WriteToDatabase(false, false, false) cache.Flush() - dbAcntActs.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dbAcntActs.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) expectAcnt := &engine.Account{ID: "cgrates.org:1"} if acnt, err := dbAcntActs.DataDB().GetAccount("cgrates.org:1"); err != nil { diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index 763f0dd20..ee0f14524 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -64,8 +64,9 @@ RP_ANY,DR_ANY_1CNT,*any,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dbAuth.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadAll(); err != nil { t.Fatal(err) } @@ -77,7 +78,7 @@ RP_ANY,DR_ANY_1CNT,*any,10` } cache.Flush() - dbAuth.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dbAuth.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/costs1_test.go b/general_tests/costs1_test.go index 3990197d3..9c2926401 100644 --- a/general_tests/costs1_test.go +++ b/general_tests/costs1_test.go @@ -52,7 +52,7 @@ RP_SMS1,DR_SMS_1,ALWAYS,10` *out,cgrates.org,data,*any,2012-01-01T00:00:00Z,RP_DATA1,, *out,cgrates.org,sms,*any,2012-01-01T00:00:00Z,RP_SMS1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', dests, timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) @@ -74,7 +74,7 @@ RP_SMS1,DR_SMS_1,ALWAYS,10` } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 3 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/datachrg1_test.go b/general_tests/datachrg1_test.go index 5f818c7a2..e42489457 100644 --- a/general_tests/datachrg1_test.go +++ b/general_tests/datachrg1_test.go @@ -43,7 +43,7 @@ DR_DATA_2,*any,RT_DATA_1c,*up,4,0,` RP_DATA1,DR_DATA_2,TM2,10` ratingProfiles := `*out,cgrates.org,data,*any,2012-01-01T00:00:00Z,RP_DATA1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', "", timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ RP_DATA1,DR_DATA_2,TM2,10` } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 1 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index 01935f450..fae9da700 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -64,8 +64,9 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -112,7 +113,7 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/ddazmbl2_test.go b/general_tests/ddazmbl2_test.go index 910e6325f..654843f8e 100644 --- a/general_tests/ddazmbl2_test.go +++ b/general_tests/ddazmbl2_test.go @@ -64,8 +64,9 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dataDB2.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -112,7 +113,7 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() - dataDB2.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB2.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/ddazmbl3_test.go b/general_tests/ddazmbl3_test.go index 4230688cf..4d938f800 100644 --- a/general_tests/ddazmbl3_test.go +++ b/general_tests/ddazmbl3_test.go @@ -62,8 +62,9 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dataDB3.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -110,7 +111,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` t.Error("No account saved") } cache.Flush() - dataDB3.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB3.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/smschrg1_test.go b/general_tests/smschrg1_test.go index 0c0eca418..8fa89a76f 100644 --- a/general_tests/smschrg1_test.go +++ b/general_tests/smschrg1_test.go @@ -41,7 +41,7 @@ func TestSMSLoadCsvTpSmsChrg1(t *testing.T) { ratingPlans := `RP_SMS1,DR_SMS_1,ALWAYS,10` ratingProfiles := `*out,cgrates.org,sms,*any,2012-01-01T00:00:00Z,RP_SMS1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', "", timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) } @@ -59,7 +59,7 @@ func TestSMSLoadCsvTpSmsChrg1(t *testing.T) { } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 1 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/tut_smgeneric_it_test.go b/general_tests/tut_smgeneric_it_test.go index a69f9be62..2406bd84d 100644 --- a/general_tests/tut_smgeneric_it_test.go +++ b/general_tests/tut_smgeneric_it_test.go @@ -101,7 +101,7 @@ func TestTutSMGCacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := tutSMGRpc.Call("ApierV2.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV2.GetCacheStats: ", err.Error()) diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index e60872b31..f11238ae7 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -105,7 +105,7 @@ func TestTutITCacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := tutLocalRpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 1760db272..f5dd393a2 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -675,6 +675,7 @@ type ArgsCache struct { ThresholdIDs *[]string ThresholdProfileIDs *[]string FilterIDs *[]string + LCRProfileIDs *[]string } // Data used to do remote cache reloads via api @@ -716,6 +717,7 @@ type CacheStats struct { Thresholds int ThresholdProfiles int Filters int + LCRProfiles int // LCRProfiles } type AttrExpFileCdrs struct { diff --git a/utils/consts.go b/utils/consts.go index 337a692ec..9b37b4311 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -113,7 +113,7 @@ const ( TBLTPStats = "tp_stats" TBLTPThresholds = "tp_thresholds" TBLTPFilters = "tp_filters" - TBLTPLCRProfiles = "tp_lcr" + TBLTPLcr = "tp_lcrs" TBLSMCosts = "sm_costs" TBLCDRs = "cdrs" TBLVersions = "versions" @@ -137,6 +137,7 @@ const ( StatsCsv = "Stats.csv" ThresholdsCsv = "Thresholds.csv" FiltersCsv = "Filters.csv" + LCRCsv = "Lcr.csv" ROUNDING_UP = "*up" ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down"