diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 0ddcb241d..b03af1b94 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -360,23 +360,6 @@ func (ri *RateInterval) GetMaxCost() (float64, string) { // Structure to store intervals according to weight type RateIntervalList []*RateInterval -func (il RateIntervalList) Len() int { - return len(il) -} - -func (il RateIntervalList) Swap(i, j int) { - il[i], il[j] = il[j], il[i] -} - -// we need higher weights earlyer in the list -func (il RateIntervalList) Less(j, i int) bool { - return il[i].Weight < il[j].Weight //|| il[i].Timing.StartTime > il[j].Timing.StartTime -} - -func (il RateIntervalList) Sort() { - sort.Sort(il) -} - // Structure to store intervals according to weight type RateIntervalTimeSorter struct { referenceTime time.Time @@ -393,6 +376,9 @@ func (il *RateIntervalTimeSorter) Swap(i, j int) { // we need higher weights earlyer in the list func (il *RateIntervalTimeSorter) Less(j, i int) bool { + if il.ris[i].Weight < il.ris[j].Weight { + return il.ris[i].Weight < il.ris[j].Weight + } t1 := il.ris[i].Timing.getLeftMargin(il.referenceTime) t2 := il.ris[j].Timing.getLeftMargin(il.referenceTime) return t1.After(t2) diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index 2560e96c0..e72665a22 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -92,28 +92,36 @@ type RatingInfo struct { // SelectRatingIntevalsForTimespan orders rate intervals in time preserving only those which aply to the specified timestamp func (ri RatingInfo) SelectRatingIntevalsForTimespan(ts *TimeSpan) (result RateIntervalList) { - ri.RateIntervals.Sort() sorter := &RateIntervalTimeSorter{referenceTime: ts.TimeStart, ris: ri.RateIntervals} rateIntervals := sorter.Sort() // get the rating interval closest to begining of timespan var delta time.Duration = -1 var bestRateIntervalIndex int + var bestIntervalWeight float64 for index, rateInterval := range rateIntervals { if !rateInterval.Contains(ts.TimeStart, false) { continue } + if rateInterval.Weight < bestIntervalWeight { + break // don't consider lower weights' + } startTime := rateInterval.Timing.getLeftMargin(ts.TimeStart) tmpDelta := ts.TimeStart.Sub(startTime) if (startTime.Before(ts.TimeStart) || startTime.Equal(ts.TimeStart)) && (delta == -1 || tmpDelta < delta) { bestRateIntervalIndex = index + bestIntervalWeight = rateInterval.Weight delta = tmpDelta } } result = append(result, rateIntervals[bestRateIntervalIndex]) // check if later rating intervals influence this timespan + //log.Print("RIS: ", utils.ToIJSON(rateIntervals)) for i := bestRateIntervalIndex + 1; i < len(rateIntervals); i++ { + if rateIntervals[i].Weight < bestIntervalWeight { + break // don't consider lower weights' + } startTime := rateIntervals[i].Timing.getLeftMargin(ts.TimeStart) if startTime.Before(ts.TimeEnd) { result = append(result, rateIntervals[i]) diff --git a/engine/ratingprofile_test.go b/engine/ratingprofile_test.go index 100aa0630..08cfecacd 100644 --- a/engine/ratingprofile_test.go +++ b/engine/ratingprofile_test.go @@ -285,6 +285,108 @@ func TestRatingProfileYearMonthDay(t *testing.T) { } } +func TestRatingProfileWeighted(t *testing.T) { + ri := &RatingInfo{ + RateIntervals: RateIntervalList{ + &RateInterval{ + Timing: &RITiming{ + StartTime: "09:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + StartTime: "00:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + StartTime: "19:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + Years: utils.Years{2016}, + Months: utils.Months{1}, + MonthDays: utils.MonthDays{6}, + WeekDays: utils.WeekDays{}, + StartTime: "00:00:00", + }, + Weight: 11, + }, + }, + } + ts := &TimeSpan{ + TimeStart: time.Date(2016, 1, 6, 23, 40, 0, 0, time.UTC), + TimeEnd: time.Date(2016, 1, 6, 23, 45, 30, 0, time.UTC), + } + rIntervals := ri.SelectRatingIntevalsForTimespan(ts) + if len(rIntervals) != 1 || + rIntervals[0].Timing.StartTime != "00:00:00" || + rIntervals[0].Weight != 11 { + t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals)) + } +} + +func TestRatingProfileWeightedMultiple(t *testing.T) { + ri := &RatingInfo{ + RateIntervals: RateIntervalList{ + &RateInterval{ + Timing: &RITiming{ + StartTime: "09:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + StartTime: "00:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + StartTime: "19:00:00", + }, + Weight: 10, + }, + &RateInterval{ + Timing: &RITiming{ + Years: utils.Years{2016}, + Months: utils.Months{1}, + MonthDays: utils.MonthDays{6}, + WeekDays: utils.WeekDays{}, + StartTime: "00:00:00", + }, + Weight: 11, + }, + &RateInterval{ + Timing: &RITiming{ + Years: utils.Years{2016}, + Months: utils.Months{1}, + MonthDays: utils.MonthDays{6}, + WeekDays: utils.WeekDays{}, + StartTime: "18:00:00", + }, + Weight: 11, + }, + }, + } + ts := &TimeSpan{ + TimeStart: time.Date(2016, 1, 6, 17, 40, 0, 0, time.UTC), + TimeEnd: time.Date(2016, 1, 6, 23, 45, 30, 0, time.UTC), + } + rIntervals := ri.SelectRatingIntevalsForTimespan(ts) + if len(rIntervals) != 2 || + rIntervals[0].Timing.StartTime != "00:00:00" || + rIntervals[0].Weight != 11 || + rIntervals[1].Timing.StartTime != "18:00:00" || + rIntervals[1].Weight != 11 { + t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals)) + } +} + func TestRatingProfileSubjectPrefixMatching(t *testing.T) { rpSubjectPrefixMatching = true rp, err := RatingProfileSubjectPrefixMatching("*out:cgrates.org:data:rif")