diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 93dbf7141..9209d1259 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -568,7 +568,7 @@ type V1TPAction struct { BalanceType string // Type of balance the action will operate on 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 + Filters []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 @@ -626,7 +626,7 @@ func (apierSv1 *APIerSv1) SetActions(attrs *V1AttrSetActions, reply *string) (er Weight: apiAct.Weight, ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, - Filter: apiAct.Filter, + Filters: apiAct.Filters, Balance: &engine.BalanceFilter{ // TODO: update this part Uuid: utils.StringPointer(apiAct.BalanceUuid), ID: utils.StringPointer(apiAct.BalanceId), @@ -677,7 +677,7 @@ func (apierSv1 *APIerSv1) GetActions(actsId *string, reply *[]*utils.TPAction) e Identifier: engAct.ActionType, ExpiryTime: engAct.ExpirationString, ExtraParameters: engAct.ExtraParameters, - Filter: engAct.Filter, + Filters: strings.Join(engAct.Filters, utils.InfieldSep), Weight: engAct.Weight, } bf := engAct.Balance diff --git a/apier/v1/tpactions_it_test.go b/apier/v1/tpactions_it_test.go index fb07bb577..7606a2c68 100644 --- a/apier/v1/tpactions_it_test.go +++ b/apier/v1/tpactions_it_test.go @@ -129,14 +129,14 @@ func testTPActionsSetTPAction(t *testing.T) { TPid: "TPAcc", ID: "ID", Actions: []*utils.TPAction{ - &utils.TPAction{ + { Identifier: "*topup_reset", BalanceId: "BalID", BalanceUuid: "BalUuid", BalanceType: "*data", Units: "10", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "DST_1002", RatingSubject: "SPECIAL_1002", @@ -148,14 +148,14 @@ func testTPActionsSetTPAction(t *testing.T) { BalanceDisabled: "false", Weight: 10, }, - &utils.TPAction{ + { Identifier: "*log", BalanceId: "BalID", BalanceUuid: "BalUuid", BalanceType: "*monetary", Units: "120", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "*any", RatingSubject: "SPECIAL_1002", @@ -211,7 +211,7 @@ func testTPActionsUpdateTPAction(t *testing.T) { BalanceType: "*data", Units: "10", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "DST_1002", RatingSubject: "SPECIAL_1002", @@ -230,7 +230,7 @@ func testTPActionsUpdateTPAction(t *testing.T) { BalanceType: "*monetary", Units: "120", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "*any", RatingSubject: "SPECIAL_1002", @@ -249,7 +249,7 @@ func testTPActionsUpdateTPAction(t *testing.T) { BalanceType: "*voice", Units: "102400", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "*any", RatingSubject: "SPECIAL_1002", diff --git a/apier/v2/apier.go b/apier/v2/apier.go index 1014b974f..aacbaa61d 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -330,7 +330,9 @@ func (apiv2 *APIerSv2) SetActions(attrs *utils.AttrSetActions, reply *string) er Weight: apiAct.Weight, ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, - Filter: apiAct.Filter, + } + if apiAct.Filters != utils.EmptyString { + a.Filters = strings.Split(apiAct.Filters, utils.InfieldSep) } if apiAct.Identifier != utils.MetaResetTriggers { // add an exception for ResetTriggers a.Balance = &engine.BalanceFilter{ // TODO: update this part diff --git a/data/storage/docker_mysql/scripts/create_tariffplan_tables.sql b/data/storage/docker_mysql/scripts/create_tariffplan_tables.sql index ab6505b52..faa327a9c 100644 --- a/data/storage/docker_mysql/scripts/create_tariffplan_tables.sql +++ b/data/storage/docker_mysql/scripts/create_tariffplan_tables.sql @@ -148,7 +148,7 @@ CREATE TABLE `tp_actions` ( `tag` varchar(64) NOT NULL, `action` varchar(24) NOT NULL, `extra_parameters` varchar(256) NOT NULL, - `filter` varchar(256) NOT NULL, + `filters` varchar(256) NOT NULL, `balance_tag` varchar(64) NOT NULL, `balance_type` varchar(24) NOT NULL, `categories` varchar(32) NOT NULL, diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 99ccd4ff6..53f449874 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -148,7 +148,7 @@ CREATE TABLE `tp_actions` ( `tag` varchar(64) NOT NULL, `action` varchar(24) NOT NULL, `extra_parameters` varchar(256) NOT NULL, - `filter` varchar(256) NOT NULL, + `filters` varchar(256) NOT NULL, `balance_tag` varchar(64) NOT NULL, `balance_type` varchar(24) NOT NULL, `categories` varchar(32) NOT NULL, diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 760219f44..cbc175e47 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -143,7 +143,7 @@ CREATE TABLE tp_actions ( tag VARCHAR(64) NOT NULL, action VARCHAR(24) NOT NULL, extra_parameters VARCHAR(256) NOT NULL, - filter VARCHAR(256) NOT NULL, + filters VARCHAR(256) NOT NULL, balance_tag VARCHAR(64) NOT NULL, balance_type VARCHAR(24) NOT NULL, categories VARCHAR(32) NOT NULL, diff --git a/engine/action.go b/engine/action.go index 6def2e51c..f599033f6 100644 --- a/engine/action.go +++ b/engine/action.go @@ -44,7 +44,7 @@ type Action struct { Id string ActionType string ExtraParameters string - Filter string + Filters []string ExpirationString string // must stay as string because it can have relative values like 1month Weight float64 Balance *BalanceFilter @@ -56,11 +56,15 @@ func (a *Action) Clone() (cln *Action) { if a == nil { return } + var fltrs []string + if a.Filters != nil { + fltrs = utils.CloneStringSlice(a.Filters) + } return &Action{ Id: a.Id, ActionType: a.ActionType, ExtraParameters: a.ExtraParameters, - Filter: a.Filter, + Filters: fltrs, ExpirationString: a.ExpirationString, Weight: a.Weight, Balance: a.Balance.Clone(), diff --git a/engine/action_plan.go b/engine/action_plan.go index f24f10c68..ddc2b4536 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -21,7 +21,6 @@ package engine import ( "fmt" "sort" - "strings" "time" "github.com/cgrates/cgrates/config" @@ -219,8 +218,8 @@ func (at *ActionTiming) Execute(fltrS *FilterS) (err error) { removeAccountActionFound := false for _, a := range aac { // check action filter - if len(a.Filter) > 0 { - if pass, err := fltrS.Pass(utils.NewTenantID(accID).Tenant, strings.Split(a.Filter, utils.InfieldSep), + if len(a.Filters) > 0 { + if pass, err := fltrS.Pass(utils.NewTenantID(accID).Tenant, a.Filters, utils.MapStorage{utils.MetaReq: config.NewObjectDP(acc)}); err != nil { return err } else if !pass { diff --git a/engine/action_plan_test.go b/engine/action_plan_test.go index b3db2f6f7..f2e18e4cf 100644 --- a/engine/action_plan_test.go +++ b/engine/action_plan_test.go @@ -128,8 +128,8 @@ func TestActionTimindSetActions(t *testing.T) { actionTiming := new(ActionTiming) actions := Actions{ - &Action{ActionType: "test", Filter: "test"}, - &Action{ActionType: "test1", Filter: "test1"}, + &Action{ActionType: "test"}, + &Action{ActionType: "test1"}, } actionTiming.SetActions(actions) if !reflect.DeepEqual(actions, actionTiming.actions) { diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 726f9109b..409777b7e 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -22,7 +22,6 @@ import ( "encoding/json" "fmt" "sort" - "strings" "time" "github.com/cgrates/cgrates/config" @@ -69,8 +68,8 @@ func (at *ActionTrigger) Execute(ub *Account, fltrS *FilterS) (err error) { removeAccountActionFound := false for _, a := range aac { // check action filter - if len(a.Filter) > 0 { - if pass, err := fltrS.Pass(utils.NewTenantID(a.Id).Tenant, strings.Split(a.Filter, utils.InfieldSep), + if len(a.Filters) > 0 { + if pass, err := fltrS.Pass(utils.NewTenantID(a.Id).Tenant, a.Filters, utils.MapStorage{utils.MetaReq: config.NewObjectDP(ub)}); err != nil { return err } else if !pass { diff --git a/engine/actions_test.go b/engine/actions_test.go index 6aeb499d8..1bf6c7fdb 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -1908,7 +1908,7 @@ func TestActionConditionalTopup(t *testing.T) { a := &Action{ ActionType: utils.MetaTopUp, - Filter: `*lt:~*req.BalanceMap.*monetary.GetTotalValue:30`, + Filters: []string{`*lt:~*req.BalanceMap.*monetary.GetTotalValue:30`}, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 11}, @@ -1974,7 +1974,7 @@ func TestActionConditionalTopupNoMatch(t *testing.T) { a := &Action{ ActionType: utils.MetaTopUp, - Filter: `*lt:~*req.BalanceMap.*monetary.GetTotalValue:3`, + Filters: []string{`*lt:~*req.BalanceMap.*monetary.GetTotalValue:3`}, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 11}, @@ -2038,7 +2038,7 @@ func TestActionConditionalTopupExistingBalance(t *testing.T) { a := &Action{ ActionType: utils.MetaTopUp, - Filter: `*gte:~*req.BalanceMap.*voice.GetTotalValue:100`, + Filters: []string{`*gte:~*req.BalanceMap.*voice.GetTotalValue:100`}, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 11}, @@ -2139,7 +2139,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { a1 := &Action{ ActionType: utils.MetaSetBalance, - Filter: "*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0", + Filters: []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}, Balance: &BalanceFilter{ Type: utils.StringPointer("*sms"), ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"), @@ -2149,7 +2149,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { } a2 := &Action{ ActionType: utils.MetaSetBalance, - Filter: "*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0", + Filters: []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}, Balance: &BalanceFilter{ Type: utils.StringPointer("*sms"), ID: utils.StringPointer("for_v3hsillmilld500m_mms_ill"), @@ -2161,7 +2161,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { } a3 := &Action{ ActionType: utils.MetaSetBalance, - Filter: "*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0", + Filters: []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}, Balance: &BalanceFilter{ Type: utils.StringPointer("*sms"), ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"), @@ -2173,7 +2173,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { } a4 := &Action{ ActionType: utils.MetaSetBalance, - Filter: "*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0", + Filters: []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}, Balance: &BalanceFilter{ Type: utils.StringPointer("*data"), Uuid: utils.StringPointer("fc927edb-1bd6-425e-a2a3-9fd8bafaa524"), @@ -2185,7 +2185,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) { } a5 := &Action{ ActionType: utils.MetaSetBalance, - Filter: "*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0", + Filters: []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}, Balance: &BalanceFilter{ Type: utils.StringPointer("*voice"), ID: utils.StringPointer("for_v3hsillmilld500m_voice_3_h"), @@ -2292,8 +2292,8 @@ func TestActionCSVFilter(t *testing.T) { if err != nil { t.Error("error getting actions: ", err) } - if len(act) != 1 || act[0].Filter != `{"*and":[{"Value":{"*lt":0}},{"Id":{"*eq":"*default"}}]}` { - t.Error("Error loading actions: ", act[0].Filter) + if len(act) != 1 || !reflect.DeepEqual(act[0].Filters, []string{"*string:~*req.BalanceMap.*monetary[0].ID:*default", "*lt:~*req.BalanceMap.*monetary[0].Value:0"}) { + t.Error("Error loading actions: ", act[0].Filters) } } diff --git a/engine/libtest.go b/engine/libtest.go index 65e9af5ba..13b504252 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -182,7 +182,7 @@ BLOCK,*topup,,,bblocker,*monetary,,NAT,,,*unlimited,,1,20,true,false,20 BLOCK,*topup,,,bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 BLOCK_EMPTY,*topup,,,bblocker,*monetary,,NAT,,,*unlimited,,0,20,true,false,20 BLOCK_EMPTY,*topup,,,bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 -FILTER,*topup,,"{""*and"":[{""Value"":{""*lt"":0}},{""Id"":{""*eq"":""*default""}}]}",bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 +FILTER,*topup,,*string:~*req.BalanceMap.*monetary[0].ID:*default;*lt:~*req.BalanceMap.*monetary[0].Value:0,bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 EXP,*topup,,,,*voice,,,,,*monthly,*any,300s,10,false,false,10 NOEXP,*topup,,,,*voice,,,,,*unlimited,*any,50s,10,false,false,10 VF,*debit,,,,*monetary,,,,,*unlimited,*any,"{""Method"":""*incremental"",""Params"":{""Units"":10, ""Interval"":""month"", ""Increment"":""day""}}",10,false,false,10 diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 7640237ed..be3be8f5a 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -696,7 +696,7 @@ func (tps ActionMdls) AsMapTPActions() (result map[string]*utils.TPActions) { BalanceType: tp.BalanceType, Units: tp.Units, ExpiryTime: tp.ExpiryTime, - Filter: tp.Filter, + Filters: tp.Filters, TimingTags: tp.TimingTags, DestinationIds: tp.DestinationTags, RatingSubject: tp.RatingSubject, @@ -750,7 +750,7 @@ func APItoModelAction(as *utils.TPActions) (result ActionMdls) { BalanceType: a.BalanceType, Units: a.Units, ExpiryTime: a.ExpiryTime, - Filter: a.Filter, + Filters: a.Filters, TimingTags: a.TimingTags, DestinationTags: a.DestinationIds, RatingSubject: a.RatingSubject, diff --git a/engine/models.go b/engine/models.go index 1dc93c6e6..807a90ee6 100644 --- a/engine/models.go +++ b/engine/models.go @@ -127,7 +127,7 @@ type ActionMdl struct { Tag string `index:"0" re:"\w+\s*"` Action string `index:"1" re:"\*\w+\s*"` ExtraParameters string `index:"2" re:"\S+\s*"` - Filter string `index:"3" re:"\S+\s*"` + Filters string `index:"3" re:"\S+\s*"` BalanceTag string `index:"4" re:"\w+\s*"` BalanceType string `index:"5" re:"\*\w+\s*"` Categories string `index:"6" re:""` diff --git a/engine/tpreader.go b/engine/tpreader.go index 1a030c396..fba78e646 100644 --- a/engine/tpreader.go +++ b/engine/tpreader.go @@ -438,10 +438,12 @@ func (tpr *TpReader) LoadActions() (err error) { acts := make([]*Action, len(tpacts)) for idx, tpact := range tpacts { // check filter field - if len(tpact.Filter) > 0 { - if err = verifyInlineFilterS(strings.Split(tpact.Filter, utils.InfieldSep)); err != nil { - return fmt.Errorf("error parsing action %s filter field: %v", tag, err) - } + var fltrs []string + if len(tpact.Filters) > 0 { + fltrs = strings.Split(tpact.Filters, utils.InfieldSep) + } + if err = verifyInlineFilterS(fltrs); err != nil { + return fmt.Errorf("error parsing action %s filter field: %v", tag, err) } acts[idx] = &Action{ Id: tag, @@ -449,7 +451,7 @@ func (tpr *TpReader) LoadActions() (err error) { Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, - Filter: tpact.Filter, + Filters: fltrs, Balance: &BalanceFilter{}, } if tpact.BalanceId != "" && tpact.BalanceId != utils.MetaAny { @@ -909,10 +911,12 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) acts := make([]*Action, len(tpacts)) for idx, tpact := range tpacts { // check filter field - if len(tpact.Filter) > 0 { - if err = verifyInlineFilterS(strings.Split(tpact.Filter, utils.InfieldSep)); err != nil { - return fmt.Errorf("error parsing action %s filter field: %v", tag, err) - } + var fltrs []string + if len(tpact.Filters) > 0 { + fltrs = strings.Split(tpact.Filters, utils.InfieldSep) + } + if err = verifyInlineFilterS(fltrs); err != nil { + return fmt.Errorf("error parsing action %s filter field: %v", tag, err) } acts[idx] = &Action{ Id: tag, @@ -921,7 +925,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, - Filter: tpact.Filter, + Filters: fltrs, Balance: &BalanceFilter{}, } if tpact.BalanceId != "" && tpact.BalanceId != utils.MetaAny { diff --git a/engine/tpreader_test.go b/engine/tpreader_test.go index cfb9fb72a..652d2c984 100644 --- a/engine/tpreader_test.go +++ b/engine/tpreader_test.go @@ -547,7 +547,6 @@ func TestGetLoadedIdsActions(t *testing.T) { Id: "ACTION_1001", ActionType: utils.MetaSetBalance, ExtraParameters: "", - Filter: "", ExpirationString: "", Weight: 10, balanceValue: 9.45, @@ -558,7 +557,6 @@ func TestGetLoadedIdsActions(t *testing.T) { Id: "ACTION_1002", ActionType: utils.MetaPublishAccount, ExtraParameters: "", - Filter: "", ExpirationString: "", Weight: 5, balanceValue: 12.32, diff --git a/engine/z_stordb_it_test.go b/engine/z_stordb_it_test.go index 7902a3e2e..8c6c6c3a8 100644 --- a/engine/z_stordb_it_test.go +++ b/engine/z_stordb_it_test.go @@ -1239,7 +1239,7 @@ func testStorDBitCRUDTpActions(t *testing.T) { BalanceType: "*monetary", Units: "10", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "", DestinationIds: "DST_ON_NET", RatingSubject: "", @@ -1264,7 +1264,7 @@ func testStorDBitCRUDTpActions(t *testing.T) { BalanceType: "*monetary", Units: "10", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "", DestinationIds: "DST_ON_NET", RatingSubject: "", diff --git a/migrator/tp_actions_it_test.go b/migrator/tp_actions_it_test.go index e3ca87963..036fda38c 100644 --- a/migrator/tp_actions_it_test.go +++ b/migrator/tp_actions_it_test.go @@ -117,7 +117,7 @@ func testTpActITPopulate(t *testing.T) { BalanceType: "*monetary", Units: "120", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "*any", RatingSubject: "SPECIAL_1002", @@ -136,7 +136,7 @@ func testTpActITPopulate(t *testing.T) { BalanceType: "*data", Units: "10", ExpiryTime: "*unlimited", - Filter: "", + Filters: "", TimingTags: "2014-01-14T00:00:00Z", DestinationIds: "DST_1002", RatingSubject: "SPECIAL_1002", diff --git a/utils/apitpdata.go b/utils/apitpdata.go index cf1af8531..ede4dc9dd 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -342,7 +342,7 @@ type TPAction struct { BalanceType string // Type of balance the action will operate on 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 + Filters 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