This commit is contained in:
DanB
2013-11-13 10:09:30 +01:00
13 changed files with 251 additions and 166 deletions

View File

@@ -144,6 +144,26 @@ func (self *ApierV1) ExecuteAction(attr *AttrExecuteAction, reply *string) error
return nil
}
type AttrSetRatingPlan struct {
TPid string
RatingPlanId string
}
// Process dependencies and load a specific rating plan from storDb into dataDb.
func (self *ApierV1) SetRatingPlan(attrs AttrSetRatingPlan, reply *string) error {
if missing := utils.MissingStructFields(&attrs, []string{"TPid", "RatingPlanId"}); len(missing) != 0 {
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
}
dbReader := engine.NewDbReader(self.StorDb, self.DataDb, attrs.TPid)
if err := dbReader.LoadRatingPlanByTag(attrs.RatingPlanId); err != nil {
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
}
*reply = OK
return nil
}
type AttrSetRatingProfile struct {
TPid string
RatingProfileId string

View File

@@ -39,7 +39,8 @@ func (self *ApierV1) SetTPRatingProfile(attrs utils.TPRatingProfile, reply *stri
}
rps := make([]*engine.RatingProfile, len(attrs.RatingActivations))
for idx, ra := range attrs.RatingActivations {
rps[idx] = &engine.RatingProfile{Tag: attrs.RatingProfileId,
rps[idx] = &engine.RatingProfile{
Tag: attrs.RatingProfileId,
Tenant: attrs.Tenant,
TOR: attrs.TOR,
Direction: attrs.Direction,

View File

@@ -25,7 +25,6 @@ import (
"github.com/cgrates/cgrates/history"
"github.com/cgrates/cgrates/utils"
"log/syslog"
"strings"
"time"
)
@@ -107,7 +106,7 @@ type CallDescriptor struct {
CallDuration time.Duration // the call duration so far (till TimeEnd)
Amount float64
FallbackSubject string // the subject to check for destination if not found on primary subject
RatingInfos []*RatingInfo
RatingInfos RatingInfos
Increments Increments
userBalance *UserBalance
}
@@ -137,55 +136,84 @@ func (cd *CallDescriptor) getUserBalance() (ub *UserBalance, err error) {
/*
Restores the activation periods for the specified prefix from storage.
*/
func (cd *CallDescriptor) LoadRatingPlans() (destPrefixes []string, matchedSubject string, err error) {
matchedSubject = cd.GetKey()
/*if val, err := cache2go.GetXCached(cd.GetKey() + cd.Destination); err == nil {
xaps := val.(xCachedRatingPlans)
cd.RatingPlans = xaps.aps
return xaps.destPrefix, matchedSubject, nil
}*/
destPrefixes, matchedSubject, values, err := cd.getRatingPlansForPrefix(cd.GetKey(), 1)
func (cd *CallDescriptor) LoadRatingPlans() (err error) {
err = cd.getRatingPlansForPrefix(cd.GetKey(), 1)
if err != nil {
// try general fallback
fallbackKey := fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, FALLBACK_SUBJECT)
// use the default subject
destPrefixes, matchedSubject, values, err = cd.getRatingPlansForPrefix(fallbackKey, 1)
err = cd.getRatingPlansForPrefix(fallbackKey, 1)
}
//load the rating plans
if err == nil && len(values) > 0 {
/*
xaps := xCachedRatingPlans{destPrefix, values, new(cache2go.XEntry)}
xaps.XCache(cd.GetKey()+cd.Destination, debitPeriod+5*time.Second, xaps)
*/
cd.RatingInfos = values
if err != nil || !cd.continousRatingInfos() {
err = errors.New("Could not determine rating plans for call")
return
}
return
}
func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int) (foundPrefixes []string, matchedSubject string, ris []*RatingInfo, err error) {
matchedSubject = key
func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int) (err error) {
if recursionDepth > RECURSION_MAX_DEPTH {
err = errors.New("Max fallback recursion depth reached!" + key)
return
}
rp, err := storageGetter.GetRatingProfile(key)
if err != nil || rp == nil {
return nil, "", nil, err
return err
}
foundPrefixes, ris, err = rp.GetRatingPlansForPrefix(cd)
if err != nil {
if rp.FallbackKey != "" {
if err = rp.GetRatingPlansForPrefix(cd); err != nil {
// try rating profile fallback
if len(rp.FallbackKeys) > 0 {
recursionDepth++
for _, fbk := range strings.Split(rp.FallbackKey, FALLBACK_SEP) {
if destPrefix, matchedSubject, values, err := cd.getRatingPlansForPrefix(fbk, recursionDepth); err == nil {
return destPrefix, matchedSubject, values, err
for _, fbk := range rp.FallbackKeys {
if err := cd.getRatingPlansForPrefix(fbk, recursionDepth); err == nil {
return err
}
}
}
}
return
}
// checks if there is rating info for the entire call duration
func (cd *CallDescriptor) continousRatingInfos() bool {
if len(cd.RatingInfos) == 0 || cd.RatingInfos[0].ActivationTime.After(cd.TimeStart) {
return false
}
for _, ri := range cd.RatingInfos {
if ri.RateIntervals == nil {
return false
}
}
return true
}
// adds a rating infos only if that call period is not already covered
// returns true if added
func (cd *CallDescriptor) addRatingInfos(ris RatingInfos) bool {
if len(cd.RatingInfos) == 0 {
cd.RatingInfos = append(cd.RatingInfos, ris...)
return true
}
cd.RatingInfos.Sort()
// check if we dont have the start covered
if cd.RatingInfos[0].ActivationTime.After(cd.TimeStart) {
if ris[0].ActivationTime.Before(cd.RatingInfos[0].ActivationTime) {
cd.RatingInfos = append(cd.RatingInfos, ris[0])
cd.RatingInfos.Sort()
}
}
for _, ri := range cd.RatingInfos {
if ri.RateIntervals == nil {
for i, new_ri := range ris {
_ = i
_ = new_ri
}
}
}
return true
}
/*
Constructs the key for the storage lookup.
The prefixLen is limiting the length of the destination prefix.
@@ -307,7 +335,7 @@ func (cd *CallDescriptor) roundTimeSpansToIncrement(timespans []*TimeSpan) []*Ti
Creates a CallCost structure with the cost information calculated for the received CallDescriptor.
*/
func (cd *CallDescriptor) GetCost() (*CallCost, error) {
destPrefix, matchedSubject, err := cd.LoadRatingPlans()
err := cd.LoadRatingPlans()
if err != nil {
Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetUserBalanceKey(), err))
return &CallCost{Cost: -1}, err
@@ -325,17 +353,19 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
}
// global rounding
cost = utils.Round(cost, roundingDecimals, roundingMethod)
startIndex := len(fmt.Sprintf("%s:%s:%s:", cd.Direction, cd.Tenant, cd.TOR))
//startIndex := len(fmt.Sprintf("%s:%s:%s:", cd.Direction, cd.Tenant, cd.TOR))
cc := &CallCost{
Direction: cd.Direction,
TOR: cd.TOR,
Tenant: cd.Tenant,
Subject: matchedSubject[startIndex:],
Account: cd.Account,
Destination: strings.Join(destPrefix, ";"),
Cost: cost,
ConnectFee: connectionFee,
Timespans: timespans}
Direction: cd.Direction,
TOR: cd.TOR,
Tenant: cd.Tenant,
// TODO, FIXME: find out where to put matched subject
//Subject: matchedSubject[startIndex:],
Account: cd.Account,
// TODO, FIXME: find out where to put matched prfixes
//Destination: strings.Join(destPrefix, ";"),
Cost: cost,
ConnectFee: connectionFee,
Timespans: timespans}
//Logger.Info(fmt.Sprintf("<Rater> Get Cost: %s => %v", cd.GetKey(), cc))
return cc, err
}
@@ -350,7 +380,7 @@ func (cd *CallDescriptor) GetMaxSessionTime(startTime time.Time) (seconds float6
if cd.CallDuration == 0 {
cd.CallDuration = cd.TimeEnd.Sub(cd.TimeStart)
}
_, _, err = cd.LoadRatingPlans()
err = cd.LoadRatingPlans()
if err != nil {
Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetUserBalanceKey(), err))
return 0, err

View File

@@ -357,17 +357,20 @@ func (csvr *CSVReader) LoadRatingProfiles() (err error) {
return errors.New(fmt.Sprintf("Could not load rating plans for tag: %v", record[5]))
}
}
rp.RatingPlanActivations = append(rp.RatingPlanActivations, &RatingPlanActivation{at, record[5]})
rpa := &RatingPlanActivation{
ActivationTime: at,
RatingPlanId: record[5],
}
if fallbacksubject != "" {
var sslice utils.StringSlice = rpa.FallbackKeys
for _, fbs := range strings.Split(fallbacksubject, ";") {
newKey := fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fbs)
var sslice utils.StringSlice = strings.Split(rp.FallbackKey, ";")
if !sslice.Contains(newKey) {
rp.FallbackKey += newKey + ";"
rpa.FallbackKeys = append(rpa.FallbackKeys, newKey)
}
}
rp.FallbackKey = strings.TrimRight(rp.FallbackKey, ";")
}
rp.RatingPlanActivations = append(rp.RatingPlanActivations, rpa)
csvr.ratingProfiles[rp.Id] = rp
}
return

View File

@@ -560,11 +560,11 @@ func TestLoadRatingProfiles(t *testing.T) {
}
rp := csvr.ratingProfiles["*out:test:0:trp"]
expected := &RatingProfile{
Id: "*out:test:0:trp",
FallbackKey: "*out:test:0:rif;*out:test:0:danb",
Id: "*out:test:0:trp",
RatingPlanActivations: RatingPlanActivations{&RatingPlanActivation{
ActivationTime: time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC),
RatingPlanId: "TDRT",
FallbackKeys: []string{"*out:test:0:rif", "*out:test:0:danb"},
}},
}
if !reflect.DeepEqual(rp, expected) {

View File

@@ -167,9 +167,9 @@ func (dbr *DbReader) LoadDestinationRates() (err error) {
}
}
if !destinationExists {
if dbExists, err := dbr.dataDb.ExistsDestination(dr.DestinationsTag); err != nil {
if dest, err := dbr.dataDb.GetDestination(dr.DestinationsTag); err != nil {
return err
} else if !dbExists {
} else if dest == nil {
return errors.New(fmt.Sprintf("Could not get destination for tag %v", dr.DestinationsTag))
}
}
@@ -218,20 +218,71 @@ func (dbr *DbReader) LoadRatingProfiles() error {
}
_, exists := dbr.ratingPlans[rp.DestRatesTimingTag]
if !exists {
if dbExists, err := dbr.dataDb.ExistsRatingPlan(rp.DestRatesTimingTag); err != nil {
if rpl, err := dbr.dataDb.GetRatingPlan(rp.DestRatesTimingTag); err != nil {
return err
} else if !dbExists {
} else if rpl == nil {
return errors.New(fmt.Sprintf("Could not load rating plans for tag: %v", rp.DestRatesTimingTag))
}
}
rp.RatingPlanActivations = append(rp.RatingPlanActivations, &RatingPlanActivation{at, rp.DestRatesTimingTag})
rp.RatingPlanActivations = append(rp.RatingPlanActivations,
&RatingPlanActivation{
ActivationTime: at,
RatingPlanId: rp.DestRatesTimingTag,
FallbackKeys: rp.FallbackKeys,
})
dbr.ratingProfiles[rp.Id] = rp
}
return nil
}
func (dbr *DbReader) LoadRatingPlanByTag(tag string) error {
ratingPlan := &RatingPlan{}
rps, err := dbr.storDb.GetTpRatingPlans(dbr.tpid, tag)
if err != nil || len(rps) == 0 {
return fmt.Errorf("No DestRateTimings profile with id %s: %v", tag, err)
}
for _, rp := range rps {
Logger.Debug(fmt.Sprintf("Rating Plan: %v", rp))
tm, err := dbr.storDb.GetTpTimings(dbr.tpid, rp.TimingTag)
Logger.Debug(fmt.Sprintf("Timing: %v", tm))
if err != nil || len(tm) == 0 {
return fmt.Errorf("No Timings profile with id %s: %v", rp.TimingTag, err)
}
rp.timing = tm[rp.TimingTag]
drm, err := dbr.storDb.GetTpDestinationRates(dbr.tpid, rp.DestinationRatesTag)
if err != nil || len(drm) == 0 {
return fmt.Errorf("No DestinationRates profile with id %s: %v", rp.DestinationRatesTag, err)
}
for _, drate := range drm[rp.DestinationRatesTag] {
Logger.Debug(fmt.Sprintf("Destination rate: %v", drate))
rt, err := dbr.storDb.GetTpRates(dbr.tpid, drate.RateTag)
if err != nil || len(rt) == 0 {
return fmt.Errorf("No Rates profile with id %s: %v", drate.RateTag, err)
}
Logger.Debug(fmt.Sprintf("Rate: %v", rt))
drate.rates = rt[drate.RateTag]
ratingPlan.AddRateInterval(drate.DestinationsTag, rp.GetRateInterval(drate))
dms, err := dbr.storDb.GetTpDestinations(dbr.tpid, drate.DestinationsTag)
if err != nil || len(dms) == 0 {
if dest, err := dbr.dataDb.GetDestination(drate.DestinationsTag); err != nil {
return err
} else if dest == nil {
return fmt.Errorf("Could not get destination for tag %v", drate.DestinationsTag)
}
}
Logger.Debug(fmt.Sprintf("Tag: %s Destinations: %v", drate.DestinationsTag, dms))
for _, destination := range dms {
Logger.Debug(fmt.Sprintf("Destination: %v", destination))
dbr.dataDb.SetDestination(destination)
}
}
}
return dbr.dataDb.SetRatingPlan(ratingPlan)
}
func (dbr *DbReader) LoadRatingProfileByTag(tag string) error {
ratingPlans := make(map[string]*RatingPlan)
resultRatingProfile := &RatingProfile{}
rpm, err := dbr.storDb.GetTpRatingProfiles(dbr.tpid, tag)
if err != nil || len(rpm) == 0 {
@@ -239,68 +290,12 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error {
}
for _, ratingProfile := range rpm {
Logger.Debug(fmt.Sprintf("Rating profile: %v", rpm))
resultRatingProfile.FallbackKey = ratingProfile.FallbackKey // it will be the last fallback key
resultRatingProfile.Id = ratingProfile.Id // idem
_, err := utils.ParseDate(ratingProfile.ActivationTime)
resultRatingProfile.Id = ratingProfile.Id // idem
at, err := utils.ParseDate(ratingProfile.ActivationTime)
if err != nil {
return fmt.Errorf("Cannot parse activation time from %v", ratingProfile.ActivationTime)
}
drtm, err := dbr.storDb.GetTpRatingPlans(dbr.tpid, ratingProfile.DestRatesTimingTag)
if err != nil || len(drtm) == 0 { // rating plan not found in storDb, check dataDb and if there will use that one
if dbExists, err := dbr.dataDb.ExistsRatingPlan(ratingProfile.DestRatesTimingTag); err != nil {
return err
} else if !dbExists {
return fmt.Errorf("No DestRateTimings profile with id %s: %v", ratingProfile.DestRatesTimingTag, err)
}
}
for _, destRateTiming := range drtm {
Logger.Debug(fmt.Sprintf("Destination rate timing: %v", rpm))
tm, err := dbr.storDb.GetTpTimings(dbr.tpid, destRateTiming.TimingTag)
Logger.Debug(fmt.Sprintf("Timing: %v", rpm))
if err != nil || len(tm) == 0 {
return fmt.Errorf("No Timings profile with id %s: %v", destRateTiming.TimingTag, err)
}
destRateTiming.timing = tm[destRateTiming.TimingTag]
drm, err := dbr.storDb.GetTpDestinationRates(dbr.tpid, destRateTiming.DestinationRatesTag)
if err != nil || len(drm) == 0 {
return fmt.Errorf("No DestinationRates profile with id %s: %v", destRateTiming.DestinationRatesTag, err)
}
for _, drate := range drm[destRateTiming.DestinationRatesTag] {
Logger.Debug(fmt.Sprintf("Destination rate: %v", rpm))
rt, err := dbr.storDb.GetTpRates(dbr.tpid, drate.RateTag)
if err != nil || len(rt) == 0 {
return fmt.Errorf("No Rates profile with id %s: %v", drate.RateTag, err)
}
Logger.Debug(fmt.Sprintf("Rate: %v", rpm))
drate.rates = rt[drate.RateTag]
if _, exists := ratingPlans[destRateTiming.Tag]; !exists {
ratingPlans[destRateTiming.Tag] = &RatingPlan{}
}
ratingPlans[destRateTiming.Tag].AddRateInterval(drate.DestinationsTag, destRateTiming.GetRateInterval(drate))
at, err := utils.ParseDate(ratingProfile.ActivationTime)
if err != nil {
return errors.New(fmt.Sprintf("Cannot parse activation time from %v", ratingProfile.ActivationTime))
}
resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations, &RatingPlanActivation{at, ratingProfile.DestRatesTimingTag})
dms, err := dbr.storDb.GetTpDestinations(dbr.tpid, drate.DestinationsTag)
if err != nil {
return fmt.Errorf("Could not get destination id %s: %v", drate.DestinationsTag, err)
} else if len(dms) == 0 {
if dbExists, err := dbr.dataDb.ExistsDestination(drate.DestinationsTag); err != nil {
return err
} else if !dbExists {
return fmt.Errorf("Could not get destination for tag %v", drate.DestinationsTag)
}
} else {
Logger.Debug(fmt.Sprintf("Tag: %s Destinations: %v", drate.DestinationsTag, dms))
for _, destination := range dms {
Logger.Debug(fmt.Sprintf("Destination: %v", rpm))
dbr.dataDb.SetDestination(destination)
}
}
}
}
resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations, &RatingPlanActivation{at, ratingProfile.DestRatesTimingTag, ratingProfile.FallbackKeys})
}
return dbr.dataDb.SetRatingProfile(resultRatingProfile)
}

View File

@@ -35,8 +35,8 @@ func TestApRestoreFromStorage(t *testing.T) {
Subject: "rif:from:tm",
Destination: "49"}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 2 {
t.Error("Error restoring activation periods: ", cd.RatingInfos)
if len(cd.RatingInfos) != 1 {
t.Errorf("Error restoring activation periods: %+v", cd.RatingInfos[0])
}
}
@@ -94,7 +94,7 @@ func TestFallbackMultiple(t *testing.T) {
Subject: "fall",
Destination: "0723045"}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 2 {
if len(cd.RatingInfos) != 1 {
t.Errorf("Error restoring rating plans: %+v", cd.RatingInfos)
}
}
@@ -200,6 +200,22 @@ func TestApAddRateIntervalGroups(t *testing.T) {
}
}
func TestGetActiveForCall(t *testing.T) {
rpas := RatingPlanActivations{
&RatingPlanActivation{ActivationTime: time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)},
&RatingPlanActivation{ActivationTime: time.Date(2013, 11, 12, 11, 40, 0, 0, time.UTC)},
&RatingPlanActivation{ActivationTime: time.Date(2013, 11, 13, 0, 0, 0, 0, time.UTC)},
}
cd := &CallDescriptor{
TimeStart: time.Date(2013, 11, 12, 11, 39, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 11, 12, 11, 45, 0, 0, time.UTC),
}
active := rpas.GetActiveForCall(cd)
if len(active) != 2 {
t.Errorf("Error getting active rating plans: %+v", active)
}
}
/**************************** Benchmarks *************************************/
func BenchmarkRatingPlanMarshalJson(b *testing.B) {

View File

@@ -27,15 +27,16 @@ import (
type RatingProfile struct {
Id string
FallbackKey string // FallbackKey is used as complete combination of Tenant:TOR:Direction:Subject
RatingPlanActivations RatingPlanActivations
Tag, Tenant, TOR, Direction, Subject string // used only for loading
DestRatesTimingTag, RatesFallbackSubject, ActivationTime string // used only for loading
Tag, Tenant, TOR, Direction, Subject string // used only for loading
DestRatesTimingTag, RatesFallbackSubject, ActivationTime string // used only for loading
FallbackKeys []string // used only for loading
}
type RatingPlanActivation struct {
ActivationTime time.Time
RatingPlanId string
FallbackKeys []string
}
func (rpa *RatingPlanActivation) Equal(orpa *RatingPlanActivation) bool {
@@ -60,45 +61,84 @@ func (rpas RatingPlanActivations) Sort() {
sort.Sort(rpas)
}
func (rpas RatingPlanActivations) GetActiveForCall(cd *CallDescriptor) RatingPlanActivations {
rpas.Sort()
lastBeforeCallStart := 0
firstAfterCallEnd := len(rpas)
for index, rpa := range rpas {
if rpa.ActivationTime.Before(cd.TimeStart) || rpa.ActivationTime.Equal(cd.TimeStart) {
lastBeforeCallStart = index
}
if rpa.ActivationTime.After(cd.TimeEnd) {
firstAfterCallEnd = index
break
}
}
return rpas[lastBeforeCallStart:firstAfterCallEnd]
}
type RatingInfo struct {
MatchedSubject string
MatchedPrefix string
ActivationTime time.Time
RateIntervals RateIntervalList
}
type RatingInfos []*RatingInfo
func (ris RatingInfos) Len() int {
return len(ris)
}
func (ris RatingInfos) Swap(i, j int) {
ris[i], ris[j] = ris[j], ris[i]
}
func (ris RatingInfos) Less(i, j int) bool {
return ris[i].ActivationTime.Before(ris[j].ActivationTime)
}
func (ris RatingInfos) Sort() {
sort.Sort(ris)
}
// TODO: what happens if there is no match for part of the call
func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (foundPrefixes []string, ris []*RatingInfo, err error) {
rp.RatingPlanActivations.Sort()
for _, rpa := range rp.RatingPlanActivations {
if rpa.ActivationTime.Before(cd.TimeEnd) {
rpl, err := storageGetter.GetRatingPlan(rpa.RatingPlanId)
if err != nil || rpl == nil {
func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (err error) {
var ris RatingInfos
for _, rpa := range rp.RatingPlanActivations.GetActiveForCall(cd) {
rpl, err := storageGetter.GetRatingPlan(rpa.RatingPlanId)
if err != nil || rpl == nil {
Logger.Err(fmt.Sprintf("Error checking destination: %v", err))
continue
}
bestPrecision := 0
var rps RateIntervalList
for dId, _ := range rpl.DestinationRates {
//precision, err := storageGetter.DestinationContainsPrefix(dId, cd.Destination)
d, err := storageGetter.GetDestination(dId)
if err != nil {
Logger.Err(fmt.Sprintf("Error checking destination: %v", err))
continue
}
bestPrecision := 0
var rps RateIntervalList
for dId, _ := range rpl.DestinationRates {
//precision, err := storageGetter.DestinationContainsPrefix(dId, cd.Destination)
d, err := storageGetter.GetDestination(dId)
if err != nil {
Logger.Err(fmt.Sprintf("Error checking destination: %v", err))
continue
}
precision := d.containsPrefix(cd.Destination)
if precision > bestPrecision {
bestPrecision = precision
rps = rpl.RateIntervalList(dId)
}
precision := d.containsPrefix(cd.Destination)
if precision > bestPrecision {
bestPrecision = precision
rps = rpl.RateIntervalList(dId)
}
if bestPrecision > 0 {
ris = append(ris, &RatingInfo{rpa.ActivationTime, rps})
foundPrefixes = append(foundPrefixes, cd.Destination[:bestPrecision])
}
if bestPrecision > 0 {
ris = append(ris, &RatingInfo{rp.Id, cd.Destination[:bestPrecision], rpa.ActivationTime, rps})
} else {
// mark the end of previous!
if len(cd.RatingInfos) > 0 {
ris = append(ris, &RatingInfo{"", "", rpa.ActivationTime, nil})
}
}
}
if len(ris) > 0 {
return foundPrefixes, ris, nil
cd.addRatingInfos(ris)
return
}
return nil, nil, errors.New("not found")
return errors.New("not found")
}

View File

@@ -65,13 +65,11 @@ type DataStorage interface {
PreCache([]string, []string) error
GetRatingPlan(string) (*RatingPlan, error)
SetRatingPlan(*RatingPlan) error
ExistsRatingPlan(string) (bool, error)
GetRatingProfile(string) (*RatingProfile, error)
SetRatingProfile(*RatingProfile) error
GetDestination(string) (*Destination, error)
// DestinationContainsPrefix(string, string) (int, error)
SetDestination(*Destination) error
ExistsDestination(string) (bool, error)
GetActions(string) (Actions, error)
SetActions(string, Actions) error
GetUserBalance(string) (*UserBalance, error)

View File

@@ -83,11 +83,6 @@ func (ms *MapStorage) SetRatingPlan(rp *RatingPlan) (err error) {
return
}
func (ms *MapStorage) ExistsRatingPlan(rpId string) (bool, error) {
_, exists := ms.dict[RATING_PLAN_PREFIX+rpId]
return exists, nil
}
func (ms *MapStorage) GetRatingProfile(key string) (rp *RatingProfile, err error) {
if values, ok := ms.dict[RATING_PROFILE_PREFIX+key]; ok {
rp = new(RatingProfile)
@@ -142,11 +137,6 @@ func (ms *MapStorage) SetDestination(dest *Destination) (err error) {
return
}
func (ms *MapStorage) ExistsDestination(destId string) (bool, error) {
_, exists := ms.dict[DESTINATION_PREFIX+destId]
return exists, nil
}
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)

View File

@@ -141,10 +141,6 @@ func (rs *RedisStorage) SetRatingPlan(rp *RatingPlan) (err error) {
return
}
func (rs *RedisStorage) ExistsRatingPlan(rpId string) (bool, error) {
return rs.db.Exists(RATING_PLAN_PREFIX + rpId)
}
func (rs *RedisStorage) GetRatingProfile(key string) (rp *RatingProfile, err error) {
var values string
if values, err = rs.db.Get(RATING_PROFILE_PREFIX + key); err == nil {
@@ -219,10 +215,6 @@ func (rs *RedisStorage) SetDestination(dest *Destination) (err error) {
return
}
func (rs *RedisStorage) ExistsDestination(destId string) (bool, error) {
return rs.db.Exists(DESTINATION_PREFIX+destId)
}
func (rs *RedisStorage) GetActions(key string) (as Actions, err error) {
var values string
if values, err = rs.db.Get(ACTION_PREFIX + key); err == nil {

View File

@@ -1104,12 +1104,11 @@ func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*Ratin
if fallback_subject != "" {
for _, fbs := range strings.Split(fallback_subject, ";") {
newKey := fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fbs)
var sslice utils.StringSlice = strings.Split(rp.FallbackKey, ";")
var sslice utils.StringSlice = rp.FallbackKeys
if !sslice.Contains(newKey) {
rp.FallbackKey += newKey + ";"
rp.FallbackKeys = append(rp.FallbackKeys, newKey)
}
}
rp.FallbackKey = strings.TrimRight(rp.FallbackKey, ";")
}
}
return rpfs, nil

View File

@@ -249,7 +249,8 @@ func (self *TPCSVImporter) importRatingProfiles(fn string) error {
if self.ImportId != "" {
rpTag += "_" + self.ImportId
}
rp := &RatingProfile{Tag: rpTag,
rp := &RatingProfile{
Tag: rpTag,
Tenant: tenant,
TOR: tor,
Direction: direction,