Update cdrc with FCTemplates

This commit is contained in:
TeoV
2018-08-24 11:34:07 -04:00
committed by Dan Christian Bogos
parent ebcdc7c49f
commit 48928a528e
25 changed files with 654 additions and 905 deletions

View File

@@ -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

View File

@@ -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"}

View File

@@ -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

View File

@@ -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) {

View File

@@ -16,38 +16,3 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package cdrc
import (
"testing"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
func TestFwvValue(t *testing.T) {
cdrLine := "CDR0000010 0 20120708181506000123451234 0040123123120 004 000018009980010001ISDN ABC 10Buiten uw regio EHV 00000009190000000009"
if val := fwvValue(cdrLine, 30, 19, "right"); val != "0123451234" {
t.Errorf("Received: <%s>", val)
}
if val := fwvValue(cdrLine, 14, 16, "right"); val != "2012070818150600" { // SetupTime
t.Errorf("Received: <%s>", val)
}
if val := fwvValue(cdrLine, 127, 8, "right"); val != "00001800" { // Usage
t.Errorf("Received: <%s>", val)
}
cdrLine = "HDR0001DDB ABC Some Connect A.B. DDB-Some-10022-20120711-309.CDR 00030920120711100255 "
if val := fwvValue(cdrLine, 135, 6, "zeroleft"); val != "309" {
t.Errorf("Received: <%s>", val)
}
}
func TestFwvRecordPassesCfgFilter(t *testing.T) {
cgrConfig, _ := config.NewDefaultCGRConfig()
cdrcConfig := cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0] // We don't really care that is for .csv since all we want to test are the filters
cdrcConfig.CdrFilter = utils.ParseRSRFieldsMustCompile(`~52:s/^0(\d{9})/+49${1}/(^+49123123120)`, utils.INFIELD_SEP)
fwvRp := &FwvRecordsProcessor{cdrcCfgs: cgrConfig.CdrcProfiles["/var/spool/cgrates/cdrc/in"]}
cdrLine := "CDR0000010 0 20120708181506000123451234 0040123123120 004 000018009980010001ISDN ABC 10Buiten uw regio EHV 00000009190000000009"
if passesFilter := fwvRp.recordPassesCfgFilter(cdrLine, cdrcConfig); !passesFilter {
t.Error("Not passes filter")
}
}

View File

@@ -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

View File

@@ -64,14 +64,14 @@ func elementText(xmlRes tree.Res, elmntPath string) (string, error) {
// handlerUsageDiff will calculate the usage as difference between timeEnd and timeStart
// Expects the 2 arguments in template separated by |
func handlerSubstractUsage(xmlElmnt tree.Res, argsTpl utils.RSRFields, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) {
func handlerSubstractUsage(xmlElmnt tree.Res, argsTpl config.RSRParsers, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) {
var argsStr string
for _, rsrArg := range argsTpl {
if rsrArg.Id == utils.HandlerArgSep {
argsStr += rsrArg.Id
if rsrArg.Rules == utils.HandlerArgSep {
argsStr += rsrArg.Rules
continue
}
absolutePath := utils.ParseHierarchyPath(rsrArg.Id, "")
absolutePath := utils.ParseHierarchyPath(rsrArg.Rules, "")
relPath := utils.HierarchyPath(absolutePath[len(cdrPath)-1:]) // Need relative path to the xmlElmnt
argStr, _ := elementText(xmlElmnt, relPath.AsString("/", true))
argsStr += argStr
@@ -142,26 +142,6 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err
cdrcCfg.Filters, xmlProvider); err != nil || !pass {
continue // Not passes filters, ignore this CDR
}
} else { //backward compatibility
filtersPassing := true
for _, rsrFltr := range cdrcCfg.CdrFilter { // here process old filter for entire CDR
if rsrFltr == nil {
continue // Pass
}
absolutePath := utils.ParseHierarchyPath(rsrFltr.Id, "")
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
fieldVal, err := elementText(cdrXML, relPath.AsString("/", true))
if err != nil {
return nil, err
}
if _, err := rsrFltr.Parse(fieldVal); err != nil {
filtersPassing = false
break
}
}
if !filtersPassing {
continue
}
}
if cdr, err := xmlProc.recordToCDR(cdrXML, cdrcCfg); err != nil {
return nil, fmt.Errorf("<CDRC> Failed converting to CDR, error: %s", err.Error())
@@ -177,12 +157,12 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err
func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *config.CdrcConfig) (*engine.CDR, error) {
cdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
var lazyHttpFields []*config.CfgCdrField
var lazyHttpFields []*config.FCTemplate
var err error
fldVals := make(map[string]string)
xmlProvider := newXmlProvider(xmlEntity, xmlProc.cdrPath)
for _, cdrFldCfg := range cdrcCfg.ContentFields {
if len(cdrFldCfg.Filters) != 0 { //backward compatibility
xmlProvider := newXmlProvider(xmlEntity, xmlProc.cdrPath)
if len(cdrFldCfg.Filters) != 0 {
tenant, err := cdrcCfg.Tenant.ParseValue("")
if err != nil {
return nil, err
@@ -191,55 +171,19 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
cdrcCfg.Filters, xmlProvider); err != nil || !pass {
continue // Not passes filters, ignore this CDR
}
} else { //backward compatibility
filtersPassing := true
for _, rsrFltr := range cdrFldCfg.FieldFilter { // here process old filter for a field from template
if rsrFltr == nil {
continue // Pass
}
absolutePath := utils.ParseHierarchyPath(rsrFltr.Id, "")
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
fieldVal, err := elementText(xmlEntity, relPath.AsString("/", true))
if err != nil {
return nil, err
}
if _, err := rsrFltr.Parse(fieldVal); err != nil {
filtersPassing = false
break
}
}
if !filtersPassing {
continue
}
}
if cdrFldCfg.Type == utils.META_COMPOSED {
for _, cfgFieldRSR := range cdrFldCfg.Value {
if cfgFieldRSR.IsStatic() {
if parsed, err := cfgFieldRSR.Parse(""); err != nil {
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s",
xmlEntity, cdrFldCfg.Tag, err.Error())
} else {
fldVals[cdrFldCfg.FieldId] += parsed
}
} else { // Dynamic value extracted using path
absolutePath := utils.ParseHierarchyPath(cfgFieldRSR.Id, "")
relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt
if elmntText, err := elementText(xmlEntity, relPath.AsString("/", true)); err != nil && err != utils.ErrNotFound {
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
} else if parsed, err := cfgFieldRSR.Parse(elmntText); err != nil {
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
} else {
fldVals[cdrFldCfg.FieldId] += parsed
}
}
out, err := cdrFldCfg.Value.ParseDataProvider(xmlProvider)
if err != nil {
return nil, err
}
fldVals[cdrFldCfg.FieldId] += out
} else if cdrFldCfg.Type == utils.META_HTTP_POST {
lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of cdr to http server
} else if cdrFldCfg.Type == utils.META_HANDLER && cdrFldCfg.HandlerId == utils.HandlerSubstractUsage {
usage, err := handlerSubstractUsage(xmlEntity, cdrFldCfg.Value, xmlProc.cdrPath, xmlProc.timezone)
if err != nil {
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error())
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.ID, err.Error())
}
fldVals[cdrFldCfg.FieldId] += strconv.FormatFloat(usage.Seconds(), 'f', -1, 64)
} else {
@@ -257,7 +201,7 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
var outValByte []byte
var fieldVal, httpAddr string
for _, rsrFld := range httpFieldCfg.Value {
if parsed, err := rsrFld.Parse(""); err != nil {
if parsed, err := rsrFld.ParseValue(utils.EmptyString); err != nil {
return nil, fmt.Errorf("Ignoring record: %v - cannot extract http address, err: %s", xmlEntity, err.Error())
} else {
httpAddr += parsed
@@ -273,7 +217,7 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con
} else {
fieldVal = string(outValByte)
if len(fieldVal) == 0 && httpFieldCfg.Mandatory {
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.Tag)
return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.ID)
}
if err := cdr.ParseFieldValue(httpFieldCfg.FieldId, fieldVal, xmlProc.timezone); err != nil {
return nil, err

View File

@@ -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},
},
},
}

View File

@@ -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

View File

@@ -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/"},
],
},

View File

@@ -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)
}
}
}
}

