mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
RateS - adding V1CostForEvent API method
This commit is contained in:
@@ -173,6 +173,12 @@ type RateSIncrement struct {
|
||||
cost *utils.Decimal // unexported total increment cost
|
||||
}
|
||||
|
||||
type RateProfileCost struct {
|
||||
ID string // RateProfileID
|
||||
Cost float64
|
||||
RateSIntervals []*RateSInterval
|
||||
}
|
||||
|
||||
// Sort will sort the IntervalRates from each Rate based on IntervalStart
|
||||
func (rpp *RateProfile) Sort() {
|
||||
for _, rate := range rpp.Rates {
|
||||
|
||||
@@ -205,9 +205,10 @@ func computeRateSIntervals(rts []*orderedRate, intervalStart, usage time.Duratio
|
||||
}
|
||||
isLastIRt := j == len(rt.IntervalRates)-1
|
||||
if iRt.IntervalStart > iRtUsageSIdx {
|
||||
break
|
||||
} else if !isLastIRt && rt.IntervalRates[j+1].IntervalStart <= iRtUsageSIdx {
|
||||
continue // the rates should be already ordered, break here
|
||||
break // we are past the start
|
||||
}
|
||||
if !isLastIRt && rt.IntervalRates[j+1].IntervalStart <= iRtUsageSIdx {
|
||||
continue // the next interval changes the rating
|
||||
}
|
||||
if !isLastIRt {
|
||||
iRtUsageEIdx = rt.IntervalRates[j+1].IntervalStart
|
||||
|
||||
@@ -71,7 +71,7 @@ func (rS *RateS) Call(serviceMethod string, args interface{}, reply interface{})
|
||||
}
|
||||
|
||||
// matchingRateProfileForEvent returns the matched RateProfile for the given event
|
||||
func (rS *RateS) matchingRateProfileForEvent(tnt string, args *ArgsCostForEvent, rPfIDs []string) (rtPfl *engine.RateProfile, err error) {
|
||||
func (rS *RateS) matchingRateProfileForEvent(tnt string, rPfIDs []string, args *ArgsCostForEvent) (rtPfl *engine.RateProfile, err error) {
|
||||
evNm := utils.MapStorage{
|
||||
utils.MetaReq: args.CGREvent.Event,
|
||||
utils.MetaOpts: args.Opts,
|
||||
@@ -93,10 +93,6 @@ func (rS *RateS) matchingRateProfileForEvent(tnt string, args *ArgsCostForEvent,
|
||||
}
|
||||
rPfIDs = rPfIDMp.AsSlice()
|
||||
}
|
||||
var sTime time.Time
|
||||
if sTime, err = args.StartTime(rS.cfg.GeneralCfg().DefaultTimezone); err != nil {
|
||||
return
|
||||
}
|
||||
for _, rPfID := range rPfIDs {
|
||||
var rPf *engine.RateProfile
|
||||
if rPf, err = rS.dm.GetRateProfile(tnt, rPfID,
|
||||
@@ -107,8 +103,8 @@ func (rS *RateS) matchingRateProfileForEvent(tnt string, args *ArgsCostForEvent,
|
||||
}
|
||||
return
|
||||
}
|
||||
if rPf.ActivationInterval != nil &&
|
||||
!rPf.ActivationInterval.IsActiveAtTime(sTime) { // not active
|
||||
if rPf.ActivationInterval != nil && args.CGREvent.Time != nil &&
|
||||
!rPf.ActivationInterval.IsActiveAtTime(*args.CGREvent.Time) { // not active
|
||||
continue
|
||||
}
|
||||
var pass bool
|
||||
@@ -128,15 +124,8 @@ func (rS *RateS) matchingRateProfileForEvent(tnt string, args *ArgsCostForEvent,
|
||||
return
|
||||
}
|
||||
|
||||
type RateProfileCost struct {
|
||||
Tenant string
|
||||
ID string
|
||||
Cost float64
|
||||
RateSIntervals []*engine.RateSInterval
|
||||
}
|
||||
|
||||
// costForEvent computes the cost for an event based on a preselected rating profile
|
||||
func (rS *RateS) rateProfileCostForEvent(rtPfl *engine.RateProfile, args *ArgsCostForEvent) (rpCost *RateProfileCost, err error) {
|
||||
func (rS *RateS) rateProfileCostForEvent(rtPfl *engine.RateProfile, args *ArgsCostForEvent) (rpCost *engine.RateProfileCost, err error) {
|
||||
var rtIDs utils.StringSet
|
||||
if rtIDs, err = engine.MatchingItemIDsForEvent(
|
||||
args.CGREventWithOpts.CGREvent.Event,
|
||||
@@ -175,7 +164,7 @@ func (rS *RateS) rateProfileCostForEvent(rtPfl *engine.RateProfile, args *ArgsCo
|
||||
if ordRts, err = orderRatesOnIntervals(aRates, sTime, usage, true, 1000000); err != nil {
|
||||
return
|
||||
}
|
||||
rpCost = &RateProfileCost{Tenant: rtPfl.Tenant, ID: rtPfl.ID}
|
||||
rpCost = &engine.RateProfileCost{ID: rtPfl.ID}
|
||||
if rpCost.RateSIntervals, err = computeRateSIntervals(ordRts, 0, usage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -194,22 +183,6 @@ func (args *ArgsCostForEvent) StartTime(tmz string) (sTime time.Time, err error)
|
||||
if tIface, has := args.Opts[utils.OptsRatesStartTime]; has {
|
||||
return utils.IfaceAsTime(tIface, tmz)
|
||||
}
|
||||
if sTime, err = args.CGREvent.FieldAsTime(utils.AnswerTime, tmz); err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
return
|
||||
}
|
||||
// not found, try SetupTime
|
||||
if sTime, err = args.CGREvent.FieldAsTime(utils.SetupTime, tmz); err != nil &&
|
||||
err != utils.ErrNotFound {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if args.CGREvent.Time != nil {
|
||||
return *args.CGREvent.Time, nil
|
||||
}
|
||||
return time.Now(), nil
|
||||
}
|
||||
|
||||
@@ -218,15 +191,23 @@ func (args *ArgsCostForEvent) Usage() (usage time.Duration, err error) {
|
||||
if uIface, has := args.Opts[utils.OptsRatesUsage]; has {
|
||||
return utils.IfaceAsDuration(uIface)
|
||||
}
|
||||
if usage, err = args.CGREvent.FieldAsDuration(utils.Usage); err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
return
|
||||
}
|
||||
}
|
||||
return time.Duration(time.Minute), nil
|
||||
}
|
||||
|
||||
// V1CostForEvent will be called to calculate the cost for an event
|
||||
func (rS *RateS) V1CostForEvent(args *ArgsCostForEvent, cC *utils.ChargedCost) (err error) {
|
||||
func (rS *RateS) V1CostForEvent(args *ArgsCostForEvent, rpCost *engine.RateProfileCost) (err error) {
|
||||
rPfIDs := make([]string, len(args.RateProfileIDs))
|
||||
for i, rpID := range args.RateProfileIDs {
|
||||
rPfIDs[i] = rpID
|
||||
}
|
||||
var rtPrl *engine.RateProfile
|
||||
if rtPrl, err = rS.matchingRateProfileForEvent(args.CGREventWithOpts.Tenant, rPfIDs, args); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
if rcvCost, errCost := rS.rateProfileCostForEvent(rtPrl, args); errCost != nil {
|
||||
return utils.NewErrServerError(errCost)
|
||||
} else {
|
||||
*rpCost = *rcvCost
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -61,137 +61,6 @@ func TestNewRateS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTime(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Time: utils.TimePointer(time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC)),
|
||||
Event: map[string]interface{}{
|
||||
utils.ToR: utils.SMS,
|
||||
},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
expectedTime := time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC)
|
||||
if sTime, err := argsCost.StartTime(utils.EmptyString); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedTime, sTime) {
|
||||
t.Errorf("Expected %+v, received %+v", expectedTime, sTime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTimeError(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.ToR: utils.SMS,
|
||||
},
|
||||
},
|
||||
Opts: map[string]interface{}{
|
||||
utils.OptsRatesStartTime: "invalidStartTime",
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
expectedErr := "Unsupported time format"
|
||||
if _, err := argsCost.StartTime(utils.EmptyString); err == nil || err.Error() != expectedErr {
|
||||
t.Errorf("Expected %+v, received %+v", expectedErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTimeFieldAsTimeErrorAnswerTime(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.AnswerTime: "0s",
|
||||
},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
expectedErr := "Unsupported time format"
|
||||
if _, err := argsCost.StartTime(utils.EmptyString); err == nil || err.Error() != expectedErr {
|
||||
t.Errorf("Expected %+v, received %+v", expectedErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTimeFieldAsTimeErrorSetupTime(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.SetupTime: "1h0m0s",
|
||||
},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
expectedErr := "Unsupported time format"
|
||||
if _, err := argsCost.StartTime(utils.EmptyString); err == nil || err.Error() != expectedErr {
|
||||
t.Errorf("Expected %+v, received %+v", expectedErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTimeFieldAsTimeNilTime(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Event: map[string]interface{}{
|
||||
utils.AnswerTime: time.Time{},
|
||||
},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
if _, err := argsCost.StartTime(utils.EmptyString); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTimeFieldAsTimeNow(t *testing.T) {
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Event: map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
if _, err := argsCost.StartTime(utils.EmptyString); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallRates(t *testing.T) {
|
||||
newRates := &RateS{}
|
||||
var reply *string
|
||||
@@ -201,25 +70,6 @@ func TestCallRates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestV1CostForEvent(t *testing.T) {
|
||||
rts := &RateS{}
|
||||
cgrEvent := &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "randomID",
|
||||
Event: map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
rateProfileIDs := []string{"randomIDs"}
|
||||
argsCost := &ArgsCostForEvent{
|
||||
rateProfileIDs,
|
||||
cgrEvent,
|
||||
}
|
||||
if err := rts.V1CostForEvent(argsCost, nil); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
defaultCfg, err := config.NewDefaultCGRConfig()
|
||||
if err != nil {
|
||||
@@ -247,7 +97,7 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if rtPRf, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if rtPRf, err := rate.matchingRateProfileForEvent("cgrates.org", []string{},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -260,14 +110,13 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{}); err != nil {
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rtPRf, rpp) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(rpp), utils.ToJSON(rtPRf))
|
||||
}
|
||||
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -280,11 +129,10 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{}); err != utils.ErrNotFound {
|
||||
}); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -297,11 +145,10 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{}); err != utils.ErrNotFound {
|
||||
}); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -314,12 +161,11 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{}); err != utils.ErrNotFound {
|
||||
}); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{"rp2"},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -332,30 +178,12 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{"rp2"}); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "CACHE1",
|
||||
Event: map[string]interface{}{},
|
||||
},
|
||||
Opts: map[string]interface{}{
|
||||
utils.OptsRatesStartTime: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{"randomProfileID"}); err.Error() != "cannot convert field: 0 to time.Time" {
|
||||
}); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
rpp.FilterIDs = []string{"*string:~*req.Account:1001;1002;1003", "*gt:~*req.Cost{*:10"}
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -368,13 +196,12 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{}); err.Error() != "invalid converter terminator in rule: <~*req.Cost{*>" {
|
||||
}); err.Error() != "invalid converter terminator in rule: <~*req.Cost{*>" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
rate.dm = nil
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org",
|
||||
if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{"rp3"},
|
||||
&ArgsCostForEvent{
|
||||
CGREventWithOpts: &utils.CGREventWithOpts{
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -387,8 +214,7 @@ func TestMatchingRateProfileEvent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{"rp3"}); err != utils.ErrNoDatabaseConn {
|
||||
}); err != utils.ErrNoDatabaseConn {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user