mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
better rounding in callcost
This commit is contained in:
@@ -153,13 +153,14 @@ func (cc *CallCost) AsJSON() string {
|
||||
return string(ccJson)
|
||||
}
|
||||
|
||||
func (cc *CallCost) UpdateCost() {
|
||||
func (cc *CallCost) updateCost() {
|
||||
cost := 0.0
|
||||
if cc.deductConnectFee { // add back the connectFee
|
||||
cost += cc.GetConnectFee()
|
||||
}
|
||||
for _, ts := range cc.Timespans {
|
||||
cost += ts.getCost()
|
||||
ts.Cost = ts.calculateCost()
|
||||
cost += ts.Cost
|
||||
cost = utils.Round(cost, globalRoundingDecimals, utils.ROUNDING_MIDDLE) // just get rid of the extra decimals
|
||||
}
|
||||
cc.Cost = cost
|
||||
|
||||
@@ -450,7 +450,8 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
// handle max cost
|
||||
maxCost, strategy := ts.RateInterval.GetMaxCost()
|
||||
|
||||
cost += ts.getCost()
|
||||
ts.Cost = ts.calculateCost()
|
||||
cost += ts.Cost
|
||||
cd.MaxCostSoFar += cost
|
||||
//log.Print("Before: ", cost)
|
||||
if strategy != "" && maxCost > 0 {
|
||||
@@ -496,7 +497,7 @@ func (cd *CallDescriptor) getCost() (*CallCost, error) {
|
||||
if cd.LoopIndex == 0 && i == 0 && ts.RateInterval != nil {
|
||||
cost += ts.RateInterval.Rating.ConnectFee
|
||||
}
|
||||
cost += ts.getCost()
|
||||
cost += ts.calculateCost()
|
||||
}
|
||||
|
||||
//startIndex := len(fmt.Sprintf("%s:%s:%s:", cd.Direction, cd.Tenant, cd.Category))
|
||||
@@ -636,7 +637,7 @@ func (cd *CallDescriptor) debit(account *Account, dryRun bool, goNegative bool)
|
||||
utils.Logger.Err(fmt.Sprintf("<Rater> Error getting cost for account key <%s>: %s", cd.GetAccountKey(), err.Error()))
|
||||
return nil, err
|
||||
}
|
||||
cc.UpdateCost()
|
||||
cc.updateCost()
|
||||
cc.Timespans.Compress()
|
||||
//log.Printf("OUT CC: ", cc)
|
||||
return
|
||||
|
||||
@@ -576,10 +576,43 @@ func TestGetCostRoundingIssue(t *testing.T) {
|
||||
cc, err := cd.GetCost()
|
||||
expected := 0.17
|
||||
if cc.Cost != expected || err != nil {
|
||||
t.Log(utils.ToIJSON(cc))
|
||||
t.Errorf("Expected %v was %+v", expected, cc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCostMaxDebitRoundingIssue(t *testing.T) {
|
||||
ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT")
|
||||
for _, at := range ap {
|
||||
at.Execute()
|
||||
}
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "dy",
|
||||
Account: "dy",
|
||||
Destination: "0723123113",
|
||||
TimeStart: time.Date(2015, 10, 26, 13, 29, 27, 0, time.UTC),
|
||||
TimeEnd: time.Date(2015, 10, 26, 13, 29, 51, 0, time.UTC),
|
||||
MaxCostSoFar: 0,
|
||||
}
|
||||
acc, err := accountingStorage.GetAccount("cgrates.org:dy")
|
||||
if err != nil || acc.BalanceMap[utils.MONETARY][0].Value != 1 {
|
||||
t.Errorf("Error getting account: %+v (%v)", utils.ToIJSON(acc), err)
|
||||
}
|
||||
cc, err := cd.MaxDebit()
|
||||
expected := 0.39
|
||||
if cc.Cost != expected || err != nil {
|
||||
t.Log(utils.ToIJSON(cc))
|
||||
t.Errorf("Expected %v was %+v", expected, cc)
|
||||
}
|
||||
acc, err = accountingStorage.GetAccount("cgrates.org:dy")
|
||||
if err != nil || acc.BalanceMap[utils.MONETARY][0].Value != 1-expected {
|
||||
t.Errorf("Error getting account: %+v (%v)", utils.ToIJSON(acc), err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxSessionTimeWithMaxCostFree(t *testing.T) {
|
||||
ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT")
|
||||
for _, at := range ap {
|
||||
|
||||
@@ -197,6 +197,7 @@ CDRST2_WARN_ACD,,*min_acd,3,true,0,,,,,,,,,,,,5,CDRST_WARN_HTTP,10
|
||||
vdf,minitsboy,MORE_MINUTES,STANDARD_TRIGGER,,
|
||||
cgrates.org,12345,TOPUP10_AT,STANDARD_TRIGGERS,,
|
||||
cgrates.org,123456,TOPUP10_AT,STANDARD_TRIGGERS,,
|
||||
cgrates.org,dy,TOPUP10_AT,STANDARD_TRIGGERS,,
|
||||
cgrates.org,remo,TOPUP10_AT,,,
|
||||
vdf,empty0,TOPUP_SHARED0_AT,,,
|
||||
vdf,empty10,TOPUP_SHARED10_AT,,,
|
||||
@@ -1043,7 +1044,7 @@ func TestLoadActionTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadAccountActions(t *testing.T) {
|
||||
if len(csvr.accountActions) != 10 {
|
||||
if len(csvr.accountActions) != 11 {
|
||||
t.Error("Failed to load account actions: ", len(csvr.accountActions))
|
||||
}
|
||||
aa := csvr.accountActions["vdf:minitsboy"]
|
||||
|
||||
@@ -318,7 +318,6 @@ func (i *RateInterval) GetCost(duration, startSecond time.Duration) float64 {
|
||||
GetRateParameters(startSecond)
|
||||
price /= rateUnit.Seconds()
|
||||
d := duration.Seconds()
|
||||
|
||||
return d * price
|
||||
}
|
||||
|
||||
|
||||
@@ -254,21 +254,15 @@ func (ts *TimeSpan) SetRateInterval(interval *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 {
|
||||
func (ts *TimeSpan) calculateCost() float64 {
|
||||
if ts.Increments.Length() == 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
|
||||
return ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart())
|
||||
} else {
|
||||
cost := ts.Increments.GetTotalCost()
|
||||
if ts.RateInterval != nil && ts.RateInterval.Rating != nil {
|
||||
return utils.Round(cost, ts.RateInterval.Rating.RoundingDecimals, ts.RateInterval.Rating.RoundingMethod)
|
||||
} else {
|
||||
return utils.Round(cost, globalRoundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
}
|
||||
return utils.Round(cost, globalRoundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,8 +285,8 @@ func (ts *TimeSpan) createIncrementsSlice() {
|
||||
// because ts cost is rounded
|
||||
//incrementCost := rate / rateUnit.Seconds() * rateIncrement.Seconds()
|
||||
nbIncrements := int(ts.GetDuration() / rateIncrement)
|
||||
incrementCost := ts.getCost() / float64(nbIncrements)
|
||||
incrementCost = utils.Round(incrementCost, globalRoundingDecimals, utils.ROUNDING_MIDDLE) // just get rid of the extra decimals
|
||||
incrementCost := ts.calculateCost() / float64(nbIncrements)
|
||||
incrementCost = utils.Round(incrementCost, ts.RateInterval.Rating.RoundingDecimals, ts.RateInterval.Rating.RoundingMethod)
|
||||
for s := 0; s < nbIncrements; s++ {
|
||||
inc := &Increment{
|
||||
Duration: rateIncrement,
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestTimespanGetCost(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC)
|
||||
ts1 := TimeSpan{TimeStart: t1, TimeEnd: t2}
|
||||
if ts1.getCost() != 0 {
|
||||
if ts1.calculateCost() != 0 {
|
||||
t.Error("No interval and still kicking")
|
||||
}
|
||||
ts1.SetRateInterval(
|
||||
@@ -223,12 +223,12 @@ func TestTimespanGetCost(t *testing.T) {
|
||||
Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 1 * time.Second}}},
|
||||
},
|
||||
)
|
||||
if ts1.getCost() != 600 {
|
||||
if ts1.calculateCost() != 600 {
|
||||
t.Error("Expected 10 got ", ts1.Cost)
|
||||
}
|
||||
ts1.RateInterval = nil
|
||||
ts1.SetRateInterval(&RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 60 * time.Second}}}})
|
||||
if ts1.getCost() != 10 {
|
||||
if ts1.calculateCost() != 10 {
|
||||
t.Error("Expected 6000 got ", ts1.Cost)
|
||||
}
|
||||
}
|
||||
@@ -239,8 +239,8 @@ func TestTimespanGetCostIntervals(t *testing.T) {
|
||||
for i := 0; i < 11; i++ {
|
||||
ts.Increments[i] = &Increment{Cost: 0.02}
|
||||
}
|
||||
if ts.getCost() != 0.22 {
|
||||
t.Error("Error caclulating timespan cost: ", ts.getCost())
|
||||
if ts.calculateCost() != 0.22 {
|
||||
t.Error("Error caclulating timespan cost: ", ts.calculateCost())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +742,7 @@ 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.06667 {
|
||||
if len(ts.Increments) < 3 || ts.Increments[2].Cost != 20.07 {
|
||||
t.Error("Wrong second slice: ", ts.Increments[2].Cost)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +233,6 @@ func (s *Session) SaveOperations() {
|
||||
firstCC.Merge(cc)
|
||||
//utils.Logger.Debug(fmt.Sprintf("AFTER MERGE: %s", utils.ToJSON(firstCC)))
|
||||
}
|
||||
// make sure we have rounded timespans final cost
|
||||
firstCC.UpdateCost()
|
||||
|
||||
var reply string
|
||||
err := s.sessionManager.CdrSrv().LogCallCost(&engine.CallCostLog{
|
||||
|
||||
Reference in New Issue
Block a user