diff --git a/engine/account.go b/engine/account.go
index cc535a7e1..90b7ce49b 100644
--- a/engine/account.go
+++ b/engine/account.go
@@ -22,6 +22,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "log"
"time"
"github.com/cgrates/cgrates/cache2go"
@@ -32,10 +33,12 @@ import (
const (
// action trigger threshold types
- TRIGGER_MIN_COUNTER = "*min_counter"
- TRIGGER_MAX_COUNTER = "*max_counter"
- TRIGGER_MIN_BALANCE = "*min_balance"
- TRIGGER_MAX_BALANCE = "*max_balance"
+ TRIGGER_MIN_EVENT_COUNTER = "*min_event_counter"
+ TRIGGER_MIN_BALANCE_COUNTER = "*min_balance_counter"
+ TRIGGER_MAX_EVENT_COUNTER = "*max_event_counter"
+ TRIGGER_MAX_BALANCE_COUNTER = "*max_balance_counter"
+ TRIGGER_MIN_BALANCE = "*min_balance"
+ TRIGGER_MAX_BALANCE = "*max_balance"
)
/*
@@ -45,7 +48,7 @@ This can represent a user or a shared group.
type Account struct {
Id string
BalanceMap map[string]BalanceChain
- UnitCounters []*UnitsCounter
+ UnitCounters UnitCounters
ActionTriggers ActionTriggers
AllowNegative bool
Disabled bool
@@ -407,7 +410,15 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo
increment.BalanceInfo.AccountId = ub.Id
increment.paid = true
if count {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{leftCC.Direction: true}, Value: cost, DestinationIds: utils.NewStringMap(leftCC.Destination)}})
+ ub.countUnits(
+ cost,
+ utils.MONETARY,
+ leftCC,
+ &Balance{
+ Directions: utils.StringMap{leftCC.Direction: true},
+ Value: cost,
+ DestinationIds: utils.NewStringMap(leftCC.Destination),
+ })
}
}
}
@@ -441,15 +452,17 @@ func (ub *Account) GetDefaultMoneyBalance() *Balance {
return defaultBalance
}
-func (ub *Account) refundIncrement(increment *Increment, unitType string, count bool) {
+func (ub *Account) refundIncrement(increment *Increment, cd *CallDescriptor, count bool) {
var balance *Balance
+ unitType := cd.TOR
+ cc := cd.CreateCallCost()
if increment.BalanceInfo.UnitBalanceUuid != "" {
if balance = ub.BalanceMap[unitType].GetBalance(increment.BalanceInfo.UnitBalanceUuid); balance == nil {
return
}
balance.AddValue(increment.Duration.Seconds())
if count {
- ub.countUnits(&Action{BalanceType: unitType, Balance: &Balance{Value: -increment.Duration.Seconds()}})
+ ub.countUnits(-increment.Duration.Seconds(), unitType, cc, balance)
}
}
// check money too
@@ -459,7 +472,7 @@ func (ub *Account) refundIncrement(increment *Increment, unitType string, count
}
balance.AddValue(increment.Cost)
if count {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: -increment.Cost}})
+ ub.countUnits(-increment.Cost, utils.MONETARY, cc, balance)
}
}
}
@@ -468,9 +481,9 @@ func (ub *Account) refundIncrement(increment *Increment, unitType string, count
func (ub *Account) executeActionTriggers(a *Action) {
ub.ActionTriggers.Sort()
for _, at := range ub.ActionTriggers {
+ limit, counter, kind := at.GetThresholdTypeInfo()
// sanity check
- if !strings.Contains(at.ThresholdType, "counter") &&
- !strings.Contains(at.ThresholdType, "balance") {
+ if kind != "counter" && kind != "balance" {
continue
}
if at.Executed {
@@ -483,9 +496,11 @@ func (ub *Account) executeActionTriggers(a *Action) {
}
if strings.Contains(at.ThresholdType, "counter") {
for _, uc := range ub.UnitCounters {
- if uc.BalanceType == at.BalanceType {
+ if uc.BalanceType == at.BalanceType &&
+ uc.CounterType == counter {
for _, mb := range uc.Balances {
- if strings.Contains(at.ThresholdType, "*max") {
+ if limit == "*max" {
+ log.Print("HERE: ", mb.MatchActionTrigger(at))
if mb.MatchActionTrigger(at) && mb.GetValue() >= at.ThresholdValue {
// run the actions
at.Execute(ub, nil)
@@ -504,7 +519,7 @@ func (ub *Account) executeActionTriggers(a *Action) {
if !b.dirty { // do not check clean balances
continue
}
- if strings.Contains(at.ThresholdType, "*max") {
+ if limit == "*max" {
if b.MatchActionTrigger(at) && b.GetValue() >= at.ThresholdValue {
// run the actions
at.Execute(ub, nil)
@@ -542,27 +557,9 @@ func (ub *Account) SetRecurrent(a *Action, recurrent bool) {
}
}
-// Returns the unit counter that matches the specified action type
-func (ub *Account) getUnitCounter(a *Action) *UnitsCounter {
- for _, uc := range ub.UnitCounters {
- if uc.BalanceType == a.BalanceType {
- return uc
- }
- }
- return nil
-}
-
-// Increments the counter for the type specified in the received Action
-// with the actions values
-func (ub *Account) countUnits(a *Action) {
- unitsCounter := ub.getUnitCounter(a)
- // if not found add the counter
- if unitsCounter == nil {
- unitsCounter = &UnitsCounter{BalanceType: a.BalanceType}
- ub.UnitCounters = append(ub.UnitCounters, unitsCounter)
- }
-
- unitsCounter.addUnits(a.Balance.GetValue(), a.Balance.DestinationIds) // DestinationIds is actually a destination (number or prefix)
+// 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)
}
@@ -577,16 +574,16 @@ func (acc *Account) initCounters() {
}
uc, exists := ucTempMap[at.BalanceType]
if !exists {
- uc = &UnitsCounter{BalanceType: at.BalanceType}
+ _, ct, _ := at.GetThresholdTypeInfo()
+ uc = &UnitsCounter{
+ BalanceType: at.BalanceType,
+ CounterType: ct,
+ }
ucTempMap[at.BalanceType] = uc
- uc.Balances = BalanceChain{&Balance{}} // init chain with default balance
+ uc.Balances = BalanceChain{}
acc.UnitCounters = append(acc.UnitCounters, uc)
}
- b := at.CreateBalance()
- if !uc.Balances.HasBalance(b) {
- uc.Balances = append(uc.Balances, b)
- }
- //uc.Balances.Sort() // do not sort, default balance first
+ uc.Balances = append(uc.Balances, at.CreateBalance())
}
}
@@ -681,7 +678,7 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance
b.SubstractValue(connectFee)
// the conect fee is not refundable!
if count {
- acc.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: connectFee, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ acc.countUnits(connectFee, utils.MONETARY, cc, b)
}
connectFeePaid = true
break
@@ -690,10 +687,11 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance
// debit connect fee
if connectFee > 0 && !connectFeePaid {
// there are no money for the connect fee; go negative
- acc.GetDefaultMoneyBalance().SubstractValue(connectFee)
+ b := acc.GetDefaultMoneyBalance()
+ b.SubstractValue(connectFee)
// the conect fee is not refundable!
if count {
- acc.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: connectFee, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ acc.countUnits(connectFee, utils.MONETARY, cc, b)
}
}
}
diff --git a/engine/account_test.go b/engine/account_test.go
index 799177a78..4712b5a69 100644
--- a/engine/account_test.go
+++ b/engine/account_test.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package engine
import (
+ "log"
"testing"
"time"
@@ -889,20 +890,22 @@ func TestAccountExecuteTriggeredActions(t *testing.T) {
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}}}}},
- ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_COUNTER, ActionsId: "TEST_ACTIONS"}},
+ ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}})
+ 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())
}
// are set to executed
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(1, utils.MONETARY, nil, nil)
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())
}
// we can reset them
ub.ResetActionTriggers(nil)
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, nil)
if ub.BalanceMap[utils.MONETARY][0].GetValue() != 120 || ub.BalanceMap[utils.VOICE][0].GetValue() != 30 {
t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue())
}
@@ -913,9 +916,9 @@ func TestAccountExecuteTriggeredActionsBalance(t *testing.T) {
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}}}},
- ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 100, ThresholdType: TRIGGER_MIN_COUNTER, ActionsId: "TEST_ACTIONS"}},
+ ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 100, ThresholdType: TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 1}})
+ ub.countUnits(1, utils.MONETARY, nil, nil)
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(), len(ub.BalanceMap[utils.MONETARY]))
}
@@ -926,9 +929,9 @@ func TestAccountExecuteTriggeredActionsOrder(t *testing.T) {
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)}}}},
- ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
+ ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 1}})
+ ub.countUnits(1, utils.MONETARY, nil, 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])
@@ -957,11 +960,11 @@ func TestCleanExpired(t *testing.T) {
func TestAccountUnitCounting(t *testing.T) {
ub := &Account{}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, 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(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
t.Error("Error counting units")
}
@@ -969,15 +972,15 @@ func TestAccountUnitCounting(t *testing.T) {
func TestAccountUnitCountingOutbound(t *testing.T) {
ub := &Account{}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, 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(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, 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(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ 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 {
t.Error("Error counting units")
}
@@ -985,15 +988,15 @@ func TestAccountUnitCountingOutbound(t *testing.T) {
func TestAccountUnitCountingOutboundInbound(t *testing.T) {
ub := &Account{}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10}})
+ ub.countUnits(1, utils.MONETARY, nil, 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])
}
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}})
+ ub.countUnits(10, utils.MONETARY, nil, 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(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.IN)}})
+ 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
t.Error("Error counting units")
}
@@ -1017,7 +1020,7 @@ func TestAccountRefund(t *testing.T) {
&Increment{Duration: 4 * time.Second, BalanceInfo: &BalanceInfo{UnitBalanceUuid: "minuteb", MoneyBalanceUuid: ""}},
}
for _, increment := range increments {
- ub.refundIncrement(increment, utils.VOICE, false)
+ ub.refundIncrement(increment, &CallDescriptor{TOR: utils.VOICE}, false)
}
if ub.BalanceMap[utils.MONETARY][0].GetValue() != 104 ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 13 ||
diff --git a/engine/action.go b/engine/action.go
index 0a2e9d592..619af3fbc 100644
--- a/engine/action.go
+++ b/engine/action.go
@@ -358,7 +358,8 @@ func resetCounterAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Act
if ub == nil {
return errors.New("nil user balance")
}
- uc := ub.getUnitCounter(a)
+ //uc := ub.getUnitCounter(a.ActionType)
+ var uc *UnitsCounter
if uc == nil {
uc = &UnitsCounter{BalanceType: a.BalanceType}
ub.UnitCounters = append(ub.UnitCounters, uc)
diff --git a/engine/action_trigger.go b/engine/action_trigger.go
index 919a895c8..54f225d6b 100644
--- a/engine/action_trigger.go
+++ b/engine/action_trigger.go
@@ -23,6 +23,7 @@ import (
"fmt"
"regexp"
"sort"
+ "strings"
"time"
"github.com/cgrates/cgrates/utils"
@@ -36,7 +37,7 @@ type ActionTrigger struct {
Recurrent bool // reset eexcuted flag each run
MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers
BalanceId string
- BalanceType string
+ BalanceType string // *monetary/*voice etc
BalanceDirections utils.StringMap // filter for balance
BalanceDestinationIds utils.StringMap // filter for balance
BalanceWeight float64 // filter for balance
@@ -53,6 +54,14 @@ type ActionTrigger struct {
lastExecutionTime time.Time
}
+func (at *ActionTrigger) GetThresholdTypeInfo() (limit, counter, kind string) {
+ slice := strings.Split(at.ThresholdType, "_")
+ if len(slice) != 3 {
+ return "", "", ""
+ }
+ return slice[0], "*" + slice[1], slice[2]
+}
+
func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err error) {
// check for min sleep time
if at.Recurrent && !at.lastExecutionTime.IsZero() && time.Since(at.lastExecutionTime) < at.MinSleep {
diff --git a/engine/actions_test.go b/engine/actions_test.go
index 75233f9a1..28c15dcf8 100644
--- a/engine/actions_test.go
+++ b/engine/actions_test.go
@@ -610,7 +610,7 @@ func TestActionTriggerMatcAllFalse(t *testing.T) {
ThresholdType: TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
- a := &Action{BalanceType: utils.VOICE, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, TRIGGER_MAX_COUNTER, 3)}
+ a := &Action{BalanceType: utils.VOICE, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, TRIGGER_MAX_EVENT_COUNTER, 3)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
diff --git a/engine/balances.go b/engine/balances.go
index f5a565656..a93b2e87e 100644
--- a/engine/balances.go
+++ b/engine/balances.go
@@ -93,6 +93,40 @@ func (b *Balance) MatchFilter(o *Balance) bool {
(o.RatingSubject == "" || 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
@@ -364,7 +398,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
inc.Cost = 0
inc.paid = true
if count {
- ub.countUnits(&Action{BalanceType: cc.TOR, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: amount, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(amount, cc.TOR, cc, b)
}
} else {
inc.paid = false
@@ -428,7 +462,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
inc.BalanceInfo.AccountId = ub.Id
inc.paid = true
if count {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: cost, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(cost, utils.MONETARY, cc, b)
}
// go to nextincrement
continue
@@ -452,9 +486,9 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
}
inc.paid = true
if count {
- ub.countUnits(&Action{BalanceType: cc.TOR, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: amount, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(amount, cc.TOR, cc, b)
if cost != 0 {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: cost, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(cost, utils.MONETARY, cc, moneyBal)
}
}
} else {
@@ -529,7 +563,7 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun
inc.BalanceInfo.AccountId = ub.Id
inc.paid = true
if count {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: amount, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(amount, utils.MONETARY, cc, b)
}
//log.Printf("TS: %+v", cc.Cost)
@@ -544,7 +578,7 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun
inc.BalanceInfo.AccountId = ub.Id
inc.paid = true
if count {
- ub.countUnits(&Action{BalanceType: utils.MONETARY, Balance: &Balance{Directions: utils.StringMap{cc.Direction: true}, Value: amount, DestinationIds: utils.StringMap{cc.Destination: true}}})
+ ub.countUnits(amount, utils.MONETARY, cc, b)
}
} else {
inc.paid = false
diff --git a/engine/calldesc.go b/engine/calldesc.go
index d0c4517ff..fe9db8c9f 100644
--- a/engine/calldesc.go
+++ b/engine/calldesc.go
@@ -709,7 +709,7 @@ func (cd *CallDescriptor) RefundIncrements() (left float64, err error) {
defer accountingStorage.SetAccount(account)
}
}
- account.refundIncrement(increment, cd.TOR, true)
+ account.refundIncrement(increment, cd, true)
}
return 0.0, err
}
diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go
index 84b6069f4..9ec034544 100644
--- a/engine/loader_csv_test.go
+++ b/engine/loader_csv_test.go
@@ -182,11 +182,11 @@ POST_AT,NEG,*asap,10
`
actionTriggers = `
-STANDARD_TRIGGER,st0,*min_counter,10,false,0,,*voice,*out,,GERMANY_O2,,,,,,,,SOME_1,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_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,,,LOG_WARNING,10
+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_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
CDRST1_WARN_ACC,,*max_acc,10,true,10m,,,,,,,,,,,,5,CDRST_WARN_HTTP,10
@@ -1010,7 +1010,7 @@ func TestLoadActionTriggers(t *testing.T) {
expected := &ActionTrigger{
BalanceType: utils.VOICE,
BalanceDirections: utils.NewStringMap(utils.OUT),
- ThresholdType: TRIGGER_MIN_COUNTER,
+ ThresholdType: TRIGGER_MIN_EVENT_COUNTER,
ThresholdValue: 10,
BalanceDestinationIds: utils.NewStringMap("GERMANY_O2"),
BalanceCategories: utils.StringMap{},
diff --git a/engine/units_counter.go b/engine/units_counter.go
index 0a4404965..2cc4b9304 100644
--- a/engine/units_counter.go
+++ b/engine/units_counter.go
@@ -19,83 +19,54 @@ along with this program. If not, see
package engine
import (
+ "log"
"strings"
- "github.com/cgrates/cgrates/cache2go"
"github.com/cgrates/cgrates/utils"
)
// Amount of a trafic of a certain type
type UnitsCounter struct {
- BalanceType string
- // Units float64
- Balances BalanceChain // first balance is the general one (no destination)
+ 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{&Balance{}} // general balance
+ 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
}
- b := at.CreateBalance()
- if !uc.Balances.HasBalance(b) {
- uc.Balances = append(uc.Balances, b)
+ uc.Balances = append(uc.Balances, at.CreateBalance())
+ }
+}
+
+type UnitCounters []*UnitsCounter
+
+func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *Balance) {
+ for _, uc := range ucs {
+ if uc.BalanceType != kind {
+ continue
}
-
- }
- //uc.Balances.Sort() // should not be sorted, leave default in first position
-}
-
-// returns the first balance that has no destination attached
-func (uc *UnitsCounter) GetGeneralBalance() *Balance {
- if len(uc.Balances) == 0 { // general balance not present for some reason
- uc.Balances = append(uc.Balances, &Balance{})
- }
- return uc.Balances[0]
-}
-
-// Adds the units from the received balance to an existing balance if the destination
-// is the same or ads the balance to the list if none matches.
-func (uc *UnitsCounter) addUnits(amount float64, prefixMap utils.StringMap) {
- counted := false
- prefix := prefixMap.String()
- if prefix != "" {
- for _, mb := range uc.Balances {
- if !mb.HasDestination() {
+ if uc.CounterType == "" {
+ uc.CounterType = utils.COUNTER_EVENT
+ }
+ for _, bal := range uc.Balances {
+ if uc.CounterType == utils.COUNTER_EVENT && cc != nil && bal.MatchCCFilter(cc) {
+ log.Print("MATCHCC")
+ bal.AddValue(amount)
continue
}
- for _, p := range utils.SplitPrefix(prefix, MIN_PREFIX_MATCH) {
- if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil {
- destIds := x.(map[interface{}]struct{})
- for key := range mb.DestinationIds {
- if _, found := destIds[key]; found {
- mb.AddValue(amount)
- counted = true
- break
- }
- if counted {
- break
- }
- }
- }
- if counted {
- break
- }
+ if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bal) {
+ bal.AddValue(amount)
+ continue
}
}
- }
- if !counted {
- // use general balance
- b := uc.GetGeneralBalance()
- b.AddValue(amount)
+
}
}
-
-/*func (uc *UnitsCounter) String() string {
- return fmt.Sprintf("%s %s %v", uc.BalanceId, uc.Direction, uc.Units)
-}*/
diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go
index 76763c41e..48ff87578 100644
--- a/engine/units_counter_test.go
+++ b/engine/units_counter_test.go
@@ -29,7 +29,7 @@ func TestUnitsCounterAddBalance(t *testing.T) {
BalanceType: utils.SMS,
Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
}
- uc.addUnits(20, utils.NewStringMap("test"))
+ UnitCounters{uc}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
if len(uc.Balances) != 3 {
t.Error("Error adding minute bucket: ", uc.Balances)
}
@@ -40,7 +40,7 @@ func TestUnitsCounterAddBalanceExists(t *testing.T) {
BalanceType: utils.SMS,
Balances: BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
}
- uc.addUnits(5, utils.NewStringMap("0723"))
+ UnitCounters{uc}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
if len(uc.Balances) != 3 || uc.Balances[1].GetValue() != 15 {
t.Error("Error adding minute bucket!")
}
diff --git a/utils/consts.go b/utils/consts.go
index ce4326b46..3e3b3ad50 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -237,6 +237,8 @@ const (
EXTRA_FIELDS = "ExtraFields"
META_SURETAX = "*sure_tax"
SURETAX = "suretax"
+ COUNTER_EVENT = "*event"
+ COUNTER_BALANCE = "*balance"
)
var (