before rewrite

This commit is contained in:
Radu Ioan Fericean
2013-12-09 12:19:58 +02:00
parent 7809fa4e8e
commit 3611494936
7 changed files with 725 additions and 150 deletions

View File

@@ -27,7 +27,7 @@ import (
type CallCost struct {
Direction, TOR, Tenant, Subject, Account, Destination string
Cost, ConnectFee float64
Timespans []*TimeSpan
Timespans TimeSpans
}
// Pretty printing for call cost

View File

@@ -22,11 +22,12 @@ import (
"encoding/json"
"errors"
"fmt"
"log/syslog"
"time"
"github.com/cgrates/cgrates/cache2go"
"github.com/cgrates/cgrates/history"
"github.com/cgrates/cgrates/utils"
"log/syslog"
"time"
)
func init() {
@@ -343,45 +344,28 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti
// 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) roundTimeSpansToIncrement(timespans []*TimeSpan) []*TimeSpan {
for i, ts := range timespans {
//log.Printf("TS: %+v", ts)
func (cd *CallDescriptor) roundTimeSpansToIncrement(timespans TimeSpans) []*TimeSpan {
for i := 0; i < len(timespans); i++ {
ts := timespans[i]
if ts.overlapped {
continue
}
if ts.RateInterval != nil {
_, rateIncrement, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart())
//log.Printf("Inc: %+v", rateIncrement)
// 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())
}
//log.Printf("Inc: %+v", rateIncrement)
if rateIncrement > ts.GetDuration() {
initialDuration := ts.GetDuration()
//log.Printf("Initial: %+v", initialDuration)
ts.TimeEnd = ts.TimeStart.Add(rateIncrement)
ts.CallDuration = ts.CallDuration + (rateIncrement - initialDuration)
//log.Printf("After: %+v", ts.CallDuration)
// overlap the rest of the timespans
i += 1
for ; i < len(timespans); i++ {
if timespans[i].TimeEnd.Before(ts.TimeEnd) || timespans[i].TimeEnd.Equal(ts.TimeEnd) {
timespans[i].overlapped = true
} else if timespans[i].TimeStart.Before(ts.TimeEnd) {
timespans[i].TimeStart = ts.TimeEnd
}
}
break
timespans.RemoveOverlapedFromIndex(i)
}
}
}
var newTimespans []*TimeSpan
// remove overlapped
for _, ts := range timespans {
if !ts.overlapped {
newTimespans = append(newTimespans, ts)
}
}
return newTimespans
return timespans
}
/*

View File

@@ -49,7 +49,7 @@ var balanceInsufficient = `{"Id":"*out:192.168.56.66:dan","Type":"*prepaid","Bal
var costInsufficient = `{"Direction":"*out","TOR":"call","Tenant":"192.168.56.66","Subject":"dan","Account":"dan","Destination":"+4986517174963","Cost":1,"ConnectFee":3,"Timespans":[{"TimeStart":"2013-12-05T09:52:17+01:00","TimeEnd":"2013-12-05T09:53:17+01:00","Cost":1,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":3,"Rates":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":60000000000,"RateUnit":60000000000}],"RoundingMethod":"*up","RoundingDecimals":2},"Weight":10},"CallDuration":60000000000,"Increments":null,"MatchedSubject":"*out:192.168.56.66:call:*any","MatchedPrefix":"+49"}]}`
func SomeTestDebitInsufficientBalance(t *testing.T) {
func FIXMETestDebitInsufficientBalance(t *testing.T) {
b1 := new(UserBalance)
if err := json.Unmarshal([]byte(balanceInsufficient), b1); err != nil {
t.Error("Error restoring balance1: ", err)

View File

@@ -20,8 +20,10 @@ package engine
import (
//"fmt"
"github.com/cgrates/cgrates/utils"
"time"
"github.com/cgrates/cgrates/utils"
)
/*
@@ -33,8 +35,8 @@ type TimeSpan struct {
ratingInfo *RatingInfo
RateInterval *RateInterval
CallDuration time.Duration // the call duration so far till TimeEnd
overlapped bool // mark a timespan as overlapped by an expanded one
Increments Increments
overlapped bool
MatchedSubject, MatchedPrefix string
}
@@ -53,6 +55,87 @@ type MinuteInfo struct {
Price float64
}
type TimeSpans []*TimeSpan
func (timespans *TimeSpans) RemoveOverlapedFromIndex(index int) {
tss := *timespans
ts := tss[index]
endOverlapIndex := index
for i := index + 1; i < len(tss); i++ {
if tss[i].TimeEnd.Before(ts.TimeEnd) || tss[i].TimeEnd.Equal(ts.TimeEnd) {
endOverlapIndex = i
} else if tss[i].TimeStart.Before(ts.TimeEnd) {
tss[i].TimeStart = ts.TimeEnd
break
}
}
if endOverlapIndex > index {
newSliceEnd := len(tss) - (endOverlapIndex - index)
// delete overlapped
copy(tss[index+1:], tss[endOverlapIndex+1:])
for i := newSliceEnd; i < len(tss); i++ {
tss[i] = nil
}
*timespans = tss[:newSliceEnd]
}
}
// The paidTs will replace the timespans that are exactly under them from the reciver list
func (timespans *TimeSpans) OverlapWithTimeSpans(paidTs TimeSpans, newTs *TimeSpan, index int) bool {
tss := *timespans
// calculate overlaped timespans
var paidDuration time.Duration
for _, pts := range paidTs {
paidDuration += pts.GetDuration()
}
if paidDuration > 0 {
// we must add the rest of the current ts to the remaingTs
var remainingTs []*TimeSpan
overlapStartIndex := index
if newTs != nil {
remainingTs = append(remainingTs, newTs)
overlapStartIndex += 1
}
for tsi := overlapStartIndex; tsi < len(tss); tsi++ {
remainingTs = append(remainingTs, tss[tsi])
}
overlapEndIndex := 0
for i, rts := range remainingTs {
if paidDuration >= rts.GetDuration() {
paidDuration -= rts.GetDuration()
} else {
if paidDuration > 0 {
// this ts was not fully paid
fragment := rts.SplitByDuration(paidDuration)
paidTs = append(paidTs, fragment)
}
// find the end position in tss
overlapEndIndex = overlapStartIndex + i
break
}
// find the end position in tss
overlapEndIndex = overlapStartIndex + i
}
// delete from index to current
if overlapEndIndex == len(tss)-1 {
tss = tss[:overlapStartIndex]
} else {
tss = append(tss[:overlapStartIndex], tss[overlapEndIndex+1:]...)
}
// append the timespans to outer tss
for i, pts := range paidTs {
tss = append(tss, nil)
copy(tss[overlapStartIndex+i+1:], tss[overlapStartIndex+i:])
tss[overlapStartIndex+i] = pts
}
*timespans = tss
return true
}
*timespans = tss
return false
}
func (incr *Increment) Clone() *Increment {
nIncr := &Increment{
Duration: incr.Duration,
@@ -318,6 +401,9 @@ func (ts *TimeSpan) SetNewCallDuration(nts *TimeSpan) {
}
func (nts *TimeSpan) copyRatingInfo(ts *TimeSpan) {
if ts.ratingInfo == nil {
return
}
nts.ratingInfo = ts.ratingInfo
nts.MatchedSubject = ts.ratingInfo.MatchedSubject
nts.MatchedPrefix = ts.ratingInfo.MatchedPrefix

View File

@@ -19,9 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"github.com/cgrates/cgrates/utils"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
func TestRightMargin(t *testing.T) {
@@ -517,7 +518,7 @@ func TestTimespanExpandingPastEnd(t *testing.T) {
t.Error("Error removing overlaped intervals: ", timespans)
}
if !timespans[0].TimeEnd.Equal(time.Date(2013, 9, 10, 14, 31, 0, 0, time.UTC)) {
t.Error("Error expanding timespan: ", timespans[0])
t.Errorf("Error expanding timespan: %+v", timespans[0])
}
}
@@ -862,3 +863,596 @@ func TestTimespanSplitByDuration(t *testing.T) {
t.Error("Error spliting increment: ", ts.Increments[4], newTs.Increments[0])
}
}
func TestRemoveOverlapedFromIndexMiddle(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(1)
if len(tss) != 3 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexMiddleNonBounds(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(1)
if len(tss) != 4 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC) ||
tss[2].TimeStart != time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexMiddleNonBoundsOver(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(1)
if len(tss) != 3 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC) ||
tss[2].TimeStart != time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexEnd(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(1)
if len(tss) != 2 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexEndPast(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 50, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(1)
if len(tss) != 2 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 50, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexAll(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(0)
if len(tss) != 1 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexNone(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(0)
if len(tss) != 4 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexOne(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(0)
if len(tss) != 1 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestRemoveOverlapedFromIndexTwo(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 50, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
}
(&tss).RemoveOverlapedFromIndex(0)
if len(tss) != 1 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 50, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %+v", ts)
}
t.Error("Error removing overlaped timespans: ", tss)
}
}
func TestOverlapWithTimeSpansMiddleLong(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 1)
if len(tss) != 3 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansMiddleMedium(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 1)
if len(tss) != 4 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansMiddleShort(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 1)
if len(tss) != 5 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 46, 30, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[4].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansStart(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 0)
if len(tss) != 3 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 47, 30, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansAlmostEnd(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 3)
if len(tss) != 5 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 48, 30, 0, time.UTC) ||
tss[4].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansEnd(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 3)
if len(tss) != 4 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansPastEnd(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 3)
if len(tss) != 4 ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC) ||
tss[1].TimeEnd != time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC) ||
tss[2].TimeEnd != time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC) ||
tss[3].TimeEnd != time.Date(2013, 12, 5, 15, 49, 30, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansAll(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 0)
if len(tss) != 1 ||
tss[0].TimeStart != time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC) ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}
func TestOverlapWithTimeSpansAllPast(t *testing.T) {
tss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 46, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 47, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
},
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 0, 0, time.UTC),
},
}
newTss := TimeSpans{
&TimeSpan{
TimeStart: time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 12, 5, 15, 49, 30, 0, time.UTC),
},
}
(&tss).OverlapWithTimeSpans(newTss, nil, 0)
if len(tss) != 1 ||
tss[0].TimeStart != time.Date(2013, 12, 5, 15, 45, 0, 0, time.UTC) ||
tss[0].TimeEnd != time.Date(2013, 12, 5, 15, 49, 30, 0, time.UTC) {
for _, ts := range tss {
t.Logf("TS: %v", ts)
}
t.Error("Error overlaping with timespans timespans: ", tss)
}
}

View File

@@ -21,6 +21,7 @@ package engine
import (
"errors"
"fmt"
"log"
"github.com/cgrates/cgrates/utils"
@@ -180,16 +181,18 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
return nil
}
}
// debit minutes
for tsIndex := 0; tsIndex < len(cc.Timespans); tsIndex++ {
ts := cc.Timespans[tsIndex]
ts.createIncrementsSlice()
tsWasSplit := false
log.Print("TS: ", ts)
for incrementIndex, increment := range ts.Increments {
if tsWasSplit {
break
}
paid := false
// debit minutes
log.Print("Debit minutes")
for _, b := range usefulMinuteBalances {
// check standard subject tags
if b.RateSubject == ZEROSECOND || b.RateSubject == "" {
@@ -228,14 +231,6 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
},
}
newTs.createIncrementsSlice()
// overlap the rest of the timespans
for i := tsIndex + 1; i < len(cc.Timespans); i++ {
if cc.Timespans[i].TimeEnd.Before(newTs.TimeEnd) || cc.Timespans[i].TimeEnd.Equal(newTs.TimeEnd) {
cc.Timespans[i].overlapped = true
} else if cc.Timespans[i].TimeStart.Before(newTs.TimeEnd) {
cc.Timespans[i].TimeStart = ts.TimeEnd
}
}
// insert the new timespan
if newTs != ts {
tsIndex++
@@ -245,14 +240,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
tsWasSplit = true
}
var newTimespans []*TimeSpan
// remove overlapped
for _, ots := range cc.Timespans {
if !ots.overlapped {
newTimespans = append(newTimespans, ots)
}
}
cc.Timespans = newTimespans
cc.Timespans.RemoveOverlapedFromIndex(tsIndex)
b.Value -= amount
newTs.Increments[0].BalanceUuids = append(newTs.Increments[0].BalanceUuids, b.Uuid)
newTs.Increments[0].MinuteInfo = &MinuteInfo{cc.Destination, amount, 0}
@@ -280,6 +268,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
var paidTs []*TimeSpan
for _, nts := range newCC.Timespans {
nts.createIncrementsSlice()
log.Printf("XXX: %+v", nts)
paidTs = append(paidTs, nts)
for nIdx, nInc := range nts.Increments {
// debit minutes and money
@@ -308,51 +297,9 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
}
}
}
// calculate overlaped timespans
var paidDuration time.Duration
for _, pts := range paidTs {
paidDuration += pts.GetDuration()
}
if paidDuration > 0 {
// split from current increment
newTs := ts.SplitByIncrement(incrementIndex)
var remainingTs []*TimeSpan
if newTs != nil {
remainingTs = append(remainingTs, newTs)
} else {
// nothing was paied form current ts so remove it
cc.Timespans = append(cc.Timespans[:tsIndex], cc.Timespans[tsIndex+1:]...)
tsIndex--
}
for tsi := tsIndex + 1; tsi < len(cc.Timespans); tsi++ {
remainingTs = append(remainingTs, cc.Timespans[tsi])
}
for remainingIndex, rts := range remainingTs {
if paidDuration >= rts.GetDuration() {
paidDuration -= rts.GetDuration()
} else {
if paidDuration > 0 {
// this ts was not fully paid
fragment := rts.SplitByDuration(paidDuration)
paidTs = append(paidTs, fragment)
}
// delete from tsIndex to current
cc.Timespans = append(cc.Timespans[:tsIndex], cc.Timespans[remainingIndex:]...)
break
}
}
// append the timpespans to outer timespans
for _, pts := range paidTs {
tsIndex++
cc.Timespans = append(cc.Timespans, nil)
copy(cc.Timespans[tsIndex+1:], cc.Timespans[tsIndex:])
cc.Timespans[tsIndex] = pts
}
paid = true
tsWasSplit = true
}
newTs := ts.SplitByIncrement(incrementIndex)
overlapped := (&cc.Timespans).OverlapWithTimeSpans(paidTs, newTs, tsIndex)
paid, tsWasSplit = overlapped, overlapped
}
if paid {
continue
@@ -368,9 +315,11 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
newTs.createIncrementsSlice()
tsWasSplit = true
}
log.Print("BREAK ON MINUTES")
break
}
}
log.Print("Debit money")
// debit monetary
for _, b := range usefulMoneyBalances {
// check standard subject tags
@@ -401,6 +350,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
var paidTs []*TimeSpan
for _, nts := range newCC.Timespans {
nts.createIncrementsSlice()
log.Printf("COST: %+v", nts)
paidTs = append(paidTs, nts)
for nIdx, nInc := range nts.Increments {
// debit money
@@ -416,54 +366,13 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
}
}
}
// calculate overlaped timespans
var paidDuration time.Duration
for _, pts := range paidTs {
paidDuration += pts.GetDuration()
}
if paidDuration > 0 {
// split from current increment
newTs := ts.SplitByIncrement(incrementIndex)
var remainingTs []*TimeSpan
if newTs != nil {
remainingTs = append(remainingTs, newTs)
} else {
// nothing was paied form current ts so remove it
cc.Timespans = append(cc.Timespans[:tsIndex], cc.Timespans[tsIndex+1:]...)
tsIndex--
}
for tsi := tsIndex + 1; tsi < len(cc.Timespans); tsi++ {
remainingTs = append(remainingTs, cc.Timespans[tsi])
}
for remainingIndex, rts := range remainingTs {
if paidDuration >= rts.GetDuration() {
paidDuration -= rts.GetDuration()
} else {
if paidDuration > 0 {
// this ts was not fully paid
fragment := rts.SplitByDuration(paidDuration)
paidTs = append(paidTs, fragment)
}
// delete from tsIndex to current
cc.Timespans = append(cc.Timespans[:tsIndex], cc.Timespans[remainingIndex:]...)
break
}
}
// append the timpespans to outer timespans
for _, pts := range paidTs {
tsIndex++
cc.Timespans = append(cc.Timespans, nil)
copy(cc.Timespans[tsIndex+1:], cc.Timespans[tsIndex:])
cc.Timespans[tsIndex] = pts
}
paid = true
tsWasSplit = true
}
newTs := ts.SplitByIncrement(incrementIndex)
overlapped := (&cc.Timespans).OverlapWithTimeSpans(paidTs, newTs, tsIndex)
paid, tsWasSplit = overlapped, overlapped
}
}
if !paid {
// FIXME: must debit all from the first monetary balance (go negative)
// no balance was attached to this increment: cut the rest of increments/timespans
if incrementIndex == 0 {
// if we are right at the begining in the ts leave it out

View File

@@ -659,8 +659,8 @@ func TestDebitCreditSubjectMixed(t *testing.T) {
Timespans: []*TimeSpan{
&TimeSpan{
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 9, 24, 10, 49, 10, 0, time.UTC),
CallDuration: 0,
TimeEnd: time.Date(2013, 9, 24, 10, 48, 55, 0, time.UTC),
CallDuration: 55 * time.Second,
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
},
},
@@ -679,12 +679,15 @@ func TestDebitCreditSubjectMixed(t *testing.T) {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
if rifsBalance.BalanceMap[MINUTES+OUTBOUND][0].Value != 0 ||
rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 80 {
rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 20 {
t.Errorf("Error extracting minutes from balance: %+v, %+v",
rifsBalance.BalanceMap[MINUTES+OUTBOUND][0].Value, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
}
if len(cc.Timespans) != 1 || cc.Timespans[0].GetDuration() != 40*time.Second {
t.Error("Error truncating extra timespans: ", cc.Timespans[0].GetDuration())
if len(cc.Timespans) != 9 || cc.Timespans[0].GetDuration() != 40*time.Second {
for _, ts := range cc.Timespans {
t.Logf("%+v %+v", ts, ts.Increments[0])
}
t.Error("Error truncating extra timespans: ", len(cc.Timespans), cc.Timespans[0].GetDuration())
}
}
@@ -701,13 +704,13 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) {
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
CallDuration: 0,
RateInterval: &RateInterval{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}},
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
},
&TimeSpan{
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
CallDuration: 10 * time.Second,
RateInterval: &RateInterval{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}},
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
},
},
}
@@ -732,8 +735,7 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) {
if len(cc.Timespans) != 2 || cc.Timespans[0].GetDuration() != time.Minute || cc.Timespans[1].GetDuration() != 20*time.Second {
t.Error("Error truncating extra timespans: ", cc.Timespans)
}
}
*/
}*/
func TestDebitSMSBalance(t *testing.T) {
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}