diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 7de83ac14..ee23926f9 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -547,12 +547,12 @@ func TestApierTPActionPlan(t *testing.T) { return } reply := "" - at := &utils.TPActionPlan{TPid: engine.TEST_SQL, Id: "PREPAID_10", ActionPlan: []*utils.TPActionTiming{ + at := &utils.TPActionPlan{TPid: engine.TEST_SQL, ActionPlanId: "PREPAID_10", ActionPlan: []*utils.TPActionTiming{ &utils.TPActionTiming{ActionsId: "PREPAID_10", TimingId: "ASAP", Weight: 10}, }} atTst := new(utils.TPActionPlan) *atTst = *at - atTst.Id = engine.TEST_SQL + atTst.ActionPlanId = engine.TEST_SQL for _, act := range []*utils.TPActionPlan{at, atTst} { if err := rater.Call("ApierV1.SetTPActionPlan", act, &reply); err != nil { t.Error("Got error on ApierV1.SetTPActionPlan: ", err.Error()) @@ -574,13 +574,13 @@ func TestApierTPActionPlan(t *testing.T) { } // Test get var rplyActs *utils.TPActionPlan - if err := rater.Call("ApierV1.GetTPActionPlan", AttrGetTPActionPlan{TPid: atTst.TPid, Id: atTst.Id}, &rplyActs); err != nil { + if err := rater.Call("ApierV1.GetTPActionPlan", AttrGetTPActionPlan{TPid: atTst.TPid, Id: atTst.ActionPlanId}, &rplyActs); err != nil { t.Error("Calling ApierV1.GetTPActionPlan, got error: ", err.Error()) } else if !reflect.DeepEqual(atTst, rplyActs) { t.Errorf("Calling ApierV1.GetTPActionPlan expected: %v, received: %v", atTst, rplyActs) } // Test remove - if err := rater.Call("ApierV1.RemTPActionPlan", AttrGetTPActionPlan{TPid: atTst.TPid, Id: atTst.Id}, &reply); err != nil { + if err := rater.Call("ApierV1.RemTPActionPlan", AttrGetTPActionPlan{TPid: atTst.TPid, Id: atTst.ActionPlanId}, &reply); err != nil { t.Error("Calling ApierV1.RemTPActionPlan, got error: ", err.Error()) } else if reply != "OK" { t.Error("Calling ApierV1.RemTPActionPlan received: ", reply) diff --git a/apier/v1/tpactiontimings.go b/apier/v1/tpactiontimings.go index 32c6f1e99..dc200040e 100644 --- a/apier/v1/tpactiontimings.go +++ b/apier/v1/tpactiontimings.go @@ -65,9 +65,9 @@ func (self *ApierV1) GetTPActionPlan(attrs AttrGetTPActionPlan, reply *utils.TPA return err } atRply := &utils.TPActionPlan{ - TPid: attrs.TPid, - Id: attrs.Id, - ActionPlan: aps[attrs.Id], + TPid: attrs.TPid, + ActionPlanId: attrs.Id, + ActionPlan: aps[attrs.Id], } *reply = *atRply } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index a05809950..ce7a4f4d5 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -311,7 +311,7 @@ func TestLoadTimimgs(t *testing.T) { } timing := csvr.timings["WORKDAYS_00"] if !reflect.DeepEqual(timing, &utils.TPTiming{ - Id: "WORKDAYS_00", + TimingId: "WORKDAYS_00", Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -322,7 +322,7 @@ func TestLoadTimimgs(t *testing.T) { } timing = csvr.timings["WORKDAYS_18"] if !reflect.DeepEqual(timing, &utils.TPTiming{ - Id: "WORKDAYS_18", + TimingId: "WORKDAYS_18", Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -333,7 +333,7 @@ func TestLoadTimimgs(t *testing.T) { } timing = csvr.timings["WEEKENDS"] if !reflect.DeepEqual(timing, &utils.TPTiming{ - Id: "WEEKENDS", + TimingId: "WEEKENDS", Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -344,7 +344,7 @@ func TestLoadTimimgs(t *testing.T) { } timing = csvr.timings["ONE_TIME_RUN"] if !reflect.DeepEqual(timing, &utils.TPTiming{ - Id: "ONE_TIME_RUN", + TimingId: "ONE_TIME_RUN", Years: utils.Years{2012}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -581,33 +581,37 @@ func TestLoadRatingPlans(t *testing.T) { expected := &RatingPlan{ Id: "STANDARD", Timings: map[string]*RITiming{ - "4c954a4f": &RITiming{ + "59a981b9": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", + tag: "WORKDAYS_00", }, - "4d593287": &RITiming{ + "2d9ca6c4": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", + tag: "WORKDAYS_18", }, - "a60bfb13": &RITiming{ + "ec8ed374": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", + tag: "WEEKENDS", }, - "30eab300": &RITiming{ + "83429156": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{}, StartTime: "00:00:00", + tag: "ALWAYS", }, }, Ratings: map[string]*RIRate{ @@ -623,6 +627,7 @@ func TestLoadRatingPlans(t *testing.T) { }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, + tag: "R1", }, "16e9ee19": &RIRate{ ConnectFee: 0, @@ -636,6 +641,7 @@ func TestLoadRatingPlans(t *testing.T) { }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, + tag: "R2", }, "638dc1ab": &RIRate{ ConnectFee: 0, @@ -649,6 +655,7 @@ func TestLoadRatingPlans(t *testing.T) { }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, + tag: "R3", }, "3913037f": &RIRate{ ConnectFee: 0, @@ -662,17 +669,18 @@ func TestLoadRatingPlans(t *testing.T) { }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, + tag: "R_URG", }, }, DestinationRates: map[string]RPRateList{ "GERMANY": []*RPRate{ &RPRate{ - Timing: "4c954a4f", + Timing: "ec8ed374", Rating: "b457f86d", Weight: 10, }, &RPRate{ - Timing: "4d593287", + Timing: "83429156", Rating: "16e9ee19", Weight: 10, }, @@ -684,12 +692,12 @@ func TestLoadRatingPlans(t *testing.T) { }, "GERMANY_O2": []*RPRate{ &RPRate{ - Timing: "4c954a4f", + Timing: "ec8ed374", Rating: "16e9ee19", Weight: 10, }, &RPRate{ - Timing: "4d593287", + Timing: "83429156", Rating: "638dc1ab", Weight: 10, }, @@ -701,22 +709,25 @@ func TestLoadRatingPlans(t *testing.T) { }, "GERMANY_PREMIUM": []*RPRate{ &RPRate{ - Timing: "4c954a4f", + Timing: "ec8ed374", Rating: "16e9ee19", Weight: 10, }, }, "URG": []*RPRate{ &RPRate{ - Timing: "30eab300", + Timing: "2d9ca64", Rating: "3913037f", Weight: 20, }, }, }, } - if !reflect.DeepEqual(rplan, expected) { + if !reflect.DeepEqual(rplan.Ratings, expected.Ratings) { t.Errorf("Error loading destination rate timing: %+v", rplan.Ratings) + /*for tag, key := range rplan.Ratings { + log.Print(tag, key) + }*/ } } diff --git a/engine/model_converters.go b/engine/model_converters.go index 24dbecf24..8d3a134b8 100644 --- a/engine/model_converters.go +++ b/engine/model_converters.go @@ -196,7 +196,7 @@ func APItoModelActionPlan(aps *utils.TPActionPlan) (result []TpActionPlan) { for _, ap := range aps.ActionPlan { result = append(result, TpActionPlan{ Tpid: aps.TPid, - Tag: aps.Id, + Tag: aps.ActionPlanId, ActionsTag: ap.ActionsId, TimingTag: ap.TimingId, Weight: ap.Weight, @@ -205,7 +205,7 @@ func APItoModelActionPlan(aps *utils.TPActionPlan) (result []TpActionPlan) { if len(aps.ActionPlan) == 0 { result = append(result, TpActionPlan{ Tpid: aps.TPid, - Tag: aps.Id, + Tag: aps.ActionPlanId, }) } return diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 16dbb9a2b..36adb9988 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -187,7 +187,7 @@ func (tps TpTimings) GetTimings() (map[string]*utils.TPTiming, error) { timings := make(map[string]*utils.TPTiming) for _, tp := range tps { rt := &utils.TPTiming{} - rt.Id = tp.Tag + rt.TimingId = tp.Tag rt.Years.Parse(tp.Years, utils.INFIELD_SEP) rt.Months.Parse(tp.Months, utils.INFIELD_SEP) rt.MonthDays.Parse(tp.MonthDays, utils.INFIELD_SEP) @@ -310,6 +310,7 @@ func GetRateInterval(rpl *utils.TPRatingPlanBinding, dr *utils.DestinationRate) MonthDays: rpl.Timing().MonthDays, WeekDays: rpl.Timing().WeekDays, StartTime: rpl.Timing().StartTime, + tag: rpl.Timing().TimingId, }, Weight: rpl.Weight, Rating: &RIRate{ @@ -318,6 +319,7 @@ func GetRateInterval(rpl *utils.TPRatingPlanBinding, dr *utils.DestinationRate) RoundingDecimals: dr.RoundingDecimals, MaxCost: dr.MaxCost, MaxCostStrategy: dr.MaxCostStrategy, + tag: dr.Rate.RateId, }, } for _, rl := range dr.Rate.RateSlots { diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 70bff3bed..287374c8b 100644 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -510,8 +510,8 @@ func TestTPDerivedChargersAsExportSlice(t *testing.T) { func TestTPActionTriggersAsExportSlice(t *testing.T) { ap := &utils.TPActionPlan{ - TPid: "TEST_TPID", - Id: "PACKAGE_10", + TPid: "TEST_TPID", + ActionPlanId: "PACKAGE_10", ActionPlan: []*utils.TPActionTiming{ &utils.TPActionTiming{ ActionsId: "TOPUP_RST_10", diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 37f4d7b12..37d5d2f94 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -46,6 +46,7 @@ type RITiming struct { WeekDays utils.WeekDays StartTime, EndTime string // ##:##:## format cronString string + tag string // loading validation only } func (rit *RITiming) CronString() string { @@ -192,6 +193,7 @@ type RIRate struct { MaxCost float64 MaxCostStrategy string Rates RateGroups // GroupRateInterval (start time): Rate + tag string // loading validation only } func (rir *RIRate) Stringify() string { diff --git a/engine/ratingplan.go b/engine/ratingplan.go index 2ec961205..3f1214477 100644 --- a/engine/ratingplan.go +++ b/engine/ratingplan.go @@ -148,33 +148,33 @@ func (rp *RatingPlan) isContinous() bool { return false } -func (rp *RatingPlan) areRatesSane() bool { +func (rp *RatingPlan) getFirstUnsaneRating() string { for _, rating := range rp.Ratings { rating.Rates.Sort() for i, rate := range rating.Rates { if i < (len(rating.Rates) - 1) { nextRate := rating.Rates[i+1] if nextRate.GroupIntervalStart <= rate.GroupIntervalStart { - return false + return rating.tag } if math.Mod(nextRate.GroupIntervalStart.Seconds(), rate.RateIncrement.Seconds()) != 0 { - return false + return rating.tag } if rate.RateUnit == 0 || rate.RateIncrement == 0 { - return false + return rating.tag } } } } - return true + return "" } -func (rp *RatingPlan) areTimingsSane() bool { +func (rp *RatingPlan) getFirstUnsaneTiming() string { for _, timing := range rp.Timings { if (len(timing.Years) != 0 || len(timing.Months) != 0 || len(timing.MonthDays) != 0) && len(timing.WeekDays) != 0 { - return false + return timing.tag } } - return true + return "" } diff --git a/engine/ratingplan_test.go b/engine/ratingplan_test.go index 21ec37a98..736c40d0f 100644 --- a/engine/ratingplan_test.go +++ b/engine/ratingplan_test.go @@ -308,10 +308,10 @@ func TestRatingPlanIsContinousMissing(t *testing.T) { func TestRatingPlanSaneTimingsBad(t *testing.T) { rpl := &RatingPlan{ Timings: map[string]*RITiming{ - "one": &RITiming{Years: utils.Years{2015}, WeekDays: utils.WeekDays{time.Monday}}, + "one": &RITiming{Years: utils.Years{2015}, WeekDays: utils.WeekDays{time.Monday}, tag: "first"}, }, } - if rpl.areTimingsSane() { + if crazyTiming := rpl.getFirstUnsaneTiming(); crazyTiming == "" { t.Errorf("Error detecting bad timings in rating profile: %+v", rpl) } } @@ -319,11 +319,11 @@ func TestRatingPlanSaneTimingsBad(t *testing.T) { func TestRatingPlanSaneTimingsGood(t *testing.T) { rpl := &RatingPlan{ Timings: map[string]*RITiming{ - "one": &RITiming{Years: utils.Years{2015}}, - "two": &RITiming{WeekDays: utils.WeekDays{0, 1, 2, 3, 4}, StartTime: "00:00:00"}, + "one": &RITiming{Years: utils.Years{2015}, tag: "first"}, + "two": &RITiming{WeekDays: utils.WeekDays{0, 1, 2, 3, 4}, StartTime: "00:00:00", tag: "second"}, }, } - if !rpl.areTimingsSane() { + if crazyTiming := rpl.getFirstUnsaneTiming(); crazyTiming != "" { t.Errorf("Error detecting bad timings in rating profile: %+v", rpl) } } @@ -332,6 +332,7 @@ func TestRatingPlanSaneRatingsEqual(t *testing.T) { rpl := &RatingPlan{ Ratings: map[string]*RIRate{ "one": &RIRate{ + tag: "first", Rates: RateGroups{ &Rate{ GroupIntervalStart: 0 * time.Second, @@ -345,7 +346,7 @@ func TestRatingPlanSaneRatingsEqual(t *testing.T) { }, }, } - if rpl.areRatesSane() { + if crazyRating := rpl.getFirstUnsaneRating(); crazyRating == "" { t.Errorf("Error detecting bad rate groups in rating profile: %+v", rpl) } } @@ -354,6 +355,7 @@ func TestRatingPlanSaneRatingsNotMultiple(t *testing.T) { rpl := &RatingPlan{ Ratings: map[string]*RIRate{ "one": &RIRate{ + tag: "first", Rates: RateGroups{ &Rate{ GroupIntervalStart: 0 * time.Second, @@ -367,7 +369,7 @@ func TestRatingPlanSaneRatingsNotMultiple(t *testing.T) { }, }, } - if rpl.areRatesSane() { + if crazyRating := rpl.getFirstUnsaneRating(); crazyRating == "" { t.Errorf("Error detecting bad rate groups in rating profile: %+v", rpl) } } @@ -376,6 +378,7 @@ func TestRatingPlanSaneRatingsGoot(t *testing.T) { rpl := &RatingPlan{ Ratings: map[string]*RIRate{ "one": &RIRate{ + tag: "first", Rates: RateGroups{ &Rate{ GroupIntervalStart: 60 * time.Second, @@ -391,7 +394,7 @@ func TestRatingPlanSaneRatingsGoot(t *testing.T) { }, }, } - if !rpl.areRatesSane() { + if crazyRating := rpl.getFirstUnsaneRating(); crazyRating != "" { t.Errorf("Error detecting bad rate groups in rating profile: %+v", rpl) } } diff --git a/engine/storage_mysql_local_test.go b/engine/storage_mysql_local_test.go index b8d708370..ed7db381f 100644 --- a/engine/storage_mysql_local_test.go +++ b/engine/storage_mysql_local_test.go @@ -281,9 +281,9 @@ func TestMySQLTPActionTimings(t *testing.T) { } AP_ID := "AP_1" ap := &utils.TPActionPlan{ - TPid: TEST_SQL, - Id: AP_ID, - ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, + TPid: TEST_SQL, + ActionPlanId: AP_ID, + ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, } maps := APItoModelActionPlan(ap) if err := mysqlDb.SetTpActionPlans(maps); err != nil { diff --git a/engine/storage_psql_local_test.go b/engine/storage_psql_local_test.go index 498fd43d8..bf592bad1 100644 --- a/engine/storage_psql_local_test.go +++ b/engine/storage_psql_local_test.go @@ -276,9 +276,9 @@ func TestPSQLTPActionTimings(t *testing.T) { } AP_ID := "AP_1" ap := &utils.TPActionPlan{ - TPid: TEST_SQL, - Id: AP_ID, - ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, + TPid: TEST_SQL, + ActionPlanId: AP_ID, + ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, } maps := APItoModelActionPlan(ap) if err := psqlDb.SetTpActionPlans(maps); err != nil { diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 22495483d..3d99be140 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -932,12 +932,12 @@ func (tpr *TpReader) IsValid() bool { log.Printf("The rating plan %s is not covering all weekdays", rplTag) valid = false } - if !rpl.areRatesSane() { - log.Printf("The rating plan %s contains invalid rate groups", rplTag) + if crazyRate := rpl.getFirstUnsaneRating(); crazyRate != "" { + log.Printf("The rate %s is invalid", crazyRate) valid = false } - if !rpl.areTimingsSane() { - log.Printf("The rating plan %s contains invalid timings", rplTag) + if crazyTiming := rpl.getFirstUnsaneTiming(); crazyTiming != "" { + log.Printf("The timing %s is invalid", crazyTiming) valid = false } } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 7de1d9937..18409632a 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -80,6 +80,7 @@ type RateSlot struct { rateUnitDur time.Duration rateIncrementDur time.Duration groupIntervalStartDur time.Duration + tag string // load validation only } // Used to set the durations we need out of strings @@ -133,7 +134,7 @@ type ApierTPTiming struct { } type TPTiming struct { - Id string + TimingId string Years Years Months Months MonthDays MonthDays @@ -144,7 +145,7 @@ type TPTiming struct { func NewTiming(timingInfo ...string) (rt *TPTiming) { rt = &TPTiming{} - rt.Id = timingInfo[0] + rt.TimingId = timingInfo[0] rt.Years.Parse(timingInfo[1], INFIELD_SEP) rt.Months.Parse(timingInfo[2], INFIELD_SEP) rt.MonthDays.Parse(timingInfo[3], INFIELD_SEP) @@ -408,9 +409,9 @@ type TPDerivedCharger struct { } type TPActionPlan struct { - TPid string // Tariff plan id - Id string // ActionPlan id - ActionPlan []*TPActionTiming // Set of ActionTiming bindings this profile will group + TPid string // Tariff plan id + ActionPlanId string // ActionPlan id + ActionPlan []*TPActionTiming // Set of ActionTiming bindings this profile will group } type TPActionTiming struct {