From 8a24738b85c4b322eebdf95158f688e9f5a096c8 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 9 Feb 2016 16:19:40 +0200 Subject: [PATCH 01/15] started action balance pointer filtering --- engine/account.go | 28 +++++---- engine/action.go | 129 +++++++++++++++++++++++++++++---------- engine/action_plan.go | 6 +- engine/action_trigger.go | 49 +++++++-------- engine/balances.go | 36 +++++------ engine/models.go | 14 ++--- engine/tp_reader.go | 67 ++++++++++++++++---- glide.lock | 34 ++++++++++- utils/apitpdata.go | 36 +++++------ utils/consts.go | 1 + utils/coreutils.go | 4 ++ utils/map.go | 3 + 12 files changed, 273 insertions(+), 134 deletions(-) diff --git a/engine/account.go b/engine/account.go index 287c3ab3a..c7f5f9d7b 100644 --- a/engine/account.go +++ b/engine/account.go @@ -93,7 +93,7 @@ func (ub *Account) setBalanceAction(a *Action) error { if a == nil { return errors.New("nil action") } - bClone := a.Balance.Clone() + bClone := a.Balance.CreateBalance() if bClone == nil { return errors.New("nil balance") } @@ -182,7 +182,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error { if a == nil { return errors.New("nil action") } - bClone := a.Balance.Clone() + bClone := a.Balance.CreateBalance() if bClone == nil { return errors.New("nil balance") } @@ -261,6 +261,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error { return nil } +/* func (ub *Account) enableDisableBalanceAction(a *Action) error { if a == nil { return errors.New("nil action") @@ -286,7 +287,7 @@ func (ub *Account) enableDisableBalanceAction(a *Action) error { } return nil } - +*/ func (ub *Account) getBalancesForPrefix(prefix, category, direction, tor string, sharedGroup string) BalanceChain { var balances BalanceChain balances = append(balances, ub.BalanceMap[tor]...) @@ -933,23 +934,24 @@ func (acc *Account) AsOldStructure() interface{} { } } for i, at := range acc.ActionTriggers { + b := at.Balance.CreateBalance() result.ActionTriggers[i] = &ActionTrigger{ Id: at.ID, ThresholdType: at.ThresholdType, ThresholdValue: at.ThresholdValue, Recurrent: at.Recurrent, MinSleep: at.MinSleep, - BalanceId: at.BalanceId, BalanceType: at.BalanceType, - BalanceDirection: at.BalanceDirections.String(), - BalanceDestinationIds: at.BalanceDestinationIds.String(), - BalanceWeight: at.BalanceWeight, - BalanceExpirationDate: at.BalanceExpirationDate, - BalanceTimingTags: at.BalanceTimingTags.String(), - BalanceRatingSubject: at.BalanceRatingSubject, - BalanceCategory: at.BalanceCategories.String(), - BalanceSharedGroup: at.BalanceSharedGroups.String(), - BalanceDisabled: at.BalanceDisabled, + BalanceId: b.Id, + BalanceDirection: b.Directions.String(), + BalanceDestinationIds: b.DestinationIds.String(), + BalanceWeight: b.Weight, + BalanceExpirationDate: b.ExpirationDate, + BalanceTimingTags: b.TimingIDs.String(), + BalanceRatingSubject: b.RatingSubject, + BalanceCategory: b.Categories.String(), + BalanceSharedGroup: b.SharedGroups.String(), + BalanceDisabled: b.Disabled, Weight: at.Weight, ActionsId: at.ActionsId, MinQueuedItems: at.MinQueuedItems, diff --git a/engine/action.go b/engine/action.go index 00e23bcb5..8e6264bd5 100644 --- a/engine/action.go +++ b/engine/action.go @@ -45,28 +45,93 @@ type Action struct { Filter string ExpirationString string // must stay as string because it can have relative values like 1month Weight float64 - Balance *Balance + Balance *BalancePointer +} + +type BalancePointer struct { + Uuid *string + Id *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 *BalancePointer) 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() } const ( - LOG = "*log" - RESET_TRIGGERS = "*reset_triggers" - SET_RECURRENT = "*set_recurrent" - UNSET_RECURRENT = "*unset_recurrent" - ALLOW_NEGATIVE = "*allow_negative" - DENY_NEGATIVE = "*deny_negative" - RESET_ACCOUNT = "*reset_account" - REMOVE_ACCOUNT = "*remove_account" - SET_BALANCE = "*set_balance" // not ready for production until switching to pointers - REMOVE_BALANCE = "*remove_balance" - TOPUP_RESET = "*topup_reset" - TOPUP = "*topup" - DEBIT_RESET = "*debit_reset" - DEBIT = "*debit" - RESET_COUNTERS = "*reset_counters" - ENABLE_ACCOUNT = "*enable_account" - DISABLE_ACCOUNT = "*disable_account" - ENABLE_DISABLE_BALANCE = "*enable_disable_balance" + LOG = "*log" + RESET_TRIGGERS = "*reset_triggers" + SET_RECURRENT = "*set_recurrent" + UNSET_RECURRENT = "*unset_recurrent" + ALLOW_NEGATIVE = "*allow_negative" + DENY_NEGATIVE = "*deny_negative" + RESET_ACCOUNT = "*reset_account" + REMOVE_ACCOUNT = "*remove_account" + SET_BALANCE = "*set_balance" // not ready for production until switching to pointers + REMOVE_BALANCE = "*remove_balance" + TOPUP_RESET = "*topup_reset" + TOPUP = "*topup" + DEBIT_RESET = "*debit_reset" + DEBIT = "*debit" + RESET_COUNTERS = "*reset_counters" + ENABLE_ACCOUNT = "*enable_account" + DISABLE_ACCOUNT = "*disable_account" + //ENABLE_DISABLE_BALANCE = "*enable_disable_balance" CALL_URL = "*call_url" CALL_URL_ASYNC = "*call_url_async" MAIL_ASYNC = "*mail_async" @@ -84,7 +149,7 @@ func (a *Action) Clone() *Action { ExtraParameters: a.ExtraParameters, ExpirationString: a.ExpirationString, Weight: a.Weight, - Balance: a.Balance.Clone(), + Balance: a.Balance, } } @@ -122,8 +187,8 @@ func getActionFunc(typ string) (actionTypeFunc, bool) { return enableUserAction, true case DISABLE_ACCOUNT: return disableUserAction, true - case ENABLE_DISABLE_BALANCE: - return enableDisableBalanceAction, true + //case ENABLE_DISABLE_BALANCE: + // return enableDisableBalanceAction, true case CALL_URL: return callUrl, true case CALL_URL_ASYNC: @@ -167,6 +232,7 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) dta = new(utils.TenantAccount) // Init with empty values } var parsedValue string // Template values + b := action.Balance.CreateBalance() for _, rsrFld := range rsrFlds { switch rsrFld.Id { case "AccountID": @@ -184,17 +250,17 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) case "BalanceType": parsedValue += rsrFld.ParseValue(action.BalanceType) case "BalanceUUID": - parsedValue += rsrFld.ParseValue(action.Balance.Uuid) + parsedValue += rsrFld.ParseValue(b.Uuid) case "BalanceID": - parsedValue += rsrFld.ParseValue(action.Balance.Id) + parsedValue += rsrFld.ParseValue(b.Id) case "BalanceValue": - parsedValue += rsrFld.ParseValue(strconv.FormatFloat(action.Balance.GetValue(), 'f', -1, 64)) + parsedValue += rsrFld.ParseValue(strconv.FormatFloat(b.GetValue(), 'f', -1, 64)) case "DestinationIDs": - parsedValue += rsrFld.ParseValue(action.Balance.DestinationIds.String()) + parsedValue += rsrFld.ParseValue(b.DestinationIds.String()) case "ExtraParameters": parsedValue += rsrFld.ParseValue(action.ExtraParameters) case "RatingSubject": - parsedValue += rsrFld.ParseValue(action.Balance.RatingSubject) + parsedValue += rsrFld.ParseValue(b.RatingSubject) case utils.CATEGORY: parsedValue += rsrFld.ParseValue(action.Balance.Categories.String()) case "SharedGroups": @@ -370,8 +436,9 @@ func resetCountersAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Ac } func genericMakeNegative(a *Action) { - if a.Balance != nil && a.Balance.GetValue() >= 0 { // only apply if not allready negative - a.Balance.SetValue(-a.Balance.GetValue()) + b := a.Balance.CreateBalance() + if a.Balance != nil && b.GetValue() >= 0 { // only apply if not allready negative + b.SetValue(-b.GetValue()) } } @@ -401,13 +468,13 @@ func disableUserAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Acti return } -func enableDisableBalanceAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { +/*func enableDisableBalanceAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { if ub == nil { return errors.New("nil account") } ub.enableDisableBalanceAction(a) return -} +}*/ func genericReset(ub *Account) error { for k, _ := range ub.BalanceMap { diff --git a/engine/action_plan.go b/engine/action_plan.go index 3b8069c64..0a9283d25 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -308,7 +308,8 @@ func (at *ActionTiming) Execute() (err error) { //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() { - a.Balance.ExpirationDate = expDate + a.Balance.ExpirationDate = &time.Time{} + *a.Balance.ExpirationDate = expDate } actionFunction, exists := getActionFunc(a.ActionType) @@ -339,7 +340,8 @@ func (at *ActionTiming) Execute() (err error) { if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) && parseErr == nil && !expDate.IsZero() { - a.Balance.ExpirationDate = expDate + a.Balance.ExpirationDate = &time.Time{} + *a.Balance.ExpirationDate = expDate } actionFunction, exists := getActionFunc(a.ActionType) diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 71c8aed6d..d9ae7b005 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -33,28 +33,18 @@ type ActionTrigger struct { UniqueID string // individual id ThresholdType string //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *exp_balance // stats: *min_asr, *max_asr, *min_acd, *max_acd, *min_tcd, *max_tcd, *min_acc, *max_acc, *min_tcc, *max_tcc, *min_ddc, *max_ddc - ThresholdValue float64 - Recurrent bool // reset excuted flag each run - MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers - ExpirationDate time.Time - ActivationDate time.Time - BalanceId string - BalanceType string // *monetary/*voice etc - BalanceDirections utils.StringMap // filter for balance - BalanceDestinationIds utils.StringMap // filter for balance - BalanceWeight float64 // filter for balance - BalanceExpirationDate time.Time // filter for balance - BalanceTimingTags utils.StringMap // filter for balance - BalanceRatingSubject string // filter for balance - BalanceCategories utils.StringMap // filter for balance - BalanceSharedGroups utils.StringMap // filter for balance - BalanceBlocker bool - BalanceDisabled bool // filter for balance - Weight float64 - ActionsId string - MinQueuedItems int // Trigger actions only if this number is hit (stats only) - Executed bool - lastExecutionTime time.Time + ThresholdValue float64 + Recurrent bool // reset excuted flag each run + MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers + ExpirationDate time.Time + ActivationDate time.Time + BalanceType string // *monetary/*voice etc + Balance *BalancePointer + Weight float64 + ActionsId string + MinQueuedItems int // Trigger actions only if this number is hit (stats only) + Executed bool + lastExecutionTime time.Time } func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err error) { @@ -90,9 +80,12 @@ func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err erro } if a.Balance == nil { - a.Balance = &Balance{} + a.Balance = &BalancePointer{} + } + if a.ExpirationString != "" { + a.Balance.ExpirationDate = &time.Time{} + *a.Balance.ExpirationDate, _ = utils.ParseDate(a.ExpirationString) } - a.Balance.ExpirationDate, _ = utils.ParseDate(a.ExpirationString) actionFunction, exists := getActionFunc(a.ActionType) if !exists { utils.Logger.Err(fmt.Sprintf("Function type %v not available, aborting execution!", a.ActionType)) @@ -131,7 +124,7 @@ func (at *ActionTrigger) Match(a *Action) bool { return match } id := a.BalanceType == "" || at.BalanceType == a.BalanceType - thresholdType, thresholdValue, direction, destinationId, weight, ratingSubject, categories, sharedGroup, timings, blocker, disabled := true, true, true, true, true, true, true, true, true, true, true + thresholdType, thresholdValue, direction, destinationID, weight, ratingSubject, categories, sharedGroup, timings, blocker, disabled := true, true, true, true, true, true, true, true, true, true, true if a.ExtraParameters != "" { t := struct { ThresholdType string @@ -149,8 +142,8 @@ func (at *ActionTrigger) Match(a *Action) bool { json.Unmarshal([]byte(a.ExtraParameters), &t) thresholdType = t.ThresholdType == "" || at.ThresholdType == t.ThresholdType thresholdValue = t.ThresholdValue == 0 || at.ThresholdValue == t.ThresholdValue - direction = len(t.BalanceDirections) == 0 || at.BalanceDirections.Equal(utils.ParseStringMap(t.BalanceDirections)) - destinationId = len(t.DestinationIds) == 0 || at.BalanceDestinationIds.Equal(utils.ParseStringMap(t.DestinationIds)) + direction = t.Balance.Directions == nil || at.Balance.Directions.Equal(utils.ParseStringMap(t.BalanceDirections)) + destinationID = len(t.DestinationIds) == 0 || at.BalanceDestinationIds.Equal(utils.ParseStringMap(t.DestinationIds)) categories = len(t.BalanceCategories) == 0 || at.BalanceCategories.Equal(utils.ParseStringMap(t.BalanceCategories)) timings = len(t.BalanceTimingTags) == 0 || at.BalanceTimingTags.Equal(utils.ParseStringMap(t.BalanceTimingTags)) sharedGroup = len(t.BalanceSharedGroups) == 0 || at.BalanceSharedGroups.Equal(utils.ParseStringMap(t.BalanceSharedGroups)) @@ -159,7 +152,7 @@ func (at *ActionTrigger) Match(a *Action) bool { blocker = at.BalanceBlocker == t.BalanceBlocker disabled = at.BalanceDisabled == t.BalanceDisabled } - return id && direction && thresholdType && thresholdValue && destinationId && weight && ratingSubject && categories && sharedGroup && timings && blocker && disabled + return id && direction && thresholdType && thresholdValue && destinationID && weight && ratingSubject && categories && sharedGroup && timings && blocker && disabled } // makes a shallow copy of the receiver diff --git a/engine/balances.go b/engine/balances.go index e1aa16777..b1a9fba96 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -72,32 +72,26 @@ func (b *Balance) Equal(o *Balance) bool { b.Blocker == o.Blocker } -func (b *Balance) MatchFilter(o *Balance, skipIds bool) bool { +func (b *Balance) MatchFilter(o *BalancePointer, skipIds bool) bool { if o == nil { return true } - if !skipIds && o.Uuid != "" { - return b.Uuid == o.Uuid + if !skipIds && o.Uuid != nil && *o.Uuid != "" { + return b.Uuid == *o.Uuid } - if !skipIds && o.Id != "" { - return b.Id == o.Id + if !skipIds && o.Id != nil && *o.Id != "" { + return b.Id == *o.Id } - if len(b.DestinationIds) == 0 { - b.DestinationIds = utils.StringMap{utils.ANY: true} - } - if len(o.DestinationIds) == 0 { - o.DestinationIds = utils.StringMap{utils.ANY: true} - } - return (o.ExpirationDate.IsZero() || b.ExpirationDate.Equal(o.ExpirationDate)) && - (o.Weight == 0 || b.Weight == o.Weight) && - (b.Blocker == o.Blocker) && - (b.Disabled == o.Disabled) && - (len(o.DestinationIds) == 0 || b.DestinationIds.Includes(o.DestinationIds)) && - (len(o.Directions) == 0 || b.Directions.Includes(o.Directions)) && - (len(o.Categories) == 0 || b.Categories.Includes(o.Categories)) && - (len(o.TimingIDs) == 0 || b.TimingIDs.Includes(o.TimingIDs)) && - (len(o.SharedGroups) == 0 || b.SharedGroups.Includes(o.SharedGroups)) && - (o.RatingSubject == "" || b.RatingSubject == o.RatingSubject) + 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.Directions == nil || b.Directions.Includes(*o.Directions)) && + (o.Categories == nil || b.Categories.Includes(*o.Categories)) && + (o.TimingIDs == nil || b.TimingIDs.Includes(*o.TimingIDs)) && + (o.SharedGroups == nil || b.SharedGroups.Includes(*o.SharedGroups)) && + (o.RatingSubject == nil || b.RatingSubject == *o.RatingSubject) } func (b *Balance) MatchCCFilter(cc *CallCost) bool { diff --git a/engine/models.go b/engine/models.go index d16916891..a37102094 100644 --- a/engine/models.go +++ b/engine/models.go @@ -166,10 +166,10 @@ type TpAction struct { SharedGroups string `index:"10" re:"[0-9A-Za-z_;]*"` ExpiryTime string `index:"11" re:"\*\w+\s*|\+\d+[smh]\s*|\d+\s*"` TimingTags string `index:"12" re:"[0-9A-Za-z_;]*|\*any"` - Units float64 `index:"13" re:"\d+\s*"` - BalanceWeight float64 `index:"14" re:"\d+\.?\d*\s*"` - BalanceBlocker bool `index:"15" re:""` - BalanceDisabled bool `index:"16" re:""` + Units string `index:"13" re:"\d+\s*"` + BalanceWeight string `index:"14" re:"\d+\.?\d*\s*"` + BalanceBlocker string `index:"15" re:""` + BalanceDisabled string `index:"16" re:""` Weight float64 `index:"17" re:"\d+\.?\d*\s*"` CreatedAt time.Time } @@ -204,9 +204,9 @@ type TpActionTrigger struct { BalanceSharedGroups string `index:"14" re:"\w+|\*any"` BalanceExpiryTime string `index:"15" re:"\*\w+\s*|\+\d+[smh]\s*|\d+\s*"` BalanceTimingTags string `index:"16" re:"[0-9A-Za-z_;]*|\*any"` - BalanceWeight float64 `index:"17" re:"\d+\.?\d*"` - BalanceBlocker bool `index:"18" re:""` - BalanceDisabled bool `index:"19" re:""` + BalanceWeight string `index:"17" re:"\d+\.?\d*"` + BalanceBlocker string `index:"18" re:""` + BalanceDisabled string `index:"19" re:""` MinQueuedItems int `index:"20" re:"\d+"` ActionsTag string `index:"21" re:"\w+"` Weight float64 `index:"22" re:"\d+\.?\d*"` diff --git a/engine/tp_reader.go b/engine/tp_reader.go index a27a4508b..17c7706d1 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -521,20 +521,61 @@ func (tpr *TpReader) LoadActions() (err error) { ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &Balance{ - Id: tpact.BalanceId, - Value: tpact.Units, - Weight: tpact.BalanceWeight, - RatingSubject: tpact.RatingSubject, - 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), - Blocker: tpact.BalanceBlocker, - Disabled: tpact.BalanceDisabled, - }, + Balance: &BalancePointer{}, } + if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { + acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) + } + + if tpact.Units != "" && tpact.Units != utils.ANY { + u, err := strconv.ParseFloat(tpact.Units, 64) + if err != nil { + return err + } + acts[idx].Balance.Value = utils.Float64Pointer(u) + } + + if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(tpact.BalanceWeight, 64) + if err != nil { + return err + } + acts[idx].Balance.Weight = utils.Float64Pointer(u) + } + if tpact.RatingSubject != "" && tpact.RatingSubject != utils.ANY { + acts[idx].Balance.RatingSubject = utils.StringPointer(tpact.RatingSubject) + } + + if tpact.Categories != "" && tpact.Categories != utils.ANY { + acts[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(tpact.Categories)) + } + if tpact.Directions != "" && tpact.Directions != utils.ANY { + 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)) + } + if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY { + acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups)) + } + if tpact.TimingTags != "" && tpact.TimingTags != utils.ANY { + acts[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.TimingTags)) + } + if tpact.BalanceBlocker != "" && tpact.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceBlocker) + if err != nil { + return err + } + acts[idx].Balance.Blocker = utils.BoolPointer(u) + } + if tpact.BalanceDisabled != "" && tpact.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceDisabled) + if err != nil { + return err + } + acts[idx].Balance.Disabled = utils.BoolPointer(u) + } + // load action timings from tags if tpact.TimingTags != "" { timingIds := strings.Split(tpact.TimingTags, utils.INFIELD_SEP) diff --git a/glide.lock b/glide.lock index ac52fee0e..84c1f8c76 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 855bc23b0e58452edf1d31f228430476a2602b79d225397d33b805b252cebb83 -updated: 2016-01-21T12:30:17.296295607+02:00 +updated: 2016-02-05T16:54:55.433704333+02:00 imports: - name: github.com/cenkalti/hub version: 57d753b5f4856e77b3cf8ecce78c97215a7d324d @@ -25,6 +25,8 @@ imports: - diam/datatype - diam/dict - diam/sm + - diam/sm/smparser + - diam/sm/smpeer - name: github.com/go-sql-driver/mysql version: bb006fd699a123d3eb514561dbefc352e978949d - name: github.com/gorhill/cronexpr @@ -37,11 +39,15 @@ imports: version: f7ee69f31298ecbe5d2b349c711e2547a617d398 - name: github.com/lib/pq version: 11fc39a580a008f1f39bb3d11d984fb34ed778d9 + subpackages: + - hstore + - oid - name: github.com/mediocregopher/radix.v2 version: 91435107718b55ff544323a2b0f25fdd8475d283 subpackages: - /pool - redis + - pool - name: github.com/peterh/liner version: 3f1c20449d1836aa4cbe38731b96f95cdf89634d - name: github.com/ugorji/go @@ -50,18 +56,44 @@ imports: - /codec - name: golang.org/x/crypto version: 552e9d568fde9701ea1944fb01c8aadaceaa7353 + subpackages: + - ssh/terminal - name: golang.org/x/net version: 961116aeebe66bfb58bb4d51818c70d256acbbb8 subpackages: - /websocket + - context + - html/atom + - http2/hpack + - internal/iana + - ipv4 + - ipv6 + - webdav/internal/xml - name: golang.org/x/text version: cf4986612c83df6c55578ba198316d1684a9a287 + subpackages: + - encoding + - encoding/charmap + - encoding/htmlindex + - transform + - encoding/internal/identifier + - encoding/internal + - encoding/japanese + - encoding/korean + - encoding/simplifiedchinese + - encoding/traditionalchinese + - encoding/unicode + - language + - internal/utf8internal + - runes + - internal/tag - name: gopkg.in/fsnotify.v1 version: 508915b7500b6e42a87132e4afeb4729cebc7cbb - name: gopkg.in/mgo.v2 version: e30de8ac9ae3b30df7065f766c71f88bba7d4e49 subpackages: - bson + - internal/scram - name: gopkg.in/tomb.v2 version: 14b3d72120e8d10ea6e6b7f87f7175734b1faab8 devImports: [] diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 9fdabdc9a..cc4a47a53 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -273,22 +273,22 @@ type TPActions struct { } type TPAction struct { - Identifier string // Identifier mapped in the code - BalanceId string // Balance identification string (account scope) - BalanceType string // Type of balance the action will operate on - Directions string // Balance direction - Units float64 // Number of units to add/deduct - ExpiryTime string // Time when the units will expire - Filter string // The condition on balances that is checked before the action - TimingTags string // Timing when balance is active - DestinationIds string // Destination profile id - RatingSubject string // Reference a rate subject defined in RatingProfiles - Categories string // category filter for balances - SharedGroups string // Reference to a shared group - BalanceWeight float64 // Balance weight + Identifier string // Identifier mapped in the code + BalanceId string // Balance identification string (account scope) + BalanceType string // Type of balance the action will operate on + Directions string // Balance direction + Units string // Number of units to add/deduct + ExpiryTime string // Time when the units will expire + Filter string // The condition on balances that is checked before the action + TimingTags string // Timing when balance is active + DestinationIds string // Destination profile id + RatingSubject string // Reference a rate subject defined in RatingProfiles + Categories string // category filter for balances + SharedGroups string // Reference to a shared group + BalanceWeight string // Balance weight ExtraParameters string - BalanceBlocker bool - BalanceDisabled bool + BalanceBlocker string + BalanceDisabled string Weight float64 // Action's weight } @@ -486,14 +486,14 @@ type TPActionTrigger struct { BalanceType string // Type of balance this trigger monitors BalanceDirections string // Traffic direction BalanceDestinationIds string // filter for balance - BalanceWeight float64 // filter for balance + BalanceWeight string // filter for balance BalanceExpirationDate string // filter for balance BalanceTimingTags string // filter for balance BalanceRatingSubject string // filter for balance BalanceCategories string // filter for balance BalanceSharedGroups string // filter for balance - BalanceBlocker bool // filter for balance - BalanceDisabled bool // filter for balance + BalanceBlocker string // filter for balance + BalanceDisabled string // filter for balance MinQueuedItems int // Trigger actions only if this number is hit (stats only) ActionsId string // Actions which will execute on threshold reached Weight float64 // weight diff --git a/utils/consts.go b/utils/consts.go index 6f413f1f3..b1f0559f8 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -89,6 +89,7 @@ const ( ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down" ANY = "*any" + ZERO = "*zero" ASAP = "*asap" USERS = "*users" COMMENT_CHAR = '#' diff --git a/utils/coreutils.go b/utils/coreutils.go index 29f501eda..091e3fc07 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -337,6 +337,10 @@ func Fib() func() time.Duration { // Utilities to provide pointers where we need to define ad-hoc func StringPointer(str string) *string { + if str == ZERO { + str = "" + return &str + } return &str } diff --git a/utils/map.go b/utils/map.go index d303efcaf..e45488935 100644 --- a/utils/map.go +++ b/utils/map.go @@ -74,6 +74,9 @@ func NewStringMap(s ...string) StringMap { } func ParseStringMap(s string) StringMap { + if s == ZERO { + return make(StringMap) + } return StringMapFromSlice(strings.Split(s, INFIELD_SEP)) } From 7bf15bf825cd9a2249a78afc63bf29ca6f90184e Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 11 Feb 2016 10:26:43 +0200 Subject: [PATCH 02/15] engine compiling --- engine/account.go | 18 +- engine/account_test.go | 223 ++++++++++------ engine/action.go | 76 +++++- engine/action_trigger.go | 66 +---- engine/actions_local_test.go | 9 +- engine/actions_test.go | 376 +++++++++++++------------- engine/balances.go | 64 ++--- engine/balances_test.go | 28 +- engine/calldesc_test.go | 6 +- engine/loader_csv_test.go | 134 +++++----- engine/model_helpers_test.go | 20 +- engine/storage_test.go | 16 +- engine/tp_reader.go | 495 ++++++++++++++++++++++++++--------- engine/units_counter.go | 6 +- engine/units_counter_test.go | 394 ++++++++++++++++------------ utils/coreutils.go | 4 + 16 files changed, 1157 insertions(+), 778 deletions(-) diff --git a/engine/account.go b/engine/account.go index c7f5f9d7b..50650c546 100644 --- a/engine/account.go +++ b/engine/account.go @@ -111,7 +111,7 @@ func (ub *Account) setBalanceAction(a *Action) error { ub.BalanceMap = make(map[string]BalanceChain, 1) } found := false - balanceType := a.BalanceType + balanceType := a.Balance.GetType() var previousSharedGroups utils.StringMap // kept for comparison for _, b := range ub.BalanceMap[balanceType] { if b.IsExpired() { @@ -190,7 +190,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error { ub.BalanceMap = make(map[string]BalanceChain, 1) } found := false - balanceType := a.BalanceType + balanceType := a.Balance.GetType() for _, b := range ub.BalanceMap[balanceType] { if b.IsExpired() { continue // just to be safe (cleaned expired balances above) @@ -592,7 +592,7 @@ func (acc *Account) ExecuteActionTriggers(a *Action) { } if strings.Contains(at.ThresholdType, "counter") { for _, uc := range acc.UnitCounters { - if uc.BalanceType == at.BalanceType && + if uc.BalanceType == at.Balance.GetType() && strings.Contains(at.ThresholdType, uc.CounterType[1:]) { for _, b := range uc.Balances { if strings.HasPrefix(at.ThresholdType, "*max") { @@ -608,7 +608,7 @@ func (acc *Account) ExecuteActionTriggers(a *Action) { } } } else { // BALANCE - for _, b := range acc.BalanceMap[at.BalanceType] { + for _, b := range acc.BalanceMap[at.Balance.GetType()] { if !b.dirty && at.ThresholdType != utils.TRIGGER_BALANCE_EXPIRED { // do not check clean balances continue } @@ -674,17 +674,17 @@ func (acc *Account) InitCounters() { ct = utils.COUNTER_BALANCE } - uc, exists := ucTempMap[at.BalanceType+ct] + uc, exists := ucTempMap[at.Balance.GetType()+ct] if !exists { uc = &UnitCounter{ - BalanceType: at.BalanceType, + BalanceType: at.Balance.GetType(), CounterType: ct, } - ucTempMap[at.BalanceType+ct] = uc + ucTempMap[at.Balance.GetType()+ct] = uc uc.Balances = BalanceChain{} acc.UnitCounters = append(acc.UnitCounters, uc) } - b := at.CreateBalance() + b := at.Balance.CreateBalance() if !uc.Balances.HasBalance(b) { uc.Balances = append(uc.Balances, b) } @@ -941,7 +941,7 @@ func (acc *Account) AsOldStructure() interface{} { ThresholdValue: at.ThresholdValue, Recurrent: at.Recurrent, MinSleep: at.MinSleep, - BalanceType: at.BalanceType, + BalanceType: at.Balance.GetType(), BalanceId: b.Id, BalanceDirection: b.Directions.String(), BalanceDestinationIds: b.DestinationIds.String(), diff --git a/engine/account_test.go b/engine/account_test.go index 11a40f65b..b603e135d 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -814,22 +814,32 @@ func TestAccountdebitBalance(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1204}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.StringMap{"NAT": true}}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &Balance{Weight: 20, DestinationIds: utils.StringMap{"NEW": true}, Directions: utils.NewStringMap(utils.OUT)} - a := &Action{BalanceType: utils.VOICE, Balance: newMb} + newMb := &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Weight: utils.Float64Pointer(20), + 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) } } -func TestAccountDisableBalance(t *testing.T) { +/*func TestAccountDisableBalance(t *testing.T) { ub := &Account{ Id: "rif", AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1204}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &Balance{Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT), Disabled: true} - a := &Action{BalanceType: utils.VOICE, Balance: newMb} + newMb := &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Weight: utils.Float64Pointer(20), + DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + } + a := &Action{Balance: newMb} ub.enableDisableBalanceAction(a) if len(ub.BalanceMap[utils.VOICE]) != 2 || ub.BalanceMap[utils.VOICE][0].Disabled != true { for _, b := range ub.BalanceMap[utils.VOICE] { @@ -837,7 +847,7 @@ func TestAccountDisableBalance(t *testing.T) { } t.Errorf("Error disabling balance! %d %+v %+v", len(ub.BalanceMap[utils.VOICE]), ub.BalanceMap[utils.VOICE][0], newMb) } -} +}*/ func TestAccountdebitBalanceExists(t *testing.T) { @@ -846,8 +856,14 @@ func TestAccountdebitBalanceExists(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1024}}, utils.VOICE: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &Balance{Value: -10, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)} - a := &Action{BalanceType: utils.VOICE, Balance: newMb} + newMb := &BalancePointer{ + Value: utils.Float64Pointer(-10), + Type: utils.StringPointer(utils.VOICE), + Weight: utils.Float64Pointer(20), + DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + } + a := &Action{Balance: newMb} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE]) != 2 || ub.BalanceMap[utils.VOICE][0].GetValue() != 25 { t.Error("Error adding minute bucket!") @@ -867,21 +883,36 @@ func TestAccountAddMinuteNil(t *testing.T) { } func TestAccountAddMinutBucketEmpty(t *testing.T) { - mb1 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)} - mb2 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)} - mb3 := &Balance{Value: -10, DestinationIds: utils.StringMap{"OTHER": true}, Directions: utils.NewStringMap(utils.OUT)} + mb1 := &BalancePointer{ + Value: utils.Float64Pointer(-10), + Type: utils.StringPointer(utils.VOICE), + DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + } + mb2 := &BalancePointer{ + Value: utils.Float64Pointer(-10), + Type: utils.StringPointer(utils.VOICE), + DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + } + mb3 := &BalancePointer{ + Value: utils.Float64Pointer(-10), + Type: utils.StringPointer(utils.VOICE), + DestinationIds: utils.StringMapPointer(utils.StringMap{"OTHER": true}), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + } ub := &Account{} - a := &Action{BalanceType: utils.VOICE, Balance: mb1} + a := &Action{Balance: mb1} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE]) != 1 { t.Error("Error adding minute bucket: ", ub.BalanceMap[utils.VOICE]) } - a = &Action{BalanceType: utils.VOICE, Balance: mb2} + a = &Action{Balance: mb2} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE]) != 1 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { t.Error("Error adding minute bucket: ", ub.BalanceMap[utils.VOICE]) } - a = &Action{BalanceType: utils.VOICE, Balance: mb3} + a = &Action{Balance: mb3} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE]) != 2 { t.Error("Error adding minute bucket: ", ub.BalanceMap[utils.VOICE]) @@ -893,7 +924,7 @@ 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: 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: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{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) if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { @@ -917,7 +948,7 @@ 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: 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: utils.TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{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) if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { @@ -930,7 +961,7 @@ 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: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}}, } ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil) @@ -945,8 +976,8 @@ func TestAccountExecuteTriggeredDayWeek(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{UniqueID: "day_trigger", BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, - &ActionTrigger{UniqueID: "week_trigger", BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{UniqueID: "day_trigger", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{UniqueID: "week_trigger", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, }, } ub.InitCounters() @@ -961,7 +992,7 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) { } // we can reset them - resetCountersAction(ub, nil, &Action{BalanceType: utils.MONETARY, Balance: &Balance{Id: "day_trigger"}}, nil) + resetCountersAction(ub, nil, &Action{Balance: &BalancePointer{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) @@ -973,7 +1004,7 @@ func TestAccountExpActionTrigger(t *testing.T) { Id: "TEST_UB", BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100, ExpirationDate: time.Date(2015, time.November, 9, 9, 48, 0, 0, time.UTC)}}, 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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -991,7 +1022,7 @@ func TestAccountExpActionTriggerNotActivated(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", ActivationDate: time.Date(2116, 2, 5, 18, 0, 0, 0, time.UTC), BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", ActivationDate: time.Date(2116, 2, 5, 18, 0, 0, 0, time.UTC), Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -1009,7 +1040,7 @@ func TestAccountExpActionTriggerExpired(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", ExpirationDate: time.Date(2016, 2, 4, 18, 0, 0, 0, time.UTC), BalanceType: utils.MONETARY, BalanceDirections: utils.StringMap{utils.OUT: true}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", ExpirationDate: time.Date(2016, 2, 4, 18, 0, 0, 0, time.UTC), Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -1565,46 +1596,58 @@ func TestAccountInitCounters(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -1628,46 +1671,58 @@ func TestAccountDoubleInitCounters(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, }, } diff --git a/engine/action.go b/engine/action.go index 8e6264bd5..94ab9ba1e 100644 --- a/engine/action.go +++ b/engine/action.go @@ -38,9 +38,9 @@ import ( Structure to be filled for each tariff plan with the bonus value for received calls minutes. */ type Action struct { - Id string - ActionType string - BalanceType string + Id string + ActionType string + //BalanceType string ExtraParameters string Filter string ExpirationString string // must stay as string because it can have relative values like 1month @@ -51,6 +51,7 @@ type Action struct { type BalancePointer struct { Uuid *string Id *string + Type *string Value *float64 Directions *utils.StringMap ExpirationDate *time.Time @@ -113,6 +114,61 @@ func (bp *BalancePointer) CreateBalance() *Balance { return b.Clone() } +func (bp *BalancePointer) 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 *BalancePointer) GetType() string { + if bp.Type == nil { + return "" + } + return *bp.Type +} + +func (bp *BalancePointer) GetValue() float64 { + if bp.Value == nil { + return 0.0 + } + return *bp.Value +} + const ( LOG = "*log" RESET_TRIGGERS = "*reset_triggers" @@ -143,9 +199,9 @@ const ( func (a *Action) Clone() *Action { return &Action{ - Id: a.Id, - ActionType: a.ActionType, - BalanceType: a.BalanceType, + Id: a.Id, + ActionType: a.ActionType, + //BalanceType: a.BalanceType, ExtraParameters: a.ExtraParameters, ExpirationString: a.ExpirationString, Weight: a.Weight, @@ -248,7 +304,7 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) case "ActionType": parsedValue += rsrFld.ParseValue(action.ActionType) case "BalanceType": - parsedValue += rsrFld.ParseValue(action.BalanceType) + parsedValue += rsrFld.ParseValue(action.Balance.GetType()) case "BalanceUUID": parsedValue += rsrFld.ParseValue(b.Uuid) case "BalanceID": @@ -651,10 +707,10 @@ func removeAccountAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Ac } func removeBalanceAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) error { - if _, exists := ub.BalanceMap[a.BalanceType]; !exists { + if _, exists := ub.BalanceMap[a.Balance.GetType()]; !exists { return utils.ErrNotFound } - bChain := ub.BalanceMap[a.BalanceType] + bChain := ub.BalanceMap[a.Balance.GetType()] found := false for i := 0; i < len(bChain); i++ { if bChain[i].MatchFilter(a.Balance, false) { @@ -665,7 +721,7 @@ func removeBalanceAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Ac found = true } } - ub.BalanceMap[a.BalanceType] = bChain + ub.BalanceMap[a.Balance.GetType()] = bChain if !found { return utils.ErrNotFound } diff --git a/engine/action_trigger.go b/engine/action_trigger.go index d9ae7b005..0fe22916c 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -19,9 +19,7 @@ along with this program. If not, see package engine import ( - "encoding/json" "fmt" - "regexp" "sort" "time" @@ -33,12 +31,12 @@ type ActionTrigger struct { UniqueID string // individual id ThresholdType string //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *exp_balance // stats: *min_asr, *max_asr, *min_acd, *max_acd, *min_tcd, *max_tcd, *min_acc, *max_acc, *min_tcc, *max_tcc, *min_ddc, *max_ddc - ThresholdValue float64 - Recurrent bool // reset excuted flag each run - MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers - ExpirationDate time.Time - ActivationDate time.Time - BalanceType string // *monetary/*voice etc + ThresholdValue float64 + Recurrent bool // reset excuted flag each run + MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers + ExpirationDate time.Time + ActivationDate time.Time + //BalanceType string // *monetary/*voice etc Balance *BalancePointer Weight float64 ActionsId string @@ -118,41 +116,7 @@ func (at *ActionTrigger) Match(a *Action) bool { if a == nil { return true } - // if we have Id than we can draw an early conclusion - if a.Id != "" { - match, _ := regexp.MatchString(a.Id, at.ID) - return match - } - id := a.BalanceType == "" || at.BalanceType == a.BalanceType - thresholdType, thresholdValue, direction, destinationID, weight, ratingSubject, categories, sharedGroup, timings, blocker, disabled := true, true, true, true, true, true, true, true, true, true, true - if a.ExtraParameters != "" { - t := struct { - ThresholdType string - ThresholdValue float64 - DestinationIds string - BalanceDirections string - BalanceWeight float64 - BalanceRatingSubject string - BalanceCategories string - BalanceSharedGroups string - BalanceTimingTags string - BalanceBlocker bool - BalanceDisabled bool - }{} - json.Unmarshal([]byte(a.ExtraParameters), &t) - thresholdType = t.ThresholdType == "" || at.ThresholdType == t.ThresholdType - thresholdValue = t.ThresholdValue == 0 || at.ThresholdValue == t.ThresholdValue - direction = t.Balance.Directions == nil || at.Balance.Directions.Equal(utils.ParseStringMap(t.BalanceDirections)) - destinationID = len(t.DestinationIds) == 0 || at.BalanceDestinationIds.Equal(utils.ParseStringMap(t.DestinationIds)) - categories = len(t.BalanceCategories) == 0 || at.BalanceCategories.Equal(utils.ParseStringMap(t.BalanceCategories)) - timings = len(t.BalanceTimingTags) == 0 || at.BalanceTimingTags.Equal(utils.ParseStringMap(t.BalanceTimingTags)) - sharedGroup = len(t.BalanceSharedGroups) == 0 || at.BalanceSharedGroups.Equal(utils.ParseStringMap(t.BalanceSharedGroups)) - weight = t.BalanceWeight == 0 || at.BalanceWeight == t.BalanceWeight - ratingSubject = t.BalanceRatingSubject == "" || at.BalanceRatingSubject == t.BalanceRatingSubject - blocker = at.BalanceBlocker == t.BalanceBlocker - disabled = at.BalanceDisabled == t.BalanceDisabled - } - return id && direction && thresholdType && thresholdValue && destinationID && weight && ratingSubject && categories && sharedGroup && timings && blocker && disabled + return at.Balance.CreateBalance().MatchFilter(a.Balance, false) } // makes a shallow copy of the receiver @@ -162,22 +126,6 @@ func (at *ActionTrigger) Clone() *ActionTrigger { return clone } -func (at *ActionTrigger) CreateBalance() *Balance { - return &Balance{ - Id: at.UniqueID, - Directions: at.BalanceDirections, - ExpirationDate: at.BalanceExpirationDate, - DestinationIds: at.BalanceDestinationIds, - RatingSubject: at.BalanceRatingSubject, - Categories: at.BalanceCategories, - SharedGroups: at.BalanceSharedGroups, - TimingIDs: at.BalanceTimingTags, - Blocker: at.BalanceBlocker, - Disabled: at.BalanceDisabled, - Weight: at.BalanceWeight, - } -} - func (at *ActionTrigger) Equals(oat *ActionTrigger) bool { // ids only return at.ID == oat.ID && at.UniqueID == oat.UniqueID diff --git a/engine/actions_local_test.go b/engine/actions_local_test.go index 177fe19b0..bdc3b8b79 100644 --- a/engine/actions_local_test.go +++ b/engine/actions_local_test.go @@ -23,6 +23,7 @@ import ( "net/rpc" "net/rpc/jsonrpc" "path" + "strconv" "testing" "time" @@ -94,7 +95,7 @@ func TestActionsLocalSetCdrlogDebit(t *testing.T) { t.Errorf("Calling ApierV1.SetAccount received: %s", reply) } attrsAA := &utils.AttrSetActions{ActionsId: "ACTS_1", Actions: []*utils.TPAction{ - &utils.TPAction{Identifier: DEBIT, BalanceType: utils.MONETARY, Units: 5.0, ExpiryTime: UNLIMITED, Weight: 20.0}, + &utils.TPAction{Identifier: DEBIT, BalanceType: utils.MONETARY, Units: "5.0", ExpiryTime: UNLIMITED, Weight: 20.0}, &utils.TPAction{Identifier: CDRLOG}, }} if err := actsLclRpc.Call("ApierV1.SetActions", attrsAA, &reply); err != nil && err.Error() != utils.ErrExists.Error() { @@ -122,7 +123,7 @@ func TestActionsLocalSetCdrlogDebit(t *testing.T) { rcvedCdrs[0].Subject != "dan2904" || rcvedCdrs[0].Usage != "1" || rcvedCdrs[0].RunID != DEBIT || - rcvedCdrs[0].Cost != attrsAA.Actions[0].Units { + strconv.FormatFloat(rcvedCdrs[0].Cost, 'f', -1, 64) != attrsAA.Actions[0].Units { t.Errorf("Received: %+v", rcvedCdrs[0]) } } @@ -139,7 +140,7 @@ func TestActionsLocalSetCdrlogTopup(t *testing.T) { t.Errorf("Calling ApierV1.SetAccount received: %s", reply) } attrsAA := &utils.AttrSetActions{ActionsId: "ACTS_2", Actions: []*utils.TPAction{ - &utils.TPAction{Identifier: TOPUP, BalanceType: utils.MONETARY, Units: 5.0, ExpiryTime: UNLIMITED, Weight: 20.0}, + &utils.TPAction{Identifier: TOPUP, BalanceType: utils.MONETARY, Units: "5.0", ExpiryTime: UNLIMITED, Weight: 20.0}, &utils.TPAction{Identifier: CDRLOG}, }} if err := actsLclRpc.Call("ApierV1.SetActions", attrsAA, &reply); err != nil && err.Error() != utils.ErrExists.Error() { @@ -167,7 +168,7 @@ func TestActionsLocalSetCdrlogTopup(t *testing.T) { rcvedCdrs[0].Subject != "dan2905" || rcvedCdrs[0].Usage != "1" || rcvedCdrs[0].RunID != TOPUP || - rcvedCdrs[0].Cost != attrsAA.Actions[0].Units { + strconv.FormatFloat(rcvedCdrs[0].Cost, 'f', -1, 64) != attrsAA.Actions[0].Units { t.Errorf("Received: %+v", rcvedCdrs[0]) } } diff --git a/engine/actions_test.go b/engine/actions_test.go index 1eb5367d6..e0e4244db 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -409,9 +409,11 @@ func TestActionPlanCheckForASAP(t *testing.T) { func TestActionPlanLogFunction(t *testing.T) { a := &Action{ - ActionType: "*log", - BalanceType: "test", - Balance: &Balance{Value: 1.1}, + ActionType: "*log", + Balance: &BalancePointer{ + Type: utils.StringPointer("test"), + Value: utils.Float64Pointer(1.1), + }, } at := &ActionTiming{ actions: []*Action{a}, @@ -424,9 +426,11 @@ func TestActionPlanLogFunction(t *testing.T) { func TestActionPlanFunctionNotAvailable(t *testing.T) { a := &Action{ - ActionType: "VALID_FUNCTION_TYPE", - BalanceType: "test", - Balance: &Balance{Value: 1.1}, + ActionType: "VALID_FUNCTION_TYPE", + Balance: &BalancePointer{ + Type: utils.StringPointer("test"), + Value: utils.Float64Pointer(1.1), + }, } at := &ActionTiming{ accountIDs: utils.StringMap{"cgrates.org:dy": true}, @@ -527,10 +531,12 @@ func TestActionPlansRemoveMember(t *testing.T) { func TestActionTriggerMatchNil(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } var a *Action if !at.Match(a) { @@ -540,10 +546,12 @@ func TestActionTriggerMatchNil(t *testing.T) { func TestActionTriggerMatchAllBlank(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } a := &Action{} if !at.Match(a) { @@ -553,12 +561,14 @@ func TestActionTriggerMatchAllBlank(t *testing.T) { func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } - a := &Action{BalanceType: utils.MONETARY, ExtraParameters: `{"BalanceDirections":"*out"}`} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: `{"BalanceDirections":"*out"}`} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -566,10 +576,12 @@ func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) { func TestActionTriggerMatchMinuteBucketFull(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } a := &Action{ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v}`, utils.TRIGGER_MAX_BALANCE, 2)} if !at.Match(a) { @@ -579,12 +591,14 @@ func TestActionTriggerMatchMinuteBucketFull(t *testing.T) { func TestActionTriggerMatchAllFull(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } - a := &Action{BalanceType: utils.MONETARY, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 2)} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 2)} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -592,12 +606,14 @@ func TestActionTriggerMatchAllFull(t *testing.T) { func TestActionTriggerMatchSomeFalse(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } - a := &Action{BalanceType: utils.MONETARY, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_BALANCE, 2)} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_BALANCE, 2)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -605,12 +621,14 @@ func TestActionTriggerMatchSomeFalse(t *testing.T) { func TestActionTriggerMatcBalanceFalse(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } - a := &Action{BalanceType: utils.MONETARY, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 3.0)} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 3.0)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -618,12 +636,14 @@ func TestActionTriggerMatcBalanceFalse(t *testing.T) { func TestActionTriggerMatcAllFalse(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, } - a := &Action{BalanceType: utils.VOICE, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_EVENT_COUNTER, 3)} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_EVENT_COUNTER, 3)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -631,16 +651,18 @@ func TestActionTriggerMatcAllFalse(t *testing.T) { func TestActionTriggerMatchAll(t *testing.T) { at := &ActionTrigger{ - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceType: utils.MONETARY, - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 2, - BalanceDestinationIds: utils.NewStringMap("NAT"), - BalanceWeight: 1.0, - BalanceRatingSubject: "test1", - BalanceSharedGroups: utils.NewStringMap("test2"), + Balance: &BalancePointer{ + 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")), + }, + ThresholdType: utils.TRIGGER_MAX_BALANCE, } - a := &Action{BalanceType: 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: &BalancePointer{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")} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -663,7 +685,7 @@ func TestActionResetTriggres(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) if ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true { @@ -676,7 +698,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { Id: "TEST_UB", BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}}, UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) if ub.ActionTriggers[0].Executed == true || ub.BalanceMap[utils.MONETARY][0].GetValue() == 12 { @@ -689,9 +711,9 @@ func TestActionResetTriggresActionFilter(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - resetTriggersAction(ub, nil, &Action{BalanceType: utils.SMS}, nil) + resetTriggersAction(ub, nil, &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}}, nil) if ub.ActionTriggers[0].Executed == false || ub.ActionTriggers[1].Executed == false { t.Error("Reset triggers action failed!") } @@ -702,7 +724,7 @@ func TestActionSetPostpaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } allowNegativeAction(ub, nil, nil, nil) if !ub.AllowNegative { @@ -716,7 +738,7 @@ func TestActionSetPrepaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } denyNegativeAction(ub, nil, nil, nil) if ub.AllowNegative { @@ -730,7 +752,7 @@ func TestActionResetPrepaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) if !ub.AllowNegative || @@ -748,7 +770,7 @@ func TestActionResetPostpaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) if ub.BalanceMap[utils.MONETARY].GetTotalValue() != 0 || @@ -764,9 +786,9 @@ func TestActionTopupResetCredit(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.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)}}}}, - 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}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -783,10 +805,10 @@ func TestActionTopupValueFactor(t *testing.T) { BalanceMap: map[string]BalanceChain{}, } a := &Action{ - BalanceType: utils.MONETARY, - Balance: &Balance{ - Value: 10, - Directions: utils.NewStringMap(utils.OUT), + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Value: utils.Float64Pointer(10), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ExtraParameters: `{"*monetary":2.0}`, } @@ -806,7 +828,7 @@ func TestActionTopupResetCreditId(t *testing.T) { }, }, } - a := &Action{BalanceType: utils.MONETARY, Balance: &Balance{Id: "TEST_B", Value: 10, Directions: utils.NewStringMap(utils.OUT)}} + a := &Action{Balance: &BalancePointer{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 || @@ -825,7 +847,7 @@ func TestActionTopupResetCreditNoId(t *testing.T) { }, }, } - a := &Action{BalanceType: utils.MONETARY, Balance: &Balance{Value: 10, Directions: utils.NewStringMap(utils.OUT)}} + a := &Action{Balance: &BalancePointer{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() != 20 || @@ -841,9 +863,9 @@ func TestActionTopupResetMinutes(t *testing.T) { 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)}}}}, - 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}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -860,9 +882,9 @@ func TestActionTopupCredit(t *testing.T) { 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)}}}}, - 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}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -878,9 +900,9 @@ func TestActionTopupMinutes(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -897,9 +919,9 @@ func TestActionDebitCredit(t *testing.T) { 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)}}}}, - 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}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -915,9 +937,9 @@ func TestActionDebitMinutes(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(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)}} + a := &Action{Balance: &BalancePointer{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 || @@ -939,7 +961,7 @@ 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, BalanceType: utils.MONETARY, ThresholdValue: 2, BalanceDestinationIds: utils.NewStringMap("NAT"), BalanceWeight: 20, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalancePointer{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) @@ -967,9 +989,9 @@ 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")}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{BalanceType: utils.MONETARY} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}} ub.InitCounters() resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || @@ -998,9 +1020,9 @@ func TestActionResetCounterCredit(t *testing.T) { 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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirections: utils.NewStringMap(utils.OUT), ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{BalanceType: utils.MONETARY} + a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}} resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 || @@ -1013,13 +1035,15 @@ func TestActionResetCounterCredit(t *testing.T) { func TestActionTriggerLogging(t *testing.T) { at := &ActionTrigger{ - ID: "some_uuid", - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - ThresholdValue: 100.0, - BalanceDestinationIds: utils.NewStringMap("NAT"), - Weight: 10.0, - ActionsId: "TEST_ACTIONS", + ID: "some_uuid", + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), + }, + ThresholdValue: 100.0, + Weight: 10.0, + ActionsId: "TEST_ACTIONS", } as, err := ratingStorage.GetActions(at.ActionsId, false) if err != nil { @@ -1084,7 +1108,7 @@ func TestActionPlanLogging(t *testing.T) { } func TestActionMakeNegative(t *testing.T) { - a := &Action{Balance: &Balance{Value: 10}} + a := &Action{Balance: &BalancePointer{Value: utils.Float64Pointer(10)}} genericMakeNegative(a) if a.Balance.GetValue() > 0 { t.Error("Failed to make negative: ", a) @@ -1117,9 +1141,8 @@ func TestRemoveAction(t *testing.T) { func TestTopupAction(t *testing.T) { initialUb, _ := accountingStorage.GetAccount("vdf:minu") a := &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT), Weight: 20}, + ActionType: TOPUP, + Balance: &BalancePointer{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{ @@ -1139,9 +1162,8 @@ func TestTopupAction(t *testing.T) { func TestTopupActionLoaded(t *testing.T) { initialUb, _ := accountingStorage.GetAccount("vdf:minitsboy") a := &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT), Weight: 20}, + ActionType: TOPUP, + Balance: &BalancePointer{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{ @@ -1168,7 +1190,7 @@ func TestActionCdrlogEmpty(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Weight: 20}, + Balance: &BalancePointer{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1190,11 +1212,11 @@ func TestActionCdrlogWithParams(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Weight: 20}, + Balance: &BalancePointer{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Weight: 20}, + Balance: &BalancePointer{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1217,11 +1239,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Weight: 20}, + Balance: &BalancePointer{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Weight: 20}, + Balance: &BalancePointer{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1301,14 +1323,12 @@ func TestActionTransactionFuncType(t *testing.T) { Timing: &RateInterval{}, actions: []*Action{ &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Balance: &Balance{Value: 1.1}, + ActionType: TOPUP, + Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ - ActionType: "VALID_FUNCTION_TYPE", - BalanceType: "test", - Balance: &Balance{Value: 1.1}, + ActionType: "VALID_FUNCTION_TYPE", + Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer("test")}, }, }, } @@ -1339,14 +1359,12 @@ func TestActionTransactionBalanceType(t *testing.T) { Timing: &RateInterval{}, actions: []*Action{ &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Balance: &Balance{Value: 1.1}, + ActionType: TOPUP, + Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ - ActionType: TOPUP, - BalanceType: "test", - Balance: nil, + ActionType: TOPUP, + Balance: &BalancePointer{Type: utils.StringPointer("test")}, }, }, } @@ -1377,18 +1395,18 @@ func TestActionWithExpireWithoutExpire(t *testing.T) { Timing: &RateInterval{}, actions: []*Action{ &Action{ - ActionType: TOPUP, - BalanceType: utils.VOICE, - Balance: &Balance{ - Value: 15, + ActionType: TOPUP, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Value: utils.Float64Pointer(15), }, }, &Action{ - ActionType: TOPUP, - BalanceType: utils.VOICE, - Balance: &Balance{ - Value: 30, - ExpirationDate: time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC), + ActionType: TOPUP, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Value: utils.Float64Pointer(30), + ExpirationDate: utils.TimePointer(time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC)), }, }, }, @@ -1432,10 +1450,10 @@ func TestActionRemoveBalance(t *testing.T) { Timing: &RateInterval{}, actions: []*Action{ &Action{ - ActionType: REMOVE_BALANCE, - BalanceType: utils.MONETARY, - Balance: &Balance{ - DestinationIds: utils.NewStringMap("NAT", "RET"), + ActionType: REMOVE_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")), }, }, }, @@ -1543,7 +1561,7 @@ func TestActionTransferMonetaryDefaultFilter(t *testing.T) { a := &Action{ ActionType: TRANSFER_MONETARY_DEFAULT, - Balance: &Balance{Weight: 20}, + Balance: &BalancePointer{Weight: utils.Float64Pointer(20)}, } at := &ActionTiming{ @@ -1603,12 +1621,12 @@ func TestActionConditionalTopup(t *testing.T) { } a := &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Filter: `{"Type":"*monetary","Value":1,"Weight":10}`, - Balance: &Balance{ - Value: 11, - Weight: 30, + ActionType: TOPUP, + Filter: `{"Type":"*monetary","Value":1,"Weight":10}`, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Value: utils.Float64Pointer(11), + Weight: utils.Float64Pointer(30), }, } @@ -1667,12 +1685,12 @@ func TestActionConditionalTopupNoMatch(t *testing.T) { } a := &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Filter: `{"Type":"*monetary","Value":2,"Weight":10}`, - Balance: &Balance{ - Value: 11, - Weight: 30, + ActionType: TOPUP, + Filter: `{"Type":"*monetary","Value":2,"Weight":10}`, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Value: utils.Float64Pointer(11), + Weight: utils.Float64Pointer(30), }, } @@ -1731,12 +1749,12 @@ func TestActionConditionalTopupExistingBalance(t *testing.T) { } a := &Action{ - ActionType: TOPUP, - BalanceType: utils.MONETARY, - Filter: `{"Type":"*voice","Value":{"*gte":100}}`, - Balance: &Balance{ - Value: 11, - Weight: 10, + ActionType: TOPUP, + Filter: `{"Type":"*voice","Value":{"*gte":100}}`, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Value: utils.Float64Pointer(11), + Weight: utils.Float64Pointer(10), }, } @@ -1832,45 +1850,45 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { } a1 := &Action{ - ActionType: "*enable_disable_balance", - BalanceType: "*sms", - Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &Balance{ - Weight: 10, - Disabled: true, + ActionType: "*enable_disable_balance", + Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", + Balance: &BalancePointer{ + Type: utils.StringPointer("*sms"), + Weight: utils.Float64Pointer(10), + Disabled: utils.BoolPointer(true), }, Weight: 9, } a2 := &Action{ - ActionType: "*enable_disable_balance", - BalanceType: "*sms", - Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &Balance{ - DestinationIds: utils.NewStringMap("FRANCE_NATIONAL"), - Weight: 10, - Disabled: true, + ActionType: "*enable_disable_balance", + Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", + Balance: &BalancePointer{ + Type: utils.StringPointer("*sms"), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")), + Weight: utils.Float64Pointer(10), + Disabled: utils.BoolPointer(true), }, Weight: 8, } a3 := &Action{ - ActionType: "*enable_disable_balance", - BalanceType: "*data", - Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &Balance{ - RatingSubject: "for_v3hsillmilld500m_data_forfait", - Weight: 10, - Disabled: true, + ActionType: "*enable_disable_balance", + Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", + Balance: &BalancePointer{ + Type: utils.StringPointer("*data"), + RatingSubject: utils.StringPointer("for_v3hsillmilld500m_data_forfait"), + Weight: utils.Float64Pointer(10), + Disabled: utils.BoolPointer(true), }, Weight: 7, } a4 := &Action{ - ActionType: "*enable_disable_balance", - BalanceType: "*voice", - Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &Balance{ - DestinationIds: utils.NewStringMap("FRANCE_NATIONAL"), - Weight: 10, - Disabled: true, + ActionType: "*enable_disable_balance", + Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", + Balance: &BalancePointer{ + Type: utils.StringPointer("*voice"), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")), + Weight: utils.Float64Pointer(10), + Disabled: utils.BoolPointer(true), }, Weight: 6, } @@ -1937,12 +1955,12 @@ func TestActionSetBalance(t *testing.T) { } a := &Action{ - ActionType: SET_BALANCE, - BalanceType: utils.MONETARY, - Balance: &Balance{ - Id: "m2", - Value: 11, - Weight: 10, + ActionType: SET_BALANCE, + Balance: &BalancePointer{ + Id: utils.StringPointer("m2"), + Type: utils.StringPointer(utils.MONETARY), + Value: utils.Float64Pointer(11), + Weight: utils.Float64Pointer(10), }, } diff --git a/engine/balances.go b/engine/balances.go index b1a9fba96..38dd1e8e4 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -94,6 +94,28 @@ func (b *Balance) MatchFilter(o *BalancePointer, skipIds bool) bool { (o.RatingSubject == nil || b.RatingSubject == *o.RatingSubject) } +func (b *Balance) HardMatchFilter(o *BalancePointer, skipIds bool) bool { + if o == nil { + return true + } + if !skipIds && o.Uuid != nil && *o.Uuid != "" { + return b.Uuid == *o.Uuid + } + 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.Directions == nil || b.Directions.Equal(*o.Directions)) && + (o.Categories == nil || b.Categories.Equal(*o.Categories)) && + (o.TimingIDs == nil || b.TimingIDs.Equal(*o.TimingIDs)) && + (o.SharedGroups == nil || b.SharedGroups.Equal(*o.SharedGroups)) && + (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 @@ -174,47 +196,7 @@ func (b *Balance) MatchDestination(destinationId string) bool { } func (b *Balance) MatchActionTrigger(at *ActionTrigger) bool { - if at.BalanceId != "" { - return b.Id == at.BalanceId - } - matchesDestination := true - if len(at.BalanceDestinationIds) != 0 { - matchesDestination = (b.DestinationIds.Equal(at.BalanceDestinationIds)) - } - matchesDirection := true - if len(at.BalanceDirections) != 0 { - matchesDirection = (b.Directions.Equal(at.BalanceDirections)) - } - matchesExpirationDate := true - if !at.BalanceExpirationDate.IsZero() { - matchesExpirationDate = (at.BalanceExpirationDate.Equal(b.ExpirationDate)) - } - matchesWeight := true - if at.BalanceWeight > 0 { - matchesWeight = (at.BalanceWeight == b.Weight) - } - matchesRatingSubject := true - if at.BalanceRatingSubject != "" { - matchesRatingSubject = (at.BalanceRatingSubject == b.RatingSubject) - } - - matchesSharedGroup := true - if len(at.BalanceSharedGroups) != 0 { - matchesSharedGroup = at.BalanceSharedGroups.Equal(b.SharedGroups) - } - - matchesTiming := true - if len(at.BalanceTimingTags) != 0 { - matchesTiming = at.BalanceTimingTags.Equal(b.TimingIDs) - } - - return matchesDestination && - matchesDirection && - matchesExpirationDate && - matchesWeight && - matchesRatingSubject && - matchesSharedGroup && - matchesTiming + return b.HardMatchFilter(at.Balance, false) } func (b *Balance) Clone() *Balance { diff --git a/engine/balances_test.go b/engine/balances_test.go index 163ab79ec..09c9dd17f 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 := &Balance{Weight: 1, precision: 1, RatingSubject: "", DestinationIds: utils.StringMap{}} + mb2 := &BalancePointer{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIds: nil} if !mb1.MatchFilter(mb2, false) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } @@ -98,7 +98,7 @@ func TestBalanceMatchFilter(t *testing.T) { func TestBalanceMatchFilterEmpty(t *testing.T) { mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} - mb2 := &Balance{} + mb2 := &BalancePointer{} 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 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} + mb2 := &BalancePointer{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 := &Balance{Id: "T2", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} + mb2 := &BalancePointer{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{BalanceId: "test"} + at := &ActionTrigger{Balance: &BalancePointer{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.BalanceId = "" + 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{BalanceDestinationIds: utils.NewStringMap("test")} + at := &ActionTrigger{Balance: &BalancePointer{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,14 +164,14 @@ func TestBalanceMatchActionTriggerDestination(t *testing.T) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } b.DestinationIds = utils.NewStringMap("test") - at.BalanceDestinationIds = utils.NewStringMap("") + at.Balance.DestinationIds = nil if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } } func TestBalanceMatchActionTriggerWeight(t *testing.T) { - at := &ActionTrigger{BalanceWeight: 1} + at := &ActionTrigger{Balance: &BalancePointer{Weight: utils.Float64Pointer(1)}} b := &Balance{Weight: 1} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) @@ -185,14 +185,14 @@ func TestBalanceMatchActionTriggerWeight(t *testing.T) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } b.Weight = 1 - at.BalanceWeight = 0 + at.Balance.Weight = nil if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } } func TestBalanceMatchActionTriggerRatingSubject(t *testing.T) { - at := &ActionTrigger{BalanceRatingSubject: "test"} + at := &ActionTrigger{Balance: &BalancePointer{RatingSubject: utils.StringPointer("test")}} b := &Balance{RatingSubject: "test"} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) @@ -206,14 +206,14 @@ func TestBalanceMatchActionTriggerRatingSubject(t *testing.T) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } b.RatingSubject = "test" - at.BalanceRatingSubject = "" + at.Balance.RatingSubject = nil if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } } func TestBalanceMatchActionTriggerSharedGroup(t *testing.T) { - at := &ActionTrigger{BalanceSharedGroups: utils.NewStringMap("test")} + at := &ActionTrigger{Balance: &BalancePointer{SharedGroups: utils.StringMapPointer(utils.NewStringMap("test"))}} b := &Balance{SharedGroups: utils.NewStringMap("test")} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) @@ -227,7 +227,7 @@ func TestBalanceMatchActionTriggerSharedGroup(t *testing.T) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } b.SharedGroups = utils.NewStringMap("test") - at.BalanceSharedGroups = utils.NewStringMap("") + at.Balance.SharedGroups = nil if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index f470910ae..e4d5cdc9e 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -41,12 +41,12 @@ func init() { func populateDB() { ats := []*Action{ - &Action{ActionType: "*topup", BalanceType: utils.MONETARY, Balance: &Balance{Value: 10}}, - &Action{ActionType: "*topup", BalanceType: utils.VOICE, Balance: &Balance{Weight: 20, Value: 10, DestinationIds: utils.NewStringMap("NAT")}}, + &Action{ActionType: "*topup", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}}, + &Action{ActionType: "*topup", Balance: &BalancePointer{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, } ats1 := []*Action{ - &Action{ActionType: "*topup", BalanceType: utils.MONETARY, Balance: &Balance{Value: 10}, Weight: 10}, + &Action{ActionType: "*topup", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}, Weight: 10}, &Action{ActionType: "*reset_account", Weight: 20}, } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index ffb85bbae..4cb27daf0 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -823,38 +823,38 @@ func TestLoadActions(t *testing.T) { &Action{ Id: "MINI0", ActionType: TOPUP_RESET, - BalanceType: utils.MONETARY, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, - Balance: &Balance{ + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), Uuid: as1[0].Balance.Uuid, - Directions: utils.NewStringMap(utils.OUT), - Value: 10, - Weight: 10, - DestinationIds: utils.StringMap{}, - TimingIDs: utils.StringMap{}, - SharedGroups: utils.StringMap{}, - Categories: utils.StringMap{}, + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Value: utils.Float64Pointer(10), + Weight: utils.Float64Pointer(10), + DestinationIds: nil, + TimingIDs: nil, + SharedGroups: nil, + Categories: nil, }, }, &Action{ Id: "MINI1", ActionType: TOPUP, - BalanceType: utils.VOICE, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, - Balance: &Balance{ + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), Uuid: as1[1].Balance.Uuid, - Directions: utils.NewStringMap(utils.OUT), - Value: 100, - Weight: 10, - RatingSubject: "test", - DestinationIds: utils.NewStringMap("NAT"), - TimingIDs: utils.StringMap{}, - SharedGroups: utils.StringMap{}, - Categories: utils.StringMap{}, + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Value: utils.Float64Pointer(100), + Weight: utils.Float64Pointer(10), + RatingSubject: utils.StringPointer("test"), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), + TimingIDs: nil, + SharedGroups: nil, + Categories: nil, }, }, } @@ -866,18 +866,18 @@ func TestLoadActions(t *testing.T) { &Action{ Id: "SHARED0", ActionType: TOPUP, - BalanceType: utils.MONETARY, ExpirationString: UNLIMITED, Weight: 10, - Balance: &Balance{ - Directions: utils.NewStringMap(utils.OUT), - DestinationIds: utils.StringMap{}, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: nil, Uuid: as2[0].Balance.Uuid, - Value: 100, - Weight: 10, - SharedGroups: utils.NewStringMap("SG1"), - TimingIDs: utils.StringMap{}, - Categories: utils.StringMap{}, + Value: utils.Float64Pointer(100), + Weight: utils.Float64Pointer(10), + SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")), + TimingIDs: nil, + Categories: nil, }, }, } @@ -891,14 +891,14 @@ func TestLoadActions(t *testing.T) { ActionType: CDRLOG, ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`, Weight: 10, - Balance: &Balance{ + Balance: &BalancePointer{ Uuid: as3[0].Balance.Uuid, - Directions: utils.StringMap{}, - DestinationIds: utils.StringMap{}, - TimingIDs: utils.StringMap{}, - Categories: utils.StringMap{}, - SharedGroups: utils.StringMap{}, - Blocker: false, + Directions: nil, + DestinationIds: nil, + TimingIDs: nil, + Categories: nil, + SharedGroups: nil, + Blocker: utils.BoolPointer(false), }, }, } @@ -1043,38 +1043,42 @@ func TestLoadActionTriggers(t *testing.T) { } atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0] expected := &ActionTrigger{ - ID: "STANDARD_TRIGGER", - UniqueID: "st0", - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, - ThresholdValue: 10, - BalanceDestinationIds: utils.NewStringMap("GERMANY_O2"), - BalanceCategories: utils.StringMap{}, - BalanceTimingTags: utils.StringMap{}, - BalanceSharedGroups: utils.StringMap{}, - Weight: 10, - ActionsId: "SOME_1", - Executed: false, + ID: "STANDARD_TRIGGER", + UniqueID: "st0", + ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, + ThresholdValue: 10, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")), + Categories: nil, + TimingIDs: nil, + SharedGroups: nil, + }, + Weight: 10, + ActionsId: "SOME_1", + Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Errorf("Error loading action trigger: %+v", atr) } atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1] expected = &ActionTrigger{ - ID: "STANDARD_TRIGGER", - UniqueID: "st1", - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - ThresholdType: utils.TRIGGER_MAX_BALANCE, - ThresholdValue: 200, - BalanceDestinationIds: utils.NewStringMap("GERMANY"), - BalanceCategories: utils.StringMap{}, - BalanceTimingTags: utils.StringMap{}, - BalanceSharedGroups: utils.StringMap{}, - Weight: 10, - ActionsId: "SOME_2", - Executed: false, + ID: "STANDARD_TRIGGER", + UniqueID: "st1", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 200, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY")), + Categories: nil, + TimingIDs: nil, + SharedGroups: nil, + }, + Weight: 10, + ActionsId: "SOME_2", + Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Errorf("Error loading action trigger: %+v", atr) @@ -1098,9 +1102,9 @@ func TestLoadAccountActions(t *testing.T) { Value: 0, Directions: utils.NewStringMap("*out"), DestinationIds: utils.NewStringMap("GERMANY_O2"), - SharedGroups: utils.StringMap{}, - Categories: utils.StringMap{}, - TimingIDs: utils.StringMap{}, + SharedGroups: nil, + Categories: nil, + TimingIDs: nil, }, }, }, @@ -1134,7 +1138,7 @@ func TestLoadDerivedChargers(t *testing.T) { t.Error("Failed to load derivedChargers: ", csvr.derivedChargers) } expCharger1 := &utils.DerivedChargers{ - DestinationIDs: utils.StringMap{}, + DestinationIDs: nil, Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunID: "extra1", RunFilters: "^filteredHeader1/filterValue1/", RequestTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: utils.META_DEFAULT, diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 90f1986c3..085012a37 100644 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -240,26 +240,26 @@ func TestTPActionsAsExportSlice(t *testing.T) { Identifier: "*topup_reset", BalanceType: "*monetary", Directions: utils.OUT, - Units: 5.0, + Units: "5.0", ExpiryTime: "*never", DestinationIds: "*any", RatingSubject: "special1", Categories: "call", SharedGroups: "GROUP1", - BalanceWeight: 10.0, + BalanceWeight: "10.0", ExtraParameters: "", Weight: 10.0}, &utils.TPAction{ Identifier: "*http_post", BalanceType: "", Directions: "", - Units: 0.0, + Units: "0.0", ExpiryTime: "", DestinationIds: "", RatingSubject: "", Categories: "", SharedGroups: "", - BalanceWeight: 0.0, + BalanceWeight: "0.0", ExtraParameters: "http://localhost/¶m1=value1", Weight: 20.0}, }, @@ -561,14 +561,14 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceType: "*monetary", BalanceDirections: "*out", BalanceDestinationIds: "", - BalanceWeight: 0.0, + BalanceWeight: "0.0", BalanceExpirationDate: "*never", BalanceTimingTags: "T1", BalanceRatingSubject: "special1", BalanceCategories: "call", BalanceSharedGroups: "SHARED_1", - BalanceBlocker: false, - BalanceDisabled: false, + BalanceBlocker: "false", + BalanceDisabled: "false", MinQueuedItems: 0, ActionsId: "LOG_WARNING", Weight: 10}, @@ -583,14 +583,14 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceType: "*monetary", BalanceDirections: "*out", BalanceDestinationIds: "FS_USERS", - BalanceWeight: 0.0, + BalanceWeight: "0.0", BalanceExpirationDate: "*never", BalanceTimingTags: "T1", BalanceRatingSubject: "special1", BalanceCategories: "call", BalanceSharedGroups: "SHARED_1", - BalanceBlocker: false, - BalanceDisabled: false, + BalanceBlocker: "false", + BalanceDisabled: "false", MinQueuedItems: 0, ActionsId: "LOG_WARNING", Weight: 10}, diff --git a/engine/storage_test.go b/engine/storage_test.go index 98a312739..1a38f6bd2 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -315,13 +315,15 @@ func GetUB() *Account { Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}, } at := &ActionTrigger{ - ID: "some_uuid", - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - ThresholdValue: 100.0, - BalanceDestinationIds: utils.NewStringMap("NAT"), - Weight: 10.0, - ActionsId: "Commando", + ID: "some_uuid", + ThresholdValue: 100.0, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), + }, + Weight: 10.0, + ActionsId: "Commando", } var zeroTime time.Time zeroTime = zeroTime.UTC() // for deep equal to find location diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 17c7706d1..27075be55 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -514,9 +514,9 @@ func (tpr *TpReader) LoadActions() (err error) { } } acts[idx] = &Action{ - Id: tag + strconv.Itoa(idx), - ActionType: tpact.Identifier, - BalanceType: tpact.BalanceType, + Id: tag + strconv.Itoa(idx), + ActionType: tpact.Identifier, + //BalanceType: tpact.BalanceType, Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, @@ -526,6 +526,9 @@ func (tpr *TpReader) LoadActions() (err error) { if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) } + if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY { + acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType) + } if tpact.Units != "" && tpact.Units != utils.ANY { u, err := strconv.ParseFloat(tpact.Units, 64) @@ -542,6 +545,13 @@ func (tpr *TpReader) LoadActions() (err error) { } acts[idx].Balance.Weight = utils.Float64Pointer(u) } + if tpact.ExpiryTime != "" && tpact.ExpiryTime != utils.ANY { + u, err := utils.ParseTimeDetectLayout(tpact.ExpiryTime, tpr.timezone) + if err != nil { + return err + } + acts[idx].Balance.ExpirationDate = utils.TimePointer(u) + } if tpact.RatingSubject != "" && tpact.RatingSubject != utils.ANY { acts[idx].Balance.RatingSubject = utils.StringPointer(tpact.RatingSubject) } @@ -666,10 +676,6 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { for key, atrsLst := range storAts { atrs := make([]*ActionTrigger, len(atrsLst)) for idx, atr := range atrsLst { - balanceExpirationDate, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) - if err != nil { - return err - } expirationDate, err := utils.ParseTimeDetectLayout(atr.ExpirationDate, tpr.timezone) if err != nil { return err @@ -686,29 +692,73 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { atr.UniqueID = utils.GenUUID() } atrs[idx] = &ActionTrigger{ - ID: key, - UniqueID: atr.UniqueID, - ThresholdType: atr.ThresholdType, - ThresholdValue: atr.ThresholdValue, - Recurrent: atr.Recurrent, - MinSleep: minSleep, - ExpirationDate: expirationDate, - ActivationDate: activationDate, - BalanceId: atr.BalanceId, - BalanceType: atr.BalanceType, - BalanceDirections: utils.ParseStringMap(atr.BalanceDirections), - BalanceDestinationIds: utils.ParseStringMap(atr.BalanceDestinationIds), - BalanceWeight: atr.BalanceWeight, - BalanceExpirationDate: balanceExpirationDate, - BalanceTimingTags: utils.ParseStringMap(atr.BalanceTimingTags), - BalanceRatingSubject: atr.BalanceRatingSubject, - BalanceCategories: utils.ParseStringMap(atr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(atr.BalanceSharedGroups), - BalanceBlocker: atr.BalanceBlocker, - BalanceDisabled: atr.BalanceDisabled, - Weight: atr.Weight, - ActionsId: atr.ActionsId, - MinQueuedItems: atr.MinQueuedItems, + ID: key, + UniqueID: atr.UniqueID, + ThresholdType: atr.ThresholdType, + ThresholdValue: atr.ThresholdValue, + Recurrent: atr.Recurrent, + MinSleep: minSleep, + ExpirationDate: expirationDate, + ActivationDate: activationDate, + Balance: &BalancePointer{}, + Weight: atr.Weight, + ActionsId: atr.ActionsId, + MinQueuedItems: atr.MinQueuedItems, + } + if atr.BalanceId != "" && atr.BalanceId != utils.ANY { + atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId) + } + + if atr.BalanceType != "" && atr.BalanceType != utils.ANY { + atrs[idx].Balance.Type = utils.StringPointer(atr.BalanceType) + } + + if atr.BalanceWeight != "" && atr.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(atr.BalanceWeight, 64) + if err != nil { + return err + } + atrs[idx].Balance.Weight = utils.Float64Pointer(u) + } + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) + if err != nil { + return err + } + atrs[idx].Balance.ExpirationDate = utils.TimePointer(u) + } + if atr.BalanceRatingSubject != "" && atr.BalanceRatingSubject != utils.ANY { + atrs[idx].Balance.RatingSubject = utils.StringPointer(atr.BalanceRatingSubject) + } + + if atr.BalanceCategories != "" && atr.BalanceCategories != utils.ANY { + atrs[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceCategories)) + } + if atr.BalanceDirections != "" && atr.BalanceDirections != utils.ANY { + 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)) + } + if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY { + atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups)) + } + if atr.BalanceTimingTags != "" && atr.BalanceTimingTags != utils.ANY { + atrs[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceTimingTags)) + } + if atr.BalanceBlocker != "" && atr.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceBlocker) + if err != nil { + return err + } + atrs[idx].Balance.Blocker = utils.BoolPointer(u) + } + if atr.BalanceDisabled != "" && atr.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceDisabled) + if err != nil { + return err + } + atrs[idx].Balance.Disabled = utils.BoolPointer(u) } } tpr.actionsTriggers[key] = atrs @@ -835,37 +885,80 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error atrsMap := make(map[string][]*ActionTrigger) for key, atrsLst := range atrs { atrs := make([]*ActionTrigger, len(atrsLst)) - for idx, apiAtr := range atrsLst { - minSleep, _ := utils.ParseDurationWithSecs(apiAtr.MinSleep) - balanceExpTime, _ := utils.ParseDate(apiAtr.BalanceExpirationDate) - expTime, _ := utils.ParseTimeDetectLayout(apiAtr.ExpirationDate, tpr.timezone) - actTime, _ := utils.ParseTimeDetectLayout(apiAtr.ActivationDate, tpr.timezone) - if apiAtr.UniqueID == "" { - apiAtr.UniqueID = utils.GenUUID() + for idx, atr := range atrsLst { + minSleep, _ := utils.ParseDurationWithSecs(atr.MinSleep) + expTime, _ := utils.ParseTimeDetectLayout(atr.ExpirationDate, tpr.timezone) + actTime, _ := utils.ParseTimeDetectLayout(atr.ActivationDate, tpr.timezone) + if atr.UniqueID == "" { + atr.UniqueID = utils.GenUUID() } atrs[idx] = &ActionTrigger{ - ID: key, - UniqueID: apiAtr.UniqueID, - ThresholdType: apiAtr.ThresholdType, - ThresholdValue: apiAtr.ThresholdValue, - Recurrent: apiAtr.Recurrent, - MinSleep: minSleep, - ExpirationDate: expTime, - ActivationDate: actTime, - BalanceId: apiAtr.BalanceId, - BalanceType: apiAtr.BalanceType, - BalanceDirections: utils.ParseStringMap(apiAtr.BalanceDirections), - BalanceDestinationIds: utils.ParseStringMap(apiAtr.BalanceDestinationIds), - BalanceWeight: apiAtr.BalanceWeight, - BalanceExpirationDate: balanceExpTime, - BalanceTimingTags: utils.ParseStringMap(apiAtr.BalanceTimingTags), - BalanceRatingSubject: apiAtr.BalanceRatingSubject, - BalanceCategories: utils.ParseStringMap(apiAtr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), - BalanceBlocker: apiAtr.BalanceBlocker, - BalanceDisabled: apiAtr.BalanceDisabled, - Weight: apiAtr.Weight, - ActionsId: apiAtr.ActionsId, + ID: key, + UniqueID: atr.UniqueID, + ThresholdType: atr.ThresholdType, + ThresholdValue: atr.ThresholdValue, + Recurrent: atr.Recurrent, + MinSleep: minSleep, + ExpirationDate: expTime, + ActivationDate: actTime, + Balance: &BalancePointer{}, + Weight: atr.Weight, + ActionsId: atr.ActionsId, + } + if atr.BalanceId != "" && atr.BalanceId != utils.ANY { + atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId) + } + + if atr.BalanceType != "" && atr.BalanceType != utils.ANY { + atrs[idx].Balance.Type = utils.StringPointer(atr.BalanceType) + } + + if atr.BalanceWeight != "" && atr.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(atr.BalanceWeight, 64) + if err != nil { + return err + } + atrs[idx].Balance.Weight = utils.Float64Pointer(u) + } + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) + if err != nil { + return err + } + atrs[idx].Balance.ExpirationDate = utils.TimePointer(u) + } + if atr.BalanceRatingSubject != "" && atr.BalanceRatingSubject != utils.ANY { + atrs[idx].Balance.RatingSubject = utils.StringPointer(atr.BalanceRatingSubject) + } + + if atr.BalanceCategories != "" && atr.BalanceCategories != utils.ANY { + atrs[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceCategories)) + } + if atr.BalanceDirections != "" && atr.BalanceDirections != utils.ANY { + 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)) + } + if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY { + atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups)) + } + if atr.BalanceTimingTags != "" && atr.BalanceTimingTags != utils.ANY { + atrs[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceTimingTags)) + } + if atr.BalanceBlocker != "" && atr.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceBlocker) + if err != nil { + return err + } + atrs[idx].Balance.Blocker = utils.BoolPointer(u) + } + if atr.BalanceDisabled != "" && atr.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceDisabled) + if err != nil { + return err + } + atrs[idx].Balance.Disabled = utils.BoolPointer(u) } } atrsMap[key] = atrs @@ -883,7 +976,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error } // actions - acts := make(map[string][]*Action) + facts := make(map[string][]*Action) for _, actId := range actionsIds { tpas, err := tpr.lr.GetTpActions(tpr.tpid, actId) if err != nil { @@ -894,7 +987,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error return err } for tag, tpacts := range as { - enacts := make([]*Action, len(tpacts)) + acts := make([]*Action, len(tpacts)) for idx, tpact := range tpacts { // check filter field if len(tpact.Filter) > 0 { @@ -902,34 +995,95 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error return fmt.Errorf("error parsing action %s filter field: %v", tag, err) } } - enacts[idx] = &Action{ - Id: tag + strconv.Itoa(idx), - ActionType: tpact.Identifier, - BalanceType: tpact.BalanceType, + acts[idx] = &Action{ + Id: tag + strconv.Itoa(idx), + ActionType: tpact.Identifier, + //BalanceType: tpact.BalanceType, Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &Balance{ - Id: tpact.BalanceId, - Value: tpact.Units, - Weight: tpact.BalanceWeight, - RatingSubject: tpact.RatingSubject, - 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), - Blocker: tpact.BalanceBlocker, - Disabled: tpact.BalanceDisabled, - }, + Balance: &BalancePointer{}, + } + if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { + acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) + } + if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY { + acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType) + } + + if tpact.Units != "" && tpact.Units != utils.ANY { + u, err := strconv.ParseFloat(tpact.Units, 64) + if err != nil { + return err + } + acts[idx].Balance.Value = utils.Float64Pointer(u) + } + + if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(tpact.BalanceWeight, 64) + if err != nil { + return err + } + acts[idx].Balance.Weight = utils.Float64Pointer(u) + } + if tpact.RatingSubject != "" && tpact.RatingSubject != utils.ANY { + acts[idx].Balance.RatingSubject = utils.StringPointer(tpact.RatingSubject) + } + + if tpact.Categories != "" && tpact.Categories != utils.ANY { + acts[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(tpact.Categories)) + } + if tpact.Directions != "" && tpact.Directions != utils.ANY { + 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)) + } + if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY { + acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups)) + } + if tpact.TimingTags != "" && tpact.TimingTags != utils.ANY { + acts[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.TimingTags)) + } + if tpact.BalanceBlocker != "" && tpact.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceBlocker) + if err != nil { + return err + } + acts[idx].Balance.Blocker = utils.BoolPointer(u) + } + if tpact.BalanceDisabled != "" && tpact.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceDisabled) + if err != nil { + return err + } + acts[idx].Balance.Disabled = utils.BoolPointer(u) + } + // load action timings from tags + if tpact.TimingTags != "" { + timingIds := strings.Split(tpact.TimingTags, utils.INFIELD_SEP) + for _, timingID := range timingIds { + if timing, found := tpr.timings[timingID]; found { + acts[idx].Balance.Timings = append(acts[idx].Balance.Timings, &RITiming{ + Years: timing.Years, + Months: timing.Months, + MonthDays: timing.MonthDays, + WeekDays: timing.WeekDays, + StartTime: timing.StartTime, + EndTime: timing.EndTime, + }) + } else { + return fmt.Errorf("could not find timing: %v", timingID) + } + } } } - acts[tag] = enacts + facts[tag] = acts } } // write actions - for k, as := range acts { + for k, as := range facts { err = tpr.ratingStorage.SetActions(k, as) if err != nil { return err @@ -1068,35 +1222,80 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { for _, atrsLst := range atrsM { atrs := make([]*ActionTrigger, len(atrsLst)) - for idx, apiAtr := range atrsLst { - minSleep, _ := utils.ParseDurationWithSecs(apiAtr.MinSleep) - balanceExpTime, _ := utils.ParseDate(apiAtr.BalanceExpirationDate) - expTime, _ := utils.ParseTimeDetectLayout(apiAtr.ExpirationDate, tpr.timezone) - actTime, _ := utils.ParseTimeDetectLayout(apiAtr.ActivationDate, tpr.timezone) - if apiAtr.UniqueID == "" { - apiAtr.UniqueID = utils.GenUUID() + for idx, atr := range atrsLst { + minSleep, _ := utils.ParseDurationWithSecs(atr.MinSleep) + expTime, _ := utils.ParseTimeDetectLayout(atr.ExpirationDate, tpr.timezone) + actTime, _ := utils.ParseTimeDetectLayout(atr.ActivationDate, tpr.timezone) + if atr.UniqueID == "" { + atr.UniqueID = utils.GenUUID() } atrs[idx] = &ActionTrigger{ - ID: triggerTag, - UniqueID: apiAtr.UniqueID, - ThresholdType: apiAtr.ThresholdType, - ThresholdValue: apiAtr.ThresholdValue, - Recurrent: apiAtr.Recurrent, - MinSleep: minSleep, - ExpirationDate: expTime, - ActivationDate: actTime, - BalanceId: apiAtr.BalanceId, - BalanceType: apiAtr.BalanceType, - BalanceDirections: utils.ParseStringMap(apiAtr.BalanceDirections), - BalanceDestinationIds: utils.ParseStringMap(apiAtr.BalanceDestinationIds), - BalanceWeight: apiAtr.BalanceWeight, - BalanceExpirationDate: balanceExpTime, - BalanceRatingSubject: apiAtr.BalanceRatingSubject, - BalanceCategories: utils.ParseStringMap(apiAtr.BalanceCategories), - BalanceSharedGroups: utils.ParseStringMap(apiAtr.BalanceSharedGroups), - BalanceTimingTags: utils.ParseStringMap(apiAtr.BalanceTimingTags), - Weight: apiAtr.Weight, - ActionsId: apiAtr.ActionsId, + ID: triggerTag, + UniqueID: atr.UniqueID, + ThresholdType: atr.ThresholdType, + ThresholdValue: atr.ThresholdValue, + Recurrent: atr.Recurrent, + MinSleep: minSleep, + ExpirationDate: expTime, + ActivationDate: actTime, + Balance: &BalancePointer{}, + Weight: atr.Weight, + ActionsId: atr.ActionsId, + } + if atr.BalanceId != "" && atr.BalanceId != utils.ANY { + atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId) + } + + if atr.BalanceType != "" && atr.BalanceType != utils.ANY { + atrs[idx].Balance.Type = utils.StringPointer(atr.BalanceType) + } + + if atr.BalanceWeight != "" && atr.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(atr.BalanceWeight, 64) + if err != nil { + return err + } + atrs[idx].Balance.Weight = utils.Float64Pointer(u) + } + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) + if err != nil { + return err + } + atrs[idx].Balance.ExpirationDate = utils.TimePointer(u) + } + if atr.BalanceRatingSubject != "" && atr.BalanceRatingSubject != utils.ANY { + atrs[idx].Balance.RatingSubject = utils.StringPointer(atr.BalanceRatingSubject) + } + + if atr.BalanceCategories != "" && atr.BalanceCategories != utils.ANY { + atrs[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceCategories)) + } + if atr.BalanceDirections != "" && atr.BalanceDirections != utils.ANY { + 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)) + } + if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY { + atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups)) + } + if atr.BalanceTimingTags != "" && atr.BalanceTimingTags != utils.ANY { + atrs[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceTimingTags)) + } + if atr.BalanceBlocker != "" && atr.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceBlocker) + if err != nil { + return err + } + atrs[idx].Balance.Blocker = utils.BoolPointer(u) + } + if atr.BalanceDisabled != "" && atr.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(atr.BalanceDisabled) + if err != nil { + return err + } + atrs[idx].Balance.Disabled = utils.BoolPointer(u) } } tpr.actionsTriggers[triggerTag] = atrs @@ -1134,7 +1333,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { return err } for tag, tpacts := range as { - enacts := make([]*Action, len(tpacts)) + acts := make([]*Action, len(tpacts)) for idx, tpact := range tpacts { // check filter field if len(tpact.Filter) > 0 { @@ -1142,30 +1341,74 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { return fmt.Errorf("error parsing action %s filter field: %v", tag, err) } } - enacts[idx] = &Action{ - Id: tag + strconv.Itoa(idx), - ActionType: tpact.Identifier, - BalanceType: tpact.BalanceType, + acts[idx] = &Action{ + Id: tag + strconv.Itoa(idx), + ActionType: tpact.Identifier, + //BalanceType: tpact.BalanceType, Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &Balance{ - Id: tpact.BalanceId, - Value: tpact.Units, - Weight: tpact.BalanceWeight, - RatingSubject: tpact.RatingSubject, - 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), - Blocker: tpact.BalanceBlocker, - Disabled: tpact.BalanceDisabled, - }, + Balance: &BalancePointer{}, } + if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { + acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) + } + if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY { + acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType) + } + + if tpact.Units != "" && tpact.Units != utils.ANY { + u, err := strconv.ParseFloat(tpact.Units, 64) + if err != nil { + return err + } + acts[idx].Balance.Value = utils.Float64Pointer(u) + } + + if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY { + u, err := strconv.ParseFloat(tpact.BalanceWeight, 64) + if err != nil { + return err + } + acts[idx].Balance.Weight = utils.Float64Pointer(u) + } + if tpact.RatingSubject != "" && tpact.RatingSubject != utils.ANY { + acts[idx].Balance.RatingSubject = utils.StringPointer(tpact.RatingSubject) + } + + if tpact.Categories != "" && tpact.Categories != utils.ANY { + acts[idx].Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(tpact.Categories)) + } + if tpact.Directions != "" && tpact.Directions != utils.ANY { + 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)) + } + if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY { + acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups)) + } + if tpact.TimingTags != "" && tpact.TimingTags != utils.ANY { + acts[idx].Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.TimingTags)) + } + if tpact.BalanceBlocker != "" && tpact.BalanceBlocker != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceBlocker) + if err != nil { + return err + } + acts[idx].Balance.Blocker = utils.BoolPointer(u) + } + if tpact.BalanceDisabled != "" && tpact.BalanceDisabled != utils.ANY { + u, err := strconv.ParseBool(tpact.BalanceDisabled) + if err != nil { + return err + } + acts[idx].Balance.Disabled = utils.BoolPointer(u) + } + } - tpr.actions[tag] = enacts + tpr.actions[tag] = acts } } } diff --git a/engine/units_counter.go b/engine/units_counter.go index 77aa21f31..f50532a2f 100644 --- a/engine/units_counter.go +++ b/engine/units_counter.go @@ -62,7 +62,9 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B bal.AddValue(amount) continue } - if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bal, true) { + bp := &BalancePointer{} + bp.LoadFromBalance(bal) + if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bp, true) { bal.AddValue(amount) continue } @@ -76,7 +78,7 @@ func (ucs UnitCounters) resetCounters(a *Action) { if uc == nil { // safeguard continue } - if a != nil && a.BalanceType != "" && a.BalanceType != uc.BalanceType { + if a != nil && a.Balance.Type != nil && a.Balance.GetType() != uc.BalanceType { continue } for _, b := range uc.Balances { diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go index aeee72cdf..cd8331fb3 100644 --- a/engine/units_counter_test.go +++ b/engine/units_counter_test.go @@ -50,46 +50,58 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -114,46 +126,58 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 20, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(20), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -178,54 +202,68 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 20, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(20), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceDestinationIds: utils.NewStringMap("NAT"), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR22", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDestinationIds: utils.NewStringMap("RET"), - BalanceWeight: 10, + UniqueID: "TestTR22", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -250,54 +288,68 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 20, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(20), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceDestinationIds: utils.NewStringMap("NAT"), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR22", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDestinationIds: utils.NewStringMap("RET"), - BalanceWeight: 10, + UniqueID: "TestTR22", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -336,46 +388,58 @@ func TestUnitCountersResetCounterById(t *testing.T) { a := &Account{ ActionTriggers: ActionTriggers{ &ActionTrigger{ - UniqueID: "TestTR1", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR11", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.MONETARY, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR2", - ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR3", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.VOICE, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.VOICE), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR4", - ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, &ActionTrigger{ - UniqueID: "TestTR5", - ThresholdType: utils.TRIGGER_MAX_BALANCE, - BalanceType: utils.SMS, - BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), - BalanceWeight: 10, + UniqueID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.SMS), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), + Weight: utils.Float64Pointer(10), + }, }, }, } @@ -395,9 +459,9 @@ func TestUnitCountersResetCounterById(t *testing.T) { t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters)) } a.UnitCounters.resetCounters(&Action{ - BalanceType: utils.MONETARY, - Balance: &Balance{ - Id: "TestTR11", + Balance: &BalancePointer{ + Type: utils.StringPointer(utils.MONETARY), + Id: utils.StringPointer("TestTR11"), }, }) if len(a.UnitCounters) != 4 || diff --git a/utils/coreutils.go b/utils/coreutils.go index 091e3fc07..4f857b07d 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -372,6 +372,10 @@ func StringMapPointer(sm StringMap) *StringMap { return &sm } +func TimePointer(t time.Time) *time.Time { + return &t +} + func ReflectFuncLocation(handler interface{}) (file string, line int) { f := runtime.FuncForPC(reflect.ValueOf(handler).Pointer()) entry := f.Entry() From cc96e6002346175661b5a76c6534074b0e894167 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 11 Feb 2016 13:40:37 +0200 Subject: [PATCH 03/15] refactoring --- engine/account.go | 5 +- engine/account_test.go | 56 +++++++------- engine/action.go | 24 +++--- engine/action_trigger.go | 5 +- engine/actions_test.go | 140 +++++++++++++++++------------------ engine/balances.go | 8 +- engine/balances_test.go | 18 ++--- engine/calldesc_test.go | 6 +- engine/loader_csv_test.go | 12 +-- engine/storage_test.go | 2 +- engine/tp_reader.go | 20 ++--- engine/units_counter.go | 10 ++- engine/units_counter_test.go | 66 ++++++++--------- utils/consts.go | 1 + 14 files changed, 195 insertions(+), 178 deletions(-) diff --git a/engine/account.go b/engine/account.go index 50650c546..7784208f3 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" @@ -587,6 +588,7 @@ func (acc *Account) ExecuteActionTriggers(a *Action) { // the next reset (see RESET_TRIGGERS action type) continue } + if !at.Match(a) { continue } @@ -673,9 +675,10 @@ 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] if !exists { + log.Print("HERE!") uc = &UnitCounter{ BalanceType: at.Balance.GetType(), CounterType: ct, diff --git a/engine/account_test.go b/engine/account_test.go index b603e135d..ae3dabd5e 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -814,7 +814,7 @@ func TestAccountdebitBalance(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1204}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.StringMap{"NAT": true}}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &BalancePointer{ + newMb := &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.StringMap{"NEW": true}), @@ -833,7 +833,7 @@ func TestAccountdebitBalance(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1204}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &BalancePointer{ + newMb := &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), @@ -856,7 +856,7 @@ func TestAccountdebitBalanceExists(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1024}}, utils.VOICE: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}}, } - newMb := &BalancePointer{ + newMb := &BalanceFilter{ Value: utils.Float64Pointer(-10), Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), @@ -883,19 +883,19 @@ func TestAccountAddMinuteNil(t *testing.T) { } func TestAccountAddMinutBucketEmpty(t *testing.T) { - mb1 := &BalancePointer{ + mb1 := &BalanceFilter{ Value: utils.Float64Pointer(-10), Type: utils.StringPointer(utils.VOICE), DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), } - mb2 := &BalancePointer{ + mb2 := &BalanceFilter{ Value: utils.Float64Pointer(-10), Type: utils.StringPointer(utils.VOICE), DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), } - mb3 := &BalancePointer{ + mb3 := &BalanceFilter{ Value: utils.Float64Pointer(-10), Type: utils.StringPointer(utils.VOICE), DestinationIds: utils.StringMapPointer(utils.StringMap{"OTHER": true}), @@ -924,7 +924,7 @@ 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: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.StringMap{utils.OUT: true}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, + 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) if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { @@ -948,7 +948,7 @@ 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: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 1}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}}, + 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) if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { @@ -961,7 +961,7 @@ 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: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}}, } ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil) @@ -976,11 +976,13 @@ func TestAccountExecuteTriggeredDayWeek(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{UniqueID: "day_trigger", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, - &ActionTrigger{UniqueID: "week_trigger", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{UniqueID: "day_trigger", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}, + &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]) } @@ -992,7 +994,7 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) { } // we can reset them - resetCountersAction(ub, nil, &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("day_trigger")}}, nil) + 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) @@ -1004,7 +1006,7 @@ func TestAccountExpActionTrigger(t *testing.T) { Id: "TEST_UB", BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100, ExpirationDate: time.Date(2015, time.November, 9, 9, 48, 0, 0, time.UTC)}}, 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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -1022,7 +1024,7 @@ func TestAccountExpActionTriggerNotActivated(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", ActivationDate: time.Date(2116, 2, 5, 18, 0, 0, 0, time.UTC), Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", ActivationDate: time.Date(2116, 2, 5, 18, 0, 0, 0, time.UTC), Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -1040,7 +1042,7 @@ func TestAccountExpActionTriggerExpired(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}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", ExpirationDate: time.Date(2016, 2, 4, 18, 0, 0, 0, time.UTC), Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", ExpirationDate: time.Date(2016, 2, 4, 18, 0, 0, 0, time.UTC), Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsId: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) @@ -1598,7 +1600,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1607,7 +1609,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1616,7 +1618,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1625,7 +1627,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1634,7 +1636,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1643,7 +1645,7 @@ func TestAccountInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1673,7 +1675,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1682,7 +1684,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1691,7 +1693,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1700,7 +1702,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1709,7 +1711,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -1718,7 +1720,7 @@ func TestAccountDoubleInitCounters(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), diff --git a/engine/action.go b/engine/action.go index 94ab9ba1e..ce4ec1a09 100644 --- a/engine/action.go +++ b/engine/action.go @@ -45,10 +45,10 @@ type Action struct { Filter string ExpirationString string // must stay as string because it can have relative values like 1month Weight float64 - Balance *BalancePointer + Balance *BalanceFilter } -type BalancePointer struct { +type BalanceFilter struct { Uuid *string Id *string Type *string @@ -67,7 +67,7 @@ type BalancePointer struct { Blocker *bool } -func (bp *BalancePointer) CreateBalance() *Balance { +func (bp *BalanceFilter) CreateBalance() *Balance { b := &Balance{} if bp.Uuid != nil { b.Uuid = *bp.Uuid @@ -114,7 +114,7 @@ func (bp *BalancePointer) CreateBalance() *Balance { return b.Clone() } -func (bp *BalancePointer) LoadFromBalance(b *Balance) { +func (bp *BalanceFilter) LoadFromBalance(b *Balance) { if b.Uuid != "" { bp.Uuid = &b.Uuid } @@ -155,20 +155,27 @@ func (bp *BalancePointer) LoadFromBalance(b *Balance) { bp.Blocker = &b.Blocker } -func (bp *BalancePointer) GetType() string { +func (bp *BalanceFilter) GetType() string { if bp.Type == nil { return "" } return *bp.Type } -func (bp *BalancePointer) GetValue() float64 { +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" @@ -492,9 +499,8 @@ func resetCountersAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Ac } func genericMakeNegative(a *Action) { - b := a.Balance.CreateBalance() - if a.Balance != nil && b.GetValue() >= 0 { // only apply if not allready negative - b.SetValue(-b.GetValue()) + if a.Balance != nil && a.Balance.GetValue() >= 0 { // only apply if not allready negative + a.Balance.SetValue(-a.Balance.GetValue()) } } diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 0fe22916c..90e42099d 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -37,7 +37,7 @@ type ActionTrigger struct { ExpirationDate time.Time ActivationDate time.Time //BalanceType string // *monetary/*voice etc - Balance *BalancePointer + Balance *BalanceFilter Weight float64 ActionsId string MinQueuedItems int // Trigger actions only if this number is hit (stats only) @@ -76,9 +76,8 @@ func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err erro continue } } - if a.Balance == nil { - a.Balance = &BalancePointer{} + a.Balance = &BalanceFilter{} } if a.ExpirationString != "" { a.Balance.ExpirationDate = &time.Time{} diff --git a/engine/actions_test.go b/engine/actions_test.go index e0e4244db..9917759da 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -410,7 +410,7 @@ func TestActionPlanCheckForASAP(t *testing.T) { func TestActionPlanLogFunction(t *testing.T) { a := &Action{ ActionType: "*log", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("test"), Value: utils.Float64Pointer(1.1), }, @@ -427,7 +427,7 @@ func TestActionPlanLogFunction(t *testing.T) { func TestActionPlanFunctionNotAvailable(t *testing.T) { a := &Action{ ActionType: "VALID_FUNCTION_TYPE", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("test"), Value: utils.Float64Pointer(1.1), }, @@ -531,7 +531,7 @@ func TestActionPlansRemoveMember(t *testing.T) { func TestActionTriggerMatchNil(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, @@ -546,7 +546,7 @@ func TestActionTriggerMatchNil(t *testing.T) { func TestActionTriggerMatchAllBlank(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, @@ -561,14 +561,14 @@ func TestActionTriggerMatchAllBlank(t *testing.T) { func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: `{"BalanceDirections":"*out"}`} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: `{"BalanceDirections":"*out"}`} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -576,7 +576,7 @@ func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) { func TestActionTriggerMatchMinuteBucketFull(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, @@ -591,14 +591,14 @@ func TestActionTriggerMatchMinuteBucketFull(t *testing.T) { func TestActionTriggerMatchAllFull(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 2)} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 2)} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -606,14 +606,14 @@ func TestActionTriggerMatchAllFull(t *testing.T) { func TestActionTriggerMatchSomeFalse(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalancePointer{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":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_BALANCE, 2)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -621,14 +621,14 @@ func TestActionTriggerMatchSomeFalse(t *testing.T) { func TestActionTriggerMatcBalanceFalse(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalancePointer{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)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 3.0)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -636,14 +636,14 @@ func TestActionTriggerMatcBalanceFalse(t *testing.T) { func TestActionTriggerMatcAllFalse(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), }, ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalancePointer{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(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_EVENT_COUNTER, 3)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -651,7 +651,7 @@ func TestActionTriggerMatcAllFalse(t *testing.T) { func TestActionTriggerMatchAll(t *testing.T) { at := &ActionTrigger{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), RatingSubject: utils.StringPointer("test1"), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), @@ -662,7 +662,7 @@ func TestActionTriggerMatchAll(t *testing.T) { }, ThresholdType: utils.TRIGGER_MAX_BALANCE, } - a := &Action{Balance: &BalancePointer{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)}, 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")} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -685,7 +685,7 @@ func TestActionResetTriggres(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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) if ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true { @@ -698,7 +698,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { Id: "TEST_UB", BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}}, UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) if ub.ActionTriggers[0].Executed == true || ub.BalanceMap[utils.MONETARY][0].GetValue() == 12 { @@ -711,9 +711,9 @@ func TestActionResetTriggresActionFilter(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{Type: utils.StringPointer(utils.SMS)}}, nil) + resetTriggersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}}, nil) if ub.ActionTriggers[0].Executed == false || ub.ActionTriggers[1].Executed == false { t.Error("Reset triggers action failed!") } @@ -724,7 +724,7 @@ func TestActionSetPostpaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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) if !ub.AllowNegative { @@ -738,7 +738,7 @@ func TestActionSetPrepaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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) if ub.AllowNegative { @@ -752,7 +752,7 @@ func TestActionResetPrepaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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) if !ub.AllowNegative || @@ -770,7 +770,7 @@ func TestActionResetPostpaid(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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) if ub.BalanceMap[utils.MONETARY].GetTotalValue() != 0 || @@ -786,9 +786,9 @@ func TestActionTopupResetCredit(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.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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + 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 || @@ -805,7 +805,7 @@ func TestActionTopupValueFactor(t *testing.T) { BalanceMap: map[string]BalanceChain{}, } a := &Action{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), @@ -828,7 +828,7 @@ func TestActionTopupResetCreditId(t *testing.T) { }, }, } - a := &Action{Balance: &BalancePointer{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 || @@ -847,7 +847,7 @@ func TestActionTopupResetCreditNoId(t *testing.T) { }, }, } - a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + 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() != 20 || @@ -863,9 +863,9 @@ func TestActionTopupResetMinutes(t *testing.T) { 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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{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 || @@ -882,9 +882,9 @@ func TestActionTopupCredit(t *testing.T) { 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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + 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 || @@ -900,9 +900,9 @@ func TestActionTopupMinutes(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{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 || @@ -919,9 +919,9 @@ func TestActionDebitCredit(t *testing.T) { 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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + 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 || @@ -937,9 +937,9 @@ func TestActionDebitMinutes(t *testing.T) { 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}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{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 || @@ -961,7 +961,7 @@ 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: &BalancePointer{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) @@ -989,9 +989,9 @@ 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")}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}} ub.InitCounters() resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || @@ -1020,9 +1020,9 @@ func TestActionResetCounterCredit(t *testing.T) { 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)}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, + 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: &BalancePointer{Type: utils.StringPointer(utils.MONETARY)}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}} resetCountersAction(ub, nil, a, nil) if !ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 || @@ -1036,7 +1036,7 @@ func TestActionResetCounterCredit(t *testing.T) { func TestActionTriggerLogging(t *testing.T) { at := &ActionTrigger{ ID: "some_uuid", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), @@ -1108,7 +1108,7 @@ func TestActionPlanLogging(t *testing.T) { } func TestActionMakeNegative(t *testing.T) { - a := &Action{Balance: &BalancePointer{Value: utils.Float64Pointer(10)}} + a := &Action{Balance: &BalanceFilter{Value: utils.Float64Pointer(10)}} genericMakeNegative(a) if a.Balance.GetValue() > 0 { t.Error("Failed to make negative: ", a) @@ -1142,7 +1142,7 @@ func TestTopupAction(t *testing.T) { initialUb, _ := accountingStorage.GetAccount("vdf:minu") a := &Action{ ActionType: TOPUP, - Balance: &BalancePointer{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 +1163,7 @@ func TestTopupActionLoaded(t *testing.T) { initialUb, _ := accountingStorage.GetAccount("vdf:minitsboy") a := &Action{ ActionType: TOPUP, - Balance: &BalancePointer{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 +1190,7 @@ func TestActionCdrlogEmpty(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalancePointer{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 +1212,11 @@ func TestActionCdrlogWithParams(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalancePointer{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: &BalancePointer{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 +1239,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalancePointer{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: &BalancePointer{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 { @@ -1324,11 +1324,11 @@ func TestActionTransactionFuncType(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, + Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ ActionType: "VALID_FUNCTION_TYPE", - Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer("test")}, + Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer("test")}, }, }, } @@ -1360,11 +1360,11 @@ func TestActionTransactionBalanceType(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalancePointer{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, + Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ ActionType: TOPUP, - Balance: &BalancePointer{Type: utils.StringPointer("test")}, + Balance: &BalanceFilter{Type: utils.StringPointer("test")}, }, }, } @@ -1396,14 +1396,14 @@ func TestActionWithExpireWithoutExpire(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(15), }, }, &Action{ ActionType: TOPUP, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(30), ExpirationDate: utils.TimePointer(time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC)), @@ -1451,7 +1451,7 @@ func TestActionRemoveBalance(t *testing.T) { actions: []*Action{ &Action{ ActionType: REMOVE_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")), }, @@ -1561,7 +1561,7 @@ func TestActionTransferMonetaryDefaultFilter(t *testing.T) { a := &Action{ ActionType: TRANSFER_MONETARY_DEFAULT, - Balance: &BalancePointer{Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Weight: utils.Float64Pointer(20)}, } at := &ActionTiming{ @@ -1623,7 +1623,7 @@ func TestActionConditionalTopup(t *testing.T) { a := &Action{ ActionType: TOPUP, Filter: `{"Type":"*monetary","Value":1,"Weight":10}`, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(11), Weight: utils.Float64Pointer(30), @@ -1687,7 +1687,7 @@ func TestActionConditionalTopupNoMatch(t *testing.T) { a := &Action{ ActionType: TOPUP, Filter: `{"Type":"*monetary","Value":2,"Weight":10}`, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(11), Weight: utils.Float64Pointer(30), @@ -1751,7 +1751,7 @@ func TestActionConditionalTopupExistingBalance(t *testing.T) { a := &Action{ ActionType: TOPUP, Filter: `{"Type":"*voice","Value":{"*gte":100}}`, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(11), Weight: utils.Float64Pointer(10), @@ -1852,7 +1852,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { a1 := &Action{ ActionType: "*enable_disable_balance", Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("*sms"), Weight: utils.Float64Pointer(10), Disabled: utils.BoolPointer(true), @@ -1862,7 +1862,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { a2 := &Action{ ActionType: "*enable_disable_balance", Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("*sms"), DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")), Weight: utils.Float64Pointer(10), @@ -1873,7 +1873,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { a3 := &Action{ ActionType: "*enable_disable_balance", Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("*data"), RatingSubject: utils.StringPointer("for_v3hsillmilld500m_data_forfait"), Weight: utils.Float64Pointer(10), @@ -1884,7 +1884,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { a4 := &Action{ ActionType: "*enable_disable_balance", Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}", - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer("*voice"), DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")), Weight: utils.Float64Pointer(10), @@ -1956,7 +1956,7 @@ func TestActionSetBalance(t *testing.T) { a := &Action{ ActionType: SET_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Id: utils.StringPointer("m2"), Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(11), diff --git a/engine/balances.go b/engine/balances.go index 38dd1e8e4..80fc005d6 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -72,7 +72,7 @@ func (b *Balance) Equal(o *Balance) bool { b.Blocker == o.Blocker } -func (b *Balance) MatchFilter(o *BalancePointer, skipIds bool) bool { +func (b *Balance) MatchFilter(o *BalanceFilter, skipIds bool) bool { if o == nil { return true } @@ -84,7 +84,7 @@ func (b *Balance) MatchFilter(o *BalancePointer, skipIds bool) bool { } return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) && (o.Weight == nil || b.Weight == *o.Weight) && - (o.Blocker != nil || b.Blocker == *o.Blocker) && + (o.Blocker == nil || b.Blocker == *o.Blocker) && (o.Disabled == nil || b.Disabled == *o.Disabled) && (o.DestinationIds == nil || b.DestinationIds.Includes(*o.DestinationIds)) && (o.Directions == nil || b.Directions.Includes(*o.Directions)) && @@ -94,7 +94,7 @@ func (b *Balance) MatchFilter(o *BalancePointer, skipIds bool) bool { (o.RatingSubject == nil || b.RatingSubject == *o.RatingSubject) } -func (b *Balance) HardMatchFilter(o *BalancePointer, skipIds bool) bool { +func (b *Balance) HardMatchFilter(o *BalanceFilter, skipIds bool) bool { if o == nil { return true } @@ -106,7 +106,7 @@ func (b *Balance) HardMatchFilter(o *BalancePointer, skipIds bool) bool { } return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) && (o.Weight == nil || b.Weight == *o.Weight) && - (o.Blocker != nil || b.Blocker == *o.Blocker) && + (o.Blocker == nil || b.Blocker == *o.Blocker) && (o.Disabled == nil || b.Disabled == *o.Disabled) && (o.DestinationIds == nil || b.DestinationIds.Equal(*o.DestinationIds)) && (o.Directions == nil || b.Directions.Equal(*o.Directions)) && diff --git a/engine/balances_test.go b/engine/balances_test.go index 09c9dd17f..93a9f23db 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 := &BalancePointer{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) } @@ -98,7 +98,7 @@ func TestBalanceMatchFilter(t *testing.T) { func TestBalanceMatchFilterEmpty(t *testing.T) { mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}} - mb2 := &BalancePointer{} + mb2 := &BalanceFilter{} 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 := &BalancePointer{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 := &BalancePointer{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: &BalancePointer{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) @@ -150,7 +150,7 @@ func TestBalanceMatchActionTriggerId(t *testing.T) { } func TestBalanceMatchActionTriggerDestination(t *testing.T) { - at := &ActionTrigger{Balance: &BalancePointer{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) @@ -171,7 +171,7 @@ func TestBalanceMatchActionTriggerDestination(t *testing.T) { } func TestBalanceMatchActionTriggerWeight(t *testing.T) { - at := &ActionTrigger{Balance: &BalancePointer{Weight: utils.Float64Pointer(1)}} + at := &ActionTrigger{Balance: &BalanceFilter{Weight: utils.Float64Pointer(1)}} b := &Balance{Weight: 1} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) @@ -192,7 +192,7 @@ func TestBalanceMatchActionTriggerWeight(t *testing.T) { } func TestBalanceMatchActionTriggerRatingSubject(t *testing.T) { - at := &ActionTrigger{Balance: &BalancePointer{RatingSubject: utils.StringPointer("test")}} + at := &ActionTrigger{Balance: &BalanceFilter{RatingSubject: utils.StringPointer("test")}} b := &Balance{RatingSubject: "test"} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) @@ -213,7 +213,7 @@ func TestBalanceMatchActionTriggerRatingSubject(t *testing.T) { } func TestBalanceMatchActionTriggerSharedGroup(t *testing.T) { - at := &ActionTrigger{Balance: &BalancePointer{SharedGroups: utils.StringMapPointer(utils.NewStringMap("test"))}} + at := &ActionTrigger{Balance: &BalanceFilter{SharedGroups: utils.StringMapPointer(utils.NewStringMap("test"))}} b := &Balance{SharedGroups: utils.NewStringMap("test")} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index e4d5cdc9e..cbac46036 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -41,12 +41,12 @@ func init() { func populateDB() { ats := []*Action{ - &Action{ActionType: "*topup", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}}, - &Action{ActionType: "*topup", Balance: &BalancePointer{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.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"))}}, } ats1 := []*Action{ - &Action{ActionType: "*topup", Balance: &BalancePointer{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}, Weight: 10}, + &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}, Weight: 10}, &Action{ActionType: "*reset_account", Weight: 20}, } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 4cb27daf0..9c6073051 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -826,7 +826,7 @@ func TestLoadActions(t *testing.T) { ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Uuid: as1[0].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), @@ -844,7 +844,7 @@ func TestLoadActions(t *testing.T) { ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Uuid: as1[1].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), @@ -868,7 +868,7 @@ func TestLoadActions(t *testing.T) { ActionType: TOPUP, ExpirationString: UNLIMITED, Weight: 10, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: nil, @@ -891,7 +891,7 @@ func TestLoadActions(t *testing.T) { ActionType: CDRLOG, ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`, Weight: 10, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Uuid: as3[0].Balance.Uuid, Directions: nil, DestinationIds: nil, @@ -1047,7 +1047,7 @@ func TestLoadActionTriggers(t *testing.T) { UniqueID: "st0", ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ThresholdValue: 10, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")), @@ -1068,7 +1068,7 @@ func TestLoadActionTriggers(t *testing.T) { UniqueID: "st1", ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 200, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY")), diff --git a/engine/storage_test.go b/engine/storage_test.go index 1a38f6bd2..2c1b9b808 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -317,7 +317,7 @@ func GetUB() *Account { at := &ActionTrigger{ ID: "some_uuid", ThresholdValue: 100.0, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 27075be55..bfa6615d6 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -521,7 +521,7 @@ func (tpr *TpReader) LoadActions() (err error) { ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, } if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) @@ -545,7 +545,7 @@ func (tpr *TpReader) LoadActions() (err error) { } acts[idx].Balance.Weight = utils.Float64Pointer(u) } - if tpact.ExpiryTime != "" && tpact.ExpiryTime != utils.ANY { + if tpact.ExpiryTime != "" && tpact.ExpiryTime != utils.ANY && tpact.ExpiryTime != utils.UNLIMITED { u, err := utils.ParseTimeDetectLayout(tpact.ExpiryTime, tpr.timezone) if err != nil { return err @@ -700,7 +700,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { MinSleep: minSleep, ExpirationDate: expirationDate, ActivationDate: activationDate, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, Weight: atr.Weight, ActionsId: atr.ActionsId, MinQueuedItems: atr.MinQueuedItems, @@ -720,7 +720,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { } atrs[idx].Balance.Weight = utils.Float64Pointer(u) } - if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY && atr.ExpirationDate != utils.UNLIMITED { u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) if err != nil { return err @@ -901,7 +901,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error MinSleep: minSleep, ExpirationDate: expTime, ActivationDate: actTime, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, Weight: atr.Weight, ActionsId: atr.ActionsId, } @@ -920,7 +920,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error } atrs[idx].Balance.Weight = utils.Float64Pointer(u) } - if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY && atr.ExpirationDate != utils.UNLIMITED { u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) if err != nil { return err @@ -1003,7 +1003,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, } if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) @@ -1238,7 +1238,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { MinSleep: minSleep, ExpirationDate: expTime, ActivationDate: actTime, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, Weight: atr.Weight, ActionsId: atr.ActionsId, } @@ -1257,7 +1257,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { } atrs[idx].Balance.Weight = utils.Float64Pointer(u) } - if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY { + if atr.BalanceExpirationDate != "" && atr.BalanceExpirationDate != utils.ANY && atr.ExpirationDate != utils.UNLIMITED { u, err := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) if err != nil { return err @@ -1349,7 +1349,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Filter: tpact.Filter, - Balance: &BalancePointer{}, + Balance: &BalanceFilter{}, } if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY { acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId) diff --git a/engine/units_counter.go b/engine/units_counter.go index f50532a2f..7854aa9ec 100644 --- a/engine/units_counter.go +++ b/engine/units_counter.go @@ -18,7 +18,11 @@ along with this program. If not, see package engine -import "github.com/cgrates/cgrates/utils" +import ( + "log" + + "github.com/cgrates/cgrates/utils" +) // Amount of a trafic of a certain type type UnitCounter struct { @@ -58,11 +62,13 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B 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) continue } - bp := &BalancePointer{} + bp := &BalanceFilter{} bp.LoadFromBalance(bal) if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bp, true) { bal.AddValue(amount) diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go index cd8331fb3..4ca1ec849 100644 --- a/engine/units_counter_test.go +++ b/engine/units_counter_test.go @@ -52,7 +52,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -61,7 +61,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -70,7 +70,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -79,7 +79,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -88,7 +88,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -97,7 +97,7 @@ func TestUnitCountersCountAllMonetary(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -128,7 +128,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -137,7 +137,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20), @@ -146,7 +146,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -155,7 +155,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -164,7 +164,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -173,7 +173,7 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -204,7 +204,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -213,7 +213,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20), @@ -222,7 +222,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), @@ -232,7 +232,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR22", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(10), @@ -241,7 +241,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -250,7 +250,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -259,7 +259,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -290,7 +290,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -299,7 +299,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20), @@ -308,7 +308,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), @@ -318,7 +318,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR22", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(10), @@ -327,7 +327,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -336,7 +336,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -345,7 +345,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(10), @@ -390,7 +390,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR1", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -399,7 +399,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR11", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -408,7 +408,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR2", ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -417,7 +417,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR3", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -426,7 +426,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR4", ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -435,7 +435,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { &ActionTrigger{ UniqueID: "TestTR5", ThresholdType: utils.TRIGGER_MAX_BALANCE, - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.SMS), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)), Weight: utils.Float64Pointer(10), @@ -459,7 +459,7 @@ func TestUnitCountersResetCounterById(t *testing.T) { t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters)) } a.UnitCounters.resetCounters(&Action{ - Balance: &BalancePointer{ + Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("TestTR11"), }, diff --git a/utils/consts.go b/utils/consts.go index b1f0559f8..ec397c55d 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -89,6 +89,7 @@ const ( ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down" ANY = "*any" + UNLIMITED = "*unlimited" ZERO = "*zero" ASAP = "*asap" USERS = "*users" From da4c1ca2da916c0ac0bac6b12d5e7d214e421458 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 15 Feb 2016 23:05:35 +0200 Subject: [PATCH 04/15] 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)) From db787e3e355417117504e678c01bd12f78f89d70 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 16 Feb 2016 11:30:52 +0200 Subject: [PATCH 05/15] execute action trigger loop protection --- engine/account.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/engine/account.go b/engine/account.go index 0130f1fb7..b1cbb463b 100644 --- a/engine/account.go +++ b/engine/account.go @@ -36,12 +36,13 @@ Structure containing information about user's credit (minutes, cents, sms...).' This can represent a user or a shared group. */ type Account struct { - Id string - BalanceMap map[string]BalanceChain - UnitCounters UnitCounters - ActionTriggers ActionTriggers - AllowNegative bool - Disabled bool + Id string + BalanceMap map[string]BalanceChain + UnitCounters UnitCounters + ActionTriggers ActionTriggers + AllowNegative bool + Disabled bool + executingTriggers bool } // User's available minutes for the specified destination @@ -572,6 +573,14 @@ func (ub *Account) refundIncrement(increment *Increment, cd *CallDescriptor, cou // Scans the action trigers and execute the actions for which trigger is met func (acc *Account) ExecuteActionTriggers(a *Action) { + if acc.executingTriggers { + return + } + acc.executingTriggers = true + defer func() { + acc.executingTriggers = false + }() + acc.ActionTriggers.Sort() for _, at := range acc.ActionTriggers { // check is effective @@ -648,7 +657,7 @@ func (acc *Account) ResetActionTriggers(a *Action) { } at.Executed = false } - acc.ExecuteActionTriggers(a) //will trigger infinite loop when executed from ExecuteActionTriggers + acc.ExecuteActionTriggers(a) } // Sets/Unsets recurrent flag for action triggers From e30fe4f6ce0d518d70bc50ad883eebfd8c50ffef Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 16 Feb 2016 22:45:23 +0200 Subject: [PATCH 06/15] unit tests passing --- apier/v1/accounts.go | 343 +++++++++++++++++---------------- apier/v1/apier.go | 131 ++++--------- apier/v1/apier_local_test.go | 8 +- apier/v1/triggers.go | 24 +-- engine/account.go | 3 + engine/action.go | 2 +- general_tests/acntacts_test.go | 2 +- 7 files changed, 232 insertions(+), 281 deletions(-) diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index bed4ce81c..d6273b517 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -353,21 +353,21 @@ func (self *ApierV1) GetAccount(attr *utils.AttrGetAccount, reply *interface{}) type AttrAddBalance struct { Tenant string Account string - BalanceUuid string - BalanceId string + BalanceUuid *string + BalanceId *string BalanceType string - Directions string + Directions *string Value float64 - ExpiryTime string - RatingSubject string - Categories string - DestinationIds string - TimingIds string - Weight float64 - SharedGroups string + ExpiryTime *string + RatingSubject *string + Categories *string + DestinationIds *string + TimingIds *string + Weight *float64 + SharedGroups *string Overwrite bool // When true it will reset if the balance is already there - Blocker bool - Disabled bool + Blocker *bool + Disabled *bool } func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { @@ -378,13 +378,17 @@ func (self *ApierV1) DebitBalance(attr *AttrAddBalance, reply *string) error { } func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *string) error { - if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { + if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType", "Value"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone) - if err != nil { - *reply = err.Error() - return err + var expTime *time.Time + if attr.ExpiryTime != nil { + expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, self.Config.DefaultTimezone) + if err != nil { + *reply = err.Error() + return err + } + expTime = &expTimeVal } accID := utils.AccountKey(attr.Tenant, attr.Account) if _, err := self.AccountDb.GetAccount(accID); err != nil { @@ -403,27 +407,36 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st if attr.Overwrite { aType += "_reset" // => *topup_reset/*debit_reset } - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: aType, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuid: attr.BalanceUuid, - Id: attr.BalanceId, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIds: utils.ParseStringMap(attr.DestinationIds), - Categories: utils.ParseStringMap(attr.Categories), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - TimingIDs: utils.ParseStringMap(attr.TimingIds), - Blocker: attr.Blocker, - Disabled: attr.Disabled, - }, + a := &engine.Action{ + ActionType: aType, + Balance: &engine.BalanceFilter{ + Uuid: attr.BalanceUuid, + ID: attr.BalanceId, + Type: utils.StringPointer(attr.BalanceType), + Value: utils.Float64Pointer(attr.Value), + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Weight: attr.Weight, + Blocker: attr.Blocker, + Disabled: attr.Disabled, }, - }) + } + if attr.Directions != nil { + a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions)) + } + if attr.DestinationIds != nil { + a.Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.DestinationIds)) + } + if attr.Categories != nil { + a.Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(*attr.Categories)) + } + if attr.SharedGroups != nil { + a.Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(*attr.SharedGroups)) + } + if attr.TimingIds != nil { + a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) + } + at.SetActions(engine.Actions{a}) if err := at.Execute(); err != nil { *reply = err.Error() return err @@ -432,7 +445,95 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st return nil } -func (self *ApierV1) EnableDisableBalance(attr *AttrAddBalance, reply *string) error { +type AttrSetBalance struct { + Tenant string + Account string + BalanceType string + BalanceUUID *string + BalanceID *string + Directions *string + Value *float64 + ExpiryTime *string + RatingSubject *string + Categories *string + DestinationIds *string + TimingIds *string + Weight *float64 + SharedGroups *string + Blocker *bool + Disabled *bool +} + +func (self *ApierV1) SetBalance(aType string, attr *AttrSetBalance, reply *string) error { + if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { + return utils.NewErrMandatoryIeMissing(missing...) + } + if (attr.BalanceID == nil || *attr.BalanceID == "") && + (attr.BalanceUUID == nil || *attr.BalanceUUID == "") { + return utils.NewErrMandatoryIeMissing("BalanceID", "or", "BalanceUUID") + } + var expTime *time.Time + if attr.ExpiryTime != nil { + expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, self.Config.DefaultTimezone) + if err != nil { + *reply = err.Error() + return err + } + expTime = &expTimeVal + } + accID := utils.AccountKey(attr.Tenant, attr.Account) + if _, err := self.AccountDb.GetAccount(accID); err != nil { + // create account if not exists + account := &engine.Account{ + Id: accID, + } + if err := self.AccountDb.SetAccount(account); err != nil { + *reply = err.Error() + return err + } + } + at := &engine.ActionTiming{} + at.SetAccountIDs(utils.StringMap{accID: true}) + + a := &engine.Action{ + ActionType: engine.SET_BALANCE, + Balance: &engine.BalanceFilter{ + Uuid: attr.BalanceUUID, + ID: attr.BalanceID, + Type: utils.StringPointer(attr.BalanceType), + Value: attr.Value, + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Weight: attr.Weight, + Blocker: attr.Blocker, + Disabled: attr.Disabled, + }, + } + if attr.Directions != nil { + a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions)) + } + if attr.DestinationIds != nil { + a.Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.DestinationIds)) + } + if attr.Categories != nil { + a.Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(*attr.Categories)) + } + if attr.SharedGroups != nil { + a.Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(*attr.SharedGroups)) + } + if attr.TimingIds != nil { + a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) + } + at.SetActions(engine.Actions{a}) + if err := at.Execute(); err != nil { + *reply = err.Error() + return err + } + *reply = OK + return nil +} + +/*func (self *ApierV1) EnableDisableBalance(attr *AttrAddBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } @@ -475,16 +576,20 @@ func (self *ApierV1) EnableDisableBalance(attr *AttrAddBalance, reply *string) e } *reply = OK return nil -} +}*/ -func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error { +func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone) - if err != nil { - *reply = err.Error() - return err + var expTime *time.Time + if attr.ExpiryTime != nil { + expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, self.Config.DefaultTimezone) + if err != nil { + *reply = err.Error() + return err + } + expTime = &expTimeVal } accID := utils.AccountKey(attr.Tenant, attr.Account) if _, err := self.AccountDb.GetAccount(accID); err != nil { @@ -493,138 +598,36 @@ func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error { at := &engine.ActionTiming{} at.SetAccountIDs(utils.StringMap{accID: true}) - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: engine.REMOVE_BALANCE, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuid: attr.BalanceUuid, - Id: attr.BalanceId, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIds: utils.ParseStringMap(attr.DestinationIds), - Categories: utils.ParseStringMap(attr.Categories), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - TimingIDs: utils.ParseStringMap(attr.TimingIds), - Blocker: attr.Blocker, - Disabled: attr.Disabled, - }, + a := &engine.Action{ + ActionType: engine.SET_BALANCE, + Balance: &engine.BalanceFilter{ + Uuid: attr.BalanceUUID, + ID: attr.BalanceID, + Type: utils.StringPointer(attr.BalanceType), + Value: attr.Value, + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Weight: attr.Weight, + Blocker: attr.Blocker, + Disabled: attr.Disabled, }, - }) - if err := at.Execute(); err != nil { - *reply = err.Error() - return err - } - *reply = OK - return nil -} - -type AttrSetBalance struct { - Tenant string - Account string - BalanceType string - BalanceUUID *string - BalanceID *string - Directions *[]string - Value *float64 - ExpiryTime *string - RatingSubject *string - Categories *[]string - DestinationIDs *[]string - SharedGroups *[]string - TimingIDs *[]string - Weight *float64 - Blocker *bool - Disabled *bool - expTime time.Time -} - -func (attr *AttrSetBalance) SetBalance(b *engine.Balance) { - if b == nil { - return } if attr.Directions != nil { - b.Directions = utils.StringMapFromSlice(*attr.Directions) + a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions)) } - if attr.Value != nil { - b.Value = *attr.Value - } - if attr.ExpiryTime != nil { - b.ExpirationDate = attr.expTime - } - if attr.RatingSubject != nil { - b.RatingSubject = *attr.RatingSubject + if attr.DestinationIds != nil { + a.Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.DestinationIds)) } if attr.Categories != nil { - b.Categories = utils.StringMapFromSlice(*attr.Categories) - } - if attr.DestinationIDs != nil { - b.DestinationIds = utils.StringMapFromSlice(*attr.DestinationIDs) + a.Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(*attr.Categories)) } if attr.SharedGroups != nil { - b.SharedGroups = utils.StringMapFromSlice(*attr.SharedGroups) + a.Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(*attr.SharedGroups)) } - if attr.TimingIDs != nil { - b.TimingIDs = utils.StringMapFromSlice(*attr.TimingIDs) + if attr.TimingIds != nil { + a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) } - if attr.Weight != nil { - b.Weight = *attr.Weight - } - if attr.Blocker != nil { - b.Blocker = *attr.Blocker - } - if attr.Disabled != nil { - b.Disabled = *attr.Disabled - } - b.SetDirty() // Mark the balance as dirty since we have modified and it should be checked by action triggers -} - -/* // SetAccount api using action and action timing to set balance, -//to be uncommented when using pointers in action.balance -func (self *ApierV1) SetBalance(attr *AttrAddBalance, reply *string) error { - if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { - return utils.NewErrMandatoryIeMissing(missing...) - } - if attr.BalanceID == "" && attr.BalanceUUID == "" { - return utils.NewErrMandatoryIeMissing("BalanceID", "or", "BalanceUUID") - } - expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone) - if err != nil { - *reply = err.Error() - return err - } - accID := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.AccountDb.GetAccount(accID); err != nil { - return utils.ErrNotFound - } - - at := &engine.ActionTiming{} - at.SetAccountIDs(utils.StringMap{accID: true}) - - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: engine.SET_BALANCE, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuuid: attr.BalanceUUID, - ID: attr.BalanceID, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIDs: utils.ParseStringMap(attr.DestinationIDs), - Categories: utils.ParseStringMap(attr.Categories), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - TimingIDs: utils.ParseStringMap(attr.TimingIDs), - Blocker: true, - Disabled: attr.Disabled, - }, - }, - }) + at.SetActions(engine.Actions{a}) if err := at.Execute(); err != nil { *reply = err.Error() return err @@ -632,16 +635,13 @@ func (self *ApierV1) SetBalance(attr *AttrAddBalance, reply *string) error { *reply = OK return nil } -*/ +/* To be removed after the above one proves reliable func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - if (attr.BalanceID == nil || *attr.BalanceID == "") && - (attr.BalanceUUID == nil || *attr.BalanceUUID == "") { - return utils.NewErrMandatoryIeMissing("BalanceID", "or", "BalanceUUID") - } + var err error if attr.ExpiryTime != nil { attr.expTime, err = utils.ParseTimeDetectLayout(*attr.ExpiryTime, self.Config.DefaultTimezone) @@ -727,3 +727,4 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { *reply = utils.OK return nil } +*/ diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 2b4f4b576..2497ac17a 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -19,12 +19,12 @@ along with this program. If not, see package v1 import ( - "encoding/json" "errors" "fmt" "log" "os" "path" + "strconv" "strings" "time" @@ -502,23 +502,37 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error } storeActions := make(engine.Actions, len(attrs.Actions)) for idx, apiAct := range attrs.Actions { + var units *float64 + if x, err := strconv.ParseFloat(apiAct.Units, 64); err == nil { + units = &x + } else { + return err + } + + var weight *float64 + if x, err := strconv.ParseFloat(apiAct.BalanceWeight, 64); err == nil { + weight = &x + } else { + return err + } + a := &engine.Action{ Id: utils.GenUUID(), ActionType: apiAct.Identifier, - BalanceType: apiAct.BalanceType, Weight: apiAct.Weight, ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, Filter: apiAct.Filter, - Balance: &engine.Balance{ - Uuid: utils.GenUUID(), - Id: apiAct.BalanceId, - Value: apiAct.Units, - Weight: apiAct.BalanceWeight, - Directions: utils.ParseStringMap(apiAct.Directions), - DestinationIds: utils.ParseStringMap(apiAct.DestinationIds), - RatingSubject: apiAct.RatingSubject, - SharedGroups: utils.ParseStringMap(apiAct.SharedGroups), + Balance: &engine.BalanceFilter{ // TODO: update this part + Uuid: utils.StringPointer(utils.GenUUID()), + ID: utils.StringPointer(apiAct.BalanceId), + Type: utils.StringPointer(apiAct.BalanceType), + Value: units, + Weight: weight, + Directions: utils.StringMapPointer(utils.ParseStringMap(apiAct.Directions)), + DestinationIDs: utils.StringMapPointer(utils.ParseStringMap(apiAct.DestinationIds)), + RatingSubject: utils.StringPointer(apiAct.RatingSubject), + SharedGroups: utils.StringMapPointer(utils.ParseStringMap(apiAct.SharedGroups)), }, } storeActions[idx] = a @@ -543,24 +557,25 @@ func (self *ApierV1) GetActions(actsId string, reply *[]*utils.TPAction) error { } for _, engAct := range engActs { act := &utils.TPAction{Identifier: engAct.ActionType, - BalanceType: engAct.BalanceType, ExpiryTime: engAct.ExpirationString, ExtraParameters: engAct.ExtraParameters, Filter: engAct.Filter, Weight: engAct.Weight, } - if engAct.Balance != nil { - act.Units = engAct.Balance.GetValue() - act.Directions = engAct.Balance.Directions.String() - act.DestinationIds = engAct.Balance.DestinationIds.String() - act.RatingSubject = engAct.Balance.RatingSubject - act.SharedGroups = engAct.Balance.SharedGroups.String() - act.BalanceWeight = engAct.Balance.Weight - act.TimingTags = engAct.Balance.TimingIDs.String() - act.BalanceId = engAct.Balance.Id - act.Categories = engAct.Balance.Categories.String() - act.BalanceBlocker = engAct.Balance.Blocker - act.BalanceDisabled = engAct.Balance.Disabled + bf := engAct.Balance + if bf != nil { + act.BalanceType = bf.GetType() + act.Units = strconv.FormatFloat(bf.GetValue(), 'f', -1, 64) + act.Directions = bf.GetDirections().String() + act.DestinationIds = bf.GetDestinationIDs().String() + act.RatingSubject = bf.GetRatingSubject() + act.SharedGroups = bf.GetSharedGroups().String() + act.BalanceWeight = strconv.FormatFloat(bf.GetWeight(), 'f', -1, 64) + act.TimingTags = bf.GetTimingIDs().String() + act.BalanceId = bf.GetID() + act.Categories = bf.GetCategories().String() + act.BalanceBlocker = strconv.FormatBool(bf.GetBlocker()) + act.BalanceDisabled = strconv.FormatBool(bf.GetDisabled()) } acts = append(acts, act) } @@ -663,74 +678,6 @@ func (self *ApierV1) GetActionPlan(attr AttrGetActionPlan, reply *[]*engine.Acti return nil } -type AttrResetTriggeredAction struct { - Id string - Tenant string - Account string - Directions string - BalanceType string - ThresholdType string - ThresholdValue float64 - DestinationId string - BalanceWeight float64 - BalanceRatingSubject string - BalanceSharedGroup string -} - -func (self *ApierV1) ResetTriggeredActions(attr AttrResetTriggeredAction, reply *string) error { - var a *engine.Action - if attr.Id != "" { - // we can identify the trigger by the id - a = &engine.Action{Id: attr.Id} - } else { - extraParameters, err := json.Marshal(struct { - ThresholdType string - ThresholdValue float64 - DestinationId string - BalanceWeight float64 - BalanceRatingSubject string - BalanceDirections string - BalanceSharedGroup string - }{ - attr.ThresholdType, - attr.ThresholdValue, - attr.DestinationId, - attr.BalanceWeight, - attr.Directions, - attr.BalanceRatingSubject, - attr.BalanceSharedGroup, - }) - if err != nil { - *reply = err.Error() - return err - } - a = &engine.Action{ - BalanceType: attr.BalanceType, - ExtraParameters: string(extraParameters), - } - } - accID := utils.AccountKey(attr.Tenant, attr.Account) - _, err := engine.Guardian.Guard(func() (interface{}, error) { - acc, err := self.AccountDb.GetAccount(accID) - if err != nil { - return 0, err - } - - acc.ResetActionTriggers(a) - - if err = self.AccountDb.SetAccount(acc); err != nil { - return 0, err - } - return 0, nil - }, 0, accID) - if err != nil { - *reply = err.Error() - return err - } - *reply = OK - return nil -} - // Process dependencies and load a specific AccountActions profile from storDb into dataDb. func (self *ApierV1) LoadAccountActions(attrs utils.TPAccountActions, reply *string) error { if len(attrs.TPid) == 0 { diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index efbd485de..dd7a445d9 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -488,8 +488,8 @@ func TestApierTPActions(t *testing.T) { } reply := "" act := &utils.TPActions{TPid: utils.TEST_SQL, ActionsId: "PREPAID_10", Actions: []*utils.TPAction{ - &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Directions: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationIds: "*any", BalanceWeight: 10, Weight: 10}, + &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Directions: "*out", Units: "10", ExpiryTime: "*unlimited", + DestinationIds: "*any", BalanceWeight: "10", Weight: 10}, }} actWarn := &utils.TPActions{TPid: utils.TEST_SQL, ActionsId: "WARN_VIA_HTTP", Actions: []*utils.TPAction{ &utils.TPAction{Identifier: "*call_url", ExtraParameters: "http://localhost:8000", Weight: 10}, @@ -955,7 +955,7 @@ func TestApierSetActions(t *testing.T) { if !*testLocal { return } - act1 := &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: 75.0, ExpiryTime: engine.UNLIMITED, Weight: 20.0} + act1 := &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75.0", ExpiryTime: engine.UNLIMITED, Weight: 20.0} attrs1 := &utils.AttrSetActions{ActionsId: "ACTS_1", Actions: []*utils.TPAction{act1}} reply1 := "" if err := rater.Call("ApierV1.SetActions", attrs1, &reply1); err != nil { @@ -974,7 +974,7 @@ func TestApierGetActions(t *testing.T) { return } expectActs := []*utils.TPAction{ - &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: 75.0, ExpiryTime: engine.UNLIMITED, Weight: 20.0}} + &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75.0", ExpiryTime: engine.UNLIMITED, Weight: 20.0}} var reply []*utils.TPAction if err := rater.Call("ApierV1.GetActions", "ACTS_1", &reply); err != nil { diff --git a/apier/v1/triggers.go b/apier/v1/triggers.go index d2470db4f..ab71455f3 100644 --- a/apier/v1/triggers.go +++ b/apier/v1/triggers.go @@ -238,44 +238,44 @@ func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers, at.ActivationDate = actTime } if attr.BalanceId != nil { - at.BalanceId = *attr.BalanceId + at.Balance.ID = attr.BalanceId } if attr.BalanceType != nil { - at.BalanceType = *attr.BalanceType + at.Balance.Type = attr.BalanceType } if attr.BalanceDirections != nil { - at.BalanceDirections = utils.NewStringMap(*attr.BalanceDirections...) + at.Balance.Directions = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDirections...)) } if attr.BalanceDestinationIds != nil { - at.BalanceDestinationIds = utils.NewStringMap(*attr.BalanceDestinationIds...) + at.Balance.DestinationIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDestinationIds...)) } if attr.BalanceWeight != nil { - at.BalanceWeight = *attr.BalanceWeight + at.Balance.Weight = attr.BalanceWeight } if attr.BalanceExpirationDate != nil { balanceExpTime, err := utils.ParseDate(*attr.BalanceExpirationDate) if err != nil { return 0, err } - at.BalanceExpirationDate = balanceExpTime + at.Balance.ExpirationDate = &balanceExpTime } if attr.BalanceTimingTags != nil { - at.BalanceTimingTags = utils.NewStringMap(*attr.BalanceTimingTags...) + at.Balance.TimingIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceTimingTags...)) } if attr.BalanceRatingSubject != nil { - at.BalanceRatingSubject = *attr.BalanceRatingSubject + at.Balance.RatingSubject = attr.BalanceRatingSubject } if attr.BalanceCategories != nil { - at.BalanceCategories = utils.NewStringMap(*attr.BalanceCategories...) + at.Balance.Categories = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceCategories...)) } if attr.BalanceSharedGroups != nil { - at.BalanceSharedGroups = utils.NewStringMap(*attr.BalanceSharedGroups...) + at.Balance.SharedGroups = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceSharedGroups...)) } if attr.BalanceBlocker != nil { - at.BalanceBlocker = *attr.BalanceBlocker + at.Balance.Blocker = attr.BalanceBlocker } if attr.BalanceDisabled != nil { - at.BalanceDisabled = *attr.BalanceDisabled + at.Balance.Disabled = attr.BalanceDisabled } if attr.MinQueuedItems != nil { at.MinQueuedItems = *attr.MinQueuedItems diff --git a/engine/account.go b/engine/account.go index b1cbb463b..4888b536d 100644 --- a/engine/account.go +++ b/engine/account.go @@ -723,6 +723,9 @@ func (acc *Account) InitCounters() { } } } + if len(acc.UnitCounters) == 0 { + acc.UnitCounters = nil // leave it nil if empty + } } func (acc *Account) CleanExpiredStuff() { diff --git a/engine/action.go b/engine/action.go index 7dde51af3..edd7cfda6 100644 --- a/engine/action.go +++ b/engine/action.go @@ -57,7 +57,7 @@ const ( DENY_NEGATIVE = "*deny_negative" RESET_ACCOUNT = "*reset_account" REMOVE_ACCOUNT = "*remove_account" - SET_BALANCE = "*set_balance" // not ready for production until switching to pointers + SET_BALANCE = "*set_balance" REMOVE_BALANCE = "*remove_balance" TOPUP_RESET = "*topup_reset" TOPUP = "*topup" diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index 524e0fb1e..50ec258cf 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -86,7 +86,7 @@ func TestAcntActsDisableAcnt(t *testing.T) { if acnt, err := acntDbAcntActs.GetAccount(acnt1Tag); err != nil { t.Error(err) } else if !reflect.DeepEqual(expectAcnt, acnt) { - t.Errorf("Expecting: %+v, received: %+v", expectAcnt, acnt) + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(expectAcnt), utils.ToJSON(acnt)) } } From 059c82fd471802a7c2876ff53f3a590b3e1bd2a1 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 17 Feb 2016 14:19:38 +0200 Subject: [PATCH 07/15] added last day of month function --- utils/coreutils.go | 15 +++++++++++++++ utils/utils_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/utils/coreutils.go b/utils/coreutils.go index 4f857b07d..b89804af0 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -518,3 +518,18 @@ func CastIfToString(iface interface{}) (strVal string, casts bool) { } return strVal, casts } + +func GetEndOfMonth(ref time.Time) time.Time { + if ref.IsZero() { + return time.Now() + } + year, month, _ := ref.Date() + if month == time.December { + year++ + month = time.January + } else { + month++ + } + eom := time.Date(year, month, 1, 0, 0, 0, 0, ref.Location()) + return eom.Add(-time.Second) +} diff --git a/utils/utils_test.go b/utils/utils_test.go index 6c66c8a0d..adca2dfad 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -600,3 +600,31 @@ func TestCastIfToString(t *testing.T) { t.Errorf("Received: %+v", sOut) } } + +func TestEndOfMonth(t *testing.T) { + eom := GetEndOfMonth(time.Date(2016, time.February, 5, 10, 1, 2, 3, time.UTC)) + expected := time.Date(2016, time.February, 29, 23, 59, 59, 0, time.UTC) + if !eom.Equal(expected) { + t.Errorf("Expected %v was %v", expected, eom) + } + eom = GetEndOfMonth(time.Date(2015, time.February, 5, 10, 1, 2, 3, time.UTC)) + expected = time.Date(2015, time.February, 28, 23, 59, 59, 0, time.UTC) + if !eom.Equal(expected) { + t.Errorf("Expected %v was %v", expected, eom) + } + eom = GetEndOfMonth(time.Date(2016, time.January, 31, 10, 1, 2, 3, time.UTC)) + expected = time.Date(2016, time.January, 31, 23, 59, 59, 0, time.UTC) + if !eom.Equal(expected) { + t.Errorf("Expected %v was %v", expected, eom) + } + eom = GetEndOfMonth(time.Date(2016, time.December, 31, 10, 1, 2, 3, time.UTC)) + expected = time.Date(2016, time.December, 31, 23, 59, 59, 0, time.UTC) + if !eom.Equal(expected) { + t.Errorf("Expected %v was %v", expected, eom) + } + eom = GetEndOfMonth(time.Date(2016, time.July, 31, 23, 59, 59, 0, time.UTC)) + expected = time.Date(2016, time.July, 31, 23, 59, 59, 0, time.UTC) + if !eom.Equal(expected) { + t.Errorf("Expected %v was %v", expected, eom) + } +} From 1707faf1e04e4b5988be58dc32512aca78fc3585 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 17 Feb 2016 14:21:19 +0200 Subject: [PATCH 08/15] added *end_month to ParseDate function --- utils/coreutils.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/coreutils.go b/utils/coreutils.go index b89804af0..3719f776f 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -193,6 +193,8 @@ func ParseDate(date string) (expDate time.Time, err error) { expDate = time.Now().AddDate(0, 1, 0) // add one month case date == "*yearly": expDate = time.Now().AddDate(1, 0, 0) // add one year + case date == "*end_month": + expDate = GetEndOfMonth(time.Now()) case strings.HasSuffix(date, "Z"): expDate, err = time.Parse(time.RFC3339, date) default: From 9fe980d42cc2065cd83fb3cdbe6351a2d257cfac Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 17 Feb 2016 17:16:07 +0200 Subject: [PATCH 09/15] renmaed *end_month to *month_end --- utils/coreutils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/coreutils.go b/utils/coreutils.go index 3719f776f..4268700cc 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -193,7 +193,7 @@ func ParseDate(date string) (expDate time.Time, err error) { expDate = time.Now().AddDate(0, 1, 0) // add one month case date == "*yearly": expDate = time.Now().AddDate(1, 0, 0) // add one year - case date == "*end_month": + case date == "*month_end": expDate = GetEndOfMonth(time.Now()) case strings.HasSuffix(date, "Z"): expDate, err = time.Parse(time.RFC3339, date) From f04d8082ba7f34c35b37e8d6e8eab42f631e0cd8 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 18 Feb 2016 18:33:38 +0200 Subject: [PATCH 10/15] updated migrator --- cmd/cgr-loader/migrator_rc8.go | 255 +++++++++++++++++++++++---------- 1 file changed, 180 insertions(+), 75 deletions(-) diff --git a/cmd/cgr-loader/migrator_rc8.go b/cmd/cgr-loader/migrator_rc8.go index 25aebd1e0..fbc660684 100644 --- a/cmd/cgr-loader/migrator_rc8.go +++ b/cmd/cgr-loader/migrator_rc8.go @@ -227,51 +227,107 @@ func (mig MigratorRC8) migrateAccounts() error { // unit counters for _, oldUc := range oldAcc.UnitCounters { newUc := &engine.UnitCounter{ - BalanceType: oldUc.BalanceType, - Balances: make(engine.BalanceChain, len(oldUc.Balances)), + Counters: make(engine.CounterFilters, len(oldUc.Balances)), } for index, oldUcBal := range oldUc.Balances { - newUc.Balances[index] = &engine.Balance{ - Uuid: oldUcBal.Uuid, - Id: oldUcBal.Id, - Value: oldUcBal.Value, - Directions: utils.ParseStringMap(oldUc.Direction), - ExpirationDate: oldUcBal.ExpirationDate, - Weight: oldUcBal.Weight, - DestinationIds: utils.ParseStringMap(oldUcBal.DestinationIds), - RatingSubject: oldUcBal.RatingSubject, - Categories: utils.ParseStringMap(oldUcBal.Category), - SharedGroups: utils.ParseStringMap(oldUcBal.SharedGroup), - Timings: oldUcBal.Timings, - TimingIDs: utils.ParseStringMap(oldUcBal.TimingIDs), - Disabled: oldUcBal.Disabled, + bf := &engine.BalanceFilter{} + if oldUcBal.Uuid != "" { + bf.Uuid = utils.StringPointer(oldUcBal.Uuid) } + if oldUcBal.Id != "" { + bf.ID = utils.StringPointer(oldUcBal.Id) + } + if oldUc.BalanceType != "" { + bf.Type = utils.StringPointer(oldUc.BalanceType) + } + // the value was used for counter value + /*if oldUcBal.Value != 0 { + bf.Value = utils.Float64Pointer(oldUcBal.Value) + }*/ + if oldUc.Direction != "" { + bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldUc.Direction)) + } + if !oldUcBal.ExpirationDate.IsZero() { + bf.ExpirationDate = utils.TimePointer(oldUcBal.ExpirationDate) + } + if oldUcBal.Weight != 0 { + bf.Weight = utils.Float64Pointer(oldUcBal.Weight) + } + if oldUcBal.DestinationIds != "" { + bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.DestinationIds)) + } + if oldUcBal.RatingSubject != "" { + bf.RatingSubject = utils.StringPointer(oldUcBal.RatingSubject) + } + if oldUcBal.Category != "" { + bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.Category)) + } + if oldUcBal.SharedGroup != "" { + bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.SharedGroup)) + } + if oldUcBal.TimingIDs != "" { + bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.TimingIDs)) + } + if oldUcBal.Disabled != false { + bf.Disabled = utils.BoolPointer(oldUcBal.Disabled) + } + bf.Timings = oldUcBal.Timings + cf := &engine.CounterFilter{ + Value: oldUcBal.Value, + Filter: bf, + } + newUc.Counters[index] = cf } } // action triggers for index, oldAtr := range oldAcc.ActionTriggers { - newAcc.ActionTriggers[index] = &engine.ActionTrigger{ - UniqueID: oldAtr.Id, - ThresholdType: oldAtr.ThresholdType, - ThresholdValue: oldAtr.ThresholdValue, - Recurrent: oldAtr.Recurrent, - MinSleep: oldAtr.MinSleep, - BalanceId: oldAtr.BalanceId, - BalanceType: oldAtr.BalanceType, - BalanceDirections: utils.ParseStringMap(oldAtr.BalanceDirection), - BalanceDestinationIds: utils.ParseStringMap(oldAtr.BalanceDestinationIds), - BalanceWeight: oldAtr.BalanceWeight, - BalanceExpirationDate: oldAtr.BalanceExpirationDate, - BalanceTimingTags: utils.ParseStringMap(oldAtr.BalanceTimingTags), - BalanceRatingSubject: oldAtr.BalanceRatingSubject, - BalanceCategories: utils.ParseStringMap(oldAtr.BalanceCategory), - BalanceSharedGroups: utils.ParseStringMap(oldAtr.BalanceSharedGroup), - BalanceDisabled: oldAtr.BalanceDisabled, - Weight: oldAtr.Weight, - ActionsId: oldAtr.ActionsId, - MinQueuedItems: oldAtr.MinQueuedItems, - Executed: oldAtr.Executed, + at := &engine.ActionTrigger{ + UniqueID: oldAtr.Id, + ThresholdType: oldAtr.ThresholdType, + ThresholdValue: oldAtr.ThresholdValue, + Recurrent: oldAtr.Recurrent, + MinSleep: oldAtr.MinSleep, + Weight: oldAtr.Weight, + ActionsId: oldAtr.ActionsId, + MinQueuedItems: oldAtr.MinQueuedItems, + Executed: oldAtr.Executed, } + bf := &engine.BalanceFilter{} + if oldAtr.BalanceId != "" { + bf.ID = utils.StringPointer(oldAtr.BalanceId) + } + if oldAtr.BalanceType != "" { + bf.Type = utils.StringPointer(oldAtr.BalanceType) + } + if oldAtr.BalanceRatingSubject != "" { + bf.RatingSubject = utils.StringPointer(oldAtr.BalanceRatingSubject) + } + if oldAtr.BalanceDirection != "" { + bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDirection)) + } + if oldAtr.BalanceDestinationIds != "" { + bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDestinationIds)) + } + if oldAtr.BalanceTimingTags != "" { + bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceTimingTags)) + } + if oldAtr.BalanceCategory != "" { + bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceCategory)) + } + if oldAtr.BalanceSharedGroup != "" { + bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceSharedGroup)) + } + if oldAtr.BalanceWeight != 0 { + bf.Weight = utils.Float64Pointer(oldAtr.BalanceWeight) + } + if oldAtr.BalanceDisabled != false { + bf.Disabled = utils.BoolPointer(oldAtr.BalanceDisabled) + } + if !oldAtr.BalanceExpirationDate.IsZero() { + bf.ExpirationDate = utils.TimePointer(oldAtr.BalanceExpirationDate) + } + at.Balance = bf + newAcc.ActionTriggers[index] = at if newAcc.ActionTriggers[index].ThresholdType == "*min_counter" || newAcc.ActionTriggers[index].ThresholdType == "*max_counter" { newAcc.ActionTriggers[index].ThresholdType = strings.Replace(newAcc.ActionTriggers[index].ThresholdType, "_", "_event_", 1) @@ -322,28 +378,53 @@ func (mig MigratorRC8) migrateActionTriggers() error { } newAtrs := make(engine.ActionTriggers, len(oldAtrs)) for index, oldAtr := range oldAtrs { - newAtrs[index] = &engine.ActionTrigger{ - UniqueID: oldAtr.Id, - ThresholdType: oldAtr.ThresholdType, - ThresholdValue: oldAtr.ThresholdValue, - Recurrent: oldAtr.Recurrent, - MinSleep: oldAtr.MinSleep, - BalanceId: oldAtr.BalanceId, - BalanceType: oldAtr.BalanceType, - BalanceDirections: utils.ParseStringMap(oldAtr.BalanceDirection), - BalanceDestinationIds: utils.ParseStringMap(oldAtr.BalanceDestinationIds), - BalanceWeight: oldAtr.BalanceWeight, - BalanceExpirationDate: oldAtr.BalanceExpirationDate, - BalanceTimingTags: utils.ParseStringMap(oldAtr.BalanceTimingTags), - BalanceRatingSubject: oldAtr.BalanceRatingSubject, - BalanceCategories: utils.ParseStringMap(oldAtr.BalanceCategory), - BalanceSharedGroups: utils.ParseStringMap(oldAtr.BalanceSharedGroup), - BalanceDisabled: oldAtr.BalanceDisabled, - Weight: oldAtr.Weight, - ActionsId: oldAtr.ActionsId, - MinQueuedItems: oldAtr.MinQueuedItems, - Executed: oldAtr.Executed, + at := &engine.ActionTrigger{ + UniqueID: oldAtr.Id, + ThresholdType: oldAtr.ThresholdType, + ThresholdValue: oldAtr.ThresholdValue, + Recurrent: oldAtr.Recurrent, + MinSleep: oldAtr.MinSleep, + Weight: oldAtr.Weight, + ActionsId: oldAtr.ActionsId, + MinQueuedItems: oldAtr.MinQueuedItems, + Executed: oldAtr.Executed, } + bf := &engine.BalanceFilter{} + if oldAtr.BalanceId != "" { + bf.ID = utils.StringPointer(oldAtr.BalanceId) + } + if oldAtr.BalanceType != "" { + bf.Type = utils.StringPointer(oldAtr.BalanceType) + } + if oldAtr.BalanceRatingSubject != "" { + bf.RatingSubject = utils.StringPointer(oldAtr.BalanceRatingSubject) + } + if oldAtr.BalanceDirection != "" { + bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDirection)) + } + if oldAtr.BalanceDestinationIds != "" { + bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDestinationIds)) + } + if oldAtr.BalanceTimingTags != "" { + bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceTimingTags)) + } + if oldAtr.BalanceCategory != "" { + bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceCategory)) + } + if oldAtr.BalanceSharedGroup != "" { + bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceSharedGroup)) + } + if oldAtr.BalanceWeight != 0 { + bf.Weight = utils.Float64Pointer(oldAtr.BalanceWeight) + } + if oldAtr.BalanceDisabled != false { + bf.Disabled = utils.BoolPointer(oldAtr.BalanceDisabled) + } + if !oldAtr.BalanceExpirationDate.IsZero() { + bf.ExpirationDate = utils.TimePointer(oldAtr.BalanceExpirationDate) + } + at.Balance = bf + newAtrs[index] = at if newAtrs[index].ThresholdType == "*min_counter" || newAtrs[index].ThresholdType == "*max_counter" { newAtrs[index].ThresholdType = strings.Replace(newAtrs[index].ThresholdType, "_", "_event_", 1) @@ -381,29 +462,53 @@ func (mig MigratorRC8) migrateActions() error { } newAcs := make(engine.Actions, len(oldAcs)) for index, oldAc := range oldAcs { - newAcs[index] = &engine.Action{ + a := &engine.Action{ Id: oldAc.Id, ActionType: oldAc.ActionType, - BalanceType: oldAc.BalanceType, ExtraParameters: oldAc.ExtraParameters, ExpirationString: oldAc.ExpirationString, Weight: oldAc.Weight, - Balance: &engine.Balance{ - Uuid: oldAc.Balance.Uuid, - Id: oldAc.Balance.Id, - Value: oldAc.Balance.Value, - Directions: utils.ParseStringMap(oldAc.Direction), - ExpirationDate: oldAc.Balance.ExpirationDate, - Weight: oldAc.Balance.Weight, - DestinationIds: utils.ParseStringMap(oldAc.Balance.DestinationIds), - RatingSubject: oldAc.Balance.RatingSubject, - Categories: utils.ParseStringMap(oldAc.Balance.Category), - SharedGroups: utils.ParseStringMap(oldAc.Balance.SharedGroup), - Timings: oldAc.Balance.Timings, - TimingIDs: utils.ParseStringMap(oldAc.Balance.TimingIDs), - Disabled: oldAc.Balance.Disabled, - }, + Balance: &engine.BalanceFilter{}, } + bf := a.Balance + if oldAc.Balance.Uuid != "" { + bf.Uuid = utils.StringPointer(oldAc.Balance.Uuid) + } + if oldAc.Balance.Id != "" { + bf.ID = utils.StringPointer(oldAc.Balance.Id) + } + if oldAc.BalanceType != "" { + bf.Type = utils.StringPointer(oldAc.BalanceType) + } + if oldAc.Balance.Value != 0 { + bf.Value = utils.Float64Pointer(oldAc.Balance.Value) + } + if oldAc.Balance.RatingSubject != "" { + bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject) + } + if oldAc.Balance.DestinationIds != "" { + bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.DestinationIds)) + } + if oldAc.Balance.TimingIDs != "" { + bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.TimingIDs)) + } + if oldAc.Balance.Category != "" { + bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.Category)) + } + if oldAc.Balance.SharedGroup != "" { + bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.SharedGroup)) + } + if oldAc.Balance.Weight != 0 { + bf.Weight = utils.Float64Pointer(oldAc.Balance.Weight) + } + if oldAc.Balance.Disabled != false { + bf.Disabled = utils.BoolPointer(oldAc.Balance.Disabled) + } + if !oldAc.Balance.ExpirationDate.IsZero() { + bf.ExpirationDate = utils.TimePointer(oldAc.Balance.ExpirationDate) + } + bf.Timings = oldAc.Balance.Timings + newAcs[index] = a } newAcsMap[key] = newAcs } From 5a2495e088cec0dcb387edb55111898245848334 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 18 Feb 2016 18:44:39 +0200 Subject: [PATCH 11/15] preserve counters --- cmd/cgr-loader/migrator_rc8.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/cgr-loader/migrator_rc8.go b/cmd/cgr-loader/migrator_rc8.go index fbc660684..1c9386a53 100644 --- a/cmd/cgr-loader/migrator_rc8.go +++ b/cmd/cgr-loader/migrator_rc8.go @@ -278,6 +278,7 @@ func (mig MigratorRC8) migrateAccounts() error { } newUc.Counters[index] = cf } + newAcc.UnitCounters[oldUc.BalanceType] = append(newAcc.UnitCounters[oldUc.BalanceType], newUc) } // action triggers for index, oldAtr := range oldAcc.ActionTriggers { From f958419d5bedb39165b604e7c4e34e3756f7f889 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 18 Feb 2016 19:25:26 +0200 Subject: [PATCH 12/15] sql data types fixes --- apier/v1/apier.go | 20 +++++++++++-------- .../mysql/create_tariffplan_tables.sql | 14 ++++++------- .../postgres/create_tariffplan_tables.sql | 16 +++++++-------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 2497ac17a..9afe5cf63 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -503,17 +503,21 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error storeActions := make(engine.Actions, len(attrs.Actions)) for idx, apiAct := range attrs.Actions { var units *float64 - if x, err := strconv.ParseFloat(apiAct.Units, 64); err == nil { - units = &x - } else { - return err + if apiAct.Units != "" { + if x, err := strconv.ParseFloat(apiAct.Units, 64); err == nil { + units = &x + } else { + return err + } } var weight *float64 - if x, err := strconv.ParseFloat(apiAct.BalanceWeight, 64); err == nil { - weight = &x - } else { - return err + if apiAct.BalanceWeight != "" { + if x, err := strconv.ParseFloat(apiAct.BalanceWeight, 64); err == nil { + weight = &x + } else { + return err + } } a := &engine.Action{ diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 0a640135a..b6240cdc5 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -152,16 +152,16 @@ CREATE TABLE `tp_actions` ( `balance_tag` varchar(64) NOT NULL, `balance_type` varchar(24) NOT NULL, `directions` varchar(8) NOT NULL, - `units` DECIMAL(20,4) NOT NULL, + `units` varchar(24) NOT NULL, `expiry_time` varchar(24) NOT NULL, `timing_tags` varchar(128) NOT NULL, `destination_tags` varchar(64) NOT NULL, `rating_subject` varchar(64) NOT NULL, `categories` varchar(32) NOT NULL, `shared_groups` varchar(64) NOT NULL, - `balance_weight` DECIMAL(8,2) NOT NULL, - `balance_blocker` BOOLEAN NOT NULL, - `balance_disabled` BOOLEAN NOT NULL, + `balance_weight` varchar(10) NOT NULL, + `balance_blocker` varchar(5) NOT NULL, + `balance_disabled` varchar(24) NOT NULL, `extra_parameters` varchar(256) NOT NULL, `filter` varchar(256) NOT NULL, `weight` DECIMAL(8,2) NOT NULL, @@ -214,9 +214,9 @@ CREATE TABLE `tp_action_triggers` ( `balance_shared_groups` varchar(64) NOT NULL, `balance_expiry_time` varchar(24) NOT NULL, `balance_timing_tags` varchar(128) NOT NULL, - `balance_weight` DECIMAL(8,2) NOT NULL, - `balance_blocker` BOOL NOT NULL, - `balance_disabled` BOOL NOT NULL, + `balance_weight` varchar(10) NOT NULL, + `balance_blocker` varchar(5) NOT NULL, + `balance_disabled` varchar(5) NOT NULL, `min_queued_items` int(11) NOT NULL, `actions_tag` varchar(64) NOT NULL, `weight` DECIMAL(8,2) NOT NULL, diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index e4d3aaee8..b5d8193c8 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -109,7 +109,7 @@ CREATE TABLE tp_rating_profiles ( activation_time VARCHAR(24) NOT NULL, rating_plan_tag VARCHAR(64) NOT NULL, fallback_subjects VARCHAR(64), - cdr_stat_queue_ids varchar(64), + cdr_stat_queue_ids VARCHAR(64), created_at TIMESTAMP, UNIQUE (tpid, loadid, tenant, category, direction, subject, activation_time) ); @@ -147,16 +147,16 @@ CREATE TABLE tp_actions ( balance_tag VARCHAR(64) NOT NULL, balance_type VARCHAR(24) NOT NULL, directions VARCHAR(8) NOT NULL, - units NUMERIC(20,4) NOT NULL, + units VARCHAR(10) NOT NULL, expiry_time VARCHAR(24) NOT NULL, timing_tags VARCHAR(128) NOT NULL, destination_tags VARCHAR(64) NOT NULL, rating_subject VARCHAR(64) NOT NULL, categories VARCHAR(32) NOT NULL, shared_groups VARCHAR(64) NOT NULL, - balance_weight NUMERIC(8,2) NOT NULL, - balance_blocker BOOLEAN NOT NULL, - balance_disabled BOOLEAN NOT NULL, + balance_weight VARCHAR(10) NOT NULL, + balance_blocker VARCHAR(5) NOT NULL, + balance_disabled VARCHAR(5) NOT NULL, extra_parameters VARCHAR(256) NOT NULL, filter VARCHAR(256) NOT NULL, weight NUMERIC(8,2) NOT NULL, @@ -209,9 +209,9 @@ CREATE TABLE tp_action_triggers ( balance_shared_groups VARCHAR(64) NOT NULL, balance_expiry_time VARCHAR(24) NOT NULL, balance_timing_tags VARCHAR(128) NOT NULL, - balance_weight NUMERIC(8,2) NOT NULL, - balance_blocker BOOL NOT NULL, - balance_disabled BOOL NOT NULL, + balance_weight VARCHAR(10) NOT NULL, + balance_blocker VARCHAR(5) NOT NULL, + balance_disabled VARCHAR(5) NOT NULL, min_queued_items INTEGER NOT NULL, actions_tag VARCHAR(64) NOT NULL, weight NUMERIC(8,2) NOT NULL, From 1511fbe808bf56d78c9eade4f6b84add9f81dd4e Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 18 Feb 2016 19:34:35 +0200 Subject: [PATCH 13/15] small fixes --- apier/v1/apier_local_test.go | 2 +- engine/actions_local_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index dd7a445d9..04d847cb9 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -980,7 +980,7 @@ func TestApierGetActions(t *testing.T) { if err := rater.Call("ApierV1.GetActions", "ACTS_1", &reply); err != nil { t.Error("Got error on ApierV1.GetActions: ", err.Error()) } else if !reflect.DeepEqual(expectActs, reply) { - t.Errorf("Expected: %v, received: %v", expectActs, reply) + t.Errorf("Expected: %v, received: %v", utils.ToJSON(expectActs), utils.ToJSON(reply)) } } diff --git a/engine/actions_local_test.go b/engine/actions_local_test.go index bdc3b8b79..b4aa17869 100644 --- a/engine/actions_local_test.go +++ b/engine/actions_local_test.go @@ -95,7 +95,7 @@ func TestActionsLocalSetCdrlogDebit(t *testing.T) { t.Errorf("Calling ApierV1.SetAccount received: %s", reply) } attrsAA := &utils.AttrSetActions{ActionsId: "ACTS_1", Actions: []*utils.TPAction{ - &utils.TPAction{Identifier: DEBIT, BalanceType: utils.MONETARY, Units: "5.0", ExpiryTime: UNLIMITED, Weight: 20.0}, + &utils.TPAction{Identifier: DEBIT, BalanceType: utils.MONETARY, Units: "5", ExpiryTime: UNLIMITED, Weight: 20.0}, &utils.TPAction{Identifier: CDRLOG}, }} if err := actsLclRpc.Call("ApierV1.SetActions", attrsAA, &reply); err != nil && err.Error() != utils.ErrExists.Error() { @@ -140,7 +140,7 @@ func TestActionsLocalSetCdrlogTopup(t *testing.T) { t.Errorf("Calling ApierV1.SetAccount received: %s", reply) } attrsAA := &utils.AttrSetActions{ActionsId: "ACTS_2", Actions: []*utils.TPAction{ - &utils.TPAction{Identifier: TOPUP, BalanceType: utils.MONETARY, Units: "5.0", ExpiryTime: UNLIMITED, Weight: 20.0}, + &utils.TPAction{Identifier: TOPUP, BalanceType: utils.MONETARY, Units: "5", ExpiryTime: UNLIMITED, Weight: 20.0}, &utils.TPAction{Identifier: CDRLOG}, }} if err := actsLclRpc.Call("ApierV1.SetActions", attrsAA, &reply); err != nil && err.Error() != utils.ErrExists.Error() { From d6d504507342ff0715b9da9f7988b430e9dd9069 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 18 Feb 2016 21:11:43 +0200 Subject: [PATCH 14/15] test fixes --- apier/v1/apier_local_test.go | 4 ++-- engine/actions_local_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 04d847cb9..c9f58cf05 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -955,7 +955,7 @@ func TestApierSetActions(t *testing.T) { if !*testLocal { return } - act1 := &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75.0", ExpiryTime: engine.UNLIMITED, Weight: 20.0} + act1 := &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75", ExpiryTime: engine.UNLIMITED, Weight: 20.0} attrs1 := &utils.AttrSetActions{ActionsId: "ACTS_1", Actions: []*utils.TPAction{act1}} reply1 := "" if err := rater.Call("ApierV1.SetActions", attrs1, &reply1); err != nil { @@ -974,7 +974,7 @@ func TestApierGetActions(t *testing.T) { return } expectActs := []*utils.TPAction{ - &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75.0", ExpiryTime: engine.UNLIMITED, Weight: 20.0}} + &utils.TPAction{Identifier: engine.TOPUP_RESET, BalanceType: utils.MONETARY, Directions: utils.OUT, Units: "75", BalanceWeight: "0", BalanceBlocker: "false", BalanceDisabled: "false", ExpiryTime: engine.UNLIMITED, Weight: 20.0}} var reply []*utils.TPAction if err := rater.Call("ApierV1.GetActions", "ACTS_1", &reply); err != nil { diff --git a/engine/actions_local_test.go b/engine/actions_local_test.go index b4aa17869..b074fc630 100644 --- a/engine/actions_local_test.go +++ b/engine/actions_local_test.go @@ -168,7 +168,7 @@ func TestActionsLocalSetCdrlogTopup(t *testing.T) { rcvedCdrs[0].Subject != "dan2905" || rcvedCdrs[0].Usage != "1" || rcvedCdrs[0].RunID != TOPUP || - strconv.FormatFloat(rcvedCdrs[0].Cost, 'f', -1, 64) != attrsAA.Actions[0].Units { + strconv.FormatFloat(-rcvedCdrs[0].Cost, 'f', -1, 64) != attrsAA.Actions[0].Units { t.Errorf("Received: %+v", rcvedCdrs[0]) } } From 2690802100b29a6bb3ad3888d4f60791ff8ac6fd Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Fri, 19 Feb 2016 12:58:14 +0200 Subject: [PATCH 15/15] triggers loading improvement --- engine/account.go | 2 +- engine/balance_filter.go | 61 +++++++++++++++++++++++++++++++++++++++ engine/loader_csv_test.go | 4 +-- utils/map.go | 14 ++++----- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/engine/account.go b/engine/account.go index 4888b536d..912e4de08 100644 --- a/engine/account.go +++ b/engine/account.go @@ -700,7 +700,7 @@ func (acc *Account) InitCounters() { uc.Counters = make(CounterFilters, 0) acc.UnitCounters[at.Balance.GetType()] = append(acc.UnitCounters[at.Balance.GetType()], uc) } - c := &CounterFilter{Filter: at.Balance} + c := &CounterFilter{Filter: at.Balance.Clone()} if (c.Filter.ID == nil || *c.Filter.ID == "") && at.UniqueID != "" { c.Filter.ID = utils.StringPointer(at.UniqueID) } diff --git a/engine/balance_filter.go b/engine/balance_filter.go index e9f95e68c..28d9c912f 100644 --- a/engine/balance_filter.go +++ b/engine/balance_filter.go @@ -47,6 +47,67 @@ func (bp *BalanceFilter) CreateBalance() *Balance { return b.Clone() } +func (bf *BalanceFilter) Clone() *BalanceFilter { + result := &BalanceFilter{} + if bf.Uuid != nil { + result.Uuid = new(string) + *result.Uuid = *bf.Uuid + } + if bf.ID != nil { + result.ID = new(string) + *result.ID = *bf.ID + } + if bf.Value != nil { + result.Value = new(float64) + *result.Value = *bf.Value + } + if bf.RatingSubject != nil { + result.RatingSubject = new(string) + *result.RatingSubject = *bf.RatingSubject + } + if bf.Type != nil { + result.Type = new(string) + *result.Type = *bf.Type + } + if bf.ExpirationDate != nil { + result.ExpirationDate = new(time.Time) + *result.ExpirationDate = *bf.ExpirationDate + } + if bf.Weight != nil { + result.Weight = new(float64) + *result.Weight = *bf.Weight + } + if bf.Disabled != nil { + result.Disabled = new(bool) + *result.Disabled = *bf.Disabled + } + if bf.Blocker != nil { + result.Blocker = new(bool) + *result.Blocker = *bf.Blocker + } + if bf.Factor != nil { + result.Factor = new(ValueFactor) + *result.Factor = *bf.Factor + } + if bf.Directions != nil { + result.Directions = utils.StringMapPointer(bf.Directions.Clone()) + } + if bf.DestinationIDs != nil { + result.DestinationIDs = utils.StringMapPointer(bf.DestinationIDs.Clone()) + } + if bf.Categories != nil { + result.Categories = utils.StringMapPointer(bf.Categories.Clone()) + } + if bf.SharedGroups != nil { + result.SharedGroups = utils.StringMapPointer(bf.SharedGroups.Clone()) + } + if bf.TimingIDs != nil { + result.TimingIDs = utils.StringMapPointer(bf.TimingIDs.Clone()) + } + + return result +} + func (bp *BalanceFilter) LoadFromBalance(b *Balance) *BalanceFilter { if b.Uuid != "" { bp.Uuid = &b.Uuid diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 69f090c8d..3f4fbf87c 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -1055,7 +1055,7 @@ func TestLoadActionTriggers(t *testing.T) { ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ThresholdValue: 10, Balance: &BalanceFilter{ - ID: utils.StringPointer("st0"), + ID: nil, Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")), @@ -1133,7 +1133,7 @@ func TestLoadAccountActions(t *testing.T) { expected.UnitCounters[utils.VOICE][0].Counters[i].Filter.ID = b.Filter.ID } 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)) + t.Errorf("Error loading account action: %+v %+v", utils.ToIJSON(aa.UnitCounters[utils.VOICE][0].Counters[0].Filter), utils.ToIJSON(expected.UnitCounters[utils.VOICE][0].Counters[0].Filter)) } // test that it does not overwrite balances existing, err := accountingStorage.GetAccount(aa.Id) diff --git a/utils/map.go b/utils/map.go index e45488935..07f2d280b 100644 --- a/utils/map.go +++ b/utils/map.go @@ -107,14 +107,6 @@ func (sm StringMap) Includes(om StringMap) bool { return true } -func (sm StringMap) Clone() StringMap { - result := make(StringMap, len(sm)) - for k := range sm { - result[k] = true - } - return result -} - func (sm StringMap) Slice() []string { result := make([]string, len(sm)) i := 0 @@ -142,6 +134,12 @@ func (sm StringMap) Copy(o StringMap) { } } +func (sm StringMap) Clone() StringMap { + result := make(StringMap, len(sm)) + result.Copy(sm) + return result +} + func (sm StringMap) String() string { return strings.Join(sm.Slice(), INFIELD_SEP) }