EventCost - generic RatingMatchedFilters, TestNewEventCostFromCallCost

This commit is contained in:
DanB
2017-05-18 17:06:42 +02:00
parent b1b54b4b8f
commit 920f1c35df
2 changed files with 367 additions and 29 deletions

View File

@@ -24,10 +24,10 @@ import (
"github.com/cgrates/cgrates/utils"
)
type RatingFilters map[string]*RatingMatchedFilters // so we can define search methods
type RatingFilters map[string]RatingMatchedFilters // so we can define search methods
// GetWithSet attempts to retrieve the UUID of a matching data or create a new one
func (rfs RatingFilters) GetUUIDWithSet(rmf *RatingMatchedFilters) string {
func (rfs RatingFilters) GetUUIDWithSet(rmf RatingMatchedFilters) string {
for k, v := range rfs {
if v.Equals(rmf) {
return k
@@ -112,8 +112,8 @@ func NewEventCostFromCallCost(cc *CallCost, cgrID, runID string) (ec *EventCost)
}
for i, ts := range cc.Timespans {
cIl := &ChargingInterval{StartTime: ts.TimeStart, CompressFactor: ts.CompressFactor}
rf := &RatingMatchedFilters{Subject: ts.MatchedSubject, DestinationPrefix: ts.MatchedPrefix,
DestinationID: ts.MatchedDestId, RatingPlanID: ts.RatingPlanId}
rf := RatingMatchedFilters{"Subject": ts.MatchedSubject, "DestinationPrefix": ts.MatchedPrefix,
"DestinationID": ts.MatchedDestId, "RatingPlanID": ts.RatingPlanId}
cIl.RatingUUID = ec.ratingUUIDForRateInterval(ts.RateInterval, rf)
if len(ts.Increments) != 0 {
cIl.Increments = make([]*ChargingIncrement, len(ts.Increments))
@@ -177,7 +177,7 @@ type EventCost struct {
Timings ChargedTimings
}
func (ec *EventCost) ratingUUIDForRateInterval(ri *RateInterval, rf *RatingMatchedFilters) string {
func (ec *EventCost) ratingUUIDForRateInterval(ri *RateInterval, rf RatingMatchedFilters) string {
if ri == nil || ri.Rating == nil {
return ""
}
@@ -267,10 +267,10 @@ func (ec *EventCost) AsCallCost(ToR, Tenant, Direction, Category, Account, Subje
if cIl.RatingUUID != "" {
if ec.Rating[cIl.RatingUUID].RatingFiltersUUID != "" {
rfs := ec.RatingFilters[ec.Rating[cIl.RatingUUID].RatingFiltersUUID]
ts.MatchedSubject = rfs.Subject
ts.MatchedPrefix = rfs.DestinationPrefix
ts.MatchedDestId = rfs.DestinationID
ts.RatingPlanId = rfs.RatingPlanID
ts.MatchedSubject = rfs["Subject"].(string)
ts.MatchedPrefix = rfs["DestinationPrefix"].(string)
ts.MatchedDestId = rfs["DestinationID"].(string)
ts.RatingPlanId = rfs["RatingPlanID"].(string)
}
}
ts.RateInterval = ec.rateIntervalForRatingUUID(cIl.RatingUUID)
@@ -302,18 +302,16 @@ func (ec *EventCost) AsCallCost(ToR, Tenant, Direction, Category, Account, Subje
// ChargingInterval represents one interval out of Usage providing charging info
// eg: PEAK vs OFFPEAK
type ChargingInterval struct {
StartTime time.Time
IntervalDetailsUUID string // reference to CIntervDetails
RatingUUID string // reference to RatingUnit
Increments []*ChargingIncrement // specific increments applied to this interval
CompressFactor int
usage *time.Duration // cache usage computation for this interval
cost *float64 // cache cost calculation on this interval
StartTime time.Time
RatingUUID string // reference to RatingUnit
Increments []*ChargingIncrement // specific increments applied to this interval
CompressFactor int
usage *time.Duration // cache usage computation for this interval
cost *float64 // cache cost calculation on this interval
}
func (cIl *ChargingInterval) Equals(oCIl *ChargingInterval) (equals bool) {
if equals = cIl.StartTime.Equal(oCIl.StartTime) &&
cIl.IntervalDetailsUUID == oCIl.IntervalDetailsUUID &&
cIl.RatingUUID == oCIl.RatingUUID &&
len(cIl.Increments) == len(oCIl.Increments); !equals {
return
@@ -383,18 +381,17 @@ func (bc *BalanceCharge) Equals(oBC *BalanceCharge) bool {
bc.ExtraChargeUUID == oBC.ExtraChargeUUID
}
type RatingMatchedFilters struct {
Subject string // matched subject
DestinationPrefix string // matched destination prefix
DestinationID string // matched destinationID
RatingPlanID string // matched ratingPlanID
}
type RatingMatchedFilters map[string]interface{}
func (rf *RatingMatchedFilters) Equals(oRF *RatingMatchedFilters) bool {
return rf.Subject == oRF.Subject &&
rf.DestinationPrefix == oRF.DestinationPrefix &&
rf.DestinationID == oRF.DestinationID &&
rf.RatingPlanID == oRF.RatingPlanID
func (rf RatingMatchedFilters) Equals(oRF RatingMatchedFilters) (equals bool) {
equals = true
for k := range rf {
if rf[k] != oRF[k] {
equals = false
break
}
}
return
}
// ChargedTiming represents one timing attached to a charge
@@ -433,5 +430,6 @@ func (ru *RatingUnit) Equals(oRU *RatingUnit) bool {
ru.MaxCost == oRU.MaxCost &&
ru.MaxCostStrategy == oRU.MaxCostStrategy &&
ru.TimingUUID == oRU.TimingUUID &&
ru.RatesUUID == oRU.RatesUUID
ru.RatesUUID == oRU.RatesUUID &&
ru.RatingFiltersUUID == oRU.RatingFiltersUUID
}

340
engine/eventcost_test.go Normal file
View File

@@ -0,0 +1,340 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
func TestNewEventCostFromCallCost(t *testing.T) {
cc := &CallCost{
Direction: utils.META_OUT,
Category: "call",
Tenant: "cgrates.org",
Subject: "dan",
Account: "dan",
Destination: "+4986517174963",
TOR: utils.VOICE,
Cost: 0.85,
RatedUsage: 120.0,
Timespans: TimeSpans{
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
Cost: 0.25,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&Rate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Minute),
},
},
},
},
DurationIndex: time.Duration(1 * time.Minute),
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{ // ConnectFee
Cost: 0.1,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.META_DEFAULT,
Value: 9.9},
AccountID: "cgrates.org:dan",
},
CompressFactor: 1,
},
&Increment{ // First 30 seconds free
Duration: time.Duration(1 * time.Second),
Cost: 0,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{
UUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
ID: "free_mins",
Value: 0,
Consumed: 1.0,
TOR: utils.VOICE,
},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
&Increment{ // Minutes with special price
Duration: time.Duration(1 * time.Second),
Cost: 0.005,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{ // Minutes with special price
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "discounted_mins",
Value: 0,
Consumed: 1.0,
TOR: utils.VOICE,
RateInterval: &RateInterval{
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&Rate{
GroupIntervalStart: time.Duration(0),
Value: 0.005,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Second),
},
&Rate{
GroupIntervalStart: time.Duration(60 * time.Second),
Value: 0.005,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Second),
},
},
},
},
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.META_DEFAULT,
Value: 9.75},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
},
},
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 20, 21, 0, time.UTC),
Cost: 0.01,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&Rate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Minute),
},
},
},
},
DurationIndex: time.Duration(1 * time.Minute),
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{
Cost: 0.01,
Duration: time.Duration(1 * time.Second),
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.META_DEFAULT,
Value: 9.15},
AccountID: "cgrates.org:dan",
},
CompressFactor: 60,
},
},
},
},
}
eEC := &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.META_DEFAULT,
Cost: utils.Float64Pointer(0.85),
Usage: utils.DurationPointer(time.Duration(2 * time.Minute)),
Charges: []*ChargingInterval{
&ChargingInterval{
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
RatingUUID: "bebf80cf-cba5-4e36-89dc-86673cff8cc4",
Increments: []*ChargingIncrement{
&ChargingIncrement{
Usage: time.Duration(0),
Cost: 0.1,
BalanceChargeUUID: "716a278d-9ca5-451a-aa59-b6a43f4fb4ef",
CompressFactor: 1,
},
&ChargingIncrement{
Usage: time.Duration(1 * time.Second),
Cost: 0,
BalanceChargeUUID: "8ee1f8ee-5783-487b-87e3-cb1bb6fd8f9f",
CompressFactor: 30,
},
&ChargingIncrement{
Usage: time.Duration(1 * time.Second),
Cost: 0.005,
BalanceChargeUUID: "77c904d4-c579-4687-8c28-a1561e39dae2",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
&ChargingInterval{
StartTime: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
RatingUUID: "bebf80cf-cba5-4e36-89dc-86673cff8cc4",
Increments: []*ChargingIncrement{
&ChargingIncrement{
Usage: time.Duration(0),
Cost: 0.01,
BalanceChargeUUID: "79463f6e-d70f-41ac-9345-76bd21714759",
CompressFactor: 60,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"bebf80cf-cba5-4e36-89dc-86673cff8cc4": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingUUID: "3e4c7dd1-10f9-4fdc-b7df-8833724933dd",
RatesUUID: "5f04c792-5c79-4873-ba39-413342671595",
RatingFiltersUUID: "8fa45f23-5bb1-44ee-867c-ad09b2bae981",
},
"2b7333c0-479c-4e5d-8d72-d089e93b2b6a": &RatingUnit{
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingUUID: "3e4c7dd1-10f9-4fdc-b7df-8833724933dd",
RatesUUID: "3246cb23-ef2e-4080-ba5b-45300cbede3f",
RatingFiltersUUID: "8fa45f23-5bb1-44ee-867c-ad09b2bae981",
},
},
Accounting: Accounting{
"2afef931-eb94-46df-8fb4-3509954e771c": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"716a278d-9ca5-451a-aa59-b6a43f4fb4ef": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"77c904d4-c579-4687-8c28-a1561e39dae2": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
RatingUUID: "2b7333c0-479c-4e5d-8d72-d089e93b2b6a",
Units: 1,
ExtraChargeUUID: "2afef931-eb94-46df-8fb4-3509954e771c",
},
"79463f6e-d70f-41ac-9345-76bd21714759": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
},
"8ee1f8ee-5783-487b-87e3-cb1bb6fd8f9f": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
Units: 1,
ExtraChargeUUID: "*none",
},
},
RatingFilters: RatingFilters{
"8fa45f23-5bb1-44ee-867c-ad09b2bae981": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"3246cb23-ef2e-4080-ba5b-45300cbede3f": RateGroups{
&Rate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateIncrement: time.Duration(1 * time.Minute),
RateUnit: time.Duration(1 * time.Second)},
},
"5f04c792-5c79-4873-ba39-413342671595": RateGroups{
&Rate{
GroupIntervalStart: time.Duration(0),
Value: 0.005,
RateIncrement: time.Duration(1 * time.Second),
RateUnit: time.Duration(1 * time.Second)},
&Rate{
GroupIntervalStart: time.Duration(60 * time.Second),
Value: 0.005,
RateIncrement: time.Duration(1 * time.Second),
RateUnit: time.Duration(1 * time.Second)},
},
},
Timings: ChargedTimings{
"3e4c7dd1-10f9-4fdc-b7df-8833724933dd": &ChargedTiming{
StartTime: "00:00:00",
},
},
}
ec := NewEventCostFromCallCost(cc, "164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT)
if cost := ec.ComputeCost(); cost != cc.Cost {
t.Errorf("Expecting: %f, received: %f", cc.Cost, cost)
}
eUsage := time.Duration(int64(cc.RatedUsage * 1000000000))
if usage := ec.ComputeUsage(); usage != eUsage {
t.Errorf("Expecting: %v, received: %v", eUsage, usage)
}
if len(ec.Charges) != len(eEC.Charges) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
for i := range eEC.Charges {
if len(eEC.Charges[i].Increments) != len(ec.Charges[i].Increments) {
t.Errorf("At index %d, expecting: %+v, received: %+v", eEC.Charges[i].Increments, ec.Charges[i].Increments)
}
}
if len(ec.Rating) != len(eEC.Rating) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if len(ec.Accounting) != len(eEC.Accounting) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if len(ec.Rates) != len(eEC.Rates) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if len(ec.Timings) != len(eEC.Timings) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
}