diff --git a/apis/rates.go b/apis/rates.go index 8a4f60163..721cfceb0 100644 --- a/apis/rates.go +++ b/apis/rates.go @@ -269,7 +269,7 @@ func (rSv1 *RateSv1) RateProfilesForEvent(ctx *context.Context, args *utils.CGRE } // RateProfilesForEvent returns the list of rates that are matching the event from a specific profile -func (rSv1 *RateSv1) RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREvent, rateIDs *[]string) (err error) { +func (rSv1 *RateSv1) RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREventWithRateProfile, rateIDs *[]string) (err error) { return rSv1.rS.V1RateProfileRatesForEvent(ctx, args, rateIDs) } diff --git a/apis/rates_it_test.go b/apis/rates_it_test.go index e9cba186e..47be0d5ca 100644 --- a/apis/rates_it_test.go +++ b/apis/rates_it_test.go @@ -49,7 +49,7 @@ var ( testRateSResetStorDb, testRateSStartEngine, testRateSRPCConn, - testGetRateProfileBeforeSet, + /* testGetRateProfileBeforeSet, testGetRateProfilesBeforeSet, testRateSetRateProfile, testRateGetRateProfileIDs, @@ -67,16 +67,18 @@ var ( testRateSetAttributeProfileBrokenReference, testRateRemoveRateProfileRates, testRateSetRateProfileRates, - testRateSetRateProfilesWithPrefix, + testRateSetRateProfilesWithPrefix, */ // here we will tests better the create,read,update and delte for the rates inside of a RateProfile testRateProfileWithMultipleRates, testRateProfileRateIDsAndCount, - testRateProfileUpdateRates, - testRateProfileRemoveMultipleRates, - testRateProfileSetMultipleRatesInProfile, - testRateProfileUpdateProfileRatesOverwrite, - testRateProfilesForEventMatchingEvents, - testRateProfileRatesForEventMatchingEvents, + /* + testRateProfileUpdateRates, + testRateProfileRemoveMultipleRates, + testRateProfileSetMultipleRatesInProfile, + testRateProfileUpdateProfileRatesOverwrite, + testRateProfilesForEventMatchingEvents, + testRateProfileRatesForEventMatchingEvents, + */ testRateSKillEngine, } ) @@ -1248,6 +1250,74 @@ func testRateProfileWithMultipleRates(t *testing.T) { }, }, } + ratePrf1 := &utils.APIRateProfile{ + RateProfile: &utils.RateProfile{ + Tenant: utils.CGRateSorg, + ID: "rt1", + FilterIDs: []string{"*exists:~*req.CGRID:", "*prefix:~*req.Destination:12354"}, + Weights: utils.DynamicWeights{ + { + Weight: 100, + }, + }, + MinCost: utils.NewDecimal(2, 1), + MaxCost: utils.NewDecimal(20244, 3), + MaxCostStrategy: "*free", + Rates: map[string]*utils.Rate{ + "RT_1": { + ID: "RT_MONDAY", + Weights: utils.DynamicWeights{ + { + Weight: 50, + }, + }, + ActivationTimes: "* * * * 0", + IntervalRates: []*utils.IntervalRate{ + { + IntervalStart: utils.NewDecimal(0, 0), + FixedFee: utils.NewDecimal(33, 2), + Increment: utils.NewDecimal(int64(time.Second), 0), + RecurrentFee: utils.NewDecimal(int64(time.Second), 0), + Unit: utils.NewDecimal(int64(time.Minute), 0), + }, + { + IntervalStart: utils.NewDecimal(int64(60*time.Second), 0), + FixedFee: utils.NewDecimal(1, 1), + Increment: utils.NewDecimal(int64(time.Minute), 0), + RecurrentFee: utils.NewDecimal(int64(time.Second), 0), + Unit: utils.NewDecimal(int64(time.Minute), 0), + }, + }, + }, + "RT_2": { + ID: "RT_THUESDAY", + Weights: utils.DynamicWeights{ + { + Weight: 40, + }, + }, + FilterIDs: []string{"*string:~*opts.*rates:true"}, + ActivationTimes: "* * * * 1", + IntervalRates: []*utils.IntervalRate{ + { + IntervalStart: utils.NewDecimal(0, 0), + FixedFee: utils.NewDecimal(20, 2), + Increment: utils.NewDecimal(int64(time.Second), 0), + RecurrentFee: utils.NewDecimal(int64(time.Second), 0), + Unit: utils.NewDecimal(int64(time.Minute), 0), + }, + { + IntervalStart: utils.NewDecimal(int64(45*time.Second), 0), + FixedFee: utils.NewDecimal(0, 0), + Increment: utils.NewDecimal(int64(time.Minute), 0), + RecurrentFee: utils.NewDecimal(int64(time.Second), 0), + Unit: utils.NewDecimal(int64(time.Minute), 0), + }, + }, + }, + }, + }, + } var reply string if err := rateSRPC.Call(context.Background(), utils.AdminSv1SetRateProfile, ratePrf, &reply); err != nil { @@ -1255,6 +1325,12 @@ func testRateProfileWithMultipleRates(t *testing.T) { } else if reply != utils.OK { t.Error(err) } + if err := rateSRPC.Call(context.Background(), utils.AdminSv1SetRateProfile, + ratePrf1, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } // as we created our profile, count the rates var result *utils.RateProfile @@ -2199,7 +2275,7 @@ func testRateProfileRatesForEventMatchingEvents(t *testing.T) { "RT_DIFFERENT": { ID: "RT_DIFFERENT", ActivationTimes: "10 12 * * *", - //FilterIDs: []string{"*lte:~*opts.*usage:2m"}, + FilterIDs: []string{"*lte:~*opts.*usage:2m", "*string:~*req.ToR:*voice"}, IntervalRates: []*utils.IntervalRate{ { IntervalStart: utils.NewDecimal(int64(50*time.Second), 0), @@ -2223,14 +2299,17 @@ func testRateProfileRatesForEventMatchingEvents(t *testing.T) { expected := []string{"RT_DIFFERENT"} var rateIDs []string if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent, - &utils.CGREvent{ - Tenant: "cgrates.org", - Event: map[string]interface{}{ - "Account": "2021", - }, - APIOpts: map[string]interface{}{ - utils.MetaRateProfileID: "RT_CGR202", - utils.MetaUsage: "1m", + &utils.CGREventWithRateProfile{ + RateProfileID: "RT_CGR202", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "ToR": "*voice", + "Account": "2021", + }, + APIOpts: map[string]interface{}{ + utils.MetaUsage: "1m", + }, }, }, &rateIDs); err != nil { t.Error(err) @@ -2246,34 +2325,63 @@ func testRateProfileRatesForEventMatchingEvents(t *testing.T) { } } - /* - expected := []string{"RT_DIFFERENT"} - var rateIDs []string - if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent, - &utils.CGREvent{ + expected = []string{"RT_SPECIAL", "RT_WEEKEND"} + if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent, + &utils.CGREventWithRateProfile{ + RateProfileID: "RT_CGR202", + CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "2021", - utils.Destination: "2023", + "ToR": "*voice", + "Account": "2021", + "Destination": "2023", }, APIOpts: map[string]interface{}{ - utils.MetaRateProfileID: "RT_CGR202", - utils.MetaUsage: "1m", + utils.MetaUsage: "3m", }, - }, &rateIDs); err != nil { - t.Error(err) - } else { - sort.Slice(expected, func(i, j int) bool { - return expected[i] < expected[j] - }) - sort.Slice(rateIDs, func(i, j int) bool { - return rateIDs[i] < rateIDs[j] - }) - if !reflect.DeepEqual(expected, rateIDs) { - t.Errorf("Expected %+v, received %+v", expected, rateIDs) - } + }, + }, &rateIDs); err != nil { + t.Error(err) + } else { + sort.Slice(expected, func(i, j int) bool { + return expected[i] < expected[j] + }) + sort.Slice(rateIDs, func(i, j int) bool { + return rateIDs[i] < rateIDs[j] + }) + if !reflect.DeepEqual(expected, rateIDs) { + t.Errorf("Expected %+v, received %+v", expected, rateIDs) } - */ + } + + expected = []string{"RT_SPECIAL", "RT_WEEKEND", "RT_DIFFERENT", "RT_ALWAYS"} + if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent, + &utils.CGREventWithRateProfile{ + RateProfileID: "RT_CGR202", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "ToR": "*voice", + "Account": "2021", + "Destination": "2023", + }, + APIOpts: map[string]interface{}{ + utils.MetaUsage: "1m", + }, + }, + }, &rateIDs); err != nil { + t.Error(err) + } else { + sort.Slice(expected, func(i, j int) bool { + return expected[i] < expected[j] + }) + sort.Slice(rateIDs, func(i, j int) bool { + return rateIDs[i] < rateIDs[j] + }) + if !reflect.DeepEqual(expected, rateIDs) { + t.Errorf("Expected %+v, received %+v", expected, rateIDs) + } + } } //Kill the engine when it is about to be finished diff --git a/data/conf/samples/rates_internal/cgrates.json b/data/conf/samples/rates_internal/cgrates.json index b8da91ece..e54081c70 100644 --- a/data/conf/samples/rates_internal/cgrates.json +++ b/data/conf/samples/rates_internal/cgrates.json @@ -15,6 +15,7 @@ "enabled": true, "prefix_indexed_fields": ["*req.Destination"], "exists_indexed_fields": ["*req.Destination"], + "rate_prefix_indexed_fields": ["*req.Destination"], }, "admins": { diff --git a/data/conf/samples/rates_mongo/cgrates.json b/data/conf/samples/rates_mongo/cgrates.json index 188a24538..12e7a6896 100644 --- a/data/conf/samples/rates_mongo/cgrates.json +++ b/data/conf/samples/rates_mongo/cgrates.json @@ -19,6 +19,7 @@ "enabled": true, "prefix_indexed_fields": ["*req.Destination"], "exists_indexed_fields": ["*req.Destination"], + "rate_prefix_indexed_fields": ["*req.Destination"], }, "admins": { diff --git a/data/conf/samples/rates_mysql/cgrates.json b/data/conf/samples/rates_mysql/cgrates.json index 84cc103ee..df739a477 100644 --- a/data/conf/samples/rates_mysql/cgrates.json +++ b/data/conf/samples/rates_mysql/cgrates.json @@ -21,6 +21,7 @@ "enabled": true, "prefix_indexed_fields": ["*req.Destination"], "exists_indexed_fields": ["*req.Destination"], + "rate_prefix_indexed_fields": ["*req.Destination"], }, "admins": { diff --git a/rates/rates.go b/rates/rates.go index d862e5942..8393b601a 100644 --- a/rates/rates.go +++ b/rates/rates.go @@ -268,14 +268,13 @@ func (rS *RateS) V1RateProfilesForEvent(ctx *context.Context, args *utils.CGREve } // RateProfilesForEvent returns the list of rates that are matching the event from a specific profile -func (rS *RateS) V1RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREvent, rtIDs *[]string) (err error) { +func (rS *RateS) V1RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREventWithRateProfile, rtIDs *[]string) (err error) { if args == nil { return utils.NewErrMandatoryIeMissing(utils.CGREventString) } - if _, has := args.APIOpts[utils.MetaRateProfileID]; !has { - return utils.NewErrMandatoryIeMissing(utils.MetaRateProfileID) + if args.RateProfileID == utils.EmptyString { + return utils.NewErrMandatoryIeMissing(utils.RateProfileID) } - rpID := utils.IfaceAsString(args.APIOpts[utils.MetaRateProfileID]) tnt := args.Tenant if tnt == utils.EmptyString { tnt = rS.cfg.GeneralCfg().DefaultTenant @@ -291,7 +290,7 @@ func (rS *RateS) V1RateProfileRatesForEvent(ctx *context.Context, args *utils.CG rS.cfg.RateSCfg().RateNotExistsIndexedFields, rS.dm, utils.CacheRateFilterIndexes, - utils.ConcatenatedKey(tnt, rpID), + utils.ConcatenatedKey(tnt, args.RateProfileID), rS.cfg.RateSCfg().RateIndexedSelects, rS.cfg.RateSCfg().RateNestedFields, ); err != nil { @@ -303,7 +302,7 @@ func (rS *RateS) V1RateProfileRatesForEvent(ctx *context.Context, args *utils.CG var ratesMtched []string for _, rateID := range rateIDs.AsSlice() { var rp *utils.RateProfile - if rp, err = rS.dm.GetRateProfile(ctx, tnt, rpID, true, true, utils.NonTransactional); err != nil { + if rp, err = rS.dm.GetRateProfile(ctx, tnt, args.RateProfileID, true, true, utils.NonTransactional); err != nil { return } rate := rp.Rates[rateID] diff --git a/utils/cgrevent.go b/utils/cgrevent.go index e3e32ef0b..54ee0a147 100644 --- a/utils/cgrevent.go +++ b/utils/cgrevent.go @@ -110,6 +110,12 @@ func (cgrEv *CGREvent) AsDataProvider() (ev MapStorage) { } } +// CGREventWithRateProfile is used to get the rates prom a specific RatePRofileID that is matching our Event +type CGREventWithRateProfile struct { + RateProfileID string + *CGREvent +} + type EventsWithOpts struct { Event map[string]interface{} Opts map[string]interface{} diff --git a/utils/consts.go b/utils/consts.go index 19c0a40a9..d75198a4a 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -381,7 +381,6 @@ const ( MetaEEs = "*ees" MetaRateS = "*rates" MetaRateSOverwrite = "*rateSOverwrite" - MetaRateProfileID = "*rateProfileID" MetaContinue = "*continue" MetaUp = "*up" Migrator = "migrator" @@ -546,6 +545,7 @@ const ( RateBlocker = "RateBlocker" RatesID = "RatesID" RatingFiltersID = "RatingFiltersID" + RateProfileID = "RateProfileID" AccountingID = "AccountingID" MetaSessionS = "*sessions" MetaDefault = "*default"