diff --git a/apier/tpdestinationrates.go b/apier/tpdestinationrates.go
new file mode 100644
index 000000000..9d96eedcf
--- /dev/null
+++ b/apier/tpdestinationrates.go
@@ -0,0 +1,84 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+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 apier
+
+// This file deals with tp_destination_rates management over APIs
+
+import (
+ "errors"
+ "fmt"
+ "github.com/cgrates/cgrates/utils"
+)
+
+
+// Creates a new DestinationRate profile within a tariff plan
+func (self *Apier) SetTPDestinationRate(attrs utils.TPDestinationRate, reply *string) error {
+ if missing := utils.MissingStructFields(&attrs, []string{"TPid", "DestinationRateId", "DestinationRates"}); len(missing) != 0 {
+ return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
+ }
+ if exists, err := self.StorDb.ExistsTPDestinationRate(attrs.TPid, attrs.DestinationRateId); 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.SetTPDestinationRate(&attrs); err != nil {
+ return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
+ }
+ *reply = "OK"
+ return nil
+}
+
+type AttrGetTPDestinationRate struct {
+ TPid string // Tariff plan id
+ DestinationRateId string // Rate id
+}
+
+// Queries specific DestinationRate profile on tariff plan
+func (self *Apier) GetTPDestinationRate(attrs AttrGetTPDestinationRate, reply *utils.TPDestinationRate) error {
+ if missing := utils.MissingStructFields(&attrs, []string{"TPid", "DestinationRateId"}); len(missing) != 0 { //Params missing
+ return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
+ }
+ if dr, err := self.StorDb.GetTPDestinationRate(attrs.TPid, attrs.DestinationRateId); err != nil {
+ return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
+ } else if dr == nil {
+ return errors.New(utils.ERR_NOT_FOUND)
+ } else {
+ *reply = *dr
+ }
+ return nil
+}
+
+type AttrTPDestinationRateIds struct {
+ TPid string // Tariff plan id
+}
+
+// Queries DestinationRate identities on specific tariff plan.
+func (self *Apier) GetTPDestinationRateIds(attrs AttrGetTPRateIds, 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.GetTPDestinationRateIds(attrs.TPid); err != nil {
+ return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
+ } else if ids == nil {
+ return errors.New(utils.ERR_NOT_FOUND)
+ } else {
+ *reply = ids
+ }
+ return nil
+}
diff --git a/apier/tprates.go b/apier/tprates.go
index eeb0a4724..56b9c8595 100644
--- a/apier/tprates.go
+++ b/apier/tprates.go
@@ -28,7 +28,7 @@ import (
// Creates a new rate within a tariff plan
func (self *Apier) SetTPRate(attrs utils.TPRate, reply *string) error {
- if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RateId", "ConnectFee", "RateSlots"}); len(missing) != 0 {
+ if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RateId", "RateSlots"}); len(missing) != 0 {
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
}
if exists, err := self.StorDb.ExistsTPRate(attrs.TPid, attrs.RateId); err != nil {
diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql
index 4301c1fdc..b05d8fe3e 100644
--- a/data/storage/mysql/create_tariffplan_tables.sql
+++ b/data/storage/mysql/create_tariffplan_tables.sql
@@ -58,7 +58,8 @@ CREATE TABLE `tp_destination_rates` (
`destinations_tag` varchar(24) NOT NULL,
`rates_tag` varchar(24) NOT NULL,
PRIMARY KEY (`id`),
- KEY `tpid` (`tpid`)
+ KEY `tpid` (`tpid`),
+ UNIQUE KEY `tpid_tag_dst_rates` (`tpid`,`tag`,`destinations_tag`, `rates_tag`)
);
--
diff --git a/rater/storage_interface.go b/rater/storage_interface.go
index 3dad396f3..14e18a344 100644
--- a/rater/storage_interface.go
+++ b/rater/storage_interface.go
@@ -71,6 +71,10 @@ type DataStorage interface {
SetTPRate(*utils.TPRate) error
GetTPRate(string, string) (*utils.TPRate, error)
GetTPRateIds(string) ([]string, error)
+ ExistsTPDestinationRate(string, string) (bool, error)
+ SetTPDestinationRate(*utils.TPDestinationRate) error
+ GetTPDestinationRate(string, string) (*utils.TPDestinationRate, error)
+ GetTPDestinationRateIds(string) ([]string, error)
// End Apier functions
GetActions(string) (Actions, error)
SetActions(string, Actions) error
diff --git a/rater/storage_map.go b/rater/storage_map.go
index 432e51336..039d2dc4f 100644
--- a/rater/storage_map.go
+++ b/rater/storage_map.go
@@ -125,6 +125,23 @@ func (ms *MapStorage) GetTPRateIds(tpid string) ([]string, error) {
return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
}
+func (ms *MapStorage) ExistsTPDestinationRate(tpid, drId string) (bool, error) {
+ return false, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (ms *MapStorage) SetTPDestinationRate(dr *utils.TPDestinationRate) error {
+ return errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (ms *MapStorage) GetTPDestinationRate(tpid, drId string) (*utils.TPDestinationRate, error) {
+ return nil, nil
+}
+
+func (ms *MapStorage) GetTPDestinationRateIds(tpid string) ([]string, error) {
+ return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+
func (ms *MapStorage) GetActions(key string) (as Actions, err error) {
if values, ok := ms.dict[ACTION_PREFIX+key]; ok {
err = ms.ms.Unmarshal(values, &as)
diff --git a/rater/storage_mongo.go b/rater/storage_mongo.go
index b8519cb00..73bf564b9 100644
--- a/rater/storage_mongo.go
+++ b/rater/storage_mongo.go
@@ -200,6 +200,22 @@ func (ms *MongoStorage) GetTPRateIds(tpid string) ([]string, error) {
return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
}
+func (ms *MongoStorage) ExistsTPDestinationRate(tpid, drId string) (bool, error) {
+ return false, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (ms *MongoStorage) SetTPDestinationRate(dr *utils.TPDestinationRate) error {
+ return errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (ms *MongoStorage) GetTPDestinationRate(tpid, drId string) (*utils.TPDestinationRate, error) {
+ return nil, nil
+}
+
+func (ms *MongoStorage) GetTPDestinationRateIds(tpid string) ([]string, error) {
+ return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
func (ms *MongoStorage) GetActions(key string) (as Actions, err error) {
result := AcKeyValue{}
err = ms.db.C("actions").Find(bson.M{"key": key}).One(&result)
diff --git a/rater/storage_redis.go b/rater/storage_redis.go
index 3bdc78242..1ba05466d 100644
--- a/rater/storage_redis.go
+++ b/rater/storage_redis.go
@@ -155,6 +155,22 @@ func (rs *RedisStorage) GetTPRateIds(tpid string) ([]string, error) {
return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
}
+func (rs *RedisStorage) ExistsTPDestinationRate(tpid, drId string) (bool, error) {
+ return false, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (rs *RedisStorage) SetTPDestinationRate(dr *utils.TPDestinationRate) error {
+ return errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
+func (rs *RedisStorage) GetTPDestinationRate(tpid, drId string) (*utils.TPDestinationRate, error) {
+ return nil, nil
+}
+
+func (rs *RedisStorage) GetTPDestinationRateIds(tpid string) ([]string, error) {
+ return nil, errors.New(utils.ERR_NOT_IMPLEMENTED)
+}
+
func (rs *RedisStorage) GetActions(key string) (as Actions, err error) {
var values string
if values, err = rs.db.Get(ACTION_PREFIX + key); err == nil {
diff --git a/rater/storage_sql.go b/rater/storage_sql.go
index d0468f0df..a7871ab75 100644
--- a/rater/storage_sql.go
+++ b/rater/storage_sql.go
@@ -22,7 +22,6 @@ import (
"database/sql"
"encoding/json"
"fmt"
- //"errors"
"github.com/cgrates/cgrates/utils"
)
@@ -267,6 +266,79 @@ func (self *SQLStorage) GetTPRateIds(tpid string) ([]string, error) {
return ids, nil
}
+func (self *SQLStorage) ExistsTPDestinationRate(tpid, drId 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_DESTINATION_RATES, tpid, drId)).Scan(&exists)
+ if err != nil {
+ return false, err
+ }
+ return exists, nil
+}
+
+func (self *SQLStorage) SetTPDestinationRate(dr *utils.TPDestinationRate) error {
+ if len(dr.DestinationRates) == 0 {
+ return nil //Nothing to set
+ }
+ // Using multiple values in query to spare some network processing time
+ qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, destinations_tag, rates_tag) VALUES", utils.TBL_TP_DESTINATION_RATES)
+ for idx, drPair := range dr.DestinationRates {
+ if idx!=0 { //Consecutive values after the first will be prefixed with "," as separator
+ qry += ","
+ }
+ qry += fmt.Sprintf("('%s','%s','%s','%s')", dr.TPid, dr.DestinationRateId, drPair.DestinationId, drPair.RateId)
+ }
+ if _, err := self.Db.Exec(qry); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (self *SQLStorage) GetTPDestinationRate(tpid, drId string) (*utils.TPDestinationRate, error) {
+ rows, err := self.Db.Query(fmt.Sprintf("SELECT destinations_tag, rates_tag FROM %s WHERE tpid='%s' AND tag='%s'", utils.TBL_TP_DESTINATION_RATES, tpid, drId))
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ dr := &utils.TPDestinationRate{TPid: tpid, DestinationRateId: drId}
+ i := 0
+ for rows.Next() {
+ i++ //Keep here a reference so we know we got at least one prefix
+ var dstTag, ratesTag string
+ err = rows.Scan(&dstTag, &ratesTag)
+ if err != nil {
+ return nil, err
+ }
+ dr.DestinationRates = append(dr.DestinationRates, utils.DestinationRate{dstTag, ratesTag})
+ }
+ if i == 0 {
+ return nil, nil
+ }
+ return dr, nil
+}
+
+func (self *SQLStorage) GetTPDestinationRateIds(tpid string) ([]string, error) {
+ rows, err := self.Db.Query(fmt.Sprintf("SELECT DISTINCT tag FROM %s where tpid='%s'", utils.TBL_TP_DESTINATION_RATES, tpid))
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ ids := []string{}
+ i := 0
+ for rows.Next() {
+ i++ //Keep here a reference so we know we got at least one
+ var id string
+ err = rows.Scan(&id)
+ if err != nil {
+ return nil, err
+ }
+ ids = append(ids, id)
+ }
+ if i == 0 {
+ return nil, nil
+ }
+ return ids, nil
+}
+
func (self *SQLStorage) GetActions(string) (as Actions, err error) {
return
}
diff --git a/utils/data_tprates.go b/utils/tpdata.go
similarity index 76%
rename from utils/data_tprates.go
rename to utils/tpdata.go
index 5a41757cc..784956d63 100644
--- a/utils/data_tprates.go
+++ b/utils/tpdata.go
@@ -18,7 +18,7 @@ along with this program. If not, see
package utils
-// This file deals with tp_rates data definition
+// This file deals with tp_* data definition
type TPRate struct {
TPid string // Tariff plan id
@@ -33,3 +33,17 @@ type RateSlot struct {
RateIncrements int // This rate will apply in increments of duration
Weight float64 // Rate's priority when dealing with grouped rates
}
+
+
+type TPDestinationRate struct {
+ TPid string // Tariff plan id
+ DestinationRateId string // DestinationRate profile id
+ DestinationRates []DestinationRate // Set of destinationid-rateid bindings
+}
+
+type DestinationRate struct {
+ DestinationId string // The destination identity
+ RateId string // The rate identity
+}
+
+