From 6fb2ca37c24dff4f0b56eb47a5d9e3aa1d838a08 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 19 Dec 2013 18:30:48 +0200 Subject: [PATCH 1/2] better rates rounding --- config/config.go | 26 ++++++++++----------- config/config_test.go | 2 +- engine/calldesc.go | 10 ++++++-- engine/rateinterval.go | 5 ++-- engine/timespans.go | 50 +++++++++++++++++++++++++--------------- engine/timespans_test.go | 4 ++-- 6 files changed, 59 insertions(+), 38 deletions(-) diff --git a/config/config.go b/config/config.go index b7f0c2581..11451a73c 100644 --- a/config/config.go +++ b/config/config.go @@ -40,18 +40,18 @@ const ( // Holds system configuration, defaults are overwritten with values from config file if found type CGRConfig struct { - RatingDBType string - RatingDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. - RatingDBPort string // The port to bind to. - RatingDBName string // The name of the database to connect to. - RatingDBUser string // The user to sign in as. - RatingDBPass string // The user's password. - AccountDBType string - AccountDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. - AccountDBPort string // The port to bind to. - AccountDBName string // The name of the database to connect to. - AccountDBUser string // The user to sign in as. - AccountDBPass string // The user's password. + RatingDBType string + RatingDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. + RatingDBPort string // The port to bind to. + RatingDBName string // The name of the database to connect to. + RatingDBUser string // The user to sign in as. + RatingDBPass string // The user's password. + AccountDBType string + AccountDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. + AccountDBPort string // The port to bind to. + AccountDBName string // The name of the database to connect to. + AccountDBUser string // The user to sign in as. + AccountDBPass string // The user's password. StorDBType string // Should reflect the database type used to store logs StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. StorDBPort string // The port to bind to. @@ -121,7 +121,7 @@ func (self *CGRConfig) setDefaults() error { self.AccountDBType = REDIS self.AccountDBHost = "127.0.0.1" self.AccountDBPort = "6379" - self.AccountDBName = "10" + self.AccountDBName = "11" self.AccountDBUser = "" self.AccountDBPass = "" self.StorDBType = utils.MYSQL diff --git a/config/config_test.go b/config/config_test.go index 81ee6b4cd..d05f3b317 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -44,7 +44,7 @@ func TestDefaults(t *testing.T) { eCfg.AccountDBType = REDIS eCfg.AccountDBHost = "127.0.0.1" eCfg.AccountDBPort = "6379" - eCfg.AccountDBName = "10" + eCfg.AccountDBName = "11" eCfg.AccountDBUser = "" eCfg.AccountDBPass = "" eCfg.StorDBType = utils.MYSQL diff --git a/engine/calldesc.go b/engine/calldesc.go index 8ee7911a8..23a005e84 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -42,8 +42,8 @@ func init() { accountingStorage, _ = NewMapStorage() } else { //dataStorage, _ = NewMongoStorage(db_server, "27017", "cgrates_test", "", "") - dataStorage, _ = NewRedisStorage("127.0.0.1:6379", 11, "", utils.MSGPACK) - accountingStorage, _ = NewRedisStorage("127.0.0.1:6379", 12, "", utils.MSGPACK) + dataStorage, _ = NewRedisStorage("127.0.0.1:6379", 12, "", utils.MSGPACK) + accountingStorage, _ = NewRedisStorage("127.0.0.1:6379", 13, "", utils.MSGPACK) } storageLogger = dataStorage.(LogStorage) } @@ -496,6 +496,12 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { if cc.Cost != 0 || cc.ConnectFee != 0 { userBalance.debitCreditBalance(cc, true) } + cost := 0.0 + // re-calculate call cost after balances + for _, ts := range cc.Timespans { + cost += ts.getCost() + } + cc.Cost = cost } return } diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 1f4beda43..7d90248e1 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -20,12 +20,13 @@ package engine import ( "fmt" - "github.com/cgrates/cgrates/utils" "reflect" "sort" "strconv" "strings" "time" + + "github.com/cgrates/cgrates/utils" ) /* @@ -241,7 +242,7 @@ func (i *RateInterval) GetCost(duration, startSecond time.Duration) float64 { d := duration.Seconds() price /= rateUnit.Seconds() - return utils.Round(d*price, i.Rating.RoundingDecimals, i.Rating.RoundingMethod) + return d * price } // Gets the price for a the provided start second diff --git a/engine/timespans.go b/engine/timespans.go index 247e6ad9d..ada1bc46f 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -21,6 +21,7 @@ package engine import ( //"fmt" + "log" "time" "github.com/cgrates/cgrates/utils" @@ -186,17 +187,6 @@ func (ts *TimeSpan) Contains(t time.Time) bool { return t.After(ts.TimeStart) && t.Before(ts.TimeEnd) } -// Returns the cost of the timespan according to the relevant cost interval. -// It also sets the Cost field of this timespan (used for refund on session -// manager debit loop where the cost cannot be recalculated) -func (ts *TimeSpan) getCost() float64 { - if ts.RateInterval == nil { - return 0 - } - ts.Cost = ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart()) - return ts.Cost -} - /* 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 @@ -213,26 +203,50 @@ func (ts *TimeSpan) SetRateInterval(i *RateInterval) { } } +// Returns the cost of the timespan according to the relevant cost interval. +// It also sets the Cost field of this timespan (used for refund on session +// manager debit loop where the cost cannot be recalculated) +func (ts *TimeSpan) getCost() float64 { + if len(ts.Increments) == 0 { + if ts.RateInterval == nil { + return 0 + } + cost := ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart()) + ts.Cost = utils.Round(cost, ts.RateInterval.Rating.RoundingDecimals, ts.RateInterval.Rating.RoundingMethod) + return ts.Cost + } else { + cost := 0.0 + for _, inc := range ts.Increments { + cost += inc.Cost + log.Print(inc.Cost, cost) + } + return cost + } + return 0 +} + func (ts *TimeSpan) createIncrementsSlice() { if ts.RateInterval == nil { return } ts.Increments = make([]*Increment, 0) // create rated units series - rate, rateIncrement, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) - incrementCost := rate / rateUnit.Seconds() * rateIncrement.Seconds() - incrementCost = utils.Round(incrementCost, ts.RateInterval.Rating.RoundingDecimals, ts.RateInterval.Rating.RoundingMethod) - totalCost := 0.0 - for s := 0; s < int(ts.GetDuration()/rateIncrement); s++ { + _, rateIncrement, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) + // we will use the cost calculated cost and devide by nb of increments + // because ts cost is rounded + //incrementCost := rate / rateUnit.Seconds() * rateIncrement.Seconds() + nbIncrements := int(ts.GetDuration() / rateIncrement) + incrementCost := ts.getCost() / float64(nbIncrements) + for s := 0; s < nbIncrements; s++ { inc := &Increment{ Duration: rateIncrement, Cost: incrementCost, BalanceUuids: make([]string, 2), } ts.Increments = append(ts.Increments, inc) - totalCost += incrementCost } - ts.Cost = totalCost + // put the rounded cost back in timespan + ts.Cost = incrementCost * float64(nbIncrements) } // returns whether the timespan has all increments marked as paid and if not diff --git a/engine/timespans_test.go b/engine/timespans_test.go index 631aa57ed..288a12cb5 100644 --- a/engine/timespans_test.go +++ b/engine/timespans_test.go @@ -718,8 +718,8 @@ func TestTimespanCreateIncrements(t *testing.T) { if len(ts.Increments) != 3 { t.Error("Error creating increment slice: ", len(ts.Increments)) } - if len(ts.Increments) < 3 || ts.Increments[2].Cost != 20 { - t.Error("Wrong second slice: ", ts.Increments) + if len(ts.Increments) < 3 || ts.Increments[2].Cost != 20.066666666666666 { + t.Error("Wrong second slice: ", ts.Increments[2].Cost) } } From a74a201735650f79be44b640433d51443176d315 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 19 Dec 2013 18:44:58 +0200 Subject: [PATCH 2/2] seting increment cost to 0 for increments payed using free minutes --- cache2go/cache_test.go | 5 +++-- engine/balances.go | 2 ++ engine/calldesc.go | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cache2go/cache_test.go b/cache2go/cache_test.go index 1eb8cc068..9ef148de8 100644 --- a/cache2go/cache_test.go +++ b/cache2go/cache_test.go @@ -98,7 +98,7 @@ func TestXRemKey(t *testing.T) { } /* -This test sometimes fails on +These tests sometimes fails on drone.io func TestGetKeyAge(t *testing.T) { Cache("t1", "test") d, err := GetKeyAge("t1") @@ -106,7 +106,7 @@ func TestGetKeyAge(t *testing.T) { t.Error("Error getting cache key age: ", d) } } -*/ + func TestXGetKeyAge(t *testing.T) { a := &myStruct{data: "mama are mere"} @@ -116,6 +116,7 @@ func TestXGetKeyAge(t *testing.T) { t.Error("Error getting cache key age: ", d) } } +*/ func TestRemPrefixKey(t *testing.T) { Cache("x_t1", "test") diff --git a/engine/balances.go b/engine/balances.go index 1a7182e70..439b7caac 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -139,6 +139,7 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *UserBalance, moneyB b.Value -= amount increment.SetMinuteBalance(b.Uuid) increment.MinuteInfo = &MinuteInfo{cc.Destination, amount, 0} + increment.Cost = 0 increment.paid = true if count { ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) @@ -180,6 +181,7 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *UserBalance, moneyB b.Value -= amount newTs.Increments[0].SetMinuteBalance(b.Uuid) newTs.Increments[0].MinuteInfo = &MinuteInfo{cc.Destination, amount, 0} + newTs.Increments[0].Cost = 0 newTs.Increments[0].paid = true if count { ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) diff --git a/engine/calldesc.go b/engine/calldesc.go index 23a005e84..ecb32c9e6 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -499,7 +499,7 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { cost := 0.0 // re-calculate call cost after balances for _, ts := range cc.Timespans { - cost += ts.getCost() + cost += ts.getCost() // FIXME: floating point sum?? } cc.Cost = cost }