diff --git a/apier/v1/apier.go b/apier/v1/apier.go index c360a2066..5037a5afe 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -151,7 +151,7 @@ func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { Value: attr.Value, ExpirationDate: expTime, RatingSubject: attr.RatingSubject, - DestinationId: attr.DestinationId, + DestinationIds: attr.DestinationId, Weight: attr.Weight, SharedGroup: attr.SharedGroup, }, @@ -539,13 +539,13 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, Balance: &engine.Balance{ - Uuid: utils.GenUUID(), - Id: apiAct.BalanceId, - Value: apiAct.Units, - Weight: apiAct.BalanceWeight, - DestinationId: apiAct.DestinationId, - RatingSubject: apiAct.RatingSubject, - SharedGroup: apiAct.SharedGroup, + Uuid: utils.GenUUID(), + Id: apiAct.BalanceId, + Value: apiAct.Units, + Weight: apiAct.BalanceWeight, + DestinationIds: apiAct.DestinationIds, + RatingSubject: apiAct.RatingSubject, + SharedGroup: apiAct.SharedGroup, }, } storeActions[idx] = a @@ -579,7 +579,7 @@ func (self *ApierV1) GetActions(actsId string, reply *[]*utils.TPAction) error { } if engAct.Balance != nil { act.Units = engAct.Balance.Value - act.DestinationId = engAct.Balance.DestinationId + act.DestinationIds = engAct.Balance.DestinationIds act.RatingSubject = engAct.Balance.RatingSubject act.SharedGroup = engAct.Balance.SharedGroup act.BalanceWeight = engAct.Balance.Weight @@ -661,21 +661,21 @@ func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) error } type AttrAddActionTrigger struct { - ActionTriggersId string - Tenant string - Account string - ThresholdType string - ThresholdValue float64 - BalanceId string - BalanceType string - BalanceDirection string - BalanceDestinationId string - BalanceRatingSubject string //ToDo - BalanceWeight float64 - BalanceExpiryTime string - BalanceSharedGroup string //ToDo - Weight float64 - ActionsId string + ActionTriggersId string + Tenant string + Account string + ThresholdType string + ThresholdValue float64 + BalanceId string + BalanceType string + BalanceDirection string + BalanceDestinationIds string + BalanceRatingSubject string //ToDo + BalanceWeight float64 + BalanceExpiryTime string + BalanceSharedGroup string //ToDo + Weight float64 + ActionsId string } func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string) error { @@ -693,7 +693,7 @@ func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string BalanceId: attr.BalanceId, BalanceType: attr.BalanceType, BalanceDirection: attr.BalanceDirection, - BalanceDestinationId: attr.BalanceDestinationId, + BalanceDestinationIds: attr.BalanceDestinationIds, BalanceWeight: attr.BalanceWeight, BalanceExpirationDate: balExpiryTime, Weight: attr.Weight, diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 2eb845eb1..6361ade72 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -489,7 +489,7 @@ func TestApierTPActions(t *testing.T) { reply := "" act := &utils.TPActions{TPid: engine.TEST_SQL, ActionsId: "PREPAID_10", Actions: []*utils.TPAction{ &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Direction: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationId: "*any", BalanceWeight: 10, Weight: 10}, + DestinationIds: "*any", BalanceWeight: 10, Weight: 10}, }} actWarn := &utils.TPActions{TPid: engine.TEST_SQL, ActionsId: "WARN_VIA_HTTP", Actions: []*utils.TPAction{ &utils.TPAction{Identifier: "*call_url", ExtraParameters: "http://localhost:8000", Weight: 10}, @@ -1030,7 +1030,7 @@ func TestApierAddTriggeredAction(t *testing.T) { reply := "" // Add balance to a previously known account attrs := &AttrAddActionTrigger{Tenant: "cgrates.org", Account: "dan2", BalanceDirection: "*out", BalanceType: "*monetary", - ThresholdType: "*min_balance", ThresholdValue: 2, BalanceDestinationId: "*any", Weight: 10, ActionsId: "WARN_VIA_HTTP"} + ThresholdType: "*min_balance", ThresholdValue: 2, BalanceDestinationIds: "*any", Weight: 10, ActionsId: "WARN_VIA_HTTP"} if err := rater.Call("ApierV1.AddTriggeredAction", attrs, &reply); err != nil { t.Error("Got error on ApierV1.AddTriggeredAction: ", err.Error()) } else if reply != "OK" { diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 33d948a38..8024426b8 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -44,7 +44,7 @@ CREATE TABLE `tp_rates` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tpid` varchar(64) NOT NULL, `tag` varchar(64) NOT NULL, - `connect_fee` decimal(7,4) NOT NULL, + `connect_fee` decimal(7,4) NOT NULL, `rate` decimal(7,4) NOT NULL, `rate_unit` varchar(16) NOT NULL, `rate_increment` varchar(16) NOT NULL, @@ -71,7 +71,7 @@ CREATE TABLE `tp_destination_rates` ( `rounding_decimals` tinyint(4) NOT NULL, `max_cost` decimal(7,4) NOT NULL, `max_cost_strategy` varchar(16) NOT NULL, - `created_at` TIMESTAMP, + `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`), KEY `tpid_drid` (`tpid`,`tag`), @@ -155,7 +155,7 @@ CREATE TABLE `tp_actions` ( `units` DECIMAL(20,4) NOT NULL, `expiry_time` varchar(24) NOT NULL, `timing_tags` varchar(128) NOT NULL, - `destination_tag` varchar(64) NOT NULL, + `destination_tags` varchar(64) NOT NULL, `rating_subject` varchar(64) NOT NULL, `category` varchar(32) NOT NULL, `shared_group` varchar(64) NOT NULL, @@ -165,7 +165,7 @@ CREATE TABLE `tp_actions` ( `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`), - UNIQUE KEY `unique_action` (`tpid`,`tag`,`action`,`balance_tag`,`balance_type`,`direction`,`expiry_time`,`timing_tags`,`destination_tag`,`shared_group`,`balance_weight`,`weight`) + UNIQUE KEY `unique_action` (`tpid`,`tag`,`action`,`balance_tag`,`balance_type`,`direction`,`expiry_time`,`timing_tags`,`destination_tags`,`shared_group`,`balance_weight`,`weight`) ); -- @@ -203,10 +203,10 @@ CREATE TABLE `tp_action_triggers` ( `threshold_value` DECIMAL(20,4) NOT NULL, `recurrent` BOOLEAN NOT NULL, `min_sleep` varchar(16) NOT NULL, - `balance_destination_tag` varchar(64) NOT NULL, - `balance_weight` DECIMAL(8,2) NOT NULL, + `balance_destination_tags` varchar(64) NOT NULL, + `balance_weight` DECIMAL(8,2) NOT NULL, `balance_expiry_time` varchar(24) NOT NULL, - `balance_timing_tags` varchar(128) NOT NULL, + `balance_timing_tags` varchar(128) NOT NULL, `balance_rating_subject` varchar(64) NOT NULL, `balance_category` varchar(32) NOT NULL, `balance_shared_group` varchar(64) NOT NULL, @@ -216,7 +216,7 @@ CREATE TABLE `tp_action_triggers` ( `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`), - UNIQUE KEY `unique_trigger_definition` (`tpid`,`tag`,`balance_tag`,`balance_type`,`balance_direction`,`threshold_type`,`threshold_value`,`balance_destination_tag`,`actions_tag`) + UNIQUE KEY `unique_trigger_definition` (`tpid`,`tag`,`balance_tag`,`balance_type`,`balance_direction`,`threshold_type`,`threshold_value`,`balance_destination_tags`,`actions_tag`) ); -- @@ -249,7 +249,7 @@ CREATE TABLE tp_lcr_rules ( `tpid` varchar(64) NOT NULL, `direction` varchar(8) NOT NULL, `tenant` varchar(64) NOT NULL, - `category` varchar(32) NOT NULL, + `category` varchar(32) NOT NULL, `account` varchar(24) NOT NULL, `subject` varchar(64) NOT NULL, `destination_tag` varchar(64) NOT NULL, diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 8b5343b79..4aba6eade 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -42,7 +42,7 @@ CREATE TABLE tp_rates ( id SERIAL PRIMARY KEY, tpid VARCHAR(64) NOT NULL, tag VARCHAR(64) NOT NULL, - connect_fee NUMERIC(7,4) NOT NULL, + connect_fee NUMERIC(7,4) NOT NULL, rate NUMERIC(7,4) NOT NULL, rate_unit VARCHAR(16) NOT NULL, rate_increment VARCHAR(16) NOT NULL, @@ -150,7 +150,7 @@ CREATE TABLE tp_actions ( units NUMERIC(20,4) NOT NULL, expiry_time VARCHAR(24) NOT NULL, timing_tags VARCHAR(128) NOT NULL, - destination_tag VARCHAR(64) NOT NULL, + destination_tags VARCHAR(64) NOT NULL, rating_subject VARCHAR(64) NOT NULL, category VARCHAR(32) NOT NULL, shared_group VARCHAR(64) NOT NULL, @@ -158,7 +158,7 @@ CREATE TABLE tp_actions ( extra_parameters VARCHAR(256) NOT NULL, weight NUMERIC(8,2) NOT NULL, created_at TIMESTAMP, - UNIQUE (tpid, tag, action, balance_tag, balance_type, direction, expiry_time, timing_tags, destination_tag, shared_group, balance_weight, weight) + UNIQUE (tpid, tag, action, balance_tag, balance_type, direction, expiry_time, timing_tags, destination_tags, shared_group, balance_weight, weight) ); CREATE INDEX tpactions_tpid_idx ON tp_actions (tpid); CREATE INDEX tpactions_idx ON tp_actions (tpid,tag); @@ -198,10 +198,10 @@ CREATE TABLE tp_action_triggers ( threshold_value NUMERIC(20,4) NOT NULL, recurrent BOOLEAN NOT NULL, min_sleep VARCHAR(16) NOT NULL, - balance_destination_tag VARCHAR(64) NOT NULL, - balance_weight NUMERIC(8,2) NOT NULL, + balance_destination_tags VARCHAR(64) NOT NULL, + balance_weight NUMERIC(8,2) NOT NULL, balance_expiry_time VARCHAR(24) NOT NULL, - balance_timing_tags VARCHAR(128) NOT NULL, + balance_timing_tags VARCHAR(128) NOT NULL, balance_rating_subject VARCHAR(64) NOT NULL, balance_category VARCHAR(32) NOT NULL, balance_shared_group VARCHAR(64) NOT NULL, @@ -209,7 +209,7 @@ CREATE TABLE tp_action_triggers ( actions_tag VARCHAR(64) NOT NULL, weight NUMERIC(8,2) NOT NULL, created_at TIMESTAMP, - UNIQUE (tpid, tag, balance_tag, balance_type, balance_direction, threshold_type, threshold_value, balance_destination_tag, actions_tag) + UNIQUE (tpid, tag, balance_tag, balance_type, balance_direction, threshold_type, threshold_value, balance_destination_tags, actions_tag) ); CREATE INDEX tpactiontrigers_tpid_idx ON tp_action_triggers (tpid); CREATE INDEX tpactiontrigers_idx ON tp_action_triggers (tpid,tag); @@ -244,7 +244,7 @@ CREATE TABLE tp_lcr_rules ( tpid VARCHAR(64) NOT NULL, direction VARCHAR(8) NOT NULL, tenant VARCHAR(64) NOT NULL, - category VARCHAR(32) NOT NULL, + category VARCHAR(32) NOT NULL, account VARCHAR(24) NOT NULL, subject VARCHAR(64) NOT NULL, destination_tag VARCHAR(64) NOT NULL, diff --git a/engine/account.go b/engine/account.go index 2e40aca17..15e99fbc7 100644 --- a/engine/account.go +++ b/engine/account.go @@ -156,14 +156,20 @@ func (ub *Account) getBalancesForPrefix(prefix, category string, balances Balanc continue } b.account = ub - if b.DestinationId != "" && b.DestinationId != utils.ANY { + if b.DestinationIds != "" && b.DestinationIds != utils.ANY { for _, p := range utils.SplitPrefix(prefix, MIN_PREFIX_MATCH) { if x, err := cache2go.GetCached(DESTINATION_PREFIX + p); err == nil { destIds := x.(map[interface{}]struct{}) for dId, _ := range destIds { - if dId == b.DestinationId { - b.precision = len(p) - usefulBalances = append(usefulBalances, b) + balDestIds := strings.Split(b.DestinationIds, utils.INFIELD_SEP) + for _, balDestID := range balDestIds { + if dId == balDestID { + b.precision = len(p) + usefulBalances = append(usefulBalances, b) + break + } + } + if b.precision > 0 { break } } @@ -329,7 +335,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo increment.BalanceInfo.AccountId = ub.Id increment.paid = true if count { - ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: leftCC.Direction, Balance: &Balance{Value: cost, DestinationId: leftCC.Destination}}) + ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: leftCC.Direction, Balance: &Balance{Value: cost, DestinationIds: leftCC.Destination}}) } } } @@ -492,7 +498,7 @@ func (ub *Account) countUnits(a *Action) { ub.UnitCounters = append(ub.UnitCounters, unitsCounter) } - unitsCounter.addUnits(a.Balance.Value, a.Balance.DestinationId) // DestinationId is actually a destination (number or prefix) + unitsCounter.addUnits(a.Balance.Value, a.Balance.DestinationIds) // DestinationIds is actually a destination (number or prefix) ub.executeActionTriggers(nil) } @@ -617,7 +623,7 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance b.SubstractAmount(connectFee) // the conect fee is not refundable! if count { - acc.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationId: cc.Destination}}) + acc.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationIds: cc.Destination}}) } connectFeePaid = true break @@ -629,7 +635,7 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance acc.GetDefaultMoneyBalance(cc.Direction).Value -= connectFee // the conect fee is not refundable! if count { - acc.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationId: cc.Destination}}) + acc.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationIds: cc.Destination}}) } } } diff --git a/engine/account_test.go b/engine/account_test.go index 35aac4212..1ce98a279 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -82,8 +82,8 @@ func TestBalanceChainStoreRestore(t *testing.T) { } func TestAccountStorageStoreRestore(t *testing.T) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} accountingStorage.SetAccount(rifsBalance) ub1, err := accountingStorage.GetAccount("other") @@ -94,8 +94,8 @@ func TestAccountStorageStoreRestore(t *testing.T) { } func TestGetSecondsForPrefix(t *testing.T) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} ub1 := &Account{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 200}}}} cd := &CallDescriptor{ Category: "0", @@ -117,8 +117,8 @@ func TestGetSecondsForPrefix(t *testing.T) { } func TestGetSpecialPricedSeconds(t *testing.T) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET", RatingSubject: "minu"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT", RatingSubject: "minu"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET", RatingSubject: "minu"} ub1 := &Account{ Id: "OUT:CUSTOMER_1:rif", @@ -146,8 +146,8 @@ func TestGetSpecialPricedSeconds(t *testing.T) { } func TestAccountStorageStore(t *testing.T) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} accountingStorage.SetAccount(rifsBalance) result, err := accountingStorage.GetAccount(rifsBalance.Id) @@ -161,7 +161,7 @@ func TestAccountStorageStore(t *testing.T) { } func TestDebitCreditZeroSecond(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1s"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -201,7 +201,7 @@ func TestDebitCreditZeroSecond(t *testing.T) { } func TestDebitCreditZeroMinute(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -246,8 +246,8 @@ func TestDebitCreditZeroMinute(t *testing.T) { } func TestDebitCreditZeroMixedMinute(t *testing.T) { - b1 := &Balance{Uuid: "testm", Value: 70, Weight: 5, DestinationId: "NAT", RatingSubject: "*zero1m"} - b2 := &Balance{Uuid: "tests", Value: 10, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testm", Value: 70, Weight: 5, DestinationIds: "NAT", RatingSubject: "*zero1m"} + b2 := &Balance{Uuid: "tests", Value: 10, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1s"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -294,7 +294,7 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) { } func TestDebitCreditNoCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -345,7 +345,7 @@ func TestDebitCreditNoCredit(t *testing.T) { } func TestDebitCreditHasCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -398,7 +398,7 @@ func TestDebitCreditHasCredit(t *testing.T) { } func TestDebitCreditSplitMinutesMoney(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1s"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -446,7 +446,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) { } func TestDebitCreditMoreTimespans(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 150, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 150, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -494,8 +494,8 @@ func TestDebitCreditMoreTimespans(t *testing.T) { } func TestDebitCreditMoreTimespansMixed(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} - b2 := &Balance{Uuid: "testa", Value: 150, Weight: 5, DestinationId: "NAT", RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} + b2 := &Balance{Uuid: "testa", Value: 150, Weight: 5, DestinationIds: "NAT", RatingSubject: "*zero1s"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -544,7 +544,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) { } func TestDebitCreditNoConectFeeCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "*zero1m"} cc := &CallCost{ Direction: OUTBOUND, Destination: "0723045326", @@ -643,7 +643,7 @@ func TestDebitCreditMoneyOnly(t *testing.T) { } func TestDebitCreditSubjectMinutes(t *testing.T) { - b1 := &Balance{Uuid: "testb", Category: "0", Value: 250, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"} + b1 := &Balance{Uuid: "testb", Category: "0", Value: 250, Weight: 10, DestinationIds: "NAT", RatingSubject: "minu"} cc := &CallCost{ Tenant: "vdf", Category: "0", @@ -727,7 +727,7 @@ func TestDebitCreditSubjectMoney(t *testing.T) { testCallcost: cc, } rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{ - utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 75, DestinationId: "NAT", RatingSubject: "minu"}}, + utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 75, DestinationIds: "NAT", RatingSubject: "minu"}}, }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) @@ -804,7 +804,7 @@ func TestDebitCreditSubjectMoney(t *testing.T) { }*/ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "minu"} cc := &CallCost{ Tenant: "vdf", Category: "0", @@ -868,7 +868,7 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) { } func TestDebitCreditSubjectMixedPartPay(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"} + b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIds: "NAT", RatingSubject: "minu"} cc := &CallCost{ Tenant: "vdf", Category: "0", @@ -935,9 +935,9 @@ func TestAccountdebitBalance(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 + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14}}, utils.DATA: BalanceChain{&Balance{Value: 1204}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, } - newMb := &Balance{Weight: 20, DestinationId: "NEW"} + newMb := &Balance{Weight: 20, DestinationIds: "NEW"} a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: newMb} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE+OUTBOUND]) != 3 || ub.BalanceMap[utils.VOICE+OUTBOUND][2] != newMb { @@ -950,9 +950,9 @@ func TestAccountdebitBalanceExists(t *testing.T) { ub := &Account{ Id: "rif", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, } - newMb := &Balance{Value: -10, Weight: 20, DestinationId: "NAT"} + newMb := &Balance{Value: -10, Weight: 20, DestinationIds: "NAT"} a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: newMb} ub.debitBalanceAction(a, false) if len(ub.BalanceMap[utils.VOICE+OUTBOUND]) != 2 || ub.BalanceMap[utils.VOICE+OUTBOUND][0].Value != 25 { @@ -964,7 +964,7 @@ func TestAccountAddMinuteNil(t *testing.T) { ub := &Account{ Id: "rif", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, } ub.debitBalanceAction(nil, false) if len(ub.BalanceMap[utils.VOICE+OUTBOUND]) != 2 { @@ -973,9 +973,9 @@ func TestAccountAddMinuteNil(t *testing.T) { } func TestAccountAddMinutBucketEmpty(t *testing.T) { - mb1 := &Balance{Value: -10, DestinationId: "NAT"} - mb2 := &Balance{Value: -10, DestinationId: "NAT"} - mb3 := &Balance{Value: -10, DestinationId: "OTHER"} + mb1 := &Balance{Value: -10, DestinationIds: "NAT"} + mb2 := &Balance{Value: -10, DestinationIds: "NAT"} + mb3 := &Balance{Value: -10, DestinationIds: "OTHER"} ub := &Account{} a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: mb1} ub.debitBalanceAction(a, false) @@ -997,7 +997,7 @@ func TestAccountAddMinutBucketEmpty(t *testing.T) { func TestAccountExecuteTriggeredActions(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ThresholdType: TRIGGER_MAX_COUNTER, ActionsId: "TEST_ACTIONS"}}, } @@ -1021,7 +1021,7 @@ func TestAccountExecuteTriggeredActions(t *testing.T) { func TestAccountExecuteTriggeredActionsBalance(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 100, ThresholdType: TRIGGER_MIN_COUNTER, ActionsId: "TEST_ACTIONS"}}, } @@ -1115,8 +1115,8 @@ func TestAccountRefund(t *testing.T) { &Balance{Uuid: "moneya", Value: 100}, }, utils.VOICE + OUTBOUND: BalanceChain{ - &Balance{Uuid: "minutea", Value: 10, Weight: 20, DestinationId: "NAT"}, - &Balance{Uuid: "minuteb", Value: 10, DestinationId: "RET"}, + &Balance{Uuid: "minutea", Value: 10, Weight: 20, DestinationIds: "NAT"}, + &Balance{Uuid: "minuteb", Value: 10, DestinationIds: "RET"}, }, }, } @@ -1279,7 +1279,7 @@ func TestDebitSMS(t *testing.T) { testCallcost: cc, } rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{ - utils.SMS + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationId: "NAT"}}, + utils.SMS + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIds: "NAT"}}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error @@ -1329,7 +1329,7 @@ func TestDebitDataUnits(t *testing.T) { testCallcost: cc, } rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{ - utils.DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationId: "NAT"}}, + utils.DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIds: "NAT"}}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error @@ -1378,7 +1378,7 @@ func TestDebitDataMoney(t *testing.T) { testCallcost: cc, } rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{ - utils.DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 0, Weight: 5, DestinationId: "NAT"}}, + utils.DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 0, Weight: 5, DestinationIds: "NAT"}}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 160}}, }} var err error @@ -1415,8 +1415,8 @@ func TestAccountGetDefaultMoneyBalance(t *testing.T) { func BenchmarkGetSecondForPrefix(b *testing.B) { b.StopTimer() - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} ub1 := &Account{Id: "other", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} cd := &CallDescriptor{ @@ -1429,8 +1429,8 @@ func BenchmarkGetSecondForPrefix(b *testing.B) { } func BenchmarkAccountStorageStoreRestore(b *testing.B) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} for i := 0; i < b.N; i++ { accountingStorage.SetAccount(rifsBalance) @@ -1439,8 +1439,8 @@ func BenchmarkAccountStorageStoreRestore(b *testing.B) { } func BenchmarkGetSecondsForPrefix(b *testing.B) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationIds: "NAT"} + b2 := &Balance{Value: 100, Weight: 20, DestinationIds: "RET"} ub1 := &Account{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b1, b2}, utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} cd := &CallDescriptor{ Destination: "0723", diff --git a/engine/action.go b/engine/action.go index a97c0beb1..df55f4ce6 100644 --- a/engine/action.go +++ b/engine/action.go @@ -158,7 +158,7 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) case "balance_value": parsedValue += rsrFld.ParseValue(strconv.FormatFloat(action.Balance.Value, 'f', -1, 64)) case "destination_id": - parsedValue += rsrFld.ParseValue(action.Balance.DestinationId) + parsedValue += rsrFld.ParseValue(action.Balance.DestinationIds) case "extra_params": parsedValue += rsrFld.ParseValue(action.ExtraParameters) case "rating_subject": diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 2c3045c7c..edc8bd803 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -23,6 +23,7 @@ import ( "fmt" "regexp" "sort" + "strings" "time" "github.com/cgrates/cgrates/utils" @@ -38,7 +39,7 @@ type ActionTrigger struct { BalanceId string BalanceType string BalanceDirection string - BalanceDestinationId string // filter for balance + BalanceDestinationIds string // filter for balance BalanceWeight float64 // filter for balance BalanceExpirationDate time.Time // filter for balance BalanceTimingTags string // filter for balance @@ -124,7 +125,7 @@ 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 - destinationId = t.DestinationId == "" || at.BalanceDestinationId == t.DestinationId + destinationId = t.DestinationId == "" || strings.Contains(at.BalanceDestinationIds, t.DestinationId) weight = t.BalanceWeight == 0 || at.BalanceWeight == t.BalanceWeight ratingSubject = t.BalanceRatingSubject == "" || at.BalanceRatingSubject == t.BalanceRatingSubject category = t.BalanceCategory == "" || at.BalanceCategory == t.BalanceCategory @@ -133,6 +134,12 @@ func (at *ActionTrigger) Match(a *Action) bool { return id && direction && thresholdType && thresholdValue && destinationId && weight && ratingSubject && category && sharedGroup } +func (at *ActionTrigger) sortDestinationIds() string { + destIds := strings.Split(at.BalanceDestinationIds, utils.INFIELD_SEP) + sort.StringSlice(destIds).Sort() + return strings.Join(destIds, utils.INFIELD_SEP) +} + // Structure to store actions according to weight type ActionTriggerPriotityList []*ActionTrigger diff --git a/engine/actions_test.go b/engine/actions_test.go index 8070e9e40..539c0bb7b 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -21,10 +21,11 @@ package engine import ( "encoding/json" "fmt" - "github.com/cgrates/cgrates/utils" "reflect" "testing" "time" + + "github.com/cgrates/cgrates/utils" ) var ( @@ -617,16 +618,16 @@ func TestActionTriggerMatcAllFalse(t *testing.T) { func TestActionTriggerMatchAll(t *testing.T) { at := &ActionTrigger{ - BalanceDirection: OUTBOUND, - BalanceType: utils.MONETARY, - ThresholdType: TRIGGER_MAX_BALANCE, - ThresholdValue: 2, - BalanceDestinationId: "NAT", - BalanceWeight: 1.0, - BalanceRatingSubject: "test1", - BalanceSharedGroup: "test2", + BalanceDirection: OUTBOUND, + BalanceType: utils.MONETARY, + ThresholdType: TRIGGER_MAX_BALANCE, + ThresholdValue: 2, + BalanceDestinationIds: "NAT", + BalanceWeight: 1.0, + BalanceRatingSubject: "test1", + BalanceSharedGroup: "test2", } - a := &Action{Direction: OUTBOUND, BalanceType: utils.MONETARY, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "DestinationId": "%v", "BalanceWeight": %v, "BalanceRatingSubject": "%v", "BalanceSharedGroup": "%v"}`, TRIGGER_MAX_BALANCE, 2, "NAT", 1.0, "test1", "test2")} + a := &Action{Direction: OUTBOUND, BalanceType: utils.MONETARY, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "DestinationIds": "%v", "BalanceWeight": %v, "BalanceRatingSubject": "%v", "BalanceSharedGroup": "%v"}`, 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) } @@ -647,7 +648,7 @@ func TestActionTriggerPriotityList(t *testing.T) { func TestActionResetTriggres(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -673,7 +674,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { func TestActionResetTriggresActionFilter(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -686,7 +687,7 @@ func TestActionResetTriggresActionFilter(t *testing.T) { func TestActionSetPostpaid(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -700,7 +701,7 @@ func TestActionSetPrepaid(t *testing.T) { ub := &Account{ Id: "TEST_UB", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -714,7 +715,7 @@ func TestActionResetPrepaid(t *testing.T) { ub := &Account{ Id: "TEST_UB", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -732,7 +733,7 @@ func TestActionResetPrepaid(t *testing.T) { func TestActionResetPostpaid(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.SMS, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -748,7 +749,7 @@ func TestActionResetPostpaid(t *testing.T) { func TestActionTopupResetCredit(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -806,11 +807,11 @@ func TestActionTopupResetMinutes(t *testing.T) { Id: "TEST_UB", BalanceMap: map[string]BalanceChain{ utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, - utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationId: "NAT"}} + a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: "NAT"}} topupResetAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE+OUTBOUND].GetTotalValue() != 5 || @@ -825,7 +826,7 @@ func TestActionTopupResetMinutes(t *testing.T) { func TestActionTopupCredit(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -843,11 +844,11 @@ func TestActionTopupCredit(t *testing.T) { func TestActionTopupMinutes(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationId: "NAT"}} + a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: "NAT"}} topupAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE+OUTBOUND].GetTotalValue() != 15 || @@ -862,7 +863,7 @@ func TestActionTopupMinutes(t *testing.T) { func TestActionDebitCredit(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -880,11 +881,11 @@ func TestActionDebitCredit(t *testing.T) { func TestActionDebitMinutes(t *testing.T) { ub := &Account{ Id: "TEST_UB", - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } - a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationId: "NAT"}} + a := &Action{BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Value: 5, Weight: 20, DestinationIds: "NAT"}} debitAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE+OUTBOUND][0].Value != 5 || @@ -903,8 +904,8 @@ func TestActionResetAllCounters(t *testing.T) { BalanceMap: map[string]BalanceChain{ utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{ - &Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, - &Balance{Weight: 10, DestinationId: "RET"}}}, + &Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, + &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -921,7 +922,7 @@ func TestActionResetAllCounters(t *testing.T) { t.FailNow() } mb := ub.UnitCounters[0].Balances[0] - if mb.Weight != 20 || mb.Value != 0 || mb.DestinationId != "NAT" { + if mb.Weight != 20 || mb.Value != 0 || mb.DestinationIds != "NAT" { t.Errorf("Balance cloned incorrectly: %v!", mb) } } @@ -932,7 +933,7 @@ func TestActionResetCounterMinutes(t *testing.T) { AllowNegative: true, BalanceMap: map[string]BalanceChain{ utils.MONETARY: BalanceChain{&Balance{Value: 100}}, - utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, ThresholdType: "*max_counter", ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -953,7 +954,7 @@ func TestActionResetCounterMinutes(t *testing.T) { t.FailNow() } mb := ub.UnitCounters[1].Balances[0] - if mb.Weight != 20 || mb.Value != 0 || mb.DestinationId != "NAT" { + if mb.Weight != 20 || mb.Value != 0 || mb.DestinationIds != "NAT" { t.Errorf("Balance cloned incorrectly: %+v!", mb) } } @@ -962,7 +963,7 @@ func TestActionResetCounterCredit(t *testing.T) { ub := &Account{ Id: "TEST_UB", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE + OUTBOUND: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceType: utils.MONETARY, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}, &UnitsCounter{BalanceType: utils.SMS, Direction: OUTBOUND, Balances: BalanceChain{&Balance{Value: 1}}}}, ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceType: utils.MONETARY, BalanceDirection: OUTBOUND, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}}, } @@ -979,13 +980,13 @@ func TestActionResetCounterCredit(t *testing.T) { func TestActionTriggerLogging(t *testing.T) { at := &ActionTrigger{ - Id: "some_uuid", - BalanceType: utils.MONETARY, - BalanceDirection: OUTBOUND, - ThresholdValue: 100.0, - BalanceDestinationId: "NAT", - Weight: 10.0, - ActionsId: "TEST_ACTIONS", + Id: "some_uuid", + BalanceType: utils.MONETARY, + BalanceDirection: OUTBOUND, + ThresholdValue: 100.0, + BalanceDestinationIds: "NAT", + Weight: 10.0, + ActionsId: "TEST_ACTIONS", } as, err := accountingStorage.GetActions(at.ActionsId, false) if err != nil { @@ -1069,7 +1070,7 @@ func TestTopupAction(t *testing.T) { ActionType: "*topup", BalanceType: utils.MONETARY, Direction: OUTBOUND, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, } at := &ActionTiming{ @@ -1092,7 +1093,7 @@ func TestTopupActionLoaded(t *testing.T) { ActionType: "*topup", BalanceType: utils.MONETARY, Direction: OUTBOUND, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, } at := &ActionTiming{ @@ -1119,7 +1120,7 @@ func TestActionCdrlogEmpty(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, }, }) if err != nil { @@ -1141,11 +1142,11 @@ func TestActionCdrlogWithParams(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, }, }) if err != nil { @@ -1168,11 +1169,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + Balance: &Balance{Value: 25, DestinationIds: "RET", Weight: 20}, }, }) if err != nil { diff --git a/engine/balances.go b/engine/balances.go index 397867bd8..9332e2bd5 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -34,7 +34,7 @@ type Balance struct { Value float64 ExpirationDate time.Time Weight float64 - DestinationId string + DestinationIds string RatingSubject string Category string SharedGroup string @@ -46,16 +46,18 @@ type Balance struct { } func (b *Balance) Equal(o *Balance) bool { - if b.DestinationId == "" { - b.DestinationId = utils.ANY + if b.DestinationIds == "" { + b.DestinationIds = utils.ANY } - if o.DestinationId == "" { - o.DestinationId = utils.ANY + if o.DestinationIds == "" { + o.DestinationIds = utils.ANY } + bDestIds := b.sortDestinationIds() + oDestIds := o.sortDestinationIds() return b.Id == o.Id && b.ExpirationDate.Equal(o.ExpirationDate) && b.Weight == o.Weight && - b.DestinationId == o.DestinationId && + bDestIds == oDestIds && b.RatingSubject == o.RatingSubject && b.Category == o.Category && b.SharedGroup == o.SharedGroup @@ -65,15 +67,17 @@ func (b *Balance) MatchFilter(o *Balance) bool { if o.Id != "" { return b.Id == o.Id } - if b.DestinationId == "" { - b.DestinationId = utils.ANY + if b.DestinationIds == "" { + b.DestinationIds = utils.ANY } - if o.DestinationId == "" { - o.DestinationId = utils.ANY + if o.DestinationIds == "" { + o.DestinationIds = utils.ANY } + bDestIds := b.sortDestinationIds() + oDestIds := o.sortDestinationIds() return (o.ExpirationDate.IsZero() || b.ExpirationDate.Equal(o.ExpirationDate)) && (o.Weight == 0 || b.Weight == o.Weight) && - (o.DestinationId == "" || b.DestinationId == o.DestinationId) && + (oDestIds == "" || bDestIds == oDestIds) && (o.RatingSubject == "" || b.RatingSubject == o.RatingSubject) && (o.Category == "" || b.Category == o.Category) && (o.SharedGroup == "" || b.SharedGroup == o.SharedGroup) @@ -81,7 +85,7 @@ func (b *Balance) MatchFilter(o *Balance) bool { // the default balance has no destinationid, Expirationdate or ratesubject func (b *Balance) IsDefault() bool { - return (b.DestinationId == "" || b.DestinationId == utils.ANY) && + return (b.DestinationIds == "" || b.DestinationIds == utils.ANY) && b.RatingSubject == "" && b.Category == "" && b.ExpirationDate.IsZero() && @@ -109,16 +113,22 @@ func (b *Balance) IsActiveAt(t time.Time) bool { return false } +func (b *Balance) sortDestinationIds() string { + destIds := strings.Split(b.DestinationIds, utils.INFIELD_SEP) + sort.StringSlice(destIds).Sort() + return strings.Join(destIds, utils.INFIELD_SEP) +} + func (b *Balance) MatchCategory(category string) bool { return b.Category == "" || b.Category == category } func (b *Balance) HasDestination() bool { - return b.DestinationId != "" && b.DestinationId != utils.ANY + return b.DestinationIds != "" && b.DestinationIds != utils.ANY } func (b *Balance) MatchDestination(destinationId string) bool { - return !b.HasDestination() || b.DestinationId == destinationId + return !b.HasDestination() || strings.Contains(b.DestinationIds, destinationId) } func (b *Balance) MatchActionTrigger(at *ActionTrigger) bool { @@ -126,8 +136,10 @@ func (b *Balance) MatchActionTrigger(at *ActionTrigger) bool { return b.Id == at.BalanceId } matchesDestination := true - if at.BalanceDestinationId != "" { - matchesDestination = (at.BalanceDestinationId == b.DestinationId) + if at.BalanceDestinationIds != "" { + bDestIds := b.sortDestinationIds() + atDestinationIds := at.sortDestinationIds() + matchesDestination = (bDestIds == atDestinationIds) } matchesExpirationDate := true if !at.BalanceExpirationDate.IsZero() { @@ -159,7 +171,7 @@ func (b *Balance) Clone() *Balance { Uuid: b.Uuid, Id: b.Id, Value: b.Value, // this value is in seconds - DestinationId: b.DestinationId, + DestinationIds: b.DestinationIds, ExpirationDate: b.ExpirationDate, Weight: b.Weight, RatingSubject: b.RatingSubject, @@ -293,7 +305,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala inc.Cost = 0 inc.paid = true if count { - ub.countUnits(&Action{BalanceType: cc.TOR, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: cc.TOR, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationIds: cc.Destination}}) } } else { inc.paid = false @@ -355,7 +367,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala inc.BalanceInfo.AccountId = ub.Id inc.paid = true if count { - ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: cost, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: cost, DestinationIds: cc.Destination}}) } // go to nextincrement continue @@ -379,9 +391,9 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala } inc.paid = true if count { - ub.countUnits(&Action{BalanceType: cc.TOR, Direction: cc.Direction, Balance: &Balance{Value: seconds, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: cc.TOR, Direction: cc.Direction, Balance: &Balance{Value: seconds, DestinationIds: cc.Destination}}) if cost != 0 { - ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: cost, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: cost, DestinationIds: cc.Destination}}) } } } else { @@ -456,7 +468,7 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun inc.BalanceInfo.AccountId = ub.Id inc.paid = true if count { - ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationIds: cc.Destination}}) } // go to nextincrement continue @@ -469,7 +481,7 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun inc.BalanceInfo.AccountId = ub.Id inc.paid = true if count { - ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: utils.MONETARY, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationIds: cc.Destination}}) } } else { inc.paid = false diff --git a/engine/balances_test.go b/engine/balances_test.go index 47550b586..eb8b2587e 100644 --- a/engine/balances_test.go +++ b/engine/balances_test.go @@ -21,6 +21,8 @@ package engine import ( "reflect" "testing" + + "github.com/cgrates/cgrates/utils" ) func TestBalanceSortPrecision(t *testing.T) { @@ -79,24 +81,24 @@ func TestBalanceSortWeightLess(t *testing.T) { } func TestBalanceEqual(t *testing.T) { - mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} - mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} - mb3 := &Balance{Weight: 1, precision: 1, RatingSubject: "2", DestinationId: ""} + mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} + mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} + mb3 := &Balance{Weight: 1, precision: 1, RatingSubject: "2", DestinationIds: ""} if !mb1.Equal(mb2) || mb2.Equal(mb3) { t.Error("Equal failure!", mb1 == mb2, mb3) } } func TestBalanceMatchFilter(t *testing.T) { - mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} - mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "", DestinationId: ""} + mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} + mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "", DestinationIds: ""} if !mb1.MatchFilter(mb2) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } } func TestBalanceMatchFilterEmpty(t *testing.T) { - mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} + mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} mb2 := &Balance{} if !mb1.MatchFilter(mb2) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) @@ -104,23 +106,23 @@ func TestBalanceMatchFilterEmpty(t *testing.T) { } func TestBalanceMatchFilterId(t *testing.T) { - mb1 := &Balance{Id: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationId: "NAT"} - mb2 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} + mb1 := &Balance{Id: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIds: "NAT"} + mb2 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} if !mb1.MatchFilter(mb2) { t.Errorf("Match filter failure: %+v == %+v", mb1, mb2) } } func TestBalanceMatchFilterDiffId(t *testing.T) { - mb1 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} - mb2 := &Balance{Id: "T2", Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} + mb1 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} + mb2 := &Balance{Id: "T2", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: ""} if mb1.MatchFilter(mb2) { t.Errorf("Match filter failure: %+v != %+v", mb1, mb2) } } func TestBalanceClone(t *testing.T) { - mb1 := &Balance{Value: 1, Weight: 2, RatingSubject: "test", DestinationId: "5"} + mb1 := &Balance{Value: 1, Weight: 2, RatingSubject: "test", DestinationIds: "5"} mb2 := mb1.Clone() if mb1 == mb2 || !reflect.DeepEqual(mb1, mb2) { t.Errorf("Cloning failure: \n%v\n%v", mb1, mb2) @@ -149,21 +151,21 @@ func TestBalanceMatchActionTriggerId(t *testing.T) { } func TestBalanceMatchActionTriggerDestination(t *testing.T) { - at := &ActionTrigger{BalanceDestinationId: "test"} - b := &Balance{DestinationId: "test"} + at := &ActionTrigger{BalanceDestinationIds: "test"} + b := &Balance{DestinationIds: "test"} if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } - b.DestinationId = "test1" + b.DestinationIds = "test1" if b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } - b.DestinationId = "" + b.DestinationIds = "" if b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } - b.DestinationId = "test" - at.BalanceDestinationId = "" + b.DestinationIds = "test" + at.BalanceDestinationIds = "" if !b.MatchActionTrigger(at) { t.Errorf("Error matching action trigger: %+v %+v", b, at) } @@ -238,3 +240,27 @@ func TestBalanceIsDefault(t *testing.T) { t.Errorf("Balance should be default: %+v", b) } } + +func TestBalanceSortDestinationIds(t *testing.T) { + b := Balance{DestinationIds: "a_first;c_third;b_second"} + sortedDestIds := b.sortDestinationIds() + if sortedDestIds != "a_first;b_second;c_third" { + t.Error("Error sorting destination ids: ", sortedDestIds) + } +} + +func TestBalanceSortDestinationIdsOne(t *testing.T) { + b := Balance{DestinationIds: utils.ANY} + sortedDestIds := b.sortDestinationIds() + if sortedDestIds != utils.ANY { + t.Error("Error sorting destination ids: ", sortedDestIds) + } +} + +func TestBalanceSortDestinationEmpty(t *testing.T) { + b := Balance{DestinationIds: ""} + sortedDestIds := b.sortDestinationIds() + if sortedDestIds != "" { + t.Error("Error sorting destination ids: ", sortedDestIds) + } +} diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 2c4f95ac1..c34e95505 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -40,7 +40,7 @@ func init() { func populateDB() { ats := []*Action{ &Action{ActionType: "*topup", BalanceType: utils.MONETARY, Direction: OUTBOUND, Balance: &Balance{Value: 10}}, - &Action{ActionType: "*topup", BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Weight: 20, Value: 10, DestinationId: "NAT"}}, + &Action{ActionType: "*topup", BalanceType: utils.VOICE, Direction: OUTBOUND, Balance: &Balance{Weight: 20, Value: 10, DestinationIds: "NAT"}}, } ats1 := []*Action{ &Action{ActionType: "*topup", BalanceType: utils.MONETARY, Direction: OUTBOUND, Balance: &Balance{Value: 10}, Weight: 20}, @@ -51,16 +51,16 @@ func populateDB() { BalanceMap: map[string]BalanceChain{ utils.MONETARY + OUTBOUND: BalanceChain{&Balance{Value: 50}}, utils.VOICE + OUTBOUND: BalanceChain{ - &Balance{Value: 200, DestinationId: "NAT", Weight: 10}, - &Balance{Value: 100, DestinationId: "RET", Weight: 20}, + &Balance{Value: 200, DestinationIds: "NAT", Weight: 10}, + &Balance{Value: 100, DestinationIds: "RET", Weight: 20}, }}, } broker := &Account{ Id: "*out:vdf:broker", BalanceMap: map[string]BalanceChain{ utils.VOICE + OUTBOUND: BalanceChain{ - &Balance{Value: 20, DestinationId: "NAT", Weight: 10, RatingSubject: "rif"}, - &Balance{Value: 100, DestinationId: "RET", Weight: 20}, + &Balance{Value: 20, DestinationIds: "NAT", Weight: 10, RatingSubject: "rif"}, + &Balance{Value: 100, DestinationIds: "RET", Weight: 20}, }}, } luna := &Account{ @@ -75,8 +75,8 @@ func populateDB() { Id: "*out:vdf:minitsboy", BalanceMap: map[string]BalanceChain{ utils.VOICE + OUTBOUND: BalanceChain{ - &Balance{Value: 20, DestinationId: "NAT", Weight: 10, RatingSubject: "rif"}, - &Balance{Value: 100, DestinationId: "RET", Weight: 20}, + &Balance{Value: 20, DestinationIds: "NAT", Weight: 10, RatingSubject: "rif"}, + &Balance{Value: 100, DestinationIds: "RET", Weight: 20}, }, utils.MONETARY + OUTBOUND: BalanceChain{ &Balance{Value: 100, Weight: 10}, diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 8dded3e10..c15553d4a 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -697,15 +697,15 @@ func (csvr *CSVReader) LoadActions() (err error) { ExpirationString: record[ACTSCSVIDX_EXPIRY_TIME], ExtraParameters: record[ACTSCSVIDX_EXTRA_PARAMS], Balance: &Balance{ - Uuid: utils.GenUUID(), - Id: record[ACTSCSVIDX_BALANCE_TAG], - Value: units, - Weight: balanceWeight, - DestinationId: record[ACTSCSVIDX_DESTINATION_TAG], - TimingIDs: record[ACTSCSVIDX_TIMING_TAGS], - RatingSubject: record[ACTSCSVIDX_RATING_SUBJECT], - Category: record[ACTSCSVIDX_CATEGORY], - SharedGroup: record[ACTSCSVIDX_SHARED_GROUP], + Uuid: utils.GenUUID(), + Id: record[ACTSCSVIDX_BALANCE_TAG], + Value: units, + Weight: balanceWeight, + DestinationIds: record[ACTSCSVIDX_DESTINATION_TAG], + TimingIDs: record[ACTSCSVIDX_TIMING_TAGS], + RatingSubject: record[ACTSCSVIDX_RATING_SUBJECT], + Category: record[ACTSCSVIDX_CATEGORY], + SharedGroup: record[ACTSCSVIDX_SHARED_GROUP], }, } // load action timings from tags @@ -839,7 +839,7 @@ func (csvr *CSVReader) LoadActionTriggers() (err error) { BalanceId: record[ATRIGCSVIDX_BAL_TAG], BalanceType: record[ATRIGCSVIDX_BAL_TYPE], BalanceDirection: record[ATRIGCSVIDX_BAL_DIRECTION], - BalanceDestinationId: record[ATRIGCSVIDX_BAL_DESTINATION_TAG], + BalanceDestinationIds: record[ATRIGCSVIDX_BAL_DESTINATION_TAG], BalanceWeight: balanceWeight, BalanceExpirationDate: balanceExp, BalanceTimingTags: record[ATRIGCSVIDX_BAL_TIMING_TAGS], diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 8f1a07798..45aa7bcd0 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -725,11 +725,11 @@ func TestLoadActions(t *testing.T) { ExtraParameters: "", Weight: 10, Balance: &Balance{ - Uuid: as1[1].Balance.Uuid, - Value: 100, - Weight: 10, - RatingSubject: "test", - DestinationId: "NAT", + Uuid: as1[1].Balance.Uuid, + Value: 100, + Weight: 10, + RatingSubject: "test", + DestinationIds: "NAT", }, }, } @@ -891,30 +891,30 @@ func TestLoadActionTriggers(t *testing.T) { } atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0] expected := &ActionTrigger{ - Id: "st0", - BalanceType: utils.VOICE, - BalanceDirection: OUTBOUND, - ThresholdType: TRIGGER_MIN_COUNTER, - ThresholdValue: 10, - BalanceDestinationId: "GERMANY_O2", - Weight: 10, - ActionsId: "SOME_1", - Executed: false, + Id: "st0", + BalanceType: utils.VOICE, + BalanceDirection: OUTBOUND, + ThresholdType: TRIGGER_MIN_COUNTER, + ThresholdValue: 10, + BalanceDestinationIds: "GERMANY_O2", + Weight: 10, + ActionsId: "SOME_1", + Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Error("Error loading action trigger: ", atr) } atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1] expected = &ActionTrigger{ - Id: "st1", - BalanceType: utils.VOICE, - BalanceDirection: OUTBOUND, - ThresholdType: TRIGGER_MAX_BALANCE, - ThresholdValue: 200, - BalanceDestinationId: "GERMANY", - Weight: 10, - ActionsId: "SOME_2", - Executed: false, + Id: "st1", + BalanceType: utils.VOICE, + BalanceDirection: OUTBOUND, + ThresholdType: TRIGGER_MAX_BALANCE, + ThresholdValue: 200, + BalanceDestinationIds: "GERMANY", + Weight: 10, + ActionsId: "SOME_2", + Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Error("Error loading action trigger: ", atr) diff --git a/engine/loader_db.go b/engine/loader_db.go index 2d057b882..ceb2d2b1a 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -568,14 +568,14 @@ func (dbr *DbReader) LoadActions() (err error) { ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Balance: &Balance{ - Uuid: utils.GenUUID(), - Id: tpact.BalanceId, - Value: tpact.Units, - Weight: tpact.BalanceWeight, - TimingIDs: tpact.TimingTags, - RatingSubject: tpact.RatingSubject, - Category: tpact.Category, - DestinationId: tpact.DestinationId, + Uuid: utils.GenUUID(), + Id: tpact.BalanceId, + Value: tpact.Units, + Weight: tpact.BalanceWeight, + TimingIDs: tpact.TimingTags, + RatingSubject: tpact.RatingSubject, + Category: tpact.Category, + DestinationIds: tpact.DestinationIds, }, } // load action timings from tags @@ -665,7 +665,7 @@ func (dbr *DbReader) LoadActionTriggers() (err error) { BalanceId: apiAtr.BalanceId, BalanceType: apiAtr.BalanceType, BalanceDirection: apiAtr.BalanceDirection, - BalanceDestinationId: apiAtr.BalanceDestinationId, + BalanceDestinationIds: apiAtr.BalanceDestinationIds, BalanceWeight: apiAtr.BalanceWeight, BalanceExpirationDate: balance_expiration_date, BalanceTimingTags: apiAtr.BalanceTimingTags, @@ -821,7 +821,7 @@ func (dbr *DbReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) BalanceId: apiAtr.BalanceId, BalanceType: apiAtr.BalanceType, BalanceDirection: apiAtr.BalanceDirection, - BalanceDestinationId: apiAtr.BalanceDestinationId, + BalanceDestinationIds: apiAtr.BalanceDestinationIds, BalanceWeight: apiAtr.BalanceWeight, BalanceExpirationDate: expTime, BalanceRatingSubject: apiAtr.BalanceRatingSubject, @@ -859,11 +859,11 @@ func (dbr *DbReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Balance: &Balance{ - Uuid: utils.GenUUID(), - Value: tpact.Units, - Weight: tpact.BalanceWeight, - RatingSubject: tpact.RatingSubject, - DestinationId: tpact.DestinationId, + Uuid: utils.GenUUID(), + Value: tpact.Units, + Weight: tpact.BalanceWeight, + RatingSubject: tpact.RatingSubject, + DestinationIds: tpact.DestinationIds, }, } } diff --git a/engine/models.go b/engine/models.go index 20a01902d..141173559 100644 --- a/engine/models.go +++ b/engine/models.go @@ -138,7 +138,7 @@ type TpAction struct { Units float64 ExpiryTime string TimingTags string - DestinationTag string + DestinationTags string RatingSubject string Category string SharedGroup string @@ -159,28 +159,28 @@ type TpActionPlan struct { } type TpActionTrigger struct { - Id int64 - Tpid string - Tag string - UniqueId string - ThresholdType string - ThresholdValue float64 - Recurrent bool - MinSleep string - BalanceTag string - BalanceType string - BalanceDirection string - BalanceDestinationTag string - BalanceWeight float64 - BalanceExpiryTime string - BalanceTimingTags string - BalanceRatingSubject string - BalanceCategory string - BalanceSharedGroup string - MinQueuedItems int - ActionsTag string - Weight float64 - CreatedAt time.Time + Id int64 + Tpid string + Tag string + UniqueId string + ThresholdType string + ThresholdValue float64 + Recurrent bool + MinSleep string + BalanceTag string + BalanceType string + BalanceDirection string + BalanceDestinationTags string + BalanceWeight float64 + BalanceExpiryTime string + BalanceTimingTags string + BalanceRatingSubject string + BalanceCategory string + BalanceSharedGroup string + MinQueuedItems int + ActionsTag string + Weight float64 + CreatedAt time.Time } type TpAccountAction struct { diff --git a/engine/responder_test.go b/engine/responder_test.go index e3b22a6a0..58a995bc7 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -71,8 +71,8 @@ func TestGetDerivedMaxSessionTime(t *testing.T) { if err := dataStorage.SetDestination(deTMobile); err != nil { t.Error(err) } - b10 := &Balance{Value: 10, Weight: 10, DestinationId: "DE_TMOBILE"} - b20 := &Balance{Value: 20, Weight: 10, DestinationId: "DE_TMOBILE"} + b10 := &Balance{Value: 10, Weight: 10, DestinationIds: "DE_TMOBILE"} + b20 := &Balance{Value: 20, Weight: 10, DestinationIds: "DE_TMOBILE"} rifsAccount := &Account{Id: utils.ConcatenatedKey(utils.OUT, testTenant, "rif"), BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b10}}} dansAccount := &Account{Id: utils.ConcatenatedKey(utils.OUT, testTenant, "dan"), BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{b20}}} if err := accountingStorage.SetAccount(rifsAccount); err != nil { @@ -419,8 +419,8 @@ func TestGetLCR(t *testing.T) { } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts[1], lcrLc.SupplierCosts[1]) } - bRif12 := &Balance{Value: 40, Weight: 10, DestinationId: dstDe.Id} - bIvo12 := &Balance{Value: 60, Weight: 10, DestinationId: dstDe.Id} + bRif12 := &Balance{Value: 40, Weight: 10, DestinationIds: dstDe.Id} + bIvo12 := &Balance{Value: 60, Weight: 10, DestinationIds: dstDe.Id} rif12sAccount := &Account{Id: utils.ConcatenatedKey(utils.OUT, "tenant12", "rif12"), BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{bRif12}}, AllowNegative: true} ivo12sAccount := &Account{Id: utils.ConcatenatedKey(utils.OUT, "tenant12", "ivo12"), BalanceMap: map[string]BalanceChain{utils.VOICE + OUTBOUND: BalanceChain{bIvo12}}, AllowNegative: true} for _, acnt := range []*Account{rif12sAccount, ivo12sAccount} { diff --git a/engine/storage_mysql_local_test.go b/engine/storage_mysql_local_test.go index 9e08a6055..e90951310 100644 --- a/engine/storage_mysql_local_test.go +++ b/engine/storage_mysql_local_test.go @@ -233,7 +233,7 @@ func TestMySQLSetGetTPActions(t *testing.T) { ACTS_ID := "PREPAID_10" acts := []*utils.TPAction{ &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Direction: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationId: "*any", BalanceWeight: 10, Weight: 10}} + DestinationIds: "*any", BalanceWeight: 10, Weight: 10}} tpActions := &utils.TPActions{TPid: TEST_SQL, ActionsId: ACTS_ID, Actions: acts} if err := mysqlDb.SetTPActions(TEST_SQL, map[string][]*utils.TPAction{ACTS_ID: acts}); err != nil { t.Error(err.Error()) @@ -266,15 +266,15 @@ func TestMySQLSetGetTPActionTriggers(t *testing.T) { return } atrg := &utils.TPActionTrigger{ - Id: "MY_FIRST_ATGR", - BalanceType: "*monetary", - BalanceDirection: "*out", - ThresholdType: "*min_balance", - ThresholdValue: 2.0, - Recurrent: true, - BalanceDestinationId: "*any", - Weight: 10.0, - ActionsId: "LOG_BALANCE", + Id: "MY_FIRST_ATGR", + BalanceType: "*monetary", + BalanceDirection: "*out", + ThresholdType: "*min_balance", + ThresholdValue: 2.0, + Recurrent: true, + BalanceDestinationIds: "*any", + Weight: 10.0, + ActionsId: "LOG_BALANCE", } mpAtrgs := map[string][]*utils.TPActionTrigger{TEST_SQL: []*utils.TPActionTrigger{atrg}} if err := mysqlDb.SetTPActionTriggers(TEST_SQL, mpAtrgs); err != nil { diff --git a/engine/storage_psql_local_test.go b/engine/storage_psql_local_test.go index f8d45c325..04f18b52c 100644 --- a/engine/storage_psql_local_test.go +++ b/engine/storage_psql_local_test.go @@ -232,7 +232,7 @@ func TestPSQLSetGetTPActions(t *testing.T) { ACTS_ID := "PREPAID_10" acts := []*utils.TPAction{ &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Direction: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationId: "*any", BalanceWeight: 10, Weight: 10}} + DestinationIds: "*any", BalanceWeight: 10, Weight: 10}} tpActions := &utils.TPActions{TPid: TEST_SQL, ActionsId: ACTS_ID, Actions: acts} if err := psqlDb.SetTPActions(TEST_SQL, map[string][]*utils.TPAction{ACTS_ID: acts}); err != nil { t.Error(err.Error()) @@ -265,15 +265,15 @@ func TestPSQLSetGetTPActionTriggers(t *testing.T) { return } atrg := &utils.TPActionTrigger{ - Id: "MY_FIRST_ATGR", - BalanceType: "*monetary", - BalanceDirection: "*out", - ThresholdType: "*min_balance", - ThresholdValue: 2.0, - Recurrent: true, - BalanceDestinationId: "*any", - Weight: 10.0, - ActionsId: "LOG_BALANCE", + Id: "MY_FIRST_ATGR", + BalanceType: "*monetary", + BalanceDirection: "*out", + ThresholdType: "*min_balance", + ThresholdValue: 2.0, + Recurrent: true, + BalanceDestinationIds: "*any", + Weight: 10.0, + ActionsId: "LOG_BALANCE", } mpAtrgs := map[string][]*utils.TPActionTrigger{TEST_SQL: []*utils.TPActionTrigger{atrg}} if err := psqlDb.SetTPActionTriggers(TEST_SQL, mpAtrgs); err != nil { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index a1eadcbf2..6a31ba73a 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -520,7 +520,7 @@ func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*utils.TPAct Units: ac.Units, ExpiryTime: ac.ExpiryTime, TimingTags: ac.TimingTags, - DestinationTag: ac.DestinationId, + DestinationTags: ac.DestinationIds, RatingSubject: ac.RatingSubject, Category: ac.Category, SharedGroup: ac.SharedGroup, @@ -553,7 +553,7 @@ func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, err Units: tpAct.Units, ExpiryTime: tpAct.ExpiryTime, TimingTags: tpAct.TimingTags, - DestinationId: tpAct.DestinationTag, + DestinationIds: tpAct.DestinationTags, RatingSubject: tpAct.RatingSubject, Category: tpAct.Category, BalanceWeight: tpAct.BalanceWeight, @@ -622,27 +622,27 @@ func (self *SQLStorage) SetTPActionTriggers(tpid string, ats map[string][]*utils id = utils.GenUUID() } saved := tx.Save(&TpActionTrigger{ - Tpid: tpid, - UniqueId: id, - Tag: atId, - ThresholdType: at.ThresholdType, - ThresholdValue: at.ThresholdValue, - Recurrent: at.Recurrent, - MinSleep: at.MinSleep, - BalanceTag: at.BalanceId, - BalanceType: at.BalanceType, - BalanceDirection: at.BalanceDirection, - BalanceDestinationTag: at.BalanceDestinationId, - BalanceWeight: at.BalanceWeight, - BalanceExpiryTime: at.BalanceExpirationDate, - BalanceTimingTags: at.BalanceTimingTags, - BalanceRatingSubject: at.BalanceRatingSubject, - BalanceCategory: at.BalanceCategory, - BalanceSharedGroup: at.BalanceSharedGroup, - MinQueuedItems: at.MinQueuedItems, - ActionsTag: at.ActionsId, - Weight: at.Weight, - CreatedAt: time.Now(), + Tpid: tpid, + UniqueId: id, + Tag: atId, + ThresholdType: at.ThresholdType, + ThresholdValue: at.ThresholdValue, + Recurrent: at.Recurrent, + MinSleep: at.MinSleep, + BalanceTag: at.BalanceId, + BalanceType: at.BalanceType, + BalanceDirection: at.BalanceDirection, + BalanceDestinationTags: at.BalanceDestinationIds, + BalanceWeight: at.BalanceWeight, + BalanceExpiryTime: at.BalanceExpirationDate, + BalanceTimingTags: at.BalanceTimingTags, + BalanceRatingSubject: at.BalanceRatingSubject, + BalanceCategory: at.BalanceCategory, + BalanceSharedGroup: at.BalanceSharedGroup, + MinQueuedItems: at.MinQueuedItems, + ActionsTag: at.ActionsId, + Weight: at.Weight, + CreatedAt: time.Now(), }) if saved.Error != nil { tx.Rollback() @@ -1583,7 +1583,7 @@ func (self *SQLStorage) GetTpActions(tpid, tag string) (map[string][]*utils.TPAc Units: tpAc.Units, ExpiryTime: tpAc.ExpiryTime, TimingTags: tpAc.TimingTags, - DestinationId: tpAc.DestinationTag, + DestinationIds: tpAc.DestinationTags, RatingSubject: tpAc.RatingSubject, Category: tpAc.Category, SharedGroup: tpAc.SharedGroup, @@ -1612,7 +1612,7 @@ func (self *SQLStorage) GetTpActionTriggers(tpid, tag string) (map[string][]*uti BalanceId: tpAt.BalanceTag, BalanceType: tpAt.BalanceType, BalanceDirection: tpAt.BalanceDirection, - BalanceDestinationId: tpAt.BalanceDestinationTag, + BalanceDestinationIds: tpAt.BalanceDestinationTags, BalanceWeight: tpAt.BalanceWeight, BalanceExpirationDate: tpAt.BalanceExpiryTime, BalanceTimingTags: tpAt.BalanceTimingTags, diff --git a/engine/storage_test.go b/engine/storage_test.go index 4b3f6591a..977452773 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -206,23 +206,23 @@ func GetUB() *Account { uc := &UnitsCounter{ Direction: OUTBOUND, BalanceType: utils.SMS, - Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}, + Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}, } at := &ActionTrigger{ - Id: "some_uuid", - BalanceType: utils.MONETARY, - BalanceDirection: OUTBOUND, - ThresholdValue: 100.0, - BalanceDestinationId: "NAT", - Weight: 10.0, - ActionsId: "Commando", + Id: "some_uuid", + BalanceType: utils.MONETARY, + BalanceDirection: OUTBOUND, + ThresholdValue: 100.0, + BalanceDestinationIds: "NAT", + Weight: 10.0, + ActionsId: "Commando", } var zeroTime time.Time zeroTime = zeroTime.UTC() // for deep equal to find location ub := &Account{ Id: "rif", AllowNegative: true, - BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}}, + BalanceMap: map[string]BalanceChain{utils.SMS + OUTBOUND: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}}, UnitCounters: []*UnitsCounter{uc, uc}, ActionTriggers: ActionTriggerPriotityList{at, at, at}, } diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 80a6711be..62be9b103 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -389,7 +389,7 @@ func (self *TPCSVImporter) importActions(fn string) error { } continue } - actId, actionType, balanceTag, balanceType, direction, destTag, rateSubject, category, sharedGroup := record[ACTSCSVIDX_TAG], record[ACTSCSVIDX_ACTION], + actId, actionType, balanceTag, balanceType, direction, destTags, rateSubject, category, sharedGroup := record[ACTSCSVIDX_TAG], record[ACTSCSVIDX_ACTION], record[ACTSCSVIDX_BALANCE_TAG], record[ACTSCSVIDX_BALANCE_TYPE], record[ACTSCSVIDX_DIRECTION], record[ACTSCSVIDX_DESTINATION_TAG], record[ACTSCSVIDX_RATING_SUBJECT], record[ACTSCSVIDX_CATEGORY], record[ACTSCSVIDX_SHARED_GROUP] units, err := strconv.ParseFloat(record[ACTSCSVIDX_UNITS], 64) @@ -417,7 +417,7 @@ func (self *TPCSVImporter) importActions(fn string) error { Direction: direction, Units: units, ExpiryTime: record[ACTSCSVIDX_EXPIRY_TIME], - DestinationId: destTag, + DestinationIds: destTags, RatingSubject: rateSubject, Category: category, SharedGroup: sharedGroup, @@ -503,7 +503,7 @@ func (self *TPCSVImporter) importActionTriggers(fn string) error { } continue } - tag, balanceId, balanceType, direction, thresholdType, destinationTag, balanceExpirationDate, balanceRatingSubject, balanceCategory, balanceSharedGroup, actionsTag := record[ATRIGCSVIDX_TAG], record[ATRIGCSVIDX_BAL_TAG], record[ATRIGCSVIDX_BAL_TYPE], + tag, balanceId, balanceType, direction, thresholdType, destinationTags, balanceExpirationDate, balanceRatingSubject, balanceCategory, balanceSharedGroup, actionsTag := record[ATRIGCSVIDX_TAG], record[ATRIGCSVIDX_BAL_TAG], record[ATRIGCSVIDX_BAL_TYPE], record[ATRIGCSVIDX_BAL_DIRECTION], record[ATRIGCSVIDX_THRESHOLD_TYPE], record[ATRIGCSVIDX_BAL_DESTINATION_TAG], record[ATRIGCSVIDX_BAL_EXPIRY_TIME], record[ATRIGCSVIDX_BAL_RATING_SUBJECT], record[ATRIGCSVIDX_BAL_CATEGORY], record[ATRIGCSVIDX_BAL_SHARED_GROUP], record[ATRIGCSVIDX_ACTIONS_TAG] threshold, err := strconv.ParseFloat(record[ATRIGCSVIDX_THRESHOLD_VALUE], 64) @@ -548,7 +548,7 @@ func (self *TPCSVImporter) importActionTriggers(fn string) error { BalanceId: balanceId, BalanceType: balanceType, BalanceDirection: direction, - BalanceDestinationId: destinationTag, + BalanceDestinationIds: destinationTags, BalanceWeight: balanceWeight, BalanceExpirationDate: balanceExpirationDate, BalanceRatingSubject: balanceRatingSubject, diff --git a/engine/units_counter.go b/engine/units_counter.go index f4eb8a7bd..8b44ed88d 100644 --- a/engine/units_counter.go +++ b/engine/units_counter.go @@ -79,7 +79,7 @@ func (uc *UnitsCounter) addUnits(amount float64, prefix string) { for _, p := range utils.SplitPrefix(prefix, MIN_PREFIX_MATCH) { if x, err := cache2go.GetCached(DESTINATION_PREFIX + p); err == nil { destIds := x.(map[interface{}]struct{}) - if _, found := destIds[mb.DestinationId]; found { + if _, found := destIds[mb.DestinationIds]; found { mb.Value += amount counted = true break diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go index 3a753ba5e..74a3dd698 100644 --- a/engine/units_counter_test.go +++ b/engine/units_counter_test.go @@ -28,7 +28,7 @@ func TestUnitsCounterAddBalance(t *testing.T) { uc := &UnitsCounter{ Direction: OUTBOUND, BalanceType: utils.SMS, - Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}, + Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}, } uc.addUnits(20, "test") if len(uc.Balances) != 3 { @@ -40,7 +40,7 @@ func TestUnitsCounterAddBalanceExists(t *testing.T) { uc := &UnitsCounter{ Direction: OUTBOUND, BalanceType: utils.SMS, - Balances: BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}, + Balances: BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationIds: "NAT"}, &Balance{Weight: 10, DestinationIds: "RET"}}, } uc.addUnits(5, "0723") if len(uc.Balances) != 3 || uc.Balances[1].Value != 15 { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 9a91a7a8e..e9e57f283 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -311,7 +311,7 @@ type TPActions struct { func (self *TPActions) AsExportSlice() [][]string { retSlice := make([][]string, len(self.Actions)) for idx, act := range self.Actions { - retSlice[idx] = []string{self.ActionsId, act.Identifier, act.ExtraParameters, act.BalanceType, act.Direction, act.Category, act.DestinationId, act.RatingSubject, + retSlice[idx] = []string{self.ActionsId, act.Identifier, act.ExtraParameters, act.BalanceType, act.Direction, act.Category, act.DestinationIds, act.RatingSubject, act.SharedGroup, act.ExpiryTime, strconv.FormatFloat(act.Units, 'f', -1, 64), strconv.FormatFloat(act.BalanceWeight, 'f', -1, 64), strconv.FormatFloat(act.Weight, 'f', -1, 64)} } return retSlice @@ -325,7 +325,7 @@ type TPAction struct { Units float64 // Number of units to add/deduct ExpiryTime string // Time when the units will expire TimingTags string // Timing when balance is active - DestinationId string // Destination profile id + DestinationIds string // Destination profile id RatingSubject string // Reference a rate subject defined in RatingProfiles Category string // category filter for balances SharedGroup string // Reference to a shared group @@ -534,7 +534,7 @@ func (self *TPActionTriggers) AsExportSlice() [][]string { retSlice := make([][]string, len(self.ActionTriggers)) for idx, at := range self.ActionTriggers { retSlice[idx] = []string{self.ActionTriggersId, at.ThresholdType, strconv.FormatFloat(at.ThresholdValue, 'f', -1, 64), strconv.FormatBool(at.Recurrent), at.MinSleep, - at.BalanceId, at.BalanceType, at.BalanceDirection, at.BalanceCategory, at.BalanceDestinationId, at.BalanceRatingSubject, at.BalanceSharedGroup, at.BalanceExpirationDate, at.BalanceTimingTags, + at.BalanceId, at.BalanceType, at.BalanceDirection, at.BalanceCategory, at.BalanceDestinationIds, at.BalanceRatingSubject, at.BalanceSharedGroup, at.BalanceExpirationDate, at.BalanceTimingTags, strconv.FormatFloat(at.BalanceWeight, 'f', -1, 64), strconv.Itoa(at.MinQueuedItems), at.ActionsId, strconv.FormatFloat(at.Weight, 'f', -1, 64)} } return retSlice @@ -549,7 +549,7 @@ type TPActionTrigger struct { BalanceId string // The id of the balance in the account BalanceType string // Type of balance this trigger monitors BalanceDirection string // Traffic direction - BalanceDestinationId string // filter for balance + BalanceDestinationIds string // filter for balance BalanceWeight float64 // filter for balance BalanceExpirationDate string // filter for balance BalanceTimingTags string // filter for balance diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go index 66681de33..3db3e3813 100644 --- a/utils/apitpdata_test.go +++ b/utils/apitpdata_test.go @@ -173,7 +173,7 @@ func TestTPActionsAsExportSlice(t *testing.T) { Direction: OUT, Units: 5.0, ExpiryTime: "*never", - DestinationId: "*any", + DestinationIds: "*any", RatingSubject: "special1", Category: "call", SharedGroup: "GROUP1", @@ -186,7 +186,7 @@ func TestTPActionsAsExportSlice(t *testing.T) { Direction: "", Units: 0.0, ExpiryTime: "", - DestinationId: "", + DestinationIds: "", RatingSubject: "", Category: "", SharedGroup: "", @@ -426,7 +426,7 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceId: "b1", BalanceType: "*monetary", BalanceDirection: "*out", - BalanceDestinationId: "", + BalanceDestinationIds: "", BalanceWeight: 0.0, BalanceExpirationDate: "*never", BalanceTimingTags: "T1", @@ -444,7 +444,7 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceId: "b2", BalanceType: "*monetary", BalanceDirection: "*out", - BalanceDestinationId: "FS_USERS", + BalanceDestinationIds: "FS_USERS", BalanceWeight: 0.0, BalanceExpirationDate: "*never", BalanceTimingTags: "T1",