diff --git a/apier/v1/tpactions.go b/apier/v1/tpactions.go index 62849693f..b2cde95c2 100644 --- a/apier/v1/tpactions.go +++ b/apier/v1/tpactions.go @@ -50,13 +50,15 @@ func (self *ApierV1) SetTPActions(attrs utils.TPActions, reply *string) error { ActionType: act.Identifier, BalanceId: act.BalanceType, Direction: act.Direction, - Units: act.Units, ExpirationString: act.ExpiryTime, - DestinationTag: act.DestinationId, - RateType: act.RateType, - RateValue: act.Rate, - MinutesWeight: act.MinutesWeight, - Weight: act.Weight, + Balance: &engine.Balance{ + Value: act.Units, + DestinationId: act.DestinationId, + SpecialPriceType: act.RateType, + SpecialPrice: act.Rate, + Weight: act.MinutesWeight, + }, + Weight: act.Weight, } } if err := self.StorDb.SetTPActions(attrs.TPid, map[string][]*engine.Action{attrs.ActionsId: acts}); err != nil { diff --git a/apier/v1/tprates.go b/apier/v1/tprates.go index 1fd6cae71..641eb5872 100644 --- a/apier/v1/tprates.go +++ b/apier/v1/tprates.go @@ -23,9 +23,9 @@ package apier import ( "errors" "fmt" - "time" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" + "time" ) // Creates a new rate within a tariff plan @@ -38,7 +38,7 @@ func (self *ApierV1) SetTPRate(attrs utils.TPRate, reply *string) error { } else if exists { return errors.New(utils.ERR_DUPLICATE) } - rts := make([]*engine.Rate, len(attrs.RateSlots)) + rts := make([]*engine.LoadRate, len(attrs.RateSlots)) for idx, rtSlot := range attrs.RateSlots { var errParse error itrvlStrs := []string{rtSlot.RatedUnits, rtSlot.RateIncrements, rtSlot.GroupIntervalStart} @@ -48,10 +48,10 @@ func (self *ApierV1) SetTPRate(attrs utils.TPRate, reply *string) error { return fmt.Errorf("%s:Parsing interval failed:%s", utils.ERR_SERVER_ERROR, errParse.Error()) } } - rts[idx] = &engine.Rate{attrs.RateId, rtSlot.ConnectFee, rtSlot.Rate, itrvls[0], itrvls[1], itrvls[2], + rts[idx] = &engine.LoadRate{attrs.RateId, rtSlot.ConnectFee, rtSlot.Rate, itrvls[0], itrvls[1], itrvls[2], rtSlot.RoundingMethod, rtSlot.RoundingDecimals, rtSlot.Weight} } - if err := self.StorDb.SetTPRates(attrs.TPid, map[string][]*engine.Rate{attrs.RateId: rts}); err != nil { + if err := self.StorDb.SetTPRates(attrs.TPid, map[string][]*engine.LoadRate{attrs.RateId: rts}); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } *reply = "OK" diff --git a/docs/ratinglogic.rst b/docs/ratinglogic.rst index 9470b55d3..535d54a7d 100644 --- a/docs/ratinglogic.rst +++ b/docs/ratinglogic.rst @@ -15,7 +15,7 @@ The call information comes to CGRateS having the following vital information lik LoopIndex // indicates the position of this segment in a cost request loop CallDuration // the call duration so far (partial or final) FallbackSubject // the subject to check for destination if not found on primary subject - ActivationPeriods + RatingPlans } When the session manager receives a call start event it will first check if the call is prepaid or postpaid. If the call is postpaid than the cost will be determined only once at the end of the call but if the call is prepaid there will be a debit operation every X seconds (X is configurable). @@ -31,7 +31,7 @@ What are the activation periods? :: - type Interval struct { + type RateInterval struct { Years Months MonthDays @@ -51,9 +51,9 @@ What are the activation periods? } -An **Interval** specifies the Month, the MonthDay, the WeekDays, the StartTime and the EndTime when the Interval's price profile is in effect. +An **RateInterval** specifies the Month, the MonthDay, the WeekDays, the StartTime and the EndTime when the RateInterval's price profile is in effect. -:Example: The Interval {"Month": [1], "WeekDays":[1,2,3,4,5], "StartTime":"18:00:00"} specifies the *Price* for the first month of each year from Monday to Friday starting 18:00. Most structure elements are optional and they can be combined in any way it makes sense. If an element is omitted it means it is zero or any. +:Example: The RateInterval {"Month": [1], "WeekDays":[1,2,3,4,5], "StartTime":"18:00:00"} specifies the *Price* for the first month of each year from Monday to Friday starting 18:00. Most structure elements are optional and they can be combined in any way it makes sense. If an element is omitted it means it is zero or any. The *ConnectFee* specifies the connection price for the call if this interval is the first one of the call. @@ -65,7 +65,7 @@ The *RoundingMethod* and the *RoundingDecimals* will adjust the price using the The **Price** structure defines the start (*GroupIntervalStart*) of a section of a call with a specified rate *Value* per *RateUnit* diving and rounding the section in *RateIncrement* subsections. -So when there is a need to define new sets of prices just define new ActivationPeriods with the activation time set to the moment when it becomes active. +So when there is a need to define new sets of prices just define new RatingPlans with the activation time set to the moment when it becomes active. Let's get back to the engine. When a GetCost or Debit call comes to the engine it will try to match the best rating profile for the given *Direction*, *Tenant*, *TOR* and *Subject* using the longest *Subject* prefix method or using the *FallbackSubject* if not found. The rating profile contains the activation periods that might apply to the call in question. @@ -75,21 +75,21 @@ At this point in rating process the engine will start splitting the call into va 2. Activation periods: if there were not enough special price minutes available than the engine will check if the call spans over multiple activation periods (the call starts in initial rates period and continues in another). -3. Intervals: for each activation period that apply to the call the engine will select the best rate intervals that apply. +3. RateIntervals: for each activation period that apply to the call the engine will select the best rate intervals that apply. :: type TimeSpan struct { TimeStart, TimeEnd Cost - ActivationPeriod - Interval + RatingPlan + RateInterval MinuteInfo CallDuration // the call duration so far till TimeEnd } -The result of this splitting will be a list of *TimeSpan* structures each having attached the MinuteInfo or the Interval that gave the price for it. The *CallDuration* attribute will select the right *Price* from the *Interval* *Prices* list. The final cost for the call will be the sum of the prices of these times spans plus the *ConnectionFee* from the first time span of the call. +The result of this splitting will be a list of *TimeSpan* structures each having attached the MinuteInfo or the RateInterval that gave the price for it. The *CallDuration* attribute will select the right *Price* from the *RateInterval* *Prices* list. The final cost for the call will be the sum of the prices of these times spans plus the *ConnectionFee* from the first time span of the call. 6.2.1 User balances ------------------- diff --git a/engine/action.go b/engine/action.go index 039264ca1..23463914f 100644 --- a/engine/action.go +++ b/engine/action.go @@ -21,23 +21,19 @@ package engine import ( "fmt" "sort" - "time" ) /* Structure to be filled for each tariff plan with the bonus value for received calls minutes. */ type Action struct { - Id string - ActionType string - BalanceId string - Direction string - ExpirationString string - Weight float64 - Balance *Balance - DestinationTag, RateType string // From here for import/load purposes only - ExpirationDate time.Time - Units, RateValue, MinutesWeight float64 + Id string + ActionType string + BalanceId string + Direction string + ExpirationString string + Weight float64 + Balance *Balance } const ( diff --git a/engine/action_timing.go b/engine/action_timing.go index a608b9dcb..ae84f8835 100644 --- a/engine/action_timing.go +++ b/engine/action_timing.go @@ -37,7 +37,7 @@ type ActionTiming struct { Id string // uniquely identify the timing Tag string // informative purpose only UserBalanceIds []string - Timing *Interval + Timing *RateInterval Weight float64 ActionsId string actions Actions diff --git a/engine/actions_test.go b/engine/actions_test.go index 85d52399c..06d2a595f 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -34,7 +34,7 @@ func TestActionTimingNothing(t *testing.T) { } func TestActionTimingOnlyHour(t *testing.T) { - at := &ActionTiming{Timing: &Interval{StartTime: "10:01:00"}} + at := &ActionTiming{Timing: &RateInterval{StartTime: "10:01:00"}} st := at.GetNextStartTime() now := time.Now() y, m, d := now.Date() @@ -45,7 +45,7 @@ func TestActionTimingOnlyHour(t *testing.T) { } func TestActionTimingOnlyWeekdays(t *testing.T) { - at := &ActionTiming{Timing: &Interval{WeekDays: []time.Weekday{time.Monday}}} + at := &ActionTiming{Timing: &RateInterval{WeekDays: []time.Weekday{time.Monday}}} st := at.GetNextStartTime() now := time.Now() y, m, d := now.Date() @@ -64,7 +64,7 @@ func TestActionTimingOnlyWeekdays(t *testing.T) { } func TestActionTimingHourWeekdays(t *testing.T) { - at := &ActionTiming{Timing: &Interval{WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}} + at := &ActionTiming{Timing: &RateInterval{WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}} st := at.GetNextStartTime() now := time.Now() y, m, d := now.Date() @@ -85,7 +85,7 @@ func TestActionTimingOnlyMonthdays(t *testing.T) { now := time.Now() y, m, d := now.Date() tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - at := &ActionTiming{Timing: &Interval{MonthDays: MonthDays{1, 25, 2, tomorrow.Day()}}} + at := &ActionTiming{Timing: &RateInterval{MonthDays: MonthDays{1, 25, 2, tomorrow.Day()}}} st := at.GetNextStartTime() expected := tomorrow if !st.Equal(expected) { @@ -102,7 +102,7 @@ func TestActionTimingHourMonthdays(t *testing.T) { if now.After(testTime) { day = tomorrow.Day() } - at := &ActionTiming{Timing: &Interval{MonthDays: MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}} + at := &ActionTiming{Timing: &RateInterval{MonthDays: MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}} st := at.GetNextStartTime() expected := time.Date(y, m, day, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -114,7 +114,7 @@ func TestActionTimingOnlyMonths(t *testing.T) { now := time.Now() y, m, d := now.Date() nextMonth := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionTiming{Timing: &Interval{Months: Months{time.February, time.May, nextMonth.Month()}}} + at := &ActionTiming{Timing: &RateInterval{Months: Months{time.February, time.May, nextMonth.Month()}}} st := at.GetNextStartTime() expected := time.Date(y, nextMonth.Month(), 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -131,7 +131,7 @@ func TestActionTimingHourMonths(t *testing.T) { if now.After(testTime) { month = nextMonth.Month() } - at := &ActionTiming{Timing: &Interval{Months: Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}} + at := &ActionTiming{Timing: &RateInterval{Months: Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}} st := at.GetNextStartTime() expected := time.Date(y, month, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -156,7 +156,7 @@ func TestActionTimingHourMonthdaysMonths(t *testing.T) { month = nextMonth.Month() } } - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Months: Months{now.Month(), nextMonth.Month()}, MonthDays: MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00", @@ -172,7 +172,7 @@ func TestActionTimingFirstOfTheMonth(t *testing.T) { now := time.Now() y, m, _ := now.Date() nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{1}, }} @@ -187,7 +187,7 @@ func TestActionTimingOnlyYears(t *testing.T) { now := time.Now() y, m, d := now.Date() nextYear := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionTiming{Timing: &Interval{Years: Years{now.Year(), nextYear.Year()}}} + at := &ActionTiming{Timing: &RateInterval{Years: Years{now.Year(), nextYear.Year()}}} st := at.GetNextStartTime() expected := time.Date(nextYear.Year(), 1, 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -204,7 +204,7 @@ func TestActionTimingHourYears(t *testing.T) { if now.After(testTime) { year = nextYear.Year() } - at := &ActionTiming{Timing: &Interval{Years: Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}} + at := &ActionTiming{Timing: &RateInterval{Years: Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}} st := at.GetNextStartTime() expected := time.Date(year, m, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -229,7 +229,7 @@ func TestActionTimingHourMonthdaysYear(t *testing.T) { year = nextYear.Year() } } - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Years: Years{now.Year(), nextYear.Year()}, MonthDays: MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00", @@ -266,7 +266,7 @@ func TestActionTimingHourMonthdaysMonthYear(t *testing.T) { year = nextYear.Year() } } - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Years: Years{now.Year(), nextYear.Year()}, Months: Months{now.Month(), nextMonth.Month()}, MonthDays: MonthDays{now.Day(), tomorrow.Day()}, @@ -283,7 +283,7 @@ func TestActionTimingFirstOfTheYear(t *testing.T) { now := time.Now() y, _, _ := now.Date() nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Years: Years{nextYear.Year()}, Months: Months{time.January}, MonthDays: MonthDays{1}, @@ -300,7 +300,7 @@ func TestActionTimingFirstMonthOfTheYear(t *testing.T) { now := time.Now() y, _, _ := now.Date() nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionTiming{Timing: &Interval{ + at := &ActionTiming{Timing: &RateInterval{ Months: Months{time.January}, }} st := at.GetNextStartTime() @@ -311,14 +311,14 @@ func TestActionTimingFirstMonthOfTheYear(t *testing.T) { } func TestActionTimingCheckForASAP(t *testing.T) { - at := &ActionTiming{Timing: &Interval{StartTime: ASAP}} + at := &ActionTiming{Timing: &RateInterval{StartTime: ASAP}} if !at.CheckForASAP() { t.Errorf("%v should be asap!", at) } } func TestActionTimingIsOneTimeRun(t *testing.T) { - at := &ActionTiming{Timing: &Interval{StartTime: ASAP}} + at := &ActionTiming{Timing: &RateInterval{StartTime: ASAP}} if !at.CheckForASAP() { t.Errorf("%v should be asap!", at) } @@ -328,7 +328,7 @@ func TestActionTimingIsOneTimeRun(t *testing.T) { } func TestActionTimingOneTimeRun(t *testing.T) { - at := &ActionTiming{Timing: &Interval{StartTime: ASAP}} + at := &ActionTiming{Timing: &RateInterval{StartTime: ASAP}} at.CheckForASAP() nextRun := at.GetNextStartTime() if nextRun.IsZero() { @@ -352,14 +352,14 @@ func TestActionTimingLogFunction(t *testing.T) { } func TestActionTimingPriotityListSortByWeight(t *testing.T) { - at1 := &ActionTiming{Timing: &Interval{ + at1 := &ActionTiming{Timing: &RateInterval{ Years: Years{2100}, Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{1}, StartTime: "00:00:00", Weight: 20, }} - at2 := &ActionTiming{Timing: &Interval{ + at2 := &ActionTiming{Timing: &RateInterval{ Years: Years{2100}, Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{2}, @@ -376,7 +376,7 @@ func TestActionTimingPriotityListSortByWeight(t *testing.T) { func TestActionTimingPriotityListWeight(t *testing.T) { at1 := &ActionTiming{ - Timing: &Interval{ + Timing: &RateInterval{ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{1}, StartTime: "00:00:00", @@ -384,7 +384,7 @@ func TestActionTimingPriotityListWeight(t *testing.T) { Weight: 10.0, } at2 := &ActionTiming{ - Timing: &Interval{ + Timing: &RateInterval{ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{1}, StartTime: "00:00:00", @@ -848,7 +848,7 @@ func TestActionTriggerLogging(t *testing.T) { } func TestActionTimingLogging(t *testing.T) { - i := &Interval{ + i := &RateInterval{ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, @@ -856,7 +856,7 @@ func TestActionTimingLogging(t *testing.T) { EndTime: "00:00:00", Weight: 10.0, ConnectFee: 0.0, - Prices: PriceGroups{&Price{0, 1.0, 1 * time.Second, 60 * time.Second}}, + Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 60 * time.Second}}, } at := &ActionTiming{ Id: "some uuid", diff --git a/engine/callcost.go b/engine/callcost.go index 499e1c09b..7c75f29ab 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -47,8 +47,8 @@ func (cc *CallCost) Merge(other *CallCost) { } ts := cc.Timespans[len(cc.Timespans)-1] otherTs := other.Timespans[0] - if reflect.DeepEqual(ts.ActivationPeriod, otherTs.ActivationPeriod) && - reflect.DeepEqual(ts.MinuteInfo, otherTs.MinuteInfo) && reflect.DeepEqual(ts.Interval, otherTs.Interval) { + if reflect.DeepEqual(ts.RatingPlan, otherTs.RatingPlan) && + reflect.DeepEqual(ts.MinuteInfo, otherTs.MinuteInfo) && reflect.DeepEqual(ts.RateInterval, otherTs.RateInterval) { // extend the last timespan with ts.TimeEnd = ts.TimeEnd.Add(otherTs.GetDuration()) // add the rest of the timspans diff --git a/engine/callcost_test.go b/engine/callcost_test.go index 57e13c043..d1e9f364b 100644 --- a/engine/callcost_test.go +++ b/engine/callcost_test.go @@ -56,7 +56,7 @@ func TestMultipleResultMerge(t *testing.T) { if cc1.Cost != 60 { t.Errorf("expected 60 was %v", cc1.Cost) for _, ts := range cc1.Timespans { - t.Log(ts.Interval) + t.Log(ts.RateInterval) } } t1 = time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC) @@ -66,7 +66,7 @@ func TestMultipleResultMerge(t *testing.T) { if cc2.Cost != 30 { t.Errorf("expected 30 was %v", cc2.Cost) for _, ts := range cc1.Timespans { - t.Log(ts.Interval) + t.Log(ts.RateInterval) } } cc1.Merge(cc2) diff --git a/engine/calldesc.go b/engine/calldesc.go index becd10a58..9211af136 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -107,13 +107,13 @@ type CallDescriptor struct { CallDuration time.Duration // the call duration so far (partial or final) Amount float64 FallbackSubject string // the subject to check for destination if not found on primary subject - ActivationPeriods []*ActivationPeriod + RatingPlans []*RatingPlan userBalance *UserBalance } // Adds an activation period that applyes to current call descriptor. -func (cd *CallDescriptor) AddActivationPeriod(aps ...*ActivationPeriod) { - cd.ActivationPeriods = append(cd.ActivationPeriods, aps...) +func (cd *CallDescriptor) AddRatingPlan(aps ...*RatingPlan) { + cd.RatingPlans = append(cd.RatingPlans, aps...) } // Returns the key used to retrive the user balance involved in this call @@ -136,28 +136,28 @@ func (cd *CallDescriptor) getUserBalance() (ub *UserBalance, err error) { /* Restores the activation periods for the specified prefix from storage. */ -func (cd *CallDescriptor) LoadActivationPeriods() (destPrefix string, err error) { +func (cd *CallDescriptor) LoadRatingPlans() (destPrefix string, err error) { if val, err := cache2go.GetXCached(cd.GetKey() + cd.Destination); err == nil { - xaps := val.(xCachedActivationPeriods) - cd.ActivationPeriods = xaps.aps + xaps := val.(xCachedRatingPlans) + cd.RatingPlans = xaps.aps return xaps.destPrefix, nil } - destPrefix, values, err := cd.getActivationPeriodsForPrefix(cd.GetKey(), 1) + destPrefix, values, err := cd.getRatingPlansForPrefix(cd.GetKey(), 1) if err != nil { fallbackKey := fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, FALLBACK_SUBJECT) // use the default subject - destPrefix, values, err = cd.getActivationPeriodsForPrefix(fallbackKey, 1) + destPrefix, values, err = cd.getRatingPlansForPrefix(fallbackKey, 1) } //load the activation preriods if err == nil && len(values) > 0 { - xaps := xCachedActivationPeriods{destPrefix, values, new(cache2go.XEntry)} + xaps := xCachedRatingPlans{destPrefix, values, new(cache2go.XEntry)} xaps.XCache(cd.GetKey()+cd.Destination, debitPeriod+5*time.Second, xaps) - cd.ActivationPeriods = values + cd.RatingPlans = values } return } -func (cd *CallDescriptor) getActivationPeriodsForPrefix(key string, recursionDepth int) (foundPrefix string, aps []*ActivationPeriod, err error) { +func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int) (foundPrefix string, aps []*RatingPlan, err error) { if recursionDepth > RECURSION_MAX_DEPTH { err = errors.New("Max fallback recursion depth reached!" + key) return @@ -166,12 +166,12 @@ func (cd *CallDescriptor) getActivationPeriodsForPrefix(key string, recursionDep if err != nil { return "", nil, err } - foundPrefix, aps, err = rp.GetActivationPeriodsForPrefix(cd.Destination) + foundPrefix, aps, err = rp.GetRatingPlansForPrefix(cd.Destination) if err != nil { if rp.FallbackKey != "" { recursionDepth++ for _, fbk := range strings.Split(rp.FallbackKey, FALLBACK_SEP) { - if destPrefix, values, err := cd.getActivationPeriodsForPrefix(fbk, recursionDepth); err == nil { + if destPrefix, values, err := cd.getRatingPlansForPrefix(fbk, recursionDepth); err == nil { return destPrefix, values, err } } @@ -217,23 +217,23 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti if firstSpan.MinuteInfo != nil { return // all the timespans are on minutes } - if len(cd.ActivationPeriods) == 0 { + if len(cd.RatingPlans) == 0 { return } - firstSpan.ActivationPeriod = cd.ActivationPeriods[0] + firstSpan.RatingPlan = cd.RatingPlans[0] // split on activation periods afterStart, afterEnd := false, false //optimization for multiple activation periods - for _, ap := range cd.ActivationPeriods { + for _, ap := range cd.RatingPlans { if !afterStart && !afterEnd && ap.ActivationTime.Before(cd.TimeStart) { - firstSpan.ActivationPeriod = ap + firstSpan.RatingPlan = ap } else { afterStart = true for i := 0; i < len(timespans); i++ { if timespans[i].MinuteInfo != nil { continue } - newTs := timespans[i].SplitByActivationPeriod(ap) + newTs := timespans[i].SplitByRatingPlan(ap) if newTs != nil { timespans = append(timespans, newTs) } else { @@ -248,16 +248,16 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti if timespans[i].MinuteInfo != nil { continue // cont try to split timespans payed with minutes } - ap := timespans[i].ActivationPeriod - //timespans[i].ActivationPeriod = nil - ap.Intervals.Sort() - for _, interval := range ap.Intervals { - if timespans[i].Interval != nil && timespans[i].Interval.Weight < interval.Weight { + ap := timespans[i].RatingPlan + //timespans[i].RatingPlan = nil + ap.RateIntervals.Sort() + for _, interval := range ap.RateIntervals { + if timespans[i].RateInterval != nil && timespans[i].RateInterval.Weight < interval.Weight { continue // if the timespan has an interval than it already has a heigher weight } - newTs := timespans[i].SplitByInterval(interval) + newTs := timespans[i].SplitByRateInterval(interval) if newTs != nil { - newTs.ActivationPeriod = ap + newTs.RatingPlan = ap timespans = append(timespans, newTs) } } @@ -266,15 +266,20 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti return } -// if the rate interval for any timespan has a RatingInterval larger than the timespan duration +// if the rate interval for any timespan has a RatingIncrement larger than the timespan duration // the timespan must expand potentially overlaping folowing timespans and may exceed call // descriptor's initial duration func (cd *CallDescriptor) expandTimeSpans(timespans []*TimeSpan) []*TimeSpan { for i, ts := range timespans { - if ts.Interval != nil { - _, rateIncrement, _ := ts.Interval.GetPriceParameters(ts.GetGroupStart()) + if ts.RateInterval != nil { + _, rateIncrement, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) + // if the timespan duration is larger than the rate increment make sure it is a multiple of it + if rateIncrement < ts.GetDuration() { + rateIncrement = utils.RoundTo(rateIncrement, ts.GetDuration()) + } if rateIncrement > ts.GetDuration() { ts.TimeEnd = ts.TimeStart.Add(rateIncrement) + ts.SetNewCallDuration(ts) // set new call duration for this timespan // overlap the rest of the timespans for ; i < len(timespans); i++ { if timespans[i].TimeEnd.Before(ts.TimeEnd) { @@ -301,7 +306,7 @@ func (cd *CallDescriptor) expandTimeSpans(timespans []*TimeSpan) []*TimeSpan { Creates a CallCost structure with the cost information calculated for the received CallDescriptor. */ func (cd *CallDescriptor) GetCost() (*CallCost, error) { - destPrefix, err := cd.LoadActivationPeriods() + destPrefix, 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 @@ -312,8 +317,8 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) { for i, ts := range timespans { // only add connect fee if this is the first/only call cost request - if cd.LoopIndex == 0 && i == 0 && ts.MinuteInfo == nil && ts.Interval != nil { - connectionFee = ts.Interval.ConnectFee + if cd.LoopIndex == 0 && i == 0 && ts.MinuteInfo == nil && ts.RateInterval != nil { + connectionFee = ts.RateInterval.ConnectFee } cost += ts.getCost(cd) } @@ -339,7 +344,7 @@ If the user has no credit then it will return 0. If the user has postpayed plan it returns -1. */ func (cd *CallDescriptor) GetMaxSessionTime(startTime time.Time) (seconds float64, err error) { - _, err = cd.LoadActivationPeriods() + _, err = cd.LoadRatingPlans() if err != nil { Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetUserBalanceKey(), err)) return 0, err @@ -371,8 +376,8 @@ func (cd *CallDescriptor) GetMaxSessionTime(startTime time.Time) (seconds float6 cost := 0.0 for i, ts := range timespans { - if i == 0 && ts.MinuteInfo == nil && ts.Interval != nil { - cost += ts.Interval.ConnectFee + if i == 0 && ts.MinuteInfo == nil && ts.RateInterval != nil { + cost += ts.RateInterval.ConnectFee } cost += ts.getCost(cd) } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 936c5e0b5..6871a8bca 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -68,10 +68,10 @@ func TestSplitSpans(t *testing.T) { t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} - cd.LoadActivationPeriods() + cd.LoadRatingPlans() timespans := cd.splitInTimeSpans(nil) if len(timespans) != 2 { - t.Log(cd.ActivationPeriods) + t.Log(cd.RatingPlans) t.Error("Wrong number of timespans: ", len(timespans)) } } @@ -116,7 +116,7 @@ func TestFullDestNotFound(t *testing.T) { result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { - t.Log(cd.ActivationPeriods) + t.Log(cd.RatingPlans) t.Errorf("Expected %v was %v", expected, result) } } @@ -128,12 +128,12 @@ func TestSubjectNotFound(t *testing.T) { result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { - t.Log(cd.ActivationPeriods) + t.Log(cd.RatingPlans) t.Errorf("Expected %v was %v", expected, result) } } -func TestMultipleActivationPeriods(t *testing.T) { +func TestMultipleRatingPlans(t *testing.T) { t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC) cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} @@ -145,7 +145,7 @@ func TestMultipleActivationPeriods(t *testing.T) { } } -func TestSpansMultipleActivationPeriods(t *testing.T) { +func TestSpansMultipleRatingPlans(t *testing.T) { t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC) cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} @@ -242,7 +242,7 @@ func BenchmarkStorageRestoring(b *testing.B) { cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { - cd.LoadActivationPeriods() + cd.LoadRatingPlans() } } @@ -262,7 +262,7 @@ func BenchmarkSplitting(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} - cd.LoadActivationPeriods() + cd.LoadRatingPlans() b.StartTimer() for i := 0; i < b.N; i++ { cd.splitInTimeSpans(nil) diff --git a/engine/history_test.go b/engine/history_test.go index 976dba2c7..274c25289 100644 --- a/engine/history_test.go +++ b/engine/history_test.go @@ -36,19 +36,3 @@ func TestHistoryDestinations(t *testing.T) { t.Error("Error in destination history content:", scribe.DestBuf.String()) } } - -func TestHistoryratingProfiles(t *testing.T) { - scribe := historyScribe.(*history.MockScribe) - expected := `[{"Key":"*out:CUSTOMER_1:0:danb","Object":{"Id":"*out:CUSTOMER_1:0:danb","FallbackKey":"","DestinationMap":{"ALL":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:CUSTOMER_1:0:rif:from:tm","Object":{"Id":"*out:CUSTOMER_1:0:rif:from:tm","FallbackKey":"*out:CUSTOMER_1:0:danb","DestinationMap":{"ALL":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:CUSTOMER_2:0:danb:87.139.12.167","Object":{"Id":"*out:CUSTOMER_2:0:danb:87.139.12.167","FallbackKey":"*out:CUSTOMER_2:0:danb","DestinationMap":{"ALL":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:*any","Object":{"Id":"*out:vdf:0:*any","FallbackKey":"","DestinationMap":{"ALL":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:fall","Object":{"Id":"*out:vdf:0:fall","FallbackKey":"*out:vdf:0:rif","DestinationMap":{"ALL":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:inf","Object":{"Id":"*out:vdf:0:inf","FallbackKey":"*out:vdf:0:inf","DestinationMap":{"ALL":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:minu","Object":{"Id":"*out:vdf:0:minu","FallbackKey":"","DestinationMap":{"ALL":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:one","Object":{"Id":"*out:vdf:0:one","FallbackKey":"","DestinationMap":{"ALL":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.2,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.1,"RateIncrement":1000000000,"RateUnit":60000000000},{"GroupIntervalStart":0,"Value":0.05,"RateIncrement":1000000000,"RateUnit":60000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}} -{"Key":"*out:vdf:0:rif","Object":{"Id":"*out:vdf:0:rif","FallbackKey":"","DestinationMap":{"ALL":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_O2":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"GERMANY_PREMIUM":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"NAT":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}],"RET":[{"ActivationTime":"2012-01-01T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]},{"ActivationTime":"2012-02-28T00:00:00Z","Intervals":[{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":1,"Prices":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[1,2,3,4,5],"StartTime":"18:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0},{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[6,0],"StartTime":"00:00:00","EndTime":"","Weight":10,"ConnectFee":0,"Prices":[{"GroupIntervalStart":0,"Value":0.5,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"","RoundingDecimals":0}]}]},"Tag":"","Tenant":"","TOR":"","Direction":"","Subject":"","DestRatesTimingTag":"","RatesFallbackSubject":"","ActivationTime":""}}]` - if scribe.RpBuf.String() != expected { - t.Error("Error in rating profiles history content:", scribe.RpBuf.String()) - } -} diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 12e9939f4..1413a8a64 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -39,9 +39,9 @@ type CSVReader struct { accountActions []*UserBalance destinations []*Destination timings map[string]*Timing - rates map[string]*Rate + rates map[string]*LoadRate destinationRates map[string][]*DestinationRate - activationPeriods map[string]*ActivationPeriod + activationPeriods map[string]*RatingPlan ratingProfiles map[string]*RatingProfile // file names destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn, @@ -55,10 +55,10 @@ func NewFileCSVReader(storage DataStorage, sep rune, destinationsFn, timingsFn, c.actions = make(map[string][]*Action) c.actionsTimings = make(map[string][]*ActionTiming) c.actionsTriggers = make(map[string][]*ActionTrigger) - c.rates = make(map[string]*Rate) + c.rates = make(map[string]*LoadRate) c.destinationRates = make(map[string][]*DestinationRate) c.timings = make(map[string]*Timing) - c.activationPeriods = make(map[string]*ActivationPeriod) + c.activationPeriods = make(map[string]*RatingPlan) c.ratingProfiles = make(map[string]*RatingProfile) c.readerFunc = openFileCSVReader c.destinationsFn, c.timingsFn, c.ratesFn, c.destinationratesFn, c.destinationratetimingsFn, c.ratingprofilesFn, @@ -223,8 +223,8 @@ func (csvr *CSVReader) LoadRates() (err error) { } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tag := record[0] - var r *Rate - r, err = NewRate(record[0], record[1], record[2], record[3], record[4], record[5], record[6], record[7], record[8]) + var r *LoadRate + r, err = NewLoadRate(record[0], record[1], record[2], record[3], record[4], record[5], record[6], record[7], record[8]) if err != nil { return err } @@ -285,9 +285,9 @@ func (csvr *CSVReader) LoadDestinationRateTimings() (err error) { } for _, dr := range drs { if _, exists := csvr.activationPeriods[tag]; !exists { - csvr.activationPeriods[tag] = &ActivationPeriod{} + csvr.activationPeriods[tag] = &RatingPlan{} } - csvr.activationPeriods[tag].AddInterval(rt.GetInterval(dr)) + csvr.activationPeriods[tag].AddRateInterval(rt.GetRateInterval(dr)) } } return @@ -320,10 +320,10 @@ func (csvr *CSVReader) LoadRatingProfiles() (err error) { if !exists { return errors.New(fmt.Sprintf("Could not load ratinTiming for tag: %v", record[5])) } - newAP := &ActivationPeriod{ActivationTime: at} + newAP := &RatingPlan{ActivationTime: at} //copy(newAP.Intervals, ap.Intervals) - newAP.Intervals = append(newAP.Intervals, ap.Intervals...) - rp.AddActivationPeriodIfNotPresent(d.Id, newAP) + newAP.RateIntervals = append(newAP.RateIntervals, ap.RateIntervals...) + rp.AddRatingPlanIfNotPresent(d.Id, newAP) if fallbacksubject != "" { rp.FallbackKey = fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fallbacksubject) } @@ -411,7 +411,7 @@ func (csvr *CSVReader) LoadActionTimings() (err error) { Id: utils.GenUUID(), Tag: record[2], Weight: weight, - Timing: &Interval{ + Timing: &RateInterval{ Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, diff --git a/engine/loader_db.go b/engine/loader_db.go index 4c55a7030..2141e7c46 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -35,9 +35,9 @@ type DbReader struct { accountActions []*UserBalance destinations []*Destination timings map[string]*Timing - rates map[string]*Rate + rates map[string]*LoadRate destinationRates map[string][]*DestinationRate - activationPeriods map[string]*ActivationPeriod + activationPeriods map[string]*RatingPlan ratingProfiles map[string]*RatingProfile } @@ -46,7 +46,7 @@ func NewDbReader(storDB LoadStorage, storage DataStorage, tpid string) *DbReader c.storDb = storDB c.dataDb = storage c.tpid = tpid - c.activationPeriods = make(map[string]*ActivationPeriod) + c.activationPeriods = make(map[string]*RatingPlan) c.actionsTimings = make(map[string][]*ActionTiming) return c } @@ -169,9 +169,9 @@ func (dbr *DbReader) LoadDestinationRateTimings() error { for _, dr := range drs { _, exists := dbr.activationPeriods[rt.Tag] if !exists { - dbr.activationPeriods[rt.Tag] = &ActivationPeriod{} + dbr.activationPeriods[rt.Tag] = &RatingPlan{} } - dbr.activationPeriods[rt.Tag].AddInterval(rt.GetInterval(dr)) + dbr.activationPeriods[rt.Tag].AddRateInterval(rt.GetRateInterval(dr)) } } return nil @@ -192,10 +192,10 @@ func (dbr *DbReader) LoadRatingProfiles() error { if !exists { return errors.New(fmt.Sprintf("Could not load rating timing for tag: %v", rp.DestRatesTimingTag)) } - newAP := &ActivationPeriod{ActivationTime: at} + newAP := &RatingPlan{ActivationTime: at} //copy(newAP.Intervals, ap.Intervals) - newAP.Intervals = append(newAP.Intervals, ap.Intervals...) - rp.AddActivationPeriodIfNotPresent(d.Id, newAP) + newAP.RateIntervals = append(newAP.RateIntervals, ap.RateIntervals...) + rp.AddRatingPlanIfNotPresent(d.Id, newAP) } } @@ -203,7 +203,7 @@ func (dbr *DbReader) LoadRatingProfiles() error { } func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { - activationPeriods := make(map[string]*ActivationPeriod) + activationPeriods := make(map[string]*RatingPlan) resultRatingProfile := &RatingProfile{} rpm, err := dbr.storDb.GetTpRatingProfiles(dbr.tpid, tag) if err != nil || len(rpm) == 0 { @@ -242,9 +242,9 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { Logger.Debug(fmt.Sprintf("Rate: %v", rpm)) drate.Rate = rt[drate.RateTag] if _, exists := activationPeriods[destrateTiming.Tag]; !exists { - activationPeriods[destrateTiming.Tag] = &ActivationPeriod{} + activationPeriods[destrateTiming.Tag] = &RatingPlan{} } - activationPeriods[destrateTiming.Tag].AddInterval(destrateTiming.GetInterval(drate)) + activationPeriods[destrateTiming.Tag].AddRateInterval(destrateTiming.GetRateInterval(drate)) dm, err := dbr.storDb.GetTpDestinations(dbr.tpid, drate.DestinationsTag) if err != nil || len(dm) == 0 { return fmt.Errorf("Could not get destination id %s: %v", drate.DestinationsTag, err) @@ -253,9 +253,9 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { for _, destination := range dm { Logger.Debug(fmt.Sprintf("Destination: %v", rpm)) ap := activationPeriods[ratingProfile.DestRatesTimingTag] - newAP := &ActivationPeriod{ActivationTime: at} - newAP.Intervals = append(newAP.Intervals, ap.Intervals...) - resultRatingProfile.AddActivationPeriodIfNotPresent(destination.Id, newAP) + newAP := &RatingPlan{ActivationTime: at} + newAP.RateIntervals = append(newAP.RateIntervals, ap.RateIntervals...) + resultRatingProfile.AddRatingPlanIfNotPresent(destination.Id, newAP) dbr.dataDb.SetDestination(destination) } } @@ -288,7 +288,7 @@ func (dbr *DbReader) LoadActionTimings() (err error) { Id: utils.GenUUID(), Tag: at.Tag, Weight: at.Weight, - Timing: &Interval{ + Timing: &RateInterval{ Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, @@ -387,7 +387,7 @@ func (dbr *DbReader) LoadAccountActionsByTag(tag string) error { Id: utils.GenUUID(), Tag: at.Tag, Weight: at.Weight, - Timing: &Interval{ + Timing: &RateInterval{ Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, diff --git a/engine/loader_helpers.go b/engine/loader_helpers.go index 03e97247d..393e04f86 100644 --- a/engine/loader_helpers.go +++ b/engine/loader_helpers.go @@ -46,7 +46,7 @@ type TPLoader interface { WriteToDatabase(bool, bool) error } -type Rate struct { +type LoadRate struct { Tag string ConnectFee, Price float64 RateUnit, RateIncrement, GroupIntervalStart time.Duration @@ -55,7 +55,7 @@ type Rate struct { Weight float64 } -func NewRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterval, roundingMethod, roundingDecimals, weight string) (r *Rate, err error) { +func NewLoadRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterval, roundingMethod, roundingDecimals, weight string) (r *LoadRate, err error) { cf, err := strconv.ParseFloat(connectFee, 64) if err != nil { log.Printf("Error parsing connect fee from: %v", connectFee) @@ -92,7 +92,7 @@ func NewRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterval, return } - r = &Rate{ + r = &LoadRate{ Tag: tag, ConnectFee: cf, Price: p, @@ -110,7 +110,7 @@ type DestinationRate struct { Tag string DestinationsTag string RateTag string - Rate *Rate + Rate *LoadRate } type Timing struct { @@ -155,8 +155,8 @@ func NewDestinationRateTiming(destinationRatesTag string, timing *Timing, weight return } -func (rt *DestinationRateTiming) GetInterval(dr *DestinationRate) (i *Interval) { - i = &Interval{ +func (rt *DestinationRateTiming) GetRateInterval(dr *DestinationRate) (i *RateInterval) { + i = &RateInterval{ Years: rt.timing.Years, Months: rt.timing.Months, MonthDays: rt.timing.MonthDays, @@ -164,7 +164,7 @@ func (rt *DestinationRateTiming) GetInterval(dr *DestinationRate) (i *Interval) StartTime: rt.timing.StartTime, Weight: rt.Weight, ConnectFee: dr.Rate.ConnectFee, - Prices: PriceGroups{&Price{ + Rates: RateGroups{&Rate{ GroupIntervalStart: dr.Rate.GroupIntervalStart, Value: dr.Rate.Price, RateIncrement: dr.Rate.RateIncrement, diff --git a/engine/interval.go b/engine/rateinterval.go similarity index 79% rename from engine/interval.go rename to engine/rateinterval.go index 1181a430b..db8c8b0fe 100644 --- a/engine/interval.go +++ b/engine/rateinterval.go @@ -32,48 +32,48 @@ import ( /* Defines a time interval for which a certain set of prices will apply */ -type Interval struct { +type RateInterval struct { Years Years Months Months MonthDays MonthDays WeekDays WeekDays StartTime, EndTime string // ##:##:## format Weight, ConnectFee float64 - Prices PriceGroups // GroupInterval (start time): Price + Rates RateGroups // GroupRateInterval (start time): Rate RoundingMethod string RoundingDecimals int } -type Price struct { +type Rate struct { GroupIntervalStart time.Duration Value float64 RateIncrement time.Duration RateUnit time.Duration } -func (p *Price) Equal(o *Price) bool { +func (p *Rate) Equal(o *Rate) bool { return p.GroupIntervalStart == o.GroupIntervalStart && p.Value == o.Value && p.RateIncrement == o.RateIncrement && p.RateUnit == o.RateUnit } -type PriceGroups []*Price +type RateGroups []*Rate -func (pg PriceGroups) Len() int { +func (pg RateGroups) Len() int { return len(pg) } -func (pg PriceGroups) Swap(i, j int) { +func (pg RateGroups) Swap(i, j int) { pg[i], pg[j] = pg[j], pg[i] } -func (pg PriceGroups) Less(i, j int) bool { +func (pg RateGroups) Less(i, j int) bool { return pg[i].GroupIntervalStart < pg[j].GroupIntervalStart } -func (pg PriceGroups) Sort() { +func (pg RateGroups) Sort() { sort.Sort(pg) } -func (pg PriceGroups) Equal(og PriceGroups) bool { +func (pg RateGroups) Equal(og RateGroups) bool { if len(pg) != len(og) { return false } @@ -85,7 +85,7 @@ func (pg PriceGroups) Equal(og PriceGroups) bool { return true } -func (pg *PriceGroups) AddPrice(ps ...*Price) { +func (pg *RateGroups) AddRate(ps ...*Rate) { for _, p := range ps { found := false for _, op := range *pg { @@ -103,7 +103,7 @@ func (pg *PriceGroups) AddPrice(ps ...*Price) { /* Returns true if the received time result inside the interval */ -func (i *Interval) Contains(t time.Time) bool { +func (i *RateInterval) Contains(t time.Time) bool { // check for years if len(i.Years) > 0 && !i.Years.Contains(t.Year()) { return false @@ -152,7 +152,7 @@ func (i *Interval) Contains(t time.Time) bool { /* Returns a time object that represents the end of the interval realtive to the received time */ -func (i *Interval) getRightMargin(t time.Time) (rigthtTime time.Time) { +func (i *RateInterval) getRightMargin(t time.Time) (rigthtTime time.Time) { year, month, day := t.Year(), t.Month(), t.Day() hour, min, sec, nsec := 23, 59, 59, 0 loc := t.Location() @@ -168,7 +168,7 @@ func (i *Interval) getRightMargin(t time.Time) (rigthtTime time.Time) { /* Returns a time object that represents the start of the interval realtive to the received time */ -func (i *Interval) getLeftMargin(t time.Time) (rigthtTime time.Time) { +func (i *RateInterval) getLeftMargin(t time.Time) (rigthtTime time.Time) { year, month, day := t.Year(), t.Month(), t.Day() hour, min, sec, nsec := 0, 0, 0, 0 loc := t.Location() @@ -181,11 +181,11 @@ func (i *Interval) getLeftMargin(t time.Time) (rigthtTime time.Time) { return time.Date(year, month, day, hour, min, sec, nsec, loc) } -func (i *Interval) String() string { +func (i *RateInterval) String() string { return fmt.Sprintf("%v %v %v %v %v %v", i.Years, i.Months, i.MonthDays, i.WeekDays, i.StartTime, i.EndTime) } -func (i *Interval) Equal(o *Interval) bool { +func (i *RateInterval) Equal(o *RateInterval) bool { return reflect.DeepEqual(i.Years, o.Years) && reflect.DeepEqual(i.Months, o.Months) && reflect.DeepEqual(i.MonthDays, o.MonthDays) && @@ -194,8 +194,8 @@ func (i *Interval) Equal(o *Interval) bool { i.EndTime == o.EndTime } -func (i *Interval) GetCost(duration, startSecond time.Duration) (cost float64) { - price, rateIncrement, rateUnit := i.GetPriceParameters(startSecond) +func (i *RateInterval) GetCost(duration, startSecond time.Duration) (cost float64) { + price, rateIncrement, rateUnit := i.GetRateParameters(startSecond) d := float64(duration.Seconds()) price /= rateUnit.Seconds() ri := rateIncrement.Seconds() @@ -204,11 +204,11 @@ func (i *Interval) GetCost(duration, startSecond time.Duration) (cost float64) { } // Gets the price for a the provided start second -func (i *Interval) GetPriceParameters(startSecond time.Duration) (price float64, rateIncrement, rateUnit time.Duration) { - i.Prices.Sort() - for index, price := range i.Prices { - if price.GroupIntervalStart <= startSecond && (index == len(i.Prices)-1 || - i.Prices[index+1].GroupIntervalStart > startSecond) { +func (i *RateInterval) GetRateParameters(startSecond time.Duration) (price float64, rateIncrement, rateUnit time.Duration) { + i.Rates.Sort() + for index, price := range i.Rates { + if price.GroupIntervalStart <= startSecond && (index == len(i.Rates)-1 || + i.Rates[index+1].GroupIntervalStart > startSecond) { if price.RateIncrement == 0 { price.RateIncrement = 1 * time.Second } @@ -222,20 +222,20 @@ func (i *Interval) GetPriceParameters(startSecond time.Duration) (price float64, } // Structure to store intervals according to weight -type IntervalList []*Interval +type RateIntervalList []*RateInterval -func (il IntervalList) Len() int { +func (il RateIntervalList) Len() int { return len(il) } -func (il IntervalList) Swap(i, j int) { +func (il RateIntervalList) Swap(i, j int) { il[i], il[j] = il[j], il[i] } -func (il IntervalList) Less(i, j int) bool { +func (il RateIntervalList) Less(i, j int) bool { return il[i].Weight < il[j].Weight } -func (il IntervalList) Sort() { +func (il RateIntervalList) Sort() { sort.Sort(il) } diff --git a/engine/interval_test.go b/engine/rateinterval_test.go similarity index 75% rename from engine/interval_test.go rename to engine/rateinterval_test.go index 6ea61ad73..e3daf02e3 100644 --- a/engine/interval_test.go +++ b/engine/rateinterval_test.go @@ -23,8 +23,8 @@ import ( "time" ) -func TestIntervalMonth(t *testing.T) { - i := &Interval{Months: Months{time.February}} +func TestRateIntervalMonth(t *testing.T) { + i := &RateInterval{Months: Months{time.February}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.January, 10, 23, 0, 0, 0, time.UTC) if !i.Contains(d) { @@ -35,8 +35,8 @@ func TestIntervalMonth(t *testing.T) { } } -func TestIntervalMonthDay(t *testing.T) { - i := &Interval{MonthDays: MonthDays{10}} +func TestRateIntervalMonthDay(t *testing.T) { + i := &RateInterval{MonthDays: MonthDays{10}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 11, 23, 0, 0, 0, time.UTC) if !i.Contains(d) { @@ -47,8 +47,8 @@ func TestIntervalMonthDay(t *testing.T) { } } -func TestIntervalMonthAndMonthDay(t *testing.T) { - i := &Interval{Months: Months{time.February}, MonthDays: MonthDays{10}} +func TestRateIntervalMonthAndMonthDay(t *testing.T) { + i := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{10}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 11, 23, 0, 0, 0, time.UTC) d2 := time.Date(2012, time.January, 10, 23, 0, 0, 0, time.UTC) @@ -63,9 +63,9 @@ func TestIntervalMonthAndMonthDay(t *testing.T) { } } -func TestIntervalWeekDays(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Wednesday}} - i2 := &Interval{WeekDays: []time.Weekday{time.Wednesday, time.Thursday}} +func TestRateIntervalWeekDays(t *testing.T) { + i := &RateInterval{WeekDays: []time.Weekday{time.Wednesday}} + i2 := &RateInterval{WeekDays: []time.Weekday{time.Wednesday, time.Thursday}} d := time.Date(2012, time.February, 1, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 2, 23, 0, 0, 0, time.UTC) if !i.Contains(d) { @@ -82,9 +82,9 @@ func TestIntervalWeekDays(t *testing.T) { } } -func TestIntervalMonthAndMonthDayAndWeekDays(t *testing.T) { - i := &Interval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}} - i2 := &Interval{Months: Months{time.February}, MonthDays: MonthDays{2}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}} +func TestRateIntervalMonthAndMonthDayAndWeekDays(t *testing.T) { + i := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}} + i2 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{2}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}} d := time.Date(2012, time.February, 1, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 2, 23, 0, 0, 0, time.UTC) if !i.Contains(d) { @@ -101,8 +101,8 @@ func TestIntervalMonthAndMonthDayAndWeekDays(t *testing.T) { } } -func TestIntervalHours(t *testing.T) { - i := &Interval{StartTime: "14:30:00", EndTime: "15:00:00"} +func TestRateIntervalHours(t *testing.T) { + i := &RateInterval{StartTime: "14:30:00", EndTime: "15:00:00"} d := time.Date(2012, time.February, 10, 14, 30, 1, 0, time.UTC) d1 := time.Date(2012, time.January, 10, 14, 29, 0, 0, time.UTC) d2 := time.Date(2012, time.January, 10, 14, 59, 0, 0, time.UTC) @@ -121,8 +121,8 @@ func TestIntervalHours(t *testing.T) { } } -func TestIntervalEverything(t *testing.T) { - i := &Interval{Months: Months{time.February}, +func TestRateIntervalEverything(t *testing.T) { + i := &RateInterval{Months: Months{time.February}, Years: Years{2012}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, @@ -150,13 +150,13 @@ func TestIntervalEverything(t *testing.T) { } } -func TestIntervalEqual(t *testing.T) { - i1 := &Interval{Months: Months{time.February}, +func TestRateIntervalEqual(t *testing.T) { + i1 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - i2 := &Interval{Months: Months{time.February}, + i2 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", @@ -166,13 +166,13 @@ func TestIntervalEqual(t *testing.T) { } } -func TestIntervalNotEqual(t *testing.T) { - i1 := &Interval{Months: Months{time.February}, +func TestRateIntervalNotEqual(t *testing.T) { + i1 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}, StartTime: "14:30:00", EndTime: "15:00:00"} - i2 := &Interval{Months: Months{time.February}, + i2 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", @@ -182,13 +182,13 @@ func TestIntervalNotEqual(t *testing.T) { } } -func TestIntervalGetCost(t *testing.T) { +func TestRateIntervalGetCost(t *testing.T) { } /*********************************Benchmarks**************************************/ -func BenchmarkIntervalContainsDate(b *testing.B) { - i := &Interval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} +func BenchmarkRateIntervalContainsDate(b *testing.B) { + i := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} d := time.Date(2012, time.February, 1, 14, 30, 0, 0, time.UTC) for x := 0; x < b.N; x++ { i.Contains(d) diff --git a/engine/activationperiod.go b/engine/ratingplan.go similarity index 75% rename from engine/activationperiod.go rename to engine/ratingplan.go index deed2c518..5e14bf74f 100644 --- a/engine/activationperiod.go +++ b/engine/ratingplan.go @@ -26,36 +26,36 @@ import ( /* The struture that is saved to storage. */ -type ActivationPeriod struct { +type RatingPlan struct { ActivationTime time.Time - Intervals IntervalList + RateIntervals RateIntervalList } -type xCachedActivationPeriods struct { +type xCachedRatingPlans struct { destPrefix string - aps []*ActivationPeriod + aps []*RatingPlan *cache2go.XEntry } /* Adds one ore more intervals to the internal interval list only if it is not allready in the list. */ -func (ap *ActivationPeriod) AddInterval(is ...*Interval) { +func (ap *RatingPlan) AddRateInterval(is ...*RateInterval) { for _, i := range is { found := false - for _, ei := range ap.Intervals { + for _, ei := range ap.RateIntervals { if i.Equal(ei) { - (&ei.Prices).AddPrice(i.Prices...) + (&ei.Rates).AddRate(i.Rates...) found = true break } } if !found { - ap.Intervals = append(ap.Intervals, i) + ap.RateIntervals = append(ap.RateIntervals, i) } } } -func (ap *ActivationPeriod) Equal(o *ActivationPeriod) bool { +func (ap *RatingPlan) Equal(o *RatingPlan) bool { return ap.ActivationTime == o.ActivationTime } diff --git a/engine/activationperiod_test.go b/engine/ratingplan_test.go similarity index 61% rename from engine/activationperiod_test.go rename to engine/ratingplan_test.go index c1aff6236..ef007ba93 100644 --- a/engine/activationperiod_test.go +++ b/engine/ratingplan_test.go @@ -32,23 +32,23 @@ func TestApRestoreFromStorage(t *testing.T) { Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 2 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 2 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestApStoreRestoreJson(t *testing.T) { d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) result, _ := json.Marshal(ap) - ap1 := &ActivationPeriod{} + ap1 := &RatingPlan{} json.Unmarshal(result, ap1) if !reflect.DeepEqual(ap, ap1) { t.Errorf("Expected %v was %v", ap, ap1) @@ -57,11 +57,11 @@ func TestApStoreRestoreJson(t *testing.T) { func TestApStoreRestoreBlank(t *testing.T) { d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + i := &RateInterval{} + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) result, _ := json.Marshal(ap) - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} json.Unmarshal(result, &ap1) if reflect.DeepEqual(ap, ap1) { t.Errorf("Expected %v was %v", ap, ap1) @@ -70,116 +70,116 @@ func TestApStoreRestoreBlank(t *testing.T) { func TestFallbackDirect(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "41"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 1 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 1 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestFallbackMultiple(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "fall", Destination: "0723045"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 1 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 1 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestFallbackWithBackTrace(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "4123"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 1 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 1 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestFallbackDefault(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "one", Destination: "0723"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 1 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 1 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestFallbackNoInfiniteLoop(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "rif", Destination: "0721"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 0 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 0 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestFallbackNoInfiniteLoopSelf(t *testing.T) { cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "inf", Destination: "0721"} - cd.LoadActivationPeriods() - if len(cd.ActivationPeriods) != 0 { - t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) + cd.LoadRatingPlans() + if len(cd.RatingPlans) != 0 { + t.Error("Error restoring activation periods: ", len(cd.RatingPlans)) } } func TestApAddIntervalIfNotPresent(t *testing.T) { - i1 := &Interval{Months: Months{time.February}, + i1 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - i2 := &Interval{Months: Months{time.February}, + i2 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - i3 := &Interval{Months: Months{time.February}, + i3 := &RateInterval{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{} - ap.AddInterval(i1) - ap.AddInterval(i2) - if len(ap.Intervals) != 1 { + ap := &RatingPlan{} + ap.AddRateInterval(i1) + ap.AddRateInterval(i2) + if len(ap.RateIntervals) != 1 { t.Error("Wronfully appended interval ;)") } - ap.AddInterval(i3) - if len(ap.Intervals) != 2 { + ap.AddRateInterval(i3) + if len(ap.RateIntervals) != 2 { t.Error("Wronfully not appended interval ;)") } } -func TestApAddIntervalGroups(t *testing.T) { - i1 := &Interval{ - Prices: PriceGroups{&Price{0, 1, 1 * time.Second, 1 * time.Second}}, +func TestApAddRateIntervalGroups(t *testing.T) { + i1 := &RateInterval{ + Rates: RateGroups{&Rate{0, 1, 1 * time.Second, 1 * time.Second}}, } - i2 := &Interval{ - Prices: PriceGroups{&Price{30 * time.Second, 2, 1 * time.Second, 1 * time.Second}}, + i2 := &RateInterval{ + Rates: RateGroups{&Rate{30 * time.Second, 2, 1 * time.Second, 1 * time.Second}}, } - i3 := &Interval{ - Prices: PriceGroups{&Price{30 * time.Second, 2, 1 * time.Second, 1 * time.Second}}, + i3 := &RateInterval{ + Rates: RateGroups{&Rate{30 * time.Second, 2, 1 * time.Second, 1 * time.Second}}, } - ap := &ActivationPeriod{} - ap.AddInterval(i1) - ap.AddInterval(i2) - ap.AddInterval(i3) - if len(ap.Intervals) != 1 { + ap := &RatingPlan{} + ap.AddRateInterval(i1) + ap.AddRateInterval(i2) + ap.AddRateInterval(i3) + if len(ap.RateIntervals) != 1 { t.Error("Wronfully appended interval ;)") } - if len(ap.Intervals[0].Prices) != 2 { - t.Error("Group prices not formed: ", ap.Intervals[0].Prices) + if len(ap.RateIntervals[0].Rates) != 2 { + t.Error("Group prices not formed: ", ap.RateIntervals[0].Rates) } } /**************************** Benchmarks *************************************/ -func BenchmarkActivationPeriodStoreRestoreJson(b *testing.B) { +func BenchmarkRatingPlanStoreRestoreJson(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} b.StartTimer() for i := 0; i < b.N; i++ { result, _ := json.Marshal(ap) @@ -187,18 +187,18 @@ func BenchmarkActivationPeriodStoreRestoreJson(b *testing.B) { } } -func BenchmarkActivationPeriodStoreRestore(b *testing.B) { +func BenchmarkRatingPlanStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) - ap1 := &ActivationPeriod{} + ap1 := &RatingPlan{} b.StartTimer() for i := 0; i < b.N; i++ { result, _ := marsh.Marshal(ap) diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index 664f139f2..0c243de0f 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -26,14 +26,14 @@ import ( type RatingProfile struct { Id string FallbackKey string // FallbackKey is used as complete combination of Tenant:TOR:Direction:Subject - DestinationMap map[string][]*ActivationPeriod + DestinationMap map[string][]*RatingPlan Tag, Tenant, TOR, Direction, Subject, DestRatesTimingTag, RatesFallbackSubject, ActivationTime string // used only for loading } // Adds an activation period that applyes to current rating profile if not already present. -func (rp *RatingProfile) AddActivationPeriodIfNotPresent(destInfo string, aps ...*ActivationPeriod) { +func (rp *RatingProfile) AddRatingPlanIfNotPresent(destInfo string, aps ...*RatingPlan) { if rp.DestinationMap == nil { - rp.DestinationMap = make(map[string][]*ActivationPeriod, 1) + rp.DestinationMap = make(map[string][]*RatingPlan, 1) } for _, ap := range aps { found := false @@ -49,7 +49,7 @@ func (rp *RatingProfile) AddActivationPeriodIfNotPresent(destInfo string, aps .. } } -func (rp *RatingProfile) GetActivationPeriodsForPrefix(destPrefix string) (foundPrefix string, aps []*ActivationPeriod, err error) { +func (rp *RatingProfile) GetRatingPlansForPrefix(destPrefix string) (foundPrefix string, aps []*RatingPlan, err error) { bestPrecision := 0 for k, v := range rp.DestinationMap { d, err := GetDestination(k) diff --git a/engine/ratingprofile_test.go b/engine/ratingprofile_test.go index 76e0f78e3..cd7afc6cc 100644 --- a/engine/ratingprofile_test.go +++ b/engine/ratingprofile_test.go @@ -24,16 +24,16 @@ import ( ) func TestRpAddAPIfNotPresent(t *testing.T) { - ap1 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} - ap2 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} - ap3 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 1, time.UTC)} + ap1 := &RatingPlan{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} + ap2 := &RatingPlan{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} + ap3 := &RatingPlan{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 1, time.UTC)} rp := &RatingProfile{} - rp.AddActivationPeriodIfNotPresent("test", ap1) - rp.AddActivationPeriodIfNotPresent("test", ap2) + rp.AddRatingPlanIfNotPresent("test", ap1) + rp.AddRatingPlanIfNotPresent("test", ap2) if len(rp.DestinationMap["test"]) != 1 { t.Error("Wronfully appended activation period ;)", len(rp.DestinationMap["test"])) } - rp.AddActivationPeriodIfNotPresent("test", ap3) + rp.AddRatingPlanIfNotPresent("test", ap3) if len(rp.DestinationMap["test"]) != 2 { t.Error("Wronfully not appended activation period ;)", len(rp.DestinationMap["test"])) } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 2dd07f493..161c5c930 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -110,7 +110,7 @@ type LoadStorage interface { GetTPDestination(string, string) (*Destination, error) GetTPDestinationIds(string) ([]string, error) ExistsTPRate(string, string) (bool, error) - SetTPRates(string, map[string][]*Rate) error + SetTPRates(string, map[string][]*LoadRate) error GetTPRate(string, string) (*utils.TPRate, error) GetTPRateIds(string) ([]string, error) ExistsTPDestinationRate(string, string) (bool, error) @@ -142,7 +142,7 @@ type LoadStorage interface { // loader functions GetTpDestinations(string, string) ([]*Destination, error) GetTpTimings(string, string) (map[string]*Timing, error) - GetTpRates(string, string) (map[string]*Rate, error) + GetTpRates(string, string) (map[string]*LoadRate, error) GetTpDestinationRates(string, string) (map[string][]*DestinationRate, error) GetTpDestinationRateTimings(string, string) ([]*DestinationRateTiming, error) GetTpRatingProfiles(string, string) (map[string]*RatingProfile, error) diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 2668849d8..13d13f1a3 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -192,7 +192,7 @@ func (self *SQLStorage) ExistsTPRate(tpid, rtId string) (bool, error) { return exists, nil } -func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*Rate) error { +func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*LoadRate) error { if len(rts) == 0 { return nil //Nothing to set } @@ -541,7 +541,7 @@ func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*Action) err } qry += fmt.Sprintf("('%s','%s','%s','%s','%s',%f,'%s','%s','%s',%f,%f,%f)", tpid, actId, act.ActionType, act.BalanceId, act.Direction, act.Balance.Value, act.ExpirationString, - act.DestinationTag, act.RateType, act.RateValue, act.MinutesWeight, act.Weight) + act.Balance.DestinationId, act.Balance.SpecialPriceType, act.Balance.SpecialPrice, act.Balance.Weight, act.Weight) i++ } } @@ -921,8 +921,8 @@ func (self *SQLStorage) GetTpDestinations(tpid, tag string) ([]*Destination, err return dests, nil } -func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string]*Rate, error) { - rts := make(map[string]*Rate) +func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string]*LoadRate, error) { + rts := make(map[string]*LoadRate) q := fmt.Sprintf("SELECT tag, connect_fee, rate, rate_unit, rate_increment, group_interval_start, rounding_method, rounding_decimals, weight FROM %s WHERE tpid='%s' ", utils.TBL_TP_RATES, tpid) if tag != "" { q += fmt.Sprintf(" AND tag='%s'", tag) @@ -940,7 +940,7 @@ func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string]*Rate, error) { if err := rows.Scan(&tag, &connect_fee, &rate, &rate_unit, &rate_increment, &group_interval_start, &roundingMethod, &roundingDecimals, &weight); err != nil { return nil, err } - r := &Rate{ + r := &LoadRate{ Tag: tag, ConnectFee: connect_fee, Price: rate, diff --git a/engine/storage_test.go b/engine/storage_test.go index e77d99bf5..4a297a4b4 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -104,16 +104,16 @@ func GetUB() *UserBalance { func BenchmarkMarshallerJSONStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := new(JSONMarshaler) @@ -128,16 +128,16 @@ func BenchmarkMarshallerJSONStoreRestore(b *testing.B) { func BenchmarkMarshallerBSONStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := new(BSONMarshaler) @@ -152,16 +152,16 @@ func BenchmarkMarshallerBSONStoreRestore(b *testing.B) { func BenchmarkMarshallerJSONBufStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := new(JSONBufMarshaler) @@ -176,16 +176,16 @@ func BenchmarkMarshallerJSONBufStoreRestore(b *testing.B) { func BenchmarkMarshallerGOBStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := new(GOBMarshaler) @@ -200,16 +200,16 @@ func BenchmarkMarshallerGOBStoreRestore(b *testing.B) { func BenchmarkMarshallerMsgpackStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := new(MsgpackMarshaler) @@ -225,16 +225,16 @@ func BenchmarkMarshallerMsgpackStoreRestore(b *testing.B) { func BenchmarkMarshallerCodecMsgpackStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := NewCodecMsgpackMarshaler() @@ -249,16 +249,16 @@ func BenchmarkMarshallerCodecMsgpackStoreRestore(b *testing.B) { func BenchmarkMarshallerBincStoreRestore(b *testing.B) { b.StopTimer() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Months: []time.Month{time.February}, + i := &RateInterval{Months: []time.Month{time.February}, MonthDays: []int{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) + ap := &RatingPlan{ActivationTime: d} + ap.AddRateInterval(i) ub := GetUB() - ap1 := ActivationPeriod{} + ap1 := RatingPlan{} ub1 := &UserBalance{} b.StartTimer() ms := NewBincMarshaler() diff --git a/engine/timespans.go b/engine/timespans.go index 4feaa626d..b2abd493a 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -29,8 +29,8 @@ A unit in which a call will be split that has a specific price related interval type TimeSpan struct { TimeStart, TimeEnd time.Time Cost float64 - ActivationPeriod *ActivationPeriod - Interval *Interval + RatingPlan *RatingPlan + RateInterval *RateInterval MinuteInfo *MinuteInfo CallDuration time.Duration // the call duration so far till TimeEnd overlapped bool // mark a timespan as overlapped by an expanded one @@ -43,9 +43,7 @@ type MinuteInfo struct { Price float64 } -/* -Returns the duration of the timespan -*/ +// Returns the duration of the timespan func (ts *TimeSpan) GetDuration() time.Duration { return ts.TimeEnd.Sub(ts.TimeStart) } @@ -57,18 +55,11 @@ func (ts *TimeSpan) getCost(cd *CallDescriptor) (cost float64) { if ts.MinuteInfo != nil { return ts.GetDuration().Seconds() * ts.MinuteInfo.Price } - if ts.Interval == nil { + if ts.RateInterval == nil { return 0 } - i := ts.Interval + i := ts.RateInterval cost = i.GetCost(ts.GetDuration(), ts.GetGroupStart()) - // if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil { - // userBalance.mux.RLock() - // if percentageDiscount, err := userBalance.getVolumeDiscount(cd.Destination, INBOUND); err == nil && percentageDiscount > 0 { - // cost *= (100 - percentageDiscount) / 100 - // } - // userBalance.mux.RUnlock() - // } ts.Cost = cost return } @@ -84,15 +75,15 @@ func (ts *TimeSpan) Contains(t time.Time) bool { Will set the interval as spans's interval if new Weight is lower then span's interval Weight or if the Weights are equal and new price is lower then spans's interval price */ -func (ts *TimeSpan) SetInterval(i *Interval) { - if ts.Interval == nil || ts.Interval.Weight < i.Weight { - ts.Interval = i +func (ts *TimeSpan) SetRateInterval(i *RateInterval) { + if ts.RateInterval == nil || ts.RateInterval.Weight < i.Weight { + ts.RateInterval = i return } - iPrice, _, _ := i.GetPriceParameters(ts.GetGroupStart()) - tsPrice, _, _ := ts.Interval.GetPriceParameters(ts.GetGroupStart()) - if ts.Interval.Weight == i.Weight && iPrice < tsPrice { - ts.Interval = i + iPrice, _, _ := i.GetRateParameters(ts.GetGroupStart()) + tsPrice, _, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) + if ts.RateInterval.Weight == i.Weight && iPrice < tsPrice { + ts.RateInterval = i } } @@ -102,7 +93,7 @@ It will modify the endtime of the received timespan and it will return a new timespan starting from the end of the received one. The interval will attach itself to the timespan that overlaps the interval. */ -func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { +func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) { //Logger.Debug("here: ", ts, " +++ ", i) // if the span is not in interval return nil @@ -111,14 +102,14 @@ func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { return } // split by GroupStart - i.Prices.Sort() - for _, price := range i.Prices { + i.Rates.Sort() + for _, price := range i.Rates { if ts.GetGroupStart() < price.GroupIntervalStart && ts.GetGroupEnd() >= price.GroupIntervalStart { - ts.SetInterval(i) + ts.SetRateInterval(i) splitTime := ts.TimeStart.Add(price.GroupIntervalStart - ts.GetGroupStart()) nts = &TimeSpan{TimeStart: splitTime, TimeEnd: ts.TimeEnd} ts.TimeEnd = splitTime - nts.SetInterval(i) + nts.SetRateInterval(i) nts.CallDuration = ts.CallDuration ts.SetNewCallDuration(nts) @@ -129,14 +120,14 @@ func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { // if the span is enclosed in the interval try to set as new interval and return nil if i.Contains(ts.TimeStart) && i.Contains(ts.TimeEnd) { //Logger.Debug("All in interval") - ts.SetInterval(i) + ts.SetRateInterval(i) return } // if only the start time is in the interval split the interval to the right if i.Contains(ts.TimeStart) { //Logger.Debug("Start in interval") splitTime := i.getRightMargin(ts.TimeStart) - ts.SetInterval(i) + ts.SetRateInterval(i) if splitTime == ts.TimeStart { return } @@ -157,7 +148,7 @@ func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { nts = &TimeSpan{TimeStart: splitTime, TimeEnd: ts.TimeEnd} ts.TimeEnd = splitTime - nts.SetInterval(i) + nts.SetRateInterval(i) nts.CallDuration = ts.CallDuration ts.SetNewCallDuration(nts) @@ -169,11 +160,11 @@ func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { /* Splits the given timespan on activation period's activation time. */ -func (ts *TimeSpan) SplitByActivationPeriod(ap *ActivationPeriod) (newTs *TimeSpan) { +func (ts *TimeSpan) SplitByRatingPlan(ap *RatingPlan) (newTs *TimeSpan) { if !ts.Contains(ap.ActivationTime) { return nil } - newTs = &TimeSpan{TimeStart: ap.ActivationTime, TimeEnd: ts.TimeEnd, ActivationPeriod: ap} + newTs = &TimeSpan{TimeStart: ap.ActivationTime, TimeEnd: ts.TimeEnd, RatingPlan: ap} newTs.CallDuration = ts.CallDuration ts.TimeEnd = ap.ActivationTime ts.SetNewCallDuration(newTs) @@ -217,6 +208,7 @@ func (ts *TimeSpan) SplitByMinuteBalance(mb *Balance) (newTs *TimeSpan) { return } +// Returns the starting time of this timespan func (ts *TimeSpan) GetGroupStart() time.Duration { s := ts.CallDuration - ts.GetDuration() if s < 0 { @@ -229,6 +221,7 @@ func (ts *TimeSpan) GetGroupEnd() time.Duration { return ts.CallDuration } +// sets the CallDuration attribute to reflect new timespan func (ts *TimeSpan) SetNewCallDuration(nts *TimeSpan) { d := ts.CallDuration - nts.GetDuration() if d < 0 { diff --git a/engine/timespans_test.go b/engine/timespans_test.go index 410609e3b..ff2ec3bad 100644 --- a/engine/timespans_test.go +++ b/engine/timespans_test.go @@ -24,24 +24,24 @@ import ( ) func TestRightMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} + i := &RateInterval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} t1 := time.Date(2012, time.February, 3, 23, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 4, 0, 10, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) { t.Error("Incorrect first half", ts) } if nts.TimeStart != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 15*60-1 || nts.GetDuration().Seconds() != 10*60+1 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), ts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), ts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { @@ -50,24 +50,24 @@ func TestRightMargin(t *testing.T) { } func TestRightHourMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, EndTime: "17:59:00"} + i := &RateInterval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, EndTime: "17:59:00"} t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 18, 00, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) { t.Error("Incorrect first half", ts) } if nts.TimeStart != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 29*60 || nts.GetDuration().Seconds() != 1*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) @@ -75,23 +75,23 @@ func TestRightHourMargin(t *testing.T) { } func TestLeftMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} + i := &RateInterval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} t1 := time.Date(2012, time.February, 5, 23, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 6, 0, 10, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) { t.Error("Incorrect first half", ts) } if nts.TimeStart != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if nts.Interval != i { - t.Error("Interval not attached correctly") + if nts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 10*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) @@ -99,23 +99,23 @@ func TestLeftMargin(t *testing.T) { } func TestLeftHourMargin(t *testing.T) { - i := &Interval{Months: Months{time.December}, MonthDays: MonthDays{1}, StartTime: "09:00:00"} + i := &RateInterval{Months: Months{time.December}, MonthDays: MonthDays{1}, StartTime: "09:00:00"} t1 := time.Date(2012, time.December, 1, 8, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.December, 1, 9, 20, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) { t.Error("Incorrect first half", ts) } if nts.TimeStart != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if nts.Interval != i { - t.Error("Interval not attached correctly") + if nts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 20*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) @@ -123,27 +123,27 @@ func TestLeftHourMargin(t *testing.T) { } func TestEnclosingMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Sunday}} + i := &RateInterval{WeekDays: []time.Weekday{time.Sunday}} t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) if ts.TimeStart != t1 || ts.TimeEnd != t2 || nts != nil { t.Error("Incorrect enclosing", ts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } } func TestOutsideMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday}} + i := &RateInterval{WeekDays: []time.Weekday{time.Monday}} t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - result := ts.SplitByInterval(i) + result := ts.SplitByRateInterval(i) if result != nil { - t.Error("Interval not split correctly") + t.Error("RateInterval not split correctly") } } @@ -168,17 +168,17 @@ func TestSplitByActivationTime(t *testing.T) { t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC) t3 := time.Date(2012, time.February, 5, 17, 50, 0, 0, time.UTC) ts := TimeSpan{TimeStart: t1, TimeEnd: t2} - ap1 := &ActivationPeriod{ActivationTime: t1} - ap2 := &ActivationPeriod{ActivationTime: t2} - ap3 := &ActivationPeriod{ActivationTime: t3} + ap1 := &RatingPlan{ActivationTime: t1} + ap2 := &RatingPlan{ActivationTime: t2} + ap3 := &RatingPlan{ActivationTime: t3} - if ts.SplitByActivationPeriod(ap1) != nil { + if ts.SplitByRatingPlan(ap1) != nil { t.Error("Error spliting on left margin") } - if ts.SplitByActivationPeriod(ap2) != nil { + if ts.SplitByRatingPlan(ap2) != nil { t.Error("Error spliting on right margin") } - result := ts.SplitByActivationPeriod(ap3) + result := ts.SplitByRatingPlan(ap3) if result.TimeStart != t3 || result.TimeEnd != t2 { t.Error("Error spliting on interior") } @@ -192,27 +192,27 @@ func TestTimespanGetCost(t *testing.T) { if ts1.getCost(cd) != 0 { t.Error("No interval and still kicking") } - ts1.Interval = &Interval{Prices: PriceGroups{&Price{0, 1.0, 1 * time.Second, 1 * time.Second}}} + ts1.RateInterval = &RateInterval{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}} if ts1.getCost(cd) != 600 { t.Error("Expected 10 got ", ts1.getCost(cd)) } - ts1.Interval.Prices[0].RateUnit = 60 * time.Second + ts1.RateInterval.Rates[0].RateUnit = 60 * time.Second if ts1.getCost(cd) != 10 { t.Error("Expected 6000 got ", ts1.getCost(cd)) } } -func TestSetInterval(t *testing.T) { - i1 := &Interval{Prices: PriceGroups{&Price{0, 1.0, 1 * time.Second, 1 * time.Second}}} - ts1 := TimeSpan{Interval: i1} - i2 := &Interval{Prices: PriceGroups{&Price{0, 2.0, 1 * time.Second, 1 * time.Second}}} - ts1.SetInterval(i2) - if ts1.Interval != i1 { +func TestSetRateInterval(t *testing.T) { + i1 := &RateInterval{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}} + ts1 := TimeSpan{RateInterval: i1} + i2 := &RateInterval{Rates: RateGroups{&Rate{0, 2.0, 1 * time.Second, 1 * time.Second}}} + ts1.SetRateInterval(i2) + if ts1.RateInterval != i1 { t.Error("Smaller price interval should win") } i2.Weight = 1 - ts1.SetInterval(i2) - if ts1.Interval != i2 { + ts1.SetRateInterval(i2) + if ts1.RateInterval != i2 { t.Error("Bigger ponder interval should win") } } @@ -330,15 +330,15 @@ func TestTimespanSplitByMinuteBalanceScarceExpiringDifferentScarceFirst(t *testi } func TestTimespanSplitGroupedRates(t *testing.T) { - i := &Interval{ + i := &RateInterval{ EndTime: "17:59:00", - Prices: PriceGroups{&Price{0, 2, 1 * time.Second, 1 * time.Second}, &Price{900 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, + Rates: RateGroups{&Rate{0, 2, 1 * time.Second, 1 * time.Second}, &Rate{900 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, } t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 18, 00, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 1800 * time.Second} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) splitTime := time.Date(2012, time.February, 3, 17, 45, 00, 0, time.UTC) if ts.TimeStart != t1 || ts.TimeEnd != splitTime { t.Error("Incorrect first half", ts.TimeStart, ts.TimeEnd) @@ -346,17 +346,17 @@ func TestTimespanSplitGroupedRates(t *testing.T) { if nts.TimeStart != splitTime || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } - c1 := ts.Interval.GetCost(ts.GetDuration(), ts.GetGroupStart()) - c2 := nts.Interval.GetCost(nts.GetDuration(), nts.GetGroupStart()) + c1 := ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart()) + c2 := nts.RateInterval.GetCost(nts.GetDuration(), nts.GetGroupStart()) if c1 != 1800 || c2 != 900 { t.Error("Wrong costs: ", c1, c2) } if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 15*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) @@ -364,15 +364,15 @@ func TestTimespanSplitGroupedRates(t *testing.T) { } func TestTimespanSplitGroupedRatesIncrements(t *testing.T) { - i := &Interval{ + i := &RateInterval{ EndTime: "17:59:00", - Prices: PriceGroups{&Price{0, 2, 1 * time.Second, 1 * time.Second}, &Price{30 * time.Second, 1, 60 * time.Second, 1 * time.Second}}, + Rates: RateGroups{&Rate{0, 2, 1 * time.Second, 1 * time.Second}, &Rate{30 * time.Second, 1, 60 * time.Second, 1 * time.Second}}, } t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 17, 31, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 60 * time.Second} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) splitTime := time.Date(2012, time.February, 3, 17, 30, 30, 0, time.UTC) if ts.TimeStart != t1 || ts.TimeEnd != splitTime { t.Error("Incorrect first half", ts) @@ -380,17 +380,17 @@ func TestTimespanSplitGroupedRatesIncrements(t *testing.T) { if nts.TimeStart != splitTime || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } - c1 := ts.Interval.GetCost(ts.GetDuration(), ts.GetGroupStart()) - c2 := nts.Interval.GetCost(nts.GetDuration(), nts.GetGroupStart()) + c1 := ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart()) + c2 := nts.RateInterval.GetCost(nts.GetDuration(), nts.GetGroupStart()) if c1 != 60 || c2 != 60 { t.Error("Wrong costs: ", c1, c2) } if ts.GetDuration().Seconds() != 0.5*60 || nts.GetDuration().Seconds() != 0.5*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) @@ -398,15 +398,15 @@ func TestTimespanSplitGroupedRatesIncrements(t *testing.T) { } func TestTimespanSplitRightHourMarginBeforeGroup(t *testing.T) { - i := &Interval{ + i := &RateInterval{ EndTime: "17:00:30", - Prices: PriceGroups{&Price{0, 2, 1 * time.Second, 1 * time.Second}, &Price{60 * time.Second, 1, 60 * time.Second, 1 * time.Second}}, + Rates: RateGroups{&Rate{0, 2, 1 * time.Second, 1 * time.Second}, &Rate{60 * time.Second, 1, 60 * time.Second, 1 * time.Second}}, } t1 := time.Date(2012, time.February, 3, 17, 00, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 17, 01, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) splitTime := time.Date(2012, time.February, 3, 17, 00, 30, 0, time.UTC) if ts.TimeStart != t1 || ts.TimeEnd != splitTime { t.Error("Incorrect first half", ts) @@ -414,32 +414,32 @@ func TestTimespanSplitRightHourMarginBeforeGroup(t *testing.T) { if nts.TimeStart != splitTime || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 30 || nts.GetDuration().Seconds() != 30 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) } - nnts := nts.SplitByInterval(i) + nnts := nts.SplitByRateInterval(i) if nnts != nil { t.Error("Bad new split", nnts) } } func TestTimespanSplitGroupSecondSplit(t *testing.T) { - i := &Interval{ + i := &RateInterval{ EndTime: "17:03:30", - Prices: PriceGroups{&Price{0, 2, 1 * time.Second, 1 * time.Second}, &Price{60 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, + Rates: RateGroups{&Rate{0, 2, 1 * time.Second, 1 * time.Second}, &Rate{60 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, } t1 := time.Date(2012, time.February, 3, 17, 00, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 17, 04, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 240 * time.Second} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) splitTime := time.Date(2012, time.February, 3, 17, 01, 00, 0, time.UTC) if ts.TimeStart != t1 || ts.TimeEnd != splitTime { t.Error("Incorrect first half", nts) @@ -447,17 +447,17 @@ func TestTimespanSplitGroupSecondSplit(t *testing.T) { if nts.TimeStart != splitTime || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 60 || nts.GetDuration().Seconds() != 180 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) } - nnts := nts.SplitByInterval(i) + nnts := nts.SplitByRateInterval(i) nsplitTime := time.Date(2012, time.February, 3, 17, 03, 30, 0, time.UTC) if nts.TimeStart != splitTime || nts.TimeEnd != nsplitTime { t.Error("Incorrect first half", nts) @@ -465,25 +465,25 @@ func TestTimespanSplitGroupSecondSplit(t *testing.T) { if nnts.TimeStart != nsplitTime || nnts.TimeEnd != t2 { t.Error("Incorrect second half", nnts) } - if nts.Interval != i { - t.Error("Interval not attached correctly") + if nts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if nts.GetDuration().Seconds() != 150 || nnts.GetDuration().Seconds() != 30 { - t.Error("Wrong durations.for Intervals", nts.GetDuration().Seconds(), nnts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", nts.GetDuration().Seconds(), nnts.GetDuration().Seconds()) } } func TestTimespanSplitMultipleGroup(t *testing.T) { - i := &Interval{ + i := &RateInterval{ EndTime: "17:05:00", - Prices: PriceGroups{&Price{0, 2, 1 * time.Second, 1 * time.Second}, &Price{60 * time.Second, 1, 1 * time.Second, 1 * time.Second}, &Price{180 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, + Rates: RateGroups{&Rate{0, 2, 1 * time.Second, 1 * time.Second}, &Rate{60 * time.Second, 1, 1 * time.Second, 1 * time.Second}, &Rate{180 * time.Second, 1, 1 * time.Second, 1 * time.Second}}, } t1 := time.Date(2012, time.February, 3, 17, 00, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 3, 17, 04, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 240 * time.Second} oldDuration := ts.GetDuration() - nts := ts.SplitByInterval(i) + nts := ts.SplitByRateInterval(i) splitTime := time.Date(2012, time.February, 3, 17, 01, 00, 0, time.UTC) if ts.TimeStart != t1 || ts.TimeEnd != splitTime { t.Error("Incorrect first half", nts) @@ -491,17 +491,17 @@ func TestTimespanSplitMultipleGroup(t *testing.T) { if nts.TimeStart != splitTime || nts.TimeEnd != t2 { t.Error("Incorrect second half", nts) } - if ts.Interval != i { - t.Error("Interval not attached correctly") + if ts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if ts.GetDuration().Seconds() != 60 || nts.GetDuration().Seconds() != 180 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) } if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) } - nnts := nts.SplitByInterval(i) + nnts := nts.SplitByRateInterval(i) nsplitTime := time.Date(2012, time.February, 3, 17, 03, 00, 0, time.UTC) if nts.TimeStart != splitTime || nts.TimeEnd != nsplitTime { t.Error("Incorrect first half", nts) @@ -509,12 +509,12 @@ func TestTimespanSplitMultipleGroup(t *testing.T) { if nnts.TimeStart != nsplitTime || nnts.TimeEnd != t2 { t.Error("Incorrect second half", nnts) } - if nts.Interval != i { - t.Error("Interval not attached correctly") + if nts.RateInterval != i { + t.Error("RateInterval not attached correctly") } if nts.GetDuration().Seconds() != 120 || nnts.GetDuration().Seconds() != 60 { - t.Error("Wrong durations.for Intervals", nts.GetDuration().Seconds(), nnts.GetDuration().Seconds()) + t.Error("Wrong durations.for RateIntervals", nts.GetDuration().Seconds(), nnts.GetDuration().Seconds()) } } @@ -523,8 +523,8 @@ func TestTimespanExpandingPastEnd(t *testing.T) { &TimeSpan{ TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC), - Interval: &Interval{Prices: PriceGroups{ - &Price{RateIncrement: 60 * time.Second}, + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 60 * time.Second}, }}, }, &TimeSpan{ @@ -542,13 +542,37 @@ func TestTimespanExpandingPastEnd(t *testing.T) { } } +func TestTimespanExpandingRoundingPastEnd(t *testing.T) { + timespans := []*TimeSpan{ + &TimeSpan{ + TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), + TimeEnd: time.Date(2013, 9, 10, 14, 30, 20, 0, time.UTC), + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 15 * time.Second}, + }}, + }, + &TimeSpan{ + TimeStart: time.Date(2013, 9, 10, 14, 30, 20, 0, time.UTC), + TimeEnd: time.Date(2013, 9, 10, 14, 30, 40, 0, time.UTC), + }, + } + cd := &CallDescriptor{} + timespans = cd.expandTimeSpans(timespans) + if len(timespans) != 2 { + t.Error("Error removing overlaped intervals: ", timespans) + } + if !timespans[0].TimeEnd.Equal(time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC)) { + t.Error("Error expanding timespan: ", timespans[0]) + } +} + func TestTimespanExpandingPastEndMultiple(t *testing.T) { timespans := []*TimeSpan{ &TimeSpan{ TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC), - Interval: &Interval{Prices: PriceGroups{ - &Price{RateIncrement: 60 * time.Second}, + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 60 * time.Second}, }}, }, &TimeSpan{ @@ -575,8 +599,8 @@ func TestTimespanExpandingPastEndMultipleEqual(t *testing.T) { &TimeSpan{ TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC), - Interval: &Interval{Prices: PriceGroups{ - &Price{RateIncrement: 60 * time.Second}, + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 60 * time.Second}, }}, }, &TimeSpan{ @@ -603,8 +627,8 @@ func TestTimespanExpandingBeforeEnd(t *testing.T) { &TimeSpan{ TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC), - Interval: &Interval{Prices: PriceGroups{ - &Price{RateIncrement: 45 * time.Second}, + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 45 * time.Second}, }}, }, &TimeSpan{ @@ -629,8 +653,8 @@ func TestTimespanExpandingBeforeEndMultiple(t *testing.T) { &TimeSpan{ TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 10, 14, 30, 30, 0, time.UTC), - Interval: &Interval{Prices: PriceGroups{ - &Price{RateIncrement: 45 * time.Second}, + RateInterval: &RateInterval{Rates: RateGroups{ + &Rate{RateIncrement: 45 * time.Second}, }}, }, &TimeSpan{ diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 56824abd4..324c122ba 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -24,7 +24,6 @@ import ( "io/ioutil" "log" "strconv" - "time" ) // Import tariff plan from csv into storDb @@ -139,11 +138,11 @@ func (self *TPCSVImporter) importRates(fn string) error { } continue } - rt, err := NewRate(record[0], record[1], record[2], record[3], record[4], record[5], record[6], record[7], record[8]) + rt, err := NewLoadRate(record[0], record[1], record[2], record[3], record[4], record[5], record[6], record[7], record[8]) if err != nil { return err } - if err := self.StorDb.SetTPRates(self.TPid, map[string][]*Rate{record[0]: []*Rate{rt}}); err != nil { + if err := self.StorDb.SetTPRates(self.TPid, map[string][]*LoadRate{record[0]: []*LoadRate{rt}}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } @@ -294,16 +293,6 @@ func (self *TPCSVImporter) importActions(fn string) error { } continue } - var expiryTime time.Time // Empty initialized time represents never expire - if record[5] != "*unlimited" { // ToDo: Expand here for other meta tags or go way of adding time for expiry - expiryTime, err = time.Parse(time.RFC3339, record[5]) - if err != nil { - if self.Verbose { - log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) - } - continue - } - } rateValue, _ := strconv.ParseFloat(record[8], 64) // Ignore errors since empty string is error, we can find out based on rateType if defined minutesWeight, _ := strconv.ParseFloat(record[9], 64) weight, err := strconv.ParseFloat(record[10], 64) @@ -314,16 +303,18 @@ func (self *TPCSVImporter) importActions(fn string) error { continue } act := &Action{ - ActionType: actionType, - BalanceId: balanceType, - Direction: direction, - Units: units, - ExpirationDate: expiryTime, - DestinationTag: destTag, - RateType: rateType, - RateValue: rateValue, - MinutesWeight: minutesWeight, - Weight: weight, + ActionType: actionType, + BalanceId: balanceType, + Direction: direction, + ExpirationString: record[5], + Balance: &Balance{ + Value: units, + DestinationId: destTag, + SpecialPriceType: rateType, + SpecialPrice: rateValue, + Weight: minutesWeight, + }, + Weight: weight, } if err := self.StorDb.SetTPActions(self.TPid, map[string][]*Action{actId: []*Action{act}}); err != nil { if self.Verbose { diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index 130971b66..a466bb2bc 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -285,7 +285,7 @@ func (sm *FSSessionManager) OnChannelHangupComplete(ev Event) { Account: lastCC.Account, Destination: lastCC.Destination, Amount: -cost, - // FallbackSubject: lastCC.FallbackSubject, // ToDo: check how to best add it + // FallbackSubject: lastCC.FallbackSubject, // TODO: check how to best add it } var response float64 err := sm.connector.DebitCents(*cd, &response) diff --git a/utils/coreutils.go b/utils/coreutils.go index 5cbe8c54d..73b047373 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -121,13 +121,14 @@ func ParseDate(date string) (expDate time.Time, err error) { return expDate, err } -// returns a number equeal or larger than the peram that exactly -// is divisible to 60 -func RoundToMinute(seconds float64) float64 { - if math.Mod(seconds, 60) == 0 { - return seconds +// returns a number equeal or larger than the amount that exactly +// is divisible to whole +func RoundTo(whole, amount time.Duration) time.Duration { + a, w := float64(amount), float64(whole) + if math.Mod(a, w) == 0 { + return amount } - return (60 - math.Mod(seconds, 60)) + seconds + return time.Duration((w - math.Mod(a, w)) + a) } func SplitPrefix(prefix string) []string { diff --git a/utils/utils_test.go b/utils/utils_test.go index 89bb11742..af65bb6a7 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -195,33 +195,34 @@ func TestMissingStructFieldsIncorrect(t *testing.T) { } } -func TestRoundToMinute(t *testing.T) { - result := RoundToMinute(0) - expected := 0.0 +func TestRound(t *testing.T) { + minute := time.Minute + result := RoundTo(minute, 0*time.Second) + expected := 0 * time.Second if result != expected { t.Errorf("Error rounding to minute1: expected %v was %v", expected, result) } - result = RoundToMinute(1) - expected = 60.0 + result = RoundTo(minute, 1*time.Second) + expected = minute if result != expected { t.Errorf("Error rounding to minute2: expected %v was %v", expected, result) } - result = RoundToMinute(59) - expected = 60.0 + result = RoundTo(minute, 5*time.Second) + expected = minute if result != expected { t.Errorf("Error rounding to minute3: expected %v was %v", expected, result) } - result = RoundToMinute(60) - expected = 60.0 + result = RoundTo(minute, minute) + expected = minute if result != expected { t.Errorf("Error rounding to minute4: expected %v was %v", expected, result) } - result = RoundToMinute(90) - expected = 120.0 + result = RoundTo(minute, 90*time.Second) + expected = 120 * time.Second if result != expected { t.Errorf("Error rounding to minute5: expected %v was %v", expected, result) } - result = RoundToMinute(120) + result = RoundTo(60, 120) expected = 120.0 if result != expected { t.Errorf("Error rounding to minute5: expected %v was %v", expected, result)