mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
interval and activation profile refactoring
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
-------------------
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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"]))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user