View File

@@ -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"},
],
},
],

View File

@@ -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),

View File

@@ -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]))
}
}

View File

@@ -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))
}
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)"},
],
},
],

View File

@@ -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},
],
},
],

View File

@@ -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},
],
},
],

View File

@@ -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"},
],
},
],

View File

@@ -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"},
],
},
],

View File

@@ -6,7 +6,6 @@
// This file contains the default configuration hardcoded into CGRateS.
// This is what you get when you load CGRateS with an empty configuration file.
"stor_db": { // database used to store offline tariff plans and CDRs
"db_password": "CGRateS.org", // password to use when connecting to stordb
},
@@ -37,36 +36,36 @@
"cdr_format": "fwv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
"cdr_in_dir": "/tmp/cgr_fwv/cdrc/in", // absolute path towards the directory where the CDRs are stored
"cdr_out_dir": "/tmp/cgr_fwv/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
"cdr_source_id": "cdrc", // free form field, tag identifying the source of the CDRs within CDRS database
"cdr_source_id": "cdrc", // free form field, id identifying the source of the CDRs within CDRS database
"cdr_filter": "", // filter CDR records to import
"filters":["*string:0-10:CDR0000010"],
"header_fields": [
{"tag": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "95", "width": 40, "padding":"right"},
{"tag": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "135", "width": 6, "padding":"zeroleft"},
{"id": "FileName", "field_id": "CdrFileName", "type": "*composed", "value": "~95-135", "padding":"right"},
{"id": "FileSeqNr", "field_id": "FileSeqNr", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~135-141", "padding":"zeroleft"},
],
"content_fields": [ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
{"tag": "Tor", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^rated", "mandatory": true},
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "width": 10, "padding":"right", "mandatory": true},
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "30", "width": 19, "padding":"right", "mandatory": true},
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "52", "width": 28, "padding":"right", "mandatory": true},
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "width": 16, "mandatory": true},
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "width": 8, "mandatory": true},
{"tag": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "138", "width": 1, "mandatory": true},
{"tag": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "103", "padding":"zeroleft", "width": 8},
{"tag": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "115", "padding":"zeroleft", "width": 8},
{"tag": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "3", "width": 3, "padding":"zeroleft", "mandatory": true},
{"tag": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "14", "width": 16, "padding":"right", "mandatory": true},
"content_fields": [ // import template, id will match internally CDR field, in case of .csv value will be represented by index of the field value
{"id": "Tor", "field_id": "ToR", "type": "*composed", "value": "*voice", "mandatory": true},
{"id": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "rated", "mandatory": true},
{"id": "Direction", "field_id": "Direction", "type": "*composed", "value": "*out", "mandatory": true},
{"id": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "~0-10", "padding":"right", "mandatory": true},
{"id": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "cgrates.org", "mandatory": true},
{"id": "Category", "field_id": "Category", "type": "*composed", "value": "call", "mandatory": true},
{"id": "Account", "field_id": "Account", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
{"id": "Subject", "field_id": "Subject", "type": "*composed", "value": "~30-49", "padding":"right", "mandatory": true},
{"id": "Destination", "field_id": "Destination", "type": "*composed", "value": "~52-80", "padding":"right", "mandatory": true},
{"id": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
{"id": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "~14-30:s/(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}-${2}-${3} ${4}:${5}:${6}/", "mandatory": true},
{"id": "Usage", "field_id": "Usage", "type": "*composed", "value": "~127-135:s/(\\d{2})(\\d{2})(\\d{2})(\\d{2})/${1}h${2}m${3}s/", "mandatory": true},
{"id": "DisconnectCause", "field_id": "DisconnectCause", "type": "*composed", "value": "~138-139", "mandatory": true},
{"id": "RetailAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~103-111", "padding":"zeroleft"},
{"id": "WholesaleAmount", "field_id": "RetailAmount", "type": "*composed", "value": "~115-123", "padding":"zeroleft"},
{"id": "AccId1", "field_id": "AccId1", "type": "*composed", "value": "~3-6", "padding":"zeroleft", "mandatory": true},
{"id": "AccId2", "field_id": "AccId2", "type": "*composed", "value": "~14-30", "padding":"right", "mandatory": true},
],
"trailer_fields": [
{"tag": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "142", "width": 8},
{"tag": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "150", "width": 12},
{"id": "NrOfCdrs", "type": "metatag", "metatag_id":"total_cdrs", "value": "~142-150"},
{"id": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "~150-162"},
],
},
],

View File

@@ -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},
],
},
],

View File

@@ -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},
],
},
],