From 769960bf2f01f5d8971e83fb719814f1b5eea815 Mon Sep 17 00:00:00 2001 From: rbarrabe Date: Tue, 12 Apr 2016 11:35:15 +0200 Subject: [PATCH 1/9] Update huawei.xml --- data/diameter/dict/huawei/huawei.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/data/diameter/dict/huawei/huawei.xml b/data/diameter/dict/huawei/huawei.xml index 70e182ddd..4f48257d3 100644 --- a/data/diameter/dict/huawei/huawei.xml +++ b/data/diameter/dict/huawei/huawei.xml @@ -36,6 +36,15 @@ + + + + + + + + + From ea0f6745d0cac3f26f37875b4a504ce7f4213891 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 12 Apr 2016 19:36:40 +0300 Subject: [PATCH 2/9] derived charging exclude destination feature --- engine/handler_derivedcharging.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/engine/handler_derivedcharging.go b/engine/handler_derivedcharging.go index 52f48eb03..e845ac1dd 100644 --- a/engine/handler_derivedcharging.go +++ b/engine/handler_derivedcharging.go @@ -50,12 +50,10 @@ func DerivedChargersMatchesDest(dcs *utils.DerivedChargers, dest string) bool { for _, p := range utils.SplitPrefix(dest, MIN_PREFIX_MATCH) { if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil { destIds := x.(map[interface{}]struct{}) - for value := range dcs.DestinationIDs { - for idId := range destIds { - dId := idId.(string) - if value == dId { - return true - } + for dId := range destIds { + includeDest, found := dcs.DestinationIDs[dId.(string)] + if found { + return includeDest } } } From cbaeb9262664364e8fb03f637c78f2264e788e69 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 12 Apr 2016 19:48:01 +0300 Subject: [PATCH 3/9] dc exclude destination test --- engine/handler_derivedcharging_test.go | 18 ++++++++++++++++++ engine/history_test.go | 1 + engine/loader_csv_test.go | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/engine/handler_derivedcharging_test.go b/engine/handler_derivedcharging_test.go index 8a2c98f54..bb793b9ba 100644 --- a/engine/handler_derivedcharging_test.go +++ b/engine/handler_derivedcharging_test.go @@ -119,3 +119,21 @@ func TestHandleDeivedChargersMatchDestNatRet(t *testing.T) { t.Error("Derived charger failed to match dest") } } + +func TestHandleDeivedChargersMatchDestSpec(t *testing.T) { + dcs := &utils.DerivedChargers{ + DestinationIDs: utils.NewStringMap("NAT", "SPEC"), + } + if !DerivedChargersMatchesDest(dcs, "0723045326") { + t.Error("Derived charger failed to match dest") + } +} + +func TestHandleDeivedChargersMatchDestNegativeSpec(t *testing.T) { + dcs := &utils.DerivedChargers{ + DestinationIDs: utils.NewStringMap("NAT", "!SPEC"), + } + if DerivedChargersMatchesDest(dcs, "0723045326") { + t.Error("Derived charger failed to match dest") + } +} diff --git a/engine/history_test.go b/engine/history_test.go index 3e51c5a4a..e3d797e4b 100644 --- a/engine/history_test.go +++ b/engine/history_test.go @@ -47,6 +47,7 @@ func TestHistoryDestinations(t *testing.T) { {"Id":"PSTN_71","Prefixes":["+4971"]}, {"Id":"PSTN_72","Prefixes":["+4972"]}, {"Id":"RET","Prefixes":["0723","0724"]}, +{"Id":"SPEC","Prefixes":["0723045"]}, {"Id":"URG","Prefixes":["112"]}` if !strings.Contains(buf.String(), expected) { t.Error("Error in destination history content:", buf.String()) diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 357f56fb8..d26ebbcc6 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -42,6 +42,7 @@ NAT,0723 NAT,+49 RET,0723 RET,0724 +SPEC,0723045 PSTN_71,+4971 PSTN_72,+4972 PSTN_70,+4970 @@ -319,7 +320,7 @@ func init() { } func TestLoadDestinations(t *testing.T) { - if len(csvr.destinations) != 12 { + if len(csvr.destinations) != 13 { t.Error("Failed to load destinations: ", len(csvr.destinations)) } for _, d := range csvr.destinations { From bafa9d9802e0198d28b78bb924d3b7997abfc4df Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 12 Apr 2016 22:33:54 +0300 Subject: [PATCH 4/9] improve rating selection with splitting on days --- engine/calldesc.go | 21 ++++++++++++++++++-- engine/calldesc_test.go | 37 ++++++++++++++++++++++++++++++++++++ engine/ratingplan.go | 7 +------ engine/ratingprofile_test.go | 35 ++++++++++++++++++++++++++++++++++ engine/timespans.go | 22 +++++++++++++++++++++ 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/engine/calldesc.go b/engine/calldesc.go index fca3a671d..d6b98f57e 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -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 diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index ddde0471f..607a97a23 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -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) diff --git a/engine/ratingplan.go b/engine/ratingplan.go index 3f1214477..fd902ed8e 100644 --- a/engine/ratingplan.go +++ b/engine/ratingplan.go @@ -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. diff --git a/engine/ratingprofile_test.go b/engine/ratingprofile_test.go index 4f929029a..100aa0630 100644 --- a/engine/ratingprofile_test.go +++ b/engine/ratingprofile_test.go @@ -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") diff --git a/engine/timespans.go b/engine/timespans.go index 8a716f307..366de1d3f 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -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() From 6cf36e5be0c5867a409bab25a71db39683f7e30f Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 12 Apr 2016 23:17:01 +0300 Subject: [PATCH 5/9] better rate intervals sorting according to weight should solve the issue #424 --- engine/rateinterval.go | 20 ++----- engine/ratingprofile.go | 10 +++- engine/ratingprofile_test.go | 102 +++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 18 deletions(-) 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") From 6f686fd26a01c165962b32a4aa133158ab7a08c8 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 13 Apr 2016 09:38:48 +0300 Subject: [PATCH 6/9] updated dockerfiole to go 1.6.1 --- data/docker/devel/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/docker/devel/Dockerfile b/data/docker/devel/Dockerfile index ea0a8b803..5e4917784 100644 --- a/data/docker/devel/Dockerfile +++ b/data/docker/devel/Dockerfile @@ -26,7 +26,7 @@ COPY mongod.conf /etc/mongod.conf RUN useradd -c CGRateS -d /var/run/cgrates -s /bin/false -r cgrates # install golang -RUN wget -qO- https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz | tar xzf - -C /root/ +RUN wget -qO- https://storage.googleapis.com/golang/go1.6.1.linux-amd64.tar.gz | tar xzf - -C /root/ #install glide RUN GOROOT=/root/go GOPATH=/root/code /root/go/bin/go get github.com/Masterminds/glide From c9c49015b989b1d838d54af2489874a56fcb8213 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 13 Apr 2016 09:39:03 +0300 Subject: [PATCH 7/9] better check of 0h --- engine/rateinterval.go | 2 +- engine/timespans.go | 6 ++---- utils/coreutils.go | 4 ++++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/engine/rateinterval.go b/engine/rateinterval.go index b03af1b94..0b0b13ed2 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -289,7 +289,7 @@ Returns true if the received time result inside the interval */ func (i *RateInterval) Contains(t time.Time, endTime bool) bool { if endTime { - if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 { // back one second to 23:59:59 + if utils.TimeIs0h(t) { // back one second to 23:59:59 t = t.Add(-1 * time.Second) } } diff --git a/engine/timespans.go b/engine/timespans.go index 366de1d3f..33bc79e8d 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -614,14 +614,12 @@ func (ts *TimeSpan) SplitByRatingPlan(rp *RatingInfo) (newTs *TimeSpan) { // Splits the given timespan on activation period's activation time. func (ts *TimeSpan) SplitByDay() (newTs *TimeSpan) { - if ts.TimeStart.Day() == ts.TimeEnd.Day() { + if ts.TimeStart.Day() == ts.TimeEnd.Day() || utils.TimeIs0h(ts.TimeEnd) { 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, diff --git a/utils/coreutils.go b/utils/coreutils.go index 35453b5d5..461fb2d98 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -547,3 +547,7 @@ func SizeFmt(num float64, suffix string) string { } return fmt.Sprintf("%.1f%s%s", num, "Yi", suffix) } + +func TimeIs0h(t time.Time) bool { + return t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 +} From 77753ffc640abfa9bc5eeb32677781680a70acaa Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 13 Apr 2016 18:29:02 +0300 Subject: [PATCH 8/9] do not split data on days --- engine/calldesc.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/engine/calldesc.go b/engine/calldesc.go index d6b98f57e..150563676 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -378,20 +378,20 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { } } } - } - //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 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)) From 538aba2293deb602b389d32d0244f795b4f38da2 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 13 Apr 2016 23:29:47 +0300 Subject: [PATCH 9/9] improved one integration test --- general_tests/tp_it_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/general_tests/tp_it_test.go b/general_tests/tp_it_test.go index 1ad58d833..cb66dca3e 100644 --- a/general_tests/tp_it_test.go +++ b/general_tests/tp_it_test.go @@ -161,6 +161,12 @@ func TestTpZeroCost(t *testing.T) { if !*testIntegration { return } + var acnt *engine.Account + attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1012"} + if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error("Got error on ApierV2.GetAccount: ", err.Error()) + } + balanceValueBefore := acnt.BalanceMap[utils.MONETARY][0].Value tStart := time.Date(2016, 3, 31, 0, 0, 0, 0, time.UTC) cd := engine.CallDescriptor{ Direction: "*out", @@ -175,15 +181,13 @@ func TestTpZeroCost(t *testing.T) { } var cc engine.CallCost if err := tpRPC.Call("Responder.Debit", cd, &cc); err != nil { - t.Error("Got error on Responder.GetCost: ", err.Error()) + t.Error("Got error on Responder.Debit: ", err.Error()) } else if cc.GetDuration() != 20*time.Second { t.Errorf("Calling Responder.MaxDebit got callcost: %v", utils.ToIJSON(cc)) } - var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1012"} if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error("Got error on ApierV2.GetAccount: ", err.Error()) - } else if acnt.BalanceMap[utils.MONETARY][0].Value != 11.0 { + } else if acnt.BalanceMap[utils.MONETARY][0].Value != balanceValueBefore { t.Errorf("Calling ApierV2.GetAccount received: %s", utils.ToIJSON(acnt)) } }