diff --git a/cdre/cdrexporter.go b/cdre/cdrexporter.go
index c21185d0a..1c227e9e8 100644
--- a/cdre/cdrexporter.go
+++ b/cdre/cdrexporter.go
@@ -37,6 +37,7 @@ const (
CONSTANT = "constant"
METATAG = "metatag"
CONCATENATED_CDRFIELD = "concatenated_cdrfield"
+ COMBIMED = "combimed"
HTTP_POST = "http_post"
META_EXPORTID = "export_id"
META_TIMENOW = "time_now"
diff --git a/config/cdreconfig.go b/config/cdreconfig.go
index 2dee8fbea..7fea319d0 100644
--- a/config/cdreconfig.go
+++ b/config/cdreconfig.go
@@ -90,6 +90,7 @@ type CdreCdrField struct {
Strip string
Padding string
Layout string
+ Filter *utils.RSRField
Mandatory bool
valueAsRsrField *utils.RSRField // Cached if the need arrises
}
diff --git a/config/xmlcdre.go b/config/xmlcdre.go
index bd0be8cea..54315ee40 100644
--- a/config/xmlcdre.go
+++ b/config/xmlcdre.go
@@ -105,26 +105,28 @@ type CgrXmlCfgCdrTrailer struct {
// CDR field
type CgrXmlCfgCdrField struct {
- XMLName xml.Name `xml:"field"`
- Name string `xml:"name,attr"`
- Type string `xml:"type,attr"`
- Value string `xml:"value,attr"`
- Width int `xml:"width,attr"` // Field width
- Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
- Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
- Layout string `xml:"layout,attr"` // Eg. time format layout
- Mandatory bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
- valueAsRsrField *utils.RSRField // Cached if the need arrises
+ XMLName xml.Name `xml:"field"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ Value string `xml:"value,attr"`
+ Width int `xml:"width,attr"` // Field width
+ Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
+ Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
+ Layout string `xml:"layout,attr"` // Eg. time format layout
+ Filter string `xml:"filter,attr"` // Eg. combimed filters
+ Mandatory bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
+ valueAsRsrField *utils.RSRField // Cached if the need arrises
+ filterAsRsrField *utils.RSRField
}
func (cdrFld *CgrXmlCfgCdrField) populateRSRField() (err error) {
- if cdrFld.Type != utils.CDRFIELD { // We only need rsrField in case of cdrfield type
- return nil
- }
- if cdrFld.valueAsRsrField, err = utils.NewRSRField(cdrFld.Value); err != nil {
- return err
- }
- return nil
+ cdrFld.valueAsRsrField, err = utils.NewRSRField(cdrFld.Value)
+ return err
+}
+
+func (cdrFld *CgrXmlCfgCdrField) populateFltrRSRField() (err error) {
+ cdrFld.filterAsRsrField, err = utils.NewRSRField(cdrFld.Filter)
+ return err
}
func (cdrFld *CgrXmlCfgCdrField) ValueAsRSRField() *utils.RSRField {
@@ -140,6 +142,7 @@ func (cdrFld *CgrXmlCfgCdrField) AsCdreCdrField() *CdreCdrField {
Strip: cdrFld.Strip,
Padding: cdrFld.Padding,
Layout: cdrFld.Layout,
+ Filter: cdrFld.filterAsRsrField,
Mandatory: cdrFld.Mandatory,
valueAsRsrField: cdrFld.valueAsRsrField,
}
diff --git a/config/xmlcdre_test.go b/config/xmlcdre_test.go
index dae9b5700..c1802e0c3 100644
--- a/config/xmlcdre_test.go
+++ b/config/xmlcdre_test.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package config
import (
+ "fmt"
"github.com/cgrates/cgrates/utils"
"reflect"
"strings"
@@ -38,12 +39,12 @@ func TestXmlCdreCfgPopulateCdreRSRFIeld(t *testing.T) {
if recv := cdreField.ValueAsRSRField(); !reflect.DeepEqual(valRSRField, recv) {
t.Errorf("Expecting %v, received %v", valRSRField, recv)
}
- cdreField = CgrXmlCfgCdrField{Name: "TEST1", Type: "constant", Value: `someval`}
+ /*cdreField = CgrXmlCfgCdrField{Name: "TEST1", Type: "constant", Value: `someval`}
if err := cdreField.populateRSRField(); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if cdreField.valueAsRsrField != nil {
t.Error("Should not load the RSRField")
- }
+ }*/
}
func TestXmlCdreCfgParseXmlConfig(t *testing.T) {
@@ -119,6 +120,7 @@ func TestXmlCdreCfgParseXmlConfig(t *testing.T) {
+
@@ -155,7 +157,7 @@ func TestXmlCdreCfgGetCdreCfg(t *testing.T) {
if cdreCsvCfg1 == nil {
t.Error("Could not parse CdreFw instance")
}
- if len(cdreCsvCfg1["CHECK-CSV1"].Content.Fields) != 5 {
+ if len(cdreCsvCfg1["CHECK-CSV1"].Content.Fields) != 6 {
t.Error("Unexpected number of content fields parsed", len(cdreCsvCfg1["CHECK-CSV1"].Content.Fields))
}
}
@@ -185,6 +187,7 @@ func TestXmlCdreCfgAsCdreConfig(t *testing.T) {
+
@@ -217,18 +220,21 @@ func TestXmlCdreCfgAsCdreConfig(t *testing.T) {
MaskLength: 1,
ExportDir: "/var/log/cgrates/cdre",
}
+ fltrCombiMed, _ := utils.NewRSRField("~mediation_runid:s/DEFAULT/SECOND_RUN/")
eCdreCfg.HeaderFields = []*CdreCdrField{
&CdreCdrField{
- Name: "TypeOfRecord",
- Type: "constant",
- Value: "10",
- Width: 2},
+ Name: "TypeOfRecord",
+ Type: "constant",
+ Value: "10",
+ Width: 2,
+ valueAsRsrField: &utils.RSRField{Id: "10"}},
&CdreCdrField{
- Name: "LastCdr",
- Type: "metatag",
- Value: "last_cdr_time",
- Layout: "020106150400",
- Width: 12},
+ Name: "LastCdr",
+ Type: "metatag",
+ Value: "last_cdr_time",
+ Layout: "020106150400",
+ Width: 12,
+ valueAsRsrField: &utils.RSRField{Id: "last_cdr_time"}},
}
eCdreCfg.ContentFields = []*CdreCdrField{
&CdreCdrField{
@@ -246,36 +252,53 @@ func TestXmlCdreCfgAsCdreConfig(t *testing.T) {
valueAsRsrField: &utils.RSRField{Id: "productid"},
},
&CdreCdrField{
- Name: "NetworkId",
- Type: "constant",
- Value: "3",
- Width: 1,
+ Name: "NetworkId",
+ Type: "constant",
+ Value: "3",
+ Width: 1,
+ valueAsRsrField: &utils.RSRField{Id: "3"},
},
&CdreCdrField{
- Name: "FromHttpPost1",
- Type: "http_post",
- Value: "https://localhost:8000",
- Width: 10,
- Strip: "xright",
- Padding: "left",
+ Name: "FromHttpPost1",
+ Type: "http_post",
+ Value: "https://localhost:8000",
+ Width: 10,
+ Strip: "xright",
+ Padding: "left",
+ valueAsRsrField: &utils.RSRField{Id: "https://localhost:8000"},
+ },
+ &CdreCdrField{
+ Name: "CombiMed1",
+ Type: "combimed",
+ Value: "cost",
+ Width: 10,
+ Strip: "xright",
+ Padding: "left",
+ Filter: fltrCombiMed,
+ valueAsRsrField: &utils.RSRField{Id: "cost"},
},
}
eCdreCfg.TrailerFields = []*CdreCdrField{
&CdreCdrField{
- Name: "DistributorCode",
- Type: "constant",
- Value: "VOI",
- Width: 3,
+ Name: "DistributorCode",
+ Type: "constant",
+ Value: "VOI",
+ Width: 3,
+ valueAsRsrField: &utils.RSRField{Id: "VOI"},
},
&CdreCdrField{
- Name: "FileSeqNr",
- Type: "metatag",
- Value: "export_id",
- Width: 5,
- Padding: "zeroleft",
+ Name: "FileSeqNr",
+ Type: "metatag",
+ Value: "export_id",
+ Width: 5,
+ Padding: "zeroleft",
+ valueAsRsrField: &utils.RSRField{Id: "export_id"},
},
}
if rcvCdreCfg := xmlCdreCfgs["CDRE-FW2"].AsCdreConfig(); !reflect.DeepEqual(rcvCdreCfg, eCdreCfg) {
+ for _, fld := range rcvCdreCfg.ContentFields {
+ fmt.Printf("Fld: %+v\n", fld)
+ }
t.Errorf("Expecting: %v, received: %v", eCdreCfg, rcvCdreCfg)
}
}
diff --git a/config/xmlconfig.go b/config/xmlconfig.go
index fbaedb7d7..b75b48b7a 100644
--- a/config/xmlconfig.go
+++ b/config/xmlconfig.go
@@ -109,12 +109,37 @@ func (xmlCfg *CgrXmlCfgDocument) cacheCdreCfgs() error {
} else if cdreCfg == nil {
return fmt.Errorf("Could not unmarshal CgrXmlCdreCfg: %s", cfgInst.Id)
}
+ if cdreCfg.Header != nil {
+ // Cache rsr fields
+ for _, fld := range cdreCfg.Header.Fields {
+ if err := fld.populateRSRField(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
+ }
+ if err := fld.populateFltrRSRField(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
+ }
+ }
+ }
if cdreCfg.Content != nil {
// Cache rsr fields
for _, fld := range cdreCfg.Content.Fields {
if err := fld.populateRSRField(); err != nil {
return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
}
+ if err := fld.populateFltrRSRField(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
+ }
+ }
+ }
+ if cdreCfg.Trailer != nil {
+ // Cache rsr fields
+ for _, fld := range cdreCfg.Trailer.Fields {
+ if err := fld.populateRSRField(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
+ }
+ if err := fld.populateFltrRSRField(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Name, err.Error())
+ }
}
}
xmlCfg.cdres[cfgInst.Id] = cdreCfg