From 6d3e011634b64a2d06a9ba3aa261abd4ba45f6c0 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 22 Jul 2013 22:15:14 +0300 Subject: [PATCH] some rating optimization and all hardcoded values using *lowercase --- rater/action.go | 22 +++++++------- rater/activationperiod.go | 6 +++- rater/activationperiod_test.go | 20 ++++++------ rater/callcost_test.go | 18 +++++------ rater/calldesc.go | 24 +++++++-------- rater/calldesc_test.go | 54 ++++++++++++++++----------------- rater/dateseries.go | 16 +++++----- rater/dateseries_test.go | 8 ++--- rater/interval.go | 21 +++++++++++++ rater/loader_csv_test.go | 36 +++++++++++----------- rater/minute_buckets.go | 4 +-- rater/simple_serializer_test.go | 4 +-- rater/timespans.go | 9 ++++++ rater/units_counter_test.go | 2 +- rater/userbalance.go | 28 ++++++++--------- rater/userbalance_test.go | 14 ++++----- 16 files changed, 160 insertions(+), 126 deletions(-) diff --git a/rater/action.go b/rater/action.go index 62aa77f42..99a7c9964 100644 --- a/rater/action.go +++ b/rater/action.go @@ -39,17 +39,17 @@ type Action struct { } const ( - LOG = "LOG" - RESET_TRIGGERS = "RESET_TRIGGERS" - SET_POSTPAID = "SET_POSTPAID" - RESET_POSTPAID = "RESET_POSTPAID" - SET_PREPAID = "SET_PREPAID" - RESET_PREPAID = "RESET_PREPAID" - TOPUP_RESET = "TOPUP_RESET" - TOPUP = "TOPUP" - DEBIT = "DEBIT" - RESET_COUNTER = "RESET_COUNTER" - RESET_COUNTERS = "RESET_COUNTERS" + LOG = "*log" + RESET_TRIGGERS = "*reset_triggers" + SET_POSTPAID = "*set_postpaid" + RESET_POSTPAID = "*reset_postpaid" + SET_PREPAID = "*set_prepaid" + RESET_PREPAID = "*reset_prepaid" + TOPUP_RESET = "*topup_reset" + TOPUP = "*topup" + DEBIT = "*debit" + RESET_COUNTER = "*reset_counter" + RESET_COUNTERS = "*reset_counters" ) type actionTypeFunc func(*UserBalance, *Action) error diff --git a/rater/activationperiod.go b/rater/activationperiod.go index a06d037be..701a213ce 100644 --- a/rater/activationperiod.go +++ b/rater/activationperiod.go @@ -28,7 +28,7 @@ The struture that is saved to storage. */ type ActivationPeriod struct { ActivationTime time.Time - Intervals []*Interval + Intervals IntervalList } type xCachedActivationPeriods struct { @@ -65,3 +65,7 @@ func (ap *ActivationPeriod) AddIntervalIfNotPresent(is ...*Interval) { func (ap *ActivationPeriod) Equal(o *ActivationPeriod) bool { return ap.ActivationTime == o.ActivationTime } + +func (ap *ActivationPeriod) GetGroupTimeLimits() []float64 { + return nil +} diff --git a/rater/activationperiod_test.go b/rater/activationperiod_test.go index 64a0b1f59..6e31db2ad 100644 --- a/rater/activationperiod_test.go +++ b/rater/activationperiod_test.go @@ -8,7 +8,7 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of +but WITH*out ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -28,7 +28,7 @@ import ( func TestApRestoreFromStorage(t *testing.T) { cd := &CallDescriptor{ - Direction: "OUT", + Direction: OUTBOUND, TOR: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", @@ -49,7 +49,7 @@ func TestApStoreRestoreJson(t *testing.T) { ap := &ActivationPeriod{ActivationTime: d} ap.AddInterval(i) result, _ := json.Marshal(ap) - expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Years\":null,\"Months\":[2],\"MonthDays\":[1],\"WeekDays\":[3,4],\"StartTime\":\"14:30:00\",\"EndTime\":\"15:00:00\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0,\"RoundingMethod\":\"\",\"RoundingDecimals\":0}]}" + expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Years\":null,\"Months\":[2],\"MonthDays\":[1],\"WeekDays\":[3,4],\"StartTime\":\"14:30:00\",\"EndTime\":\"15:00:00\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0,\"GroupInterval\":0,\"RoundingMethod\":\"\",\"RoundingDecimals\":0}]}" if string(result) != expected { t.Errorf("Expected %q was %q", expected, result) } @@ -66,7 +66,7 @@ func TestApStoreRestoreBlank(t *testing.T) { ap := &ActivationPeriod{ActivationTime: d} ap.AddInterval(i) result, _ := json.Marshal(ap) - expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Years\":null,\"Months\":null,\"MonthDays\":null,\"WeekDays\":null,\"StartTime\":\"\",\"EndTime\":\"\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0,\"RoundingMethod\":\"\",\"RoundingDecimals\":0}]}" + expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Years\":null,\"Months\":null,\"MonthDays\":null,\"WeekDays\":null,\"StartTime\":\"\",\"EndTime\":\"\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0,\"GroupInterval\":0,\"RoundingMethod\":\"\",\"RoundingDecimals\":0}]}" if string(result) != expected { t.Errorf("Expected %q was %q", expected, result) } @@ -78,7 +78,7 @@ func TestApStoreRestoreBlank(t *testing.T) { } func TestFallbackDirect(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "41"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "41"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 1 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) @@ -86,7 +86,7 @@ func TestFallbackDirect(t *testing.T) { } func TestFallbackMultiple(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "vdf", Subject: "fall", Destination: "0723045"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "fall", Destination: "0723045"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 1 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) @@ -94,7 +94,7 @@ func TestFallbackMultiple(t *testing.T) { } func TestFallbackWithBackTrace(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "4123"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "4123"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 1 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) @@ -102,7 +102,7 @@ func TestFallbackWithBackTrace(t *testing.T) { } func TestFallbackDefault(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "vdf", Subject: "one", Destination: "0723"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "one", Destination: "0723"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 1 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) @@ -110,7 +110,7 @@ func TestFallbackDefault(t *testing.T) { } func TestFallbackNoInfiniteLoop(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "vdf", Subject: "rif", Destination: "0721"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "rif", Destination: "0721"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 0 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) @@ -118,7 +118,7 @@ func TestFallbackNoInfiniteLoop(t *testing.T) { } func TestFallbackNoInfiniteLoopSelf(t *testing.T) { - cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "vdf", Subject: "inf", Destination: "0721"} + cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "inf", Destination: "0721"} cd.LoadActivationPeriods() if len(cd.ActivationPeriods) != 0 { t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods)) diff --git a/rater/callcost_test.go b/rater/callcost_test.go index 547fe3bf6..57d37b14f 100644 --- a/rater/callcost_test.go +++ b/rater/callcost_test.go @@ -8,7 +8,7 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of +but WITH*out ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -27,14 +27,14 @@ import ( func TestSingleResultMerge(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 00, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 17, 01, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.GetCost() if cc1.Cost != 60 { t.Errorf("expected 60 was %v", cc1.Cost) } t1 = time.Date(2012, time.February, 2, 17, 01, 0, 0, time.UTC) t2 = time.Date(2012, time.February, 2, 17, 02, 0, 0, time.UTC) - cd = &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc2, _ := cd.GetCost() if cc2.Cost != 60 { t.Errorf("expected 60 was %v", cc2.Cost) @@ -51,7 +51,7 @@ func TestSingleResultMerge(t *testing.T) { func TestMultipleResultMerge(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.GetCost() if cc1.Cost != 60 { t.Errorf("expected 60 was %v", cc1.Cost) @@ -61,7 +61,7 @@ func TestMultipleResultMerge(t *testing.T) { } t1 = time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC) t2 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC) - cd = &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc2, _ := cd.GetCost() if cc2.Cost != 30 { t.Errorf("expected 30 was %v", cc2.Cost) @@ -81,14 +81,14 @@ func TestMultipleResultMerge(t *testing.T) { func TestMultipleInputLeftMerge(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.GetCost() if cc1.Cost != 90 { t.Errorf("expected 90 was %v", cc1.Cost) } t1 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC) t2 = time.Date(2012, time.February, 2, 18, 02, 0, 0, time.UTC) - cd = &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc2, _ := cd.GetCost() if cc2.Cost != 30 { t.Errorf("expected 30 was %v", cc2.Cost) @@ -105,14 +105,14 @@ func TestMultipleInputLeftMerge(t *testing.T) { func TestMultipleInputRightMerge(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 58, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.GetCost() if cc1.Cost != 60 { t.Errorf("expected 60 was %v", cc1.Cost) } t1 = time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC) t2 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC) - cd = &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cc2, _ := cd.GetCost() if cc2.Cost != 90 { t.Errorf("expected 90 was %v", cc2.Cost) diff --git a/rater/calldesc.go b/rater/calldesc.go index 4501a9f4d..5e1f9e228 100644 --- a/rater/calldesc.go +++ b/rater/calldesc.go @@ -40,7 +40,7 @@ func init() { const ( RECURSION_MAX_DEPTH = 10 - FALLBACK_SUBJECT = "*all" + FALLBACK_SUBJECT = "*any" FALLBACK_SEP = ";" ) @@ -189,17 +189,13 @@ func (cd *CallDescriptor) GetKey() string { return fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, cd.Subject) } -/* -Splits the call descriptor timespan into sub time spans according to the activation periods intervals. -*/ -func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { - return cd.splitTimeSpan(&TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd}) -} - /* Splits the received timespan into sub time spans according to the activation periods intervals. */ -func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeSpan) { +func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*TimeSpan) { + if firstSpan == nil { + firstSpan = &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd} + } timespans = append(timespans, firstSpan) // split on (free) minute buckets if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil { @@ -250,11 +246,15 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS // split on price intervals for i := 0; i < len(timespans); i++ { if timespans[i].MinuteInfo != nil { - continue + continue // cont try to split timespans payed with minutes } ap := timespans[i].ActivationPeriod //timespans[i].ActivationPeriod = nil + ap.Intervals.Sort() for _, interval := range ap.Intervals { + if timespans[i].Interval != nil && timespans[i].Interval.Weight < interval.Weight { + continue // if the timespan has an interval than it already has a heigher weight + } newTs := timespans[i].SplitByInterval(interval) if newTs != nil { newTs.ActivationPeriod = ap @@ -274,7 +274,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) { Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetUserBalanceKey(), err)) return &CallCost{}, err } - timespans := cd.splitInTimeSpans() + timespans := cd.splitInTimeSpans(nil) cost := 0.0 connectionFee := 0.0 @@ -336,7 +336,7 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { for i := 0; i < 10; i++ { maxDuration, _ := time.ParseDuration(fmt.Sprintf("%vs", maxSessionSeconds-availableSeconds)) ts := &TimeSpan{TimeStart: now, TimeEnd: now.Add(maxDuration)} - timespans := cd.splitTimeSpan(ts) + timespans := cd.splitInTimeSpans(ts) cost := 0.0 for i, ts := range timespans { diff --git a/rater/calldesc_test.go b/rater/calldesc_test.go index 0d073ce51..41e73cdf2 100644 --- a/rater/calldesc_test.go +++ b/rater/calldesc_test.go @@ -8,7 +8,7 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of +but WITH*out ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -30,7 +30,7 @@ func init() { func populateDB() { minu := &UserBalance{ - Id: "OUT:vdf:minu", + Id: "*out:vdf:minu", Type: UB_TYPE_PREPAID, BalanceMap: map[string]BalanceChain{CREDIT: BalanceChain{&Balance{Value: 0}}}, MinuteBuckets: []*MinuteBucket{ @@ -39,7 +39,7 @@ func populateDB() { }, } broker := &UserBalance{ - Id: "OUT:vdf:broker", + Id: "*out:vdf:broker", Type: UB_TYPE_PREPAID, MinuteBuckets: []*MinuteBucket{ &MinuteBucket{Seconds: 20, DestinationId: "NAT", Weight: 10, Price: 1}, @@ -58,10 +58,10 @@ func populateDB() { func TestSplitSpans(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cd.LoadActivationPeriods() - timespans := cd.splitInTimeSpans() + timespans := cd.splitInTimeSpans(nil) if len(timespans) != 2 { t.Log(cd.ActivationPeriods) t.Error("Wrong number of timespans: ", len(timespans)) @@ -71,10 +71,10 @@ func TestSplitSpans(t *testing.T) { func TestRedisSplitSpans(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257", TimeStart: t1, TimeEnd: t2} cd.LoadActivationPeriods() - timespans := cd.splitInTimeSpans() + timespans := cd.splitInTimeSpans(nil) if len(timespans) != 2 { t.Log(cd.ActivationPeriods) t.Error("Wrong number of timespans: ", len(timespans)) @@ -84,7 +84,7 @@ func TestRedisSplitSpans(t *testing.T) { func TestGetCost(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -95,7 +95,7 @@ func TestGetCost(t *testing.T) { func TestGetCostNoConnectFee(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 1} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 1} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -106,7 +106,7 @@ func TestGetCostNoConnectFee(t *testing.T) { func TestGetCostAccount(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Account: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Account: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -117,7 +117,7 @@ func TestGetCostAccount(t *testing.T) { func TestFullDestNotFound(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256308200", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256308200", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -129,7 +129,7 @@ func TestFullDestNotFound(t *testing.T) { func TestSubjectNotFound(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "not_exiting", Destination: "025740532", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "not_exiting", Destination: "025740532", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -141,7 +141,7 @@ func TestSubjectNotFound(t *testing.T) { func TestMultipleActivationPeriods(t *testing.T) { t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 2700, ConnectFee: 1} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -153,7 +153,7 @@ func TestMultipleActivationPeriods(t *testing.T) { func TestSpansMultipleActivationPeriods(t *testing.T) { t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 1200, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -164,7 +164,7 @@ func TestSpansMultipleActivationPeriods(t *testing.T) { func TestLessThanAMinute(t *testing.T) { t1 := time.Date(2012, time.February, 8, 23, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 23, 50, 30, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 15, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -175,7 +175,7 @@ func TestLessThanAMinute(t *testing.T) { func TestUniquePrice(t *testing.T) { t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723045326", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723045326", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0723", Cost: 1810.5, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -186,7 +186,7 @@ func TestUniquePrice(t *testing.T) { func TestMinutesCost(t *testing.T) { t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 22, 51, 50, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", TimeStart: t1, TimeEnd: t2} result, _ := cd.GetCost() expected := &CallCost{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Cost: 55, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -195,7 +195,7 @@ func TestMinutesCost(t *testing.T) { } func TestMaxSessionTimeNoUserBalance(t *testing.T) { - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", Amount: 1000} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", Amount: 1000} result, err := cd.GetMaxSessionTime() if result != 1000 || err == nil { t.Errorf("Expected %v was %v (%v)", 1000, result, err) @@ -203,7 +203,7 @@ func TestMaxSessionTimeNoUserBalance(t *testing.T) { } func TestMaxSessionTimeWithUserBalance(t *testing.T) { - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "minu", Destination: "0723", Amount: 1000} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minu", Destination: "0723", Amount: 1000} result, err := cd.GetMaxSessionTime() expected := 300.0 if result != expected || err != nil { @@ -212,7 +212,7 @@ func TestMaxSessionTimeWithUserBalance(t *testing.T) { } func TestMaxSessionTimeWithUserBalanceAccount(t *testing.T) { - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "minu_from_tm", Account: "minu", Destination: "0723", Amount: 1000} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minu_from_tm", Account: "minu", Destination: "0723", Amount: 1000} result, err := cd.GetMaxSessionTime() expected := 300.0 if result != expected || err != nil { @@ -221,7 +221,7 @@ func TestMaxSessionTimeWithUserBalanceAccount(t *testing.T) { } func TestMaxSessionTimeNoCredit(t *testing.T) { - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "broker", Destination: "0723", Amount: 5400} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "broker", Destination: "0723", Amount: 5400} result, err := cd.GetMaxSessionTime() if result != 100 || err != nil { t.Errorf("Expected %v was %v", 100, result) @@ -233,7 +233,7 @@ func BenchmarkStorageGetting(b *testing.B) { b.StopTimer() t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { storageGetter.GetRatingProfile(cd.GetKey()) @@ -244,7 +244,7 @@ func BenchmarkStorageRestoring(b *testing.B) { b.StopTimer() t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { cd.LoadActivationPeriods() @@ -255,7 +255,7 @@ func BenchmarkStorageGetCost(b *testing.B) { b.StopTimer() t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetCost() @@ -266,11 +266,11 @@ func BenchmarkSplitting(b *testing.B) { b.StopTimer() t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} cd.LoadActivationPeriods() b.StartTimer() for i := 0; i < b.N; i++ { - cd.splitInTimeSpans() + cd.splitInTimeSpans(nil) } } @@ -285,7 +285,7 @@ func BenchmarkStorageSingleGetSessionTime(b *testing.B) { func BenchmarkStorageMultipleGetSessionTime(b *testing.B) { b.StopTimer() - cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 5400} + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 5400} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() diff --git a/rater/dateseries.go b/rater/dateseries.go index 0be0a2200..090857def 100644 --- a/rater/dateseries.go +++ b/rater/dateseries.go @@ -61,7 +61,7 @@ func (ys Years) Contains(year int) (result bool) { // Parse Years elements from string separated by sep. func (ys *Years) Parse(input, sep string) { switch input { - case "*all", "": + case "*any", "": *ys = []int{} default: elements := strings.Split(input, sep) @@ -75,7 +75,7 @@ func (ys *Years) Parse(input, sep string) { func (ys Years) Serialize(sep string) string { if len(ys) == 0 { - return "*all" + return "*any" } var yStr string for idx, yr := range ys { @@ -124,7 +124,7 @@ func (m Months) Contains(month time.Month) (result bool) { // Loades Month elemnents from a string separated by sep. func (m *Months) Parse(input, sep string) { switch input { - case "*all": + case "*any": *m = allMonths case "*none": // Apier cannot receive empty string, hence using meta-tag *m = []time.Month{} @@ -146,7 +146,7 @@ func (m Months) Serialize(sep string) string { return "*none" } if reflect.DeepEqual(m, Months(allMonths)) { - return "*all" + return "*any" } var mStr string for idx, mt := range m { @@ -195,7 +195,7 @@ func (md MonthDays) Contains(monthDay int) (result bool) { // Parse MonthDay elements from string separated by sep. func (md *MonthDays) Parse(input, sep string) { switch input { - case "*all": + case "*any": *md = allMonthDays case "": *md = []int{} @@ -215,7 +215,7 @@ func (md MonthDays) Serialize(sep string) string { return "*none" } if reflect.DeepEqual(md, MonthDays(allMonthDays)) { - return "*all" + return "*any" } var mdsStr string for idx, mDay := range md { @@ -263,7 +263,7 @@ func (wd WeekDays) Contains(weekDay time.Weekday) (result bool) { func (wd *WeekDays) Parse(input, sep string) { switch input { - case "*all": + case "*any": *wd = allWeekDays case "": *wd = []time.Weekday{} @@ -283,7 +283,7 @@ func (wd WeekDays) Serialize(sep string) string { return "*none" } if reflect.DeepEqual(wd, WeekDays(allWeekDays)) { - return "*all" + return "*any" } var wdStr string for idx, d := range wd { diff --git a/rater/dateseries_test.go b/rater/dateseries_test.go index d19a99055..0325286b3 100644 --- a/rater/dateseries_test.go +++ b/rater/dateseries_test.go @@ -67,7 +67,7 @@ func TestWeekDayStoreRestoreJson(t *testing.T) { func TestYearsSerialize(t *testing.T) { ys := &Years{} yString := ys.Serialize(";") - expectString := "*all" + expectString := "*any" if expectString != yString { t.Errorf("Expected: %s, got: %s", expectString, yString) } @@ -94,7 +94,7 @@ func TestMonthsSerialize(t *testing.T) { } mths1 := Months(allMonths) mString1 := mths1.Serialize(";") - expectString1 := "*all" + expectString1 := "*any" if expectString1 != mString1 { t.Errorf("Expected: %s, got: %s", expectString1, mString1) } @@ -121,7 +121,7 @@ func TestMonthDaysSerialize(t *testing.T) { } mds1 := MonthDays(allMonthDays) mdsString1 := mds1.Serialize(";") - expectString1 := "*all" + expectString1 := "*any" if expectString1 != mdsString1 { t.Errorf("Expected: %s, got: %s", expectString1, mdsString1) } @@ -148,7 +148,7 @@ func TestWeekDaysSerialize(t *testing.T) { } wds1 := WeekDays(allWeekDays) wdsString1 := wds1.Serialize(";") - expectString1 := "*all" + expectString1 := "*any" if expectString1 != wdsString1 { t.Errorf("Expected: %s, got: %s", expectString1, wdsString1) } diff --git a/rater/interval.go b/rater/interval.go index d6062c325..9be52ca96 100644 --- a/rater/interval.go +++ b/rater/interval.go @@ -23,6 +23,7 @@ import ( "github.com/cgrates/cgrates/utils" "math" "reflect" + "sort" "strconv" "strings" "time" @@ -39,6 +40,7 @@ type Interval struct { WeekDays WeekDays StartTime, EndTime string // ##:##:## format Weight, ConnectFee, Price, PricedUnits, RateIncrements float64 + GroupInterval float64 RoundingMethod string RoundingDecimals int } @@ -146,3 +148,22 @@ func (i *Interval) GetCost(duration float64) (cost float64) { } return utils.Round(cost, i.RoundingDecimals, i.RoundingMethod) } + +// Structure to store actions according to weight +type IntervalList []*Interval + +func (il IntervalList) Len() int { + return len(il) +} + +func (il IntervalList) Swap(i, j int) { + il[i], il[j] = il[j], il[i] +} + +func (il IntervalList) Less(i, j int) bool { + return il[i].Weight < il[j].Weight +} + +func (il IntervalList) Sort() { + sort.Sort(il) +} diff --git a/rater/loader_csv_test.go b/rater/loader_csv_test.go index 1b771cc27..e7f672404 100644 --- a/rater/loader_csv_test.go +++ b/rater/loader_csv_test.go @@ -38,9 +38,9 @@ RET,0723 RET,0724 ` timings = ` -WORKDAYS_00,*all,*all,*all,1;2;3;4;5,00:00:00 -WORKDAYS_18,*all,*all,*all,1;2;3;4;5,18:00:00 -WEEKENDS,*all,*all,*all,6;7,00:00:00 +WORKDAYS_00,*any,*any,*any,1;2;3;4;5,00:00:00 +WORKDAYS_18,*any,*any,*any,1;2;3;4;5,18:00:00 +WEEKENDS,*any,*any,*any,6;7,00:00:00 ONE_TIME_RUN,2012,,,,*asap ` rates = ` @@ -71,30 +71,30 @@ EVENING,P2,WORKDAYS_18,10 EVENING,P2,WEEKENDS,10 ` ratingProfiles = ` -CUSTOMER_1,0,OUT,rif:from:tm,danb,PREMIUM,2012-01-01T00:00:00Z -CUSTOMER_1,0,OUT,rif:from:tm,danb,STANDARD,2012-02-28T00:00:00Z -CUSTOMER_2,0,OUT,danb:87.139.12.167,danb,STANDARD,2012-01-01T00:00:00Z -CUSTOMER_1,0,OUT,danb,,PREMIUM,2012-01-01T00:00:00Z -vdf,0,OUT,rif,,EVENING,2012-01-01T00:00:00Z -vdf,0,OUT,rif,,EVENING,2012-02-28T00:00:00Z -vdf,0,OUT,minu,,EVENING,2012-01-01T00:00:00Z -vdf,0,OUT,*all,,EVENING,2012-02-28T00:00:00Z -vdf,0,OUT,one,,STANDARD,2012-02-28T00:00:00Z -vdf,0,OUT,inf,inf,STANDARD,2012-02-28T00:00:00Z -vdf,0,OUT,fall,one|rif,PREMIUM,2012-02-28T00:00:00Z +CUSTOMER_1,0,*out,rif:from:tm,danb,PREMIUM,2012-01-01T00:00:00Z +CUSTOMER_1,0,*out,rif:from:tm,danb,STANDARD,2012-02-28T00:00:00Z +CUSTOMER_2,0,*out,danb:87.139.12.167,danb,STANDARD,2012-01-01T00:00:00Z +CUSTOMER_1,0,*out,danb,,PREMIUM,2012-01-01T00:00:00Z +vdf,0,*out,rif,,EVENING,2012-01-01T00:00:00Z +vdf,0,*out,rif,,EVENING,2012-02-28T00:00:00Z +vdf,0,*out,minu,,EVENING,2012-01-01T00:00:00Z +vdf,0,*out,*any,,EVENING,2012-02-28T00:00:00Z +vdf,0,*out,one,,STANDARD,2012-02-28T00:00:00Z +vdf,0,*out,inf,inf,STANDARD,2012-02-28T00:00:00Z +vdf,0,*out,fall,one|rif,PREMIUM,2012-02-28T00:00:00Z ` actions = ` -MINI,TOPUP,MINUTES,OUT,100,1374239002,NAT,ABSOLUTE,0,10,10 +MINI,TOPUP,MINUTES,*out,100,1374239002,NAT,*absolute,0,10,10 ` actionTimings = ` MORE_MINUTES,MINI,ONE_TIME_RUN,10 ` actionTriggers = ` -STANDARD_TRIGGER,MINUTES,OUT,COUNTER,10,GERMANY_O2,SOME_1,10 -STANDARD_TRIGGER,MINUTES,OUT,BALANCE,200,GERMANY,SOME_2,10 +STANDARD_TRIGGER,MINUTES,*out,COUNTER,10,GERMANY_O2,SOME_1,10 +STANDARD_TRIGGER,MINUTES,*out,BALANCE,200,GERMANY,SOME_2,10 ` accountActions = ` -vdf,minitsboy,OUT,MORE_MINUTES,STANDARD_TRIGGER +vdf,minitsboy,*out,MORE_MINUTES,STANDARD_TRIGGER ` ) diff --git a/rater/minute_buckets.go b/rater/minute_buckets.go index c525834f0..343133564 100644 --- a/rater/minute_buckets.go +++ b/rater/minute_buckets.go @@ -35,8 +35,8 @@ type MinuteBucket struct { } const ( - PERCENT = "PERCENT" - ABSOLUTE = "ABSOLUTE" + PERCENT = "*percent" + ABSOLUTE = "*absolute" ) // Returns the available number of seconds for a specified credit diff --git a/rater/simple_serializer_test.go b/rater/simple_serializer_test.go index f37e66140..3dab01eeb 100644 --- a/rater/simple_serializer_test.go +++ b/rater/simple_serializer_test.go @@ -117,13 +117,13 @@ func TestActionTriggerStoreRestore(t *testing.T) { BalanceId: CREDIT, Direction: OUTBOUND, ThresholdValue: 100.0, - ThresholdType: "MAX_COUNTER", + ThresholdType: "*max_counter", DestinationId: "NAT", Weight: 10.0, ActionsId: "Commando", } r, err := at.Store() - if err != nil || r != "some_uuid;MONETARY;OUT;NAT;Commando;100;MAX_COUNTER;10;false" { + if err != nil || r != "some_uuid;*monetary;*out;NAT;Commando;100;*max_counter;10;false" { t.Errorf("Error serializing action trigger: %v", string(r)) } o := &ActionTrigger{} diff --git a/rater/timespans.go b/rater/timespans.go index 523c75d1e..58accc180 100644 --- a/rater/timespans.go +++ b/rater/timespans.go @@ -32,6 +32,7 @@ type TimeSpan struct { ActivationPeriod *ActivationPeriod Interval *Interval MinuteInfo *MinuteInfo + CallDuration float64 // the call duration so far till TimeEnd } // Holds the bonus minute information related to a specified timespan @@ -187,3 +188,11 @@ func (ts *TimeSpan) SplitByMinuteBucket(mb *MinuteBucket) (newTs *TimeSpan) { return } + +func (ts *TimeSpan) GetGroupStart() float64 { + return ts.CallDuration - ts.GetDuration().Seconds() +} + +func (ts *TimeSpan) GetGroupEnd() float64 { + return ts.CallDuration +} diff --git a/rater/units_counter_test.go b/rater/units_counter_test.go index 0ea435fa4..a2198d953 100644 --- a/rater/units_counter_test.go +++ b/rater/units_counter_test.go @@ -31,7 +31,7 @@ func TestUnitsCounterStoreRestore(t *testing.T) { MinuteBuckets: []*MinuteBucket{&MinuteBucket{Weight: 20, Price: 1, DestinationId: "NAT"}, &MinuteBucket{Weight: 10, Price: 10, PriceType: ABSOLUTE, DestinationId: "RET"}}, } r, err := uc.Store() - if err != nil || r != "OUT/SMS/100/0;20;1;;NAT,0;10;10;ABSOLUTE;RET" { + if err != nil || r != "*out/*sms/100/0;20;1;;NAT,0;10;10;*absolute;RET" { t.Errorf("Error serializing units counter: %v", string(r)) } o := &UnitsCounter{} diff --git a/rater/userbalance.go b/rater/userbalance.go index 53e0f6f35..69464ee31 100644 --- a/rater/userbalance.go +++ b/rater/userbalance.go @@ -27,17 +27,17 @@ import ( ) const ( - UB_TYPE_POSTPAID = "postpaid" - UB_TYPE_PREPAID = "prepaid" + UB_TYPE_POSTPAID = "*postpaid" + UB_TYPE_PREPAID = "*prepaid" // Direction type - INBOUND = "IN" - OUTBOUND = "OUT" + INBOUND = "*in" + OUTBOUND = "*out" // Balance types - CREDIT = "MONETARY" - SMS = "SMS" - TRAFFIC = "INTERNET" - TRAFFIC_TIME = "INTERNET_TIME" - MINUTES = "MINUTES" + CREDIT = "*monetary" + SMS = "*sms" + TRAFFIC = "*internet" + TRAFFIC_TIME = "*internet_time" + MINUTES = "*minutes" ) /* @@ -295,12 +295,12 @@ func (ub *UserBalance) executeActionTriggers(a *Action) { at.ThresholdValue != a.MinuteBucket.Price))) { continue } - if strings.Contains(at.ThresholdType, "COUNTER") { + if strings.Contains(at.ThresholdType, "counter") { for _, uc := range ub.UnitCounters { if uc.BalanceId == at.BalanceId { if at.BalanceId == MINUTES && at.DestinationId != "" { // last check adds safety for _, mb := range uc.MinuteBuckets { - if strings.Contains(at.ThresholdType, "MAX") { + if strings.Contains(at.ThresholdType, "*max") { if mb.DestinationId == at.DestinationId && mb.Seconds >= at.ThresholdValue { // run the actions at.Execute(ub) @@ -313,7 +313,7 @@ func (ub *UserBalance) executeActionTriggers(a *Action) { } } } else { - if strings.Contains(at.ThresholdType, "MAX") { + if strings.Contains(at.ThresholdType, "*max") { if uc.Units >= at.ThresholdValue { // run the actions at.Execute(ub) @@ -331,7 +331,7 @@ func (ub *UserBalance) executeActionTriggers(a *Action) { for _, b := range ub.BalanceMap[at.BalanceId] { if at.BalanceId == MINUTES && at.DestinationId != "" { // last check adds safety for _, mb := range ub.MinuteBuckets { - if strings.Contains(at.ThresholdType, "MAX") { + if strings.Contains(at.ThresholdType, "*max") { if mb.DestinationId == at.DestinationId && mb.Seconds >= at.ThresholdValue { // run the actions at.Execute(ub) @@ -344,7 +344,7 @@ func (ub *UserBalance) executeActionTriggers(a *Action) { } } } else { - if strings.Contains(at.ThresholdType, "MAX") { + if strings.Contains(at.ThresholdType, "*max") { if b.Value >= at.ThresholdValue { // run the actions at.Execute(ub) diff --git a/rater/userbalance_test.go b/rater/userbalance_test.go index 725cea2e7..00297c465 100644 --- a/rater/userbalance_test.go +++ b/rater/userbalance_test.go @@ -36,13 +36,13 @@ func init() { func populateTestActionsForTriggers() { ats := []*Action{ - &Action{ActionType: "TOPUP", BalanceId: CREDIT, Direction: OUTBOUND, Units: 10}, - &Action{ActionType: "TOPUP", BalanceId: MINUTES, Direction: OUTBOUND, MinuteBucket: &MinuteBucket{Weight: 20, Price: 1, Seconds: 10, DestinationId: "NAT"}}, + &Action{ActionType: "*topup", BalanceId: CREDIT, Direction: OUTBOUND, Units: 10}, + &Action{ActionType: "*topup", BalanceId: MINUTES, Direction: OUTBOUND, MinuteBucket: &MinuteBucket{Weight: 20, Price: 1, Seconds: 10, DestinationId: "NAT"}}, } storageGetter.SetActions("TEST_ACTIONS", ats) ats1 := []*Action{ - &Action{ActionType: "TOPUP", BalanceId: CREDIT, Direction: OUTBOUND, Units: 10, Weight: 20}, - &Action{ActionType: "RESET_PREPAID", Weight: 10}, + &Action{ActionType: "*topup", BalanceId: CREDIT, Direction: OUTBOUND, Units: 10, Weight: 20}, + &Action{ActionType: "*reset_prepaid", Weight: 10}, } storageGetter.SetActions("TEST_ACTIONS_ORDER", ats1) } @@ -423,7 +423,7 @@ func TestUserBalanceExecuteTriggeredActions(t *testing.T) { BalanceMap: map[string]BalanceChain{CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 100}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceId: CREDIT, Direction: OUTBOUND, Units: 1}}, MinuteBuckets: []*MinuteBucket{&MinuteBucket{Seconds: 10, Weight: 20, Price: 1, DestinationId: "NAT"}, &MinuteBucket{Weight: 10, Price: 10, PriceType: ABSOLUTE, DestinationId: "RET"}}, - ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, Direction: OUTBOUND, ThresholdValue: 2, ThresholdType: "MAX_COUNTER", ActionsId: "TEST_ACTIONS"}}, + ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, Direction: OUTBOUND, ThresholdValue: 2, ThresholdType: "*max_counter", ActionsId: "TEST_ACTIONS"}}, } ub.countUnits(&Action{BalanceId: CREDIT, Units: 1}) if ub.BalanceMap[CREDIT+OUTBOUND][0].Value != 110 || ub.MinuteBuckets[0].Seconds != 20 { @@ -448,7 +448,7 @@ func TestUserBalanceExecuteTriggeredActionsBalance(t *testing.T) { BalanceMap: map[string]BalanceChain{CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 100}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceId: CREDIT, Direction: OUTBOUND, Units: 1}}, MinuteBuckets: []*MinuteBucket{&MinuteBucket{Seconds: 10, Weight: 20, Price: 1, DestinationId: "NAT"}, &MinuteBucket{Weight: 10, Price: 10, PriceType: ABSOLUTE, DestinationId: "RET"}}, - ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, Direction: OUTBOUND, ThresholdValue: 100, ThresholdType: "MIN_COUNTER", ActionsId: "TEST_ACTIONS"}}, + ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, Direction: OUTBOUND, ThresholdValue: 100, ThresholdType: "*min_counter", ActionsId: "TEST_ACTIONS"}}, } ub.countUnits(&Action{BalanceId: CREDIT, Units: 1}) if ub.BalanceMap[CREDIT+OUTBOUND][0].Value != 110 || ub.MinuteBuckets[0].Seconds != 20 { @@ -461,7 +461,7 @@ func TestUserBalanceExecuteTriggeredActionsOrder(t *testing.T) { Id: "TEST_UB_OREDER", BalanceMap: map[string]BalanceChain{CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 100}}}, UnitCounters: []*UnitsCounter{&UnitsCounter{BalanceId: CREDIT, Direction: OUTBOUND, Units: 1}}, - ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, ThresholdValue: 2, ThresholdType: "MAX_COUNTER", ActionsId: "TEST_ACTIONS_ORDER"}}, + ActionTriggers: ActionTriggerPriotityList{&ActionTrigger{BalanceId: CREDIT, ThresholdValue: 2, ThresholdType: "*max_counter", ActionsId: "TEST_ACTIONS_ORDER"}}, } ub.countUnits(&Action{BalanceId: CREDIT, Direction: OUTBOUND, Units: 1}) if len(ub.BalanceMap[CREDIT+OUTBOUND]) != 1 || ub.BalanceMap[CREDIT+OUTBOUND][0].Value != 10 {