*generic balance used by all tors

fixes #250
This commit is contained in:
Radu Ioan Fericean
2015-10-30 17:03:54 +02:00
parent 362c6fa7c6
commit 88137b75db
7 changed files with 136 additions and 32 deletions

View File

@@ -39,7 +39,7 @@ func TestDfNewdfCgrJsonCfgFromReader(t *testing.T) {
func TestDfGeneralJsonCfg(t *testing.T) {
eCfg := &GeneralJsonCfg{
Http_skip_tls_verify: utils.BoolPointer(false),
Rounding_decimals: utils.IntPointer(10),
Rounding_decimals: utils.IntPointer(5),
Dbdata_encoding: utils.StringPointer("msgpack"),
Tpexport_dir: utils.StringPointer("/var/log/cgrates/tpe"),
Http_failed_dir: utils.StringPointer("/var/log/cgrates/http_failed"),

View File

@@ -52,8 +52,9 @@ type Account struct {
// User's available minutes for the specified destination
func (ub *Account) getCreditForPrefix(cd *CallDescriptor) (duration time.Duration, credit float64, balances BalanceChain) {
creditBalances := ub.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, ub.BalanceMap[utils.MONETARY], "")
unitBalances := ub.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, ub.BalanceMap[cd.TOR], "")
creditBalances := ub.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, utils.MONETARY, "")
unitBalances := ub.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, cd.TOR, "")
// gather all balances from shared groups
var extendedCreditBalances BalanceChain
for _, cb := range creditBalances {
@@ -182,7 +183,12 @@ func (ub *Account) enableDisableBalanceAction(a *Action) error {
return nil
}
func (ub *Account) getBalancesForPrefix(prefix, category string, direction string, balances BalanceChain, sharedGroup string) BalanceChain {
func (ub *Account) getBalancesForPrefix(prefix, category, direction, tor string, sharedGroup string) BalanceChain {
var balances BalanceChain
balances = append(balances, ub.BalanceMap[tor]...)
if tor != utils.MONETARY && tor != utils.GENERIC {
balances = append(balances, ub.BalanceMap[utils.GENERIC]...)
}
var usefulBalances BalanceChain
for _, b := range balances {
if b.Disabled {
@@ -235,7 +241,7 @@ func (ub *Account) getBalancesForPrefix(prefix, category string, direction strin
// like getBalancesForPrefix but expanding shared balances
func (account *Account) getAlldBalancesForPrefix(destination, category, direction, balanceType string) (bc BalanceChain) {
balances := account.getBalancesForPrefix(destination, category, direction, account.BalanceMap[balanceType], "")
balances := account.getBalancesForPrefix(destination, category, direction, balanceType, "")
for _, b := range balances {
if len(b.SharedGroups) > 0 {
for sgId := range b.SharedGroups {
@@ -615,8 +621,8 @@ func (ub *Account) GetSharedGroups() (groups []string) {
func (account *Account) GetUniqueSharedGroupMembers(cd *CallDescriptor) ([]string, error) {
var balances []*Balance
balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, account.BalanceMap[utils.MONETARY], "")...)
balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, account.BalanceMap[cd.TOR], "")...)
balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, utils.MONETARY, "")...)
balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, cd.TOR, "")...)
// gather all shared group ids
var sharedGroupIds []string
for _, b := range balances {

View File

@@ -1231,6 +1231,92 @@ func TestDebitGeneric(t *testing.T) {
}
}
func TestDebitGenericBalance(t *testing.T) {
cc := &CallCost{
Direction: utils.OUT,
Destination: "0723045326",
Timespans: []*TimeSpan{
&TimeSpan{
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 9, 24, 10, 48, 30, 0, time.UTC),
ratingInfo: &RatingInfo{},
DurationIndex: 0,
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1 * time.Second, RateUnit: time.Second}}}},
},
},
TOR: utils.VOICE,
}
cd := &CallDescriptor{
TimeStart: cc.Timespans[0].TimeStart,
TimeEnd: cc.Timespans[0].TimeEnd,
Direction: cc.Direction,
Destination: cc.Destination,
TOR: cc.TOR,
DurationIndex: cc.GetDuration(),
testCallcost: cc,
}
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
utils.GENERIC: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIds: utils.StringMap{"NAT": true}, Factor: ValueFactor{utils.VOICE: 60.0}}},
utils.MONETARY: BalanceChain{&Balance{Value: 21}},
}}
var err error
cc, err = rifsBalance.debitCreditBalance(cd, false, false, true)
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testm" {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
if rifsBalance.BalanceMap[utils.GENERIC][0].GetValue() != 99.4999 ||
rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 {
t.Logf("%+v", cc.Timespans[0].Increments[0])
t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue())
}
}
func TestDebitGenericBalanceWithRatingSubject(t *testing.T) {
cc := &CallCost{
Direction: utils.OUT,
Destination: "0723045326",
Timespans: []*TimeSpan{
&TimeSpan{
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 9, 24, 10, 48, 30, 0, time.UTC),
ratingInfo: &RatingInfo{},
DurationIndex: 0,
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 0, RateIncrement: time.Second, RateUnit: time.Second}}}},
},
},
TOR: utils.VOICE,
}
cd := &CallDescriptor{
TimeStart: cc.Timespans[0].TimeStart,
TimeEnd: cc.Timespans[0].TimeEnd,
Direction: cc.Direction,
Destination: cc.Destination,
TOR: cc.TOR,
DurationIndex: cc.GetDuration(),
testCallcost: cc,
}
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
utils.GENERIC: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIds: utils.StringMap{"NAT": true}, Factor: ValueFactor{utils.VOICE: 60.0}, RatingSubject: "free"}},
utils.MONETARY: BalanceChain{&Balance{Value: 21}},
}}
var err error
cc, err = rifsBalance.debitCreditBalance(cd, false, false, true)
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testm" {
t.Error("Error setting balance id to increment: ", cc.Timespans[0])
}
if rifsBalance.BalanceMap[utils.GENERIC][0].GetValue() != 99.4999 ||
rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 {
t.Logf("%+v", cc.Timespans[0].Increments[0])
t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue())
}
}
func TestDebitDataUnits(t *testing.T) {
cc := &CallCost{
Direction: utils.OUT,

View File

@@ -45,6 +45,7 @@ type Balance struct {
Timings []*RITiming
TimingIDs utils.StringMap
Disabled bool
Factor ValueFactor
precision int
account *Account // used to store ub reference for shared balances
dirty bool
@@ -319,8 +320,6 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
TimeEnd: cd.TimeEnd,
})
seconds := duration.Seconds()
amount := seconds
ts := cc.Timespans[0]
ts.RoundToDuration(duration)
ts.RateInterval = &RateInterval{
@@ -352,8 +351,10 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
//log.Printf("CC: %+v", ts)
for incIndex, inc := range ts.Increments {
//log.Printf("INCREMENET: %+v", inc)
if seconds == 1 {
amount = inc.Duration.Seconds()
amount := inc.Duration.Seconds()
if b.Factor != nil {
amount = utils.Round(amount/b.Factor.GetValue(cd.TOR), globalRoundingDecimals, utils.ROUNDING_UP)
}
if b.GetValue() >= amount {
b.SubstractValue(amount)
@@ -401,9 +402,11 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
maxCost, strategy := ts.RateInterval.GetMaxCost()
for incIndex, inc := range ts.Increments {
// debit minutes and money
seconds := inc.Duration.Seconds()
amount := inc.Duration.Seconds()
if b.Factor != nil {
amount = utils.Round(amount/b.Factor.GetValue(cd.TOR), globalRoundingDecimals, utils.ROUNDING_UP)
}
cost := inc.Cost
//log.Printf("INC: %+v", inc)
inc.paid = false
if strategy == utils.MAX_COST_DISCONNECT && cd.MaxCostSoFar >= maxCost {
// cat the entire current timespan
@@ -437,11 +440,11 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
break
}
}
if (cost == 0 || moneyBal != nil) && b.GetValue() >= seconds {
b.SubstractValue(seconds)
if (cost == 0 || moneyBal != nil) && b.GetValue() >= amount {
b.SubstractValue(amount)
inc.BalanceInfo.UnitBalanceUuid = b.Uuid
inc.BalanceInfo.AccountId = ub.Id
inc.UnitInfo = &UnitInfo{cc.Destination, seconds, cc.TOR}
inc.UnitInfo = &UnitInfo{cc.Destination, amount, cc.TOR}
if cost != 0 {
inc.BalanceInfo.MoneyBalanceUuid = moneyBal.Uuid
moneyBal.SubstractValue(cost)
@@ -449,7 +452,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
}
inc.paid = true
if count {
ub.countUnits(&Action{BalanceType: cc.TOR, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: seconds, DestinationIds: utils.StringMap{cc.Destination: true}}})
ub.countUnits(&Action{BalanceType: cc.TOR, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: amount, DestinationIds: utils.StringMap{cc.Destination: true}}})
if cost != 0 {
ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: cost, DestinationIds: utils.StringMap{cc.Destination: true}}})
}
@@ -678,3 +681,12 @@ func (bc BalanceChain) SaveDirtyBalances(acc *Account) {
}
}
}
type ValueFactor map[string]float64
func (f ValueFactor) GetValue(tor string) float64 {
if value, ok := f[tor]; ok {
return value
}
return 1.0
}

View File

@@ -817,12 +817,12 @@ func TestLoadActions(t *testing.T) {
ExtraParameters: "",
Weight: 10,
Balance: &Balance{
Uuid: as1[0].Balance.Uuid,
Directions: utils.NewStringMap(utils.OUT),
Value: 10,
Weight: 10,
TimingIDs: utils.StringMap{},
SharedGroups: utils.StringMap{},
Uuid: as1[0].Balance.Uuid,
Directions: utils.NewStringMap(utils.OUT),
Value: 10,
Weight: 10,
TimingIDs: utils.StringMap{},
SharedGroups: utils.StringMap{},
},
},
&Action{
@@ -840,7 +840,7 @@ func TestLoadActions(t *testing.T) {
RatingSubject: "test",
DestinationIds: utils.NewStringMap("NAT"),
TimingIDs: utils.StringMap{},
SharedGroups: utils.StringMap{},
SharedGroups: utils.StringMap{},
},
},
}
@@ -861,7 +861,7 @@ func TestLoadActions(t *testing.T) {
Uuid: as2[0].Balance.Uuid,
Value: 100,
Weight: 10,
SharedGroups: utils.NewStringMap("SG1"),
SharedGroups: utils.NewStringMap("SG1"),
TimingIDs: utils.StringMap{},
},
},
@@ -881,7 +881,7 @@ func TestLoadActions(t *testing.T) {
Directions: utils.StringMap{},
DestinationIds: utils.StringMap{},
TimingIDs: utils.StringMap{},
SharedGroups: utils.StringMap{},
SharedGroups: utils.StringMap{},
},
},
}
@@ -1014,8 +1014,8 @@ func TestLoadActionTriggers(t *testing.T) {
ThresholdValue: 10,
BalanceDestinationIds: utils.NewStringMap("GERMANY_O2"),
BalanceCategories: utils.StringMap{},
BalanceTimingTags: utils.StringMap{},
BalanceSharedGroups: utils.StringMap{},
BalanceTimingTags: utils.StringMap{},
BalanceSharedGroups: utils.StringMap{},
Weight: 10,
ActionsId: "SOME_1",
Executed: false,
@@ -1031,8 +1031,8 @@ func TestLoadActionTriggers(t *testing.T) {
ThresholdValue: 200,
BalanceDestinationIds: utils.NewStringMap("GERMANY"),
BalanceCategories: utils.StringMap{},
BalanceTimingTags: utils.StringMap{},
BalanceSharedGroups: utils.StringMap{},
BalanceTimingTags: utils.StringMap{},
BalanceSharedGroups: utils.StringMap{},
Weight: 10,
ActionsId: "SOME_2",
Executed: false,

View File

@@ -103,7 +103,7 @@ func (sg *SharedGroup) GetBalances(destination, category, direction, balanceType
}
}
//sg.members = append(sg.members, nUb)
sb := nUb.getBalancesForPrefix(destination, category, direction, nUb.BalanceMap[balanceType], sg.Id)
sb := nUb.getBalancesForPrefix(destination, category, direction, balanceType, sg.Id)
bc = append(bc, sb...)
}
/* } else {

View File

@@ -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.0666666667 {
if len(ts.Increments) < 3 || ts.Increments[2].Cost != 20.06667 {
t.Error("Wrong second slice: ", ts.Increments[2].Cost)
}
}