mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-23 08:08:45 +05:00
Merge fixes
This commit is contained in:
@@ -116,13 +116,13 @@ type RateSlot struct {
|
||||
// Used to set the durations we need out of strings
|
||||
func (self *RateSlot) SetDurations() error {
|
||||
var err error
|
||||
if self.rateUnitDur, err = ParseDurationWithSecs(self.RateUnit); err != nil {
|
||||
if self.rateUnitDur, err = ParseDurationWithNanosecs(self.RateUnit); err != nil {
|
||||
return err
|
||||
}
|
||||
if self.rateIncrementDur, err = ParseDurationWithSecs(self.RateIncrement); err != nil {
|
||||
if self.rateIncrementDur, err = ParseDurationWithNanosecs(self.RateIncrement); err != nil {
|
||||
return err
|
||||
}
|
||||
if self.groupIntervalStartDur, err = ParseDurationWithSecs(self.GroupIntervalStart); err != nil {
|
||||
if self.groupIntervalStartDur, err = ParseDurationWithNanosecs(self.GroupIntervalStart); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -738,7 +738,6 @@ type AttrExpFileCdrs struct {
|
||||
CdrHosts []string // If provided, it will filter cdrhost
|
||||
CdrSources []string // If provided, it will filter cdrsource
|
||||
ReqTypes []string // If provided, it will fiter reqtype
|
||||
Directions []string // If provided, it will fiter direction
|
||||
Tenants []string // If provided, it will filter tenant
|
||||
Categories []string // If provided, it will filter çategory
|
||||
Accounts []string // If provided, it will filter account
|
||||
@@ -763,7 +762,6 @@ func (self *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error)
|
||||
OriginHosts: self.CdrHosts,
|
||||
Sources: self.CdrSources,
|
||||
RequestTypes: self.ReqTypes,
|
||||
Directions: self.Directions,
|
||||
Tenants: self.Tenants,
|
||||
Categories: self.Categories,
|
||||
Accounts: self.Accounts,
|
||||
@@ -837,7 +835,6 @@ func (self *AttrGetCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
|
||||
OriginHosts: self.CdrHosts,
|
||||
Sources: self.CdrSources,
|
||||
RequestTypes: self.ReqTypes,
|
||||
Directions: self.Directions,
|
||||
Tenants: self.Tenants,
|
||||
Categories: self.Categories,
|
||||
Accounts: self.Accounts,
|
||||
@@ -881,7 +878,6 @@ type AttrRateCdrs struct {
|
||||
CdrHosts []string // If provided, it will filter cdrhost
|
||||
CdrSources []string // If provided, it will filter cdrsource
|
||||
ReqTypes []string // If provided, it will fiter reqtype
|
||||
Directions []string // If provided, it will fiter direction
|
||||
Tenants []string // If provided, it will filter tenant
|
||||
Categories []string // If provided, it will filter çategory
|
||||
Accounts []string // If provided, it will filter account
|
||||
@@ -904,7 +900,6 @@ func (attrRateCDRs *AttrRateCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, er
|
||||
Sources: attrRateCDRs.CdrSources,
|
||||
ToRs: attrRateCDRs.TORs,
|
||||
RequestTypes: attrRateCDRs.ReqTypes,
|
||||
Directions: attrRateCDRs.Directions,
|
||||
Tenants: attrRateCDRs.Tenants,
|
||||
Categories: attrRateCDRs.Categories,
|
||||
Accounts: attrRateCDRs.Accounts,
|
||||
@@ -1015,8 +1010,6 @@ type CDRsFilter struct {
|
||||
NotToRs []string // Filter specific TORs out
|
||||
RequestTypes []string // If provided, it will fiter reqtype
|
||||
NotRequestTypes []string // Filter out specific request types
|
||||
Directions []string // If provided, it will fiter direction
|
||||
NotDirections []string // Filter out specific directions
|
||||
Tenants []string // If provided, it will filter tenant
|
||||
NotTenants []string // If provided, it will filter tenant
|
||||
Categories []string // If provided, it will filter çategory
|
||||
@@ -1027,10 +1020,6 @@ type CDRsFilter struct {
|
||||
NotSubjects []string // Filter out specific subjects
|
||||
DestinationPrefixes []string // If provided, it will filter on destination prefix
|
||||
NotDestinationPrefixes []string // Filter out specific destination prefixes
|
||||
Suppliers []string // If provided, it will filter the supplier
|
||||
NotSuppliers []string // Filter out specific suppliers
|
||||
DisconnectCauses []string // Filter for disconnect Cause
|
||||
NotDisconnectCauses []string // Filter out specific disconnect causes
|
||||
Costs []float64 // Query based on costs specified
|
||||
NotCosts []float64 // Filter out specific costs out from result
|
||||
ExtraFields map[string]string // Query based on extra fields content
|
||||
@@ -1047,8 +1036,6 @@ type CDRsFilter struct {
|
||||
UpdatedAtEnd *time.Time // End interval, smaller than
|
||||
MinUsage string // Start of the usage interval (>=)
|
||||
MaxUsage string // End of the usage interval (<)
|
||||
MinPDD string // Start of the pdd interval (>=)
|
||||
MaxPDD string // End of the pdd interval (<)
|
||||
MinCost *float64 // Start of the cost interval (>=)
|
||||
MaxCost *float64 // End of the usage interval (<)
|
||||
Unscoped bool // Include soft-deleted records in results
|
||||
@@ -1071,8 +1058,6 @@ type RPCCDRsFilter struct {
|
||||
NotToRs []string // Filter specific TORs out
|
||||
RequestTypes []string // If provided, it will fiter reqtype
|
||||
NotRequestTypes []string // Filter out specific request types
|
||||
Directions []string // If provided, it will fiter direction
|
||||
NotDirections []string // Filter out specific directions
|
||||
Tenants []string // If provided, it will filter tenant
|
||||
NotTenants []string // If provided, it will filter tenant
|
||||
Categories []string // If provided, it will filter çategory
|
||||
@@ -1083,10 +1068,6 @@ type RPCCDRsFilter struct {
|
||||
NotSubjects []string // Filter out specific subjects
|
||||
DestinationPrefixes []string // If provided, it will filter on destination prefix
|
||||
NotDestinationPrefixes []string // Filter out specific destination prefixes
|
||||
Suppliers []string // If provided, it will filter the supplier
|
||||
NotSuppliers []string // Filter out specific suppliers
|
||||
DisconnectCauses []string // Filter for disconnect Cause
|
||||
NotDisconnectCauses []string // Filter out specific disconnect causes
|
||||
Costs []float64 // Query based on costs specified
|
||||
NotCosts []float64 // Filter out specific costs out from result
|
||||
ExtraFields map[string]string // Query based on extra fields content
|
||||
@@ -1103,8 +1084,6 @@ type RPCCDRsFilter struct {
|
||||
UpdatedAtEnd string // End interval, smaller than
|
||||
MinUsage string // Start of the usage interval (>=)
|
||||
MaxUsage string // End of the usage interval (<)
|
||||
MinPDD string // Start of the pdd interval (>=)
|
||||
MaxPDD string // End of the pdd interval (<)
|
||||
MinCost *float64 // Start of the cost interval (>=)
|
||||
MaxCost *float64 // End of the usage interval (<)
|
||||
Paginator // Add pagination
|
||||
@@ -1124,8 +1103,6 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
|
||||
NotSources: self.NotSources,
|
||||
RequestTypes: self.RequestTypes,
|
||||
NotRequestTypes: self.NotRequestTypes,
|
||||
Directions: self.Directions,
|
||||
NotDirections: self.NotDirections,
|
||||
Tenants: self.Tenants,
|
||||
NotTenants: self.NotTenants,
|
||||
Categories: self.Categories,
|
||||
@@ -1136,23 +1113,17 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
|
||||
NotSubjects: self.NotSubjects,
|
||||
DestinationPrefixes: self.DestinationPrefixes,
|
||||
NotDestinationPrefixes: self.NotDestinationPrefixes,
|
||||
Suppliers: self.Suppliers,
|
||||
NotSuppliers: self.NotSuppliers,
|
||||
DisconnectCauses: self.DisconnectCauses,
|
||||
NotDisconnectCauses: self.NotDisconnectCauses,
|
||||
Costs: self.Costs,
|
||||
NotCosts: self.NotCosts,
|
||||
ExtraFields: self.ExtraFields,
|
||||
NotExtraFields: self.NotExtraFields,
|
||||
OrderIDStart: self.OrderIDStart,
|
||||
OrderIDEnd: self.OrderIDEnd,
|
||||
MinUsage: self.MinUsage,
|
||||
MaxUsage: self.MaxUsage,
|
||||
MinPDD: self.MinPDD,
|
||||
MaxPDD: self.MaxPDD,
|
||||
MinCost: self.MinCost,
|
||||
MaxCost: self.MaxCost,
|
||||
Paginator: self.Paginator,
|
||||
Costs: self.Costs,
|
||||
NotCosts: self.NotCosts,
|
||||
ExtraFields: self.ExtraFields,
|
||||
NotExtraFields: self.NotExtraFields,
|
||||
OrderIDStart: self.OrderIDStart,
|
||||
OrderIDEnd: self.OrderIDEnd,
|
||||
MinUsage: self.MinUsage,
|
||||
MaxUsage: self.MaxUsage,
|
||||
MinCost: self.MinCost,
|
||||
MaxCost: self.MaxCost,
|
||||
Paginator: self.Paginator,
|
||||
}
|
||||
if len(self.SetupTimeStart) != 0 {
|
||||
if sTimeStart, err := ParseTimeDetectLayout(self.SetupTimeStart, timezone); err != nil {
|
||||
|
||||
@@ -113,9 +113,10 @@ const (
|
||||
TBLTPStats = "tp_stats"
|
||||
TBLTPThresholds = "tp_thresholds"
|
||||
TBLTPFilters = "tp_filters"
|
||||
TBLTPLcr = "tp_lcr"
|
||||
TBLSMCosts = "sm_costs"
|
||||
TBLCDRs = "cdrs"
|
||||
SMCostsTBL = "sm_costs"
|
||||
CDRsTBL = "cdrs"
|
||||
TBLTPLCRProfiles = "tp_lcr"
|
||||
TBLTPLcr = "tp_lcrs"
|
||||
TBLVersions = "versions"
|
||||
TIMINGS_CSV = "Timings.csv"
|
||||
DESTINATIONS_CSV = "Destinations.csv"
|
||||
@@ -409,7 +410,6 @@ const (
|
||||
UnsupportedMigrationTask = "unsupported migration task"
|
||||
NoStorDBConnection = "not connected to StorDB"
|
||||
UndefinedVersion = "undefined version"
|
||||
MetaSetVersions = "*set_versions"
|
||||
UnsupportedDB = "unsupported database"
|
||||
ACCOUNT_SUMMARY = "AccountSummary"
|
||||
TxtSuffix = ".txt"
|
||||
@@ -434,13 +434,6 @@ const (
|
||||
MetaEveryMinute = "*every_minute"
|
||||
MetaHourly = "*hourly"
|
||||
ID = "ID"
|
||||
MetaASR = "*asr"
|
||||
MetaACD = "*acd"
|
||||
MetaTCD = "*tcd"
|
||||
MetaACC = "*acc"
|
||||
MetaTCC = "*tcc"
|
||||
MetaPDD = "*pdd"
|
||||
MetaDDC = "*ddc"
|
||||
CacheDestinations = "destinations"
|
||||
CacheReverseDestinations = "reverse_destinations"
|
||||
CacheRatingPlans = "rating_plans"
|
||||
@@ -491,6 +484,7 @@ const (
|
||||
StatUpdate = "StatUpdate"
|
||||
ResourceUpdate = "ResourceUpdate"
|
||||
CDR = "CDR"
|
||||
CDRs = "CDRs"
|
||||
ExpiryTime = "ExpiryTime"
|
||||
AllowNegative = "AllowNegative"
|
||||
Disabled = "Disabled"
|
||||
@@ -577,6 +571,26 @@ const (
|
||||
MetaTpRatingProfile = "*TpRatingProfile"
|
||||
MetaStorDB = "*StorDB"
|
||||
MetaDataDB = "*DataDB"
|
||||
SMGenericV2UpdateSession = "SMGenericV2.UpdateSession"
|
||||
SMGenericV2InitiateSession = "SMGenericV2.InitiateSession"
|
||||
SMGenericV1UpdateSession = "SMGenericV1.UpdateSession"
|
||||
SMGenericV1InitiateSession = "SMGenericV1.InitiateSession"
|
||||
)
|
||||
|
||||
//Meta
|
||||
const (
|
||||
MetaASR = "*asr"
|
||||
MetaACD = "*acd"
|
||||
MetaTCD = "*tcd"
|
||||
MetaACC = "*acc"
|
||||
MetaTCC = "*tcc"
|
||||
MetaPDD = "*pdd"
|
||||
MetaDDC = "*ddc"
|
||||
)
|
||||
|
||||
//Migrator Metas
|
||||
const (
|
||||
MetaSetVersions = "*set_versions"
|
||||
)
|
||||
|
||||
func buildCacheInstRevPrefixes() {
|
||||
|
||||
@@ -289,6 +289,17 @@ func ParseDurationWithSecs(durStr string) (d time.Duration, err error) {
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits
|
||||
func ParseDurationWithNanosecs(durStr string) (d time.Duration, err error) {
|
||||
if durStr == "" {
|
||||
return
|
||||
}
|
||||
if _, err = strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered
|
||||
durStr += "ns"
|
||||
}
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
func AccountKey(tenant, account string) string {
|
||||
return fmt.Sprintf("%s:%s", tenant, account)
|
||||
}
|
||||
@@ -304,10 +315,15 @@ func MinDuration(d1, d2 time.Duration) time.Duration {
|
||||
// ParseZeroRatingSubject will parse the subject in the balance
|
||||
// returns duration if able to extract it from subject
|
||||
// returns error if not able to parse duration (ie: if ratingSubject is standard one)
|
||||
func ParseZeroRatingSubject(rateSubj string) (time.Duration, error) {
|
||||
func ParseZeroRatingSubject(tor, rateSubj string) (time.Duration, error) {
|
||||
rateSubj = strings.TrimSpace(rateSubj)
|
||||
if rateSubj == "" || rateSubj == ANY {
|
||||
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s"
|
||||
switch tor {
|
||||
case VOICE:
|
||||
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s"
|
||||
default:
|
||||
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1ns"
|
||||
}
|
||||
}
|
||||
if !strings.HasPrefix(rateSubj, ZERO_RATING_SUBJECT_PREFIX) {
|
||||
return 0, errors.New("malformed rating subject: " + rateSubj)
|
||||
@@ -479,34 +495,6 @@ func LogFull(v interface{}) {
|
||||
log.Print(ToIJSON(v))
|
||||
}
|
||||
|
||||
// Used to convert from generic interface type towards string value
|
||||
func ConvertIfaceToString(fld interface{}) (string, bool) {
|
||||
var strVal string
|
||||
var converted bool
|
||||
switch fld.(type) {
|
||||
case string:
|
||||
strVal = fld.(string)
|
||||
converted = true
|
||||
case int:
|
||||
strVal = strconv.Itoa(fld.(int))
|
||||
converted = true
|
||||
case int64:
|
||||
strVal = strconv.FormatInt(fld.(int64), 10)
|
||||
converted = true
|
||||
case bool:
|
||||
strVal = strconv.FormatBool(fld.(bool))
|
||||
converted = true
|
||||
case []uint8:
|
||||
var byteVal []byte
|
||||
if byteVal, converted = fld.([]byte); converted {
|
||||
strVal = string(byteVal)
|
||||
}
|
||||
default: // Maybe we are lucky and the value converts to string
|
||||
strVal, converted = fld.(string)
|
||||
}
|
||||
return strVal, converted
|
||||
}
|
||||
|
||||
// Simple object cloner, b should be a pointer towards a value into which we want to decode
|
||||
func Clone(a, b interface{}) error {
|
||||
buff := new(bytes.Buffer)
|
||||
|
||||
@@ -416,7 +416,7 @@ func TestParseZeroRatingSubject(t *testing.T) {
|
||||
subj := []string{"", "*zero1s", "*zero5m", "*zero10h"}
|
||||
dur := []time.Duration{time.Second, time.Second, 5 * time.Minute, 10 * time.Hour}
|
||||
for i, s := range subj {
|
||||
if d, err := ParseZeroRatingSubject(s); err != nil || d != dur[i] {
|
||||
if d, err := ParseZeroRatingSubject(VOICE, s); err != nil || d != dur[i] {
|
||||
t.Error("Error parsing rating subject: ", s, d, err)
|
||||
}
|
||||
}
|
||||
@@ -434,25 +434,6 @@ func TestConcatenatedKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertIfaceToString(t *testing.T) {
|
||||
val := interface{}("string1")
|
||||
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "string1" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}(123)
|
||||
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "123" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}([]byte("byte_val"))
|
||||
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "byte_val" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}(true)
|
||||
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "true" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMandatory(t *testing.T) {
|
||||
_, err := FmtFieldWidth("", "", 0, "", "", true)
|
||||
if err == nil {
|
||||
|
||||
@@ -46,6 +46,7 @@ var (
|
||||
ErrResourceUnavailable = errors.New("RESOURCE_UNAVAILABLE")
|
||||
ErrNoActiveSession = errors.New("NO_ACTIVE_SESSION")
|
||||
ErrPartiallyExecuted = errors.New("PARTIALLY_EXECUTED")
|
||||
ErrMaxUsageExceeded = errors.New("MAX_USAGE_EXCEEDED")
|
||||
)
|
||||
|
||||
// NewCGRError initialises a new CGRError
|
||||
|
||||
@@ -30,9 +30,6 @@ func CastFieldIfToString(fld interface{}) (string, bool) {
|
||||
var strVal string
|
||||
var converted bool
|
||||
switch fld.(type) {
|
||||
case string:
|
||||
strVal = fld.(string)
|
||||
converted = true
|
||||
case int:
|
||||
strVal = strconv.Itoa(fld.(int))
|
||||
converted = true
|
||||
|
||||
@@ -218,6 +218,22 @@ func TestStringToInterface(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCastFieldIfToString(t *testing.T) {
|
||||
val := interface{}("string1")
|
||||
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "string1" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}(123)
|
||||
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "123" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}([]byte("byte_val"))
|
||||
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "byte_val" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
val = interface{}(true)
|
||||
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "true" {
|
||||
t.Error(resVal, converted)
|
||||
}
|
||||
if strVal, cast := CastFieldIfToString(time.Duration(1 * time.Second)); !cast {
|
||||
t.Error("cannot cast time.Duration")
|
||||
} else if strVal != "1s" {
|
||||
|
||||
@@ -33,9 +33,12 @@ type ValueFormula struct {
|
||||
Static float64
|
||||
}
|
||||
|
||||
func ParseBalanceFilterValue(val string) (*ValueFormula, error) {
|
||||
u, err := strconv.ParseFloat(val, 64)
|
||||
if err == nil {
|
||||
func ParseBalanceFilterValue(tor string, val string) (*ValueFormula, error) {
|
||||
if tor == VOICE { // VOICE balance is parsed as nanoseconds with support for time duration strings
|
||||
if d, err := ParseDurationWithNanosecs(val); err == nil {
|
||||
return &ValueFormula{Static: float64(d.Nanoseconds())}, err
|
||||
}
|
||||
} else if u, err := strconv.ParseFloat(val, 64); err == nil {
|
||||
return &ValueFormula{Static: u}, err
|
||||
}
|
||||
var vf ValueFormula
|
||||
|
||||
@@ -19,6 +19,7 @@ package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -54,3 +55,24 @@ func TestValueFormulaDayYear(t *testing.T) {
|
||||
t.Error("error caclulating value using formula: ", x)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueFormulaParseBalanceFilterValue(t *testing.T) {
|
||||
eVF := &ValueFormula{Static: 10000000000.0}
|
||||
if vf, err := ParseBalanceFilterValue(VOICE, "10s"); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eVF, vf) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
|
||||
}
|
||||
eVF = &ValueFormula{Static: 1024.0}
|
||||
if vf, err := ParseBalanceFilterValue(DATA, "1024"); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eVF, vf) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
|
||||
}
|
||||
eVF = &ValueFormula{Static: 10.0}
|
||||
if vf, err := ParseBalanceFilterValue(MONETARY, "10"); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eVF, vf) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user