From ddc2240c67d1a2a8b5e083199ef864ba940e7fa7 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 29 Jul 2013 18:21:13 +0200 Subject: [PATCH] TPCSVImporter RatingProfiles, changed RateProfile into RatingProfile in APIs for consistency --- ...{tprateprofiles.go => tpratingprofiles.go} | 41 +++++++---- cmd/cgr-loader/cgr-loader.go | 4 +- .../mysql/create_tariffplan_tables.sql | 2 +- ...eprofiles.rst => api_tpratingprofiles.rst} | 52 ++++++------- docs/apicalls.rst | 6 +- engine/loader_db.go | 14 ++-- engine/ratingprofile.go | 6 +- engine/storage_interface.go | 8 +- engine/storage_map.go | 8 +- engine/storage_mongo.go | 8 +- engine/storage_redis.go | 8 +- engine/storage_sql.go | 73 +++++++++++-------- engine/tpimporter_csv.go | 43 +++++++++++ utils/apitpdata.go | 6 +- utils/consts.go | 2 +- 15 files changed, 175 insertions(+), 106 deletions(-) rename apier/{tprateprofiles.go => tpratingprofiles.go} (54%) rename docs/{api_tprateprofiles.rst => api_tpratingprofiles.rst} (76%) diff --git a/apier/tprateprofiles.go b/apier/tpratingprofiles.go similarity index 54% rename from apier/tprateprofiles.go rename to apier/tpratingprofiles.go index 4ec4eefd7..ca6a6908c 100644 --- a/apier/tprateprofiles.go +++ b/apier/tpratingprofiles.go @@ -24,36 +24,49 @@ import ( "errors" "fmt" "github.com/cgrates/cgrates/utils" + "github.com/cgrates/cgrates/engine" ) -// Creates a new RateProfile within a tariff plan -func (self *Apier) SetTPRateProfile(attrs utils.TPRateProfile, reply *string) error { - if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RateProfileId", "Tenant", "TOR", "Direction", "Subject", "RatingActivations"}); len(missing) != 0 { +// Creates a new RatingProfile within a tariff plan +func (self *Apier) SetTPRatingProfile(attrs utils.TPRatingProfile, reply *string) error { + if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RatingProfileId", "Tenant", "TOR", "Direction", "Subject", "RatingActivations"}); len(missing) != 0 { return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } - if exists, err := self.StorDb.ExistsTPRateProfile(attrs.TPid, attrs.RateProfileId); err != nil { + if exists, err := self.StorDb.ExistsTPRatingProfile(attrs.TPid, attrs.RatingProfileId); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if exists { return errors.New(utils.ERR_DUPLICATE) } - if err := self.StorDb.SetTPRateProfile(&attrs); err != nil { + rps := make([]*engine.RatingProfile, len(attrs.RatingActivations)) + for idx,ra := range attrs.RatingActivations { + rps[idx] = &engine.RatingProfile{Tag: attrs.RatingProfileId, + Tenant: attrs.Tenant, + TOR: attrs.TOR, + Direction: attrs.Direction, + Subject: attrs.Subject, + ActivationTime: ra.ActivationTime, + DestRatesTimingTag: ra.DestRateTimingId, + RatesFallbackSubject: attrs.RatesFallbackSubject, + } + } + if err := self.StorDb.SetTPRatingProfiles( attrs.TPid, map[string][]*engine.RatingProfile{ attrs.RatingProfileId: rps } ); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } *reply = "OK" return nil } -type AttrGetTPRateProfile struct { +type AttrGetTPRatingProfile struct { TPid string // Tariff plan id - RateProfileId string // RateProfile id + RatingProfileId string // RatingProfile id } -// Queries specific RateProfile on tariff plan -func (self *Apier) GetTPRateProfile(attrs AttrGetTPRateProfile, reply *utils.TPRateProfile) error { - if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RateProfileId"}); len(missing) != 0 { //Params missing +// Queries specific RatingProfile on tariff plan +func (self *Apier) GetTPRatingProfile(attrs AttrGetTPRatingProfile, reply *utils.TPRatingProfile) error { + if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RatingProfileId"}); len(missing) != 0 { //Params missing return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } - if dr, err := self.StorDb.GetTPRateProfile(attrs.TPid, attrs.RateProfileId); err != nil { + if dr, err := self.StorDb.GetTPRatingProfile(attrs.TPid, attrs.RatingProfileId); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if dr == nil { return errors.New(utils.ERR_NOT_FOUND) @@ -63,12 +76,12 @@ func (self *Apier) GetTPRateProfile(attrs AttrGetTPRateProfile, reply *utils.TPR return nil } -// Queries RateProfile identities on specific tariff plan. -func (self *Apier) GetTPRateProfileIds(attrs utils.AttrTPRateProfileIds, reply *[]string) error { +// Queries RatingProfile identities on specific tariff plan. +func (self *Apier) GetTPRatingProfileIds(attrs utils.AttrTPRatingProfileIds, reply *[]string) error { if missing := utils.MissingStructFields(&attrs, []string{"TPid"}); len(missing) != 0 { //Params missing return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } - if ids, err := self.StorDb.GetTPRateProfileIds(&attrs); err != nil { + if ids, err := self.StorDb.GetTPRatingProfileIds(&attrs); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if ids == nil { return errors.New(utils.ERR_NOT_FOUND) diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index d60d6f60d..1a958f733 100644 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -52,7 +52,7 @@ var ( verbose = flag.Bool("verbose", false, "Enable detailed verbose logging output") fromStorDb = flag.Bool("from-stordb", false, "Load the tariff plan from storDb to dataDb") toStorDb = flag.Bool("to-stordb", false, "Import the tariff plan from files to storDb") - + runId = flag.String("runid", "", "Uniquely identify an import/load, postpended to some automatic fields") ) func main() { @@ -89,7 +89,7 @@ func main() { if *tpid == "" { log.Fatal("TPid required, please define it via *-tpid* command argument.") } - csvImporter := engine.TPCSVImporter{ *tpid, storDb, *dataPath, ',', *verbose } + csvImporter := engine.TPCSVImporter{ *tpid, storDb, *dataPath, ',', *verbose, *runId } if errImport := csvImporter.Run(); errImport != nil { log.Fatal(errImport) } diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index bead88034..4a7fa78b0 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -90,7 +90,7 @@ CREATE TABLE `tp_destrate_timings` ( -- Table structure for table `tp_rate_profiles` -- -CREATE TABLE `tp_rate_profiles` ( +CREATE TABLE `tp_rating_profiles` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tpid` char(40) NOT NULL, `tag` varchar(24) NOT NULL, diff --git a/docs/api_tprateprofiles.rst b/docs/api_tpratingprofiles.rst similarity index 76% rename from docs/api_tprateprofiles.rst rename to docs/api_tpratingprofiles.rst index 1015fdf32..376a9370e 100644 --- a/docs/api_tprateprofiles.rst +++ b/docs/api_tpratingprofiles.rst @@ -1,16 +1,16 @@ -Apier.SetTPRateProfile -++++++++++++++++++++++ +Apier.SetTPRatingProfile +++++++++++++++++++++++++ -Creates a new RateProfile within a tariff plan. +Creates a new RatingProfile within a tariff plan. **Request**: Data: :: - type TPRateProfile struct { + type TPRatingProfile struct { TPid string // Tariff plan id - RateProfileId string // RateProfile id + RatingProfileId string // RatingProfile id Tenant string // Tenant's Id TOR string // TypeOfRecord Direction string // Traffic direction, OUT is the only one supported for now @@ -24,18 +24,18 @@ Creates a new RateProfile within a tariff plan. DestRateTimingId string // Id of DestRateTiming profile } - Mandatory parameters: ``[]string{"TPid", "RateProfileId", "Tenant", "TOR", "Direction", "Subject", "RatingActivations"}`` + Mandatory parameters: ``[]string{"TPid", "RatingProfileId", "Tenant", "TOR", "Direction", "Subject", "RatingActivations"}`` *JSON sample*: :: { "id": 3, - "method": "Apier.SetTPRateProfile", + "method": "Apier.SetTPRatingProfile", "params": [ { "Direction": "OUT", - "RateProfileId": "SAMPLE_RP_2", + "RatingProfileId": "SAMPLE_RP_2", "RatingActivations": [ { "ActivationTime": 1373609003, @@ -79,35 +79,35 @@ Creates a new RateProfile within a tariff plan. ``SERVER_ERROR`` - Server error occurred. - ``DUPLICATE`` - The specified combination of TPid/RateProfileId already exists in StorDb. + ``DUPLICATE`` - The specified combination of TPid/RatingProfileId already exists in StorDb. -Apier.GetTPRateProfile -++++++++++++++++++++++ +Apier.GetTPRatingProfile +++++++++++++++++++++++++ -Queries specific RateProfile on tariff plan. +Queries specific RatingProfile on tariff plan. **Request**: Data: :: - type AttrGetTPRateProfile struct { + type AttrGetTPRatingProfile struct { TPid string // Tariff plan id - RateProfileId string // RateProfile id + RatingProfileId string // RatingProfile id } - Mandatory parameters: ``[]string{"TPid", "RateProfileId"}`` + Mandatory parameters: ``[]string{"TPid", "RatingProfileId"}`` *JSON sample*: :: { "id": 0, - "method": "Apier.GetTPRateProfile", + "method": "Apier.GetTPRatingProfile", "params": [ { - "RateProfileId": "SAMPLE_RP_2", + "RatingProfileId": "SAMPLE_RP_2", "TPid": "SAMPLE_TP" } ] @@ -118,9 +118,9 @@ Queries specific RateProfile on tariff plan. Data: :: - type TPRateProfile struct { + type TPRatingProfile struct { TPid string // Tariff plan id - RateProfileId string // RateProfile id + RatingProfileId string // RatingProfile id Tenant string // Tenant's Id TOR string // TypeOfRecord Direction string // Traffic direction, OUT is the only one supported for now @@ -142,7 +142,7 @@ Queries specific RateProfile on tariff plan. "id": 0, "result": { "Direction": "OUT", - "RateProfileId": "SAMPLE_RP_2", + "RatingProfileId": "SAMPLE_RP_2", "RatesFallbackSubject": "", "RatingActivations": [ { @@ -167,20 +167,20 @@ Queries specific RateProfile on tariff plan. ``SERVER_ERROR`` - Server error occurred. - ``NOT_FOUND`` - Requested RateProfile profile not found. + ``NOT_FOUND`` - Requested RatingProfile profile not found. -Apier.GetTPRateProfileIds -+++++++++++++++++++++++++ +Apier.GetTPRatingProfileIds ++++++++++++++++++++++++++++ -Queries specific RateProfile on tariff plan. Attribute parameters used as extra filters. +Queries specific RatingProfile on tariff plan. Attribute parameters used as extra filters. **Request**: Data: :: - type AttrTPRateProfileIds struct { + type AttrTPRatingProfileIds struct { TPid string // Tariff plan id Tenant string // Tenant's Id TOR string // TypeOfRecord @@ -195,7 +195,7 @@ Queries specific RateProfile on tariff plan. Attribute parameters used as extra { "id": 0, - "method": "Apier.GetTPRateProfileIds", + "method": "Apier.GetTPRatingProfileIds", "params": [ { "Subject": "dan", diff --git a/docs/apicalls.rst b/docs/apicalls.rst index 4afedbeb5..dc015cd7e 100644 --- a/docs/apicalls.rst +++ b/docs/apicalls.rst @@ -169,13 +169,13 @@ DestinationRateTimings api_tpdestratetimings -RateProfiles -~~~~~~~~~~~~ +RatingProfiles +~~~~~~~~~~~~~~ .. toctree:: :maxdepth: 2 - api_tprateprofiles + api_tpratingprofiles Actions ~~~~~~~ diff --git a/engine/loader_db.go b/engine/loader_db.go index 90213e278..0d7287fda 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -184,11 +184,11 @@ func (dbr *DbReader) LoadRatingProfiles() error { return err } for _, rp := range rpfs { - at := time.Unix(rp.activationTime, 0) + at := time.Unix(rp.ActivationTime, 0) for _, d := range dbr.destinations { - ap, exists := dbr.activationPeriods[rp.destRatesTimingTag] + ap, exists := dbr.activationPeriods[rp.DestRatesTimingTag] if !exists { - return errors.New(fmt.Sprintf("Could not load rating timing for tag: %v", rp.destRatesTimingTag)) + return errors.New(fmt.Sprintf("Could not load rating timing for tag: %v", rp.DestRatesTimingTag)) } newAP := &ActivationPeriod{ActivationTime: at} //copy(newAP.Intervals, ap.Intervals) @@ -211,12 +211,12 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { } for _, ratingProfile := range rpm { resultRatingProfile.FallbackKey = ratingProfile.FallbackKey // it will be the last fallback key - at := time.Unix(ratingProfile.activationTime, 0) - drtm, err := dbr.storDb.GetTpDestinationRateTimings(dbr.tpid, ratingProfile.destRatesTimingTag) + at := time.Unix(ratingProfile.ActivationTime, 0) + drtm, err := dbr.storDb.GetTpDestinationRateTimings(dbr.tpid, ratingProfile.DestRatesTimingTag) if err != nil { return err } else if len(drtm) == 0 { - return fmt.Errorf("No DestRateTimings profile with id: %s", ratingProfile.destRatesTimingTag) + return fmt.Errorf("No DestRateTimings profile with id: %s", ratingProfile.DestRatesTimingTag) } for _, destrateTiming := range drtm { tm, err := dbr.storDb.GetTpTimings(dbr.tpid, destrateTiming.TimingsTag) @@ -249,7 +249,7 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { return err } for _, destination := range dm { - ap := activationPeriods[ratingProfile.destRatesTimingTag] + ap := activationPeriods[ratingProfile.DestRatesTimingTag] newAP := &ActivationPeriod{ActivationTime: at} newAP.Intervals = append(newAP.Intervals, ap.Intervals...) resultRatingProfile.AddActivationPeriodIfNotPresent(destination.Id, newAP) diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index 969d29349..8105e72e4 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -30,10 +30,10 @@ const ( type RatingProfile struct { Id string - FallbackKey string + FallbackKey string // FallbackKey is used as complete combination of Tenant:TOR:Direction:Subject DestinationMap map[string][]*ActivationPeriod - tag, destRatesTimingTag string // used only for loading - activationTime int64 + Tag, Tenant, TOR, Direction, Subject, DestRatesTimingTag, RatesFallbackSubject string // used only for loading + ActivationTime int64 } // Adds an activation period that applyes to current rating profile if not already present. diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 8845cab2d..dd7570213 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -79,10 +79,10 @@ type DataStorage interface { SetTPDestRateTimings(string, map[string][]*DestinationRateTiming) error GetTPDestRateTiming(string, string) (*utils.TPDestRateTiming, error) GetTPDestRateTimingIds(string) ([]string, error) - ExistsTPRateProfile(string, string) (bool, error) - SetTPRateProfile(*utils.TPRateProfile) error - GetTPRateProfile(string, string) (*utils.TPRateProfile, error) - GetTPRateProfileIds(*utils.AttrTPRateProfileIds) ([]string, error) + ExistsTPRatingProfile(string, string) (bool, error) + SetTPRatingProfiles(string, map[string][]*RatingProfile) error + GetTPRatingProfile(string, string) (*utils.TPRatingProfile, error) + GetTPRatingProfileIds(*utils.AttrTPRatingProfileIds) ([]string, error) ExistsTPActions(string, string) (bool, error) SetTPActions(*utils.TPActions) error GetTPActions(string, string) (*utils.TPActions, error) diff --git a/engine/storage_map.go b/engine/storage_map.go index 4fef94931..051b10745 100644 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -157,19 +157,19 @@ func (ms *MapStorage) GetTPDestRateTimingIds(tpid string) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MapStorage) ExistsTPRateProfile(tpid, rpId string) (bool, error) { +func (ms *MapStorage) ExistsTPRatingProfile(tpid, rpId string) (bool, error) { return false, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MapStorage) SetTPRateProfile(rp *utils.TPRateProfile) error { +func (ms *MapStorage) SetTPRatingProfiles(tpid string, rps map[string][]*RatingProfile) error { return errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MapStorage) GetTPRateProfile(tpid, rpId string) (*utils.TPRateProfile, error) { +func (ms *MapStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingProfile, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MapStorage) GetTPRateProfileIds(filters *utils.AttrTPRateProfileIds) ([]string, error) { +func (ms *MapStorage) GetTPRatingProfileIds(filters *utils.AttrTPRatingProfileIds) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } diff --git a/engine/storage_mongo.go b/engine/storage_mongo.go index c4867abc9..a73bb6c0a 100644 --- a/engine/storage_mongo.go +++ b/engine/storage_mongo.go @@ -232,19 +232,19 @@ func (ms *MongoStorage) GetTPDestRateTimingIds(tpid string) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MongoStorage) ExistsTPRateProfile(tpid, rpId string) (bool, error) { +func (ms *MongoStorage) ExistsTPRatingProfile(tpid, rpId string) (bool, error) { return false, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MongoStorage) SetTPRateProfile(rp *utils.TPRateProfile) error { +func (ms *MongoStorage) SetTPRatingProfiles(tpid string, rps map[string][]*RatingProfile) error { return errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MongoStorage) GetTPRateProfile(tpid, rpId string) (*utils.TPRateProfile, error) { +func (ms *MongoStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingProfile, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (ms *MongoStorage) GetTPRateProfileIds(filters *utils.AttrTPRateProfileIds) ([]string, error) { +func (ms *MongoStorage) GetTPRatingProfileIds(filters *utils.AttrTPRatingProfileIds) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 3e65dc567..ada155c96 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -187,19 +187,19 @@ func (rs *RedisStorage) GetTPDestRateTimingIds(tpid string) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (rs *RedisStorage) ExistsTPRateProfile(tpid, rpId string) (bool, error) { +func (rs *RedisStorage) ExistsTPRatingProfile(tpid, rpId string) (bool, error) { return false, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (rs *RedisStorage) SetTPRateProfile(rp *utils.TPRateProfile) error { +func (rs *RedisStorage) SetTPRatingProfiles(tpid string, rps map[string][]*RatingProfile) error { return errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (rs *RedisStorage) GetTPRateProfile(tpid, rpId string) (*utils.TPRateProfile, error) { +func (rs *RedisStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingProfile, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (rs *RedisStorage) GetTPRateProfileIds(filters *utils.AttrTPRateProfileIds) ([]string, error) { +func (rs *RedisStorage) GetTPRatingProfileIds(filters *utils.AttrTPRatingProfileIds) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index cd29f7992..e90b5dfbf 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -215,14 +215,16 @@ func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*Rate) error { return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, connect_fee, rate, rated_units, rate_increments, group_interval, rounding_method, rounding_decimals, weight) VALUES ", utils.TBL_TP_RATES) + i := 0 for rtId, rtRows := range rts { - for idx, rt := range rtRows { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator + for _, rt := range rtRows { + if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s', '%s', %f, %f, %d, %d,%d,'%s', %d, %f)", tpid, rtId, rt.ConnectFee, rt.Price, int(rt.PricedUnits), int(rt.RateIncrements), int(rt.GroupInterval), rt.RoundingMethod, rt.RoundingDecimals, rt.Weight) + i++ } } if _, err := self.Db.Exec(qry); err != nil { @@ -294,13 +296,15 @@ func (self *SQLStorage) SetTPDestinationRates(tpid string, drs map[string][]*Des return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, destinations_tag, rates_tag) VALUES ", utils.TBL_TP_DESTINATION_RATES) + i := 0 for drId, drRows := range drs { - for idx, dr := range drRows { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator + for _, dr := range drRows { + if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s')", tpid, drId, dr.DestinationsTag, dr.RateTag) + i++ } } if _, err := self.Db.Exec(qry); err != nil { @@ -369,13 +373,15 @@ func (self *SQLStorage) SetTPDestRateTimings(tpid string, drts map[string][]*Des return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, destrates_tag, timing_tag, weight) VALUES ", utils.TBL_TP_DESTRATE_TIMINGS) + i := 0 for drtId, drtRows := range drts { - for idx, drt := range drtRows { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator + for _, drt := range drtRows { + if i!=0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s',%f)", tpid, drtId, drt.DestinationRatesTag, drt.TimingsTag, drt.Weight) + i++ } } if _, err := self.Db.Exec(qry); err != nil { @@ -431,7 +437,7 @@ func (self *SQLStorage) GetTPDestRateTimingIds(tpid string) ([]string, error) { return ids, nil } -func (self *SQLStorage) ExistsTPRateProfile(tpid, rpId string) (bool, error) { +func (self *SQLStorage) ExistsTPRatingProfile(tpid, rpId string) (bool, error) { var exists bool err := self.Db.QueryRow(fmt.Sprintf("SELECT EXISTS (SELECT 1 FROM %s WHERE tpid='%s' AND tag='%s')", utils.TBL_TP_RATE_PROFILES, tpid, rpId)).Scan(&exists) if err != nil { @@ -440,20 +446,23 @@ func (self *SQLStorage) ExistsTPRateProfile(tpid, rpId string) (bool, error) { return exists, nil } -func (self *SQLStorage) SetTPRateProfile(rp *utils.TPRateProfile) error { - var qry string - if len(rp.RatingActivations) == 0 { // Possibility to only set fallback rate subject - qry = fmt.Sprintf("INSERT INTO %s (tpid,tag,tenant,tor,direction,subject,activation_time,destrates_timing_tag,rates_fallback_subject) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', 0,'','%s')", - utils.TBL_TP_RATE_PROFILES, rp.TPid, rp.RateProfileId, rp.Tenant, rp.TOR, rp.Direction, rp.Subject, rp.RatesFallbackSubject) - } else { - qry = fmt.Sprintf("INSERT INTO %s (tpid,tag,tenant,tor,direction,subject,activation_time,destrates_timing_tag,rates_fallback_subject) VALUES ", utils.TBL_TP_RATE_PROFILES) - // Using multiple values in query to spare some network processing time - for idx, rpa := range rp.RatingActivations { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator +func (self *SQLStorage) SetTPRatingProfiles(tpid string, rps map[string][]*RatingProfile) error { + if len(rps) == 0 { + return nil //Nothing to set + } + qry := fmt.Sprintf("INSERT INTO %s (tpid,tag,tenant,tor,direction,subject,activation_time,destrates_timing_tag,rates_fallback_subject) VALUES ", + utils.TBL_TP_RATE_PROFILES) + i := 0 + for rpId, rp := range rps { + for _, rpa := range rp { + if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } - qry += fmt.Sprintf("('%s', '%s', '%s', '%s', '%s', '%s', %d,'%s','%s')", rp.TPid, rp.RateProfileId, rp.Tenant, rp.TOR, rp.Direction, rp.Subject, rpa.ActivationTime, rpa.DestRateTimingId, rp.RatesFallbackSubject) + qry += fmt.Sprintf("('%s', '%s', '%s', '%s', '%s', '%s', %d,'%s','%s')", tpid, rpId, rpa.Tenant, rpa.TOR, rpa.Direction, + rpa.Subject, rpa.ActivationTime, rpa.DestRatesTimingTag, rpa.RatesFallbackSubject) + i++ } + } if _, err := self.Db.Exec(qry); err != nil { return err @@ -461,13 +470,13 @@ func (self *SQLStorage) SetTPRateProfile(rp *utils.TPRateProfile) error { return nil } -func (self *SQLStorage) GetTPRateProfile(tpid, rpId string) (*utils.TPRateProfile, error) { +func (self *SQLStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingProfile, error) { rows, err := self.Db.Query(fmt.Sprintf("SELECT tenant,tor,direction,subject,activation_time,destrates_timing_tag,rates_fallback_subject FROM %s WHERE tpid='%s' AND tag='%s'", utils.TBL_TP_RATE_PROFILES, tpid, rpId)) if err != nil { return nil, err } defer rows.Close() - rp := &utils.TPRateProfile{TPid: tpid, RateProfileId: rpId} + rp := &utils.TPRatingProfile{TPid: tpid, RatingProfileId: rpId} i := 0 for rows.Next() { i++ //Keep here a reference so we know we got at least one result @@ -492,7 +501,7 @@ func (self *SQLStorage) GetTPRateProfile(tpid, rpId string) (*utils.TPRateProfil return rp, nil } -func (self *SQLStorage) GetTPRateProfileIds(filters *utils.AttrTPRateProfileIds) ([]string, error) { +func (self *SQLStorage) GetTPRatingProfileIds(filters *utils.AttrTPRatingProfileIds) ([]string, error) { qry := fmt.Sprintf("SELECT DISTINCT tag FROM %s where tpid='%s'", utils.TBL_TP_RATE_PROFILES, filters.TPid) if filters.Tenant != "" { qry += fmt.Sprintf(" AND tenant='%s'", filters.Tenant) @@ -618,13 +627,15 @@ func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string][]*utils. return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid,tag,actions_tag,timing_tag,weight) VALUES ", utils.TBL_TP_ACTION_TIMINGS) + i := 0 for atId, atRows := range ats { - for idx, atsRow := range atRows { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator + for _, atsRow := range atRows { + if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s',%f)", tpid, atId, atsRow.ActionsId, atsRow.TimingId, atsRow.Weight) + i++ } } if _, err := self.Db.Exec(qry); err != nil { @@ -694,14 +705,16 @@ func (self *SQLStorage) SetTPActionTriggers(tpid string, ats map[string][]*Actio } qry := fmt.Sprintf("INSERT INTO %s (tpid,tag,balance_tag,direction,threshold_type,threshold_value,destination_tag,actions_tag,weight) VALUES ", utils.TBL_TP_ACTION_TRIGGERS) + i := 0 for atId, atRows := range ats { - for idx, atsRow := range atRows { - if idx != 0 { //Consecutive values after the first will be prefixed with "," as separator + for _, atsRow := range atRows { + if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s','%s', %f, '%s','%s',%f)", tpid, atId, atsRow.BalanceId, atsRow.Direction, atsRow.ThresholdType, atsRow.ThresholdValue, atsRow.DestinationId, atsRow.ActionsId, atsRow.Weight) + i++ } } if _, err := self.Db.Exec(qry); err != nil { @@ -749,12 +762,12 @@ func (self *SQLStorage) SetTPAccountActions(tpid string, aa map[string]*AccountA utils.TBL_TP_ACCOUNT_ACTIONS) i := 0 for aaId, aActs := range aa { - i++ if i != 1 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s','%s','%s','%s')", tpid, aaId, aActs.Tenant, aActs.Account, aActs.Direction, aActs.ActionTimingsTag, aActs.ActionTriggersTag) + i++ } if _, err := self.Db.Exec(qry); err != nil { return err @@ -1066,12 +1079,12 @@ func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*Ratin } key := fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, subject) rp, ok := rpfs[key] - if !ok || rp.tag != tag { - rp = &RatingProfile{Id: key, tag: tag} + if !ok || rp.Tag != tag { + rp = &RatingProfile{Id: key, Tag: tag} rpfs[key] = rp } - rp.destRatesTimingTag = destrates_timing_tag - rp.activationTime = activation_time + rp.DestRatesTimingTag = destrates_timing_tag + rp.ActivationTime = activation_time if fallback_subject != "" { rp.FallbackKey = fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fallback_subject) } diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 9f45e32ae..23d35f6bb 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "log" "strconv" + "time" "github.com/cgrates/cgrates/utils" ) @@ -34,6 +35,7 @@ type TPCSVImporter struct { DirPath string // Directory path to import from Sep rune // Separator in the csv file Verbose bool // If true will print a detailed information instead of silently discarding it + ImportId string // Use this to differentiate between imports (eg: when autogenerating fields like RatingProfileId } // Maps csv file to handler which should process it. Defined like this since tests on 1.0.3 were failing on Travis. @@ -218,6 +220,47 @@ func (self *TPCSVImporter) importDestRateTimings(fn string) error { } func (self *TPCSVImporter) importRatingProfiles(fn string) error { + if self.Verbose { + log.Printf("Processing file: <%s> ", fn) + } + fParser, err := NewTPCSVFileParser( self.DirPath, fn ) + if err!=nil { + return err + } + lineNr := 0 + for { + lineNr++ + record, err := fParser.ParseNextLine() + if err == io.EOF { // Reached end of file + break + } else if err != nil { + if self.Verbose { + log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) + } + continue + } + tenant, tor, direction, subject, destRatesTimingTag, fallbacksubject := record[0], record[1], record[2], record[3], record[5], record[6] + at, err := time.Parse(time.RFC3339, record[4]) + if err != nil { + log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) + } + rpTag := "TPCSV" //Autogenerate rating profile id + if self.ImportId != "" { + rpTag += "_"+self.ImportId + } + rp := &RatingProfile{Tag: rpTag, + Tenant: tenant, + TOR: tor, + Direction: direction, + Subject: subject, + ActivationTime: at.Unix(), + DestRatesTimingTag: destRatesTimingTag, + RatesFallbackSubject: fallbacksubject, + } + if err := self.StorDb.SetTPRatingProfiles( self.TPid, map[string][]*RatingProfile{rpTag:[]*RatingProfile{rp}}); err != nil { + log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) + } + } return nil } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 89d396b33..03d92d7d1 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -60,9 +60,9 @@ type DestRateTiming struct { Weight float64 // Binding priority taken into consideration when more DestinationRates are active on a time slot } -type TPRateProfile struct { +type TPRatingProfile struct { TPid string // Tariff plan id - RateProfileId string // RateProfile id + RatingProfileId string // RatingProfile id Tenant string // Tenant's Id TOR string // TypeOfRecord Direction string // Traffic direction, OUT is the only one supported for now @@ -76,7 +76,7 @@ type RatingActivation struct { DestRateTimingId string // Id of DestRateTiming profile } -type AttrTPRateProfileIds struct { +type AttrTPRatingProfileIds struct { TPid string // Tariff plan id Tenant string // Tenant's Id TOR string // TypeOfRecord diff --git a/utils/consts.go b/utils/consts.go index 103805c34..bbd905f60 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -24,7 +24,7 @@ const ( TBL_TP_RATES = "tp_rates" TBL_TP_DESTINATION_RATES = "tp_destination_rates" TBL_TP_DESTRATE_TIMINGS = "tp_destrate_timings" - TBL_TP_RATE_PROFILES = "tp_rate_profiles" + TBL_TP_RATE_PROFILES = "tp_rating_profiles" TBL_TP_ACTIONS = "tp_actions" TBL_TP_ACTION_TIMINGS = "tp_action_timings" TBL_TP_ACTION_TRIGGERS = "tp_action_triggers"