some rating optimization and all hardcoded values using *lowercase

This commit is contained in:
Radu Ioan Fericean
2013-07-22 22:15:14 +03:00
parent 2c7eb3593e
commit 6d3e011634
16 changed files with 160 additions and 126 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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))

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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
`
)

View File

@@ -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

View File

@@ -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{}

View File

@@ -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
}

View File

@@ -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{}

View File

@@ -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)

View File

@@ -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 {