From 39a51dc8262ea88d99477deb460f922cae62c824 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 3 Aug 2015 11:50:56 +0300 Subject: [PATCH 1/5] better rateinterval sorting --- engine/rateinterval.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 37d5d2f94..5e76e6693 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -376,7 +376,8 @@ func (il RateIntervalList) Swap(i, j int) { // we need higher weights earlyer in the list func (il RateIntervalList) Less(j, i int) bool { - return il[i].Weight < il[j].Weight + return il[i].Weight < il[j].Weight || + il[i].Timing.StartTime > il[j].Timing.StartTime } func (il RateIntervalList) Sort() { From 5e20dadfbaf337ed0c6e609fc372bc1d1c366a00 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 3 Aug 2015 13:23:05 +0300 Subject: [PATCH 2/5] make sure account is not cached --- engine/rateinterval.go | 3 +-- sessionmanager/session.go | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 5e76e6693..8c9d521fc 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -376,8 +376,7 @@ func (il RateIntervalList) Swap(i, j int) { // 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 + return il[i].Weight < il[j].Weight //|| il[i].Timing.StartTime > il[j].Timing.StartTime } func (il RateIntervalList) Sort() { diff --git a/sessionmanager/session.go b/sessionmanager/session.go index a7cb64aae..09f539db7 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -86,6 +86,7 @@ func (s *Session) debitLoop(runIdx int) { //engine.Logger.Debug(fmt.Sprintf("NEXTCD: %s", utils.ToJSON(nextCd))) nextCd.DurationIndex += debitPeriod // first presumed duration cc := new(engine.CallCost) + nextCd.account = nil // make sure it is not cached if err := s.sessionManager.Rater().MaxDebit(nextCd, cc); err != nil { engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err)) s.sessionManager.DisconnectSession(s.eventStart, s.connId, SYSTEM_ERROR) From 872891d6d94446de80a350fd7fb56572ff9a7282 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 3 Aug 2015 13:29:47 +0300 Subject: [PATCH 3/5] created method for account reset --- engine/calldesc.go | 4 ++++ sessionmanager/session.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/calldesc.go b/engine/calldesc.go index 5580c0687..f4fb5fb30 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -168,6 +168,10 @@ func (cd *CallDescriptor) getAccount() (ub *Account, err error) { return cd.account, err } +func (cd *CallDescriptor) ResetAccount() { + cd.account = nil +} + /* Restores the activation periods for the specified prefix from storage. */ diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 09f539db7..8a48b1ad4 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -86,7 +86,7 @@ func (s *Session) debitLoop(runIdx int) { //engine.Logger.Debug(fmt.Sprintf("NEXTCD: %s", utils.ToJSON(nextCd))) nextCd.DurationIndex += debitPeriod // first presumed duration cc := new(engine.CallCost) - nextCd.account = nil // make sure it is not cached + nextCd.ResetAccount() // make sure it is not cached if err := s.sessionManager.Rater().MaxDebit(nextCd, cc); err != nil { engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err)) s.sessionManager.DisconnectSession(s.eventStart, s.connId, SYSTEM_ERROR) From e3f4b21dac34f773f5fd984263d9b43bac7867a7 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 3 Aug 2015 13:47:57 +0300 Subject: [PATCH 4/5] make sure the account is not cached in calldesc --- engine/calldesc.go | 10 ++++++---- sessionmanager/session.go | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/engine/calldesc.go b/engine/calldesc.go index f4fb5fb30..345f53951 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -168,10 +168,6 @@ func (cd *CallDescriptor) getAccount() (ub *Account, err error) { return cd.account, err } -func (cd *CallDescriptor) ResetAccount() { - cd.account = nil -} - /* Restores the activation periods for the specified prefix from storage. */ @@ -425,6 +421,7 @@ func (cd *CallDescriptor) GetDuration() time.Duration { Creates a CallCost structure with the cost information calculated for the received CallDescriptor. */ func (cd *CallDescriptor) GetCost() (*CallCost, error) { + cd.account = nil // make sure it's not cached cc, err := cd.getCost() if err != nil { return nil, err @@ -589,6 +586,7 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura } func (cd *CallDescriptor) GetMaxSessionDuration() (duration time.Duration, err error) { + cd.account = nil // make sure it's not cached if account, err := cd.getAccount(); err != nil || account == nil { Logger.Err(fmt.Sprintf("Could not get user balance for <%s>: %s.", cd.GetAccountKey(), err.Error())) return 0, err @@ -642,6 +640,7 @@ func (cd *CallDescriptor) debit(account *Account, dryRun bool, goNegative bool) } func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { + cd.account = nil // make sure it's not cached // lock all group members if account, err := cd.getAccount(); err != nil || account == nil { Logger.Err(fmt.Sprintf("Could not get user balance for <%s>: %s.", cd.GetAccountKey(), err.Error())) @@ -664,6 +663,7 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { // This methods combines the Debit and GetMaxSessionDuration and will debit the max available time as returned // by the GetMaxSessionDuration method. The amount filed has to be filled in call descriptor. func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) { + cd.account = nil // make sure it's not cached if account, err := cd.getAccount(); err != nil || account == nil { Logger.Err(fmt.Sprintf("Could not get user balance for <%s>: %s.", cd.GetAccountKey(), err.Error())) return nil, err @@ -695,6 +695,7 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) { } func (cd *CallDescriptor) RefundIncrements() (left float64, err error) { + cd.account = nil // make sure it's not cached accountsCache := make(map[string]*Account) for _, increment := range cd.Increments { account, found := accountsCache[increment.BalanceInfo.AccountId] @@ -773,6 +774,7 @@ func (cd *CallDescriptor) GetLCRFromStorage() (*LCR, error) { } func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) { + cd.account = nil // make sure it's not cached lcr, err := cd.GetLCRFromStorage() if err != nil { return nil, err diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 8a48b1ad4..a7cb64aae 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -86,7 +86,6 @@ func (s *Session) debitLoop(runIdx int) { //engine.Logger.Debug(fmt.Sprintf("NEXTCD: %s", utils.ToJSON(nextCd))) nextCd.DurationIndex += debitPeriod // first presumed duration cc := new(engine.CallCost) - nextCd.ResetAccount() // make sure it is not cached if err := s.sessionManager.Rater().MaxDebit(nextCd, cc); err != nil { engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err)) s.sessionManager.DisconnectSession(s.eventStart, s.connId, SYSTEM_ERROR) From f8d72138f32f2c6a7c9f94c279a8506651129a14 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 3 Aug 2015 20:57:26 +0300 Subject: [PATCH 5/5] improvement on timing contains date method --- engine/balances.go | 2 +- engine/callcost_test.go | 1 + engine/calldesc.go | 32 +++++++++-- engine/calldesc_test.go | 12 ++-- engine/rateinterval.go | 117 +++++++++++++++++---------------------- engine/timespans.go | 89 +++++++++++++++++------------ engine/timespans_test.go | 21 +++++-- 7 files changed, 159 insertions(+), 115 deletions(-) diff --git a/engine/balances.go b/engine/balances.go index 6766ea55d..0408bdcc1 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -109,7 +109,7 @@ func (b *Balance) IsActiveAt(t time.Time) bool { return true } for _, tim := range b.Timings { - if tim.IsActiveAt(t, false) { + if tim.IsActiveAt(t) { return true } } diff --git a/engine/callcost_test.go b/engine/callcost_test.go index 6b3d6701f..10d2803cc 100644 --- a/engine/callcost_test.go +++ b/engine/callcost_test.go @@ -55,6 +55,7 @@ func TestMultipleResultMerge(t *testing.T) { cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.getCost() if cc1.Cost != 61 { + //ils.LogFull(cc1) t.Errorf("expected 61 was %v", cc1.Cost) for _, ts := range cc1.Timespans { t.Log(ts.RateInterval) diff --git a/engine/calldesc.go b/engine/calldesc.go index 345f53951..026a02c57 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -338,6 +338,7 @@ 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 @@ -346,8 +347,23 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { } } } - } + // split on days + /*for i := 0; i < len(timespans); i++ { + if timespans[i].TimeStart.Day() != timespans[i].TimeEnd.Day() { + //log.Print("TS: ", timespans[i].TimeStart, timespans[i].TimeEnd) + start := timespans[i].TimeStart + newTs := timespans[i].SplitByTime(time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()).Add(24 * time.Hour)) + if newTs != nil { + //log.Print("NEW TS: ", newTs.TimeStart, newTs.TimeEnd) + // insert the new timespan + index := i + 1 + timespans = append(timespans, nil) + copy(timespans[index+1:], timespans[index:]) + timespans[index] = newTs + } + } + }*/ // Logger.Debug(fmt.Sprintf("After SplitByRatingPlan: %+v", timespans)) // split on rate intervals for i := 0; i < len(timespans); i++ { @@ -357,16 +373,20 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { // Logger.Debug(fmt.Sprintf("rp: %+v", rp)) //timespans[i].RatingPlan = nil rp.RateIntervals.Sort() + /*for _, interval := range rp.RateIntervals { + if !timespans[i].hasBetterRateIntervalThan(interval) { + timespans[i].SetRateInterval(interval) + } + }*/ + //log.Print("ORIG TS: ", timespans[i].TimeStart, timespans[i].TimeEnd) + //log.Print(timespans[i].RateInterval) for _, interval := range rp.RateIntervals { //log.Printf("\tINTERVAL: %+v", interval.Timing) - if timespans[i].hasBetterRateIntervalThan(interval) { - //log.Print("continue") - continue // if the timespan has an interval than it already has a heigher weight - } newTs := timespans[i].SplitByRateInterval(interval, cd.TOR != utils.VOICE) //utils.PrintFull(timespans[i]) //utils.PrintFull(newTs) if newTs != nil { + //log.Print("NEW TS: ", newTs.TimeStart, newTs.TimeEnd) newTs.setRatingInfo(rp) // insert the new timespan index := i + 1 @@ -378,6 +398,8 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { } } } + //log.Print("TS: ", timespans[i].TimeStart, timespans[i].TimeEnd) + //log.Print(timespans[i].RateInterval.Timing) } //Logger.Debug(fmt.Sprintf("After SplitByRateInterval: %+v", timespans)) diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index bcdfa6197..8ac3f708f 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -195,7 +195,6 @@ func TestSplitSpansWeekend(t *testing.T) { }, } - //log.Print("=============================") timespans := cd.splitInTimeSpans() if len(timespans) != 2 { t.Log(cd.RatingInfos) @@ -404,9 +403,10 @@ 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", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} - result, _ := cd.GetCost() - if result.Cost != 1200 || result.GetConnectFee() != 0 { - t.Errorf("Expected %v was %v", 1200, result) + cc, _ := cd.GetCost() + if cc.Cost != 2100 || cc.GetConnectFee() != 0 { + utils.LogFull(cc) + t.Errorf("Expected %v was %v (%v)", 2100, cc, cc.GetConnectFee()) } } @@ -977,7 +977,9 @@ func TestDebitNegatve(t *testing.T) { t.Errorf("Error debiting from empty share: %+v", balanceMap[0].GetValue()) } cc, err = cd.MaxDebit() - //utils.PrintFull(cc) + acc, _ = cd.getAccount() + balanceMap = acc.BalanceMap[utils.MONETARY+OUTBOUND] + //utils.LogFull(balanceMap) if err != nil || cc.Cost != 2.5 { t.Errorf("Debit from empty share error: %+v, %v", cc, err) } diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 8c9d521fc..0087f9b7b 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -116,13 +116,44 @@ func (rit *RITiming) CronString() string { return rit.cronString } -// Returns wheter the Timing is active at the specified time -func (rit *RITiming) IsActiveAt(t time.Time, endTime bool) bool { - // if the received time represents an endtime consider it 24 instead of 0 - hour := t.Hour() - if endTime && hour == 0 { - hour = 24 +/* +Returns a time object that represents the end of the interval realtive to the received time +*/ +func (rit *RITiming) 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() + if rit.EndTime != "" { + split := strings.Split(rit.EndTime, ":") + hour, _ = strconv.Atoi(split[0]) + min, _ = strconv.Atoi(split[1]) + sec, _ = strconv.Atoi(split[2]) + //log.Print("RIGHT1: ", time.Date(year, month, day, hour, min, sec, nsec, loc)) + return time.Date(year, month, day, hour, min, sec, nsec, loc) } + //log.Print("RIGHT2: ", time.Date(year, month, day, hour, min, sec, nsec, loc).Add(time.Second)) + return time.Date(year, month, day, hour, min, sec, nsec, loc).Add(time.Second) +} + +/* +Returns a time object that represents the start of the interval realtive to the received time +*/ +func (rit *RITiming) 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() + if rit.StartTime != "" { + split := strings.Split(rit.StartTime, ":") + hour, _ = strconv.Atoi(split[0]) + min, _ = strconv.Atoi(split[1]) + sec, _ = strconv.Atoi(split[2]) + } + //log.Print("LEFT: ", time.Date(year, month, day, hour, min, sec, nsec, loc)) + return time.Date(year, month, day, hour, min, sec, nsec, loc) +} + +// Returns wheter the Timing is active at the specified time +func (rit *RITiming) IsActiveAt(t time.Time) bool { // check for years if len(rit.Years) > 0 && !rit.Years.Contains(t.Year()) { return false @@ -139,38 +170,25 @@ func (rit *RITiming) IsActiveAt(t time.Time, endTime bool) bool { if len(rit.WeekDays) > 0 && !rit.WeekDays.Contains(t.Weekday()) { return false } + //log.Print("Time: ", t) + + //log.Print("Left Margin: ", rit.getLeftMargin(t)) // check for start hour - if rit.StartTime != "" { - split := strings.Split(rit.StartTime, ":") - sh, _ := strconv.Atoi(split[0]) - sm, _ := strconv.Atoi(split[1]) - ss, _ := strconv.Atoi(split[2]) - // if the hour result before or result the same hour but the minute result before - if hour < sh || - (hour == sh && t.Minute() < sm) || - (hour == sh && t.Minute() == sm && t.Second() < ss) { - return false - } + if t.Before(rit.getLeftMargin(t)) { + return false } + + //log.Print("Right Margin: ", rit.getRightMargin(t)) // check for end hour - if rit.EndTime != "" { - split := strings.Split(rit.EndTime, ":") - eh, _ := strconv.Atoi(split[0]) - em, _ := strconv.Atoi(split[1]) - es, _ := strconv.Atoi(split[2]) - // if the hour result after or result the same hour but the minute result after - if hour > eh || - (hour == eh && t.Minute() > em) || - (hour == eh && t.Minute() == em && t.Second() > es) { - return false - } + if t.After(rit.getRightMargin(t)) { + return false } return true } // IsActive returns wheter the Timing is active now func (rit *RITiming) IsActive() bool { - return rit.IsActiveAt(time.Now(), false) + return rit.IsActiveAt(time.Now()) } func (rit *RITiming) IsBlank() bool { @@ -271,43 +289,12 @@ func (pg *RateGroups) AddRate(ps ...*Rate) { Returns true if the received time result inside the interval */ func (i *RateInterval) Contains(t time.Time, endTime bool) bool { - return i.Timing.IsActiveAt(t, endTime) -} - -/* -Returns a time object that represents the end of the interval realtive to the received 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() - if i.Timing.EndTime != "" { - split := strings.Split(i.Timing.EndTime, ":") - hour, _ = strconv.Atoi(split[0]) - min, _ = strconv.Atoi(split[1]) - sec, _ = strconv.Atoi(split[2]) - //log.Print("RIGHT1: ", time.Date(year, month, day, hour, min, sec, nsec, loc)) - return time.Date(year, month, day, hour, min, sec, nsec, loc) + if endTime { + if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 { // back one second to 23:59:59 + t = t.Add(-1 * time.Second) + } } - //log.Print("RIGHT2: ", time.Date(year, month, day, hour, min, sec, nsec, loc).Add(time.Second)) - return time.Date(year, month, day, hour, min, sec, nsec, loc).Add(time.Second) -} - -/* -Returns a time object that represents the start of the interval realtive to the received 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() - if i.Timing.StartTime != "" { - split := strings.Split(i.Timing.StartTime, ":") - hour, _ = strconv.Atoi(split[0]) - min, _ = strconv.Atoi(split[1]) - sec, _ = strconv.Atoi(split[2]) - } - //log.Print("LEFT: ", time.Date(year, month, day, hour, min, sec, nsec, loc)) - return time.Date(year, month, day, hour, min, sec, nsec, loc) + return i.Timing.IsActiveAt(t) } func (i *RateInterval) String_DISABLED() string { diff --git a/engine/timespans.go b/engine/timespans.go index 30d76b292..a4197f9ec 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -242,24 +242,13 @@ func (ts *TimeSpan) Contains(t time.Time) bool { return t.After(ts.TimeStart) && t.Before(ts.TimeEnd) } -/* -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) SetRateInterval(i *RateInterval) { - //log.Printf("SETRATEINTERVAL: %+v", i.Timing) - // higher weights are better - if ts.RateInterval == nil || ts.RateInterval.Weight < i.Weight { - ts.RateInterval = i - //log.Printf("RET TS: %+v", ts.RateInterval.Timing) +func (ts *TimeSpan) SetRateInterval(interval *RateInterval) { + if interval == nil { return } - iPrice, _, _ := i.GetRateParameters(ts.GetGroupStart()) - tsPrice, _, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) - if ts.RateInterval.Weight == i.Weight && iPrice <= tsPrice { - ts.RateInterval = i + if !ts.hasBetterRateIntervalThan(interval) { + ts.RateInterval = interval } - //log.Printf("END TS: %+v", ts.RateInterval.Timing) } // Returns the cost of the timespan according to the relevant cost interval. @@ -354,7 +343,7 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp for _, rate := range i.Rating.Rates { //Logger.Debug(fmt.Sprintf("Rate: %+v", rate)) if ts.GetGroupStart() < rate.GroupIntervalStart && ts.GetGroupEnd() > rate.GroupIntervalStart { - // Logger.Debug(fmt.Sprintf("Splitting")) + //log.Print("Splitting") ts.SetRateInterval(i) splitTime := ts.TimeStart.Add(rate.GroupIntervalStart - ts.GetGroupStart()) nts = &TimeSpan{ @@ -387,8 +376,7 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp // if only the start time is in the interval split the interval to the right if i.Contains(ts.TimeStart, false) { //log.Print("Start in interval") - splitTime := i.getRightMargin(ts.TimeStart) - + splitTime := i.Timing.getRightMargin(ts.TimeStart) ts.SetRateInterval(i) if splitTime == ts.TimeStart || splitTime.Equal(ts.TimeEnd) { return @@ -408,7 +396,7 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp if i.Contains(ts.TimeEnd, true) { //log.Print("End in interval") //tmpTime := time.Date(ts.TimeStart.) - splitTime := i.getLeftMargin(ts.TimeEnd) + splitTime := i.Timing.getLeftMargin(ts.TimeEnd) splitTime = utils.CopyHour(splitTime, ts.TimeStart) if splitTime.Equal(ts.TimeEnd) { return @@ -419,7 +407,6 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp } nts.copyRatingInfo(ts) ts.TimeEnd = splitTime - nts.SetRateInterval(i) nts.DurationIndex = ts.DurationIndex ts.SetNewDurationIndex(nts) @@ -429,6 +416,22 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp return } +/*func (ts *TimeSpan) SplitByTime(splitTime time.Time) (nts *TimeSpan) { + if splitTime.Equal(ts.TimeEnd) { + return + } + nts = &TimeSpan{ + TimeStart: splitTime, + TimeEnd: ts.TimeEnd, + } + nts.copyRatingInfo(ts) + ts.TimeEnd = splitTime + nts.SetRateInterval(ts.RateInterval) + nts.DurationIndex = ts.DurationIndex + ts.SetNewDurationIndex(nts) + return +}*/ + // Split the timespan at the given increment start func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan { if index <= 0 || index >= len(ts.Increments) { @@ -552,30 +555,46 @@ func (ts *TimeSpan) AddIncrement(inc *Increment) { } func (ts *TimeSpan) hasBetterRateIntervalThan(interval *RateInterval) bool { + if interval.Timing == nil { + return false + } + otherLeftMargin := interval.Timing.getLeftMargin(ts.TimeStart) + otherDistance := ts.TimeStart.Sub(otherLeftMargin) + //log.Print("OTHER LEFT: ", otherLeftMargin) + //log.Print("OTHER DISTANCE: ", otherDistance) + // if the distance is negative it's not usable + if otherDistance < 0 { + return true + } + //log.Print("RI: ", ts.RateInterval) if ts.RateInterval == nil { return false } - //log.Print("StartTime: ", ts.TimeStart) - //log.Printf("OWN: %+v", ts.RateInterval) - //log.Printf("OTHER: %+v", interval) + // the higher the weight the better if ts.RateInterval != nil && - ts.RateInterval.Weight > interval.Weight { - return true + ts.RateInterval.Weight < interval.Weight { + return false } // check interval is closer than the new one - ownLeftMargin := ts.RateInterval.getLeftMargin(ts.TimeStart) - otherLeftMargin := interval.getLeftMargin(ts.TimeStart) + ownLeftMargin := ts.RateInterval.Timing.getLeftMargin(ts.TimeStart) ownDistance := ts.TimeStart.Sub(ownLeftMargin) - otherDistance := ts.TimeStart.Sub(otherLeftMargin) - endOtherDistance := ts.TimeEnd.Sub(otherLeftMargin) - // if thr distance is negative relative to both ends it's not usable - if otherDistance < 0 && endOtherDistance < 0 { - return true - } + + //log.Print("OWN LEFT: ", otherLeftMargin) + //log.Print("OWN DISTANCE: ", otherDistance) + //endOtherDistance := ts.TimeEnd.Sub(otherLeftMargin) + // if own interval is closer than its better - if ownDistance <= otherDistance { + //log.Print(ownDistance) + if ownDistance > otherDistance { + return false + } + ownPrice, _, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) + otherPrice, _, _ := interval.GetRateParameters(ts.GetGroupStart()) + // if own price is smaller than it's better + //log.Print(ownPrice, otherPrice) + if ownPrice < otherPrice { return true } - return false + return true } diff --git a/engine/timespans_test.go b/engine/timespans_test.go index 468e2a51e..e2b21d1b2 100644 --- a/engine/timespans_test.go +++ b/engine/timespans_test.go @@ -217,7 +217,12 @@ func TestTimespanGetCost(t *testing.T) { if ts1.getCost() != 0 { t.Error("No interval and still kicking") } - ts1.SetRateInterval(&RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}}}) + ts1.SetRateInterval( + &RateInterval{ + Timing: &RITiming{}, + Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}}, + }, + ) if ts1.getCost() != 600 { t.Error("Expected 10 got ", ts1.Cost) } @@ -240,10 +245,18 @@ func TestTimespanGetCostIntervals(t *testing.T) { } func TestSetRateInterval(t *testing.T) { - i1 := &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}}} + i1 := &RateInterval{ + Timing: &RITiming{}, + Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}}, + } ts1 := TimeSpan{RateInterval: i1} - i2 := &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{0, 2.0, 1 * time.Second, 1 * time.Second}}}} - ts1.SetRateInterval(i2) + i2 := &RateInterval{ + Timing: &RITiming{}, + Rating: &RIRate{Rates: RateGroups{&Rate{0, 2.0, 1 * time.Second, 1 * time.Second}}}, + } + if !ts1.hasBetterRateIntervalThan(i2) { + ts1.SetRateInterval(i2) + } if ts1.RateInterval != i1 { t.Error("Smaller price interval should win") }