diff --git a/engine/action_timing.go b/engine/action_timing.go index 9b9729a57..c29096c27 100644 --- a/engine/action_timing.go +++ b/engine/action_timing.go @@ -34,15 +34,14 @@ const ( ) type ActionTiming struct { - Id string // uniquely identify the timing - Tag string // informative purpose only - UserBalanceIds []string - Timing *RateInterval - Weight float64 - ActionsId string - actions Actions - stCache time.Time // cached time of the next start - ActionsTag, TimingsTag string // used only for loading + Id string // uniquely identify the timing + Tag string // informative purpose only + UserBalanceIds []string + Timing *RateInterval + Weight float64 + ActionsId string + actions Actions + stCache time.Time // cached time of the next start } type ActionTimings []*ActionTiming diff --git a/engine/actions_test.go b/engine/actions_test.go index 26ea65ec9..958b7626b 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -86,7 +86,7 @@ func TestActionTimingOnlyMonthdays(t *testing.T) { now := time.Now() y, m, d := now.Date() tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: MonthDays{1, 25, 2, tomorrow.Day()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}} st := at.GetNextStartTime() expected := tomorrow if !st.Equal(expected) { @@ -103,7 +103,7 @@ func TestActionTimingHourMonthdays(t *testing.T) { if now.After(testTime) { day = tomorrow.Day() } - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime() expected := time.Date(y, m, day, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -115,7 +115,7 @@ func TestActionTimingOnlyMonths(t *testing.T) { now := time.Now() y, m, d := now.Date() nextMonth := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: Months{time.February, time.May, nextMonth.Month()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} st := at.GetNextStartTime() expected := time.Date(y, nextMonth.Month(), 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -132,7 +132,7 @@ func TestActionTimingHourMonths(t *testing.T) { if now.After(testTime) { month = nextMonth.Month() } - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime() expected := time.Date(y, month, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -159,8 +159,8 @@ func TestActionTimingHourMonthdaysMonths(t *testing.T) { } at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Months: Months{now.Month(), nextMonth.Month()}, - MonthDays: MonthDays{now.Day(), tomorrow.Day()}, + Months: utils.Months{now.Month(), nextMonth.Month()}, + MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00", }, }} @@ -177,8 +177,8 @@ func TestActionTimingFirstOfTheMonth(t *testing.T) { nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1}, }, }} st := at.GetNextStartTime() @@ -192,7 +192,7 @@ func TestActionTimingOnlyYears(t *testing.T) { now := time.Now() y, m, d := now.Date() nextYear := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: Years{now.Year(), nextYear.Year()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} st := at.GetNextStartTime() expected := time.Date(nextYear.Year(), 1, 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -209,7 +209,7 @@ func TestActionTimingHourYears(t *testing.T) { if now.After(testTime) { year = nextYear.Year() } - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime() expected := time.Date(year, m, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -236,8 +236,8 @@ func TestActionTimingHourMonthdaysYear(t *testing.T) { } at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{now.Year(), nextYear.Year()}, - MonthDays: MonthDays{now.Day(), tomorrow.Day()}, + Years: utils.Years{now.Year(), nextYear.Year()}, + MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00", }, }} @@ -275,9 +275,9 @@ func TestActionTimingHourMonthdaysMonthYear(t *testing.T) { } at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{now.Year(), nextYear.Year()}, - Months: Months{now.Month(), nextMonth.Month()}, - MonthDays: MonthDays{now.Day(), tomorrow.Day()}, + Years: utils.Years{now.Year(), nextYear.Year()}, + Months: utils.Months{now.Month(), nextMonth.Month()}, + MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00", }, }} @@ -294,9 +294,9 @@ func TestActionTimingFirstOfTheYear(t *testing.T) { nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{nextYear.Year()}, - Months: Months{time.January}, - MonthDays: MonthDays{1}, + Years: utils.Years{nextYear.Year()}, + Months: utils.Months{time.January}, + MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, }} @@ -313,7 +313,7 @@ func TestActionTimingFirstMonthOfTheYear(t *testing.T) { nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Months: Months{time.January}, + Months: utils.Months{time.January}, }, }} st := at.GetNextStartTime() @@ -367,18 +367,18 @@ func TestActionTimingLogFunction(t *testing.T) { func TestActionTimingPriotityListSortByWeight(t *testing.T) { at1 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{2100}, - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{1}, + Years: utils.Years{2100}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, Weight: 20, }} at2 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{2100}, - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{2}, + Years: utils.Years{2100}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{2}, StartTime: "00:00:00", }, Weight: 10, @@ -395,8 +395,8 @@ func TestActionTimingPriotityListWeight(t *testing.T) { at1 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, }, @@ -405,8 +405,8 @@ func TestActionTimingPriotityListWeight(t *testing.T) { at2 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, }, @@ -871,9 +871,9 @@ func TestActionTriggerLogging(t *testing.T) { func TestActionTimingLogging(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ - Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, - WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + WeekDays: utils.WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, StartTime: "18:00:00", EndTime: "00:00:00", }, diff --git a/engine/calldesc.go b/engine/calldesc.go index 2b21e40b5..6259016e3 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -161,13 +161,15 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int if err != nil || rp == nil { return err } - if err = rp.GetRatingPlansForPrefix(cd); err != nil { + if err = rp.GetRatingPlansForPrefix(cd); err != nil || !cd.continousRatingInfos() { // try rating profile fallback - if len(rp.FallbackKeys) > 0 { - recursionDepth++ - for _, fbk := range rp.FallbackKeys { - if err := cd.getRatingPlansForPrefix(fbk, recursionDepth); err == nil { - return err + for _, ri := range cd.RatingInfos { + if len(ri.FallbackKeys) > 0 { + recursionDepth++ + for _, fbk := range ri.FallbackKeys { + if err := cd.getRatingPlansForPrefix(fbk, recursionDepth); err == nil { + return err + } } } } diff --git a/engine/dateseries.go b/engine/dateseries.go deleted file mode 100644 index fca2cc4b1..000000000 --- a/engine/dateseries.go +++ /dev/null @@ -1,272 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2013 ITsysCOM - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -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 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package engine - -import ( - "fmt" - "sort" - "strconv" - "strings" - "time" -) - -// Defines years days series -type Years []int - -func (ys Years) Sort() { - sort.Sort(ys) -} - -func (ys Years) Len() int { - return len(ys) -} - -func (ys Years) Swap(i, j int) { - ys[i], ys[j] = ys[j], ys[i] -} - -func (ys Years) Less(j, i int) bool { - return ys[j] < ys[i] -} - -// Return true if the specified date is inside the series -func (ys Years) Contains(year int) (result bool) { - result = false - for _, yss := range ys { - if yss == year { - result = true - break - } - } - return -} - -// Parse Years elements from string separated by sep. -func (ys *Years) Parse(input, sep string) { - switch input { - case "*any", "": - *ys = []int{} - default: - elements := strings.Split(input, sep) - for _, yss := range elements { - if year, err := strconv.Atoi(yss); err == nil { - *ys = append(*ys, year) - } - } - } -} - -func (ys Years) Serialize(sep string) string { - if len(ys) == 0 { - return "*any" - } - var yStr string - for idx, yr := range ys { - if idx != 0 { - yStr = fmt.Sprintf("%s%s%d", yStr, sep, yr) - } else { - yStr = strconv.Itoa(yr) - } - } - return yStr -} - -// Defines months series -type Months []time.Month - -func (m Months) Sort() { - sort.Sort(m) -} - -func (m Months) Len() int { - return len(m) -} - -func (m Months) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -func (m Months) Less(j, i int) bool { - return m[j] < m[i] -} - -// Return true if the specified date is inside the series -func (m Months) Contains(month time.Month) (result bool) { - for _, ms := range m { - if ms == month { - result = true - break - } - } - return -} - -// Loades Month elemnents from a string separated by sep. -func (m *Months) Parse(input, sep string) { - switch input { - case "*any", "": // Apier cannot receive empty string, hence using meta-tag - *m = []time.Month{} - default: - elements := strings.Split(input, sep) - for _, ms := range elements { - if month, err := strconv.Atoi(ms); err == nil { - *m = append(*m, time.Month(month)) - } - } - } -} - -// Dumps the months in a serialized string, similar to the one parsed -func (m Months) Serialize(sep string) string { - if len(m) == 0 { - return "*any" - } - var mStr string - for idx, mt := range m { - if idx != 0 { - mStr = fmt.Sprintf("%s%s%d", mStr, sep, mt) - } else { - mStr = strconv.Itoa(int(mt)) - } - } - return mStr -} - -// Defines month days series -type MonthDays []int - -func (md MonthDays) Sort() { - sort.Sort(md) -} - -func (md MonthDays) Len() int { - return len(md) -} - -func (md MonthDays) Swap(i, j int) { - md[i], md[j] = md[j], md[i] -} - -func (md MonthDays) Less(j, i int) bool { - return md[j] < md[i] -} - -// Return true if the specified date is inside the series -func (md MonthDays) Contains(monthDay int) (result bool) { - result = false - for _, mds := range md { - if mds == monthDay { - result = true - break - } - } - return -} - -// Parse MonthDay elements from string separated by sep. -func (md *MonthDays) Parse(input, sep string) { - switch input { - case "*any", "": - *md = []int{} - default: - elements := strings.Split(input, sep) - for _, mds := range elements { - if day, err := strconv.Atoi(mds); err == nil { - *md = append(*md, day) - } - } - } -} - -// Dumps the month days in a serialized string, similar to the one parsed -func (md MonthDays) Serialize(sep string) string { - if len(md) == 0 { - return "*any" - } - var mdsStr string - for idx, mDay := range md { - if idx != 0 { - mdsStr = fmt.Sprintf("%s%s%d", mdsStr, sep, mDay) - } else { - mdsStr = strconv.Itoa(mDay) - } - } - return mdsStr -} - -// Defines week days series -type WeekDays []time.Weekday - -func (wd WeekDays) Sort() { - sort.Sort(wd) -} - -func (wd WeekDays) Len() int { - return len(wd) -} - -func (wd WeekDays) Swap(i, j int) { - wd[i], wd[j] = wd[j], wd[i] -} - -func (wd WeekDays) Less(j, i int) bool { - return wd[j] < wd[i] -} - -// Return true if the specified date is inside the series -func (wd WeekDays) Contains(weekDay time.Weekday) (result bool) { - result = false - for _, wds := range wd { - if wds == weekDay { - result = true - break - } - } - return -} - -func (wd *WeekDays) Parse(input, sep string) { - switch input { - case "*any", "": - *wd = []time.Weekday{} - default: - elements := strings.Split(input, sep) - for _, wds := range elements { - if day, err := strconv.Atoi(wds); err == nil { - *wd = append(*wd, time.Weekday(day%7)) // %7 for sunday = 7 normalization - } - } - } -} - -// Dumps the week days in a serialized string, similar to the one parsed -func (wd WeekDays) Serialize(sep string) string { - if len(wd) == 0 { - return "*any" - } - var wdStr string - for idx, d := range wd { - if idx != 0 { - wdStr = fmt.Sprintf("%s%s%d", wdStr, sep, d) - } else { - wdStr = strconv.Itoa(int(d)) - } - } - return wdStr -} diff --git a/engine/dateseries_test.go b/engine/dateseries_test.go deleted file mode 100644 index 11c6110ad..000000000 --- a/engine/dateseries_test.go +++ /dev/null @@ -1,149 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2013 ITsysCOM - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -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 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package engine - -import ( - "encoding/json" - "reflect" - "testing" - "time" -) - -func TestMonthStoreRestoreJson(t *testing.T) { - m := Months{5, 6, 7, 8} - r, _ := json.Marshal(m) - if string(r) != "[5,6,7,8]" { - t.Errorf("Error serializing months: %v", string(r)) - } - o := Months{} - json.Unmarshal(r, &o) - if !reflect.DeepEqual(o, m) { - t.Errorf("Expected %v was %v", m, o) - } -} - -func TestMonthDayStoreRestoreJson(t *testing.T) { - md := MonthDays{24, 25, 26} - r, _ := json.Marshal(md) - if string(r) != "[24,25,26]" { - t.Errorf("Error serializing month days: %v", string(r)) - } - o := MonthDays{} - json.Unmarshal(r, &o) - if !reflect.DeepEqual(o, md) { - t.Errorf("Expected %v was %v", md, o) - } -} - -func TestWeekDayStoreRestoreJson(t *testing.T) { - wd := WeekDays{time.Saturday, time.Sunday} - r, _ := json.Marshal(wd) - if string(r) != "[6,0]" { - t.Errorf("Error serializing week days: %v", string(r)) - } - o := WeekDays{} - json.Unmarshal(r, &o) - if !reflect.DeepEqual(o, wd) { - t.Errorf("Expected %v was %v", wd, o) - } -} - -func TestYearsSerialize(t *testing.T) { - ys := &Years{} - yString := ys.Serialize(";") - expectString := "*any" - if expectString != yString { - t.Errorf("Expected: %s, got: %s", expectString, yString) - } - ys2 := &Years{2012} - yString2 := ys2.Serialize(";") - expectString2 := "2012" - if expectString2 != yString2 { - t.Errorf("Expected: %s, got: %s", expectString2, yString2) - } - ys3 := &Years{2013, 2014, 2015} - yString3 := ys3.Serialize(";") - expectString3 := "2013;2014;2015" - if expectString3 != yString3 { - t.Errorf("Expected: %s, got: %s", expectString3, yString3) - } -} - -func TestMonthsSerialize(t *testing.T) { - mths := &Months{} - mString := mths.Serialize(";") - expectString := "*any" - if expectString != mString { - t.Errorf("Expected: %s, got: %s", expectString, mString) - } - mths2 := &Months{time.January} - mString2 := mths2.Serialize(";") - expectString2 := "1" - if expectString2 != mString2 { - t.Errorf("Expected: %s, got: %s", expectString2, mString2) - } - mths3 := &Months{time.January, time.December} - mString3 := mths3.Serialize(";") - expectString3 := "1;12" - if expectString3 != mString3 { - t.Errorf("Expected: %s, got: %s", expectString3, mString3) - } -} - -func TestMonthDaysSerialize(t *testing.T) { - mds := &MonthDays{} - mdsString := mds.Serialize(";") - expectString := "*any" - if expectString != mdsString { - t.Errorf("Expected: %s, got: %s", expectString, mdsString) - } - mds2 := &MonthDays{1} - mdsString2 := mds2.Serialize(";") - expectString2 := "1" - if expectString2 != mdsString2 { - t.Errorf("Expected: %s, got: %s", expectString2, mdsString2) - } - mds3 := &MonthDays{1, 2, 3, 4, 5} - mdsString3 := mds3.Serialize(";") - expectString3 := "1;2;3;4;5" - if expectString3 != mdsString3 { - t.Errorf("Expected: %s, got: %s", expectString3, mdsString3) - } -} - -func TestWeekDaysSerialize(t *testing.T) { - wds := &WeekDays{} - wdsString := wds.Serialize(";") - expectString := "*any" - if expectString != wdsString { - t.Errorf("Expected: %s, got: %s", expectString, wdsString) - } - wds2 := &WeekDays{time.Monday} - wdsString2 := wds2.Serialize(";") - expectString2 := "1" - if expectString2 != wdsString2 { - t.Errorf("Expected: %s, got: %s", expectString2, wdsString2) - } - wds3 := &WeekDays{time.Monday, time.Saturday, time.Sunday} - wdsString3 := wds3.Serialize(";") - expectString3 := "1;6;0" - if expectString3 != wdsString3 { - t.Errorf("Expected: %s, got: %s", expectString3, wdsString3) - } -} diff --git a/engine/loader_csv.go b/engine/loader_csv.go index e3447ed66..2759eca48 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -38,9 +38,9 @@ type CSVReader struct { actionsTriggers map[string][]*ActionTrigger accountActions []*UserBalance destinations []*Destination - timings map[string]*Timing - rates map[string][]*LoadRate - destinationRates map[string][]*DestinationRate + timings map[string]*utils.TPTiming + rates map[string]*utils.TPRate + destinationRates map[string]*utils.TPDestinationRate ratingPlans map[string]*RatingPlan ratingProfiles map[string]*RatingProfile // file names @@ -55,9 +55,9 @@ func NewFileCSVReader(storage DataStorage, sep rune, destinationsFn, timingsFn, c.actions = make(map[string][]*Action) c.actionsTimings = make(map[string][]*ActionTiming) c.actionsTriggers = make(map[string][]*ActionTrigger) - c.rates = make(map[string][]*LoadRate) - c.destinationRates = make(map[string][]*DestinationRate) - c.timings = make(map[string]*Timing) + c.rates = make(map[string]*utils.TPRate) + c.destinationRates = make(map[string]*utils.TPDestinationRate) + c.timings = make(map[string]*utils.TPTiming) c.ratingPlans = make(map[string]*RatingPlan) c.ratingProfiles = make(map[string]*RatingProfile) c.readerFunc = openFileCSVReader @@ -236,7 +236,7 @@ func (csvr *CSVReader) LoadRates() (err error) { for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tag := record[0] - var r *LoadRate + var r *utils.TPRate r, err = NewLoadRate(record[0], record[1], record[2], record[3], record[4], record[5], record[6], record[7]) if err != nil { return err @@ -244,11 +244,14 @@ func (csvr *CSVReader) LoadRates() (err error) { // same tag only to create rate groups existingRates, exists := csvr.rates[tag] if exists { - if err := existingRates[len(existingRates)-1].ValidNextGroup(r); err != nil { + rss := existingRates.RateSlots + if err := ValidNextGroup(rss[len(rss)-1], r.RateSlots[0]); err != nil { return err } + csvr.rates[tag].RateSlots = append(csvr.rates[tag].RateSlots, r.RateSlots[0]) + } else { + csvr.rates[tag] = r } - csvr.rates[tag] = append(csvr.rates[tag], r) } return } @@ -283,13 +286,22 @@ func (csvr *CSVReader) LoadDestinationRates() (err error) { return fmt.Errorf("Could not get destination for tag %v", record[1]) } } - dr := &DestinationRate{ - Tag: tag, - DestinationsTag: record[1], - rates: r, + dr := &utils.TPDestinationRate{ + DestinationRateId: tag, + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: record[1], + Rate: r, + }, + }, } - - csvr.destinationRates[tag] = append(csvr.destinationRates[tag], dr) + existingDR, exists := csvr.destinationRates[tag] + if exists { + existingDR.DestinationRates = append(existingDR.DestinationRates, dr.DestinationRates[0]) + } else { + existingDR = dr + } + csvr.destinationRates[tag] = existingDR } return } @@ -314,14 +326,14 @@ func (csvr *CSVReader) LoadRatingPlans() (err error) { if !exists { return errors.New(fmt.Sprintf("Could not find destination rate for tag %v", record[1])) } - drt := NewDestinationRateTiming(t, record[3]) + rpl := NewRatingPlan(t, record[3]) plan, exists := csvr.ratingPlans[tag] if !exists { plan = &RatingPlan{Id: tag} csvr.ratingPlans[tag] = plan } - for _, dr := range drs { - plan.AddRateInterval(dr.DestinationsTag, drt.GetRateInterval(dr)) + for _, dr := range drs.DestinationRates { + plan.AddRateInterval(dr.DestinationId, GetRateInterval(rpl, dr)) } } return diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 1e1ed0124..3e41256ce 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -190,45 +190,45 @@ func TestLoadTimimgs(t *testing.T) { t.Error("Failed to load timings: ", csvr.timings) } timing := csvr.timings["WORKDAYS_00"] - if !reflect.DeepEqual(timing, &Timing{ + if !reflect.DeepEqual(timing, &utils.TPTiming{ Id: "WORKDAYS_00", - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{1, 2, 3, 4, 5}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", }) { t.Error("Error loading timing: ", timing) } timing = csvr.timings["WORKDAYS_18"] - if !reflect.DeepEqual(timing, &Timing{ + if !reflect.DeepEqual(timing, &utils.TPTiming{ Id: "WORKDAYS_18", - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{1, 2, 3, 4, 5}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", }) { t.Error("Error loading timing: ", timing) } timing = csvr.timings["WEEKENDS"] - if !reflect.DeepEqual(timing, &Timing{ + if !reflect.DeepEqual(timing, &utils.TPTiming{ Id: "WEEKENDS", - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{time.Saturday, time.Sunday}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", }) { t.Error("Error loading timing: ", timing) } timing = csvr.timings["ONE_TIME_RUN"] - if !reflect.DeepEqual(timing, &Timing{ + if !reflect.DeepEqual(timing, &utils.TPTiming{ Id: "ONE_TIME_RUN", - Years: Years{2012}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{}, + Years: utils.Years{2012}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, StartTime: "*asap", }) { t.Error("Error loading timing: ", timing) @@ -239,24 +239,22 @@ func TestLoadRates(t *testing.T) { if len(csvr.rates) != 9 { t.Error("Failed to load rates: ", csvr.rates) } - rate := csvr.rates["R1"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "R1", + rate := csvr.rates["R1"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 0.2, + Rate: 0.2, RateUnit: time.Minute, RateIncrement: time.Second, GroupIntervalStart: 0, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 2, }) { - t.Error("Error loading rate: ", csvr.rates["R1"][0]) + t.Error("Error loading rate: ", csvr.rates["R1"].RateSlots[0]) } - rate = csvr.rates["R2"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "R2", + rate = csvr.rates["R2"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 0.1, + Rate: 0.1, RateUnit: time.Minute, RateIncrement: time.Second, GroupIntervalStart: 0, @@ -265,11 +263,10 @@ func TestLoadRates(t *testing.T) { }) { t.Error("Error loading rate: ", csvr.rates) } - rate = csvr.rates["R3"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "R3", + rate = csvr.rates["R3"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 0.05, + Rate: 0.05, RateUnit: time.Minute, RateIncrement: time.Second, GroupIntervalStart: 0, @@ -278,11 +275,10 @@ func TestLoadRates(t *testing.T) { }) { t.Error("Error loading rate: ", csvr.rates) } - rate = csvr.rates["R4"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "R4", + rate = csvr.rates["R4"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 1, - Price: 1.0, + Rate: 1.0, RateUnit: time.Second, RateIncrement: time.Second, GroupIntervalStart: 0, @@ -291,11 +287,10 @@ func TestLoadRates(t *testing.T) { }) { t.Error("Error loading rate: ", csvr.rates) } - rate = csvr.rates["R5"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "R5", + rate = csvr.rates["R5"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 0.5, + Rate: 0.5, RateUnit: time.Second, RateIncrement: time.Second, GroupIntervalStart: 0, @@ -305,11 +300,10 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", csvr.rates) } - rate = csvr.rates["LANDLINE_OFFPEAK"][0] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "LANDLINE_OFFPEAK", + rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[0] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 1, + Rate: 1, RateUnit: time.Second, RateIncrement: time.Minute, GroupIntervalStart: 0, @@ -318,11 +312,10 @@ func TestLoadRates(t *testing.T) { }) { t.Errorf("Error loading rate: %+v", rate) } - rate = csvr.rates["LANDLINE_OFFPEAK"][1] - if !reflect.DeepEqual(rate, &LoadRate{ - Tag: "LANDLINE_OFFPEAK", + rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[1] + if !reflect.DeepEqual(rate, &utils.RateSlot{ ConnectFee: 0, - Price: 1, + Rate: 1, RateUnit: time.Second, RateIncrement: time.Second, GroupIntervalStart: 60 * time.Second, @@ -338,96 +331,107 @@ func TestLoadDestinationRates(t *testing.T) { t.Error("Failed to load destinationrates: ", csvr.destinationRates) } drs := csvr.destinationRates["RT_STANDARD"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "RT_STANDARD", - DestinationsTag: "GERMANY", - rates: csvr.rates["R1"], + dr := &utils.TPDestinationRate{ + TPid: "", + DestinationRateId: "RT_STANDARD", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "GERMANY", + Rate: csvr.rates["R1"], + }, + &utils.DestinationRate{ + DestinationId: "GERMANY_O2", + Rate: csvr.rates["R2"], + }, + &utils.DestinationRate{ + DestinationId: "GERMANY_PREMIUM", + Rate: csvr.rates["R2"], + }, }, - &DestinationRate{ - Tag: "RT_STANDARD", - DestinationsTag: "GERMANY_O2", - rates: csvr.rates["R2"], - }, - &DestinationRate{ - Tag: "RT_STANDARD", - DestinationsTag: "GERMANY_PREMIUM", - rates: csvr.rates["R2"], - }, - }) { - t.Error("Error loading destination rate: ", drs) + } + if !reflect.DeepEqual(drs, dr) { + t.Errorf("Error loading destination rate: \n%+v \n%+v", drs, dr) } drs = csvr.destinationRates["RT_DEFAULT"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "RT_DEFAULT", - DestinationsTag: "ALL", - rates: csvr.rates["R2"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "RT_DEFAULT", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "ALL", + Rate: csvr.rates["R2"], + }, }, }) { - t.Error("Error loading destination rate: ", drs) + t.Errorf("Error loading destination rate: %+v", drs) } drs = csvr.destinationRates["RT_STD_WEEKEND"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "RT_STD_WEEKEND", - DestinationsTag: "GERMANY", - rates: csvr.rates["R2"], - }, - &DestinationRate{ - Tag: "RT_STD_WEEKEND", - DestinationsTag: "GERMANY_O2", - rates: csvr.rates["R3"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "RT_STD_WEEKEND", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "GERMANY", + Rate: csvr.rates["R2"], + }, + &utils.DestinationRate{ + DestinationId: "GERMANY_O2", + Rate: csvr.rates["R3"], + }, }, }) { t.Error("Error loading destination rate: ", drs) } drs = csvr.destinationRates["P1"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "P1", - DestinationsTag: "NAT", - rates: csvr.rates["R4"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "P1", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "NAT", + Rate: csvr.rates["R4"], + }, }, }) { t.Error("Error loading destination rate: ", drs) } drs = csvr.destinationRates["P2"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "P2", - DestinationsTag: "NAT", - rates: csvr.rates["R5"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "P2", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "NAT", + Rate: csvr.rates["R5"], + }, }, }) { t.Error("Error loading destination rate: ", drs) } drs = csvr.destinationRates["T1"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "T1", - DestinationsTag: "NAT", - rates: csvr.rates["LANDLINE_OFFPEAK"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "T1", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "NAT", + Rate: csvr.rates["LANDLINE_OFFPEAK"], + }, }, }) { t.Error("Error loading destination rate: ", drs) } drs = csvr.destinationRates["T2"] - if !reflect.DeepEqual(drs, []*DestinationRate{ - &DestinationRate{ - Tag: "T2", - DestinationsTag: "GERMANY", - rates: csvr.rates["GBP_72"], - }, - &DestinationRate{ - Tag: "T2", - DestinationsTag: "GERMANY_O2", - rates: csvr.rates["GBP_70"], - }, - &DestinationRate{ - Tag: "T2", - DestinationsTag: "GERMANY_PREMIUM", - rates: csvr.rates["GBP_71"], + if !reflect.DeepEqual(drs, &utils.TPDestinationRate{ + DestinationRateId: "T2", + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: "GERMANY", + Rate: csvr.rates["GBP_72"], + }, + &utils.DestinationRate{ + DestinationId: "GERMANY_O2", + Rate: csvr.rates["GBP_70"], + }, + &utils.DestinationRate{ + DestinationId: "GERMANY_PREMIUM", + Rate: csvr.rates["GBP_71"], + }, }, }) { t.Error("Error loading destination rate: ", drs) @@ -443,24 +447,24 @@ func TestLoadDestinationRateTimings(t *testing.T) { Id: "STANDARD", Timings: map[string]*RITiming{ "14ae6e41": &RITiming{ - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{1, 2, 3, 4, 5}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", }, "9a6f8e32": &RITiming{ - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{1, 2, 3, 4, 5}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", }, "7181e535": &RITiming{ - Years: Years{}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{time.Saturday, time.Sunday}, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", }, }, @@ -625,10 +629,10 @@ func TestLoadActionTimings(t *testing.T) { UserBalanceIds: []string{"*out:vdf:minitsboy"}, Timing: &RateInterval{ Timing: &RITiming{ - Years: Years{2012}, - Months: Months{}, - MonthDays: MonthDays{}, - WeekDays: WeekDays{}, + Years: utils.Years{2012}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, StartTime: ASAP, }, }, diff --git a/engine/loader_db.go b/engine/loader_db.go index 00c054646..36a246839 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -34,9 +34,9 @@ type DbReader struct { actionsTriggers map[string][]*ActionTrigger accountActions []*UserBalance destinations []*Destination - timings map[string]*Timing - rates map[string][]*LoadRate - destinationRates map[string][]*DestinationRate + timings map[string]*utils.TPTiming + rates map[string]*utils.TPRate + destinationRates map[string]*utils.TPDestinationRate ratingPlans map[string]*RatingPlan ratingProfiles map[string]*RatingProfile } @@ -153,15 +153,15 @@ func (dbr *DbReader) LoadDestinationRates() (err error) { return err } for _, drs := range dbr.destinationRates { - for _, dr := range drs { - rates, exists := dbr.rates[dr.RateTag] + for _, dr := range drs.DestinationRates { + rate, exists := dbr.rates[dr.RateId] if !exists { - return errors.New(fmt.Sprintf("Could not find rate for tag %v", dr.RateTag)) + return errors.New(fmt.Sprintf("Could not find rate for tag %v", dr.RateId)) } - dr.rates = rates + dr.Rate = rate destinationExists := false for _, d := range dbr.destinations { - if d.Id == dr.DestinationsTag { + if d.Id == dr.DestinationId { destinationExists = true break } @@ -183,24 +183,24 @@ func (dbr *DbReader) LoadRatingPlans() error { if err != nil { return err } - for _, drt := range drts { - t, exists := dbr.timings[drt.TimingTag] + for _, drt := range drts.RatingPlans { + t, exists := dbr.timings[drt.TimingId] if !exists { - return errors.New(fmt.Sprintf("Could not get timing for tag %v", drt.TimingTag)) + return errors.New(fmt.Sprintf("Could not get timing for tag %v", drt.TimingId)) } - drt.timing = t - drs, exists := dbr.destinationRates[drt.DestinationRatesTag] + drt.Timing = t + drs, exists := dbr.destinationRates[drt.DestRatesId] if !exists { - return errors.New(fmt.Sprintf("Could not find destination rate for tag %v", drt.DestinationRatesTag)) + return errors.New(fmt.Sprintf("Could not find destination rate for tag %v", drt.DestRatesId)) } - plan, exists := dbr.ratingPlans[drt.Tag] + plan, exists := dbr.ratingPlans[drts.RatingPlanId] if !exists { - plan = &RatingPlan{Id: drt.Tag} - dbr.ratingPlans[drt.Tag] = plan + plan = &RatingPlan{Id: drts.RatingPlanId} + dbr.ratingPlans[drts.RatingPlanId] = plan } - for _, dr := range drs { - plan.AddRateInterval(dr.DestinationsTag, drt.GetRateInterval(dr)) + for _, dr := range drs.DestinationRates { + plan.AddRateInterval(dr.DestinationId, GetRateInterval(drt, dr)) } } return nil @@ -212,11 +212,12 @@ func (dbr *DbReader) LoadRatingProfiles() error { return err } for _, rp := range rpfs { + rpf := &RatingProfile{Id: rp.RatingProfileId} at, err := utils.ParseDate(rp.ActivationTime) if err != nil { return errors.New(fmt.Sprintf("Cannot parse activation time from %v", rp.ActivationTime)) } - _, exists := dbr.ratingPlans[rp.DestRatesTimingTag] + _, exists := dbr.ratingPlans[rp.RatingPlanId] if !exists { if dbExists, err := dbr.dataDb.ExistsData(RATING_PLAN, rp.DestRatesTimingTag); err != nil { return err @@ -224,13 +225,13 @@ func (dbr *DbReader) LoadRatingProfiles() error { return errors.New(fmt.Sprintf("Could not load rating plans for tag: %v", rp.DestRatesTimingTag)) } } - rp.RatingPlanActivations = append(rp.RatingPlanActivations, + rpf.RatingPlanActivations = append(rpf.RatingPlanActivations, &RatingPlanActivation{ ActivationTime: at, - RatingPlanId: rp.DestRatesTimingTag, + RatingPlanId: rp.RatingPlanId, FallbackKeys: rp.FallbackKeys, }) - dbr.ratingProfiles[rp.Id] = rp + dbr.ratingProfiles[rpf.Id] = rpf } return nil } @@ -238,31 +239,30 @@ func (dbr *DbReader) LoadRatingProfiles() error { func (dbr *DbReader) LoadRatingPlanByTag(tag string) error { ratingPlan := &RatingPlan{} rps, err := dbr.storDb.GetTpRatingPlans(dbr.tpid, tag) - if err != nil || len(rps) == 0 { + if err != nil || len(rps.RatingPlans) == 0 { return fmt.Errorf("No DestRateTimings profile with id %s: %v", tag, err) } - for _, rp := range rps { - + for _, rp := range rps.RatingPlans { Logger.Debug(fmt.Sprintf("Rating Plan: %v", rp)) - tm, err := dbr.storDb.GetTpTimings(dbr.tpid, rp.TimingTag) + tm, err := dbr.storDb.GetTpTimings(dbr.tpid, rp.TimingId) Logger.Debug(fmt.Sprintf("Timing: %v", tm)) if err != nil || len(tm) == 0 { - return fmt.Errorf("No Timings profile with id %s: %v", rp.TimingTag, err) + return fmt.Errorf("No Timings profile with id %s: %v", rp.TimingId, err) } - rp.timing = tm[rp.TimingTag] - drm, err := dbr.storDb.GetTpDestinationRates(dbr.tpid, rp.DestinationRatesTag) + rp.Timing = tm[rp.TimingId] + drm, err := dbr.storDb.GetTpDestinationRates(dbr.tpid, rp.DestRatesId) if err != nil || len(drm) == 0 { - return fmt.Errorf("No DestinationRates profile with id %s: %v", rp.DestinationRatesTag, err) + return fmt.Errorf("No DestinationRates profile with id %s: %v", rp.DestRatesId, err) } - for _, drate := range drm[rp.DestinationRatesTag] { + for _, drate := range drm[rp.DestRatesId].DestinationRates { Logger.Debug(fmt.Sprintf("Destination rate: %v", drate)) - rt, err := dbr.storDb.GetTpRates(dbr.tpid, drate.RateTag) + rt, err := dbr.storDb.GetTpRates(dbr.tpid, drate.RateId) if err != nil || len(rt) == 0 { - return fmt.Errorf("No Rates profile with id %s: %v", drate.RateTag, err) + return fmt.Errorf("No Rates profile with id %s: %v", drate.RateId, err) } Logger.Debug(fmt.Sprintf("Rate: %v", rt)) - drate.rates = rt[drate.RateTag] - ratingPlan.AddRateInterval(drate.DestinationsTag, rp.GetRateInterval(drate)) + drate.Rate = rt[drate.RateId] + ratingPlan.AddRateInterval(drate.DestinationId, GetRateInterval(rp, drate)) dms, err := dbr.storDb.GetTpDestinations(dbr.tpid, drate.DestinationsTag) if err != nil { @@ -275,7 +275,7 @@ func (dbr *DbReader) LoadRatingPlanByTag(tag string) error { } continue } - Logger.Debug(fmt.Sprintf("Tag: %s Destinations: %v", drate.DestinationsTag, dms)) + Logger.Debug(fmt.Sprintf("Tag: %s Destinations: %v", drate.DestinationId, dms)) for _, destination := range dms { Logger.Debug(fmt.Sprintf("Destination: %v", destination)) dbr.dataDb.SetDestination(destination) @@ -287,16 +287,16 @@ func (dbr *DbReader) LoadRatingPlanByTag(tag string) error { func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { resultRatingProfile := &RatingProfile{} - rpm, err := dbr.storDb.GetTpRatingProfiles(dbr.tpid, tag) - if err != nil || len(rpm) == 0 { + rpfs, err := dbr.storDb.GetTpRatingProfiles(dbr.tpid, tag) + if err != nil || len(rpfs) == 0 { return fmt.Errorf("No RateProfile with id %s: %v", tag, err) } - for _, ratingProfile := range rpm { - Logger.Debug(fmt.Sprintf("Rating profile: %v", rpm)) - resultRatingProfile.Id = ratingProfile.Id // idem - at, err := utils.ParseDate(ratingProfile.ActivationTime) + for _, rp := range rpfs { + Logger.Debug(fmt.Sprintf("Rating profile: %v", rpfs)) + resultRatingProfile.Id = rp.RatingProfileId + at, err := utils.ParseDate(rp.ActivationTime) if err != nil { - return fmt.Errorf("Cannot parse activation time from %v", ratingProfile.ActivationTime) + return fmt.Errorf("Cannot parse activation time from %v", rp.ActivationTime) } // Check if referenced RatingPlan exists _, exists := dbr.ratingPlans[ratingProfile.DestRatesTimingTag] @@ -307,7 +307,7 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { return errors.New(fmt.Sprintf("Could not load rating plans for tag: %v", ratingProfile.DestRatesTimingTag)) } } - resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations, &RatingPlanActivation{at, ratingProfile.DestRatesTimingTag, ratingProfile.FallbackKeys}) + resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations, &RatingPlanActivation{at, rp.RatingPlanId, rp.FallbackKeys}) } return dbr.dataDb.SetRatingProfile(resultRatingProfile) } @@ -323,18 +323,18 @@ func (dbr *DbReader) LoadActionTimings() (err error) { return err } for tag, ats := range atsMap { - for _, at := range ats { + for _, at := range ats.ActionTimings { _, exists := dbr.actions[at.ActionsId] if !exists { return errors.New(fmt.Sprintf("ActionTiming: Could not load the action for tag: %v", at.ActionsId)) } - t, exists := dbr.timings[at.Tag] + t, exists := dbr.timings[ats.ActionTimingsId] if !exists { - return errors.New(fmt.Sprintf("ActionTiming: Could not load the timing for tag: %v", at.Tag)) + return errors.New(fmt.Sprintf("ActionTiming: Could not load the timing for tag: %v", ats.ActionTimingsId)) } actTmg := &ActionTiming{ Id: utils.GenUUID(), - Tag: at.Tag, + Tag: ats.ActionTimingsId, Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ @@ -419,23 +419,24 @@ func (dbr *DbReader) LoadAccountActionsByTag(tag string) error { return fmt.Errorf("No ActionTimings with id <%s>", accountAction.ActionTimingsTag) } var actionTimings []*ActionTiming - for _, at := range actionTimingsMap[accountAction.ActionTimingsTag] { + ats := actionTimingsMap[accountAction.ActionTimingsTag] + for _, at := range ats.ActionTimings { existsAction, err := dbr.storDb.ExistsTPActions(dbr.tpid, at.ActionsId) if err != nil { return err } else if !existsAction { return fmt.Errorf("No Action with id <%s>", at.ActionsId) } - timingsMap, err := dbr.storDb.GetTpTimings(dbr.tpid, at.Tag) + timingsMap, err := dbr.storDb.GetTpTimings(dbr.tpid, ats.ActionTimingsId) if err != nil { return err } else if len(timingsMap) == 0 { - return fmt.Errorf("No Timing with id <%s>", at.Tag) + return fmt.Errorf("No Timing with id <%s>", ats.ActionTimingsId) } - t := timingsMap[at.Tag] + t := timingsMap[ats.ActionTimingsId] actTmg := &ActionTiming{ Id: utils.GenUUID(), - Tag: at.Tag, + Tag: ats.ActionTimingsId, Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ @@ -458,7 +459,7 @@ func (dbr *DbReader) LoadAccountActionsByTag(tag string) error { } } if !found { - at.UserBalanceIds = append(exitingUserBalanceIds, id) + actTmg.UserBalanceIds = append(exitingUserBalanceIds, id) } actionTimings = append(actionTimings, actTmg) } diff --git a/engine/loader_helpers.go b/engine/loader_helpers.go index 98c7b4e4b..b5b2a8038 100644 --- a/engine/loader_helpers.go +++ b/engine/loader_helpers.go @@ -47,15 +47,15 @@ type TPLoader interface { WriteToDatabase(bool, bool) error } -type LoadRate struct { +/*type LoadRate struct { Tag string ConnectFee, Price float64 RateUnit, RateIncrement, GroupIntervalStart time.Duration RoundingMethod string RoundingDecimals int -} +}*/ -func NewLoadRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterval, roundingMethod, roundingDecimals string) (r *LoadRate, err error) { +func NewLoadRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterval, roundingMethod, roundingDecimals string) (r *utils.TPRate, err error) { cf, err := strconv.ParseFloat(connectFee, 64) if err != nil { log.Printf("Error parsing connect fee from: %v", connectFee) @@ -87,20 +87,24 @@ func NewLoadRate(tag, connectFee, price, ratedUnits, rateIncrements, groupInterv return } - r = &LoadRate{ - Tag: tag, - ConnectFee: cf, - Price: p, - GroupIntervalStart: gi, - RateUnit: ru, - RateIncrement: ri, - RoundingMethod: roundingMethod, - RoundingDecimals: rd, + r = &utils.TPRate{ + RateId: tag, + RateSlots: []*utils.RateSlot{ + &utils.RateSlot{ + ConnectFee: cf, + Rate: p, + GroupIntervalStart: gi, + RateUnit: ru, + RateIncrement: ri, + RoundingMethod: roundingMethod, + RoundingDecimals: rd, + }, + }, } return } -func (present *LoadRate) ValidNextGroup(next *LoadRate) error { +func ValidNextGroup(present, next *utils.RateSlot) error { if next.GroupIntervalStart <= present.GroupIntervalStart { return errors.New(fmt.Sprintf("Next rate group interval start must be heigher than the last one: %#v", next)) } @@ -113,24 +117,8 @@ func (present *LoadRate) ValidNextGroup(next *LoadRate) error { return nil } -type DestinationRate struct { - Tag string - DestinationsTag string - RateTag string // intermediary used when loading from db - rates []*LoadRate -} - -type Timing struct { - Id string - Years Years - Months Months - MonthDays MonthDays - WeekDays WeekDays - StartTime string -} - -func NewTiming(timingInfo ...string) (rt *Timing) { - rt = &Timing{} +func NewTiming(timingInfo ...string) (rt *utils.TPTiming) { + rt = &utils.TPTiming{} rt.Id = timingInfo[0] rt.Years.Parse(timingInfo[1], ";") rt.Months.Parse(timingInfo[2], ";") @@ -140,47 +128,39 @@ func NewTiming(timingInfo ...string) (rt *Timing) { return } -type DestinationRateTiming struct { - Tag string - DestinationRatesTag string // intermediary used when loading from db - Weight float64 - TimingTag string // intermediary used when loading from db - timing *Timing -} - -func NewDestinationRateTiming(timing *Timing, weight string) (drt *DestinationRateTiming) { +func NewRatingPlan(timing *utils.TPTiming, weight string) (drt *utils.RatingPlan) { w, err := strconv.ParseFloat(weight, 64) if err != nil { log.Printf("Error parsing weight unit from: %v", weight) return } - drt = &DestinationRateTiming{ - timing: timing, + drt = &utils.RatingPlan{ + Timing: timing, Weight: w, } return } -func (drt *DestinationRateTiming) GetRateInterval(dr *DestinationRate) (i *RateInterval) { +func GetRateInterval(rpl *utils.RatingPlan, dr *utils.DestinationRate) (i *RateInterval) { i = &RateInterval{ Timing: &RITiming{ - Years: drt.timing.Years, - Months: drt.timing.Months, - MonthDays: drt.timing.MonthDays, - WeekDays: drt.timing.WeekDays, - StartTime: drt.timing.StartTime, + Years: rpl.Timing.Years, + Months: rpl.Timing.Months, + MonthDays: rpl.Timing.MonthDays, + WeekDays: rpl.Timing.WeekDays, + StartTime: rpl.Timing.StartTime, }, - Weight: drt.Weight, + Weight: rpl.Weight, Rating: &RIRate{ - ConnectFee: dr.rates[0].ConnectFee, - RoundingMethod: dr.rates[0].RoundingMethod, - RoundingDecimals: dr.rates[0].RoundingDecimals, + ConnectFee: dr.Rate.RateSlots[0].ConnectFee, + RoundingMethod: dr.Rate.RateSlots[0].RoundingMethod, + RoundingDecimals: dr.Rate.RateSlots[0].RoundingDecimals, }, } - for _, rl := range dr.rates { + for _, rl := range dr.Rate.RateSlots { i.Rating.Rates = append(i.Rating.Rates, &Rate{ GroupIntervalStart: rl.GroupIntervalStart, - Value: rl.Price, + Value: rl.Rate, RateIncrement: rl.RateIncrement, RateUnit: rl.RateUnit, }) diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 50b0cf771..1f4beda43 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -39,10 +39,10 @@ type RateInterval struct { // Separate structure used for rating plan size optimization type RITiming struct { - Years Years - Months Months - MonthDays MonthDays - WeekDays WeekDays + Years utils.Years + Months utils.Months + MonthDays utils.MonthDays + WeekDays utils.WeekDays StartTime, EndTime string // ##:##:## format } diff --git a/engine/rateinterval_test.go b/engine/rateinterval_test.go index 4f195c0d8..de24999a3 100644 --- a/engine/rateinterval_test.go +++ b/engine/rateinterval_test.go @@ -27,7 +27,7 @@ import ( func TestRateIntervalSimpleContains(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ - WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, + WeekDays: utils.WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, StartTime: "18:00:00", EndTime: "", }, @@ -39,7 +39,7 @@ func TestRateIntervalSimpleContains(t *testing.T) { } func TestRateIntervalMonth(t *testing.T) { - i := &RateInterval{Timing: &RITiming{Months: Months{time.February}}} + i := &RateInterval{Timing: &RITiming{Months: utils.Months{time.February}}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.January, 10, 23, 0, 0, 0, time.UTC) if !i.Contains(d, false) { @@ -51,7 +51,7 @@ func TestRateIntervalMonth(t *testing.T) { } func TestRateIntervalMonthDay(t *testing.T) { - i := &RateInterval{Timing: &RITiming{MonthDays: MonthDays{10}}} + i := &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{10}}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 11, 23, 0, 0, 0, time.UTC) if !i.Contains(d, false) { @@ -63,7 +63,7 @@ func TestRateIntervalMonthDay(t *testing.T) { } func TestRateIntervalMonthAndMonthDay(t *testing.T) { - i := &RateInterval{Timing: &RITiming{Months: Months{time.February}, MonthDays: MonthDays{10}}} + i := &RateInterval{Timing: &RITiming{Months: utils.Months{time.February}, MonthDays: utils.MonthDays{10}}} d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 11, 23, 0, 0, 0, time.UTC) d2 := time.Date(2012, time.January, 10, 23, 0, 0, 0, time.UTC) @@ -98,8 +98,8 @@ func TestRateIntervalWeekDays(t *testing.T) { } func TestRateIntervalMonthAndMonthDayAndWeekDays(t *testing.T) { - i := &RateInterval{Timing: &RITiming{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}}} - i2 := &RateInterval{Timing: &RITiming{Months: Months{time.February}, MonthDays: MonthDays{2}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}}} + i := &RateInterval{Timing: &RITiming{Months: utils.Months{time.February}, MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}}} + i2 := &RateInterval{Timing: &RITiming{Months: utils.Months{time.February}, MonthDays: utils.MonthDays{2}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}}} d := time.Date(2012, time.February, 1, 23, 0, 0, 0, time.UTC) d1 := time.Date(2012, time.February, 2, 23, 0, 0, 0, time.UTC) if !i.Contains(d, false) { @@ -139,9 +139,9 @@ func TestRateIntervalHours(t *testing.T) { func TestRateIntervalEverything(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ - Months: Months{time.February}, - Years: Years{2012}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + Years: utils.Years{2012}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} @@ -170,14 +170,14 @@ func TestRateIntervalEverything(t *testing.T) { func TestRateIntervalEqual(t *testing.T) { i1 := &RateInterval{ Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} i2 := &RateInterval{Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} @@ -189,14 +189,14 @@ func TestRateIntervalEqual(t *testing.T) { func TestRateIntervalNotEqual(t *testing.T) { i1 := &RateInterval{ Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}, StartTime: "14:30:00", EndTime: "15:00:00"}} i2 := &RateInterval{Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} @@ -207,15 +207,15 @@ func TestRateIntervalNotEqual(t *testing.T) { func TestRitStrigyfy(t *testing.T) { rit1 := &RITiming{ - Years: Years{}, - Months: Months{time.January, time.February}, - MonthDays: MonthDays{}, + Years: utils.Years{}, + Months: utils.Months{time.January, time.February}, + MonthDays: utils.MonthDays{}, StartTime: "00:00:00", } rit2 := &RITiming{ - Years: Years{}, - Months: Months{time.January, time.February}, - MonthDays: MonthDays{}, + Years: utils.Years{}, + Months: utils.Months{time.January, time.February}, + MonthDays: utils.MonthDays{}, StartTime: "00:00:00", } if rit1.Stringify() != rit2.Stringify() { @@ -286,7 +286,7 @@ func TestRateStrigyfy(t *testing.T) { /*********************************Benchmarks**************************************/ func BenchmarkRateIntervalContainsDate(b *testing.B) { - i := &RateInterval{Timing: &RITiming{Months: Months{time.February}, MonthDays: MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} + i := &RateInterval{Timing: &RITiming{Months: utils.Months{time.February}, MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} d := time.Date(2012, time.February, 1, 14, 30, 0, 0, time.UTC) for x := 0; x < b.N; x++ { i.Contains(d, false) diff --git a/engine/ratingplan_test.go b/engine/ratingplan_test.go index 9e492d717..5be37e5b1 100644 --- a/engine/ratingplan_test.go +++ b/engine/ratingplan_test.go @@ -20,6 +20,7 @@ package engine import ( "encoding/json" + "github.com/cgrates/cgrates/utils" "reflect" "testing" "time" @@ -148,20 +149,20 @@ func TestFallbackNoInfiniteLoopSelf(t *testing.T) { func TestApAddIntervalIfNotPresent(t *testing.T) { i1 := &RateInterval{ Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} i2 := &RateInterval{Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"}} i3 := &RateInterval{Timing: &RITiming{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, WeekDays: []time.Weekday{time.Wednesday}, StartTime: "14:30:00", EndTime: "15:00:00"}} diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index ab7813932..594082f71 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -26,11 +26,8 @@ import ( ) type RatingProfile struct { - Id string - RatingPlanActivations RatingPlanActivations - Tag, Tenant, TOR, Direction, Subject string // used only for loading - DestRatesTimingTag, RatesFallbackSubject, ActivationTime string // used only for loading - FallbackKeys []string // used only for loading + Id string + RatingPlanActivations RatingPlanActivations } type RatingPlanActivation struct { @@ -82,6 +79,7 @@ type RatingInfo struct { MatchedPrefix string ActivationTime time.Time RateIntervals RateIntervalList + FallbackKeys []string } type RatingInfos []*RatingInfo @@ -127,11 +125,11 @@ func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (err error) } } if bestPrecision > 0 { - ris = append(ris, &RatingInfo{rp.Id, cd.Destination[:bestPrecision], rpa.ActivationTime, rps}) + ris = append(ris, &RatingInfo{rp.Id, cd.Destination[:bestPrecision], rpa.ActivationTime, rps, rpa.FallbackKeys}) } else { // mark the end of previous! if len(cd.RatingInfos) > 0 { - ris = append(ris, &RatingInfo{"", "", rpa.ActivationTime, nil}) + ris = append(ris, &RatingInfo{"", "", rpa.ActivationTime, nil, rpa.FallbackKeys}) } } } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 25470c52c..5c7615153 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -104,28 +104,28 @@ type LoadStorage interface { Storage // Apier functions GetTPIds() ([]string, error) - SetTPTiming(string, *Timing) error + SetTPTiming(string, *utils.TPTiming) error ExistsTPTiming(string, string) (bool, error) - GetTPTiming(string, string) (*Timing, error) + GetTPTiming(string, string) (*utils.TPTiming, error) GetTPTimingIds(string) ([]string, error) SetTPDestination(string, *Destination) error ExistsTPDestination(string, string) (bool, error) GetTPDestination(string, string) (*Destination, error) GetTPDestinationIds(string) ([]string, error) ExistsTPRate(string, string) (bool, error) - SetTPRates(string, map[string][]*LoadRate) error + SetTPRates(string, map[string]*utils.TPRate) error GetTPRate(string, string) (*utils.TPRate, error) GetTPRateIds(string) ([]string, error) ExistsTPDestinationRate(string, string) (bool, error) - SetTPDestinationRates(string, map[string][]*DestinationRate) error + SetTPDestinationRates(string, map[string]*utils.TPDestinationRate) error GetTPDestinationRate(string, string) (*utils.TPDestinationRate, error) GetTPDestinationRateIds(string) ([]string, error) ExistsTPRatingPlan(string, string) (bool, error) - SetTPRatingPlans(string, map[string][]*DestinationRateTiming) error + SetTPRatingPlans(string, map[string]*utils.TPRatingPlan) error GetTPRatingPlan(string, string) (*utils.TPRatingPlan, error) GetTPRatingPlanIds(string) ([]string, error) ExistsTPRatingProfile(string, string) (bool, error) - SetTPRatingProfiles(string, map[string][]*RatingProfile) error + SetTPRatingProfiles(string, map[string][]*utils.TPRatingProfile) error GetTPRatingProfile(string, string) (*utils.TPRatingProfile, error) GetTPRatingProfileIds(*utils.AttrTPRatingProfileIds) ([]string, error) ExistsTPActions(string, string) (bool, error) @@ -133,8 +133,8 @@ type LoadStorage interface { GetTPActions(string, string) (*utils.TPActions, error) GetTPActionIds(string) ([]string, error) ExistsTPActionTimings(string, string) (bool, error) - SetTPActionTimings(string, map[string][]*ActionTiming) error - GetTPActionTimings(string, string) (map[string][]*utils.TPActionTimingsRow, error) + SetTPActionTimings(string, map[string]*utils.ApiTPActionTimings) error + GetTPActionTimings(string, string) (map[string]*utils.ApiTPActionTimings, error) GetTPActionTimingIds(string) ([]string, error) ExistsTPActionTriggers(string, string) (bool, error) SetTPActionTriggers(string, map[string][]*ActionTrigger) error @@ -144,13 +144,13 @@ type LoadStorage interface { GetTPAccountActionIds(string) ([]string, error) // loader functions GetTpDestinations(string, string) ([]*Destination, error) - GetTpTimings(string, string) (map[string]*Timing, error) - GetTpRates(string, string) (map[string][]*LoadRate, error) - GetTpDestinationRates(string, string) (map[string][]*DestinationRate, error) - GetTpRatingPlans(string, string) ([]*DestinationRateTiming, error) - GetTpRatingProfiles(string, string) (map[string]*RatingProfile, error) + GetTpTimings(string, string) (map[string]*utils.TPTiming, error) + GetTpRates(string, string) (map[string]*utils.TPRate, error) + GetTpDestinationRates(string, string) (map[string]*utils.TPDestinationRate, error) + GetTpRatingPlans(string, string) (*utils.TPRatingPlan, error) + GetTpRatingProfiles(string, string) (map[string]*utils.TPRatingProfile, error) GetTpActions(string, string) (map[string][]*Action, error) - GetTpActionTimings(string, string) (map[string][]*ActionTiming, error) + GetTpActionTimings(string, string) (map[string]utils.ApiTPActionTimings, error) GetTpActionTriggers(string, string) (map[string][]*ActionTrigger, error) GetTpAccountActions(string, string) (map[string]*AccountAction, error) } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 4fe086aae..24f2da06f 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -64,7 +64,7 @@ func (self *SQLStorage) GetTPIds() ([]string, error) { return ids, nil } -func (self *SQLStorage) SetTPTiming(tpid string, tm *Timing) error { +func (self *SQLStorage) SetTPTiming(tpid string, tm *utils.TPTiming) error { if _, err := self.Db.Exec(fmt.Sprintf("INSERT INTO %s (tpid, tag, years, months, month_days, week_days, time) VALUES('%s','%s','%s','%s','%s','%s','%s')", utils.TBL_TP_TIMINGS, tpid, tm.Id, tm.Years.Serialize(";"), tm.Months.Serialize(";"), tm.MonthDays.Serialize(";"), tm.WeekDays.Serialize(";"), tm.StartTime)); err != nil { @@ -82,7 +82,7 @@ func (self *SQLStorage) ExistsTPTiming(tpid, tmId string) (bool, error) { return exists, nil } -func (self *SQLStorage) GetTPTiming(tpid, tmId string) (*Timing, error) { +func (self *SQLStorage) GetTPTiming(tpid, tmId string) (*utils.TPTiming, error) { var years, months, monthDays, weekDays, time string err := self.Db.QueryRow(fmt.Sprintf("SELECT years, months, month_days, week_days, time FROM %s WHERE tpid='%s' AND tag='%s' LIMIT 1", utils.TBL_TP_TIMINGS, tpid, tmId)).Scan(&years, &months, &monthDays, &weekDays, &time) @@ -193,19 +193,19 @@ func (self *SQLStorage) ExistsTPRate(tpid, rtId string) (bool, error) { return exists, nil } -func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*LoadRate) error { +func (self *SQLStorage) SetTPRates(tpid string, rts map[string]*utils.TPRate) error { if len(rts) == 0 { return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, connect_fee, rate, rate_unit, rate_increment, group_interval_start, rounding_method, rounding_decimals) VALUES ", utils.TBL_TP_RATES) i := 0 for rtId, rtRows := range rts { - for _, rt := range rtRows { + for _, rt := range rtRows.RateSlots { if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s', '%s', %f, %f, %d, %d,%d,'%s', %d)", - tpid, rtId, rt.ConnectFee, rt.Price, rt.RateUnit, rt.RateIncrement, rt.GroupIntervalStart, + tpid, rtId, rt.ConnectFee, rt.Rate, rt.RateUnit, rt.RateIncrement, rt.GroupIntervalStart, rt.RoundingMethod, rt.RoundingDecimals) i++ } @@ -234,8 +234,7 @@ func (self *SQLStorage) GetTPRate(tpid, rtId string) (*utils.TPRate, error) { if err != nil { return nil, err } - rt.RateSlots = append(rt.RateSlots, utils.RateSlot{connectFee, rate, rateUnit.String(), rateIncrement.String(), - groupIntervalStart.String(), roundingMethod, roundingDecimals}) + rt.RateSlots = append(rt.RateSlots, &utils.RateSlot{connectFee, rate, rateUnit, rateIncrement, groupIntervalStart, roundingMethod, roundingDecimals}) } if i == 0 { return nil, nil @@ -275,19 +274,19 @@ func (self *SQLStorage) ExistsTPDestinationRate(tpid, drId string) (bool, error) return exists, nil } -func (self *SQLStorage) SetTPDestinationRates(tpid string, drs map[string][]*DestinationRate) error { +func (self *SQLStorage) SetTPDestinationRates(tpid string, drs map[string]*utils.TPDestinationRate) error { if len(drs) == 0 { return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, destinations_tag, rates_tag) VALUES ", utils.TBL_TP_DESTINATION_RATES) i := 0 for drId, drRows := range drs { - for _, dr := range drRows { + for _, dr := range drRows.DestinationRates { if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s')", - tpid, drId, dr.DestinationsTag, dr.RateTag) + tpid, drId, dr.DestinationId, dr.RateId) i++ } } @@ -312,7 +311,7 @@ func (self *SQLStorage) GetTPDestinationRate(tpid, drId string) (*utils.TPDestin if err != nil { return nil, err } - dr.DestinationRates = append(dr.DestinationRates, utils.DestinationRate{dstTag, ratesTag}) + dr.DestinationRates = append(dr.DestinationRates, &utils.DestinationRate{dstTag, ratesTag, nil}) } if i == 0 { return nil, nil @@ -352,19 +351,19 @@ func (self *SQLStorage) ExistsTPRatingPlan(tpid, drtId string) (bool, error) { return exists, nil } -func (self *SQLStorage) SetTPRatingPlans(tpid string, drts map[string][]*DestinationRateTiming) error { +func (self *SQLStorage) SetTPRatingPlans(tpid string, drts map[string]*utils.TPRatingPlan) error { if len(drts) == 0 { return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid, tag, destrates_tag, timing_tag, weight) VALUES ", utils.TBL_TP_RATING_PLANS) i := 0 for drtId, drtRows := range drts { - for _, drt := range drtRows { + for _, drt := range drtRows.RatingPlans { if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s',%f)", - tpid, drtId, drt.DestinationRatesTag, drt.TimingTag, drt.Weight) + tpid, drtId, drt.DestRatesId, drt.TimingId, drt.Weight) i++ } } @@ -390,7 +389,7 @@ func (self *SQLStorage) GetTPRatingPlan(tpid, drtId string) (*utils.TPRatingPlan if err != nil { return nil, err } - drt.RatingPlans = append(drt.RatingPlans, utils.RatingPlan{drTag, timingTag, weight}) + drt.RatingPlans = append(drt.RatingPlans, &utils.RatingPlan{drTag, timingTag, weight, nil}) } if i == 0 { return nil, nil @@ -430,7 +429,7 @@ func (self *SQLStorage) ExistsTPRatingProfile(tpid, rpId string) (bool, error) { return exists, nil } -func (self *SQLStorage) SetTPRatingProfiles(tpid string, rps map[string][]*RatingProfile) error { +func (self *SQLStorage) SetTPRatingProfiles(tpid string, rps map[string][]*utils.TPRatingProfile) error { if len(rps) == 0 { return nil //Nothing to set } @@ -443,7 +442,7 @@ func (self *SQLStorage) SetTPRatingProfiles(tpid string, rps map[string][]*Ratin qry += "," } qry += fmt.Sprintf("('%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s')", tpid, rpId, rpa.Tenant, rpa.TOR, rpa.Direction, - rpa.Subject, rpa.ActivationTime, rpa.DestRatesTimingTag, rpa.RatesFallbackSubject) + rpa.Subject, rpa.ActivationTime, rpa.RatingPlanId, rpa.FallbackKeys) i++ } @@ -474,9 +473,9 @@ func (self *SQLStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingPr rp.TOR = tor rp.Direction = direction rp.Subject = subject - rp.RatesFallbackSubject = fallbackSubj + rp.FallbackKeys = strings.Split(fallbackSubj, FALLBACK_SEP) } - rp.RatingActivations = append(rp.RatingActivations, utils.RatingActivation{aTime, drtId}) + rp.RatingPlanActivations = append(rp.RatingPlanActivations, &utils.RatingActivation{aTime, drtId}) } if i == 0 { return nil, nil @@ -567,7 +566,7 @@ func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, err if err = rows.Scan(&action, &balanceId, &dir, &units, &expTime, &destId, &rateSubject, &balanceWeight, &extraParameters, &weight); err != nil { return nil, err } - acts.Actions = append(acts.Actions, utils.Action{action, balanceId, dir, units, expTime, destId, rateSubject, balanceWeight, extraParameters, weight}) + acts.Actions = append(acts.Actions, &utils.Action{action, balanceId, dir, units, expTime, destId, rateSubject, balanceWeight, extraParameters, weight}) } if i == 0 { return nil, nil @@ -607,19 +606,19 @@ func (self *SQLStorage) ExistsTPActionTimings(tpid, atId string) (bool, error) { } // Sets actionTimings in sqlDB. Imput is expected in form map[actionTimingId][]rows, eg a full .csv file content -func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string][]*ActionTiming) error { +func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string]utils.ApiTPActionTimings) error { if len(ats) == 0 { return nil //Nothing to set } qry := fmt.Sprintf("INSERT INTO %s (tpid,tag,actions_tag,timing_tag,weight) VALUES ", utils.TBL_TP_ACTION_TIMINGS) i := 0 for atId, atRows := range ats { - for _, at := range atRows { + for _, at := range atRows.ActionTimings { if i != 0 { //Consecutive values after the first will be prefixed with "," as separator qry += "," } qry += fmt.Sprintf("('%s','%s','%s','%s',%f)", - tpid, atId, at.ActionsTag, at.TimingsTag, at.Weight) + tpid, atId, at.ActionsId, at.TimingId, at.Weight) i++ } } @@ -629,8 +628,8 @@ func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string][]*Action return nil } -func (self *SQLStorage) GetTPActionTimings(tpid, atId string) (map[string][]*utils.TPActionTimingsRow, error) { - ats := make(map[string][]*utils.TPActionTimingsRow) +func (self *SQLStorage) GetTPActionTimings(tpid, atId string) (map[string][]*utils.ApiActionTiming, error) { + ats := make(map[string][]*utils.ApiActionTiming) q := fmt.Sprintf("SELECT tag,actions_tag,timing_tag,weight FROM %s WHERE tpid='%s'", utils.TBL_TP_ACTION_TIMINGS, tpid) if atId != "" { q += fmt.Sprintf(" AND tag='%s'", atId) @@ -648,7 +647,7 @@ func (self *SQLStorage) GetTPActionTimings(tpid, atId string) (map[string][]*uti if err = rows.Scan(&tag, &actionsId, &timingId, &weight); err != nil { return nil, err } - ats[tag] = append(ats[tag], &utils.TPActionTimingsRow{actionsId, timingId, weight}) + ats[tag] = append(ats[tag], &utils.ApiActionTiming{actionsId, timingId, weight}) } return ats, nil } @@ -957,8 +956,8 @@ func (self *SQLStorage) GetTpDestinations(tpid, tag string) ([]*Destination, err return dests, nil } -func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string][]*LoadRate, error) { - rts := make(map[string][]*LoadRate) +func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string]*utils.TPRate, error) { + rts := make(map[string]*utils.TPRate) q := fmt.Sprintf("SELECT tag, connect_fee, rate, rate_unit, rate_increment, group_interval_start, rounding_method, rounding_decimals FROM %s WHERE tpid='%s' ", utils.TBL_TP_RATES, tpid) if tag != "" { q += fmt.Sprintf(" AND tag='%s'", tag) @@ -976,30 +975,38 @@ func (self *SQLStorage) GetTpRates(tpid, tag string) (map[string][]*LoadRate, er if err := rows.Scan(&tag, &connect_fee, &rate, &rate_unit, &rate_increment, &group_interval_start, &roundingMethod, &roundingDecimals); err != nil { return nil, err } - r := &LoadRate{ - Tag: tag, - ConnectFee: connect_fee, - Price: rate, - RateUnit: rate_unit, - RateIncrement: rate_increment, - GroupIntervalStart: group_interval_start, - RoundingMethod: roundingMethod, - RoundingDecimals: roundingDecimals, + r := &utils.TPRate{ + RateId: tag, + RateSlots: []*utils.RateSlot{ + &utils.RateSlot{ + ConnectFee: connect_fee, + Rate: rate, + RateUnit: rate_unit, + RateIncrement: rate_increment, + GroupIntervalStart: group_interval_start, + RoundingMethod: roundingMethod, + RoundingDecimals: roundingDecimals, + }, + }, } // same tag only to create rate groups existingRates, exists := rts[tag] if exists { - if err := existingRates[len(existingRates)-1].ValidNextGroup(r); err != nil { + rss := existingRates.RateSlots + if err := ValidNextGroup(rss[len(rss)-1], r.RateSlots[0]); err != nil { return nil, err } + rts[tag].RateSlots = append(rts[tag].RateSlots, r.RateSlots[0]) + } else { + rts[tag] = r + } - rts[tag] = append(rts[tag], r) } return rts, nil } -func (self *SQLStorage) GetTpDestinationRates(tpid, tag string) (map[string][]*DestinationRate, error) { - rts := make(map[string][]*DestinationRate) +func (self *SQLStorage) GetTpDestinationRates(tpid, tag string) (map[string]*utils.TPDestinationRate, error) { + rts := make(map[string]*utils.TPDestinationRate) q := fmt.Sprintf("SELECT * FROM %s WHERE tpid='%s'", utils.TBL_TP_DESTINATION_RATES, tpid) if tag != "" { q += fmt.Sprintf(" AND tag='%s'", tag) @@ -1015,18 +1022,29 @@ func (self *SQLStorage) GetTpDestinationRates(tpid, tag string) (map[string][]*D if err := rows.Scan(&id, &tpid, &tag, &destinations_tag, &rate_tag); err != nil { return nil, err } - dr := &DestinationRate{ - Tag: tag, - DestinationsTag: destinations_tag, - RateTag: rate_tag, + + dr := &utils.TPDestinationRate{ + DestinationRateId: tag, + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: destinations_tag, + RateId: rate_tag, + }, + }, } - rts[tag] = append(rts[tag], dr) + existingDR, exists := rts[tag] + if exists { + existingDR.DestinationRates = append(existingDR.DestinationRates, dr.DestinationRates[0]) + } else { + existingDR = dr + } + rts[tag] = existingDR } return rts, nil } -func (self *SQLStorage) GetTpTimings(tpid, tag string) (map[string]*Timing, error) { - tms := make(map[string]*Timing) +func (self *SQLStorage) GetTpTimings(tpid, tag string) (map[string]*utils.TPTiming, error) { + tms := make(map[string]*utils.TPTiming) q := fmt.Sprintf("SELECT * FROM %s WHERE tpid='%s'", utils.TBL_TP_TIMINGS, tpid) if tag != "" { q += fmt.Sprintf(" AND tag='%s'", tag) @@ -1047,8 +1065,8 @@ func (self *SQLStorage) GetTpTimings(tpid, tag string) (map[string]*Timing, erro return tms, nil } -func (self *SQLStorage) GetTpRatingPlans(tpid, tag string) ([]*DestinationRateTiming, error) { - var rts []*DestinationRateTiming +func (self *SQLStorage) GetTpRatingPlans(tpid, tag string) (*utils.TPRatingPlan, error) { + rts := &utils.TPRatingPlan{RatingPlanId: tag} q := fmt.Sprintf("SELECT * FROM %s WHERE tpid='%s'", utils.TBL_TP_RATING_PLANS, tpid) if tag != "" { q += fmt.Sprintf(" AND tag='%s'", tag) @@ -1065,19 +1083,18 @@ func (self *SQLStorage) GetTpRatingPlans(tpid, tag string) ([]*DestinationRateTi if err := rows.Scan(&id, &tpid, &tag, &destination_rates_tag, &timings_tag, &weight); err != nil { return nil, err } - rt := &DestinationRateTiming{ - Tag: tag, - DestinationRatesTag: destination_rates_tag, - Weight: weight, - TimingTag: timings_tag, + rt := &utils.RatingPlan{ + DestRatesId: destination_rates_tag, + Weight: weight, + TimingId: timings_tag, } - rts = append(rts, rt) + rts.RatingPlans = append(rts.RatingPlans, rt) } return rts, nil } -func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*RatingProfile, error) { - rpfs := make(map[string]*RatingProfile) +func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*utils.TPRatingProfile, error) { + rpfs := make(map[string]*utils.TPRatingProfile) q := fmt.Sprintf("SELECT tag,tenant,tor,direction,subject,activation_time,rating_plan_tag,fallback_subject FROM %s WHERE tpid='%s'", utils.TBL_TP_RATE_PROFILES, tpid) if tag != "" { @@ -1095,11 +1112,11 @@ func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*Ratin } key := fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, subject) rp, ok := rpfs[key] - if !ok || rp.Tag != tag { - rp = &RatingProfile{Id: key, Tag: tag} + if !ok || rp.RatingProfileId != tag { + rp = &utils.TPRatingProfile{RatingProfileId: key, Tag: tag} rpfs[key] = rp } - rp.DestRatesTimingTag = rating_plan_tag + rp.RatingPlanId = rating_plan_tag rp.ActivationTime = activation_time if fallback_subject != "" { for _, fbs := range strings.Split(fallback_subject, ";") { diff --git a/engine/timespans_test.go b/engine/timespans_test.go index e4381fb51..8d1b4b074 100644 --- a/engine/timespans_test.go +++ b/engine/timespans_test.go @@ -54,7 +54,7 @@ func TestRightMargin(t *testing.T) { func TestSplitMiddle(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ - WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, + WeekDays: utils.WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, StartTime: "18:00:00", EndTime: "", }} @@ -123,7 +123,7 @@ func TestLeftMargin(t *testing.T) { } func TestLeftHourMargin(t *testing.T) { - i := &RateInterval{Timing: &RITiming{Months: Months{time.December}, MonthDays: MonthDays{1}, StartTime: "09:00:00"}} + i := &RateInterval{Timing: &RITiming{Months: utils.Months{time.December}, MonthDays: utils.MonthDays{1}, StartTime: "09:00:00"}} t1 := time.Date(2012, time.December, 1, 8, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.December, 1, 9, 20, 0, 0, time.UTC) ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index e1688e0ad..562e6bb61 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -24,6 +24,7 @@ import ( "io/ioutil" "log" "strconv" + "strings" ) // Import tariff plan from csv into storDb @@ -142,7 +143,7 @@ func (self *TPCSVImporter) importRates(fn string) error { if err != nil { return err } - if err := self.StorDb.SetTPRates(self.TPid, map[string][]*LoadRate{record[0]: []*LoadRate{rt}}); err != nil { + if err := self.StorDb.SetTPRates(self.TPid, map[string]*utils.TPRate{record[0]: rt}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } @@ -169,9 +170,17 @@ func (self *TPCSVImporter) importDestinationRates(fn string) error { } continue } - dr := &DestinationRate{record[0], record[1], record[2], nil} + dr := &utils.TPDestinationRate{ + DestinationRateId: record[0], + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: record[1], + RateId: record[2], + }, + }, + } if err := self.StorDb.SetTPDestinationRates(self.TPid, - map[string][]*DestinationRate{dr.Tag: []*DestinationRate{dr}}); err != nil { + map[string]*utils.TPDestinationRate{dr.DestinationRateId: dr}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } @@ -205,12 +214,17 @@ func (self *TPCSVImporter) importRatingPlans(fn string) error { } continue } - drt := &DestinationRateTiming{Tag: record[0], - DestinationRatesTag: record[1], - Weight: weight, - TimingTag: record[2], + drt := &utils.TPRatingPlan{ + RatingPlanId: record[0], + RatingPlans: []*utils.RatingPlan{ + &utils.RatingPlan{ + DestRatesId: record[1], + Weight: weight, + TimingId: record[2], + }, + }, } - if err := self.StorDb.SetTPRatingPlans(self.TPid, map[string][]*DestinationRateTiming{drt.Tag: []*DestinationRateTiming{drt}}); err != nil { + if err := self.StorDb.SetTPRatingPlans(self.TPid, map[string]*utils.TPRatingPlan{drt.RatingPlanId: drt}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } @@ -249,17 +263,17 @@ func (self *TPCSVImporter) importRatingProfiles(fn string) error { if self.ImportId != "" { rpTag += "_" + self.ImportId } - rp := &RatingProfile{ - Tag: rpTag, - Tenant: tenant, - TOR: tor, - Direction: direction, - Subject: subject, - ActivationTime: record[4], - DestRatesTimingTag: destRatesTimingTag, - RatesFallbackSubject: fallbacksubject, + rp := &utils.TPRatingProfile{ + Tag: rpTag, + Tenant: tenant, + TOR: tor, + Direction: direction, + Subject: subject, + ActivationTime: record[4], + RatingPlanId: destRatesTimingTag, + FallbackKeys: strings.Split(fallbacksubject, FALLBACK_SEP), } - if err := self.StorDb.SetTPRatingProfiles(self.TPid, map[string][]*RatingProfile{rpTag: []*RatingProfile{rp}}); err != nil { + if err := self.StorDb.SetTPRatingProfiles(self.TPid, map[string][]*utils.TPRatingProfile{rpTag: []*utils.TPRatingProfile{rp}}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } @@ -351,13 +365,17 @@ func (self *TPCSVImporter) importActionTimings(fn string) error { } continue } - at := &ActionTiming{ - Tag: tag, - ActionsTag: actionsTag, - TimingsTag: timingTag, - Weight: weight, + ats := &utils.ApiTPActionTimings{ + ActionTimingsId: tag, + ActionTimings: []*utils.ApiActionTiming{ + &utils.ApiActionTiming{ + ActionsId: actionsTag, + TimingId: timingTag, + Weight: weight, + }, + }, } - if err := self.StorDb.SetTPActionTimings(self.TPid, map[string][]*ActionTiming{tag: []*ActionTiming{at}}); err != nil { + if err := self.StorDb.SetTPActionTimings(self.TPid, map[string]*utils.ApiTPActionTimings{tag: ats}); err != nil { if self.Verbose { log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index c39fd103f..dd622c886 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -18,61 +18,80 @@ along with this program. If not, see package utils +import ( + "time" +) + // This file deals with tp_* data definition type TPRate struct { - TPid string // Tariff plan id - RateId string // Rate id - RateSlots []RateSlot // One or more RateSlots + TPid string // Tariff plan id + RateId string // Rate id + RateSlots []*RateSlot // One or more RateSlots } type RateSlot struct { - ConnectFee float64 // ConnectFee applied once the call is answered - Rate float64 // Rate applied - RateUnit string // Number of billing units this rate applies to - RateIncrement string // This rate will apply in increments of duration - GroupIntervalStart string // Group position - RoundingMethod string // Use this method to round the cost - RoundingDecimals int // Round the cost number of decimals + ConnectFee float64 // ConnectFee applied once the call is answered + Rate float64 // Rate applied + RateUnit time.Duration // Number of billing units this rate applies to + RateIncrement time.Duration // This rate will apply in increments of duration + GroupIntervalStart time.Duration // Group position + RoundingMethod string // Use this method to round the cost + RoundingDecimals int // Round the cost number of decimals } type TPDestinationRate struct { - TPid string // Tariff plan id - DestinationRateId string // DestinationRate profile id - DestinationRates []DestinationRate // Set of destinationid-rateid bindings + TPid string // Tariff plan id + DestinationRateId string // DestinationRate profile id + DestinationRates []*DestinationRate // Set of destinationid-rateid bindings } type DestinationRate struct { DestinationId string // The destination identity RateId string // The rate identity + Rate *TPRate +} + +type TPTiming struct { + Id string + Years Years + Months Months + MonthDays MonthDays + WeekDays WeekDays + StartTime string } type TPRatingPlan struct { - TPid string // Tariff plan id - RatingPlanId string // RatingPlan profile id - RatingPlans []RatingPlan // Set of destinationid-rateid bindings + TPid string // Tariff plan id + RatingPlanId string // RatingPlan profile id + RatingPlans []*RatingPlan // Set of destinationid-rateid bindings } type RatingPlan struct { DestRatesId string // The DestinationRate identity TimingId string // The timing identity Weight float64 // Binding priority taken into consideration when more DestinationRates are active on a time slot + Timing *TPTiming } type TPRatingProfile struct { - TPid string // Tariff plan id - RatingProfileId string // RatingProfile id - Tenant string // Tenant's Id - TOR string // TypeOfRecord - Direction string // Traffic direction, OUT is the only one supported for now - Subject string // Rating subject, usually the same as account - RatesFallbackSubject string // Fallback on this subject if rates not found for destination - RatingActivations []RatingActivation // Activate rate profiles at specific time + TPid string // Tariff plan id + Tag string + RatingProfileId string // RatingProfile id + RatingPlanId string + Tenant string // Tenant's Id + TOR string // TypeOfRecord + Direction string // Traffic direction, OUT is the only one supported for now + Subject string // Rating subject, usually the same as account + FallbackKeys []string // Fallback on this subject if rates not found for destination + ActivationTime string + RatingPlanActivations []*RatingActivation // Activate rate profiles at specific time } type RatingActivation struct { ActivationTime string // Time when this profile will become active, defined as unix epoch time DestRateTimingId string // Id of DestRateTiming profile + // FallbackKeys []string } type AttrTPRatingProfileIds struct { @@ -84,9 +103,9 @@ type AttrTPRatingProfileIds struct { } type TPActions struct { - TPid string // Tariff plan id - ActionsId string // Actions id - Actions []Action // Set of actions this Actions profile will perform + TPid string // Tariff plan id + ActionsId string // Actions id + Actions []*Action // Set of actions this Actions profile will perform } type Action struct { @@ -94,7 +113,7 @@ type Action struct { BalanceType string // Type of balance the action will operate on Direction string // Balance direction Units float64 // Number of units to add/deduct - ExpiryTime string // Time when the units will expire + ExpiryTime string // Time when the units will expire\ DestinationId string // Destination profile id RatingSubject string // Reference a rate subject defined in RatingProfiles BalanceWeight float64 // Balance weight @@ -103,9 +122,9 @@ type Action struct { } type ApiTPActionTimings struct { - TPid string // Tariff plan id - ActionTimingsId string // ActionTimings id - ActionTimings []ApiActionTiming // Set of ActionTiming bindings this profile will group + TPid string // Tariff plan id + ActionTimingsId string // ActionTimings id + ActionTimings []*ApiActionTiming // Set of ActionTiming bindings this profile will group } type ApiActionTiming struct { @@ -115,9 +134,9 @@ type ApiActionTiming struct { } type ApiTPActionTriggers struct { - TPid string // Tariff plan id - ActionTriggersId string // Profile id - ActionTriggers []ApiActionTrigger // Set of triggers grouped in this profile + TPid string // Tariff plan id + ActionTriggersId string // Profile id + ActionTriggers []*ApiActionTrigger // Set of triggers grouped in this profile } diff --git a/utils/tpdata.go b/utils/tpdata.go deleted file mode 100644 index a3c5001c3..000000000 --- a/utils/tpdata.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2013 ITsysCOM - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -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 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -// Represents a single row in .csv or storDb, id will be used as key in the map holding all rows -type TPActionTimingsRow struct { - ActionsId string // Actions id - TimingId string // Timing profile id - Weight float64 // Binding's weight -}