diff --git a/cdrc/csv.go b/cdrc/csv.go index 586f19664..47e97ccf4 100644 --- a/cdrc/csv.go +++ b/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 diff --git a/cdrc/csv_test.go b/cdrc/csv_test.go index a95f36ad1..f304870ba 100644 --- a/cdrc/csv_test.go +++ b/cdrc/csv_test.go @@ -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"} diff --git a/cdrc/fwv.go b/cdrc/fwv.go index 6a5a9c4a8..fa9e3b0e6 100644 --- a/cdrc/fwv.go +++ b/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 diff --git a/cdrc/fwv_it_test.go b/cdrc/fwv_it_test.go index d2e3760b4..717588101 100644 --- a/cdrc/fwv_it_test.go +++ b/cdrc/fwv_it_test.go @@ -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) { diff --git a/cdrc/fwv_test.go b/cdrc/fwv_test.go index 39a16b453..aca6d2989 100644 --- a/cdrc/fwv_test.go +++ b/cdrc/fwv_test.go @@ -16,38 +16,3 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ 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") - } -} diff --git a/cdrc/partial_cdr.go b/cdrc/partial_cdr.go index 9a5aa5aba..2b8141e6a 100644 --- a/cdrc/partial_cdr.go +++ b/cdrc/partial_cdr.go @@ -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 diff --git a/cdrc/xml.go b/cdrc/xml.go index 87d427dff..6c1a8bc14 100644 --- a/cdrc/xml.go +++ b/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(" 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 diff --git a/cdrc/xml_test.go b/cdrc/xml_test.go index 17a38b5bb..17a96b0ee 100644 --- a/cdrc/xml_test.go +++ b/cdrc/xml_test.go @@ -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}, }, }, } diff --git a/config/cdrcconfig.go b/config/cdrcconfig.go index 9446ef696..59c14d61c 100644 --- a/config/cdrcconfig.go +++ b/config/cdrcconfig.go @@ -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 diff --git a/config/cfg_data.json b/config/cfg_data.json index f3bd28acd..9d2d9cf93 100644 --- a/config/cfg_data.json +++ b/config/cfg_data.json @@ -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/"}, ], }, diff --git a/config/config.go b/config/config.go index 59f5f328d..27a408eb2 100755 --- a/config/config.go +++ b/config/config.go @@ -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) + } } } } diff --git a/config/config_defaults.go b/config/config_defaults.go index 1940abb93..b9d6adab5 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -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"}, ], }, ], diff --git a/config/config_json_test.go b/config/config_json_test.go index 493c0fbea..62858d1d4 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -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), diff --git a/config/config_test.go b/config/config_test.go index 0449be154..5276d95ee 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -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])) } } diff --git a/config/configcdrc_test.go b/config/configcdrc_test.go index 4ea9f9ee0..63883a38d 100644 --- a/config/configcdrc_test.go +++ b/config/configcdrc_test.go @@ -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)) } } diff --git a/config/fctemplate.go b/config/fctemplate.go index 0aebac13c..72bc6d68e 100755 --- a/config/fctemplate.go +++ b/config/fctemplate.go @@ -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 { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index c6a2d1d05..bc65f7890 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -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 } diff --git a/data/conf/samples/cdrc_partcsv/cgrates.json b/data/conf/samples/cdrc_partcsv/cgrates.json index c9d9bf844..4b4335bcd 100644 --- a/data/conf/samples/cdrc_partcsv/cgrates.json +++ b/data/conf/samples/cdrc_partcsv/cgrates.json @@ -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)"}, ], }, ], diff --git a/data/conf/samples/cdrccsv/cgrates.json b/data/conf/samples/cdrccsv/cgrates.json index 90ce02fe1..efeb34b06 100644 --- a/data/conf/samples/cdrccsv/cgrates.json +++ b/data/conf/samples/cdrccsv/cgrates.json @@ -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}, ], }, ], diff --git a/data/conf/samples/cdrccsvwithfilter/cgrates.json b/data/conf/samples/cdrccsvwithfilter/cgrates.json index cb1a74ddb..d92f4ac2c 100755 --- a/data/conf/samples/cdrccsvwithfilter/cgrates.json +++ b/data/conf/samples/cdrccsvwithfilter/cgrates.json @@ -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}, ], }, ], diff --git a/data/conf/samples/cdrcflatstore/cgrates.json b/data/conf/samples/cdrcflatstore/cgrates.json index dd2b5f102..ca89452b4 100644 --- a/data/conf/samples/cdrcflatstore/cgrates.json +++ b/data/conf/samples/cdrcflatstore/cgrates.json @@ -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"}, ], }, ], diff --git a/data/conf/samples/cdrcfwv/cgrates.json b/data/conf/samples/cdrcfwv/cgrates.json index 318f6cf63..e75d88ab2 100644 --- a/data/conf/samples/cdrcfwv/cgrates.json +++ b/data/conf/samples/cdrcfwv/cgrates.json @@ -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"}, ], }, ], diff --git a/data/conf/samples/cdrcfwvwithfilter/cgrates.json b/data/conf/samples/cdrcfwvwithfilter/cgrates.json index 178d4ebfb..ccf138822 100755 --- a/data/conf/samples/cdrcfwvwithfilter/cgrates.json +++ b/data/conf/samples/cdrcfwvwithfilter/cgrates.json @@ -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 "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"}, ], }, ], diff --git a/data/conf/samples/cdrcxml/cgrates.json b/data/conf/samples/cdrcxml/cgrates.json index 4e73feb18..aa63a2e07 100644 --- a/data/conf/samples/cdrcxml/cgrates.json +++ b/data/conf/samples/cdrcxml/cgrates.json @@ -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}, ], }, ], diff --git a/data/conf/samples/cdrcxmlwithfilter/cgrates.json b/data/conf/samples/cdrcxmlwithfilter/cgrates.json index 736f8283f..9058608da 100755 --- a/data/conf/samples/cdrcxmlwithfilter/cgrates.json +++ b/data/conf/samples/cdrcxmlwithfilter/cgrates.json @@ -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}, ], }, ],