mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-21 07:08:45 +05:00
Add StartTime, IntervalStart and Usage as opts for rates
This commit is contained in:
committed by
Dan Christian Bogos
parent
a897848d7b
commit
0d5945cf12
@@ -1108,7 +1108,10 @@ const CGRATES_CFG_JSON = `
|
||||
"rate_nested_fields": false, // determines which field is checked when matching indexed filters(true: all; false: only the one on the first level)
|
||||
"verbosity": 1000, // number of increment iterations allowed
|
||||
"opts":{ //
|
||||
// "*rateProfileIDs": [], //
|
||||
// "*rateProfileIDs": [], //
|
||||
"*startTime": "*now", //
|
||||
"*usage": "1m", //
|
||||
"*intervalStart": "0", //
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -1970,7 +1970,11 @@ func TestDfRateSJsonCfg(t *testing.T) {
|
||||
Rate_suffix_indexed_fields: &[]string{},
|
||||
Rate_nested_fields: utils.BoolPointer(false),
|
||||
Verbosity: utils.IntPointer(1000),
|
||||
Opts: &RatesOptsJson{},
|
||||
Opts: &RatesOptsJson{
|
||||
StartTime: utils.StringPointer(utils.MetaNow),
|
||||
Usage: utils.StringPointer("1m"),
|
||||
IntervalStart: utils.StringPointer("0"),
|
||||
},
|
||||
}
|
||||
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -25,6 +25,9 @@ import (
|
||||
|
||||
type RatesOpts struct {
|
||||
RateProfileIDs []string
|
||||
StartTime string
|
||||
Usage string
|
||||
IntervalStart string
|
||||
}
|
||||
|
||||
// RateSCfg the rates config section
|
||||
@@ -51,6 +54,15 @@ func (rateOpts *RatesOpts) loadFromJSONCfg(jsnCfg *RatesOptsJson) (err error) {
|
||||
if jsnCfg.RateProfileIDs != nil {
|
||||
rateOpts.RateProfileIDs = *jsnCfg.RateProfileIDs
|
||||
}
|
||||
if jsnCfg.StartTime != nil {
|
||||
rateOpts.StartTime = *jsnCfg.StartTime
|
||||
}
|
||||
if jsnCfg.Usage != nil {
|
||||
rateOpts.Usage = *jsnCfg.Usage
|
||||
}
|
||||
if jsnCfg.IntervalStart != nil {
|
||||
rateOpts.IntervalStart = *jsnCfg.IntervalStart
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -115,6 +127,9 @@ func (rCfg *RateSCfg) loadFromJSONCfg(jsnCfg *RateSJsonCfg) (err error) {
|
||||
func (rCfg RateSCfg) AsMapInterface(string) interface{} {
|
||||
opts := map[string]interface{}{
|
||||
utils.MetaRateProfileIDsCfg: rCfg.Opts.RateProfileIDs,
|
||||
utils.MetaStartTime: rCfg.Opts.StartTime,
|
||||
utils.MetaUsage: rCfg.Opts.Usage,
|
||||
utils.MetaIntervalStartCfg: rCfg.Opts.IntervalStart,
|
||||
}
|
||||
mp := map[string]interface{}{
|
||||
utils.EnabledCfg: rCfg.Enabled,
|
||||
@@ -153,6 +168,9 @@ func (rateOpts *RatesOpts) Clone() *RatesOpts {
|
||||
}
|
||||
return &RatesOpts{
|
||||
RateProfileIDs: rtIDs,
|
||||
StartTime: rateOpts.StartTime,
|
||||
Usage: rateOpts.Usage,
|
||||
IntervalStart: rateOpts.IntervalStart,
|
||||
}
|
||||
}
|
||||
func (RateSCfg) SName() string { return RateSJSON }
|
||||
@@ -193,6 +211,9 @@ func (rCfg RateSCfg) Clone() (cln *RateSCfg) {
|
||||
|
||||
type RatesOptsJson struct {
|
||||
RateProfileIDs *[]string `json:"*rateProfileIDs"`
|
||||
StartTime *string `json:"*startTime"`
|
||||
Usage *string `json:"*usage"`
|
||||
IntervalStart *string `json:"*intervalStart"`
|
||||
}
|
||||
|
||||
type RateSJsonCfg struct {
|
||||
@@ -218,6 +239,15 @@ func diffRatesOptsJsonCfg(d *RatesOptsJson, v1, v2 *RatesOpts) *RatesOptsJson {
|
||||
if !utils.SliceStringEqual(v1.RateProfileIDs, v2.RateProfileIDs) {
|
||||
d.RateProfileIDs = utils.SliceStringPointer(v2.RateProfileIDs)
|
||||
}
|
||||
if v1.StartTime != v2.StartTime {
|
||||
d.StartTime = utils.StringPointer(v2.StartTime)
|
||||
}
|
||||
if v1.Usage != v2.Usage {
|
||||
d.Usage = utils.StringPointer(v2.Usage)
|
||||
}
|
||||
if v1.IntervalStart != v2.IntervalStart {
|
||||
d.IntervalStart = utils.StringPointer(v2.IntervalStart)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,11 @@ func TestRateSConfigloadFromJsonCfg(t *testing.T) {
|
||||
RateSuffixIndexedFields: &[]string{"*req.index1"},
|
||||
RateNestedFields: true,
|
||||
Verbosity: 20,
|
||||
Opts: &RatesOpts{},
|
||||
Opts: &RatesOpts{
|
||||
StartTime: utils.MetaNow,
|
||||
Usage: "1m",
|
||||
IntervalStart: "0",
|
||||
},
|
||||
}
|
||||
jsonCfg := NewDefaultCGRConfig()
|
||||
if err = jsonCfg.rateSCfg.loadFromJSONCfg(cfgJSON); err != nil {
|
||||
@@ -80,6 +84,9 @@ func TestRatesCfgAsMapInterface(t *testing.T) {
|
||||
utils.Verbosity: 1000,
|
||||
utils.OptsCfg: map[string]interface{}{
|
||||
utils.MetaRateProfileIDsCfg: []string(nil),
|
||||
utils.MetaStartTime: utils.MetaNow,
|
||||
utils.MetaUsage: "1m",
|
||||
utils.MetaIntervalStartCfg: "0",
|
||||
},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
@@ -120,6 +127,9 @@ func TestRatesCfgAsMapInterface1(t *testing.T) {
|
||||
utils.Verbosity: 1000,
|
||||
utils.OptsCfg: map[string]interface{}{
|
||||
utils.MetaRateProfileIDsCfg: []string(nil),
|
||||
utils.MetaStartTime: utils.MetaNow,
|
||||
utils.MetaUsage: "1m",
|
||||
utils.MetaIntervalStartCfg: "0",
|
||||
},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
|
||||
@@ -168,11 +168,11 @@ func (rS *RateS) rateProfileCostForEvent(ctx *context.Context, rtPfl *utils.Rate
|
||||
}
|
||||
}
|
||||
var sTime time.Time
|
||||
if sTime, err = args.StartTime(rS.cfg.GeneralCfg().DefaultTimezone); err != nil {
|
||||
if sTime, err = args.StartTime(rS.cfg.RateSCfg().Opts.StartTime, rS.cfg.GeneralCfg().DefaultTimezone); err != nil {
|
||||
return
|
||||
}
|
||||
var usage *decimal.Big
|
||||
if usage, err = args.Usage(); err != nil {
|
||||
if usage, err = args.Usage(rS.cfg.RateSCfg().Opts.Usage); err != nil {
|
||||
return
|
||||
}
|
||||
var ordRts []*orderedRate
|
||||
@@ -190,7 +190,7 @@ func (rS *RateS) rateProfileCostForEvent(ctx *context.Context, rtPfl *utils.Rate
|
||||
rpCost.MaxCost = rtPfl.MaxCost
|
||||
}
|
||||
var ivalStart *decimal.Big
|
||||
if ivalStart, err = args.IntervalStart(); err != nil {
|
||||
if ivalStart, err = args.IntervalStart(rS.cfg.RateSCfg().Opts.IntervalStart); err != nil {
|
||||
return
|
||||
}
|
||||
var costIntervals []*utils.RateSInterval
|
||||
|
||||
@@ -983,18 +983,18 @@ type ArgExportCDRs struct {
|
||||
}
|
||||
|
||||
// StartTime returns the event time used to check active rate profiles
|
||||
func (args *CGREvent) StartTime(tmz string) (sTime time.Time, err error) {
|
||||
func (args *CGREvent) StartTime(configSTime, tmz string) (time.Time, error) {
|
||||
if tIface, has := args.APIOpts[OptsRatesStartTime]; has {
|
||||
return IfaceAsTime(tIface, tmz)
|
||||
}
|
||||
if tIface, has := args.APIOpts[MetaStartTime]; has {
|
||||
return IfaceAsTime(tIface, tmz)
|
||||
}
|
||||
return time.Now(), nil
|
||||
return ParseTimeDetectLayout(configSTime, tmz)
|
||||
}
|
||||
|
||||
// usage returns the event time used to check active rate profiles
|
||||
func (args *CGREvent) Usage() (usage *decimal.Big, err error) {
|
||||
func (args *CGREvent) Usage(configUsage string) (usage *decimal.Big, err error) {
|
||||
// first search for the rateUsage in opts
|
||||
if uIface, has := args.APIOpts[OptsRatesUsage]; has {
|
||||
return IfaceAsBig(uIface)
|
||||
@@ -1004,15 +1004,15 @@ func (args *CGREvent) Usage() (usage *decimal.Big, err error) {
|
||||
return IfaceAsBig(uIface)
|
||||
}
|
||||
// if the usage is not found in the event populate with default value and overwrite the NOT_FOUND error with nil
|
||||
return decimal.New(int64(time.Minute), 0), nil
|
||||
return StringAsBig(configUsage)
|
||||
}
|
||||
|
||||
// IntervalStart returns the inerval start out of APIOpts received for the event
|
||||
func (args *CGREvent) IntervalStart() (ivlStart *decimal.Big, err error) {
|
||||
func (args *CGREvent) IntervalStart(configIvlStart string) (ivlStart *decimal.Big, err error) {
|
||||
if iface, has := args.APIOpts[OptsRatesIntervalStart]; has {
|
||||
return IfaceAsBig(iface)
|
||||
}
|
||||
return decimal.New(0, 0), nil
|
||||
return StringAsBig(configIvlStart)
|
||||
}
|
||||
|
||||
type TPActionProfile struct {
|
||||
|
||||
@@ -563,7 +563,7 @@ func TestStartTimeNow(t *testing.T) {
|
||||
},
|
||||
}
|
||||
timpulet1 := time.Now()
|
||||
result, err := ev.StartTime("")
|
||||
result, err := ev.StartTime(MetaNow, "")
|
||||
timpulet2 := time.Now()
|
||||
if err != nil {
|
||||
t.Errorf("Expected <nil> , received <%+v>", err)
|
||||
@@ -583,7 +583,21 @@ func TestStartTime(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"123", "456", "789"},
|
||||
},
|
||||
}
|
||||
if result, err := ev.StartTime(""); err != nil {
|
||||
if result, err := ev.StartTime(MetaNow, ""); err != nil {
|
||||
t.Errorf("Expected <nil> , received <%+v>", err)
|
||||
} else if !reflect.DeepEqual(result.String(), "2018-01-07 17:00:10 +0000 UTC") {
|
||||
t.Errorf("Expected <2018-01-07 17:00:10 +0000 UTC> , received <%+v>", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTime2(t *testing.T) {
|
||||
ev := &CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TestEvent",
|
||||
Event: map[string]interface{}{},
|
||||
APIOpts: map[string]interface{}{},
|
||||
}
|
||||
if result, err := ev.StartTime("2018-01-07T17:00:10Z", ""); err != nil {
|
||||
t.Errorf("Expected <nil> , received <%+v>", err)
|
||||
} else if !reflect.DeepEqual(result.String(), "2018-01-07 17:00:10 +0000 UTC") {
|
||||
t.Errorf("Expected <2018-01-07 17:00:10 +0000 UTC> , received <%+v>", result)
|
||||
@@ -600,7 +614,7 @@ func TestStartTimeError(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"123", "456", "789"},
|
||||
},
|
||||
}
|
||||
_, err := ev.StartTime("")
|
||||
_, err := ev.StartTime(MetaNow, "")
|
||||
if err == nil && err.Error() != "received <Unsupported time format" {
|
||||
t.Errorf("Expected <nil> , received <%+v>", err)
|
||||
}
|
||||
@@ -615,7 +629,7 @@ func TestUsageMinute(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"123", "456", "789"},
|
||||
},
|
||||
}
|
||||
if rcv, err := ev.Usage(); err != nil {
|
||||
if rcv, err := ev.Usage("60s"); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(decimal.New(int64(time.Minute), 0), rcv) {
|
||||
t.Errorf("Expected %+v, received %+v", decimal.New(int64(time.Minute), 0), rcv)
|
||||
@@ -632,7 +646,7 @@ func TestUsageError(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"123", "456", "789"},
|
||||
},
|
||||
}
|
||||
_, err := ev.Usage()
|
||||
_, err := ev.Usage("1m")
|
||||
if err == nil && err.Error() != "received <Unsupported time format" {
|
||||
t.Errorf("Expected <nil> , received <%+v>", err)
|
||||
}
|
||||
@@ -649,7 +663,7 @@ func TestUsage(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
if result, err := ev.Usage(); err != nil {
|
||||
if result, err := ev.Usage("1m"); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(result.String(), "130000000000") {
|
||||
t.Errorf("Expected <130000000000> , received <%+v>", result.String())
|
||||
@@ -742,7 +756,7 @@ func TestATDUsage(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := ev.Usage()
|
||||
_, err := ev.Usage("1m")
|
||||
expected := "cannot convert field: bool to decimal.Big"
|
||||
if err == nil || err.Error() != expected {
|
||||
t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, err.Error())
|
||||
@@ -772,7 +786,7 @@ func TestIntervalStart(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"RP_1001"},
|
||||
},
|
||||
}
|
||||
rcv, err := args.IntervalStart()
|
||||
rcv, err := args.IntervalStart("0")
|
||||
exp := new(decimal.Big).SetUint64(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -787,7 +801,7 @@ func TestIntervalStartDefault(t *testing.T) {
|
||||
OptsRatesRateProfileIDs: []string{"RP_1001"},
|
||||
},
|
||||
}
|
||||
rcv, err := args.IntervalStart()
|
||||
rcv, err := args.IntervalStart("0")
|
||||
exp := new(decimal.Big).SetUint64(0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -1923,6 +1923,7 @@ const (
|
||||
|
||||
// RateSCfg
|
||||
MetaRateProfileIDsCfg = "*rateProfileIDs"
|
||||
MetaIntervalStartCfg = "*intervalStart"
|
||||
RateIndexedSelectsCfg = "rate_indexed_selects"
|
||||
RateNestedFieldsCfg = "rate_nested_fields"
|
||||
RateStringIndexedFieldsCfg = "rate_string_indexed_fields"
|
||||
|
||||
@@ -72,6 +72,29 @@ func IfaceAsTime(itm interface{}, timezone string) (t time.Time, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func StringAsBig(itm string) (b *decimal.Big, err error) {
|
||||
if strings.HasSuffix(itm, NsSuffix) ||
|
||||
strings.HasSuffix(itm, UsSuffix) ||
|
||||
strings.HasSuffix(itm, µSuffix) ||
|
||||
strings.HasSuffix(itm, MsSuffix) ||
|
||||
strings.HasSuffix(itm, SSuffix) ||
|
||||
strings.HasSuffix(itm, MSuffix) ||
|
||||
strings.HasSuffix(itm, HSuffix) {
|
||||
var tm time.Duration
|
||||
if tm, err = time.ParseDuration(itm); err != nil {
|
||||
return
|
||||
}
|
||||
return decimal.New(int64(tm), 0), nil
|
||||
}
|
||||
z, ok := new(decimal.Big).SetString(itm)
|
||||
// verify ok and check if the value was converted successfuly
|
||||
// and the big is a valid number
|
||||
if !ok || z.IsNaN(0) {
|
||||
return nil, fmt.Errorf("can't convert <%+v> to decimal", itm)
|
||||
}
|
||||
return z, nil
|
||||
}
|
||||
|
||||
func IfaceAsBig(itm interface{}) (b *decimal.Big, err error) {
|
||||
switch it := itm.(type) {
|
||||
case time.Duration:
|
||||
@@ -101,26 +124,7 @@ func IfaceAsBig(itm interface{}) (b *decimal.Big, err error) {
|
||||
case float64: // automatically hitting here also ints
|
||||
return new(decimal.Big).SetFloat64(it), nil
|
||||
case string:
|
||||
if strings.HasSuffix(it, NsSuffix) ||
|
||||
strings.HasSuffix(it, UsSuffix) ||
|
||||
strings.HasSuffix(it, µSuffix) ||
|
||||
strings.HasSuffix(it, MsSuffix) ||
|
||||
strings.HasSuffix(it, SSuffix) ||
|
||||
strings.HasSuffix(it, MSuffix) ||
|
||||
strings.HasSuffix(it, HSuffix) {
|
||||
var tm time.Duration
|
||||
if tm, err = time.ParseDuration(it); err != nil {
|
||||
return
|
||||
}
|
||||
return decimal.New(int64(tm), 0), nil
|
||||
}
|
||||
z, ok := new(decimal.Big).SetString(it)
|
||||
// verify ok and check if the value was converted successfuly
|
||||
// and the big is a valid number
|
||||
if !ok || z.IsNaN(0) {
|
||||
return nil, fmt.Errorf("can't convert <%+v> to decimal", it)
|
||||
}
|
||||
return z, nil
|
||||
return StringAsBig(it)
|
||||
case *Decimal:
|
||||
return it.Big, nil
|
||||
case *decimal.Big:
|
||||
|
||||
Reference in New Issue
Block a user