Decimal NewDecimalFromUsage accepting empty string

This commit is contained in:
DanB
2021-08-28 12:39:55 +02:00
parent 59d7e71e4f
commit 14f5fe80f1
3 changed files with 24 additions and 87 deletions

View File

@@ -36,7 +36,7 @@ type SortedRoute struct {
sortingDataF64 map[string]float64 // only the data we sort after
}
// SortedRoutes is returned as part of GetRoutes call
// SortedRoutes represents all viable routes inside one routing profile
type SortedRoutes struct {
ProfileID string // Profile matched
Sorting string // Sorting algorithm

View File

@@ -183,91 +183,22 @@ func (rpS *RouteService) matchingRouteProfilesForEvent(ctx *context.Context, tnt
// costForEvent will compute cost out of accounts and rating plans for event
// returns map[string]interface{} with cost and relevant matching information inside
func (rpS *RouteService) costForEvent(ev *utils.CGREvent,
func (rpS *RouteService) costForEvent(ctx *context.Context, ev *utils.CGREvent,
acntIDs, rpIDs []string) (costData map[string]interface{}, err error) {
costData = make(map[string]interface{})
if err = ev.CheckMandatoryFields([]string{utils.AccountField,
utils.Destination, utils.SetupTime}); err != nil {
return
}
// var acnt , subj, dst string
// if acnt, err = ev.FieldAsString(utils.AccountField); err != nil {
// return
// }
// if subj, err = ev.FieldAsString(utils.Subject); err != nil {
// if err != utils.ErrNotFound {
// return
// }
// subj = acnt
// }
// if dst, err = ev.FieldAsString(utils.Destination); err != nil {
// return
// }
var sTime time.Time
if sTime, err = ev.FieldAsTime(utils.SetupTime, rpS.cgrcfg.GeneralCfg().DefaultTimezone); err != nil {
return
}
var usage time.Duration
if usage, err = ev.FieldAsDuration(utils.Usage); err != nil {
if err != utils.ErrNotFound {
return
}
// in case usage is missing from event we decide to use 1 minute as default
usage = time.Duration(1 * time.Minute)
err = nil
}
var accountMaxUsage time.Duration
var acntCost map[string]interface{}
var initialUsage time.Duration
if len(acntIDs) != 0 {
// if err := rpS.connMgr.Call(rpS.cgrcfg.RouteSCfg().RALsConns, nil, utils.ResponderGetMaxSessionTimeOnAccounts,
// &utils.GetMaxSessionTimeOnAccountsArgs{
// Tenant: ev.Tenant,
// Subject: subj,
// Destination: dst,
// SetupTime: sTime,
// Usage: usage,
// AccountIDs: acntIDs,
// }, &acntCost); err != nil {
// return nil, err
// }
if ifaceMaxUsage, has := acntCost[utils.CapMaxUsage]; has {
if accountMaxUsage, err = utils.IfaceAsDuration(ifaceMaxUsage); err != nil {
return nil, err
}
if usage > accountMaxUsage {
// remain usage needs to be covered by rating plans
if len(rpIDs) == 0 {
return nil, fmt.Errorf("no rating plans defined for remaining usage")
}
// update the setup time and the usage
sTime = sTime.Add(accountMaxUsage)
initialUsage = usage
}
for k, v := range acntCost { // update the costData with the infos from AccountS
costData[k] = v
}
}
var rpCost utils.RateProfileCost
if err = rpS.connMgr.Call(ctx, rpS.cgrcfg.RouteSCfg().RateSConns,
utils.RateSv1CostForEvent,
&utils.ArgsCostForEvent{
RateProfileIDs: rpIDs,
CGREvent: ev,
}, &rpCost); err != nil {
return nil, err
} else {
costData[utils.Cost], _ = rpCost.Cost.Float64()
costData[utils.RatingPlanID] = rpCost.ID
}
if accountMaxUsage == 0 || accountMaxUsage < initialUsage {
var rpCost map[string]interface{}
// if err := rpS.connMgr.Call(rpS.cgrcfg.RouteSCfg().RALsConns, nil, utils.ResponderGetCostOnRatingPlans,
// &utils.GetCostOnRatingPlansArgs{
// Tenant: ev.Tenant,
// Account: acnt,
// Subject: subj,
// Destination: dst,
// SetupTime: sTime,
// Usage: usage,
// RateProfileIDs: rpIDs,
// }, &rpCost); err != nil {
// return nil, err
// }
for k, v := range rpCost { // do not overwrite the return map
costData[k] = v
}
}
return
}
@@ -379,7 +310,7 @@ func (rpS *RouteService) populateSortingData(ctx *context.Context, ev *utils.CGR
}
//calculate costData if we have fields
if len(route.AccountIDs) != 0 || len(route.RateProfileIDs) != 0 {
costData, err := rpS.costForEvent(ev, route.AccountIDs, route.RateProfileIDs)
costData, err := rpS.costForEvent(ctx, ev, route.AccountIDs, route.RateProfileIDs)
if err != nil {
if extraOpts.ignoreErrors {
utils.Logger.Warning(
@@ -675,7 +606,7 @@ func (rpS *RouteService) sortedRoutesForProfile(ctx *context.Context, tnt string
return
}
// sortedRoutesForEvent will return the list of valid route IDs
// sortedRoutesForEvent will return the list of sortedRoutes
// for event based on filters and sorting algorithms
func (rpS *RouteService) sortedRoutesForEvent(ctx *context.Context, tnt string, args *ArgsGetRoutes) (sortedRoutes SortedRoutesList, err error) {
if _, has := args.CGREvent.Event[utils.Usage]; !has {

View File

@@ -106,6 +106,9 @@ func NewDecimalFromFloat64(f float64) *Decimal {
// NewDecimalFromUsage is a constructor for Decimal out of unit represents as string
func NewDecimalFromUsage(u string) (d *Decimal, err error) {
switch {
// There was no duration present, equivalent of 0 decimal
case u == EmptyString:
d = NewDecimal(0, 0)
//"ns", "us" (or "µs"), "ms", "s", "m", "h"
case strings.HasSuffix(u, NsSuffix), strings.HasSuffix(u, UsSuffix), strings.HasSuffix(u, µSuffix), strings.HasSuffix(u, MsSuffix),
strings.HasSuffix(u, SSuffix), strings.HasSuffix(u, MSuffix), strings.HasSuffix(u, HSuffix):
@@ -114,16 +117,14 @@ func NewDecimalFromUsage(u string) (d *Decimal, err error) {
return
}
d = NewDecimal(int64(tm), 0)
return
default:
var i int64
if i, err = strconv.ParseInt(u, 10, 64); err != nil {
return
}
d = NewDecimal(i, 0)
return
}
return
}
// NewDecimal is a constructor for Decimal, following the one of decimal.Big
@@ -200,3 +201,8 @@ func (d *Decimal) Round(rndDec int) *Decimal {
ctx.Precision = rndDec
return &Decimal{ctx.Round(d.Big)}
}
// Float64 returns the decimal as float64 number or !ok otherwise
func (d *Decimal) Float64() (f float64, ok bool) {
return d.Big.Float64()
}