diff --git a/engine/account.go b/engine/account.go index f8eab32fe..93cb32e36 100644 --- a/engine/account.go +++ b/engine/account.go @@ -339,12 +339,12 @@ func (ub *Account) executeActionTriggers(a *Action) { if uc.BalanceType == at.BalanceType { for _, mb := range uc.Balances { if strings.Contains(at.ThresholdType, "*max") { - if mb.MatchDestination(at.DestinationId) && mb.Value >= at.ThresholdValue { + if mb.MatchActionTrigger(at) && mb.Value >= at.ThresholdValue { // run the actions at.Execute(ub) } } else { //MIN - if mb.MatchDestination(at.DestinationId) && mb.Value <= at.ThresholdValue { + if mb.MatchActionTrigger(at) && mb.Value <= at.ThresholdValue { // run the actions at.Execute(ub) } @@ -354,13 +354,16 @@ func (ub *Account) executeActionTriggers(a *Action) { } } else { // BALANCE for _, b := range ub.BalanceMap[at.BalanceType+at.Direction] { + if !b.dirty { // do not check clean balances + continue + } if strings.Contains(at.ThresholdType, "*max") { - if b.MatchDestination(at.DestinationId) && b.Value >= at.ThresholdValue { + if b.MatchActionTrigger(at) && b.Value >= at.ThresholdValue { // run the actions at.Execute(ub) } } else { //MIN - if b.MatchDestination(at.DestinationId) && b.Value <= at.ThresholdValue { + if b.MatchActionTrigger(at) && b.Value <= at.ThresholdValue { // run the actions at.Execute(ub) } diff --git a/engine/action_trigger.go b/engine/action_trigger.go index bac755d7e..716423ad5 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -22,26 +22,29 @@ import ( "encoding/json" "fmt" "sort" + "time" "github.com/cgrates/cgrates/utils" ) type ActionTrigger struct { - Id string // uniquely identify the trigger - BalanceType string - Direction string - ThresholdType string //*min_counter, *max_counter, *min_balance, *max_balance - ThresholdValue float64 - Recurrent bool // reset eexcuted flag each run - DestinationId string - Weight float64 - ActionsId string - Executed bool + Id string // uniquely identify the trigger + BalanceType string + Direction string + ThresholdType string //*min_counter, *max_counter, *min_balance, *max_balance + ThresholdValue float64 + Recurrent bool // reset eexcuted flag each run + DestinationId string + BalanceWeight float64 + BalanceExpirationDate time.Time + Weight float64 + ActionsId string + Executed bool } func (at *ActionTrigger) Execute(ub *Account) (err error) { if ub.Disabled { - return fmt.Errorf("User %s is disabled", ub.Id) + return fmt.Errorf("User %s is disabled and there are triggers in action!", ub.Id) } // does NOT need to Lock() because it is triggered from a method that took the Lock var aac Actions diff --git a/engine/actions_test.go b/engine/actions_test.go index 048844c11..6d1cda925 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -827,7 +827,7 @@ func TestActionResetCounterMinutes(t *testing.T) { CREDIT: BalanceChain{&Balance{Value: 100}}, MINUTES: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: CREDIT, Balances: BalanceChain{&Balance{Value: 1}}}}, - ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: CREDIT, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: CREDIT, ThresholdType: "*max_counter", ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } a := &Action{BalanceType: MINUTES} resetCounterAction(ub, a) @@ -840,14 +840,14 @@ func TestActionResetCounterMinutes(t *testing.T) { for _, b := range ub.UnitCounters[1].Balances { t.Logf("B: %+v", b) } - t.Error("Reset counters action failed!", ub.UnitCounters[1]) + t.Errorf("Reset counters action failed: %+v", ub) } if len(ub.UnitCounters) < 2 || len(ub.UnitCounters[1].Balances) < 1 { t.FailNow() } mb := ub.UnitCounters[1].Balances[0] if mb.Weight != 20 || mb.Value != 0 || mb.DestinationId != "NAT" { - t.Errorf("Balance cloned incorrectly: %v!", mb) + t.Errorf("Balance cloned incorrectly: %+v!", mb) } } diff --git a/engine/balances.go b/engine/balances.go index 53259188d..0fb946792 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -74,6 +74,20 @@ func (b *Balance) MatchDestination(destinationId string) bool { return !b.HasDestination() || b.DestinationId == destinationId } +func (b *Balance) MatchActionTrigger(at *ActionTrigger) bool { + matchesExpirationDate := true + if !at.BalanceExpirationDate.IsZero() { + matchesExpirationDate = (at.BalanceExpirationDate.Equal(b.ExpirationDate)) + } + matchesWeight := true + if at.BalanceWeight > 0 { + matchesWeight = (at.BalanceWeight == b.Weight) + } + return b.MatchDestination(at.DestinationId) && + matchesExpirationDate && + matchesWeight +} + func (b *Balance) Clone() *Balance { return &Balance{ Uuid: b.Uuid, diff --git a/engine/units_counter.go b/engine/units_counter.go index 4bc76ac12..879e8699c 100644 --- a/engine/units_counter.go +++ b/engine/units_counter.go @@ -19,6 +19,8 @@ along with this program. If not, see package engine import ( + "strings" + "github.com/cgrates/cgrates/cache2go" "github.com/cgrates/cgrates/utils" ) @@ -36,6 +38,10 @@ type UnitsCounter struct { func (uc *UnitsCounter) initBalances(ats []*ActionTrigger) { uc.Balances = BalanceChain{&Balance{}} // general balance for _, at := range ats { + if !strings.Contains(at.ThresholdType, "counter") { + // only get actions fo counter type action triggers + continue + } acs, err := accountingStorage.GetActions(at.ActionsId, false) if err != nil { continue