improve rating selection with splitting on days

This commit is contained in:
Radu Ioan Fericean
2016-04-12 22:33:54 +03:00
parent cbaeb92626
commit bafa9d9802
5 changed files with 114 additions and 8 deletions

View File

@@ -362,6 +362,7 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
// split on rating plans
afterStart, afterEnd := false, false //optimization for multiple activation periods
for _, rp := range cd.RatingInfos {
//log.Print("RP: ", utils.ToJSON(rp))
if !afterStart && !afterEnd && rp.ActivationTime.Before(cd.TimeStart) {
firstSpan.setRatingInfo(rp)
} else {
@@ -369,7 +370,6 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
for i := 0; i < len(timespans); i++ {
newTs := timespans[i].SplitByRatingPlan(rp)
if newTs != nil {
//log.Print("NEW TS", newTs.TimeStart)
timespans = append(timespans, newTs)
} else {
afterEnd = true
@@ -379,7 +379,22 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
}
}
}
// utils.Logger.Debug(fmt.Sprintf("After SplitByRatingPlan: %+v", timespans))
//log.Printf("After SplitByRatingPlan: %+v", utils.ToJSON(timespans))
// split on days
for i := 0; i < len(timespans); i++ {
rp := timespans[i].ratingInfo
newTs := timespans[i].SplitByDay()
if newTs != nil {
//log.Print("NEW TS: ", newTs.TimeStart, newTs.TimeEnd)
newTs.setRatingInfo(rp)
// insert the new timespan
index := i + 1
timespans = append(timespans, nil)
copy(timespans[index+1:], timespans[index:])
timespans[index] = newTs
}
}
//log.Printf("After SplitByDay: %+v", utils.ToJSON(timespans))
// split on rate intervals
for i := 0; i < len(timespans); i++ {
//log.Printf("==============%v==================", i)
@@ -388,6 +403,7 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
// utils.Logger.Debug(fmt.Sprintf("rp: %+v", rp))
//timespans[i].RatingPlan = nil
rateIntervals := rp.SelectRatingIntevalsForTimespan(timespans[i])
//log.Print("RIs: ", utils.ToJSON(rateIntervals))
/*for _, interval := range rp.RateIntervals {
if !timespans[i].hasBetterRateIntervalThan(interval) {
timespans[i].SetRateInterval(interval)
@@ -520,6 +536,7 @@ func (cd *CallDescriptor) getCost() (*CallCost, error) {
cd.TOR = utils.VOICE
}
err := cd.LoadRatingPlans()
//log.Print("RI: ", utils.ToJSON(cd.RatingInfos))
if err != nil {
//utils.Logger.Err(fmt.Sprintf("error getting cost for key <%s>: %s", cd.GetKey(cd.Subject), err.Error()))
return &CallCost{Cost: -1}, err

View File

@@ -326,6 +326,43 @@ func TestGetCostRatingPlansAndRatingIntervalsMore(t *testing.T) {
}
}
func TestGetCostRatingPlansAndRatingIntervalsMoreDays(t *testing.T) {
t1 := time.Date(2012, time.February, 20, 9, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 23, 18, 10, 0, 0, time.UTC)
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, DurationIndex: t2.Sub(t1)}
result, _ := cd.GetCost()
if len(result.Timespans) != 8 ||
!result.Timespans[0].TimeEnd.Equal(result.Timespans[1].TimeStart) ||
!result.Timespans[1].TimeEnd.Equal(result.Timespans[2].TimeStart) ||
!result.Timespans[2].TimeEnd.Equal(result.Timespans[3].TimeStart) ||
!result.Timespans[3].TimeEnd.Equal(result.Timespans[4].TimeStart) ||
!result.Timespans[4].TimeEnd.Equal(result.Timespans[5].TimeStart) ||
!result.Timespans[5].TimeEnd.Equal(result.Timespans[6].TimeStart) ||
!result.Timespans[6].TimeEnd.Equal(result.Timespans[7].TimeStart) {
for _, ts := range result.Timespans {
t.Logf("TS %+v", ts)
}
t.Errorf("Expected %+v was %+v", 4, len(result.Timespans))
}
}
func TestGetCostRatingPlansAndRatingIntervalsMoreDaysWeekend(t *testing.T) {
t1 := time.Date(2012, time.February, 24, 9, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 27, 18, 10, 0, 0, time.UTC)
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, DurationIndex: t2.Sub(t1)}
result, _ := cd.GetCost()
if len(result.Timespans) != 5 ||
!result.Timespans[0].TimeEnd.Equal(result.Timespans[1].TimeStart) ||
!result.Timespans[1].TimeEnd.Equal(result.Timespans[2].TimeStart) ||
!result.Timespans[2].TimeEnd.Equal(result.Timespans[3].TimeStart) ||
!result.Timespans[3].TimeEnd.Equal(result.Timespans[4].TimeStart) {
for _, ts := range result.Timespans {
t.Logf("TS %+v", ts)
}
t.Errorf("Expected %+v was %+v", 4, len(result.Timespans))
}
}
func TestGetCostRateGroups(t *testing.T) {
t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC)
t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC)

View File

@@ -59,12 +59,7 @@ func (rp *RatingPlan) RateIntervalList(dId string) RateIntervalList {
return ril
}
/*
type xCachedRatingPlan struct {
rp *RatingPlan
*cache2go.XEntry
}
*/
// no sorter because it's sorted with RateIntervalTimeSorter
/*
Adds one ore more intervals to the internal interval list only if it is not allready in the list.

View File

@@ -250,6 +250,41 @@ func TestRatingProfileRIforTSMidnight(t *testing.T) {
}
}
func TestRatingProfileYearMonthDay(t *testing.T) {
ri := &RatingInfo{
RateIntervals: RateIntervalList{
&RateInterval{
Timing: &RITiming{
StartTime: "09:00:00",
},
},
&RateInterval{
Timing: &RITiming{
StartTime: "00:00:00",
},
},
&RateInterval{
Timing: &RITiming{
Years: utils.Years{2016},
Months: utils.Months{1},
MonthDays: utils.MonthDays{6, 7},
WeekDays: utils.WeekDays{},
StartTime: "19:00:00",
},
},
},
}
ts := &TimeSpan{
TimeStart: time.Date(2016, 1, 6, 23, 40, 0, 0, time.UTC),
TimeEnd: time.Date(2016, 1, 7, 1, 1, 30, 0, time.UTC),
}
rIntervals := ri.SelectRatingIntevalsForTimespan(ts)
if len(rIntervals) != 1 ||
rIntervals[0].Timing.StartTime != "19:00:00" {
t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals))
}
}
func TestRatingProfileSubjectPrefixMatching(t *testing.T) {
rpSubjectPrefixMatching = true
rp, err := RatingProfileSubjectPrefixMatching("*out:cgrates.org:data:rif")

View File

@@ -612,6 +612,28 @@ func (ts *TimeSpan) SplitByRatingPlan(rp *RatingInfo) (newTs *TimeSpan) {
return
}
// Splits the given timespan on activation period's activation time.
func (ts *TimeSpan) SplitByDay() (newTs *TimeSpan) {
if ts.TimeStart.Day() == ts.TimeEnd.Day() {
return
}
splitDate := ts.TimeStart.AddDate(0, 0, 1)
splitDate = time.Date(splitDate.Year(), splitDate.Month(), splitDate.Day(), 0, 0, 0, 0, splitDate.Location())
if splitDate == ts.TimeEnd { // the end date time was actually 00:00:00
return
}
newTs = &TimeSpan{
TimeStart: splitDate,
TimeEnd: ts.TimeEnd,
}
newTs.copyRatingInfo(ts)
newTs.DurationIndex = ts.DurationIndex
ts.TimeEnd = splitDate
ts.SetNewDurationIndex(newTs)
// Logger.Debug(fmt.Sprintf("RP SPLITTING: %+v %+v", ts, newTs))
return
}
// Returns the starting time of this timespan
func (ts *TimeSpan) GetGroupStart() time.Duration {
s := ts.DurationIndex - ts.GetDuration()