diff --git a/engine/cdr.go b/engine/cdr.go index d239fc1d4..30f14ade4 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -154,10 +154,7 @@ func (cdr *CDR) FormatCost(shiftDecimals, roundDecimals int) string { // FieldAsString is used to retrieve fields as string, primary fields are const labeled func (cdr *CDR) FieldAsString(rsrPrs *config.RSRParser) (parsed string, err error) { parsed, err = rsrPrs.ParseDataProviderWithInterfaces( - utils.MapStorage{ - utils.MetaReq: cdr.AsMapStringIface(), - utils.MetaEC: cdr.CostDetails, - }, utils.NestingSep) + cdr.AsMapStorage(), utils.NestingSep) if err != nil { return } @@ -167,10 +164,7 @@ func (cdr *CDR) FieldAsString(rsrPrs *config.RSRParser) (parsed string, err erro // FieldsAsString concatenates values of multiple fields defined in template, used eg in CDR templates func (cdr *CDR) FieldsAsString(rsrFlds config.RSRParsers) string { outVal, err := rsrFlds.ParseDataProviderWithInterfaces( - utils.MapStorage{ - utils.MetaReq: cdr.AsMapStringIface(), - utils.MetaEC: cdr.CostDetails, - }, utils.NestingSep) + cdr.AsMapStorage(), utils.NestingSep) if err != nil { return "" } @@ -216,6 +210,16 @@ func (cdr *CDR) Clone() *CDR { return cln } +func (cdr *CDR) AsMapStorage() (mp utils.MapStorage) { + mp = utils.MapStorage{ + utils.MetaReq: cdr.AsMapStringIface(), + } + if cdr.CostDetails != nil { + mp[utils.MetaEC] = cdr.CostDetails + } + return +} + func (cdr *CDR) AsMapStringIface() (mp map[string]interface{}) { mp = make(map[string]interface{}) for fld, val := range cdr.ExtraFields { @@ -294,10 +298,7 @@ func (cdr *CDR) combimedCdrFieldVal(cfgCdrFld *config.FCTemplate, groupCDRs []*C if cdr.CGRID != grpCDR.CGRID { continue // We only care about cdrs with same primary cdr behind } - if pass, err := filterS.Pass(grpCDR.Tenant, cfgCdrFld.Filters, utils.MapStorage{ - utils.MetaReq: grpCDR.AsMapStringIface(), - utils.MetaEC: grpCDR.CostDetails, - }); err != nil { + if pass, err := filterS.Pass(grpCDR.Tenant, cfgCdrFld.Filters, grpCDR.AsMapStorage()); err != nil { return utils.EmptyString, err } else if !pass { continue @@ -407,10 +408,7 @@ func (cdr *CDR) formatField(cfgFld *config.FCTemplate, httpSkipTLSCheck bool, // ExportRecord is a []string to keep it compatible with encoding/csv Writer func (cdr *CDR) AsExportRecord(exportFields []*config.FCTemplate, httpSkipTLSCheck bool, groupedCDRs []*CDR, filterS *FilterS) (expRecord []string, err error) { - nM := utils.MapStorage{ - utils.MetaReq: cdr.AsMapStringIface(), - utils.MetaEC: cdr.CostDetails, - } + nM := cdr.AsMapStorage() for _, cfgFld := range exportFields { if !strings.HasPrefix(cfgFld.Path, utils.MetaExp+utils.NestingSep) { continue @@ -437,10 +435,7 @@ func (cdr *CDR) AsExportRecord(exportFields []*config.FCTemplate, func (cdr *CDR) AsExportMap(exportFields []*config.FCTemplate, httpSkipTLSCheck bool, groupedCDRs []*CDR, filterS *FilterS) (expMap map[string]string, err error) { expMap = make(map[string]string) - nM := utils.MapStorage{ - utils.MetaReq: cdr.AsMapStringIface(), - utils.MetaEC: cdr.CostDetails, - } + nM := cdr.AsMapStorage() for _, cfgFld := range exportFields { if !strings.HasPrefix(cfgFld.Path, utils.MetaExp+utils.NestingSep) { continue diff --git a/engine/cdre.go b/engine/cdre.go index 51e0159df..77e38bb55 100644 --- a/engine/cdre.go +++ b/engine/cdre.go @@ -390,10 +390,7 @@ func (cdre *CDRExporter) processCDRs() (err error) { continue } if len(cdre.exportTemplate.Filters) != 0 { - cgrDp := utils.MapStorage{ - utils.MetaReq: cdr.AsMapStringIface(), - utils.MetaEC: cdr.CostDetails, - } + cgrDp := cdr.AsMapStorage() if pass, err := cdre.filterS.Pass(cdre.exportTemplate.Tenant, cdre.exportTemplate.Filters, cgrDp); err != nil || !pass { continue // Not passes filters, ignore this CDR diff --git a/engine/eventcost.go b/engine/eventcost.go index bbcd888d2..04431a964 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -901,9 +901,6 @@ func (ec *EventCost) Trim(atUsage time.Duration) (srplusEC *EventCost, err error // FieldAsInterface func to implement DataProvider func (ec *EventCost) FieldAsInterface(fldPath []string) (val interface{}, err error) { - if len(fldPath) == 0 { - return nil, utils.ErrNotFound - } if val, err = ec.cache.FieldAsInterface(fldPath); err != nil { if err != utils.ErrNotFound { // item found in cache return diff --git a/engine/eventcost_test.go b/engine/eventcost_test.go index debf68a2f..a9f5fe51a 100644 --- a/engine/eventcost_test.go +++ b/engine/eventcost_test.go @@ -3050,3 +3050,19 @@ func TestECAsDataProvider2(t *testing.T) { t.Errorf("Unexpected error:%v", err) } } + +func TestECFieldAsInterfaceNilEventCost(t *testing.T) { + dft, _ := config.NewDefaultCGRConfig() + cdr, err := NewMapEvent(map[string]interface{}{}).AsCDR(dft, "cgrates.org", "UTC") + if err != nil { + t.Fatal(err) + } + nM := cdr.AsMapStorage() + if _, err := nM.FieldAsInterface([]string{"*ec", "Charges[0]", "Increments[0]", "Accounting", "Balance", "ID"}); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Fatalf("Expected error:%s, received: %v", utils.ErrNotFound.Error(), err) + } + + if _, err := nM.FieldAsInterface([]string{"*req", "CostDetails", "Charges[0]", "Increments[0]", "Accounting", "Balance", "ID"}); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Fatalf("Expected error:%s, received: %v", utils.ErrNotFound.Error(), err) + } +}