From 418a9cf12f60dc1ca243a6999594ff54bbf14540 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 15 Feb 2016 23:05:35 +0200 Subject: [PATCH] most engine tests passing ResetAccountPending --- engine/account.go | 118 +++++++++++-------- engine/account_test.go | 109 ++++++++--------- engine/action.go | 130 +-------------------- engine/action_plan.go | 5 +- engine/action_trigger.go | 32 ++++- engine/actions_test.go | 193 +++++++++++++++++++----------- engine/balance_filter.go | 220 +++++++++++++++++++++++++++++++++++ engine/balances.go | 46 +------- engine/balances_test.go | 14 +-- engine/callcost.go | 38 ++++++ engine/calldesc_test.go | 2 +- engine/loader_csv_test.go | 60 ++++++---- engine/model_helpers_test.go | 8 +- engine/storage_test.go | 7 +- engine/tp_reader.go | 24 ++-- engine/units_counter.go | 81 +++++++------ engine/units_counter_test.go | 160 ++++++++++++++----------- 17 files changed, 746 insertions(+), 501 deletions(-) create mode 100644 engine/balance_filter.go 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))