From 0bb8691101b9017549cb7a58c931025fba89d0fa Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 22 Dec 2014 23:00:23 +0200 Subject: [PATCH] balance activation times --- .../mysql/create_tariffplan_tables.sql | 10 +- .../postgres/create_tariffplan_tables.sql | 8 +- data/tariffplans/cdrstats/ActionTriggers.csv | 12 +- data/tariffplans/cdrstats/Actions.csv | 4 +- .../prepaid1centpsec/ActionTriggers.csv | 18 +-- data/tariffplans/prepaid1centpsec/Actions.csv | 12 +- data/tariffplans/tutorial/ActionTriggers.csv | 24 ++-- data/tariffplans/tutorial/Actions.csv | 18 +-- engine/action_trigger.go | 1 + engine/balances.go | 30 ++++- engine/balances_test.go | 32 ++++++ engine/loader_csv.go | 24 +++- engine/loader_csv_test.go | 40 +++---- engine/loader_db.go | 20 ++++ engine/loader_helpers.go | 16 ++- engine/models.go | 2 + engine/rateinterval.go | 106 ++++++++++-------- engine/rateinterval_test.go | 8 ++ engine/storage_sql.go | 5 + general_tests/acntacts_test.go | 6 +- general_tests/ddazmbl1_test.go | 4 +- general_tests/ddazmbl2_test.go | 4 +- general_tests/ddazmbl3_test.go | 2 +- utils/apitpdata.go | 5 +- utils/apitpdata_test.go | 6 +- utils/consts.go | 4 +- 26 files changed, 281 insertions(+), 140 deletions(-) diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index d6ba599fb..c91a37687 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -10,7 +10,7 @@ CREATE TABLE `tp_timings` ( `months` varchar(255) NOT NULL, `month_days` varchar(255) NOT NULL, `week_days` varchar(255) NOT NULL, - `time` varchar(16) NOT NULL, + `time` varchar(32) NOT NULL, `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`), @@ -150,7 +150,8 @@ CREATE TABLE `tp_actions` ( `direction` varchar(8) NOT NULL, `units` DECIMAL(20,4) NOT NULL, `expiry_time` varchar(24) NOT NULL, - `destination_tag` varchar(64) NOT NULL, + `timing_tags` varchar(128) NOT NULL, + `balance_destination_tag` varchar(64) NOT NULL, `rating_subject` varchar(64) NOT NULL, `category` varchar(16) NOT NULL, `shared_group` varchar(64) NOT NULL, @@ -160,7 +161,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`,`destination_tag`,`shared_group`,`balance_weight`,`weight`) + UNIQUE KEY `unique_action` (`tpid`,`tag`,`action`,`balance_tag`,`balance_type`,`direction`,`expiry_time`,`timing_tags`,`destination_tag`,`shared_group`,`balance_weight`,`weight`) ); -- @@ -199,7 +200,8 @@ CREATE TABLE `tp_action_triggers` ( `min_sleep` BIGINT NOT NULL, `balance_destination_tag` varchar(64) NOT NULL, `balance_weight` DECIMAL(8,2) NOT NULL, - `balance_expiry_time` varchar(24) NOT NULL, + `balance_expiry_time` varchar(24) NOT NULL, + `balance_timing_tags` varchar(128) NOT NULL, `balance_rating_subject` varchar(64) NOT NULL, `balance_category` varchar(16) NOT NULL, `balance_shared_group` varchar(64) NOT NULL, diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 807cfade9..1e94c280c 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -10,7 +10,7 @@ CREATE TABLE tp_timings ( months VARCHAR(255) NOT NULL, month_days VARCHAR(255) NOT NULL, week_days VARCHAR(255) NOT NULL, - time VARCHAR(16) NOT NULL, + time VARCHAR(32) NOT NULL, created_at TIMESTAMP, UNIQUE (tpid, tag) ); @@ -131,6 +131,7 @@ CREATE TABLE tp_actions ( direction VARCHAR(8) NOT NULL, units NUMERIC(20,4) NOT NULL, expiry_time VARCHAR(24) NOT NULL, + timing_tags VARCHAR(128) NOT NULL, destination_tag VARCHAR(64) NOT NULL, rating_subject VARCHAR(64) NOT NULL, category VARCHAR(16) NOT NULL, @@ -139,7 +140,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, destination_tag, shared_group, balance_weight, weight) + UNIQUE (tpid, tag, action, balance_tag, balance_type, direction, expiry_time, timing_tags, destination_tag, shared_group, balance_weight, weight) ); -- @@ -176,7 +177,8 @@ CREATE TABLE tp_action_triggers ( min_sleep BIGINT NOT NULL, balance_destination_tag VARCHAR(64) NOT NULL, balance_weight NUMERIC(8,2) NOT NULL, - balance_expiry_time VARCHAR(24) NOT NULL, + balance_expiry_time VARCHAR(24) NOT NULL, + balance_timing_tags VARCHAR(128) NOT NULL, balance_rating_subject VARCHAR(64) NOT NULL, balance_category VARCHAR(16) NOT NULL, balance_shared_group VARCHAR(64) NOT NULL, diff --git a/data/tariffplans/cdrstats/ActionTriggers.csv b/data/tariffplans/cdrstats/ActionTriggers.csv index 7306e3988..346069763 100644 --- a/data/tariffplans/cdrstats/ActionTriggers.csv +++ b/data/tariffplans/cdrstats/ActionTriggers.csv @@ -1,6 +1,6 @@ -#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceWeight[13],StatsMinQueuedItems[14],ActionsTag[15],Weight[16] -CDRST3_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,3,CDRST_LOG,10 -CDRST3_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,5,CDRST_LOG,10 -CDRST3_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,5,CDRST_LOG,10 -CDRST4_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,5,CDRST_LOG,10 -CDRST4_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,2,CDRST_LOG,10 +#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceTimingTags[13],BalanceWeight[14],StatsMinQueuedItems[15],ActionsTag[16],Weight[17] +CDRST3_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,,3,CDRST_LOG,10 +CDRST3_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,,5,CDRST_LOG,10 +CDRST3_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,,5,CDRST_LOG,10 +CDRST4_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,,5,CDRST_LOG,10 +CDRST4_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,,2,CDRST_LOG,10 diff --git a/data/tariffplans/cdrstats/Actions.csv b/data/tariffplans/cdrstats/Actions.csv index de648b802..899e4928e 100644 --- a/data/tariffplans/cdrstats/Actions.csv +++ b/data/tariffplans/cdrstats/Actions.csv @@ -1,2 +1,2 @@ -#ActionsTag,Action,BalanceTag,BalanceType,Direction,Units,ExpiryTime,DestinationTag,RatingSubject,Category,BalanceWeight,SharedGroup,ExtraParameters,Weight -CDRST_LOG,*log,,,,,,,,,,,,10 +#ActionsTag,Action,BalanceTag,BalanceType,Direction,Units,ExpiryTime,TimingTags,DestinationTag,RatingSubject,Category,BalanceWeight,SharedGroup,ExtraParameters,Weight +CDRST_LOG,*log,,,,,,,,,,,,,10 diff --git a/data/tariffplans/prepaid1centpsec/ActionTriggers.csv b/data/tariffplans/prepaid1centpsec/ActionTriggers.csv index 6c332cd78..32388fa79 100644 --- a/data/tariffplans/prepaid1centpsec/ActionTriggers.csv +++ b/data/tariffplans/prepaid1centpsec/ActionTriggers.csv @@ -1,9 +1,9 @@ -#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceWeight[13],StatsMinQueuedItems[14],ActionsTag[15],Weight[16] -STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,LOG_BALANCE,10 -STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,LOG_BALANCE,10 -STANDARD_TRIGGERS,*max_counter,15,false,0,,*monetary,*out,,FS_USERS,,,,,,LOG_BALANCE,10 -CDRST1_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,3,CDRST_WARN_HTTP,10 -CDRST1_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST1_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST2_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST2_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,2,CDRST_LOG,10 +#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceTimingTags[13],BalanceWeight[14],StatsMinQueuedItems[15],ActionsTag[16],Weight[17] +STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,,LOG_BALANCE,10 +STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,,LOG_BALANCE,10 +STANDARD_TRIGGERS,*max_counter,15,false,0,,*monetary,*out,,FS_USERS,,,,,,,LOG_BALANCE,10 +CDRST1_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,,3,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,,2,CDRST_LOG,10 diff --git a/data/tariffplans/prepaid1centpsec/Actions.csv b/data/tariffplans/prepaid1centpsec/Actions.csv index 80aa38c2d..181f39c86 100644 --- a/data/tariffplans/prepaid1centpsec/Actions.csv +++ b/data/tariffplans/prepaid1centpsec/Actions.csv @@ -1,6 +1,6 @@ -#ActionsTag[0],Action[1],ActionExtraParameters[2],BalanceTag[3],BalanceType[4],Direction[5],Category[6],DestinationTag[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],Units[11],BalanceWeight[12],Weight[13] -PREPAID_10,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,10,10,10 -BONUS_1,*topup,,,*monetary,*out,,*any,,,*unlimited,1,10,10 -LOG_BALANCE,*log,,,,,,,,,,,,10 -CDRST_WARN_HTTP,*call_url,http://localhost:8080,,,,,,,,,,,10 -CDRST_LOG,*log,,,,,,,,,,,,10 +#ActionsTag[0],Action[1],ActionExtraParameters[2],BalanceTag[3],BalanceType[4],Direction[5],Category[6],DestinationTag[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],TimingTags[11],Units[12],BalanceWeight[13],Weight[14] +PREPAID_10,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,10,10,10 +BONUS_1,*topup,,,*monetary,*out,,*any,,,*unlimited,,1,10,10 +LOG_BALANCE,*log,,,,,,,,,,,,,10 +CDRST_WARN_HTTP,*call_url,http://localhost:8080,,,,,,,,,,,,10 +CDRST_LOG,*log,,,,,,,,,,,,,10 diff --git a/data/tariffplans/tutorial/ActionTriggers.csv b/data/tariffplans/tutorial/ActionTriggers.csv index 0c80f4402..4fee052ab 100644 --- a/data/tariffplans/tutorial/ActionTriggers.csv +++ b/data/tariffplans/tutorial/ActionTriggers.csv @@ -1,12 +1,12 @@ -#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceWeight[13],StatsMinQueuedItems[14],ActionsTag[15],Weight[16] -STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,*max_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,*max_balance,100,false,0,,*monetary,*out,,,,,,,,DISABLE_AND_LOG,10 -CDRST1_WARN,*min_asr,45,true,1m,,,,,,,,,,3,LOG_WARNING,10 -CDRST1_WARN,*min_acd,10,true,1m,,,,,,,,,,5,LOG_WARNING,10 -CDRST1_WARN,*max_acc,10,true,1m,,,,,,,,,,5,LOG_WARNING,10 -CDRST1001_WARN,*min_asr,65,true,1m,,,,,,,,,,3,LOG_WARNING,10 -CDRST1001_WARN,*min_acd,10,true,1m,,,,,,,,,,5,LOG_WARNING,10 -CDRST1001_WARN,*max_acc,5,true,1m,,,,,,,,,,5,LOG_WARNING,10 -CDRST3_WARN,*min_acd,60,false,1m,,,,,,,,,,5,LOG_WARNING,10 +#Tag[0],ThresholdType[1],ThresholdValue[2],Recurrent[3],MinSleep[4],BalanceTag[5],BalanceType[6],BalanceDirection[7],BalanceCategory[8],BalanceDestinationTag[9],BalanceRatingSubject[10],BalanceSharedGroup[11],BalanceExpiryTime[12],BalanceTimingTags[13],BalanceWeight[14],StatsMinQueuedItems[15],ActionsTag[16],Weight[17] +STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,*max_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,*max_balance,100,false,0,,*monetary,*out,,,,,,,,,DISABLE_AND_LOG,10 +CDRST1_WARN,*min_asr,45,true,1m,,,,,,,,,,,3,LOG_WARNING,10 +CDRST1_WARN,*min_acd,10,true,1m,,,,,,,,,,,5,LOG_WARNING,10 +CDRST1_WARN,*max_acc,10,true,1m,,,,,,,,,,,5,LOG_WARNING,10 +CDRST1001_WARN,*min_asr,65,true,1m,,,,,,,,,,,3,LOG_WARNING,10 +CDRST1001_WARN,*min_acd,10,true,1m,,,,,,,,,,,5,LOG_WARNING,10 +CDRST1001_WARN,*max_acc,5,true,1m,,,,,,,,,,,5,LOG_WARNING,10 +CDRST3_WARN,*min_acd,60,false,1m,,,,,,,,,,,5,LOG_WARNING,10 diff --git a/data/tariffplans/tutorial/Actions.csv b/data/tariffplans/tutorial/Actions.csv index 5b210817d..1ffc58ad6 100644 --- a/data/tariffplans/tutorial/Actions.csv +++ b/data/tariffplans/tutorial/Actions.csv @@ -1,9 +1,9 @@ -#ActionsTag[0],Action[1],ExtraParameters[2],BalanceTag[3],BalanceType[4],Direction[5],Category[6],DestinationTag[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],Units[11],BalanceWeight[12],Weight[13] -TOPUP_RST_10,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,10,10,10 -TOPUP_RST_5,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,5,20,10 -TOPUP_RST_5,*topup_reset,,,*voice,*out,,DST_1002,SPECIAL_1002,,*unlimited,90,20,10 -TOPUP_RST_SHARED_5,*topup,,,*monetary,*out,,*any,,SHARED_A,*unlimited,5,10,10 -SHARED_A_0,*topup_reset,,,*monetary,*out,,*any,,SHARED_A,*unlimited,0,10,10 -LOG_WARNING,*log,,,,,,,,,,,,10 -DISABLE_AND_LOG,*log,,,,,,,,,,,,10 -DISABLE_AND_LOG,*disable_account,,,,,,,,,,,,10 +#ActionsTag[0],Action[1],ExtraParameters[2],BalanceTag[3],BalanceType[4],Direction[5],Category[6],DestinationTag[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],TimingTags[11],Units[12],BalanceWeight[13],Weight[14] +TOPUP_RST_10,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,10,10,10 +TOPUP_RST_5,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,5,20,10 +TOPUP_RST_5,*topup_reset,,,*voice,*out,,DST_1002,SPECIAL_1002,,*unlimited,,90,20,10 +TOPUP_RST_SHARED_5,*topup,,,*monetary,*out,,*any,,SHARED_A,*unlimited,,5,10,10 +SHARED_A_0,*topup_reset,,,*monetary,*out,,*any,,SHARED_A,*unlimited,,0,10,10 +LOG_WARNING,*log,,,,,,,,,,,,,10 +DISABLE_AND_LOG,*log,,,,,,,,,,,,,10 +DISABLE_AND_LOG,*disable_account,,,,,,,,,,,,,10 diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 059558593..8b2b67729 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -40,6 +40,7 @@ type ActionTrigger struct { BalanceDestinationId string // filter for balance BalanceWeight float64 // filter for balance BalanceExpirationDate time.Time // filter for balance + BalanceTimingTags string // filter for balance BalanceRatingSubject string // filter for balance BalanceCategory string // filter for balance BalanceSharedGroup string // filter for balance diff --git a/engine/balances.go b/engine/balances.go index e56dee59d..aabb73e2a 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -37,6 +37,8 @@ type Balance struct { RatingSubject string Category string SharedGroup string + Timings []*RITiming + TimingIDs string precision int account *Account // used to store ub reference for shared balances dirty bool @@ -89,6 +91,22 @@ func (b *Balance) IsExpired() bool { return !b.ExpirationDate.IsZero() && b.ExpirationDate.Before(time.Now()) } +func (b *Balance) IsActive() bool { + return b.IsActiveAt(time.Now()) +} + +func (b *Balance) IsActiveAt(t time.Time) bool { + if len(b.Timings) == 0 { + return true + } + for _, tim := range b.Timings { + if tim.IsActiveAt(t, false) { + return true + } + } + return false +} + func (b *Balance) MatchCategory(category string) bool { return b.Category == "" || b.Category == category } @@ -223,10 +241,15 @@ func (b *Balance) DebitUnits(cc *CallCost, count bool, ub *Account, moneyBalance continue } tsWasSplit := false + currentTime := ts.TimeStart for incrementIndex, increment := range ts.Increments { if tsWasSplit { break } + currentTime = currentTime.Add(increment.Duration) + if !b.IsActiveAt(currentTime) { + continue + } if increment.paid { continue } @@ -369,10 +392,15 @@ func (b *Balance) DebitMoney(cc *CallCost, count bool, ub *Account) error { continue } tsWasSplit := false + currentTime := ts.TimeStart for incrementIndex, increment := range ts.Increments { if tsWasSplit { break } + currentTime = currentTime.Add(increment.Duration) + if !b.IsActiveAt(currentTime) { + continue + } if increment.paid { continue } @@ -472,7 +500,7 @@ func (bc BalanceChain) Sort() { func (bc BalanceChain) GetTotalValue() (total float64) { for _, b := range bc { - if !b.IsExpired() { + if !b.IsExpired() && b.IsActive() { total += b.Value } } diff --git a/engine/balances_test.go b/engine/balances_test.go index de41086ff..57cb7b020 100644 --- a/engine/balances_test.go +++ b/engine/balances_test.go @@ -87,6 +87,38 @@ func TestBalanceEqual(t *testing.T) { } } +func TestBalanceMatchFilter(t *testing.T) { + mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} + mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "", DestinationId: ""} + if !mb1.MatchFilter(mb2) { + t.Error("Match filter failure: %+v == %+v", mb1, mb2) + } +} + +func TestBalanceMatchFilterEmpty(t *testing.T) { + mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationId: ""} + mb2 := &Balance{} + if !mb1.MatchFilter(mb2) { + t.Error("Match filter failure: %+v == %+v", mb1, mb2) + } +} + +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: ""} + if !mb1.MatchFilter(mb2) { + t.Error("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: ""} + if mb1.MatchFilter(mb2) { + t.Error("Match filter failure: %+v != %+v", mb1, mb2) + } +} + func TestBalanceClone(t *testing.T) { mb1 := &Balance{Value: 1, Weight: 2, RatingSubject: "test", DestinationId: "5"} mb2 := mb1.Clone() diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 555af9f2a..54313a002 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -522,7 +522,7 @@ func (csvr *CSVReader) LoadRatingProfiles() (err error) { return fmt.Errorf("Cannot parse activation time from %v", record[4]) } // extract aliases from subject - aliases := strings.Split(subject, ";") + aliases := strings.Split(subject, utils.INFIELD_SEP) csvr.dirtyRpAliases = append(csvr.dirtyRpAliases, &TenantRatingSubject{Tenant: tenant, Subject: aliases[0]}) if len(aliases) > 1 { subject = aliases[0] @@ -692,11 +692,30 @@ func (csvr *CSVReader) LoadActions() (err error) { 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], }, } + // load action timings from tags + if a.Balance.TimingIDs != "" { + timingIds := strings.Split(a.Balance.TimingIDs, utils.INFIELD_SEP) + for _, timingID := range timingIds { + if timing, found := csvr.timings[timingID]; found { + a.Balance.Timings = append(a.Balance.Timings, &RITiming{ + Years: timing.Years, + Months: timing.Months, + MonthDays: timing.MonthDays, + WeekDays: timing.WeekDays, + StartTime: timing.StartTime, + EndTime: timing.EndTime, + }) + } else { + return fmt.Errorf("Could not find timing: %v", timingID) + } + } + } if _, err := utils.ParseDate(a.ExpirationString); err != nil { return fmt.Errorf("Could not parse expiration time: %v", err) } @@ -807,6 +826,7 @@ func (csvr *CSVReader) LoadActionTriggers() (err error) { BalanceDestinationId: record[ATRIGCSVIDX_BAL_DESTINATION_TAG], BalanceWeight: balanceWeight, BalanceExpirationDate: balanceExp, + BalanceTimingTags: record[ATRIGCSVIDX_BAL_TIMING_TAGS], BalanceRatingSubject: record[ATRIGCSVIDX_BAL_RATING_SUBJECT], BalanceCategory: record[ATRIGCSVIDX_BAL_CATEGORY], BalanceSharedGroup: record[ATRIGCSVIDX_BAL_SHARED_GROUP], @@ -832,7 +852,7 @@ func (csvr *CSVReader) LoadAccountActions() (err error) { for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tenant, account, direction := record[0], record[1], record[2] // extract aliases from subject - aliases := strings.Split(account, ";") + aliases := strings.Split(account, utils.INFIELD_SEP) csvr.dirtyAccAliases = append(csvr.dirtyAccAliases, &TenantAccount{Tenant: tenant, Account: aliases[0]}) if len(aliases) > 1 { account = aliases[0] diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 5d4ad982e..e7b781daa 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -140,16 +140,16 @@ SG3,*any,*lowest, ` actions = ` -MINI,*topup_reset,,,*monetary,*out,,,,,*unlimited,10,10,10 -MINI,*topup,,,*voice,*out,,NAT,test,,*unlimited,100,10,10 -SHARED,*topup,,,*monetary,*out,,,,SG1,*unlimited,100,10,10 -TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,1,10,10 -TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,40,10,10 -SE0,*topup_reset,,,*monetary,*out,,,,SG2,*unlimited,0,10,10 -SE10,*topup_reset,,,*monetary,*out,,,,SG2,*unlimited,10,5,10 -SE10,*topup,,,*monetary,*out,,,,,*unlimited,10,10,10 -EE0,*topup_reset,,,*monetary,*out,,,,SG3,*unlimited,0,10,10 -EE0,*allow_negative,,,*monetary,*out,,,,,*unlimited,0,10,10 +MINI,*topup_reset,,,*monetary,*out,,,,,*unlimited,,10,10,10 +MINI,*topup,,,*voice,*out,,NAT,test,,*unlimited,,100,10,10 +SHARED,*topup,,,*monetary,*out,,,,SG1,*unlimited,,100,10,10 +TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,1,10,10 +TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,10 +SE0,*topup_reset,,,*monetary,*out,,,,SG2,*unlimited,,0,10,10 +SE10,*topup_reset,,,*monetary,*out,,,,SG2,*unlimited,,10,5,10 +SE10,*topup,,,*monetary,*out,,,,,*unlimited,,10,10,10 +EE0,*topup_reset,,,*monetary,*out,,,,SG3,*unlimited,,0,10,10 +EE0,*allow_negative,,,*monetary,*out,,,,,*unlimited,,0,10,10 ` actionTimings = ` MORE_MINUTES,MINI,ONE_TIME_RUN,10 @@ -162,16 +162,16 @@ TOPUP_EMPTY_AT,EE0,ASAP,10 ` actionTriggers = ` -STANDARD_TRIGGER,*min_counter,10,false,0,,*voice,*out,,GERMANY_O2,,,,,,SOME_1,10 -STANDARD_TRIGGER,*max_balance,200,false,0,,*voice,*out,,GERMANY,,,,,,SOME_2,10 -STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,LOG_WARNING,10 -STANDARD_TRIGGERS,*max_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,LOG_WARNING,10 -CDRST1_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,3,CDRST_WARN_HTTP,10 -CDRST1_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST1_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST2_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,5,CDRST_WARN_HTTP,10 -CDRST2_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,5,CDRST_WARN_HTTP,10 +STANDARD_TRIGGER,*min_counter,10,false,0,,*voice,*out,,GERMANY_O2,,,,,,,SOME_1,10 +STANDARD_TRIGGER,*max_balance,200,false,0,,*voice,*out,,GERMANY,,,,,,,SOME_2,10 +STANDARD_TRIGGERS,*min_balance,2,false,0,,*monetary,*out,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,*max_balance,20,false,0,,*monetary,*out,,,,,,,,,LOG_WARNING,10 +STANDARD_TRIGGERS,*max_counter,5,false,0,,*monetary,*out,,FS_USERS,,,,,,,LOG_WARNING,10 +CDRST1_WARN_ASR,*min_asr,45,true,1h,,,,,,,,,,,3,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACD,*min_acd,10,true,1h,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACC,*max_acc,10,true,10m,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ASR,*min_asr,30,true,0,,,,,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ACD,*min_acd,3,true,0,,,,,,,,,,,5,CDRST_WARN_HTTP,10 ` accountActions = ` vdf,minitsboy;a1;a2,*out,MORE_MINUTES,STANDARD_TRIGGER diff --git a/engine/loader_db.go b/engine/loader_db.go index d17c1c32b..8b12209eb 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -573,11 +573,30 @@ func (dbr *DbReader) LoadActions() (err error) { Id: tpact.BalanceTag, Value: tpact.Units, Weight: tpact.BalanceWeight, + TimingIDs: tpact.TimingTags, RatingSubject: tpact.RatingSubject, Category: tpact.Category, DestinationId: tpact.DestinationId, }, } + // load action timings from tags + if acts[idx].Balance.TimingIDs != "" { + timingIds := strings.Split(acts[idx].Balance.TimingIDs, utils.INFIELD_SEP) + for _, timingID := range timingIds { + if timing, found := dbr.timings[timingID]; found { + acts[idx].Balance.Timings = append(acts[idx].Balance.Timings, &RITiming{ + Years: timing.Years, + Months: timing.Months, + MonthDays: timing.MonthDays, + WeekDays: timing.WeekDays, + StartTime: timing.StartTime, + EndTime: timing.EndTime, + }) + } else { + return fmt.Errorf("Could not find timing: %v", timingID) + } + } + } } dbr.actions[tag] = acts } @@ -642,6 +661,7 @@ func (dbr *DbReader) LoadActionTriggers() (err error) { BalanceDestinationId: apiAtr.BalanceDestinationId, BalanceWeight: apiAtr.BalanceWeight, BalanceExpirationDate: balance_expiration_date, + BalanceTimingTags: apiAtr.BalanceTimingTags, BalanceRatingSubject: apiAtr.BalanceRatingSubject, BalanceCategory: apiAtr.BalanceCategory, BalanceSharedGroup: apiAtr.BalanceSharedGroup, diff --git a/engine/loader_helpers.go b/engine/loader_helpers.go index ec98b9c89..4e82edd7d 100644 --- a/engine/loader_helpers.go +++ b/engine/loader_helpers.go @@ -47,6 +47,7 @@ const ( ACTSCSVIDX_RATING_SUBJECT ACTSCSVIDX_SHARED_GROUP ACTSCSVIDX_EXPIRY_TIME + ACTSCSVIDX_TIMING_TAGS ACTSCSVIDX_UNITS ACTSCSVIDX_BALANCE_WEIGHT ACTSCSVIDX_WEIGHT @@ -67,6 +68,7 @@ const ( ATRIGCSVIDX_BAL_RATING_SUBJECT ATRIGCSVIDX_BAL_SHARED_GROUP ATRIGCSVIDX_BAL_EXPIRY_TIME + ATRIGCSVIDX_BAL_TIMING_TAGS ATRIGCSVIDX_BAL_WEIGHT ATRIGCSVIDX_STATS_MIN_QUEUED_ITEMS ATRIGCSVIDX_ACTIONS_TAG @@ -127,11 +129,15 @@ func ValidNextGroup(present, next *utils.RateSlot) error { func NewTiming(timingInfo ...string) (rt *utils.TPTiming) { rt = &utils.TPTiming{} rt.Id = timingInfo[0] - rt.Years.Parse(timingInfo[1], ";") - rt.Months.Parse(timingInfo[2], ";") - rt.MonthDays.Parse(timingInfo[3], ";") - rt.WeekDays.Parse(timingInfo[4], ";") - rt.StartTime = timingInfo[5] + rt.Years.Parse(timingInfo[1], utils.INFIELD_SEP) + rt.Months.Parse(timingInfo[2], utils.INFIELD_SEP) + rt.MonthDays.Parse(timingInfo[3], utils.INFIELD_SEP) + rt.WeekDays.Parse(timingInfo[4], utils.INFIELD_SEP) + times := strings.Split(timingInfo[5], utils.INFIELD_SEP) + rt.StartTime = times[0] + if len(times) > 1 { + rt.EndTime = times[1] + } return } diff --git a/engine/models.go b/engine/models.go index 538058790..6a3b4f38a 100644 --- a/engine/models.go +++ b/engine/models.go @@ -134,6 +134,7 @@ type TpAction struct { Direction string Units float64 ExpiryTime string + TimingTags string DestinationTag string RatingSubject string Category string @@ -168,6 +169,7 @@ type TpActionTrigger struct { BalanceDestinationTag string BalanceWeight float64 BalanceExpiryTime string + BalanceTimingTags string BalanceRatingSubject string BalanceCategory string BalanceSharedGroup string diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 6e9aac077..d04def8b6 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -115,6 +115,63 @@ func (rit *RITiming) CronString() string { return rit.cronString } +// Returns wheter the Timing is active at the specified time +func (rit *RITiming) IsActiveAt(t time.Time, endTime bool) bool { + // if the received time represents an endtime consider it 24 instead of 0 + hour := t.Hour() + if endTime && hour == 0 { + hour = 24 + } + // check for years + if len(rit.Years) > 0 && !rit.Years.Contains(t.Year()) { + return false + } + // check for months + if len(rit.Months) > 0 && !rit.Months.Contains(t.Month()) { + return false + } + // check for month days + if len(rit.MonthDays) > 0 && !rit.MonthDays.Contains(t.Day()) { + return false + } + // check for weekdays + if len(rit.WeekDays) > 0 && !rit.WeekDays.Contains(t.Weekday()) { + return false + } + // check for start hour + if rit.StartTime != "" { + split := strings.Split(rit.StartTime, ":") + sh, _ := strconv.Atoi(split[0]) + sm, _ := strconv.Atoi(split[1]) + ss, _ := strconv.Atoi(split[2]) + // if the hour result before or result the same hour but the minute result before + if hour < sh || + (hour == sh && t.Minute() < sm) || + (hour == sh && t.Minute() == sm && t.Second() < ss) { + return false + } + } + // check for end hour + if rit.EndTime != "" { + split := strings.Split(rit.EndTime, ":") + eh, _ := strconv.Atoi(split[0]) + em, _ := strconv.Atoi(split[1]) + es, _ := strconv.Atoi(split[2]) + // if the hour result after or result the same hour but the minute result after + if hour > eh || + (hour == eh && t.Minute() > em) || + (hour == eh && t.Minute() == em && t.Second() > es) { + return false + } + } + return true +} + +// Returns wheter the Timing is active now +func (rit *RITiming) IsActive() bool { + return rit.IsActiveAt(time.Now(), false) +} + func (rit *RITiming) Stringify() string { return utils.Sha1(fmt.Sprintf("%v", rit))[:8] } @@ -202,54 +259,7 @@ func (pg *RateGroups) AddRate(ps ...*Rate) { Returns true if the received time result inside the interval */ func (i *RateInterval) Contains(t time.Time, endTime bool) bool { - // if the received time represents an endtime cosnidere it 24 instead of 0 - hour := t.Hour() - if endTime && hour == 0 { - hour = 24 - } - // check for years - if len(i.Timing.Years) > 0 && !i.Timing.Years.Contains(t.Year()) { - return false - } - // check for months - if len(i.Timing.Months) > 0 && !i.Timing.Months.Contains(t.Month()) { - return false - } - // check for month days - if len(i.Timing.MonthDays) > 0 && !i.Timing.MonthDays.Contains(t.Day()) { - return false - } - // check for weekdays - if len(i.Timing.WeekDays) > 0 && !i.Timing.WeekDays.Contains(t.Weekday()) { - return false - } - // check for start hour - if i.Timing.StartTime != "" { - split := strings.Split(i.Timing.StartTime, ":") - sh, _ := strconv.Atoi(split[0]) - sm, _ := strconv.Atoi(split[1]) - ss, _ := strconv.Atoi(split[2]) - // if the hour result before or result the same hour but the minute result before - if hour < sh || - (hour == sh && t.Minute() < sm) || - (hour == sh && t.Minute() == sm && t.Second() < ss) { - return false - } - } - // check for end hour - if i.Timing.EndTime != "" { - split := strings.Split(i.Timing.EndTime, ":") - eh, _ := strconv.Atoi(split[0]) - em, _ := strconv.Atoi(split[1]) - es, _ := strconv.Atoi(split[2]) - // if the hour result after or result the same hour but the minute result after - if hour > eh || - (hour == eh && t.Minute() > em) || - (hour == eh && t.Minute() == em && t.Second() > es) { - return false - } - } - return true + return i.Timing.IsActiveAt(t, endTime) } /* diff --git a/engine/rateinterval_test.go b/engine/rateinterval_test.go index fb6a94c1e..d3135f694 100644 --- a/engine/rateinterval_test.go +++ b/engine/rateinterval_test.go @@ -25,6 +25,10 @@ import ( "github.com/cgrates/cgrates/utils" ) +var ( + ACTIVE_TIME = time.Now() +) + func TestRateIntervalSimpleContains(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ @@ -337,6 +341,10 @@ func TestRateIntervalCronEmpty(t *testing.T) { } } +func TestTimingIsActive(t *testing.T) { + +} + /*********************************Benchmarks**************************************/ func BenchmarkRateIntervalContainsDate(b *testing.B) { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 882eeb5ee..f11248a97 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -511,6 +511,7 @@ func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*utils.TPAct Direction: ac.Direction, Units: ac.Units, ExpiryTime: ac.ExpiryTime, + TimingTags: ac.TimingTags, DestinationTag: ac.DestinationId, RatingSubject: ac.RatingSubject, Category: ac.Category, @@ -543,6 +544,7 @@ func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, err Direction: tpAct.Direction, Units: tpAct.Units, ExpiryTime: tpAct.ExpiryTime, + TimingTags: tpAct.TimingTags, DestinationId: tpAct.DestinationTag, RatingSubject: tpAct.RatingSubject, Category: tpAct.Category, @@ -620,6 +622,7 @@ func (self *SQLStorage) SetTPActionTriggers(tpid string, ats map[string][]*utils BalanceDestinationTag: at.BalanceDestinationId, BalanceWeight: at.BalanceWeight, BalanceExpiryTime: at.BalanceExpirationDate, + BalanceTimingTags: at.BalanceTimingTags, BalanceRatingSubject: at.BalanceRatingSubject, BalanceCategory: at.BalanceCategory, BalanceSharedGroup: at.BalanceSharedGroup, @@ -1402,6 +1405,7 @@ func (self *SQLStorage) GetTpActions(tpid, tag string) (map[string][]*utils.TPAc Direction: tpAc.Direction, Units: tpAc.Units, ExpiryTime: tpAc.ExpiryTime, + TimingTags: tpAc.TimingTags, DestinationId: tpAc.DestinationTag, RatingSubject: tpAc.RatingSubject, Category: tpAc.Category, @@ -1433,6 +1437,7 @@ func (self *SQLStorage) GetTpActionTriggers(tpid, tag string) (map[string][]*uti BalanceDestinationId: tpAt.BalanceDestinationTag, BalanceWeight: tpAt.BalanceWeight, BalanceExpirationDate: tpAt.BalanceExpiryTime, + BalanceTimingTags: tpAt.BalanceTimingTags, BalanceRatingSubject: tpAt.BalanceRatingSubject, BalanceCategory: tpAt.BalanceCategory, BalanceSharedGroup: tpAt.BalanceSharedGroup, diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index 8fa543007..b1c235e4d 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -44,9 +44,9 @@ func TestAcntActsLoadCsv(t *testing.T) { ratingProfiles := `` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC,*topup_reset,,,*voice,*out,,*any,,,*unlimited,10,10,10 -DISABLE_ACNT,*disable_account,,,,,,,,,,,,10 -ENABLE_ACNT,*enable_account,,,,,,,,,,,,10` + actions := `TOPUP10_AC,*topup_reset,,,*voice,*out,,*any,,,*unlimited,,10,10,10 +DISABLE_ACNT,*disable_account,,,,,,,,,,,,,10 +ENABLE_ACNT,*enable_account,,,,,,,,,,,,,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10` actionTriggers := `` accountActions := `cgrates.org,1,*out,TOPUP10_AT,` diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index e370d542c..29faae1d2 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -52,8 +52,8 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` *out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,10,10,10 -TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,40,10,10` + actions := `TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,10,10,10 +TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10 TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` diff --git a/general_tests/ddazmbl2_test.go b/general_tests/ddazmbl2_test.go index 2f57b98a2..009321733 100644 --- a/general_tests/ddazmbl2_test.go +++ b/general_tests/ddazmbl2_test.go @@ -52,8 +52,8 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` *out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,0,10,10 -TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,40,10,10` + actions := `TOPUP10_AC,*topup_reset,,,*monetary,*out,,*any,,,*unlimited,,0,10,10 +TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10 TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` diff --git a/general_tests/ddazmbl3_test.go b/general_tests/ddazmbl3_test.go index 3bd6bca89..9f941296d 100644 --- a/general_tests/ddazmbl3_test.go +++ b/general_tests/ddazmbl3_test.go @@ -52,7 +52,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` *out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,40,10,10` + actions := `TOPUP10_AC1,*topup_reset,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,10` actionPlans := `TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` accountActions := `cgrates.org,12346,*out,TOPUP10_AT,` diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 5b97e72d7..528f1638a 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -177,6 +177,7 @@ type TPTiming struct { MonthDays MonthDays WeekDays WeekDays StartTime string + EndTime string } type TPRatingPlan struct { @@ -320,6 +321,7 @@ type TPAction struct { Direction string // Balance direction 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 RatingSubject string // Reference a rate subject defined in RatingProfiles Category string // category filter for balances @@ -522,7 +524,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), strconv.FormatFloat(at.MinSleep.Seconds(), 'f', -1, 64), - at.BalanceTag, at.BalanceType, at.BalanceDirection, at.BalanceCategory, at.BalanceDestinationId, at.BalanceRatingSubject, at.BalanceSharedGroup, at.BalanceExpirationDate, + at.BalanceTag, at.BalanceType, at.BalanceDirection, at.BalanceCategory, at.BalanceDestinationId, 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 @@ -539,6 +541,7 @@ type TPActionTrigger struct { BalanceDestinationId string // filter for balance BalanceWeight float64 // filter for balance BalanceExpirationDate string // filter for balance + BalanceTimingTags string // filter for balance BalanceRatingSubject string // filter for balance BalanceCategory string // filter for balance BalanceSharedGroup string // filter for balance diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go index ea8ba1d48..e661c990e 100644 --- a/utils/apitpdata_test.go +++ b/utils/apitpdata_test.go @@ -422,6 +422,7 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceDestinationId: "", BalanceWeight: 0.0, BalanceExpirationDate: "*never", + BalanceTimingTags: "T1", BalanceRatingSubject: "special1", BalanceCategory: "call", BalanceSharedGroup: "SHARED_1", @@ -439,6 +440,7 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { BalanceDestinationId: "FS_USERS", BalanceWeight: 0.0, BalanceExpirationDate: "*never", + BalanceTimingTags: "T1", BalanceRatingSubject: "special1", BalanceCategory: "call", BalanceSharedGroup: "SHARED_1", @@ -448,8 +450,8 @@ func TestTPActionPlanAsExportSlice(t *testing.T) { }, } expectedSlc := [][]string{ - []string{"STANDARD_TRIGGERS", "*min_balance", "2", "false", "0", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "0", "0", "LOG_WARNING", "10"}, - []string{"STANDARD_TRIGGERS", "*max_counter", "5", "false", "0", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "0", "0", "LOG_WARNING", "10"}, + []string{"STANDARD_TRIGGERS", "*min_balance", "2", "false", "0", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "T1", "0", "0", "LOG_WARNING", "10"}, + []string{"STANDARD_TRIGGERS", "*max_counter", "5", "false", "0", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "T1", "0", "0", "LOG_WARNING", "10"}, } if slc := at.AsExportSlice(); !reflect.DeepEqual(expectedSlc, slc) { t.Errorf("Expecting: %+v, received: %+v", expectedSlc, slc) diff --git a/utils/consts.go b/utils/consts.go index f3f7baacf..d393f9bd9 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -61,9 +61,9 @@ const ( RATE_PROFILES_NRCOLS = 7 SHARED_GROUPS_NRCOLS = 4 LCRS_NRCOLS = 9 - ACTIONS_NRCOLS = 14 + ACTIONS_NRCOLS = 15 ACTION_PLANS_NRCOLS = 4 - ACTION_TRIGGERS_NRCOLS = 17 + ACTION_TRIGGERS_NRCOLS = 18 ACCOUNT_ACTIONS_NRCOLS = 5 DERIVED_CHARGERS_NRCOLS = 17 CDR_STATS_NRCOLS = 21