diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 28b3a8f4f..0f851ffcf 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -1811,6 +1811,7 @@ func (self *ApierV1) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, path.Join(attrs.FolderPath, utils.FiltersCsv), path.Join(attrs.FolderPath, utils.SuppliersCsv), path.Join(attrs.FolderPath, utils.AttributesCsv), + path.Join(attrs.FolderPath, utils.ChargersCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/apier/v2/apier.go b/apier/v2/apier.go index 64e9845ad..ae9d535e2 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.FiltersCsv), path.Join(attrs.FolderPath, utils.SuppliersCsv), path.Join(attrs.FolderPath, utils.AttributesCsv), + path.Join(attrs.FolderPath, utils.ChargersCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 294b543fa..0a4966468 100755 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -279,6 +279,7 @@ func main() { path.Join(*dataPath, utils.FiltersCsv), path.Join(*dataPath, utils.SuppliersCsv), path.Join(*dataPath, utils.AttributesCsv), + path.Join(*dataPath, utils.ChargersCsv), ) } diff --git a/data/tutorials/osips_native/cgrates/etc/cgrates/cgrates.json b/data/tutorials/osips_native/cgrates/etc/cgrates/cgrates.json index 082dea2eb..05820fbc5 100644 --- a/data/tutorials/osips_native/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/osips_native/cgrates/etc/cgrates/cgrates.json @@ -31,7 +31,7 @@ {"address": "127.0.0.1:2012", "transport": "*json"} ], "attributes_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], }, @@ -42,7 +42,7 @@ {"address": "127.0.0.1:2012", "transport": "*json"} ], "stats_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "sessions_cost_retries": 5, }, @@ -52,25 +52,25 @@ "enabled": true, "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests "rals_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "cdrs_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "resources_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "suppliers_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "attributes_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "stats_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "thresholds_conns": [ - {"address": "*internal", "transport": "*json"} + {"address": "*internal"} ], "debit_interval": "10s", "channel_sync_interval":"7s", diff --git a/engine/chargers.go b/engine/chargers.go index 62dd0aa2a..9b04f0243 100644 --- a/engine/chargers.go +++ b/engine/chargers.go @@ -56,3 +56,13 @@ func (cS *ChargerService) Shutdown() (err error) { utils.Logger.Info(fmt.Sprintf("<%s> shutdown complete", utils.ChargerS)) return } + +type ChargerProfile struct { + Tenant string + ID string + FilterIDs []string + ActivationInterval *utils.ActivationInterval // Activation interval + RunID string + AttributeIDs []string + Weight float64 +} diff --git a/engine/libtest.go b/engine/libtest.go index 1be8cb8a5..eb7635148 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -141,6 +141,7 @@ func LoadTariffPlanFromFolder(tpPath, timezone string, dm *DataManager, disable_ path.Join(tpPath, utils.FiltersCsv), path.Join(tpPath, utils.SuppliersCsv), path.Join(tpPath, utils.AttributesCsv), + path.Join(tpPath, utils.ChargersCsv), ), "", timezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/engine/storage_csv.go b/engine/storage_csv.go index ae32cc50c..8b7919fa8 100644 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -34,34 +34,34 @@ type CSVStorage struct { // file names destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, - cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn string + cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn, chargerProfilesFn 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, suppProfilesFn, attributeProfilesFn string) *CSVStorage { + resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn, chargerProfilesFn 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, c.suppProfilesFn, c.attributeProfilesFn = destinationsFn, timingsFn, + c.filterFn, c.suppProfilesFn, c.attributeProfilesFn, c.chargerProfilesFn = destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, - usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn + usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn, chargerProfilesFn 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, suppProfilesFn, attributeProfilesFn string) *CSVStorage { + aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn, chargerProfilesFn 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, suppProfilesFn, attributeProfilesFn) + statsFn, thresholdsFn, filterFn, suppProfilesFn, attributeProfilesFn, chargerProfilesFn) c.readerFunc = openStringCSVStorage return c } @@ -770,6 +770,34 @@ func (csvs *CSVStorage) GetTPAttributes(tpid, id string) ([]*utils.TPAttributePr return tpAls.AsTPAttributes(), nil } +func (csvs *CSVStorage) GetTPChargers(tpid, id string) ([]*utils.TPChargerProfile, error) { + // csvReader, fp, err := csvs.readerFunc(csvs.chargerProfilesFn, csvs.sep, getColumnCount(TPCharger{})) + // if err != nil { + // //log.Print("Could not load AttributeProfile file: ", err) + // // allow writing of the other values + // return nil, nil + // } + // if fp != nil { + // defer fp.Close() + // } + // var tpAls TPAttributes + // for record, err := csvReader.Read(); err != io.EOF; record, err = csvReader.Read() { + // if err != nil { + // log.Printf("bad line in %s, %s\n", csvs.chargerProfilesFn, err.Error()) + // return nil, err + // } + // if attributeProfile, err := csvLoad(TPAttribute{}, record); err != nil { + // log.Print("error loading tpAliasProfile: ", err) + // return nil, err + // } else { + // attributeProfile := attributeProfile.(TPAttribute) + // attributeProfile.Tpid = tpid + // tpAls = append(tpAls, &attributeProfile) + // } + // } + return nil, nil +} + func (csvs *CSVStorage) GetTpIds(colName string) ([]string, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index b88ee1ac5..45962415b 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -151,6 +151,9 @@ type DataDB interface { GetAttributeProfileDrv(string, string) (*AttributeProfile, error) SetAttributeProfileDrv(*AttributeProfile) error RemoveAttributeProfileDrv(string, string) error + GetChargerProfileDrv(string, string) (*ChargerProfile, error) + SetChargerProfileDrv(*ChargerProfile) error + RemoveChargerProfileDrv(string, string) error } type StorDB interface { @@ -201,6 +204,7 @@ type LoadReader interface { GetTPFilters(string, string) ([]*utils.TPFilterProfile, error) GetTPSuppliers(string, string) ([]*utils.TPSupplierProfile, error) GetTPAttributes(string, string) ([]*utils.TPAttributeProfile, error) + GetTPChargers(string, string) ([]*utils.TPChargerProfile, error) } type LoadWriter interface { @@ -227,6 +231,7 @@ type LoadWriter interface { SetTPFilters([]*utils.TPFilterProfile) error SetTPSuppliers([]*utils.TPSupplierProfile) error SetTPAttributes([]*utils.TPAttributeProfile) error + SetTPChargers([]*utils.TPChargerProfile) error } // NewMarshaler returns the marshaler type selected by mrshlerStr diff --git a/engine/storage_map_datadb.go b/engine/storage_map_datadb.go index 17e668d3e..14be866d2 100644 --- a/engine/storage_map_datadb.go +++ b/engine/storage_map_datadb.go @@ -1703,6 +1703,39 @@ func (ms *MapStorage) RemoveAttributeProfileDrv(tenant, id string) (err error) { return } +func (ms *MapStorage) GetChargerProfileDrv(tenant, id string) (r *ChargerProfile, err error) { + ms.mu.RLock() + defer ms.mu.RUnlock() + values, ok := ms.dict[utils.ChargerProfilePrefix+utils.ConcatenatedKey(tenant, id)] + if !ok { + return nil, utils.ErrNotFound + } + err = ms.ms.Unmarshal(values, &r) + if err != nil { + return nil, err + } + return +} + +func (ms *MapStorage) SetChargerProfileDrv(r *ChargerProfile) (err error) { + ms.mu.Lock() + defer ms.mu.Unlock() + result, err := ms.ms.Marshal(r) + if err != nil { + return err + } + ms.dict[utils.ChargerProfilePrefix+utils.ConcatenatedKey(r.Tenant, r.ID)] = result + return +} + +func (ms *MapStorage) RemoveChargerProfileDrv(tenant, id string) (err error) { + ms.mu.Lock() + defer ms.mu.Unlock() + key := utils.ChargerProfilePrefix + utils.ConcatenatedKey(tenant, id) + delete(ms.dict, key) + return +} + func (ms *MapStorage) GetVersions(itm string) (vrs Versions, err error) { ms.mu.Lock() defer ms.mu.Unlock() diff --git a/engine/storage_map_stordb.go b/engine/storage_map_stordb.go index 51b96c88b..f9854a3cc 100755 --- a/engine/storage_map_stordb.go +++ b/engine/storage_map_stordb.go @@ -97,6 +97,9 @@ func (ms *MapStorage) GetTPSuppliers(tpid, id string) (supps []*utils.TPSupplier func (ms *MapStorage) GetTPAttributes(tpid, id string) (attrs []*utils.TPAttributeProfile, err error) { return nil, utils.ErrNotImplemented } +func (ms *MapStorage) GetTPChargers(tpid, id string) (attrs []*utils.TPChargerProfile, err error) { + return nil, utils.ErrNotImplemented +} //implement LoadWriter interface func (ms *MapStorage) RemTpData(table, tpid string, args map[string]string) (err error) { @@ -170,6 +173,9 @@ func (ms *MapStorage) SetTPSuppliers(suppliers []*utils.TPSupplierProfile) (err func (ms *MapStorage) SetTPAttributes(attributes []*utils.TPAttributeProfile) (err error) { return utils.ErrNotImplemented } +func (ms *MapStorage) SetTPChargers(attributes []*utils.TPChargerProfile) (err error) { + return utils.ErrNotImplemented +} //implement CdrStorage interface func (ms *MapStorage) SetCDR(cdr *CDR, allowUpdate bool) (err error) { diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index c0e1dd0f7..f5651fcf3 100644 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -68,6 +68,7 @@ const ( colSpp = "supplier_profiles" colAttr = "attribute_profiles" ColCDRs = "cdrs" + colCpp = "charger_profiles" ) var ( @@ -2382,3 +2383,31 @@ func (ms *MongoStorage) RemoveAttributeProfileDrv(tenant, id string) (err error) } return nil } + +func (ms *MongoStorage) GetChargerProfileDrv(tenant, id string) (r *ChargerProfile, err error) { + session, col := ms.conn(colCpp) + defer session.Close() + if err = col.Find(bson.M{"tenant": tenant, "id": id}).One(&r); err != nil { + if err == mgo.ErrNotFound { + err = utils.ErrNotFound + } + return nil, err + } + return +} + +func (ms *MongoStorage) SetChargerProfileDrv(r *ChargerProfile) (err error) { + session, col := ms.conn(colCpp) + defer session.Close() + _, err = col.Upsert(bson.M{"tenant": r.Tenant, "id": r.ID}, r) + return +} + +func (ms *MongoStorage) RemoveChargerProfileDrv(tenant, id string) (err error) { + session, col := ms.conn(colCpp) + defer session.Close() + if err = col.Remove(bson.M{"tenant": tenant, "id": id}); err != nil { + return + } + return nil +} diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 669bfa24f..5cb67f75d 100644 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1295,6 +1295,37 @@ func (ms *MongoStorage) SetTPAttributes(tpSPs []*utils.TPAttributeProfile) (err return } +func (ms *MongoStorage) GetTPChargers(tpid, id string) ([]*utils.TPChargerProfile, error) { + filter := bson.M{ + "tpid": tpid, + } + if id != "" { + filter["id"] = id + } + var results []*utils.TPChargerProfile + session, col := ms.conn(utils.TBLTPChargers) + defer session.Close() + err := col.Find(filter).All(&results) + if len(results) == 0 { + return results, utils.ErrNotFound + } + return results, err +} + +func (ms *MongoStorage) SetTPChargers(tpCPP []*utils.TPChargerProfile) (err error) { + if len(tpCPP) == 0 { + return + } + session, col := ms.conn(utils.TBLTPChargers) + defer session.Close() + tx := col.Bulk() + for _, tp := range tpCPP { + tx.Upsert(bson.M{"tpid": tp.TPid, "id": tp.ID}, tp) + } + _, err = tx.Run() + return +} + func (ms *MongoStorage) GetVersions(itm string) (vrs Versions, err error) { session, col := ms.conn(colVer) defer session.Close() diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 852a74aac..90bd12709 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -1824,6 +1824,37 @@ func (rs *RedisStorage) RemoveAttributeProfileDrv(tenant, id string) (err error) return } +func (rs *RedisStorage) GetChargerProfileDrv(tenant, id string) (r *ChargerProfile, err error) { + key := utils.ChargerProfilePrefix + utils.ConcatenatedKey(tenant, id) + var values []byte + if values, err = rs.Cmd("GET", key).Bytes(); err != nil { + if err == redis.ErrRespNil { // did not find the destination + err = utils.ErrNotFound + } + return + } + if err = rs.ms.Unmarshal(values, &r); err != nil { + return + } + return +} + +func (rs *RedisStorage) SetChargerProfileDrv(r *ChargerProfile) (err error) { + result, err := rs.ms.Marshal(r) + if err != nil { + return err + } + return rs.Cmd("SET", utils.ChargerProfilePrefix+utils.ConcatenatedKey(r.Tenant, r.ID), result).Err +} + +func (rs *RedisStorage) RemoveChargerProfileDrv(tenant, id string) (err error) { + key := utils.ChargerProfilePrefix + utils.ConcatenatedKey(tenant, id) + if err = rs.Cmd("DEL", key).Err; err != nil { + return + } + return +} + func (rs *RedisStorage) GetStorageType() string { return utils.REDIS } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 8716de534..f86b83c56 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -1623,6 +1623,10 @@ func (self *SQLStorage) GetTPAttributes(tpid, id string) ([]*utils.TPAttributePr return arls, nil } +func (self *SQLStorage) GetTPChargers(tpid, id string) ([]*utils.TPChargerProfile, error) { + return nil, 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/tpimporter_csv.go b/engine/tpimporter_csv.go index f36863bec..4d7242574 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -63,6 +63,7 @@ var fileHandlers = map[string]func(*TPCSVImporter, string) error{ utils.FiltersCsv: (*TPCSVImporter).importFilters, utils.SuppliersCsv: (*TPCSVImporter).importSuppliers, utils.AttributesCsv: (*TPCSVImporter).importAttributeProfiles, + utils.ChargersCsv: (*TPCSVImporter).importChargerProfiles, } func (self *TPCSVImporter) Run() error { @@ -89,6 +90,7 @@ func (self *TPCSVImporter) Run() error { path.Join(self.DirPath, utils.FiltersCsv), path.Join(self.DirPath, utils.SuppliersCsv), path.Join(self.DirPath, utils.AttributesCsv), + path.Join(self.DirPath, utils.ChargersCsv), ) files, _ := ioutil.ReadDir(self.DirPath) for _, f := range files { @@ -423,3 +425,14 @@ func (self *TPCSVImporter) importAttributeProfiles(fn string) error { } return self.StorDb.SetTPAttributes(rls) } + +func (self *TPCSVImporter) importChargerProfiles(fn string) error { + if self.Verbose { + log.Printf("Processing file: <%s> ", fn) + } + rls, err := self.csvr.GetTPChargers(self.TPid, "") + if err != nil { + return err + } + return self.StorDb.SetTPChargers(rls) +} diff --git a/utils/apitpdata.go b/utils/apitpdata.go index b9d6dcf96..0371622b5 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1422,3 +1422,14 @@ type TPAttributeProfile struct { Attributes []*TPAttribute Weight float64 } + +type TPChargerProfile struct { + TPid string + Tenant string + ID string + FilterIDs []string + ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires + RunID string + AttributeIDs []string + Weight float64 +} diff --git a/utils/consts.go b/utils/consts.go index b460ed16f..45cd8aa46 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -805,6 +805,7 @@ const ( FiltersCsv = "Filters.csv" SuppliersCsv = "Suppliers.csv" AttributesCsv = "Attributes.csv" + ChargersCsv = "Chargers.csv" ) // Table Name @@ -833,6 +834,7 @@ const ( CDRsTBL = "cdrs" TBLTPSuppliers = "tp_suppliers" TBLTPAttributes = "tp_attributes" + TBLTPChargers = "tp_chargers" TBLVersions = "versions" OldSMCosts = "sm_costs" )