diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index 4331f4c24..14768acfb 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -188,6 +188,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error return 0, err } ub.ActionTriggers = atrs + ub.InitCounters() } if attr.AllowNegative != nil { ub.AllowNegative = *attr.AllowNegative diff --git a/engine/account.go b/engine/account.go index 90b7ce49b..4ed5f534a 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" @@ -117,7 +116,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error { continue // just to be safe (cleaned expired balances above) } b.account = ub - if b.MatchFilter(a.Balance) { + if b.MatchFilter(a.Balance, false) { if reset { b.SetValue(0) } @@ -185,7 +184,7 @@ func (ub *Account) enableDisableBalanceAction(a *Action) error { id := a.BalanceType ub.CleanExpiredBalances() for _, b := range ub.BalanceMap[id] { - if b.MatchFilter(a.Balance) { + if b.MatchFilter(a.Balance, false) { b.Disabled = a.Balance.Disabled b.dirty = true found = true @@ -500,7 +499,6 @@ func (ub *Account) executeActionTriggers(a *Action) { uc.CounterType == counter { for _, mb := range uc.Balances { if limit == "*max" { - log.Print("HERE: ", mb.MatchActionTrigger(at)) if mb.MatchActionTrigger(at) && mb.GetValue() >= at.ThresholdValue { // run the actions at.Execute(ub, nil) @@ -537,19 +535,19 @@ func (ub *Account) executeActionTriggers(a *Action) { // Mark all action trigers as ready for execution // If the action is not nil it acts like a filter -func (ub *Account) ResetActionTriggers(a *Action) { - for _, at := range ub.ActionTriggers { +func (acc *Account) ResetActionTriggers(a *Action) { + for _, at := range acc.ActionTriggers { if !at.Match(a) { continue } at.Executed = false } - ub.executeActionTriggers(a) + acc.executeActionTriggers(a) } // Sets/Unsets recurrent flag for action triggers -func (ub *Account) SetRecurrent(a *Action, recurrent bool) { - for _, at := range ub.ActionTriggers { +func (acc *Account) SetRecurrent(a *Action, recurrent bool) { + for _, at := range acc.ActionTriggers { if !at.Match(a) { continue } @@ -558,49 +556,51 @@ func (ub *Account) SetRecurrent(a *Action, recurrent bool) { } // Increments the counter for the type -func (ub *Account) countUnits(amount float64, kind string, cc *CallCost, b *Balance) { - ub.UnitCounters.addUnits(amount, kind, cc, b) - ub.executeActionTriggers(nil) +func (acc *Account) countUnits(amount float64, kind string, cc *CallCost, b *Balance) { + acc.UnitCounters.addUnits(amount, kind, cc, b) + acc.executeActionTriggers(nil) } -// Create counters for all triggered actions that have actions opertating on balances -func (acc *Account) initCounters() { - ucTempMap := make(map[string]*UnitsCounter) - // add default balance +// Create counters for all triggered actions +func (acc *Account) InitCounters() { + acc.UnitCounters = make(UnitCounters, 0) + ucTempMap := make(map[string]*UnitCounter) for _, at := range acc.ActionTriggers { if !strings.Contains(at.ThresholdType, "counter") { - // only get actions for counter type action triggers continue } - uc, exists := ucTempMap[at.BalanceType] + _, ct, _ := at.GetThresholdTypeInfo() + uc, exists := ucTempMap[at.BalanceType+ct] if !exists { - _, ct, _ := at.GetThresholdTypeInfo() - uc = &UnitsCounter{ + uc = &UnitCounter{ BalanceType: at.BalanceType, CounterType: ct, } - ucTempMap[at.BalanceType] = uc + ucTempMap[at.BalanceType+ct] = uc uc.Balances = BalanceChain{} acc.UnitCounters = append(acc.UnitCounters, uc) } - uc.Balances = append(uc.Balances, at.CreateBalance()) + b := at.CreateBalance() + if !uc.Balances.HasBalance(b) { + uc.Balances = append(uc.Balances, b) + } } } -func (ub *Account) CleanExpiredBalances() { - for key, bm := range ub.BalanceMap { +func (acc *Account) CleanExpiredBalances() { + for key, bm := range acc.BalanceMap { for i := 0; i < len(bm); i++ { if bm[i].IsExpired() { // delete it bm = append(bm[:i], bm[i+1:]...) } } - ub.BalanceMap[key] = bm + acc.BalanceMap[key] = bm } } -func (ub *Account) allBalancesExpired() bool { - for _, bm := range ub.BalanceMap { +func (acc *Account) allBalancesExpired() bool { + for _, bm := range acc.BalanceMap { for i := 0; i < len(bm); i++ { if !bm[i].IsExpired() { return false @@ -611,8 +611,8 @@ func (ub *Account) allBalancesExpired() bool { } // returns the shared groups that this user balance belnongs to -func (ub *Account) GetSharedGroups() (groups []string) { - for _, balanceChain := range ub.BalanceMap { +func (acc *Account) GetSharedGroups() (groups []string) { + for _, balanceChain := range acc.BalanceMap { for _, b := range balanceChain { for sg := range b.SharedGroups { groups = append(groups, sg) diff --git a/engine/account_test.go b/engine/account_test.go index 4712b5a69..e579232c8 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" @@ -889,12 +888,10 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.StringMap{utils.OUT: true}}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.StringMap{utils.OUT: true}}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, } - log.Print("==============") ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil) - log.Print("==============") if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) } @@ -915,7 +912,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 100, ThresholdType: TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, } ub.countUnits(1, utils.MONETARY, nil, nil) @@ -928,10 +925,11 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}}, } - ub.countUnits(1, utils.MONETARY, nil, nil) + + 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]) @@ -959,45 +957,45 @@ func TestCleanExpired(t *testing.T) { } func TestAccountUnitCounting(t *testing.T) { - ub := &Account{} - ub.countUnits(10, utils.MONETARY, nil, nil) + ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{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 { t.Error("Error counting units") } - ub.countUnits(10, utils.MONETARY, nil, nil) + 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 { t.Error("Error counting units") } } func TestAccountUnitCountingOutbound(t *testing.T) { - ub := &Account{} - ub.countUnits(10, utils.MONETARY, nil, nil) + ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: 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.Error("Error counting units") } - ub.countUnits(10, utils.MONETARY, nil, nil) + 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 { t.Error("Error counting units") } - ub.countUnits(10, utils.MONETARY, nil, nil) + 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 { t.Error("Error counting units") } } func TestAccountUnitCountingOutboundInbound(t *testing.T) { - ub := &Account{} - ub.countUnits(1, utils.MONETARY, nil, nil) + ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: 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]) + t.Errorf("Error counting units: %+v", ub.UnitCounters[0].Balances[0]) } - ub.countUnits(10, utils.MONETARY, nil, nil) + 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 { t.Error("Error counting units") } - ub.countUnits(10, utils.MONETARY, nil, nil) - if len(ub.UnitCounters) != 1 || (ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 30) { // for the moment no in/out distinction + 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) { t.Error("Error counting units") } } @@ -1439,6 +1437,133 @@ func TestAccountGetDefaultMoneyBalance(t *testing.T) { } } +func TestAccountInitCounters(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Id: "TestTR1", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR11", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR2", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR3", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR4", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR5", + ThresholdType: TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + }, + } + 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) + } + } + t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters)) + } +} + +func TestAccountDoubleInitCounters(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Id: "TestTR1", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR11", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR2", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR3", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR4", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR5", + ThresholdType: TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + }, + } + 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) + } + } + t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters)) + } +} + /*********************************** Benchmarks *******************************/ func BenchmarkGetSecondForPrefix(b *testing.B) { diff --git a/engine/action.go b/engine/action.go index 619af3fbc..f7be99cde 100644 --- a/engine/action.go +++ b/engine/action.go @@ -60,7 +60,6 @@ const ( TOPUP = "*topup" DEBIT_RESET = "*debit_reset" DEBIT = "*debit" - RESET_COUNTER = "*reset_counter" RESET_COUNTERS = "*reset_counters" ENABLE_ACCOUNT = "*enable_account" DISABLE_ACCOUNT = "*disable_account" @@ -112,8 +111,6 @@ func getActionFunc(typ string) (actionTypeFunc, bool) { return debitResetAction, true case DEBIT: return debitAction, true - case RESET_COUNTER: - return resetCounterAction, true case RESET_COUNTERS: return resetCountersAction, true case ENABLE_ACCOUNT: @@ -354,26 +351,11 @@ func debitAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) ( return } -func resetCounterAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { - if ub == nil { - return errors.New("nil user balance") - } - //uc := ub.getUnitCounter(a.ActionType) - var uc *UnitsCounter - if uc == nil { - uc = &UnitsCounter{BalanceType: a.BalanceType} - ub.UnitCounters = append(ub.UnitCounters, uc) - } - uc.initBalances(ub.ActionTriggers) - return -} - func resetCountersAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { if ub == nil { return errors.New("nil user balance") } - ub.UnitCounters = make([]*UnitsCounter, 0) - ub.initCounters() + ub.UnitCounters.resetCounters(a) return } @@ -422,7 +404,7 @@ func genericReset(ub *Account) error { for k, _ := range ub.BalanceMap { ub.BalanceMap[k] = BalanceChain{&Balance{Value: 0}} } - ub.UnitCounters = make([]*UnitsCounter, 0) + ub.UnitCounters = make(UnitCounters, 0) ub.ResetActionTriggers(nil) return nil } diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 54f225d6b..7ab63c864 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -157,6 +157,7 @@ func (at *ActionTrigger) Clone() *ActionTrigger { func (at *ActionTrigger) CreateBalance() *Balance { return &Balance{ + Id: at.Id, Directions: at.BalanceDirections, ExpirationDate: at.BalanceExpirationDate, DestinationIds: at.BalanceDestinationIds, diff --git a/engine/actions_test.go b/engine/actions_test.go index 28c15dcf8..320977ae3 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -649,7 +649,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) @@ -662,7 +662,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { ub := &Account{ Id: "TEST_UB", BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}}, - UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) @@ -675,7 +675,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, &Action{BalanceType: utils.SMS}, nil) @@ -688,7 +688,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } allowNegativeAction(ub, nil, nil, nil) @@ -702,7 +702,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } denyNegativeAction(ub, nil, nil, nil) @@ -716,7 +716,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) @@ -734,7 +734,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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) @@ -750,7 +750,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}} @@ -827,7 +827,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.VOICE, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}} @@ -846,7 +846,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}} @@ -864,7 +864,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.VOICE, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}} @@ -883,7 +883,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}} @@ -901,7 +901,7 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, + UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.VOICE, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}} @@ -925,22 +925,23 @@ func TestActionResetAllCounters(t *testing.T) { utils.VOICE: BalanceChain{ &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)}}}, - UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: "*max_counter", BalanceType: utils.MONETARY, ThresholdValue: 2, BalanceDestinationIds: utils.NewStringMap("NAT"), BalanceWeight: 20, ActionsId: "TEST_ACTIONS", Executed: true}}, + + ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: TRIGGER_MAX_EVENT_COUNTER, BalanceType: utils.MONETARY, ThresholdValue: 2, BalanceDestinationIds: utils.NewStringMap("NAT"), BalanceWeight: 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) != 2 || + len(ub.UnitCounters[0].Balances) != 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) + t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[0], ub.UnitCounters[0].Balances[0]) } if len(ub.UnitCounters) < 1 { t.FailNow() } - mb := ub.UnitCounters[0].Balances[1] + mb := ub.UnitCounters[0].Balances[0] if mb.Weight != 20 || mb.GetValue() != 0 || mb.DestinationIds["NAT"] == false { t.Errorf("Balance cloned incorrectly: %+v", mb) } @@ -953,11 +954,11 @@ func TestActionResetCounterOnlyDefault(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")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}}, - UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdType: "*max_counter", ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdType: TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.MONETARY} - resetCounterAction(ub, nil, a, nil) + ub.InitCounters() + resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 || len(ub.UnitCounters) != 1 || @@ -973,7 +974,7 @@ func TestActionResetCounterOnlyDefault(t *testing.T) { t.FailNow() } mb := ub.UnitCounters[0].Balances[0] - if mb.Weight != 0 || mb.GetValue() != 0 || mb.DestinationIds[utils.ANY] != true { + if mb.Weight != 0 || mb.GetValue() != 0 || len(mb.DestinationIds) != 0 { t.Errorf("Balance cloned incorrectly: %+v!", mb) } } @@ -983,11 +984,11 @@ 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: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}, &UnitsCounter{BalanceType: utils.SMS, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, + 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)}}}}, ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: utils.MONETARY} - resetCounterAction(ub, nil, a, nil) + resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 || len(ub.UnitCounters) != 2 || diff --git a/engine/balances.go b/engine/balances.go index a93b2e87e..4f9d055f1 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -70,11 +70,11 @@ func (b *Balance) Equal(o *Balance) bool { b.Disabled == o.Disabled } -func (b *Balance) MatchFilter(o *Balance) bool { - if o.Uuid != "" { +func (b *Balance) MatchFilter(o *Balance, skipIds bool) bool { + if !skipIds && o.Uuid != "" { return b.Uuid == o.Uuid } - if o.Id != "" { + if !skipIds && o.Id != "" { return b.Id == o.Id } if len(b.DestinationIds) == 0 { diff --git a/engine/balances_test.go b/engine/balances_test.go index 608db65ba..163ab79ec 100644 --- a/engine/balances_test.go +++ b/engine/balances_test.go @@ -91,7 +91,7 @@ func TestBalanceEqual(t *testing.T) { func TestBalanceMatchFilter(t *testing.T) { mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "", DestinationIds: utils.StringMap{}} - if !mb1.MatchFilter(mb2) { + if !mb1.MatchFilter(mb2, false) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } } @@ -99,7 +99,7 @@ func TestBalanceMatchFilter(t *testing.T) { func TestBalanceMatchFilterEmpty(t *testing.T) { mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} mb2 := &Balance{} - if !mb1.MatchFilter(mb2) { + if !mb1.MatchFilter(mb2, false) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } } @@ -107,7 +107,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 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} - if !mb1.MatchFilter(mb2) { + if !mb1.MatchFilter(mb2, false) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } } @@ -115,7 +115,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 := &Balance{Id: "T2", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} - if mb1.MatchFilter(mb2) { + if mb1.MatchFilter(mb2, false) { t.Errorf("Match filter failure: %+v != %+v", mb1, mb2) } } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 9ec034544..dd01947a9 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -183,9 +183,9 @@ POST_AT,NEG,*asap,10 actionTriggers = ` STANDARD_TRIGGER,st0,*min_event_counter,10,false,0,,*voice,*out,,GERMANY_O2,,,,,,,,SOME_1,10 -STANDARD_TRIGGER,st1,*max_event_balance,200,false,0,,*voice,*out,,GERMANY,,,,,,,,SOME_2,10 -STANDARD_TRIGGERS,,*min_event_balance,2,false,0,,*monetary,*out,,,,,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,,*max_event_balance,20,false,0,,*monetary,*out,,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGER,st1,*max_balance,200,false,0,,*voice,*out,,GERMANY,,,,,,,,SOME_2,10 +STANDARD_TRIGGERS,,*min_balance,2,false,0,,*monetary,*out,,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,,*max_balance,20,false,0,,*monetary,*out,,,,,,,,,,LOG_WARNING,10 STANDARD_TRIGGERS,,*max_event_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,,,LOG_WARNING,10 CDRST1_WARN_ASR,,*min_asr,45,true,1h,,,,,,,,,,,,3,CDRST_WARN_HTTP,10 CDRST1_WARN_ACD,,*min_acd,10,true,1h,,,,,,,,,,,,5,CDRST_WARN_HTTP,10 diff --git a/engine/storage_test.go b/engine/storage_test.go index 3332cec8b..306c9289b 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -275,7 +275,7 @@ func TestDifferentUuid(t *testing.T) { /************************** Benchmarks *****************************/ func GetUB() *Account { - uc := &UnitsCounter{ + uc := &UnitCounter{ BalanceType: utils.SMS, Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}, } @@ -294,7 +294,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: []*UnitsCounter{uc, uc}, + UnitCounters: UnitCounters{uc, uc}, ActionTriggers: ActionTriggers{at, at, at}, } return ub diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 75165cd84..3c2ef32fe 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -517,8 +517,8 @@ func (tpr *TpReader) LoadActions() (err error) { Categories: utils.ParseStringMap(tpact.Categories), Directions: utils.ParseStringMap(tpact.Directions), DestinationIds: utils.ParseStringMap(tpact.DestinationIds), - SharedGroups: utils.ParseStringMap(tpact.SharedGroups), - TimingIDs: utils.ParseStringMap(tpact.TimingTags), + SharedGroups: utils.ParseStringMap(tpact.SharedGroups), + TimingIDs: utils.ParseStringMap(tpact.TimingTags), }, } // load action timings from tags @@ -624,7 +624,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { BalanceTimingTags: utils.ParseStringMap(atr.BalanceTimingTags), BalanceRatingSubject: atr.BalanceRatingSubject, BalanceCategories: utils.ParseStringMap(atr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(atr.BalanceSharedGroups), + BalanceSharedGroups: utils.ParseStringMap(atr.BalanceSharedGroups), Weight: atr.Weight, ActionsId: atr.ActionsId, MinQueuedItems: atr.MinQueuedItems, @@ -762,7 +762,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error BalanceExpirationDate: expTime, BalanceRatingSubject: apiAtr.BalanceRatingSubject, BalanceCategories: utils.ParseStringMap(apiAtr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), + BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), Weight: apiAtr.Weight, ActionsId: apiAtr.ActionsId, } @@ -808,8 +808,8 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error RatingSubject: tpact.RatingSubject, Directions: utils.ParseStringMap(tpact.Directions), DestinationIds: utils.ParseStringMap(tpact.DestinationIds), - SharedGroups: utils.ParseStringMap(tpact.SharedGroups), - TimingIDs: utils.ParseStringMap(tpact.TimingTags), + SharedGroups: utils.ParseStringMap(tpact.SharedGroups), + TimingIDs: utils.ParseStringMap(tpact.TimingTags), }, } } @@ -830,7 +830,8 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error } } ub.ActionTriggers = actionTriggers.Clone() - + // init counters + ub.InitCounters() if err := tpr.accountingStorage.SetAccount(ub); err != nil { return err } @@ -966,8 +967,8 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { BalanceExpirationDate: expTime, BalanceRatingSubject: apiAtr.BalanceRatingSubject, BalanceCategories: utils.ParseStringMap(apiAtr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), - BalanceTimingTags: utils.ParseStringMap(apiAtr.BalanceTimingTags), + BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), + BalanceTimingTags: utils.ParseStringMap(apiAtr.BalanceTimingTags), Weight: apiAtr.Weight, ActionsId: apiAtr.ActionsId, } @@ -1022,8 +1023,8 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { RatingSubject: tpact.RatingSubject, Directions: utils.ParseStringMap(tpact.Directions), DestinationIds: utils.ParseStringMap(tpact.DestinationIds), - SharedGroups: utils.ParseStringMap(tpact.SharedGroups), - TimingIDs: utils.ParseStringMap(tpact.TimingTags), + SharedGroups: utils.ParseStringMap(tpact.SharedGroups), + TimingIDs: utils.ParseStringMap(tpact.TimingTags), }, } } diff --git a/engine/units_counter.go b/engine/units_counter.go index 2cc4b9304..b07065eed 100644 --- a/engine/units_counter.go +++ b/engine/units_counter.go @@ -18,35 +18,16 @@ along with this program. If not, see package engine -import ( - "log" - "strings" - - "github.com/cgrates/cgrates/utils" -) +import "github.com/cgrates/cgrates/utils" // Amount of a trafic of a certain type -type UnitsCounter struct { +type UnitCounter struct { BalanceType string // *monetary/*voice/*sms/etc CounterType string // *event or *balance Balances BalanceChain // first balance is the general one (no destination) } -// clears balances for this counter -// makes sure there are balances for all action triggers -func (uc *UnitsCounter) initBalances(ats []*ActionTrigger) { - uc.Balances = BalanceChain{} - for _, at := range ats { - if !strings.Contains(at.ThresholdType, "counter") || - at.BalanceType != uc.BalanceType { - // only get actions for counter type action triggers and with the same type - continue - } - uc.Balances = append(uc.Balances, at.CreateBalance()) - } -} - -type UnitCounters []*UnitsCounter +type UnitCounters []*UnitCounter func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *Balance) { for _, uc := range ucs { @@ -58,11 +39,10 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B } for _, bal := range uc.Balances { if uc.CounterType == utils.COUNTER_EVENT && cc != nil && bal.MatchCCFilter(cc) { - log.Print("MATCHCC") bal.AddValue(amount) continue } - if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bal) { + if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bal, true) { bal.AddValue(amount) continue } @@ -70,3 +50,16 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B } } + +func (ucs UnitCounters) resetCounters(a *Action) { + for _, uc := range ucs { + if a != nil && a.BalanceType != "" && a.BalanceType != uc.BalanceType { + continue + } + for _, b := range uc.Balances { + if a == nil || a.Balance == nil || b.MatchFilter(a.Balance, false) { + b.Value = 0 + } + } + } +} diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go index 48ff87578..a8ec56785 100644 --- a/engine/units_counter_test.go +++ b/engine/units_counter_test.go @@ -25,7 +25,7 @@ import ( ) func TestUnitsCounterAddBalance(t *testing.T) { - uc := &UnitsCounter{ + uc := &UnitCounter{ BalanceType: utils.SMS, Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}, } @@ -36,7 +36,7 @@ func TestUnitsCounterAddBalance(t *testing.T) { } func TestUnitsCounterAddBalanceExists(t *testing.T) { - uc := &UnitsCounter{ + 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")}}, } @@ -45,3 +45,203 @@ func TestUnitsCounterAddBalanceExists(t *testing.T) { t.Error("Error adding minute bucket!") } } + +func TestUnitCountersCountAllMonetary(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Id: "TestTR1", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR11", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR2", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR3", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR4", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR5", + ThresholdType: TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + }, + } + 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) + } + } + t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters)) + } +} + +func TestUnitCountersCountAllMonetaryId(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Id: "TestTR1", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR11", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 20, + }, + &ActionTrigger{ + Id: "TestTR2", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR3", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR4", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR5", + ThresholdType: TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + }, + } + 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) + } + } + t.Errorf("Error adding unit counters: %v", len(a.UnitCounters)) + } +} + +func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Id: "TestTR1", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR11", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 20, + }, + &ActionTrigger{ + Id: "TestTR2", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceDestinationIds: utils.NewStringMap("NAT"), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR22", + ThresholdType: TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDestinationIds: utils.NewStringMap("RET"), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR3", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR4", + ThresholdType: TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + &ActionTrigger{ + Id: "TestTR5", + ThresholdType: TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT), + BalanceWeight: 10, + }, + }, + } + 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) + } + } + t.Errorf("Error adding unit counters: %v", len(a.UnitCounters)) + } +}