mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Update cdrc with FCTemplates
This commit is contained in:
committed by
Dan Christian Bogos
parent
ebcdc7c49f
commit
48928a528e
76
cdrc/csv.go
76
cdrc/csv.go
@@ -34,7 +34,7 @@ import (
|
||||
func NewCsvRecordsProcessor(csvReader *csv.Reader, timezone, fileName string,
|
||||
dfltCdrcCfg *config.CdrcConfig, cdrcCfgs []*config.CdrcConfig,
|
||||
httpSkipTlsCheck bool, unpairedRecordsCache *UnpairedRecordsCache, partialRecordsCache *PartialRecordsCache,
|
||||
cacheDumpFields []*config.CfgCdrField, filterS *engine.FilterS) *CsvRecordsProcessor {
|
||||
cacheDumpFields []*config.FCTemplate, filterS *engine.FilterS) *CsvRecordsProcessor {
|
||||
return &CsvRecordsProcessor{csvReader: csvReader, timezone: timezone, fileName: fileName,
|
||||
dfltCdrcCfg: dfltCdrcCfg, cdrcCfgs: cdrcCfgs, httpSkipTlsCheck: httpSkipTlsCheck, unpairedRecordsCache: unpairedRecordsCache,
|
||||
partialRecordsCache: partialRecordsCache, partialCacheDumpFields: cacheDumpFields, filterS: filterS}
|
||||
@@ -51,7 +51,7 @@ type CsvRecordsProcessor struct {
|
||||
httpSkipTlsCheck bool
|
||||
unpairedRecordsCache *UnpairedRecordsCache // Shared by cdrc so we can cache for all files in a folder
|
||||
partialRecordsCache *PartialRecordsCache // Cache records which are of type "Partial"
|
||||
partialCacheDumpFields []*config.CfgCdrField
|
||||
partialCacheDumpFields []*config.FCTemplate
|
||||
filterS *engine.FilterS
|
||||
}
|
||||
|
||||
@@ -115,22 +115,6 @@ func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR,
|
||||
cdrcCfg.Filters, csvProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
passes := true
|
||||
for _, rsrFilter := range cdrcCfg.CdrFilter { // here process old filter for entire CDR
|
||||
if rsrFilter == nil { // Nil filter does not need to match anything
|
||||
continue
|
||||
}
|
||||
if cfgFieldIdx, err := strconv.Atoi(rsrFilter.Id); err != nil || len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot compile filter %+v", record, rsrFilter)
|
||||
} else if _, err := rsrFilter.Parse(record[cfgFieldIdx]); err != nil {
|
||||
passes = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !passes { // Stop importing cdrc fields profile due to non matching filter
|
||||
continue
|
||||
}
|
||||
}
|
||||
storedCdr, err := self.recordToStoredCdr(record, cdrcCfg)
|
||||
if err != nil {
|
||||
@@ -154,10 +138,10 @@ func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR,
|
||||
func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *config.CdrcConfig) (*engine.CDR, error) {
|
||||
storedCdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
|
||||
var err error
|
||||
var lazyHttpFields []*config.CfgCdrField
|
||||
csvProvider := newCsvProvider(record) // used for filterS and for RSRParsers
|
||||
var lazyHttpFields []*config.FCTemplate
|
||||
for _, cdrFldCfg := range cdrcCfg.ContentFields {
|
||||
if len(cdrFldCfg.Filters) != 0 {
|
||||
csvProvider := newCsvProvider(record)
|
||||
tenant, err := cdrcCfg.Tenant.ParseValue("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -166,59 +150,23 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *con
|
||||
cdrcCfg.Filters, csvProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
passes := true
|
||||
for _, rsrFilter := range cdrFldCfg.FieldFilter { // here process old filter for a field from template
|
||||
if rsrFilter == nil { // Nil filter does not need to match anything
|
||||
continue
|
||||
}
|
||||
if cfgFieldIdx, err := strconv.Atoi(rsrFilter.Id); err != nil || len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot compile field filter %+v", record, rsrFilter)
|
||||
} else if _, err := rsrFilter.Parse(record[cfgFieldIdx]); err != nil {
|
||||
passes = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !passes { // Stop processing this field template since it's filters are not matching
|
||||
continue
|
||||
}
|
||||
}
|
||||
if utils.IsSliceMember([]string{utils.KAM_FLATSTORE, utils.OSIPS_FLATSTORE}, self.dfltCdrcCfg.CdrFormat) { // Hardcode some values in case of flatstore
|
||||
switch cdrFldCfg.FieldId {
|
||||
case utils.OriginID:
|
||||
cdrFldCfg.Value = utils.ParseRSRFieldsMustCompile("3;1;2", utils.INFIELD_SEP) // in case of flatstore, accounting id is made up out of callid, from_tag and to_tag
|
||||
cdrFldCfg.Value = config.NewRSRParsersMustCompile("~3;~1;~2", true) // in case of flatstore, accounting id is made up out of callid, from_tag and to_tag
|
||||
case utils.Usage:
|
||||
cdrFldCfg.Value = utils.ParseRSRFieldsMustCompile(strconv.Itoa(len(record)-1), utils.INFIELD_SEP) // in case of flatstore, last element will be the duration computed by us
|
||||
cdrFldCfg.Value = config.NewRSRParsersMustCompile("~"+strconv.Itoa(len(record)-1), true) // in case of flatstore, last element will be the duration computed by us
|
||||
}
|
||||
}
|
||||
var fieldVal string
|
||||
switch cdrFldCfg.Type {
|
||||
case utils.META_COMPOSED, utils.MetaUnixTimestamp:
|
||||
for _, cfgFieldRSR := range cdrFldCfg.Value {
|
||||
if cfgFieldRSR.IsStatic() {
|
||||
if parsed, err := cfgFieldRSR.Parse(""); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
|
||||
record, cdrFldCfg.Tag, err.Error())
|
||||
} else {
|
||||
fieldVal += parsed
|
||||
}
|
||||
} else { // Dynamic value extracted using index
|
||||
if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cdrFldCfg.Tag)
|
||||
} else {
|
||||
strVal, err := cfgFieldRSR.Parse(record[cfgFieldIdx])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
|
||||
record, cdrFldCfg.Tag, err.Error())
|
||||
}
|
||||
if cdrFldCfg.Type == utils.MetaUnixTimestamp {
|
||||
t, _ := utils.ParseTimeDetectLayout(strVal, self.timezone)
|
||||
strVal = strconv.Itoa(int(t.Unix()))
|
||||
}
|
||||
fieldVal += strVal
|
||||
}
|
||||
}
|
||||
out, err := cdrFldCfg.Value.ParseDataProvider(csvProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldVal = out
|
||||
case utils.META_HTTP_POST:
|
||||
lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of storedCdr to http server
|
||||
default:
|
||||
@@ -236,7 +184,7 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *con
|
||||
var outValByte []byte
|
||||
var fieldVal, httpAddr string
|
||||
for _, rsrFld := range httpFieldCfg.Value {
|
||||
if parsed, err := rsrFld.Parse(""); err != nil {
|
||||
if parsed, err := rsrFld.ParseValue(utils.EmptyString); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract http address for field %+v, err: %s",
|
||||
record, rsrFld, err.Error())
|
||||
} else {
|
||||
@@ -253,7 +201,7 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *con
|
||||
} else {
|
||||
fieldVal = string(outValByte)
|
||||
if len(fieldVal) == 0 && httpFieldCfg.Mandatory {
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.Tag)
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.ID)
|
||||
}
|
||||
if err := storedCdr.ParseFieldValue(httpFieldCfg.FieldId, fieldVal, self.timezone); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -31,16 +31,18 @@ func TestCsvRecordToCDR(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0]
|
||||
cdrcConfig.CdrSourceId = "TEST_CDRC"
|
||||
cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: utils.RunID, Type: utils.META_COMPOSED,
|
||||
FieldId: utils.RunID, Value: utils.ParseRSRFieldsMustCompile("^*default", utils.INFIELD_SEP)})
|
||||
cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.FCTemplate{
|
||||
ID: utils.RunID, Type: utils.META_COMPOSED, FieldId: utils.RunID,
|
||||
Value: config.NewRSRParsersMustCompile("*default", true)})
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: []*config.CdrcConfig{cdrcConfig}}
|
||||
cdrRow := []string{"firstField", "secondField"}
|
||||
_, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig)
|
||||
if err == nil {
|
||||
t.Error("Failed to corectly detect missing fields from record")
|
||||
}
|
||||
cdrRow = []string{"ignored", "ignored", utils.VOICE, "acc1", utils.META_PREPAID, "*out", "cgrates.org", "call", "1001", "1001", "+4986517174963",
|
||||
"2013-02-03 19:50:00", "2013-02-03 19:54:00", "62s", "supplier1", "172.16.1.1", "NORMAL_DISCONNECT"}
|
||||
cdrRow = []string{"ignored", "ignored", utils.VOICE, "acc1", utils.META_PREPAID, "*out", "cgrates.org",
|
||||
"call", "1001", "1001", "+4986517174963", "2013-02-03 19:50:00", "2013-02-03 19:54:00",
|
||||
"62s", "supplier1", "172.16.1.1", "NORMAL_DISCONNECT"}
|
||||
rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse CDR in rated cdr", err)
|
||||
@@ -73,8 +75,12 @@ func TestCsvDataMultiplyFactor(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0]
|
||||
cdrcConfig.CdrSourceId = "TEST_CDRC"
|
||||
cdrcConfig.ContentFields = []*config.CfgCdrField{&config.CfgCdrField{Tag: "TORField", Type: utils.META_COMPOSED, FieldId: utils.ToR, Value: []*utils.RSRField{&utils.RSRField{Id: "0"}}},
|
||||
&config.CfgCdrField{Tag: "UsageField", Type: utils.META_COMPOSED, FieldId: utils.Usage, Value: []*utils.RSRField{&utils.RSRField{Id: "1"}}}}
|
||||
cdrcConfig.ContentFields = []*config.FCTemplate{
|
||||
&config.FCTemplate{ID: "TORField", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: config.NewRSRParsersMustCompile("~0", true)},
|
||||
&config.FCTemplate{ID: "UsageField", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: config.NewRSRParsersMustCompile("~1", true)},
|
||||
}
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: []*config.CdrcConfig{cdrcConfig}}
|
||||
csvProcessor.cdrcCfgs[0].DataUsageMultiplyFactor = 0
|
||||
cdrRow := []string{"*data", "1"}
|
||||
|
||||
103
cdrc/fwv.go
103
cdrc/fwv.go
@@ -34,21 +34,6 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func fwvValue(cdrLine string, indexStart, width int, padding string) string {
|
||||
rawVal := cdrLine[indexStart : indexStart+width]
|
||||
switch padding {
|
||||
case "left":
|
||||
rawVal = strings.TrimLeft(rawVal, " ")
|
||||
case "right":
|
||||
rawVal = strings.TrimRight(rawVal, " ")
|
||||
case "zeroleft":
|
||||
rawVal = strings.TrimLeft(rawVal, "0 ")
|
||||
case "zeroright":
|
||||
rawVal = strings.TrimRight(rawVal, "0 ")
|
||||
}
|
||||
return rawVal
|
||||
}
|
||||
|
||||
func NewFwvRecordsProcessor(file *os.File, dfltCfg *config.CdrcConfig, cdrcCfgs []*config.CdrcConfig, httpClient *http.Client,
|
||||
httpSkipTlsCheck bool, timezone string, filterS *engine.FilterS) *FwvRecordsProcessor {
|
||||
return &FwvRecordsProcessor{file: file, cdrcCfgs: cdrcCfgs, dfltCfg: dfltCfg, httpSkipTlsCheck: httpSkipTlsCheck, timezone: timezone, filterS: filterS}
|
||||
@@ -138,10 +123,6 @@ func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) {
|
||||
cdrcCfg.Filters, fwvProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
if passes := self.recordPassesCfgFilter(record, cdrcCfg); !passes {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if storedCdr, err := self.recordToStoredCdr(record, cdrcCfg, cdrcCfg.ID); err != nil {
|
||||
return nil, fmt.Errorf("Failed converting to StoredCdr, error: %s", err.Error())
|
||||
@@ -155,29 +136,15 @@ func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) {
|
||||
return recordCdrs, nil
|
||||
}
|
||||
|
||||
func (self *FwvRecordsProcessor) recordPassesCfgFilter(record string, cdrcCfg *config.CdrcConfig) bool {
|
||||
for _, rsrFilter := range cdrcCfg.CdrFilter {
|
||||
if rsrFilter == nil { // Nil filter does not need to match anything
|
||||
continue
|
||||
}
|
||||
if cfgFieldIdx, err := strconv.Atoi(rsrFilter.Id); err != nil || len(record) <= cfgFieldIdx {
|
||||
fmt.Errorf("Ignoring record: %v - cannot compile filter %+v", record, rsrFilter)
|
||||
return false
|
||||
} else if _, err := rsrFilter.Parse(record[cfgFieldIdx:]); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Converts a record (header or normal) to CDR
|
||||
func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *config.CdrcConfig, cfgKey string) (*engine.CDR, error) {
|
||||
var err error
|
||||
var lazyHttpFields []*config.CfgCdrField
|
||||
var cfgFields []*config.CfgCdrField
|
||||
var lazyHttpFields []*config.FCTemplate
|
||||
var cfgFields []*config.FCTemplate
|
||||
var duMultiplyFactor float64
|
||||
var storedCdr *engine.CDR
|
||||
if self.headerCdr != nil { // Clone the header CDR so we can use it as base to future processing (inherit fields defined there)
|
||||
fwvProvider := newfwvProvider(record) // used for filterS and for RSRParsers
|
||||
if self.headerCdr != nil { // Clone the header CDR so we can use it as base to future processing (inherit fields defined there)
|
||||
storedCdr = self.headerCdr.Clone()
|
||||
} else {
|
||||
storedCdr = &engine.CDR{OriginHost: "0.0.0.0", ExtraFields: make(map[string]string), Cost: -1}
|
||||
@@ -193,7 +160,7 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *confi
|
||||
}
|
||||
for _, cdrFldCfg := range cfgFields {
|
||||
if len(cdrcCfg.Filters) != 0 {
|
||||
fwvProvider := newfwvProvider(record)
|
||||
|
||||
tenant, err := cdrcCfg.Tenant.ParseValue("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -202,58 +169,29 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *confi
|
||||
cdrcCfg.Filters, fwvProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
filterPass := true
|
||||
for _, rsrFilter := range cdrFldCfg.FieldFilter {
|
||||
if rsrFilter == nil { // Nil filter does not need to match anything
|
||||
continue
|
||||
}
|
||||
if cfgFieldIdx, err := strconv.Atoi(rsrFilter.Id); err != nil || len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot compile filter %+v", record, rsrFilter)
|
||||
} else if _, err := rsrFilter.Parse(record[cfgFieldIdx:]); err != nil {
|
||||
filterPass = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !filterPass {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var fieldVal string
|
||||
switch cdrFldCfg.Type {
|
||||
case utils.META_COMPOSED:
|
||||
for _, cfgFieldRSR := range cdrFldCfg.Value {
|
||||
if cfgFieldRSR.IsStatic() {
|
||||
if parsed, err := cfgFieldRSR.Parse(""); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
|
||||
record, cdrFldCfg.Tag, err.Error())
|
||||
} else {
|
||||
fieldVal += parsed
|
||||
}
|
||||
} else { // Dynamic value extracted using index
|
||||
cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id)
|
||||
if len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s",
|
||||
record, cdrFldCfg.Tag)
|
||||
}
|
||||
if parsed, err := cfgFieldRSR.Parse(fwvValue(record, cfgFieldIdx,
|
||||
cdrFldCfg.Width, cdrFldCfg.Padding)); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
|
||||
record, cdrFldCfg.Tag, err.Error())
|
||||
} else {
|
||||
fieldVal += parsed
|
||||
}
|
||||
}
|
||||
out, err := cdrFldCfg.Value.ParseDataProvider(fwvProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldVal = out
|
||||
case utils.META_HTTP_POST:
|
||||
lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of storedCdr to http server
|
||||
default:
|
||||
//return nil, fmt.Errorf("Unsupported field type: %s", cdrFldCfg.Type)
|
||||
continue // Don't do anything for unsupported fields
|
||||
}
|
||||
if fieldVal, err = utils.FmtFieldWidth(cdrFldCfg.ID, fieldVal, cdrFldCfg.Width,
|
||||
cdrFldCfg.Strip, cdrFldCfg.Padding, cdrFldCfg.Mandatory); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fieldVal, self.timezone); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
if storedCdr.CGRID == "" && storedCdr.OriginID != "" && cfgKey != "*header" {
|
||||
storedCdr.CGRID = utils.Sha1(storedCdr.OriginID, storedCdr.SetupTime.UTC().String())
|
||||
@@ -265,7 +203,7 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *confi
|
||||
var outValByte []byte
|
||||
var fieldVal, httpAddr string
|
||||
for _, rsrFld := range httpFieldCfg.Value {
|
||||
if parsed, err := rsrFld.Parse(""); err != nil {
|
||||
if parsed, err := rsrFld.ParseValue(utils.EmptyString); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract http address, err: %s",
|
||||
record, err.Error())
|
||||
} else {
|
||||
@@ -282,7 +220,7 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *confi
|
||||
} else {
|
||||
fieldVal = string(outValByte)
|
||||
if len(fieldVal) == 0 && httpFieldCfg.Mandatory {
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.Tag)
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.ID)
|
||||
}
|
||||
if err := storedCdr.ParseFieldValue(httpFieldCfg.FieldId, fieldVal, self.timezone); err != nil {
|
||||
return nil, err
|
||||
@@ -345,14 +283,23 @@ func (fP *fwvProvider) FieldAsInterface(fldPath []string) (data interface{}, err
|
||||
}
|
||||
err = nil // cancel previous err
|
||||
indexes := strings.Split(fldPath[0], "-")
|
||||
if len(indexes) != 2 {
|
||||
return "", fmt.Errorf("Invalid format for index : %+v", fldPath[0])
|
||||
}
|
||||
startIndex, err := strconv.Atoi(indexes[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if startIndex < len(fP.req) {
|
||||
return "", fmt.Errorf("Invalid start index : %+v", startIndex)
|
||||
}
|
||||
finalIndex, err := strconv.Atoi(indexes[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalIndex > len(fP.req) {
|
||||
return "", fmt.Errorf("Invalid final index : %+v", finalIndex)
|
||||
}
|
||||
data = fP.req[startIndex:finalIndex]
|
||||
fP.cache.Set(fldPath, data, false)
|
||||
return
|
||||
|
||||
@@ -94,17 +94,17 @@ func TestFwvitCreateCdrFiles(t *testing.T) {
|
||||
fwvCdrcCfg = cdrcCfg
|
||||
}
|
||||
}
|
||||
if err := os.RemoveAll(fwvCdrcCfg.CdrInDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", fwvCdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := os.MkdirAll(fwvCdrcCfg.CdrInDir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", fwvCdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := os.RemoveAll(fwvCdrcCfg.CdrOutDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", fwvCdrcCfg.CdrOutDir, err)
|
||||
}
|
||||
if err := os.MkdirAll(fwvCdrcCfg.CdrOutDir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", fwvCdrcCfg.CdrOutDir, err)
|
||||
for _, cdrcProfiles := range fwvCfg.CdrcProfiles {
|
||||
for _, cdrcInst := range cdrcProfiles {
|
||||
for _, dir := range []string{cdrcInst.CdrInDir, cdrcInst.CdrOutDir} {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Fatal("Error removing folder: ", dir, err)
|
||||
}
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", dir, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ func TestFwvitProcessFiles(t *testing.T) {
|
||||
if len(filesOutDir) != 1 {
|
||||
t.Errorf("In CdrcOutDir, expecting 1 files, got: %d", len(filesOutDir))
|
||||
}
|
||||
time.Sleep(time.Duration(1) * time.Second)
|
||||
}
|
||||
|
||||
func TestFwvitAnalyseCDRs(t *testing.T) {
|
||||
|
||||
@@ -16,38 +16,3 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package cdrc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestFwvValue(t *testing.T) {
|
||||
cdrLine := "CDR0000010 0 20120708181506000123451234 0040123123120 004 000018009980010001ISDN ABC 10Buiten uw regio EHV 00000009190000000009"
|
||||
if val := fwvValue(cdrLine, 30, 19, "right"); val != "0123451234" {
|
||||
t.Errorf("Received: <%s>", val)
|
||||
}
|
||||
if val := fwvValue(cdrLine, 14, 16, "right"); val != "2012070818150600" { // SetupTime
|
||||
t.Errorf("Received: <%s>", val)
|
||||
}
|
||||
if val := fwvValue(cdrLine, 127, 8, "right"); val != "00001800" { // Usage
|
||||
t.Errorf("Received: <%s>", val)
|
||||
}
|
||||
cdrLine = "HDR0001DDB ABC Some Connect A.B. DDB-Some-10022-20120711-309.CDR 00030920120711100255 "
|
||||
if val := fwvValue(cdrLine, 135, 6, "zeroleft"); val != "309" {
|
||||
t.Errorf("Received: <%s>", val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFwvRecordPassesCfgFilter(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0] // We don't really care that is for .csv since all we want to test are the filters
|
||||
cdrcConfig.CdrFilter = utils.ParseRSRFieldsMustCompile(`~52:s/^0(\d{9})/+49${1}/(^+49123123120)`, utils.INFIELD_SEP)
|
||||
fwvRp := &FwvRecordsProcessor{cdrcCfgs: cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"]}
|
||||
cdrLine := "CDR0000010 0 20120708181506000123451234 0040123123120 004 000018009980010001ISDN ABC 10Buiten uw regio EHV 00000009190000000009"
|
||||
if passesFilter := fwvRp.recordPassesCfgFilter(cdrLine, cdrcConfig); !passesFilter {
|
||||
t.Error("Not passes filter")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,9 @@ func (prc *PartialRecordsCache) dumpPartialRecords(originID string) {
|
||||
csvWriter := csv.NewWriter(fileOut)
|
||||
csvWriter.Comma = prc.csvSep
|
||||
for _, cdr := range prc.partialRecords[originID].cdrs {
|
||||
expRec, err := cdr.AsExportRecord(prc.partialRecords[originID].cacheDumpFields, prc.httpSkipTlsCheck, nil, prc.roundDecimals)
|
||||
//FOR THE MOMENTN USED
|
||||
// nil instead of prc.partialRecords[originID].cacheDumpFields
|
||||
expRec, err := cdr.AsExportRecord(nil, prc.httpSkipTlsCheck, nil, prc.roundDecimals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -178,15 +180,15 @@ func (prc *PartialRecordsCache) MergePartialCDRRecord(pCDR *PartialCDRRecord) (*
|
||||
return pCDRIf.(*engine.CDR), err
|
||||
}
|
||||
|
||||
func NewPartialCDRRecord(cdr *engine.CDR, cacheDumpFlds []*config.CfgCdrField) *PartialCDRRecord {
|
||||
func NewPartialCDRRecord(cdr *engine.CDR, cacheDumpFlds []*config.FCTemplate) *PartialCDRRecord {
|
||||
return &PartialCDRRecord{cdrs: []*engine.CDR{cdr}, cacheDumpFields: cacheDumpFlds}
|
||||
}
|
||||
|
||||
// PartialCDRRecord is a record which can be updated later
|
||||
// different from PartialFlatstoreRecordsCache which is incomplete (eg: need to calculate duration out of 2 records)
|
||||
type PartialCDRRecord struct {
|
||||
cdrs []*engine.CDR // Number of CDRs
|
||||
cacheDumpFields []*config.CfgCdrField // Fields template to use when dumping from cache on disk
|
||||
cdrs []*engine.CDR // Number of CDRs
|
||||
cacheDumpFields []*config.FCTemplate // Fields template to use when dumping from cache on disk
|
||||
}
|
||||
|
||||
// Part of sort interface
|
||||
|
||||
84
cdrc/xml.go
84
cdrc/xml.go
@@ -64,14 +64,14 @@ func elementText(xmlRes tree.Res, elmntPath string) (string, error) {
|
||||
|
||||
// handlerUsageDiff will calculate the usage as difference between timeEnd and timeStart
|
||||
// Expects the 2 arguments in template separated by |
|
||||
func handlerSubstractUsage(xmlElmnt tree.Res, argsTpl utils.RSRFields, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) {
|
||||
func handlerSubstractUsage(xmlElmnt tree.Res, argsTpl config.RSRParsers, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) {
|
||||
var argsStr string
|
||||
for _, rsrArg := range argsTpl {
|
||||
if rsrArg.Id == utils.HandlerArgSep {
|
||||
argsStr += rsrArg.Id
|
||||
if rsrArg.Rules == utils.HandlerArgSep {
|
||||
argsStr += rsrArg.Rules
|
||||
continue
|
||||
}
|
||||
absolutePath := utils.ParseHierarchyPath(rsrArg.Id, "")
|
||||
absolutePath := utils.ParseHierarchyPath(rsrArg.Rules, "")
|
||||
relPath := utils.HierarchyPath(absolutePath[len(cdrPath)-1:]) // Need relative path to the xmlElmnt
|
||||
argStr, _ := elementText(xmlElmnt, relPath.AsString("/", true))
|
||||
argsStr += argStr
|
||||
@@ -142,26 +142,6 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err
|
||||
cdrcCfg.Filters, xmlProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
filtersPassing := true
|
||||
for _, rsrFltr := range cdrcCfg.CdrFilter { // here process old filter for entire CDR
|
||||
if rsrFltr == nil {
|
||||
continue // Pass
|
||||
}
|
||||
absolutePath := utils.ParseHierarchyPath(rsrFltr.Id, "")
|
||||
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
|
||||
fieldVal, err := elementText(cdrXML, relPath.AsString("/", true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := rsrFltr.Parse(fieldVal); err != nil {
|
||||
filtersPassing = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !filtersPassing {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if cdr, err := xmlProc.recordToCDR(cdrXML, cdrcCfg); err != nil {
|
||||
return nil, fmt.Errorf("<CDRC> Failed converting to CDR, error: %s", err.Error())
|
||||
@@ -177,12 +157,12 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err
|
||||
|
||||
func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *config.CdrcConfig) (*engine.CDR, error) {
|
||||
cdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
|
||||
var lazyHttpFields []*config.CfgCdrField
|
||||
var lazyHttpFields []*config.FCTemplate
|
||||
var err error
|
||||
fldVals := make(map[string]string)
|
||||
xmlProvider := newXmlProvider(xmlEntity, xmlProc.cdrPath)
|
||||
for _, cdrFldCfg := range cdrcCfg.ContentFields {
|
||||
if len(cdrFldCfg.Filters) != 0 { //backward compatibility
|
||||
xmlProvider := newXmlProvider(xmlEntity, xmlProc.cdrPath)
|
||||
if len(cdrFldCfg.Filters) != 0 {
|
||||
tenant, err := cdrcCfg.Tenant.ParseValue("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -191,55 +171,19 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
|
||||
cdrcCfg.Filters, xmlProvider); err != nil || !pass {
|
||||
continue // Not passes filters, ignore this CDR
|
||||
}
|
||||
} else { //backward compatibility
|
||||
filtersPassing := true
|
||||
for _, rsrFltr := range cdrFldCfg.FieldFilter { // here process old filter for a field from template
|
||||
if rsrFltr == nil {
|
||||
continue // Pass
|
||||
}
|
||||
absolutePath := utils.ParseHierarchyPath(rsrFltr.Id, "")
|
||||
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
|
||||
fieldVal, err := elementText(xmlEntity, relPath.AsString("/", true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := rsrFltr.Parse(fieldVal); err != nil {
|
||||
filtersPassing = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !filtersPassing {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if cdrFldCfg.Type == utils.META_COMPOSED {
|
||||
for _, cfgFieldRSR := range cdrFldCfg.Value {
|
||||
if cfgFieldRSR.IsStatic() {
|
||||
if parsed, err := cfgFieldRSR.Parse(""); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
|
||||
xmlEntity, cdrFldCfg.Tag, err.Error())
|
||||
} else {
|
||||
fldVals[cdrFldCfg.FieldId] += parsed
|
||||
}
|
||||
|
||||
} else { // Dynamic value extracted using path
|
||||
absolutePath := utils.ParseHierarchyPath(cfgFieldRSR.Id, "")
|
||||
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
|
||||
if elmntText, err := elementText(xmlEntity, relPath.AsString("/", true)); err != nil && err != utils.ErrNotFound {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
|
||||
} else if parsed, err := cfgFieldRSR.Parse(elmntText); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
|
||||
} else {
|
||||
fldVals[cdrFldCfg.FieldId] += parsed
|
||||
}
|
||||
}
|
||||
out, err := cdrFldCfg.Value.ParseDataProvider(xmlProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fldVals[cdrFldCfg.FieldId] += out
|
||||
} else if cdrFldCfg.Type == utils.META_HTTP_POST {
|
||||
lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of cdr to http server
|
||||
} else if cdrFldCfg.Type == utils.META_HANDLER && cdrFldCfg.HandlerId == utils.HandlerSubstractUsage {
|
||||
usage, err := handlerSubstractUsage(xmlEntity, cdrFldCfg.Value, xmlProc.cdrPath, xmlProc.timezone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.ID, err.Error())
|
||||
}
|
||||
fldVals[cdrFldCfg.FieldId] += strconv.FormatFloat(usage.Seconds(), 'f', -1, 64)
|
||||
} else {
|
||||
@@ -257,7 +201,7 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
|
||||
var outValByte []byte
|
||||
var fieldVal, httpAddr string
|
||||
for _, rsrFld := range httpFieldCfg.Value {
|
||||
if parsed, err := rsrFld.Parse(""); err != nil {
|
||||
if parsed, err := rsrFld.ParseValue(utils.EmptyString); err != nil {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract http address, err: %s", xmlEntity, err.Error())
|
||||
} else {
|
||||
httpAddr += parsed
|
||||
@@ -273,7 +217,7 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
|
||||
} else {
|
||||
fieldVal = string(outValByte)
|
||||
if len(fieldVal) == 0 && httpFieldCfg.Mandatory {
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.Tag)
|
||||
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.ID)
|
||||
}
|
||||
if err := cdr.ParseFieldValue(httpFieldCfg.FieldId, fieldVal, xmlProc.timezone); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -196,7 +196,8 @@ func TestXMLHandlerSubstractUsage(t *testing.T) {
|
||||
xmlTree := xmltree.MustParseXML(bytes.NewBufferString(cdrXmlBroadsoft), optsNotStrict)
|
||||
cdrs := goxpath.MustExec(xp, xmlTree, nil)
|
||||
cdrWithUsage := cdrs[1]
|
||||
if usage, err := handlerSubstractUsage(cdrWithUsage, utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime", utils.INFIELD_SEP),
|
||||
if usage, err := handlerSubstractUsage(cdrWithUsage,
|
||||
config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>releaseTime;|;~broadWorksCDR>cdrData>basicModule>answerTime", true),
|
||||
utils.HierarchyPath([]string{"broadWorksCDR", "cdrData"}), "UTC"); err != nil {
|
||||
t.Error(err)
|
||||
} else if usage != time.Duration(13483000000) {
|
||||
@@ -214,31 +215,31 @@ func TestXMLRPProcess(t *testing.T) {
|
||||
CDRPath: utils.HierarchyPath([]string{"broadWorksCDR", "cdrData"}),
|
||||
CdrSourceId: "TestXML",
|
||||
CdrFilter: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>headerModule>type(Normal)", utils.INFIELD_SEP),
|
||||
ContentFields: []*config.CfgCdrField{
|
||||
&config.CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^*voice", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>localCallId", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^*rated", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^call", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>userNumber", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>calledNumber", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>startTime", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>answerTime", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Usage", Type: utils.META_HANDLER,
|
||||
ContentFields: []*config.FCTemplate{
|
||||
&config.FCTemplate{ID: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: config.NewRSRParsersMustCompile("*voice", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>localCallId", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: config.NewRSRParsersMustCompile("*rated", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: config.NewRSRParsersMustCompile("call", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>userNumber", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>calledNumber", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>startTime", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>answerTime", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Usage", Type: utils.META_HANDLER,
|
||||
FieldId: utils.Usage, HandlerId: utils.HandlerSubstractUsage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime",
|
||||
utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "UsageSeconds", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^s", utils.INFIELD_SEP), Mandatory: true},
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>releaseTime;|;~broadWorksCDR>cdrData>basicModule>answerTime",
|
||||
true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "UsageSeconds", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: config.NewRSRParsersMustCompile("s", true), Mandatory: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -282,31 +283,31 @@ func TestXMLRPProcessWithNewFilters(t *testing.T) {
|
||||
CDRPath: utils.HierarchyPath([]string{"broadWorksCDR", "cdrData"}),
|
||||
CdrSourceId: "XMLWithFilters",
|
||||
Filters: []string{"*string:broadWorksCDR>cdrData>headerModule>type:Normal"},
|
||||
ContentFields: []*config.CfgCdrField{
|
||||
&config.CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^*voice", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>localCallId", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^*rated", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^call", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>userNumber", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>calledNumber", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>startTime", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>answerTime", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Usage", Type: utils.META_HANDLER,
|
||||
ContentFields: []*config.FCTemplate{
|
||||
&config.FCTemplate{ID: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: config.NewRSRParsersMustCompile("*voice", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>localCallId", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: config.NewRSRParsersMustCompile("*rated", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: config.NewRSRParsersMustCompile("call", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>userNumber", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>calledNumber", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>startTime", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>answerTime", true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "Usage", Type: utils.META_HANDLER,
|
||||
FieldId: utils.Usage, HandlerId: utils.HandlerSubstractUsage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime",
|
||||
utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "UsageSeconds", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("^s", utils.INFIELD_SEP), Mandatory: true},
|
||||
Value: config.NewRSRParsersMustCompile("~broadWorksCDR>cdrData>basicModule>releaseTime;|;~broadWorksCDR>cdrData>basicModule>answerTime",
|
||||
true), Mandatory: true},
|
||||
&config.FCTemplate{ID: "UsageSeconds", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: config.NewRSRParsersMustCompile("s", true), Mandatory: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ type CdrcConfig struct {
|
||||
ContinueOnSuccess bool // Continue after execution
|
||||
PartialRecordCache time.Duration // Duration to cache partial records when not pairing
|
||||
PartialCacheExpiryAction string
|
||||
HeaderFields []*CfgCdrField
|
||||
ContentFields []*CfgCdrField
|
||||
TrailerFields []*CfgCdrField
|
||||
CacheDumpFields []*CfgCdrField
|
||||
HeaderFields []*FCTemplate
|
||||
ContentFields []*FCTemplate
|
||||
TrailerFields []*FCTemplate
|
||||
CacheDumpFields []*FCTemplate
|
||||
}
|
||||
|
||||
func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
|
||||
@@ -133,24 +133,16 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
|
||||
self.PartialCacheExpiryAction = *jsnCfg.Partial_cache_expiry_action
|
||||
}
|
||||
if jsnCfg.Header_fields != nil {
|
||||
if self.HeaderFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Header_fields); err != nil {
|
||||
return err
|
||||
}
|
||||
self.HeaderFields = FCTemplatesFromFCTemapltesJsonCfg(*jsnCfg.Header_fields)
|
||||
}
|
||||
if jsnCfg.Content_fields != nil {
|
||||
if self.ContentFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Content_fields); err != nil {
|
||||
return err
|
||||
}
|
||||
self.ContentFields = FCTemplatesFromFCTemapltesJsonCfg(*jsnCfg.Content_fields)
|
||||
}
|
||||
if jsnCfg.Trailer_fields != nil {
|
||||
if self.TrailerFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Trailer_fields); err != nil {
|
||||
return err
|
||||
}
|
||||
self.TrailerFields = FCTemplatesFromFCTemapltesJsonCfg(*jsnCfg.Trailer_fields)
|
||||
}
|
||||
if jsnCfg.Cache_dump_fields != nil {
|
||||
if self.CacheDumpFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Cache_dump_fields); err != nil {
|
||||
return err
|
||||
}
|
||||
self.CacheDumpFields = FCTemplatesFromFCTemapltesJsonCfg(*jsnCfg.Cache_dump_fields)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -185,10 +177,10 @@ func (self *CdrcConfig) Clone() *CdrcConfig {
|
||||
clnCdrc.CdrSourceId = self.CdrSourceId
|
||||
clnCdrc.PartialRecordCache = self.PartialRecordCache
|
||||
clnCdrc.PartialCacheExpiryAction = self.PartialCacheExpiryAction
|
||||
clnCdrc.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields))
|
||||
clnCdrc.ContentFields = make([]*CfgCdrField, len(self.ContentFields))
|
||||
clnCdrc.TrailerFields = make([]*CfgCdrField, len(self.TrailerFields))
|
||||
clnCdrc.CacheDumpFields = make([]*CfgCdrField, len(self.CacheDumpFields))
|
||||
clnCdrc.HeaderFields = make([]*FCTemplate, len(self.HeaderFields))
|
||||
clnCdrc.ContentFields = make([]*FCTemplate, len(self.ContentFields))
|
||||
clnCdrc.TrailerFields = make([]*FCTemplate, len(self.TrailerFields))
|
||||
clnCdrc.CacheDumpFields = make([]*FCTemplate, len(self.CacheDumpFields))
|
||||
for idx, fld := range self.HeaderFields {
|
||||
clonedVal := *fld
|
||||
clnCdrc.HeaderFields[idx] = &clonedVal
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"field_id": "ToR", "value": "~7:s/^(voice|data|sms|mms|generic)$/*$1/"},
|
||||
{"field_id": "AnswerTime", "value": "1"},
|
||||
{"field_id": "AnswerTime", "value": "~1"},
|
||||
{"field_id": "Usage", "value": "~9:s/^(\\d+)$/${1}s/"},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -482,8 +482,10 @@ func (self *CGRConfig) checkConfigSanity() error {
|
||||
if cdrcInst.CdrFormat == utils.CSV {
|
||||
for _, cdrFld := range cdrcInst.ContentFields {
|
||||
for _, rsrFld := range cdrFld.Value {
|
||||
if _, errConv := strconv.Atoi(rsrFld.Id); errConv != nil && !rsrFld.IsStatic() {
|
||||
return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.Id)
|
||||
if rsrFld.attrName != "" {
|
||||
if _, errConv := strconv.Atoi(rsrFld.attrName); errConv != nil {
|
||||
return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.attrName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,34 +257,34 @@ const CGRATES_CFG_JSON = `
|
||||
"partial_cache_expiry_action": "*dump_to_file", // action taken when cache when records in cache are timed-out <*dump_to_file|*post_cdr>
|
||||
"header_fields": [], // template of the import header fields
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "2", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "7", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "8", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "9", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "10", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "11", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "12", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "~2", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "~4", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "~7", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~8", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~9", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~10", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~11", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~12", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~13", "mandatory": true},
|
||||
],
|
||||
"trailer_fields": [], // template of the import trailer fields
|
||||
"cache_dump_fields": [ // template used when dumping cached CDR, eg: partial CDRs
|
||||
{"tag": "CGRID", "type": "*composed", "value": "CGRID"},
|
||||
{"tag": "RunID", "type": "*composed", "value": "RunID"},
|
||||
{"tag": "TOR", "type": "*composed", "value": "ToR"},
|
||||
{"tag": "OriginID", "type": "*composed", "value": "OriginID"},
|
||||
{"tag": "RequestType", "type": "*composed", "value": "RequestType"},
|
||||
{"tag": "Tenant", "type": "*composed", "value": "Tenant"},
|
||||
{"tag": "Category", "type": "*composed", "value": "Category"},
|
||||
{"tag": "Account", "type": "*composed", "value": "Account"},
|
||||
{"tag": "Subject", "type": "*composed", "value": "Subject"},
|
||||
{"tag": "Destination", "type": "*composed", "value": "Destination"},
|
||||
{"tag": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"tag": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"tag": "Usage", "type": "*composed", "value": "Usage"},
|
||||
{"tag": "Cost", "type": "*composed", "value": "Cost"},
|
||||
{"id": "CGRID", "type": "*composed", "value": "CGRID"},
|
||||
{"id": "RunID", "type": "*composed", "value": "RunID"},
|
||||
{"id": "TOR", "type": "*composed", "value": "ToR"},
|
||||
{"id": "OriginID", "type": "*composed", "value": "OriginID"},
|
||||
{"id": "RequestType", "type": "*composed", "value": "RequestType"},
|
||||
{"id": "Tenant", "type": "*composed", "value": "Tenant"},
|
||||
{"id": "Category", "type": "*composed", "value": "Category"},
|
||||
{"id": "Account", "type": "*composed", "value": "Account"},
|
||||
{"id": "Subject", "type": "*composed", "value": "Subject"},
|
||||
{"id": "Destination", "type": "*composed", "value": "Destination"},
|
||||
{"id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"id": "Usage", "type": "*composed", "value": "Usage"},
|
||||
{"id": "Cost", "type": "*composed", "value": "Cost"},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -373,74 +373,74 @@ func TestDfCdreJsonCfgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDfCdrcJsonCfg(t *testing.T) {
|
||||
eFields := []*CdrFieldJsonCfg{}
|
||||
cdrFields := []*CdrFieldJsonCfg{
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.ToR), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("2"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.OriginID), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("3"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.RequestType), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("4"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"), Field_id: utils.StringPointer(utils.Tenant), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("6"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.Category), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("7"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.Account), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("8"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.Subject), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("9"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.Destination), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("10"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SetupTime), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("11"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.AnswerTime), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("12"), Mandatory: utils.BoolPointer(true)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.Usage), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("13"), Mandatory: utils.BoolPointer(true)},
|
||||
eFields := []*FcTemplateJsonCfg{}
|
||||
cdrFields := []*FcTemplateJsonCfg{
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.ToR), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~2"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.OriginID), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~3"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.RequestType), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~4"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Tenant"), Field_id: utils.StringPointer(utils.Tenant), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~6"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.Category), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~7"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.Account), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~8"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.Subject), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~9"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.Destination), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~10"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SetupTime), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~11"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.AnswerTime), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~12"), Mandatory: utils.BoolPointer(true)},
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.Usage), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("~13"), Mandatory: utils.BoolPointer(true)},
|
||||
}
|
||||
cacheDumpFields := []*CdrFieldJsonCfg{
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("CGRID"),
|
||||
cacheDumpFields := []*FcTemplateJsonCfg{
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("CGRID"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.CGRID)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("RunID"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("RunID"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.RunID)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("TOR"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.ToR)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("OriginID"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.OriginID)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("RequestType"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.RequestType)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Tenant"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Tenant)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Category"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Category"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Category)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Account"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Account"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Account)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Subject"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Subject)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Destination"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Destination)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("SetupTime"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.SetupTime),
|
||||
Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("AnswerTime"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.AnswerTime),
|
||||
Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Usage"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.Usage)},
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"),
|
||||
&FcTemplateJsonCfg{Id: utils.StringPointer("Cost"),
|
||||
Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer(utils.COST)},
|
||||
}
|
||||
@@ -478,7 +478,7 @@ func TestDfCdrcJsonCfg(t *testing.T) {
|
||||
if cfg, err := dfCgrJsonCfg.CdrcJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfg, cfg) {
|
||||
t.Errorf("Expecting: \n%s\n, received: \n%s\n: ", utils.ToIJSON(eCfg), utils.ToIJSON(cfg))
|
||||
t.Errorf("Expecting: %s \n, received: %s: ", utils.ToIJSON(eCfg), utils.ToIJSON(cfg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1235,10 +1235,10 @@ func TestNewCgrJsonCfgFromFile(t *testing.T) {
|
||||
} else if !reflect.DeepEqual(eCfg, gCfg) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eCfg, gCfg)
|
||||
}
|
||||
cdrFields := []*CdrFieldJsonCfg{
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.ToR), Value: utils.StringPointer("~7:s/^(voice|data|sms|mms|generic)$/*$1/")},
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.AnswerTime), Value: utils.StringPointer("1")},
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.Usage), Value: utils.StringPointer(`~9:s/^(\d+)$/${1}s/`)},
|
||||
cdrFields := []*FcTemplateJsonCfg{
|
||||
&FcTemplateJsonCfg{Field_id: utils.StringPointer(utils.ToR), Value: utils.StringPointer("~7:s/^(voice|data|sms|mms|generic)$/*$1/")},
|
||||
&FcTemplateJsonCfg{Field_id: utils.StringPointer(utils.AnswerTime), Value: utils.StringPointer("~1")},
|
||||
&FcTemplateJsonCfg{Field_id: utils.StringPointer(utils.Usage), Value: utils.StringPointer(`~9:s/^(\d+)$/${1}s/`)},
|
||||
}
|
||||
eCfgCdrc := []*CdrcJsonCfg{
|
||||
&CdrcJsonCfg{
|
||||
@@ -1262,7 +1262,7 @@ func TestNewCgrJsonCfgFromFile(t *testing.T) {
|
||||
if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfgCdrc, cfg) {
|
||||
t.Errorf("Expecting:\n %+v\n received:\n %+v\n", utils.ToIJSON(eCfgCdrc), utils.ToIJSON(cfg))
|
||||
t.Errorf("Expecting: %+v \n received: %+v", utils.ToIJSON(eCfgCdrc), utils.ToIJSON(cfg))
|
||||
}
|
||||
eCfgSmFs := &FreeswitchAgentJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
|
||||
@@ -163,7 +163,7 @@ func TestCgrCfgCDRC(t *testing.T) {
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"field_id": "ToR", "type": "*composed", "value": "~7:s/^(voice|data|sms|mms|generic)$/*$1/"},
|
||||
{"field_id": "AnswerTime", "type": "*composed", "value": "1"},
|
||||
{"field_id": "AnswerTime", "type": "*composed", "value": "~1"},
|
||||
{"field_id": "Usage", "type": "*composed", "value": "~9:s/^(\\d+)$/${1}s/"},
|
||||
],
|
||||
},
|
||||
@@ -192,54 +192,56 @@ func TestCgrCfgCDRC(t *testing.T) {
|
||||
ContinueOnSuccess: false,
|
||||
PartialRecordCache: time.Duration(10 * time.Second),
|
||||
PartialCacheExpiryAction: "*dump_to_file",
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{FieldId: "ToR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP)},
|
||||
&CfgCdrField{FieldId: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP)},
|
||||
&CfgCdrField{FieldId: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP)},
|
||||
HeaderFields: make([]*FCTemplate, 0),
|
||||
ContentFields: []*FCTemplate{
|
||||
&FCTemplate{FieldId: "ToR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", true)},
|
||||
&FCTemplate{FieldId: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile("~1", true)},
|
||||
&FCTemplate{FieldId: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile("~9:s/^(\\d+)$/${1}s/", true)},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
CacheDumpFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RunID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.ToR, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OriginID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RequestType, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Tenant, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Category, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Account, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Subject, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Destination, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.SetupTime, utils.INFIELD_SEP),
|
||||
TrailerFields: make([]*FCTemplate, 0),
|
||||
CacheDumpFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.CGRID, true)},
|
||||
&FCTemplate{ID: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RunID, true)},
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.ToR, true)},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.OriginID, true)},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RequestType, true)},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Tenant, true)},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Category, true)},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Account, true)},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Subject, true)},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Destination, true)},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.SetupTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.AnswerTime, utils.INFIELD_SEP),
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.AnswerTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Usage, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Usage, true)},
|
||||
&FCTemplate{ID: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.COST, true)},
|
||||
},
|
||||
},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJsonStringWithDefaults(JSN_RAW_CFG); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) {
|
||||
t.Errorf("Expected: %+v, received: %+v", eCgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0], cgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0])
|
||||
t.Errorf("Expected: %+v,\n received: %+v",
|
||||
utils.ToJSON(eCgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0]),
|
||||
utils.ToJSON(cgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0]))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,83 +53,63 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
Tenant: NewRSRParsersMustCompile("cgrates.org", true),
|
||||
PartialRecordCache: time.Duration(10) * time.Second,
|
||||
PartialCacheExpiryAction: utils.MetaDumpToFile,
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
HeaderFields: make([]*FCTemplate, 0),
|
||||
ContentFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: NewRSRParsersMustCompile("~2", true), Mandatory: true},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: NewRSRParsersMustCompile("~3", true), Mandatory: true},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: NewRSRParsersMustCompile("~4", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: NewRSRParsersMustCompile("~6", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: NewRSRParsersMustCompile("~7", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: NewRSRParsersMustCompile("~8", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: NewRSRParsersMustCompile("~9", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: NewRSRParsersMustCompile("~10", true), Mandatory: true},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: NewRSRParsersMustCompile("~11", true), Mandatory: true},
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: NewRSRParsersMustCompile("~12", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: NewRSRParsersMustCompile("~13", true), Mandatory: true},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
CacheDumpFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RunID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.ToR, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OriginID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RequestType, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Tenant, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Category, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Account, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Subject, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Destination, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.SetupTime, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.AnswerTime, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Usage, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)},
|
||||
TrailerFields: make([]*FCTemplate, 0),
|
||||
CacheDumpFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.CGRID, true)},
|
||||
&FCTemplate{ID: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RunID, true)},
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.ToR, true)},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.OriginID, true)},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RequestType, true)},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Tenant, true)},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Category, true)},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Account, true)},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Subject, true)},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Destination, true)},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.SetupTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.AnswerTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Usage, true)},
|
||||
&FCTemplate{ID: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.COST, true)},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -152,83 +132,63 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
Tenant: NewRSRParsersMustCompile("cgrates.org", true),
|
||||
PartialRecordCache: time.Duration(10) * time.Second,
|
||||
PartialCacheExpiryAction: utils.MetaDumpToFile,
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
HeaderFields: make([]*FCTemplate, 0),
|
||||
ContentFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: NewRSRParsersMustCompile("~2", true), Mandatory: true},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: NewRSRParsersMustCompile("~3", true), Mandatory: true},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: NewRSRParsersMustCompile("~4", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: NewRSRParsersMustCompile("~6", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: NewRSRParsersMustCompile("~7", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: NewRSRParsersMustCompile("~8", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: NewRSRParsersMustCompile("~9", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: NewRSRParsersMustCompile("~10", true), Mandatory: true},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: NewRSRParsersMustCompile("~11", true), Mandatory: true},
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: NewRSRParsersMustCompile("~12", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: NewRSRParsersMustCompile("~13", true), Mandatory: true},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
CacheDumpFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RunID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.ToR, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OriginID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RequestType, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Tenant, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Category, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Account, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Subject, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Destination, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.SetupTime, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.AnswerTime, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Usage, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)},
|
||||
TrailerFields: make([]*FCTemplate, 0),
|
||||
CacheDumpFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.CGRID, true)},
|
||||
&FCTemplate{ID: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RunID, true)},
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.ToR, true)},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.OriginID, true)},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RequestType, true)},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Tenant, true)},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Category, true)},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Account, true)},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Subject, true)},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Destination, true)},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.SetupTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.AnswerTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Usage, true)},
|
||||
&FCTemplate{ID: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.COST, true)},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -251,53 +211,47 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
Tenant: NewRSRParsersMustCompile("cgrates.org", true),
|
||||
PartialRecordCache: time.Duration(10) * time.Second,
|
||||
PartialCacheExpiryAction: utils.MetaDumpToFile,
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
&CfgCdrField{Tag: "", Type: "", FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
&CfgCdrField{FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
HeaderFields: make([]*FCTemplate, 0),
|
||||
ContentFields: []*FCTemplate{
|
||||
&FCTemplate{FieldId: utils.ToR,
|
||||
Value: NewRSRParsersMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", true)},
|
||||
&FCTemplate{ID: "", Type: "", FieldId: utils.AnswerTime,
|
||||
Value: NewRSRParsersMustCompile("~1", true)},
|
||||
&FCTemplate{FieldId: utils.Usage,
|
||||
Value: NewRSRParsersMustCompile("~9:s/^(\\d+)$/${1}s/", true)},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
CacheDumpFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RunID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.ToR, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OriginID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RequestType, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Tenant, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Category, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Account, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Subject, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Destination, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.SetupTime, utils.INFIELD_SEP),
|
||||
TrailerFields: make([]*FCTemplate, 0),
|
||||
CacheDumpFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.CGRID, true)},
|
||||
&FCTemplate{ID: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RunID, true)},
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.ToR, true)},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.OriginID, true)},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RequestType, true)},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Tenant, true)},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Category, true)},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Account, true)},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Subject, true)},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Destination, true)},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.SetupTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.AnswerTime, utils.INFIELD_SEP),
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.AnswerTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Usage, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Usage, true)},
|
||||
&FCTemplate{ID: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.COST, true)},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -320,90 +274,67 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
Tenant: NewRSRParsersMustCompile("cgrates.org", true),
|
||||
PartialRecordCache: time.Duration(10) * time.Second,
|
||||
PartialCacheExpiryAction: utils.MetaDumpToFile,
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true},
|
||||
HeaderFields: make([]*FCTemplate, 0),
|
||||
ContentFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED, FieldId: utils.ToR,
|
||||
Value: NewRSRParsersMustCompile("~2", true), Mandatory: true},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.OriginID,
|
||||
Value: NewRSRParsersMustCompile("~3", true), Mandatory: true},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.RequestType,
|
||||
Value: NewRSRParsersMustCompile("~4", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.Tenant,
|
||||
Value: NewRSRParsersMustCompile("~6", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED, FieldId: utils.Category,
|
||||
Value: NewRSRParsersMustCompile("~7", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED, FieldId: utils.Account,
|
||||
Value: NewRSRParsersMustCompile("~8", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED, FieldId: utils.Subject,
|
||||
Value: NewRSRParsersMustCompile("~9", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: NewRSRParsersMustCompile("~10", true), Mandatory: true},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SetupTime,
|
||||
Value: NewRSRParsersMustCompile("~11", true), Mandatory: true},
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.AnswerTime,
|
||||
Value: NewRSRParsersMustCompile("~12", true), Mandatory: true},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED, FieldId: utils.Usage,
|
||||
Value: NewRSRParsersMustCompile("~13", true), Mandatory: true},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
CacheDumpFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RunID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.ToR, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OriginID, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.RequestType, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Tenant, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Category, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Account, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Subject, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Destination, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.SetupTime, utils.INFIELD_SEP),
|
||||
TrailerFields: make([]*FCTemplate, 0),
|
||||
CacheDumpFields: []*FCTemplate{
|
||||
&FCTemplate{ID: "CGRID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.CGRID, true)},
|
||||
&FCTemplate{ID: "RunID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RunID, true)},
|
||||
&FCTemplate{ID: "TOR", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.ToR, true)},
|
||||
&FCTemplate{ID: "OriginID", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.OriginID, true)},
|
||||
&FCTemplate{ID: "RequestType", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.RequestType, true)},
|
||||
&FCTemplate{ID: "Tenant", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Tenant, true)},
|
||||
&FCTemplate{ID: "Category", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Category, true)},
|
||||
&FCTemplate{ID: "Account", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Account, true)},
|
||||
&FCTemplate{ID: "Subject", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Subject, true)},
|
||||
&FCTemplate{ID: "Destination", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Destination, true)},
|
||||
&FCTemplate{ID: "SetupTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.SetupTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.AnswerTime, utils.INFIELD_SEP),
|
||||
&FCTemplate{ID: "AnswerTime", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.AnswerTime, true),
|
||||
Layout: "2006-01-02T15:04:05Z07:00"},
|
||||
&CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.Usage, utils.INFIELD_SEP)},
|
||||
&CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)},
|
||||
&FCTemplate{ID: "Usage", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.Usage, true)},
|
||||
&FCTemplate{ID: "Cost", Type: utils.META_COMPOSED,
|
||||
Value: NewRSRParsersMustCompile(utils.COST, true)},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) {
|
||||
t.Errorf("Expected: \n%s\n, received: \n%s\n",
|
||||
utils.ToJSON(eCgrCfg.CdrcProfiles), utils.ToJSON(cgrCfg.CdrcProfiles))
|
||||
t.Errorf("Expected: %s \n, received: %s", utils.ToJSON(eCgrCfg.CdrcProfiles), utils.ToJSON(cgrCfg.CdrcProfiles))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,12 @@ func NewFCTemplateFromFCTemplateJsonCfg(jsnCfg *FcTemplateJsonCfg) *FCTemplate {
|
||||
if jsnCfg.Break_on_success != nil {
|
||||
fcTmp.BreakOnSuccess = *jsnCfg.Break_on_success
|
||||
}
|
||||
if jsnCfg.Handler_id != nil {
|
||||
fcTmp.HandlerId = *jsnCfg.Handler_id
|
||||
}
|
||||
if jsnCfg.Layout != nil {
|
||||
fcTmp.Layout = *jsnCfg.Layout
|
||||
}
|
||||
return fcTmp
|
||||
}
|
||||
|
||||
@@ -83,6 +89,8 @@ type FCTemplate struct {
|
||||
Timezone string
|
||||
Blocker bool
|
||||
BreakOnSuccess bool
|
||||
HandlerId string // used by XML in CDRC
|
||||
Layout string // time format
|
||||
}
|
||||
|
||||
func FCTemplatesFromFCTemapltesJsonCfg(jsnCfgFlds []*FcTemplateJsonCfg) []*FCTemplate {
|
||||
|
||||
@@ -207,10 +207,10 @@ type CdrcJsonCfg struct {
|
||||
Max_open_files *int
|
||||
Partial_record_cache *string
|
||||
Partial_cache_expiry_action *string
|
||||
Header_fields *[]*CdrFieldJsonCfg
|
||||
Content_fields *[]*CdrFieldJsonCfg
|
||||
Trailer_fields *[]*CdrFieldJsonCfg
|
||||
Cache_dump_fields *[]*CdrFieldJsonCfg
|
||||
Header_fields *[]*FcTemplateJsonCfg
|
||||
Content_fields *[]*FcTemplateJsonCfg
|
||||
Trailer_fields *[]*FcTemplateJsonCfg
|
||||
Cache_dump_fields *[]*FcTemplateJsonCfg
|
||||
}
|
||||
|
||||
// SM-Generic config section
|
||||
@@ -588,4 +588,6 @@ type FcTemplateJsonCfg struct {
|
||||
Timezone *string
|
||||
Blocker *bool
|
||||
Break_on_success *bool
|
||||
Handler_id *string
|
||||
Layout *string
|
||||
}
|
||||
|
||||
@@ -32,34 +32,34 @@
|
||||
"partial_record_cache": "1s", // duration to cache partial records when not pairing
|
||||
"partial_cache_expiry_action": "*dump_to_file",
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "AccId1", "field_id": "OriginID", "type": "*composed", "value": "0"},
|
||||
{"tag": "AccId2", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"tag": "AccId3", "field_id": "OriginID", "type": "*composed", "value": "1"},
|
||||
{"tag": "AccId4", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"tag": "AccId5", "field_id": "OriginID", "type": "*composed", "value": "4"},
|
||||
{"tag": "OrderID", "field_id": "OrderID", "type": "*unix_timestamp", "value": "3"},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "~0:s/^49([1-9]\\d+)$/0$1/", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~1:s/^00(\\d+)$/+$1/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6:s/^(\\d+)$/${1}s/", "mandatory": true},
|
||||
{"tag": "Partial", "field_id": "Partial", "type": "*composed", "value": "^true", "field_filter": "10(partial)"},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"id": "AccId1", "field_id": "OriginID", "type": "*composed", "value": "~0"},
|
||||
{"id": "AccId2", "field_id": "OriginID", "type": "*composed", "value": "_"},
|
||||
{"id": "AccId3", "field_id": "OriginID", "type": "*composed", "value": "~1"},
|
||||
{"id": "AccId4", "field_id": "OriginID", "type": "*composed", "value": "_"},
|
||||
{"id": "AccId5", "field_id": "OriginID", "type": "*composed", "value": "~4"},
|
||||
{"id": "OrderID", "field_id": "OrderID", "type": "*unix_timestamp", "value": "~3"},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "*rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "cgrates.org", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~0:s/^49([1-9]\\d+)$/0$1/", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~1:s/^00(\\d+)$/+$1/", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~4", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~4", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6:s/^(\\d+)$/${1}s/", "mandatory": true},
|
||||
{"id": "Partial", "field_id": "Partial", "type": "*composed", "value": "true", "field_filter": "10(partial)"},
|
||||
],
|
||||
"cache_dump_fields": [
|
||||
{"tag": "OriginID", "type": "*composed", "value": "OriginID"},
|
||||
{"tag": "OrderID", "type": "*composed", "value": "OrderID"},
|
||||
{"tag": "RequestType", "type": "*composed", "value": "RequestType"},
|
||||
{"tag": "Account", "type": "*composed", "value": "Account"},
|
||||
{"tag": "Destination", "type": "*composed", "value": "Destination"},
|
||||
{"tag": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"tag": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"tag": "Usage", "type": "*composed", "value": "Usage"},
|
||||
{"tag": "Cost", "type": "*composed", "value": "Cost"},
|
||||
{"id": "OriginID", "type": "*composed", "value": "OriginID"},
|
||||
{"id": "OrderID", "type": "*composed", "value": "OrderID"},
|
||||
{"id": "RequestType", "type": "*composed", "value": "RequestType"},
|
||||
{"id": "Account", "type": "*composed", "value": "Account"},
|
||||
{"id": "Destination", "type": "*composed", "value": "Destination"},
|
||||
{"id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
{"id": "Usage", "type": "*composed", "value": "Usage"},
|
||||
{"id": "Cost", "type": "*composed", "value": "Cost"},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -72,23 +72,23 @@
|
||||
"partial_record_cache": "1s", // duration to cache partial records when not pairing
|
||||
"partial_cache_expiry_action": "*post_cdr",
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "AccId1", "field_id": "OriginID", "type": "*composed", "value": "0"},
|
||||
{"tag": "AccId2", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"tag": "AccId3", "field_id": "OriginID", "type": "*composed", "value": "1"},
|
||||
{"tag": "AccId4", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"tag": "AccId5", "field_id": "OriginID", "type": "*composed", "value": "4"},
|
||||
{"tag": "OrderID", "field_id": "OrderID", "type": "*unix_timestamp", "value": "3"},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "~0:s/^49([1-9]\\d+)$/0$1/", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~1:s/^00(\\d+)$/+$1/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6:s/^(\\d+)$/${1}s/", "mandatory": true},
|
||||
{"tag": "Partial", "field_id": "Partial", "type": "*composed", "value": "^true", "field_filter": "10(partial)"},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"id": "AccId1", "field_id": "OriginID", "type": "*composed", "value": "0"},
|
||||
{"id": "AccId2", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"id": "AccId3", "field_id": "OriginID", "type": "*composed", "value": "1"},
|
||||
{"id": "AccId4", "field_id": "OriginID", "type": "*composed", "value": "^_"},
|
||||
{"id": "AccId5", "field_id": "OriginID", "type": "*composed", "value": "4"},
|
||||
{"id": "OrderID", "field_id": "OrderID", "type": "*unix_timestamp", "value": "3"},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~0:s/^49([1-9]\\d+)$/0$1/", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~1:s/^00(\\d+)$/+$1/", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "4", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6:s/^(\\d+)$/${1}s/", "mandatory": true},
|
||||
{"id": "Partial", "field_id": "Partial", "type": "*composed", "value": "^true", "field_filter": "10(partial)"},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -38,21 +38,21 @@
|
||||
"cdr_out_dir": "/tmp/cdrctests/csvit2/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "csvit2", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "1", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "2", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "~1", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~2", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -32,21 +32,21 @@
|
||||
"cdr_source_id": "csvit1", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"filters":["*string:3:1002"], //filter Account to be 1002
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "1", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "2", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "~1", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~2", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -58,21 +58,21 @@
|
||||
"cdr_source_id": "csvit2", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"filters":["*string:3:1002","*string:1:*prepaid","*gte:6:70"], //filter Account to be 1002 and RequestType *prepaid
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "1", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "2", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "~1", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~2", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~3", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~5", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
{"id": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "~6", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -41,24 +41,24 @@
|
||||
"cdr_in_dir": "/tmp/cgr_flatstore/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgr_flatstore/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records
|
||||
"cdr_source_id": "flatstore", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"cdr_source_id": "flatstore", // free form field, id identifying the source of the CDRs within CDRS database
|
||||
"cdr_filter": "", // filter CDR records to import
|
||||
"partial_record_cache": "1s", // duration to cache partial records when not pairing
|
||||
"content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "AccId", "cdr_field_id": "accid", "type": "cdrfield", "mandatory": true},
|
||||
{"tag": "ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "7", "mandatory": true},
|
||||
{"tag": "Direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "^out", "mandatory": true},
|
||||
{"tag": "Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "cdr_field_id": "category", "type": "cdrfield", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "cdr_field_id": "account", "type": "cdrfield", "value": "8", "mandatory": true},
|
||||
{"tag": "Subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "8", "mandatory": true},
|
||||
{"tag": "Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "9", "mandatory": true},
|
||||
{"tag": "SetupTime", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "6", "mandatory": true},
|
||||
{"tag": "AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "6", "mandatory": true},
|
||||
{"tag": "Usage", "cdr_field_id": "usage", "type": "cdrfield", "mandatory": true},
|
||||
{"tag": "DisconnectCause", "cdr_field_id": "disconnect_cause", "type": "cdrfield", "value": "4;^ ;5", "mandatory": true},
|
||||
{"tag": "DialogId", "cdr_field_id": "DialogId", "type": "cdrfield", "value": "11"},
|
||||
"content_fields":[ // import template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"id": "Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "*voice", "mandatory": true},
|
||||
{"id": "AccId", "cdr_field_id": "accid", "type": "cdrfield", "mandatory": true},
|
||||
{"id": "ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "~7", "mandatory": true},
|
||||
{"id": "Direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "out", "mandatory": true},
|
||||
{"id": "Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "cgrates.org", "mandatory": true},
|
||||
{"id": "Category", "cdr_field_id": "category", "type": "cdrfield", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "cdr_field_id": "account", "type": "cdrfield", "value": "~8", "mandatory": true},
|
||||
{"id": "Subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "~8", "mandatory": true},
|
||||
{"id": "Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "~9", "mandatory": true},
|
||||
{"id": "SetupTime", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "~6", "mandatory": true},
|
||||
{"id": "AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "~6", "mandatory": true},
|
||||
{"id": "Usage", "cdr_field_id": "usage", "type": "cdrfield", "mandatory": true},
|
||||
{"id": "DisconnectCause", "cdr_field_id": "disconnect_cause", "type": "cdrfield", "value": "~4; ;~5", "mandatory": true},
|
||||
{"id": "DialogId", "cdr_field_id": "DialogId", "type": "cdrfield", "value": "~11"},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
},
|
||||
@@ -40,32 +39,32 @@
|
||||
"cdr_source_id": "cdrc", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"cdr_filter": "", // filter CDR records to import
|
||||
"header_fields": [
|
||||
{"tag": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "95", "width": 40, "padding":"right"},
|
||||
{"tag": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
|
||||
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
|
||||
{"id": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "~95-135", "padding":"right"},
|
||||
{"id": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
|
||||
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
|
||||
],
|
||||
"content_fields": [ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "Tor", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "width": 10, "padding":"right", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "52", "width": 28, "padding":"right", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "width": 8, "mandatory": true},
|
||||
{"tag": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "138", "width": 1, "mandatory": true},
|
||||
{"tag": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "103", "padding":"zeroleft", "width": 8},
|
||||
{"tag": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "115", "padding":"zeroleft", "width": 8},
|
||||
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "3", "width": 3, "padding":"zeroleft", "mandatory": true},
|
||||
{"tag": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "14", "width": 16, "padding":"right", "mandatory": true},
|
||||
"content_fields": [ // import template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"id": "Tor", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0-10", "padding":"right", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "cgrates.org", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~52-80", "padding":"right", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127-135:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "mandatory": true},
|
||||
{"id": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "~138-139", "mandatory": true},
|
||||
{"id": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~103-111", "padding":"zeroleft"},
|
||||
{"id": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~115-123", "padding":"zeroleft"},
|
||||
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~3-6", "padding":"zeroleft", "mandatory": true},
|
||||
{"id": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "~14-30", "padding":"right", "mandatory": true},
|
||||
],
|
||||
"trailer_fields": [
|
||||
{"tag": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "142", "width": 8},
|
||||
{"tag": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "150", "width": 12},
|
||||
{"id": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "~142-150"},
|
||||
{"id": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "~150-162"},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
},
|
||||
@@ -37,36 +36,36 @@
|
||||
"cdr_format": "fwv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
"cdr_in_dir": "/tmp/cgr_fwv/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgr_fwv/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "cdrc", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"cdr_source_id": "cdrc", // free form field, id identifying the source of the CDRs within CDRS database
|
||||
"cdr_filter": "", // filter CDR records to import
|
||||
"filters":["*string:0-10:CDR0000010"],
|
||||
"header_fields": [
|
||||
{"tag": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "95", "width": 40, "padding":"right"},
|
||||
{"tag": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
|
||||
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
|
||||
{"id": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "~95-135", "padding":"right"},
|
||||
{"id": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
|
||||
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
|
||||
],
|
||||
"content_fields": [ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "Tor", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "width": 10, "padding":"right", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "52", "width": 28, "padding":"right", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "width": 8, "mandatory": true},
|
||||
{"tag": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "138", "width": 1, "mandatory": true},
|
||||
{"tag": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "103", "padding":"zeroleft", "width": 8},
|
||||
{"tag": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "115", "padding":"zeroleft", "width": 8},
|
||||
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "3", "width": 3, "padding":"zeroleft", "mandatory": true},
|
||||
{"tag": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "14", "width": 16, "padding":"right", "mandatory": true},
|
||||
"content_fields": [ // import template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"id": "Tor", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0-10", "padding":"right", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "cgrates.org", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
|
||||
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~52-80", "padding":"right", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127-135:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "mandatory": true},
|
||||
{"id": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "~138-139", "mandatory": true},
|
||||
{"id": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~103-111", "padding":"zeroleft"},
|
||||
{"id": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~115-123", "padding":"zeroleft"},
|
||||
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~3-6", "padding":"zeroleft", "mandatory": true},
|
||||
{"id": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "~14-30", "padding":"right", "mandatory": true},
|
||||
],
|
||||
"trailer_fields": [
|
||||
{"tag": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "142", "width": 8},
|
||||
{"tag": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "150", "width": 12},
|
||||
{"id": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "~142-150"},
|
||||
{"id": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "~150-162"},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -27,18 +27,18 @@
|
||||
"cdr_path": "broadWorksCDR>cdrData",
|
||||
"cdr_source_id": "xmlit1",
|
||||
"cdr_filter": "broadWorksCDR>cdrData>headerModule>type(Normal)",
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>localCallId", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>userNumber", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>calledNumber", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>startTime", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*substract_usage", "value": "broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
"content_fields":[ // import content_fields template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>localCallId", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "*rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userNumber", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>calledNumber", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>startTime", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*substract_usage", "value": "~broadWorksCDR>cdrData>basicModule>releaseTime;|;~broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -27,18 +27,18 @@
|
||||
"cdr_path": "broadWorksCDR>cdrData",
|
||||
"cdr_source_id": "xmlit1",
|
||||
"filters": ["*string:broadWorksCDR>cdrData>basicModule>userNumber:1002","*string:broadWorksCDR>cdrData>headerModule>type:Normal"],
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>localCallId", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*rated", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>userNumber", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>calledNumber", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>startTime", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*substract_usage", "value": "broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
"content_fields":[ // import content_fields template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"id": "TOR", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
|
||||
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>localCallId", "mandatory": true},
|
||||
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "*rated", "mandatory": true},
|
||||
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
|
||||
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", "mandatory": true},
|
||||
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
|
||||
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>userNumber", "mandatory": true},
|
||||
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>calledNumber", "mandatory": true},
|
||||
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>startTime", "mandatory": true},
|
||||
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
{"id": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*substract_usage", "value": "~broadWorksCDR>cdrData>basicModule>releaseTime;|;~broadWorksCDR>cdrData>basicModule>answerTime", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user