diff --git a/engine/account.go b/engine/account.go
index 7784208f3..0130f1fb7 100644
--- a/engine/account.go
+++ b/engine/account.go
@@ -22,7 +22,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "log"
"time"
"github.com/cgrates/cgrates/cache2go"
@@ -258,6 +257,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error {
return err
}
}
+ ub.InitCounters()
ub.ExecuteActionTriggers(nil)
return nil
}
@@ -588,22 +588,27 @@ func (acc *Account) ExecuteActionTriggers(a *Action) {
// the next reset (see RESET_TRIGGERS action type)
continue
}
-
if !at.Match(a) {
continue
}
if strings.Contains(at.ThresholdType, "counter") {
- for _, uc := range acc.UnitCounters {
- if uc.BalanceType == at.Balance.GetType() &&
- strings.Contains(at.ThresholdType, uc.CounterType[1:]) {
- for _, b := range uc.Balances {
- if strings.HasPrefix(at.ThresholdType, "*max") {
- if b.MatchActionTrigger(at) && b.GetValue() >= at.ThresholdValue {
- at.Execute(acc, nil)
- }
- } else { //MIN
- if b.MatchActionTrigger(at) && b.GetValue() <= at.ThresholdValue {
- at.Execute(acc, nil)
+ if (at.Balance.ID == nil || *at.Balance.ID != "") && at.UniqueID != "" {
+ at.Balance.ID = utils.StringPointer(at.UniqueID)
+ }
+ for _, counters := range acc.UnitCounters {
+ for _, uc := range counters {
+ if strings.Contains(at.ThresholdType, uc.CounterType[1:]) {
+ for _, c := range uc.Counters {
+ //log.Print("C: ", utils.ToJSON(c))
+ if strings.HasPrefix(at.ThresholdType, "*max") {
+ if c.Filter.Equal(at.Balance) && c.Value >= at.ThresholdValue {
+ //log.Print("HERE")
+ at.Execute(acc, nil)
+ }
+ } else { //MIN
+ if c.Filter.Equal(at.Balance) && c.Value <= at.ThresholdValue {
+ at.Execute(acc, nil)
+ }
}
}
}
@@ -643,7 +648,7 @@ func (acc *Account) ResetActionTriggers(a *Action) {
}
at.Executed = false
}
- acc.ExecuteActionTriggers(a)
+ acc.ExecuteActionTriggers(a) //will trigger infinite loop when executed from ExecuteActionTriggers
}
// Sets/Unsets recurrent flag for action triggers
@@ -665,9 +670,10 @@ func (acc *Account) countUnits(amount float64, kind string, cc *CallCost, b *Bal
// Create counters for all triggered actions
func (acc *Account) InitCounters() {
oldUcs := acc.UnitCounters
- acc.UnitCounters = nil
+ acc.UnitCounters = make(UnitCounters)
ucTempMap := make(map[string]*UnitCounter)
for _, at := range acc.ActionTriggers {
+ //log.Print("AT: ", utils.ToJSON(at))
if !strings.Contains(at.ThresholdType, "counter") {
continue
}
@@ -675,28 +681,36 @@ func (acc *Account) InitCounters() {
if strings.Contains(at.ThresholdType, "balance") {
ct = utils.COUNTER_BALANCE
}
- log.Print(at.Balance.GetType() + ct)
uc, exists := ucTempMap[at.Balance.GetType()+ct]
+ //log.Print("CT: ", at.Balance.GetType()+ct)
if !exists {
- log.Print("HERE!")
uc = &UnitCounter{
- BalanceType: at.Balance.GetType(),
CounterType: ct,
}
ucTempMap[at.Balance.GetType()+ct] = uc
- uc.Balances = BalanceChain{}
- acc.UnitCounters = append(acc.UnitCounters, uc)
+ uc.Counters = make(CounterFilters, 0)
+ acc.UnitCounters[at.Balance.GetType()] = append(acc.UnitCounters[at.Balance.GetType()], uc)
}
- b := at.Balance.CreateBalance()
- if !uc.Balances.HasBalance(b) {
- uc.Balances = append(uc.Balances, b)
+ c := &CounterFilter{Filter: at.Balance}
+ if (c.Filter.ID == nil || *c.Filter.ID == "") && at.UniqueID != "" {
+ c.Filter.ID = utils.StringPointer(at.UniqueID)
+ }
+ //log.Print("C: ", utils.ToJSON(c))
+ if !uc.Counters.HasCounter(c) {
+ uc.Counters = append(uc.Counters, c)
}
}
// copy old counter values
- for _, uc := range acc.UnitCounters {
- for _, oldUc := range oldUcs {
- if uc.CopyCounterValues(oldUc) {
- break
+ for key, counters := range acc.UnitCounters {
+ oldCounters, found := oldUcs[key]
+ if !found {
+ continue
+ }
+ for _, uc := range counters {
+ for _, oldUc := range oldCounters {
+ if uc.CopyCounterValues(oldUc) {
+ break
+ }
}
}
}
@@ -908,30 +922,32 @@ func (acc *Account) AsOldStructure() interface{} {
AllowNegative: acc.AllowNegative,
Disabled: acc.Disabled,
}
- for i, uc := range acc.UnitCounters {
- if uc == nil {
- continue
- }
- result.UnitCounters[i] = &UnitsCounter{
- BalanceType: uc.BalanceType,
- Balances: make(BalanceChain, len(uc.Balances)),
- }
- if len(uc.Balances) > 0 {
- result.UnitCounters[i].Direction = uc.Balances[0].Directions.String()
- for j, b := range uc.Balances {
- result.UnitCounters[i].Balances[j] = &Balance{
- Uuid: b.Uuid,
- Id: b.Id,
- Value: b.Value,
- ExpirationDate: b.ExpirationDate,
- Weight: b.Weight,
- DestinationIds: b.DestinationIds.String(),
- RatingSubject: b.RatingSubject,
- Category: b.Categories.String(),
- SharedGroup: b.SharedGroups.String(),
- Timings: b.Timings,
- TimingIDs: b.TimingIDs.String(),
- Disabled: b.Disabled,
+ for balanceType, counters := range acc.UnitCounters {
+ for i, uc := range counters {
+ if uc == nil {
+ continue
+ }
+ result.UnitCounters[i] = &UnitsCounter{
+ BalanceType: balanceType,
+ Balances: make(BalanceChain, len(uc.Counters)),
+ }
+ if len(uc.Counters) > 0 {
+ result.UnitCounters[i].Direction = (*uc.Counters[0].Filter.Directions).String()
+ for j, c := range uc.Counters {
+ result.UnitCounters[i].Balances[j] = &Balance{
+ Uuid: c.Filter.GetUuid(),
+ Id: c.Filter.GetID(),
+ Value: c.Filter.GetValue(),
+ ExpirationDate: c.Filter.GetExpirationDate(),
+ Weight: c.Filter.GetWeight(),
+ DestinationIds: c.Filter.GetDestinationIDs().String(),
+ RatingSubject: c.Filter.GetRatingSubject(),
+ Category: c.Filter.GetCategories().String(),
+ SharedGroup: c.Filter.GetSharedGroups().String(),
+ Timings: c.Filter.Timings,
+ TimingIDs: c.Filter.GetTimingIDs().String(),
+ Disabled: c.Filter.GetDisabled(),
+ }
}
}
}
diff --git a/engine/account_test.go b/engine/account_test.go
index ae3dabd5e..7def0cc0b 100644
--- a/engine/account_test.go
+++ b/engine/account_test.go
@@ -19,7 +19,6 @@ along with this program. If not, see
package engine
import (
- "log"
"testing"
"time"
@@ -817,12 +816,12 @@ func TestAccountdebitBalance(t *testing.T) {
newMb := &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Weight: utils.Float64Pointer(20),
- DestinationIds: utils.StringMapPointer(utils.StringMap{"NEW": true}),
+ DestinationIDs: utils.StringMapPointer(utils.StringMap{"NEW": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
a := &Action{Balance: newMb}
ub.debitBalanceAction(a, false)
- if len(ub.BalanceMap[utils.VOICE]) != 3 || !ub.BalanceMap[utils.VOICE][2].DestinationIds.Equal(*newMb.DestinationIds) {
+ if len(ub.BalanceMap[utils.VOICE]) != 3 || !ub.BalanceMap[utils.VOICE][2].DestinationIds.Equal(*newMb.DestinationIDs) {
t.Errorf("Error adding minute bucket! %d %+v %+v", len(ub.BalanceMap[utils.VOICE]), ub.BalanceMap[utils.VOICE][2], newMb)
}
}
@@ -860,7 +859,7 @@ func TestAccountdebitBalanceExists(t *testing.T) {
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
Weight: utils.Float64Pointer(20),
- DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
+ DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
a := &Action{Balance: newMb}
@@ -886,19 +885,19 @@ func TestAccountAddMinutBucketEmpty(t *testing.T) {
mb1 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
- DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
+ DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb2 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
- DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
+ DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb3 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
- DestinationIds: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
+ DestinationIDs: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
ub := &Account{}
@@ -923,7 +922,7 @@ func TestAccountExecuteTriggeredActions(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.StringMap{utils.OUT: true}}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.StringMap{utils.OUT: true})}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
@@ -947,7 +946,7 @@ func TestAccountExecuteTriggeredActionsBalance(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 10, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}}, &Balance{Directions: utils.NewStringMap(utils.OUT), Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, Value: 1.0}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
ub.countUnits(1, utils.MONETARY, nil, nil)
@@ -960,14 +959,14 @@ func TestAccountExecuteTriggeredActionsOrder(t *testing.T) {
ub := &Account{
Id: "TEST_UB_OREDER",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
- ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Type: utils.StringPointer(utils.MONETARY)}}}}}},
+ ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.BalanceMap[utils.MONETARY]) != 1 || ub.BalanceMap[utils.MONETARY][0].GetValue() != 10 {
- t.Errorf("Error executing triggered actions in order %v BAL: %+v", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.MONETARY][1])
+ t.Errorf("Error executing triggered actions in order %v", ub.BalanceMap[utils.MONETARY][0].GetValue())
}
}
@@ -980,24 +979,22 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) {
&ActionTrigger{UniqueID: "week_trigger", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"},
},
}
- log.Print("==============")
ub.InitCounters()
- log.Print("==============")
- if len(ub.UnitCounters) != 1 || len(ub.UnitCounters[0].Balances) != 2 {
- log.Print("Error initializing counters: ", ub.UnitCounters[0].Balances[0])
+ if len(ub.UnitCounters) != 1 || len(ub.UnitCounters[utils.MONETARY][0].Counters) != 2 {
+ t.Error("Error initializing counters: ", ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if ub.UnitCounters[0].Balances[0].Value != 1 ||
- ub.UnitCounters[0].Balances[1].Value != 1 {
- t.Error("Error incrementing both counters", ub.UnitCounters[0].Balances[0].Value, ub.UnitCounters[0].Balances[1].Value)
+ if ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 1 ||
+ ub.UnitCounters[utils.MONETARY][0].Counters[1].Value != 1 {
+ t.Error("Error incrementing both counters", ub.UnitCounters[utils.MONETARY][0].Counters[0].Value, ub.UnitCounters[utils.MONETARY][0].Counters[1].Value)
}
// we can reset them
- resetCountersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("day_trigger")}}, nil)
- if ub.UnitCounters[0].Balances[0].Value != 0 ||
- ub.UnitCounters[0].Balances[1].Value != 1 {
- t.Error("Error reseting both counters", ub.UnitCounters[0].Balances[0].Value, ub.UnitCounters[0].Balances[1].Value)
+ resetCountersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("day_trigger")}}, nil)
+ if ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 0 ||
+ ub.UnitCounters[utils.MONETARY][0].Counters[1].Value != 1 {
+ t.Error("Error reseting both counters", ub.UnitCounters[utils.MONETARY][0].Counters[0].Value, ub.UnitCounters[utils.MONETARY][0].Counters[1].Value)
}
}
@@ -1087,45 +1084,45 @@ func TestCleanExpired(t *testing.T) {
}
func TestAccountUnitCounting(t *testing.T) {
- ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0}}}}}
+ ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
}
func TestAccountUnitCountingOutbound(t *testing.T) {
- ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: utils.NewStringMap(utils.OUT)}}}}}
+ ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 30 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 30 {
t.Error("Error counting units")
}
}
func TestAccountUnitCountingOutboundInbound(t *testing.T) {
- ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: utils.NewStringMap(utils.OUT)}}}}}
+ ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
- t.Errorf("Error counting units: %+v", ub.UnitCounters[0].Balances[0])
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
+ t.Errorf("Error counting units: %+v", ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
- if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.IN}, nil)
- if len(ub.UnitCounters) != 1 || (ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20) {
+ if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
}
@@ -1654,15 +1651,18 @@ func TestAccountInitCounters(t *testing.T) {
},
}
a.InitCounters()
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- len(a.UnitCounters[1].Balances) != 1 ||
- len(a.UnitCounters[2].Balances) != 1 ||
- len(a.UnitCounters[3].Balances) != 1 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ len(a.UnitCounters[utils.VOICE][0].Counters) != 1 ||
+ len(a.UnitCounters[utils.VOICE][1].Counters) != 1 ||
+ len(a.UnitCounters[utils.SMS][0].Counters) != 1 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, c := range uc.Counters {
+ t.Logf("B: %+v", c)
+ }
}
}
t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters))
@@ -1730,15 +1730,18 @@ func TestAccountDoubleInitCounters(t *testing.T) {
}
a.InitCounters()
a.InitCounters()
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- len(a.UnitCounters[1].Balances) != 1 ||
- len(a.UnitCounters[2].Balances) != 1 ||
- len(a.UnitCounters[3].Balances) != 1 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ len(a.UnitCounters[utils.VOICE][0].Counters) != 1 ||
+ len(a.UnitCounters[utils.VOICE][1].Counters) != 1 ||
+ len(a.UnitCounters[utils.SMS][0].Counters) != 1 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, c := range uc.Counters {
+ t.Logf("B: %+v", c)
+ }
}
}
t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters))
diff --git a/engine/action.go b/engine/action.go
index ce4ec1a09..7dde51af3 100644
--- a/engine/action.go
+++ b/engine/action.go
@@ -48,134 +48,6 @@ type Action struct {
Balance *BalanceFilter
}
-type BalanceFilter struct {
- Uuid *string
- Id *string
- Type *string
- Value *float64
- Directions *utils.StringMap
- ExpirationDate *time.Time
- Weight *float64
- DestinationIds *utils.StringMap
- RatingSubject *string
- Categories *utils.StringMap
- SharedGroups *utils.StringMap
- TimingIDs *utils.StringMap
- Timings []*RITiming
- Disabled *bool
- Factor *ValueFactor
- Blocker *bool
-}
-
-func (bp *BalanceFilter) CreateBalance() *Balance {
- b := &Balance{}
- if bp.Uuid != nil {
- b.Uuid = *bp.Uuid
- }
- if bp.Id != nil {
- b.Id = *bp.Id
- }
- if bp.Value != nil {
- b.Value = *bp.Value
- }
- if bp.Directions != nil {
- b.Directions = *bp.Directions
- }
- if bp.ExpirationDate != nil {
- b.ExpirationDate = *bp.ExpirationDate
- }
- if bp.Weight != nil {
- b.Weight = *bp.Weight
- }
- if bp.DestinationIds != nil {
- b.DestinationIds = *bp.DestinationIds
- }
- if bp.RatingSubject != nil {
- b.RatingSubject = *bp.RatingSubject
- }
- if bp.Categories != nil {
- b.Categories = *bp.Categories
- }
- if bp.SharedGroups != nil {
- b.SharedGroups = *bp.SharedGroups
- }
- if bp.TimingIDs != nil {
- b.TimingIDs = *bp.TimingIDs
- }
- if bp.Disabled != nil {
- b.Disabled = *bp.Disabled
- }
- if bp.Factor != nil {
- b.Factor = *bp.Factor
- }
- if bp.Blocker != nil {
- b.Blocker = *bp.Blocker
- }
- return b.Clone()
-}
-
-func (bp *BalanceFilter) LoadFromBalance(b *Balance) {
- if b.Uuid != "" {
- bp.Uuid = &b.Uuid
- }
- if b.Id != "" {
- bp.Id = &b.Id
- }
- if b.Value != 0 {
- bp.Value = &b.Value
- }
- if len(b.Directions) != 0 {
- bp.Directions = &b.Directions
- }
- if !b.ExpirationDate.IsZero() {
- bp.ExpirationDate = &b.ExpirationDate
- }
- if b.Weight != 0 {
- bp.Weight = &b.Weight
- }
- if len(b.DestinationIds) != 0 {
- bp.DestinationIds = &b.DestinationIds
- }
- if b.RatingSubject != "" {
- bp.RatingSubject = &b.RatingSubject
- }
- if len(b.Categories) != 0 {
- bp.Categories = &b.Categories
- }
- if len(b.SharedGroups) != 0 {
- bp.SharedGroups = &b.SharedGroups
- }
- if len(b.TimingIDs) != 0 {
- bp.TimingIDs = &b.TimingIDs
- }
- if len(b.Factor) != 0 {
- bp.Factor = &b.Factor
- }
- bp.Disabled = &b.Disabled
- bp.Blocker = &b.Blocker
-}
-
-func (bp *BalanceFilter) GetType() string {
- if bp.Type == nil {
- return ""
- }
- return *bp.Type
-}
-
-func (bp *BalanceFilter) GetValue() float64 {
- if bp.Value == nil {
- return 0.0
- }
- return *bp.Value
-}
-
-func (bp *BalanceFilter) SetValue(v float64) {
- if bp.Value == nil {
- bp.Value = new(float64)
- }
- *bp.Value = v
-}
-
const (
LOG = "*log"
RESET_TRIGGERS = "*reset_triggers"
@@ -301,7 +173,7 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action)
case "AccountID":
parsedValue += rsrFld.ParseValue(acnt.Id)
case "Directions":
- parsedValue += rsrFld.ParseValue(action.Balance.Directions.String())
+ parsedValue += rsrFld.ParseValue(b.Directions.String())
case utils.TENANT:
parsedValue += rsrFld.ParseValue(dta.Tenant)
case utils.ACCOUNT:
diff --git a/engine/action_plan.go b/engine/action_plan.go
index 0a9283d25..a9081b90a 100644
--- a/engine/action_plan.go
+++ b/engine/action_plan.go
@@ -307,7 +307,7 @@ func (at *ActionTiming) Execute() (err error) {
continue // disabled acocunts are not removed from action plan
//return 0, fmt.Errorf("Account %s is disabled", accID)
}
- if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) && parseErr == nil && !expDate.IsZero() {
+ if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.HasExpirationDate()) && parseErr == nil && !expDate.IsZero() {
a.Balance.ExpirationDate = &time.Time{}
*a.Balance.ExpirationDate = expDate
}
@@ -337,8 +337,7 @@ func (at *ActionTiming) Execute() (err error) {
}
if len(at.accountIDs) == 0 { // action timing executing without accounts
for _, a := range aac {
-
- if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) &&
+ if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.HasExpirationDate()) &&
parseErr == nil && !expDate.IsZero() {
a.Balance.ExpirationDate = &time.Time{}
*a.Balance.ExpirationDate = expDate
diff --git a/engine/action_trigger.go b/engine/action_trigger.go
index 90e42099d..afca42939 100644
--- a/engine/action_trigger.go
+++ b/engine/action_trigger.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package engine
import (
+ "encoding/json"
"fmt"
"sort"
"time"
@@ -112,10 +113,37 @@ func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err erro
// returns true if the field of the action timing are equeal to the non empty
// fields of the action
func (at *ActionTrigger) Match(a *Action) bool {
- if a == nil {
+ if a == nil || a.Balance == nil {
return true
}
- return at.Balance.CreateBalance().MatchFilter(a.Balance, false)
+ if a.Balance.Type != nil && a.Balance.GetType() != at.Balance.GetType() {
+ return false
+ }
+ var thresholdType bool
+ if a.ExtraParameters != "" {
+ t := struct {
+ GroupID string
+ UniqueID string
+ ThresholdType string
+ }{}
+ json.Unmarshal([]byte(a.ExtraParameters), &t)
+ // check Ids first
+ if t.GroupID != "" {
+ return at.ID == t.GroupID
+ }
+ if t.UniqueID != "" {
+ return at.UniqueID == t.UniqueID
+ }
+ thresholdType = t.ThresholdType == "" || at.ThresholdType == t.ThresholdType
+ }
+
+ return thresholdType && at.Balance.CreateBalance().MatchFilter(a.Balance, false)
+}
+
+func (at *ActionTrigger) CreateBalance() *Balance {
+ b := at.Balance.CreateBalance()
+ b.Id = at.UniqueID
+ return b
}
// makes a shallow copy of the receiver
diff --git a/engine/actions_test.go b/engine/actions_test.go
index 9917759da..af03aa6be 100644
--- a/engine/actions_test.go
+++ b/engine/actions_test.go
@@ -613,7 +613,7 @@ func TestActionTriggerMatchSomeFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_BALANCE, 2)}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%s"}`, utils.TRIGGER_MAX_BALANCE_COUNTER)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -628,7 +628,7 @@ func TestActionTriggerMatcBalanceFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 3.0)}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ExtraParameters: fmt.Sprintf(`{"GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -643,7 +643,7 @@ func TestActionTriggerMatcAllFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_EVENT_COUNTER, 3)}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -651,18 +651,28 @@ func TestActionTriggerMatcAllFalse(t *testing.T) {
func TestActionTriggerMatchAll(t *testing.T) {
at := &ActionTrigger{
+ ID: "TEST",
+ UniqueID: "ZIP",
+ ThresholdType: "TT",
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
RatingSubject: utils.StringPointer("test1"),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(2),
Weight: utils.Float64Pointer(1.0),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
},
- ThresholdType: utils.TRIGGER_MAX_BALANCE,
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"BalanceDirections":"*out", "ThresholdType":"%v", "ThresholdValue": %v, "DestinationIds": "%v", "BalanceWeight": %v, "BalanceRatingSubject": "%v", "BalanceSharedGroup": "%v"}`, utils.TRIGGER_MAX_BALANCE, 2, "NAT", 1.0, "test1", "test2")}
+ a := &Action{Balance: &BalanceFilter{
+ Type: utils.StringPointer(utils.MONETARY),
+ RatingSubject: utils.StringPointer("test1"),
+ Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
+ Value: utils.Float64Pointer(2),
+ Weight: utils.Float64Pointer(1.0),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
+ }, ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"TEST", "ThresholdType":"TT"}`)}
if !at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -684,7 +694,7 @@ func TestActionResetTriggres(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, nil, nil)
@@ -697,7 +707,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, nil, nil)
@@ -710,7 +720,7 @@ func TestActionResetTriggresActionFilter(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}}, nil)
@@ -723,7 +733,7 @@ func TestActionSetPostpaid(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
allowNegativeAction(ub, nil, nil, nil)
@@ -737,7 +747,7 @@ func TestActionSetPrepaid(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
denyNegativeAction(ub, nil, nil, nil)
@@ -751,7 +761,7 @@ func TestActionResetPrepaid(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetAccountAction(ub, nil, nil, nil)
@@ -761,7 +771,7 @@ func TestActionResetPrepaid(t *testing.T) {
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
t.Log(ub.BalanceMap)
- t.Error("Reset prepaid action failed!")
+ t.Error("Reset account action failed!")
}
}
@@ -769,7 +779,7 @@ func TestActionResetPostpaid(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetAccountAction(ub, nil, nil, nil)
@@ -777,7 +787,7 @@ func TestActionResetPostpaid(t *testing.T) {
len(ub.UnitCounters) != 0 ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
- t.Error("Reset postpaid action failed!")
+ t.Error("Reset account action failed!")
}
}
@@ -785,17 +795,17 @@ func TestActionTopupResetCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 10 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 || // InitCounters finds no counters
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
- t.Errorf("Topup reset action failed: %+v", ub.BalanceMap[utils.MONETARY][0])
+ t.Errorf("Topup reset action failed: %+s", utils.ToIJSON(ub))
}
}
@@ -828,7 +838,7 @@ func TestActionTopupResetCreditId(t *testing.T) {
},
},
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("TEST_B"), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
@@ -862,15 +872,15 @@ func TestActionTopupResetMinutes(t *testing.T) {
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{&Balance{Value: 100}},
utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 5 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Errorf("Topup reset minutes action failed: %+v", ub.BalanceMap[utils.VOICE][0])
@@ -881,14 +891,14 @@ func TestActionTopupCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Topup action failed!", ub.BalanceMap[utils.MONETARY].GetTotalValue())
@@ -899,15 +909,15 @@ func TestActionTopupMinutes(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 15 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Topup minutes action failed!", ub.BalanceMap[utils.VOICE])
@@ -918,17 +928,17 @@ func TestActionDebitCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 90 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
- t.Error("Debit action failed!", ub.BalanceMap[utils.MONETARY].GetTotalValue())
+ t.Error("Debit action failed!", utils.ToIJSON(ub))
}
}
@@ -936,15 +946,15 @@ func TestActionDebitMinutes(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
- a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
+ a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 5 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
- len(ub.UnitCounters) != 1 ||
+ len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Debit minutes action failed!", ub.BalanceMap[utils.VOICE][0])
@@ -961,24 +971,24 @@ func TestActionResetAllCounters(t *testing.T) {
&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)},
&Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT)}}},
- ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Weight: utils.Float64Pointer(20)}, ActionsId: "TEST_ACTIONS", Executed: true}},
+ ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Weight: utils.Float64Pointer(20)}, ActionsId: "TEST_ACTIONS", Executed: true}},
}
ub.InitCounters()
resetCountersAction(ub, nil, nil, nil)
if !ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
- len(ub.UnitCounters[0].Balances) != 1 ||
+ len(ub.UnitCounters[utils.MONETARY][0].Counters) != 1 ||
len(ub.BalanceMap[utils.MONETARY]) != 1 ||
ub.ActionTriggers[0].Executed != true {
- t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[0], ub.UnitCounters[0].Balances[0])
+ t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[utils.MONETARY][0], ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
if len(ub.UnitCounters) < 1 {
t.FailNow()
}
- mb := ub.UnitCounters[0].Balances[0]
- if mb.Weight != 20 || mb.GetValue() != 0 || mb.DestinationIds["NAT"] == false {
- t.Errorf("Balance cloned incorrectly: %+v", mb)
+ c := ub.UnitCounters[utils.MONETARY][0].Counters[0]
+ if c.Filter.GetWeight() != 20 || c.Value != 0 || c.Filter.GetDestinationIDs()["NAT"] == false {
+ t.Errorf("Balance cloned incorrectly: %+v", c)
}
}
@@ -997,20 +1007,20 @@ func TestActionResetCounterOnlyDefault(t *testing.T) {
if !ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
- len(ub.UnitCounters[0].Balances) != 1 ||
+ len(ub.UnitCounters[utils.MONETARY][0].Counters) != 1 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true {
- for _, b := range ub.UnitCounters[0].Balances {
+ for _, b := range ub.UnitCounters[utils.MONETARY][0].Counters {
t.Logf("B: %+v", b)
}
t.Errorf("Reset counters action failed: %+v", ub.UnitCounters)
}
- if len(ub.UnitCounters) < 1 || len(ub.UnitCounters[0].Balances) < 1 {
+ if len(ub.UnitCounters) < 1 || len(ub.UnitCounters[utils.MONETARY][0].Counters) < 1 {
t.FailNow()
}
- mb := ub.UnitCounters[0].Balances[0]
- if mb.Weight != 0 || mb.GetValue() != 0 || len(mb.DestinationIds) != 0 {
- t.Errorf("Balance cloned incorrectly: %+v!", mb)
+ c := ub.UnitCounters[utils.MONETARY][0].Counters[0]
+ if c.Filter.GetWeight() != 0 || c.Value != 0 || len(c.Filter.GetDestinationIDs()) != 0 {
+ t.Errorf("Balance cloned incorrectly: %+v!", c)
}
}
@@ -1019,7 +1029,7 @@ func TestActionResetCounterCredit(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}, &UnitCounter{BalanceType: utils.SMS, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
+ UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}, utils.SMS: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}}
@@ -1039,7 +1049,7 @@ func TestActionTriggerLogging(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
},
ThresholdValue: 100.0,
Weight: 10.0,
@@ -1142,7 +1152,7 @@ func TestTopupAction(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minu")
a := &Action{
ActionType: TOPUP,
- Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1163,7 +1173,7 @@ func TestTopupActionLoaded(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minitsboy")
a := &Action{
ActionType: TOPUP,
- Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1190,7 +1200,7 @@ func TestActionCdrlogEmpty(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
- Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1212,11 +1222,11 @@ func TestActionCdrlogWithParams(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
- Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
- Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1239,11 +1249,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
- Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
- Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1373,7 +1383,43 @@ func TestActionTransactionBalanceType(t *testing.T) {
if err != nil || acc == nil {
t.Error("Error getting account: ", acc, err)
}
- if acc.BalanceMap[utils.MONETARY][0].Value != 10 {
+ if acc.BalanceMap[utils.MONETARY][0].Value != 11.1 {
+ t.Errorf("Transaction didn't work: %v", acc.BalanceMap[utils.MONETARY][0].Value)
+ }
+}
+
+func TestActionTransactionBalanceNotType(t *testing.T) {
+ err := accountingStorage.SetAccount(&Account{
+ Id: "cgrates.org:trans",
+ BalanceMap: map[string]BalanceChain{
+ utils.MONETARY: BalanceChain{&Balance{
+ Value: 10,
+ }},
+ },
+ })
+ if err != nil {
+ t.Error("Error setting account: ", err)
+ }
+ at := &ActionTiming{
+ accountIDs: utils.StringMap{"cgrates.org:trans": true},
+ Timing: &RateInterval{},
+ actions: []*Action{
+ &Action{
+ ActionType: TOPUP,
+ Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.VOICE)},
+ },
+ &Action{
+ ActionType: TOPUP,
+ Balance: &BalanceFilter{Type: utils.StringPointer("test")},
+ },
+ },
+ }
+ err = at.Execute()
+ acc, err := accountingStorage.GetAccount("cgrates.org:trans")
+ if err != nil || acc == nil {
+ t.Error("Error getting account: ", acc, err)
+ }
+ if acc.BalanceMap[utils.MONETARY][0].Value != 10.0 {
t.Errorf("Transaction didn't work: %v", acc.BalanceMap[utils.MONETARY][0].Value)
}
}
@@ -1453,7 +1499,7 @@ func TestActionRemoveBalance(t *testing.T) {
ActionType: REMOVE_BALANCE,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")),
},
},
},
@@ -1850,43 +1896,58 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) {
}
a1 := &Action{
- ActionType: "*enable_disable_balance",
+ ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*sms"),
- Weight: utils.Float64Pointer(10),
+ ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"),
Disabled: utils.BoolPointer(true),
},
Weight: 9,
}
a2 := &Action{
- ActionType: "*enable_disable_balance",
+ ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*sms"),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
+ ID: utils.StringPointer("for_v3hsillmilld500m_mms_ill"),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
Weight: 8,
}
a3 := &Action{
- ActionType: "*enable_disable_balance",
+ ActionType: "*set_balance",
+ Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
+ Balance: &BalanceFilter{
+ Type: utils.StringPointer("*sms"),
+ ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
+ Weight: utils.Float64Pointer(10),
+ Disabled: utils.BoolPointer(true),
+ },
+ Weight: 8,
+ }
+ a4 := &Action{
+ ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*data"),
+ Uuid: utils.StringPointer("fc927edb-1bd6-425e-a2a3-9fd8bafaa524"),
RatingSubject: utils.StringPointer("for_v3hsillmilld500m_data_forfait"),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
Weight: 7,
}
- a4 := &Action{
- ActionType: "*enable_disable_balance",
+ a5 := &Action{
+ ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*voice"),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
+ ID: utils.StringPointer("for_v3hsillmilld500m_voice_3_h"),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
@@ -1895,7 +1956,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) {
at := &ActionTiming{
accountIDs: utils.StringMap{"cgrates.org:af": true},
- actions: Actions{a1, a2, a3, a4},
+ actions: Actions{a1, a2, a3, a4, a5},
}
at.Execute()
@@ -1957,7 +2018,7 @@ func TestActionSetBalance(t *testing.T) {
a := &Action{
ActionType: SET_BALANCE,
Balance: &BalanceFilter{
- Id: utils.StringPointer("m2"),
+ ID: utils.StringPointer("m2"),
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Weight: utils.Float64Pointer(10),
diff --git a/engine/balance_filter.go b/engine/balance_filter.go
new file mode 100644
index 000000000..e9f95e68c
--- /dev/null
+++ b/engine/balance_filter.go
@@ -0,0 +1,220 @@
+package engine
+
+import (
+ "reflect"
+ "time"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+type BalanceFilter struct {
+ Uuid *string
+ ID *string
+ Type *string
+ Value *float64
+ Directions *utils.StringMap
+ ExpirationDate *time.Time
+ Weight *float64
+ DestinationIDs *utils.StringMap
+ RatingSubject *string
+ Categories *utils.StringMap
+ SharedGroups *utils.StringMap
+ TimingIDs *utils.StringMap
+ Timings []*RITiming
+ Disabled *bool
+ Factor *ValueFactor
+ Blocker *bool
+}
+
+func (bp *BalanceFilter) CreateBalance() *Balance {
+ b := &Balance{
+ Uuid: bp.GetUuid(),
+ Id: bp.GetID(),
+ Value: bp.GetValue(),
+ Directions: bp.GetDirections(),
+ ExpirationDate: bp.GetExpirationDate(),
+ Weight: bp.GetWeight(),
+ DestinationIds: bp.GetDestinationIDs(),
+ RatingSubject: bp.GetRatingSubject(),
+ Categories: bp.GetCategories(),
+ SharedGroups: bp.GetSharedGroups(),
+ Timings: bp.Timings,
+ TimingIDs: bp.GetTimingIDs(),
+ Disabled: bp.GetDisabled(),
+ Factor: bp.GetFactor(),
+ Blocker: bp.GetBlocker(),
+ }
+ return b.Clone()
+}
+
+func (bp *BalanceFilter) LoadFromBalance(b *Balance) *BalanceFilter {
+ if b.Uuid != "" {
+ bp.Uuid = &b.Uuid
+ }
+ if b.Id != "" {
+ bp.ID = &b.Id
+ }
+ if b.Value != 0 {
+ bp.Value = &b.Value
+ }
+ if len(b.Directions) != 0 {
+ bp.Directions = &b.Directions
+ }
+ if !b.ExpirationDate.IsZero() {
+ bp.ExpirationDate = &b.ExpirationDate
+ }
+ if b.Weight != 0 {
+ bp.Weight = &b.Weight
+ }
+ if len(b.DestinationIds) != 0 {
+ bp.DestinationIDs = &b.DestinationIds
+ }
+ if b.RatingSubject != "" {
+ bp.RatingSubject = &b.RatingSubject
+ }
+ if len(b.Categories) != 0 {
+ bp.Categories = &b.Categories
+ }
+ if len(b.SharedGroups) != 0 {
+ bp.SharedGroups = &b.SharedGroups
+ }
+ if len(b.TimingIDs) != 0 {
+ bp.TimingIDs = &b.TimingIDs
+ }
+ if len(b.Factor) != 0 {
+ bp.Factor = &b.Factor
+ }
+ if b.Disabled {
+ bp.Disabled = &b.Disabled
+ }
+ if b.Blocker {
+ bp.Blocker = &b.Blocker
+ }
+ return bp
+}
+
+func (bp *BalanceFilter) Equal(o *BalanceFilter) bool {
+ if bp.ID != nil && o.ID != nil {
+ return *bp.ID == *o.ID
+ }
+ return reflect.DeepEqual(bp, o)
+}
+
+func (bp *BalanceFilter) GetType() string {
+ if bp == nil || bp.Type == nil {
+ return ""
+ }
+ return *bp.Type
+}
+
+func (bp *BalanceFilter) GetValue() float64 {
+ if bp == nil || bp.Value == nil {
+ return 0.0
+ }
+ return *bp.Value
+}
+
+func (bp *BalanceFilter) SetValue(v float64) {
+ if bp.Value == nil {
+ bp.Value = new(float64)
+ }
+ *bp.Value = v
+}
+
+func (bp *BalanceFilter) GetUuid() string {
+ if bp == nil || bp.Uuid == nil {
+ return ""
+ }
+ return *bp.Uuid
+}
+
+func (bp *BalanceFilter) GetID() string {
+ if bp == nil || bp.ID == nil {
+ return ""
+ }
+ return *bp.ID
+}
+
+func (bp *BalanceFilter) GetDirections() utils.StringMap {
+ if bp == nil || bp.Directions == nil {
+ return utils.StringMap{}
+ }
+ return *bp.Directions
+}
+
+func (bp *BalanceFilter) GetDestinationIDs() utils.StringMap {
+ if bp == nil || bp.DestinationIDs == nil {
+ return utils.StringMap{}
+ }
+ return *bp.DestinationIDs
+}
+
+func (bp *BalanceFilter) GetCategories() utils.StringMap {
+ if bp == nil || bp.Categories == nil {
+ return utils.StringMap{}
+ }
+ return *bp.Categories
+}
+
+func (bp *BalanceFilter) GetTimingIDs() utils.StringMap {
+ if bp == nil || bp.TimingIDs == nil {
+ return utils.StringMap{}
+ }
+ return *bp.TimingIDs
+}
+
+func (bp *BalanceFilter) GetSharedGroups() utils.StringMap {
+ if bp == nil || bp.SharedGroups == nil {
+ return utils.StringMap{}
+ }
+ return *bp.SharedGroups
+}
+
+func (bp *BalanceFilter) GetWeight() float64 {
+ if bp == nil || bp.Weight == nil {
+ return 0.0
+ }
+ return *bp.Weight
+}
+
+func (bp *BalanceFilter) GetRatingSubject() string {
+ if bp == nil || bp.RatingSubject == nil {
+ return ""
+ }
+ return *bp.RatingSubject
+}
+
+func (bp *BalanceFilter) GetDisabled() bool {
+ if bp == nil || bp.Disabled == nil {
+ return false
+ }
+ return *bp.Disabled
+}
+
+func (bp *BalanceFilter) GetBlocker() bool {
+ if bp == nil || bp.Blocker == nil {
+ return false
+ }
+ return *bp.Blocker
+}
+
+func (bp *BalanceFilter) GetExpirationDate() time.Time {
+ if bp == nil || bp.ExpirationDate == nil {
+ return time.Time{}
+ }
+ return *bp.ExpirationDate
+}
+
+func (bp *BalanceFilter) GetFactor() ValueFactor {
+ if bp == nil || bp.Factor == nil {
+ return ValueFactor{}
+ }
+ return *bp.Factor
+}
+
+func (bp *BalanceFilter) HasExpirationDate() bool {
+ if bp.ExpirationDate == nil {
+ return true
+ }
+ return (*bp.ExpirationDate).IsZero()
+}
diff --git a/engine/balances.go b/engine/balances.go
index 80fc005d6..633b17063 100644
--- a/engine/balances.go
+++ b/engine/balances.go
@@ -79,14 +79,14 @@ func (b *Balance) MatchFilter(o *BalanceFilter, skipIds bool) bool {
if !skipIds && o.Uuid != nil && *o.Uuid != "" {
return b.Uuid == *o.Uuid
}
- if !skipIds && o.Id != nil && *o.Id != "" {
- return b.Id == *o.Id
+ if !skipIds && o.ID != nil && *o.ID != "" {
+ return b.Id == *o.ID
}
return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) &&
(o.Weight == nil || b.Weight == *o.Weight) &&
(o.Blocker == nil || b.Blocker == *o.Blocker) &&
(o.Disabled == nil || b.Disabled == *o.Disabled) &&
- (o.DestinationIds == nil || b.DestinationIds.Includes(*o.DestinationIds)) &&
+ (o.DestinationIDs == nil || b.DestinationIds.Includes(*o.DestinationIDs)) &&
(o.Directions == nil || b.Directions.Includes(*o.Directions)) &&
(o.Categories == nil || b.Categories.Includes(*o.Categories)) &&
(o.TimingIDs == nil || b.TimingIDs.Includes(*o.TimingIDs)) &&
@@ -101,14 +101,14 @@ func (b *Balance) HardMatchFilter(o *BalanceFilter, skipIds bool) bool {
if !skipIds && o.Uuid != nil && *o.Uuid != "" {
return b.Uuid == *o.Uuid
}
- if !skipIds && o.Id != nil && *o.Id != "" {
- return b.Id == *o.Id
+ if !skipIds && o.ID != nil && *o.ID != "" {
+ return b.Id == *o.ID
}
return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) &&
(o.Weight == nil || b.Weight == *o.Weight) &&
(o.Blocker == nil || b.Blocker == *o.Blocker) &&
(o.Disabled == nil || b.Disabled == *o.Disabled) &&
- (o.DestinationIds == nil || b.DestinationIds.Equal(*o.DestinationIds)) &&
+ (o.DestinationIDs == nil || b.DestinationIds.Equal(*o.DestinationIDs)) &&
(o.Directions == nil || b.Directions.Equal(*o.Directions)) &&
(o.Categories == nil || b.Categories.Equal(*o.Categories)) &&
(o.TimingIDs == nil || b.TimingIDs.Equal(*o.TimingIDs)) &&
@@ -116,40 +116,6 @@ func (b *Balance) HardMatchFilter(o *BalanceFilter, skipIds bool) bool {
(o.RatingSubject == nil || b.RatingSubject == *o.RatingSubject)
}
-func (b *Balance) MatchCCFilter(cc *CallCost) bool {
- if len(b.Categories) > 0 && cc.Category != "" && b.Categories[cc.Category] == false {
- return false
- }
- if len(b.Directions) > 0 && cc.Direction != "" && b.Directions[cc.Direction] == false {
- return false
- }
-
- // match destination ids
- foundMatchingDestId := false
- if len(b.DestinationIds) > 0 && cc.Destination != "" {
- for _, p := range utils.SplitPrefix(cc.Destination, MIN_PREFIX_MATCH) {
- if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil {
- destIds := x.(map[interface{}]struct{})
- for filterDestId := range b.DestinationIds {
- if _, ok := destIds[filterDestId]; ok {
- foundMatchingDestId = true
- break
- }
- }
- }
- if foundMatchingDestId {
- break
- }
- }
- } else {
- foundMatchingDestId = true
- }
- if !foundMatchingDestId {
- return false
- }
- return true
-}
-
// the default balance has standard Id
func (b *Balance) IsDefault() bool {
return b.Id == utils.META_DEFAULT
diff --git a/engine/balances_test.go b/engine/balances_test.go
index 93a9f23db..ec95fad73 100644
--- a/engine/balances_test.go
+++ b/engine/balances_test.go
@@ -90,7 +90,7 @@ func TestBalanceEqual(t *testing.T) {
func TestBalanceMatchFilter(t *testing.T) {
mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}}
- mb2 := &BalanceFilter{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIds: nil}
+ mb2 := &BalanceFilter{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIDs: nil}
if !mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
}
@@ -106,7 +106,7 @@ func TestBalanceMatchFilterEmpty(t *testing.T) {
func TestBalanceMatchFilterId(t *testing.T) {
mb1 := &Balance{Id: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIds: utils.NewStringMap("NAT")}
- mb2 := &BalanceFilter{Id: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIds: nil}
+ mb2 := &BalanceFilter{ID: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
if !mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
}
@@ -114,7 +114,7 @@ func TestBalanceMatchFilterId(t *testing.T) {
func TestBalanceMatchFilterDiffId(t *testing.T) {
mb1 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}}
- mb2 := &BalanceFilter{Id: utils.StringPointer("T2"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIds: nil}
+ mb2 := &BalanceFilter{ID: utils.StringPointer("T2"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
if mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v != %+v", mb1, mb2)
}
@@ -129,7 +129,7 @@ func TestBalanceClone(t *testing.T) {
}
func TestBalanceMatchActionTriggerId(t *testing.T) {
- at := &ActionTrigger{Balance: &BalanceFilter{Id: utils.StringPointer("test")}}
+ at := &ActionTrigger{Balance: &BalanceFilter{ID: utils.StringPointer("test")}}
b := &Balance{Id: "test"}
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
@@ -143,14 +143,14 @@ func TestBalanceMatchActionTriggerId(t *testing.T) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
b.Id = "test"
- at.Balance.Id = nil
+ at.Balance.ID = nil
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
}
func TestBalanceMatchActionTriggerDestination(t *testing.T) {
- at := &ActionTrigger{Balance: &BalanceFilter{DestinationIds: utils.StringMapPointer(utils.NewStringMap("test"))}}
+ at := &ActionTrigger{Balance: &BalanceFilter{DestinationIDs: utils.StringMapPointer(utils.NewStringMap("test"))}}
b := &Balance{DestinationIds: utils.NewStringMap("test")}
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
@@ -164,7 +164,7 @@ func TestBalanceMatchActionTriggerDestination(t *testing.T) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
b.DestinationIds = utils.NewStringMap("test")
- at.Balance.DestinationIds = nil
+ at.Balance.DestinationIDs = nil
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
diff --git a/engine/callcost.go b/engine/callcost.go
index 98984333c..85c8a3c4b 100644
--- a/engine/callcost.go
+++ b/engine/callcost.go
@@ -21,6 +21,7 @@ import (
"errors"
"time"
+ "github.com/cgrates/cgrates/cache2go"
"github.com/cgrates/cgrates/utils"
)
@@ -180,3 +181,40 @@ func (cc *CallCost) updateCost() {
}
cc.Cost = cost
}
+
+func (cc *CallCost) MatchCCFilter(bf *BalanceFilter) bool {
+ if bf == nil {
+ return true
+ }
+ if bf.Categories != nil && cc.Category != "" && (*bf.Categories)[cc.Category] == false {
+ return false
+ }
+ if bf.Directions != nil && cc.Direction != "" && (*bf.Directions)[cc.Direction] == false {
+ return false
+ }
+
+ // match destination ids
+ foundMatchingDestID := false
+ if bf.DestinationIDs != nil && cc.Destination != "" {
+ for _, p := range utils.SplitPrefix(cc.Destination, MIN_PREFIX_MATCH) {
+ if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil {
+ destIds := x.(map[interface{}]struct{})
+ for filterDestID := range *bf.DestinationIDs {
+ if _, ok := destIds[filterDestID]; ok {
+ foundMatchingDestID = true
+ break
+ }
+ }
+ }
+ if foundMatchingDestID {
+ break
+ }
+ }
+ } else {
+ foundMatchingDestID = true
+ }
+ if !foundMatchingDestID {
+ return false
+ }
+ return true
+}
diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go
index cbac46036..852b91a79 100644
--- a/engine/calldesc_test.go
+++ b/engine/calldesc_test.go
@@ -42,7 +42,7 @@ func init() {
func populateDB() {
ats := []*Action{
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}},
- &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
+ &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
}
ats1 := []*Action{
diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go
index 9c6073051..69f090c8d 100644
--- a/engine/loader_csv_test.go
+++ b/engine/loader_csv_test.go
@@ -832,10 +832,12 @@ func TestLoadActions(t *testing.T) {
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(10),
Weight: utils.Float64Pointer(10),
- DestinationIds: nil,
+ DestinationIDs: nil,
TimingIDs: nil,
SharedGroups: nil,
Categories: nil,
+ Disabled: utils.BoolPointer(false),
+ Blocker: utils.BoolPointer(false),
},
},
&Action{
@@ -851,10 +853,12 @@ func TestLoadActions(t *testing.T) {
Value: utils.Float64Pointer(100),
Weight: utils.Float64Pointer(10),
RatingSubject: utils.StringPointer("test"),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
TimingIDs: nil,
SharedGroups: nil,
Categories: nil,
+ Disabled: utils.BoolPointer(false),
+ Blocker: utils.BoolPointer(false),
},
},
}
@@ -871,13 +875,15 @@ func TestLoadActions(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: nil,
+ DestinationIDs: nil,
Uuid: as2[0].Balance.Uuid,
Value: utils.Float64Pointer(100),
Weight: utils.Float64Pointer(10),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")),
TimingIDs: nil,
Categories: nil,
+ Disabled: utils.BoolPointer(false),
+ Blocker: utils.BoolPointer(false),
},
},
}
@@ -894,11 +900,12 @@ func TestLoadActions(t *testing.T) {
Balance: &BalanceFilter{
Uuid: as3[0].Balance.Uuid,
Directions: nil,
- DestinationIds: nil,
+ DestinationIDs: nil,
TimingIDs: nil,
Categories: nil,
SharedGroups: nil,
Blocker: utils.BoolPointer(false),
+ Disabled: utils.BoolPointer(false),
},
},
}
@@ -1048,19 +1055,22 @@ func TestLoadActionTriggers(t *testing.T) {
ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER,
ThresholdValue: 10,
Balance: &BalanceFilter{
+ ID: utils.StringPointer("st0"),
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
Categories: nil,
TimingIDs: nil,
SharedGroups: nil,
+ Disabled: nil,
+ Blocker: nil,
},
Weight: 10,
ActionsId: "SOME_1",
Executed: false,
}
if !reflect.DeepEqual(atr, expected) {
- t.Errorf("Error loading action trigger: %+v", atr)
+ t.Errorf("Error loading action trigger: %+v", utils.ToIJSON(atr.Balance))
}
atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1]
expected = &ActionTrigger{
@@ -1071,7 +1081,7 @@ func TestLoadActionTriggers(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY")),
Categories: nil,
TimingIDs: nil,
SharedGroups: nil,
@@ -1093,18 +1103,22 @@ func TestLoadAccountActions(t *testing.T) {
expected := &Account{
Id: "vdf:minitsboy",
UnitCounters: UnitCounters{
- &UnitCounter{
- BalanceType: "*voice",
- CounterType: "*event",
- Balances: BalanceChain{
- &Balance{
- Id: "2c2ce3c9-d62b-49dc-82a5-2a17bdc6eb4e",
- Value: 0,
- Directions: utils.NewStringMap("*out"),
- DestinationIds: utils.NewStringMap("GERMANY_O2"),
- SharedGroups: nil,
- Categories: nil,
- TimingIDs: nil,
+ utils.VOICE: []*UnitCounter{
+ &UnitCounter{
+ CounterType: "*event",
+ Counters: CounterFilters{
+ &CounterFilter{
+ Value: 0,
+ Filter: &BalanceFilter{
+ ID: utils.StringPointer("st0"),
+ Type: utils.StringPointer(utils.VOICE),
+ Directions: utils.StringMapPointer(utils.NewStringMap("*out")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
+ SharedGroups: nil,
+ Categories: nil,
+ TimingIDs: nil,
+ },
+ },
},
},
},
@@ -1115,11 +1129,11 @@ func TestLoadAccountActions(t *testing.T) {
for i, atr := range aa.ActionTriggers {
csvr.actionsTriggers["STANDARD_TRIGGER"][i].ID = atr.ID
}
- for i, b := range aa.UnitCounters[0].Balances {
- expected.UnitCounters[0].Balances[i].Id = b.Id
+ for i, b := range aa.UnitCounters[utils.VOICE][0].Counters {
+ expected.UnitCounters[utils.VOICE][0].Counters[i].Filter.ID = b.Filter.ID
}
- if !reflect.DeepEqual(aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0]) {
- t.Errorf("Error loading account action: %+v \n %+v", aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0])
+ if !reflect.DeepEqual(aa.UnitCounters[utils.VOICE][0].Counters[0], expected.UnitCounters[utils.VOICE][0].Counters[0]) {
+ t.Errorf("Error loading account action: %+v", utils.ToIJSON(aa.UnitCounters[utils.VOICE][0].Counters[0].Filter))
}
// test that it does not overwrite balances
existing, err := accountingStorage.GetAccount(aa.Id)
diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go
index 085012a37..94147a6a9 100644
--- a/engine/model_helpers_test.go
+++ b/engine/model_helpers_test.go
@@ -265,8 +265,8 @@ func TestTPActionsAsExportSlice(t *testing.T) {
},
}
expectedSlc := [][]string{
- []string{"TEST_ACTIONS", "*topup_reset", "", "", "", "*monetary", utils.OUT, "call", "*any", "special1", "GROUP1", "*never", "", "5", "10", "false", "false", "10"},
- []string{"TEST_ACTIONS", "*http_post", "http://localhost/¶m1=value1", "", "", "", "", "", "", "", "", "", "", "0", "0", "false", "false", "20"},
+ []string{"TEST_ACTIONS", "*topup_reset", "", "", "", "*monetary", utils.OUT, "call", "*any", "special1", "GROUP1", "*never", "", "5.0", "10.0", "", "", "10"},
+ []string{"TEST_ACTIONS", "*http_post", "http://localhost/¶m1=value1", "", "", "", "", "", "", "", "", "", "", "0.0", "0.0", "", "", "20"},
}
ms := APItoModelAction(tpActs)
@@ -597,8 +597,8 @@ func TestTPActionPlanAsExportSlice(t *testing.T) {
},
}
expectedSlc := [][]string{
- []string{"STANDARD_TRIGGERS", "1", "*min_balance", "2", "false", "0", "", "", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "T1", "0", "false", "false", "0", "LOG_WARNING", "10"},
- []string{"STANDARD_TRIGGERS", "2", "*max_event_counter", "5", "false", "0", "", "", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "T1", "0", "false", "false", "0", "LOG_WARNING", "10"},
+ []string{"STANDARD_TRIGGERS", "1", "*min_balance", "2", "false", "0", "", "", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "T1", "0.0", "false", "false", "0", "LOG_WARNING", "10"},
+ []string{"STANDARD_TRIGGERS", "2", "*max_event_counter", "5", "false", "0", "", "", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "T1", "0.0", "false", "false", "0", "LOG_WARNING", "10"},
}
ms := APItoModelActionTrigger(at)
var slc [][]string
diff --git a/engine/storage_test.go b/engine/storage_test.go
index 2c1b9b808..ee8ed42cd 100644
--- a/engine/storage_test.go
+++ b/engine/storage_test.go
@@ -311,8 +311,7 @@ func TestStorageTask(t *testing.T) {
func GetUB() *Account {
uc := &UnitCounter{
- BalanceType: utils.SMS,
- Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
+ Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
at := &ActionTrigger{
ID: "some_uuid",
@@ -320,7 +319,7 @@ func GetUB() *Account {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
},
Weight: 10.0,
ActionsId: "Commando",
@@ -331,7 +330,7 @@ func GetUB() *Account {
Id: "rif",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
- UnitCounters: UnitCounters{uc, uc},
+ UnitCounters: UnitCounters{utils.SMS: []*UnitCounter{uc, uc}},
ActionTriggers: ActionTriggers{at, at, at},
}
return ub
diff --git a/engine/tp_reader.go b/engine/tp_reader.go
index bfa6615d6..469165aba 100644
--- a/engine/tp_reader.go
+++ b/engine/tp_reader.go
@@ -524,7 +524,7 @@ func (tpr *TpReader) LoadActions() (err error) {
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
- acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
+ acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -563,7 +563,7 @@ func (tpr *TpReader) LoadActions() (err error) {
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
- acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
+ acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))
@@ -706,7 +706,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) {
MinQueuedItems: atr.MinQueuedItems,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
- atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
+ atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -738,7 +738,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) {
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
- atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
+ atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -906,7 +906,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
ActionsId: atr.ActionsId,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
- atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
+ atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -938,7 +938,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
- atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
+ atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -1006,7 +1006,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
- acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
+ acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -1038,7 +1038,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
- acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
+ acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))
@@ -1243,7 +1243,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
ActionsId: atr.ActionsId,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
- atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
+ atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -1275,7 +1275,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
- atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
+ atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -1352,7 +1352,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
- acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
+ acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -1384,7 +1384,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
- acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
+ acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))
diff --git a/engine/units_counter.go b/engine/units_counter.go
index 7854aa9ec..b4e7f6696 100644
--- a/engine/units_counter.go
+++ b/engine/units_counter.go
@@ -18,29 +18,40 @@ along with this program. If not, see
package engine
-import (
- "log"
-
- "github.com/cgrates/cgrates/utils"
-)
+import "github.com/cgrates/cgrates/utils"
// Amount of a trafic of a certain type
type UnitCounter struct {
- BalanceType string // *monetary/*voice/*sms/etc
- CounterType string // *event or *balance
- Balances BalanceChain // first balance is the general one (no destination)
+ CounterType string // *event or *balance
+ Counters CounterFilters // first balance is the general one (no destination)
+}
+
+type CounterFilter struct {
+ Value float64
+ Filter *BalanceFilter
+}
+
+type CounterFilters []*CounterFilter
+
+func (cfs CounterFilters) HasCounter(cf *CounterFilter) bool {
+ for _, c := range cfs {
+ if c.Filter.Equal(cf.Filter) {
+ return true
+ }
+ }
+ return false
}
// Returns true if the counters were of the same type
// Copies the value from old balances
func (uc *UnitCounter) CopyCounterValues(oldUc *UnitCounter) bool {
- if uc.BalanceType+uc.CounterType != oldUc.BalanceType+oldUc.CounterType { // type check
+ if uc.CounterType != oldUc.CounterType { // type check
return false
}
- for _, b := range uc.Balances {
- for _, oldB := range oldUc.Balances {
- if b.Equal(oldB) {
- b.Value = oldB.Value
+ for _, c := range uc.Counters {
+ for _, oldC := range oldUc.Counters {
+ if c.Filter.Equal(oldC.Filter) {
+ c.Value = oldC.Value
break
}
}
@@ -48,30 +59,28 @@ func (uc *UnitCounter) CopyCounterValues(oldUc *UnitCounter) bool {
return true
}
-type UnitCounters []*UnitCounter
+type UnitCounters map[string][]*UnitCounter
func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *Balance) {
- for _, uc := range ucs {
+ counters, found := ucs[kind]
+ if !found {
+ return
+ }
+ for _, uc := range counters {
if uc == nil { // safeguard
continue
}
- if uc.BalanceType != kind {
- continue
- }
if uc.CounterType == "" {
uc.CounterType = utils.COUNTER_EVENT
}
- for _, bal := range uc.Balances {
- log.Print(b)
- if uc.CounterType == utils.COUNTER_EVENT && cc != nil && bal.MatchCCFilter(cc) {
- log.Print("HERE")
- bal.AddValue(amount)
+ for _, c := range uc.Counters {
+ if uc.CounterType == utils.COUNTER_EVENT && cc != nil && cc.MatchCCFilter(c.Filter) {
+ c.Value += amount
continue
}
- bp := &BalanceFilter{}
- bp.LoadFromBalance(bal)
- if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bp, true) {
- bal.AddValue(amount)
+
+ if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(c.Filter, true) {
+ c.Value += amount
continue
}
}
@@ -80,16 +89,18 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B
}
func (ucs UnitCounters) resetCounters(a *Action) {
- for _, uc := range ucs {
- if uc == nil { // safeguard
+ for key, counters := range ucs {
+ if a != nil && a.Balance.Type != nil && a.Balance.GetType() != key {
continue
}
- if a != nil && a.Balance.Type != nil && a.Balance.GetType() != uc.BalanceType {
- continue
- }
- for _, b := range uc.Balances {
- if a == nil || a.Balance == nil || b.MatchFilter(a.Balance, false) {
- b.Value = 0
+ for _, c := range counters {
+ if c == nil { // safeguard
+ continue
+ }
+ for _, cf := range c.Counters {
+ if a == nil || a.Balance == nil || cf.Filter.Equal(a.Balance) {
+ cf.Value = 0
+ }
}
}
}
diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go
index 4ca1ec849..4e80006c0 100644
--- a/engine/units_counter_test.go
+++ b/engine/units_counter_test.go
@@ -26,22 +26,20 @@ import (
func TestUnitsCounterAddBalance(t *testing.T) {
uc := &UnitCounter{
- BalanceType: utils.SMS,
- Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
+ Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
- UnitCounters{uc}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
- if len(uc.Balances) != 3 {
- t.Error("Error adding minute bucket: ", uc.Balances)
+ UnitCounters{utils.SMS: []*UnitCounter{uc}}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
+ if len(uc.Counters) != 3 {
+ t.Error("Error adding minute bucket: ", uc.Counters)
}
}
func TestUnitsCounterAddBalanceExists(t *testing.T) {
uc := &UnitCounter{
- BalanceType: utils.SMS,
- Balances: BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
+ Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Value: 10, Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
- UnitCounters{uc}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
- if len(uc.Balances) != 3 || uc.Balances[1].GetValue() != 15 {
+ UnitCounters{utils.SMS: []*UnitCounter{uc}}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
+ if len(uc.Counters) != 3 || uc.Counters[1].Value != 15 {
t.Error("Error adding minute bucket!")
}
}
@@ -108,14 +106,17 @@ func TestUnitCountersCountAllMonetary(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- a.UnitCounters[0].Balances[0].Value != 10 ||
- a.UnitCounters[0].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
@@ -183,15 +184,17 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) {
}
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, nil, &Balance{Weight: 20, Directions: utils.NewStringMap(utils.OUT)})
-
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- a.UnitCounters[0].Balances[0].Value != 0 ||
- a.UnitCounters[0].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 0 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
@@ -225,7 +228,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
Weight: utils.Float64Pointer(10),
},
},
@@ -234,7 +237,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
Weight: utils.Float64Pointer(10),
},
},
@@ -270,14 +273,17 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[1].Balances) != 2 ||
- a.UnitCounters[1].Balances[0].Value != 10 ||
- a.UnitCounters[1].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
+ a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
@@ -311,7 +317,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
Weight: utils.Float64Pointer(10),
},
},
@@ -320,7 +326,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
- DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")),
+ DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
Weight: utils.Float64Pointer(10),
},
},
@@ -356,28 +362,34 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[1].Balances) != 2 ||
- a.UnitCounters[1].Balances[0].Value != 10 ||
- a.UnitCounters[1].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
+ a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
}
a.InitCounters()
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[1].Balances) != 2 ||
- a.UnitCounters[1].Balances[0].Value != 10 ||
- a.UnitCounters[1].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
+ a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error keeping counter values after init: %v", len(a.UnitCounters))
@@ -446,14 +458,17 @@ func TestUnitCountersResetCounterById(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- a.UnitCounters[0].Balances[0].Value != 10 ||
- a.UnitCounters[0].Balances[1].Value != 10 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
@@ -461,17 +476,20 @@ func TestUnitCountersResetCounterById(t *testing.T) {
a.UnitCounters.resetCounters(&Action{
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
- Id: utils.StringPointer("TestTR11"),
+ ID: utils.StringPointer("TestTR11"),
},
})
- if len(a.UnitCounters) != 4 ||
- len(a.UnitCounters[0].Balances) != 2 ||
- a.UnitCounters[0].Balances[0].Value != 10 ||
- a.UnitCounters[0].Balances[1].Value != 0 {
- for _, uc := range a.UnitCounters {
- t.Logf("UC: %+v", uc)
- for _, b := range uc.Balances {
- t.Logf("B: %+v", b)
+ if len(a.UnitCounters) != 3 ||
+ len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
+ a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 0 {
+ for key, counters := range a.UnitCounters {
+ t.Log(key)
+ for _, uc := range counters {
+ t.Logf("UC: %+v", uc)
+ for _, b := range uc.Counters {
+ t.Logf("B: %+v", b)
+ }
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))