diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go
index 7ce36fabb..4bfdf59c3 100644
--- a/apier/v1/cdre.go
+++ b/apier/v1/cdre.go
@@ -155,22 +155,6 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E
if attr.CostMultiplyFactor != nil && *attr.CostMultiplyFactor != 0.0 {
costMultiplyFactor = *attr.CostMultiplyFactor
}
- costShiftDigits := exportTemplate.CostShiftDigits
- if attr.CostShiftDigits != nil {
- costShiftDigits = *attr.CostShiftDigits
- }
- roundingDecimals := exportTemplate.CostRoundingDecimals
- if attr.RoundDecimals != nil {
- roundingDecimals = *attr.RoundDecimals
- }
- maskDestId := exportTemplate.MaskDestinationID
- if attr.MaskDestinationId != nil && len(*attr.MaskDestinationId) != 0 {
- maskDestId = *attr.MaskDestinationId
- }
- maskLen := exportTemplate.MaskLength
- if attr.MaskLength != nil {
- maskLen = *attr.MaskLength
- }
cdrsFltr, err := attr.AsCDRsFilter(self.Config.DefaultTimezone)
if err != nil {
return utils.NewErrServerError(err)
@@ -182,7 +166,8 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E
*reply = utils.ExportedFileCdrs{ExportedFilePath: ""}
return nil
}
- cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, exportId, dataUsageMultiplyFactor, smsUsageMultiplyFactor, mmsUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor, costShiftDigits, roundingDecimals, self.Config.RoundingDecimals, maskDestId, maskLen, self.Config.HttpSkipTlsVerify, self.Config.DefaultTimezone)
+ cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, exportId, dataUsageMultiplyFactor, smsUsageMultiplyFactor,
+ mmsUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor, self.Config.RoundingDecimals, self.Config.HttpSkipTlsVerify)
if err != nil {
return utils.NewErrServerError(err)
}
diff --git a/apier/v1/cdrstatsv1_local_test.go b/apier/v1/cdrstatsv1_local_test.go
index 0633189e8..f1286299e 100644
--- a/apier/v1/cdrstatsv1_local_test.go
+++ b/apier/v1/cdrstatsv1_local_test.go
@@ -18,8 +18,6 @@ along with this program. If not, see
package v1
import (
- "fmt"
- "net/http"
"net/rpc"
"net/rpc/jsonrpc"
"path"
@@ -116,7 +114,6 @@ func TestCDRStatsLclPostCdrs(t *testing.T) {
if !*testLocal {
return
}
- httpClient := new(http.Client)
storedCdrs := []*engine.CDR{
&engine.CDR{CGRID: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafa",
OriginHost: "192.168.1.1", Source: "test",
@@ -147,9 +144,10 @@ func TestCDRStatsLclPostCdrs(t *testing.T) {
Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
},
}
- for _, storedCdr := range storedCdrs {
- if _, err := httpClient.PostForm(fmt.Sprintf("http://%s/cdr_http", "127.0.0.1:2080"), storedCdr.AsHttpForm()); err != nil {
- t.Error(err.Error())
+ for _, cdr := range storedCdrs {
+ var reply string
+ if err := cdrstRpc.Call("CdrsV1.ProcessCdr", cdr, &reply); err != nil {
+ t.Error(err)
}
}
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
diff --git a/apier/v2/cdre.go b/apier/v2/cdre.go
index ab77197f2..62b8ba78f 100644
--- a/apier/v2/cdre.go
+++ b/apier/v2/cdre.go
@@ -91,22 +91,6 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut
if attr.CostMultiplyFactor != nil && *attr.CostMultiplyFactor != 0.0 {
costMultiplyFactor = *attr.CostMultiplyFactor
}
- costShiftDigits := exportTemplate.CostShiftDigits
- if attr.CostShiftDigits != nil {
- costShiftDigits = *attr.CostShiftDigits
- }
- roundingDecimals := exportTemplate.CostRoundingDecimals
- if attr.RoundDecimals != nil {
- roundingDecimals = *attr.RoundDecimals
- }
- maskDestId := exportTemplate.MaskDestinationID
- if attr.MaskDestinationID != nil && len(*attr.MaskDestinationID) != 0 {
- maskDestId = *attr.MaskDestinationID
- }
- maskLen := exportTemplate.MaskLength
- if attr.MaskLength != nil {
- maskLen = *attr.MaskLength
- }
cdrsFltr, err := attr.RPCCDRsFilter.AsCDRsFilter(self.Config.DefaultTimezone)
if err != nil {
return utils.NewErrServerError(err)
@@ -118,7 +102,8 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut
*reply = utils.ExportedFileCdrs{ExportedFilePath: ""}
return nil
}
- cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, ExportID, dataUsageMultiplyFactor, SMSUsageMultiplyFactor, MMSUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor, costShiftDigits, roundingDecimals, self.Config.RoundingDecimals, maskDestId, maskLen, self.Config.HttpSkipTlsVerify, self.Config.DefaultTimezone)
+ cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, ExportID, dataUsageMultiplyFactor, SMSUsageMultiplyFactor,
+ MMSUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor, self.Config.RoundingDecimals, self.Config.HttpSkipTlsVerify)
if err != nil {
return utils.NewErrServerError(err)
}
diff --git a/cdrc/partial_cdr.go b/cdrc/partial_cdr.go
index 2692fd788..e32f87a50 100644
--- a/cdrc/partial_cdr.go
+++ b/cdrc/partial_cdr.go
@@ -68,7 +68,7 @@ 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, 0, prc.roundDecimals, prc.timezone, prc.httpSkipTlsCheck, 0, "", nil)
+ expRec, err := cdr.AsExportRecord(prc.partialRecords[originID].cacheDumpFields, prc.httpSkipTlsCheck, nil)
if err != nil {
return nil, err
}
diff --git a/cdre/cdrexporter.go b/cdre/cdrexporter.go
index 71b907495..c05f3111e 100644
--- a/cdre/cdrexporter.go
+++ b/cdre/cdrexporter.go
@@ -49,7 +49,7 @@ var err error
func NewCdrExporter(cdrs []*engine.CDR, cdrDb engine.CdrStorage, exportTpl *config.CdreConfig, cdrFormat string, fieldSeparator rune, exportId string,
dataUsageMultiplyFactor, smsUsageMultiplyFactor, mmsUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor float64,
- costShiftDigits, roundDecimals, cgrPrecision int, maskDestId string, maskLen int, httpSkipTlsCheck bool, timezone string) (*CdrExporter, error) {
+ cgrPrecision int, httpSkipTlsCheck bool) (*CdrExporter, error) {
if len(cdrs) == 0 { // Nothing to export
return nil, nil
}
@@ -63,13 +63,8 @@ func NewCdrExporter(cdrs []*engine.CDR, cdrDb engine.CdrStorage, exportTpl *conf
dataUsageMultiplyFactor: dataUsageMultiplyFactor,
mmsUsageMultiplyFactor: mmsUsageMultiplyFactor,
costMultiplyFactor: costMultiplyFactor,
- costShiftDigits: costShiftDigits,
- roundDecimals: roundDecimals,
cgrPrecision: cgrPrecision,
- maskDestId: maskDestId,
httpSkipTlsCheck: httpSkipTlsCheck,
- timezone: timezone,
- maskLen: maskLen,
negativeExports: make(map[string]string),
}
if err := cdre.processCdrs(); err != nil {
@@ -90,16 +85,14 @@ type CdrExporter struct {
mmsUsageMultiplyFactor,
genericUsageMultiplyFactor,
costMultiplyFactor float64
- costShiftDigits, roundDecimals, cgrPrecision int
- maskDestId string
- maskLen int
- httpSkipTlsCheck bool
- timezone string
- header, trailer []string // Header and Trailer fields
- content [][]string // Rows of cdr fields
- firstCdrATime, lastCdrATime time.Time
- numberOfRecords int
- totalDuration, totalDataUsage, totalSmsUsage, totalMmsUsage, totalGenericUsage time.Duration
+ cgrPrecision int
+ httpSkipTlsCheck bool
+ header, trailer []string // Header and Trailer fields
+ content [][]string // Rows of cdr fields
+ firstCdrATime, lastCdrATime time.Time
+ numberOfRecords int
+ totalDuration, totalDataUsage, totalSmsUsage,
+ totalMmsUsage, totalGenericUsage time.Duration
totalCost float64
firstExpOrderId, lastExpOrderId int64
@@ -136,7 +129,7 @@ func (cdre *CdrExporter) metaHandler(tag, arg string) (string, error) {
emulatedCdr := &engine.CDR{ToR: utils.DATA, Usage: cdre.totalDataUsage}
return emulatedCdr.FormatUsage(arg), nil
case META_COSTCDRS:
- return strconv.FormatFloat(utils.Round(cdre.totalCost, cdre.roundDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64), nil
+ return strconv.FormatFloat(utils.Round(cdre.totalCost, cdre.cgrPrecision, utils.ROUNDING_MIDDLE), 'f', -1, 64), nil
default:
return "", fmt.Errorf("Unsupported METATAG: %s", tag)
}
@@ -220,7 +213,7 @@ func (cdre *CdrExporter) processCdr(cdr *engine.CDR) error {
if cdre.costMultiplyFactor != 0.0 {
cdr.CostMultiply(cdre.costMultiplyFactor, cdre.cgrPrecision)
}
- cdrRow, err := cdr.AsExportRecord(cdre.exportTemplate.ContentFields, cdre.costShiftDigits, cdre.roundDecimals, cdre.timezone, cdre.httpSkipTlsCheck, cdre.maskLen, cdre.maskDestId, cdre.cdrs)
+ cdrRow, err := cdr.AsExportRecord(cdre.exportTemplate.ContentFields, cdre.httpSkipTlsCheck, cdre.cdrs)
if err != nil {
utils.Logger.Err(fmt.Sprintf(" Cannot export CDR with CGRID: %s and runid: %s, error: %s", cdr.CGRID, cdr.RunID, err.Error()))
return err
@@ -255,7 +248,7 @@ func (cdre *CdrExporter) processCdr(cdr *engine.CDR) error {
}
if cdr.Cost != -1 {
cdre.totalCost += cdr.Cost
- cdre.totalCost = utils.Round(cdre.totalCost, cdre.roundDecimals, utils.ROUNDING_MIDDLE)
+ cdre.totalCost = utils.Round(cdre.totalCost, cdre.cgrPrecision, utils.ROUNDING_MIDDLE)
}
if cdre.firstExpOrderId > cdr.OrderID || cdre.firstExpOrderId == 0 {
cdre.firstExpOrderId = cdr.OrderID
diff --git a/cdre/csv_test.go b/cdre/csv_test.go
index a1451d67e..4616ff759 100644
--- a/cdre/csv_test.go
+++ b/cdre/csv_test.go
@@ -39,8 +39,7 @@ func TestCsvCdrWriter(t *testing.T) {
Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID,
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
}
- cdre, err := NewCdrExporter([]*engine.CDR{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, ',', "firstexport", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 4,
- cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "")
+ cdre, err := NewCdrExporter([]*engine.CDR{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, ',', "firstexport", 0.0, 0.0, 0.0, 0.0, 0.0, cfg.RoundingDecimals, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error("Unexpected error received: ", err)
}
@@ -68,7 +67,7 @@ func TestAlternativeFieldSeparator(t *testing.T) {
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
}
cdre, err := NewCdrExporter([]*engine.CDR{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, '|',
- "firstexport", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "")
+ "firstexport", 0.0, 0.0, 0.0, 0.0, 0.0, cfg.RoundingDecimals, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error("Unexpected error received: ", err)
}
diff --git a/cdre/fixedwidth_test.go b/cdre/fixedwidth_test.go
index debc1cf03..d6a40b7c2 100644
--- a/cdre/fixedwidth_test.go
+++ b/cdre/fixedwidth_test.go
@@ -125,8 +125,8 @@ func TestWriteCdr(t *testing.T) {
Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 2.34567,
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
}
- cdre, err := NewCdrExporter([]*engine.CDR{cdr}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 4,
- cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify, "")
+ cdre, err := NewCdrExporter([]*engine.CDR{cdr}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0.0, 0.0, 0.0,
+ cfg.RoundingDecimals, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error(err)
}
@@ -152,7 +152,7 @@ func TestWriteCdr(t *testing.T) {
t.Error("Unexpected number of records in the stats: ", cdre.numberOfRecords)
} else if cdre.totalDuration != cdr.Usage {
t.Error("Unexpected total duration in the stats: ", cdre.totalDuration)
- } else if cdre.totalCost != utils.Round(cdr.Cost, cdre.roundDecimals, utils.ROUNDING_MIDDLE) {
+ } else if cdre.totalCost != utils.Round(cdr.Cost, cdre.cgrPrecision, utils.ROUNDING_MIDDLE) {
t.Error("Unexpected total cost in the stats: ", cdre.totalCost)
}
if cdre.FirstOrderId() != 1 {
@@ -161,7 +161,7 @@ func TestWriteCdr(t *testing.T) {
if cdre.LastOrderId() != 1 {
t.Error("Unexpected LastOrderId", cdre.LastOrderId())
}
- if cdre.TotalCost() != utils.Round(cdr.Cost, cdre.roundDecimals, utils.ROUNDING_MIDDLE) {
+ if cdre.TotalCost() != utils.Round(cdr.Cost, cdre.cgrPrecision, utils.ROUNDING_MIDDLE) {
t.Error("Unexpected TotalCost: ", cdre.TotalCost())
}
}
@@ -201,7 +201,7 @@ func TestWriteCdrs(t *testing.T) {
}
cfg, _ := config.NewDefaultCGRConfig()
cdre, err := NewCdrExporter([]*engine.CDR{cdr1, cdr2, cdr3, cdr4}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',',
- "fwv_1", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify, "")
+ "fwv_1", 0.0, 0.0, 0.0, 0.0, 0.0, cfg.RoundingDecimals, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error(err)
}
@@ -224,7 +224,7 @@ func TestWriteCdrs(t *testing.T) {
if cdre.totalDuration != time.Duration(330)*time.Second {
t.Error("Unexpected total duration in the stats: ", cdre.totalDuration)
}
- if cdre.totalCost != 5.9957 {
+ if cdre.totalCost != 5.99568 {
t.Error("Unexpected total cost in the stats: ", cdre.totalCost)
}
if cdre.FirstOrderId() != 2 {
@@ -233,7 +233,7 @@ func TestWriteCdrs(t *testing.T) {
if cdre.LastOrderId() != 4 {
t.Error("Unexpected LastOrderId", cdre.LastOrderId())
}
- if cdre.TotalCost() != 5.9957 {
+ if cdre.TotalCost() != 5.99568 {
t.Error("Unexpected TotalCost: ", cdre.TotalCost())
}
}
diff --git a/config/cdreconfig.go b/config/cdreconfig.go
index c1bd4a78a..f99dd1fff 100644
--- a/config/cdreconfig.go
+++ b/config/cdreconfig.go
@@ -26,10 +26,6 @@ type CdreConfig struct {
MMSUsageMultiplyFactor float64
GenericUsageMultiplyFactor float64
CostMultiplyFactor float64
- CostRoundingDecimals int
- CostShiftDigits int
- MaskDestinationID string
- MaskLength int
ExportDirectory string
HeaderFields []*CfgCdrField
ContentFields []*CfgCdrField
@@ -63,18 +59,6 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error {
if jsnCfg.Cost_multiply_factor != nil {
self.CostMultiplyFactor = *jsnCfg.Cost_multiply_factor
}
- if jsnCfg.Cost_rounding_decimals != nil {
- self.CostRoundingDecimals = *jsnCfg.Cost_rounding_decimals
- }
- if jsnCfg.Cost_shift_digits != nil {
- self.CostShiftDigits = *jsnCfg.Cost_shift_digits
- }
- if jsnCfg.Mask_destination_id != nil {
- self.MaskDestinationID = *jsnCfg.Mask_destination_id
- }
- if jsnCfg.Mask_length != nil {
- self.MaskLength = *jsnCfg.Mask_length
- }
if jsnCfg.Export_directory != nil {
self.ExportDirectory = *jsnCfg.Export_directory
}
@@ -106,10 +90,6 @@ func (self *CdreConfig) Clone() *CdreConfig {
clnCdre.MMSUsageMultiplyFactor = self.MMSUsageMultiplyFactor
clnCdre.GenericUsageMultiplyFactor = self.GenericUsageMultiplyFactor
clnCdre.CostMultiplyFactor = self.CostMultiplyFactor
- clnCdre.CostRoundingDecimals = self.CostRoundingDecimals
- clnCdre.CostShiftDigits = self.CostShiftDigits
- clnCdre.MaskDestinationID = self.MaskDestinationID
- clnCdre.MaskLength = self.MaskLength
clnCdre.ExportDirectory = self.ExportDirectory
clnCdre.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields))
for idx, fld := range self.HeaderFields {
diff --git a/config/cdreconfig_test.go b/config/cdreconfig_test.go
index c2b7e6277..a1fe15742 100644
--- a/config/cdreconfig_test.go
+++ b/config/cdreconfig_test.go
@@ -43,10 +43,6 @@ func TestCdreCfgClone(t *testing.T) {
FieldSeparator: rune(','),
DataUsageMultiplyFactor: 1.0,
CostMultiplyFactor: 1.0,
- CostRoundingDecimals: -1,
- CostShiftDigits: 0,
- MaskDestinationID: "MASKED_DESTINATIONS",
- MaskLength: 0,
ExportDirectory: "/var/spool/cgrates/cdre",
ContentFields: initContentFlds,
}
@@ -65,10 +61,6 @@ func TestCdreCfgClone(t *testing.T) {
FieldSeparator: rune(','),
DataUsageMultiplyFactor: 1.0,
CostMultiplyFactor: 1.0,
- CostRoundingDecimals: -1,
- CostShiftDigits: 0,
- MaskDestinationID: "MASKED_DESTINATIONS",
- MaskLength: 0,
ExportDirectory: "/var/spool/cgrates/cdre",
HeaderFields: emptyFields,
ContentFields: eClnContentFlds,
@@ -86,10 +78,6 @@ func TestCdreCfgClone(t *testing.T) {
if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance
t.Errorf("Cloned result: %+v", clnCdreCfg)
}
- clnCdreCfg.CostShiftDigits = 2
- if initCdreCfg.CostShiftDigits != 0 {
- t.Error("Unexpected CostShiftDigits: ", initCdreCfg.CostShiftDigits)
- }
clnCdreCfg.ContentFields[0].FieldId = "destination"
if initCdreCfg.ContentFields[0].FieldId != "cgrid" {
t.Error("Unexpected change of FieldId: ", initCdreCfg.ContentFields[0].FieldId)
diff --git a/config/cfgcdrfield.go b/config/cfgcdrfield.go
index ac8b5d4b6..7dbf6baf5 100644
--- a/config/cfgcdrfield.go
+++ b/config/cfgcdrfield.go
@@ -64,22 +64,42 @@ func NewCfgCdrFieldFromCdrFieldJsonCfg(jsnCfgFld *CdrFieldJsonCfg) (*CfgCdrField
if jsnCfgFld.Mandatory != nil {
cfgFld.Mandatory = *jsnCfgFld.Mandatory
}
+ if jsnCfgFld.Cost_shift_digits != nil {
+ cfgFld.CostShiftDigits = *jsnCfgFld.Cost_shift_digits
+ }
+ if jsnCfgFld.Rounding_decimals != nil {
+ cfgFld.RoundingDecimals = *jsnCfgFld.Rounding_decimals
+ }
+ if jsnCfgFld.Timezone != nil {
+ cfgFld.Timezone = *jsnCfgFld.Timezone
+ }
+ if jsnCfgFld.Mask_length != nil {
+ cfgFld.MaskLen = *jsnCfgFld.Mask_length
+ }
+ if jsnCfgFld.Mask_destinationd_id != nil {
+ cfgFld.MaskDestID = *jsnCfgFld.Mask_destinationd_id
+ }
return cfgFld, nil
}
type CfgCdrField struct {
- Tag string // Identifier for the administrator
- Type string // Type of field
- FieldId string // Field identifier
- HandlerId string
- Value utils.RSRFields
- Append bool
- FieldFilter utils.RSRFields
- Width int
- Strip string
- Padding string
- Layout string
- Mandatory bool
+ Tag string // Identifier for the administrator
+ Type string // Type of field
+ FieldId string // Field identifier
+ HandlerId string
+ Value utils.RSRFields
+ Append bool
+ FieldFilter utils.RSRFields
+ Width int
+ Strip string
+ Padding string
+ Layout string
+ Mandatory bool
+ CostShiftDigits int // Used in exports
+ RoundingDecimals int
+ Timezone string
+ MaskLen int
+ MaskDestID string
}
func CfgCdrFieldsFromCdrFieldsJsonCfg(jsnCfgFldss []*CdrFieldJsonCfg) ([]*CfgCdrField, error) {
diff --git a/config/config_defaults.go b/config/config_defaults.go
index b80659391..350927c97 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -243,11 +243,7 @@ const CGRATES_CFG_JSON = `
"sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
"mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
"generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
- "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
- "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
- "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
- "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
- "mask_length": 0, // length of the destination suffix to be masked
+ "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
"export_directory": "/var/spool/cgrates/cdre", // path where the exported CDRs will be placed
"header_fields": [], // template of the exported header fields
"content_fields": [ // template of the exported content fields
@@ -265,7 +261,7 @@ const CGRATES_CFG_JSON = `
{"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"},
+ {"tag":"Cost", "type": "*composed", "value": "Cost", "rounding_decimals": 4},
],
"trailer_fields": [], // template of the exported trailer fields
},
diff --git a/config/config_json_test.go b/config/config_json_test.go
index feba98d6f..bd7a52b3a 100644
--- a/config/config_json_test.go
+++ b/config/config_json_test.go
@@ -255,8 +255,9 @@ func TestDfCdreJsonCfgs(t *testing.T) {
Type: utils.StringPointer(utils.META_COMPOSED),
Value: utils.StringPointer(utils.USAGE)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"),
- Type: utils.StringPointer(utils.META_COMPOSED),
- Value: utils.StringPointer(utils.COST)},
+ Type: utils.StringPointer(utils.META_COMPOSED),
+ Value: utils.StringPointer(utils.COST),
+ Rounding_decimals: utils.IntPointer(4)},
}
eCfg := map[string]*CdreJsonCfg{
utils.META_DEFAULT: &CdreJsonCfg{
@@ -267,10 +268,6 @@ func TestDfCdreJsonCfgs(t *testing.T) {
Mms_usage_multiply_factor: utils.Float64Pointer(1.0),
Generic_usage_multiply_factor: utils.Float64Pointer(1.0),
Cost_multiply_factor: utils.Float64Pointer(1.0),
- Cost_rounding_decimals: utils.IntPointer(-1),
- Cost_shift_digits: utils.IntPointer(0),
- Mask_destination_id: utils.StringPointer("MASKED_DESTINATIONS"),
- Mask_length: utils.IntPointer(0),
Export_directory: utils.StringPointer("/var/spool/cgrates/cdre"),
Header_fields: &eFields,
Content_fields: &eContentFlds,
diff --git a/config/libconfig_json.go b/config/libconfig_json.go
index ee4234fec..d85cf53dd 100644
--- a/config/libconfig_json.go
+++ b/config/libconfig_json.go
@@ -114,18 +114,23 @@ type CdrStatsJsonCfg struct {
// One cdr field config, used in cdre and cdrc
type CdrFieldJsonCfg struct {
- Tag *string
- Type *string
- Field_id *string
- Handler_id *string
- Value *string
- Append *bool
- Width *int
- Strip *string
- Padding *string
- Layout *string
- Field_filter *string
- Mandatory *bool
+ Tag *string
+ Type *string
+ Field_id *string
+ Handler_id *string
+ Value *string
+ Append *bool
+ Width *int
+ Strip *string
+ Padding *string
+ Layout *string
+ Field_filter *string
+ Mandatory *bool
+ Cost_shift_digits *int
+ Rounding_decimals *int
+ Timezone *string
+ Mask_destinationd_id *string
+ Mask_length *int
}
// Cdre config section
@@ -137,10 +142,6 @@ type CdreJsonCfg struct {
Mms_usage_multiply_factor *float64
Generic_usage_multiply_factor *float64
Cost_multiply_factor *float64
- Cost_rounding_decimals *int
- Cost_shift_digits *int
- Mask_destination_id *string
- Mask_length *int
Export_directory *string
Header_fields *[]*CdrFieldJsonCfg
Content_fields *[]*CdrFieldJsonCfg
diff --git a/config/multifiles_local_test.go b/config/multifiles_local_test.go
index 20b560058..e1dfa1008 100644
--- a/config/multifiles_local_test.go
+++ b/config/multifiles_local_test.go
@@ -87,9 +87,6 @@ func TestMfCdreExport1Instance(t *testing.T) {
if mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor != 1.0 {
t.Error("Export1 instance has DataUsageMultiplyFormat: ", mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor)
}
- if mfCgrCfg.CdreProfiles[prfl].CostRoundingDecimals != 3.0 {
- t.Error("Export1 instance has cdrFormat: ", mfCgrCfg.CdreProfiles[prfl].CostRoundingDecimals)
- }
if len(mfCgrCfg.CdreProfiles[prfl].HeaderFields) != 2 {
t.Error("Export1 instance has number of header fields: ", len(mfCgrCfg.CdreProfiles[prfl].HeaderFields))
}
diff --git a/engine/cdr.go b/engine/cdr.go
index a7d284029..0568fe3d8 100644
--- a/engine/cdr.go
+++ b/engine/cdr.go
@@ -21,7 +21,6 @@ import (
"encoding/json"
"fmt"
"math"
- "net/url"
"strconv"
"strings"
"time"
@@ -282,35 +281,6 @@ func (cdr *CDR) Clone() *CDR {
return &clnedCDR
}
-// Ability to send the CgrCdr remotely to another CDR server, we do not include rating variables for now
-func (cdr *CDR) AsHttpForm() url.Values {
- v := url.Values{}
- for fld, val := range cdr.ExtraFields {
- v.Set(fld, val)
- }
- v.Set(utils.TOR, cdr.ToR)
- v.Set(utils.ACCID, cdr.OriginID)
- v.Set(utils.CDRHOST, cdr.OriginHost)
- v.Set(utils.CDRSOURCE, cdr.Source)
- v.Set(utils.REQTYPE, cdr.RequestType)
- v.Set(utils.DIRECTION, cdr.Direction)
- v.Set(utils.TENANT, cdr.Tenant)
- v.Set(utils.CATEGORY, cdr.Category)
- v.Set(utils.ACCOUNT, cdr.Account)
- v.Set(utils.SUBJECT, cdr.Subject)
- v.Set(utils.DESTINATION, cdr.Destination)
- v.Set(utils.SETUP_TIME, cdr.SetupTime.Format(time.RFC3339))
- v.Set(utils.PDD, cdr.FieldAsString(&utils.RSRField{Id: utils.PDD}))
- v.Set(utils.ANSWER_TIME, cdr.AnswerTime.Format(time.RFC3339))
- v.Set(utils.USAGE, cdr.FormatUsage(utils.SECONDS))
- v.Set(utils.SUPPLIER, cdr.Supplier)
- v.Set(utils.DISCONNECT_CAUSE, cdr.DisconnectCause)
- if cdr.CostDetails != nil {
- v.Set(utils.COST_DETAILS, cdr.CostDetailsJson())
- }
- return v
-}
-
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored
func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, PDDFld,
answerTimeFld, durationFld, supplierFld, disconnectCauseFld, ratedFld, costFld *utils.RSRField,
@@ -718,7 +688,7 @@ func (cdr *CDR) combimedCdrFieldVal(cfgCdrFld *config.CfgCdrField, groupCDRs []*
}
// Extracts the value specified by cfgHdr out of cdr, used for export values
-func (cdr *CDR) exportFieldValue(cfgCdrFld *config.CfgCdrField, costShiftDigits, roundDecimals int, layout string, maskLen int, maskDestID string) (string, error) {
+func (cdr *CDR) exportFieldValue(cfgCdrFld *config.CfgCdrField) (string, error) {
passesFilters := true
for _, cdfFltr := range cfgCdrFld.FieldFilter {
if !cdfFltr.FilterPasses(cdr.FieldAsString(cdfFltr)) {
@@ -741,17 +711,17 @@ func (cdr *CDR) exportFieldValue(cfgCdrFld *config.CfgCdrField, costShiftDigits,
cdrVal = string(jsonVal)
}
case utils.COST:
- cdrVal = cdr.FormatCost(costShiftDigits, roundDecimals)
+ cdrVal = cdr.FormatCost(cfgCdrFld.CostShiftDigits, cfgCdrFld.RoundingDecimals)
case utils.USAGE:
- cdrVal = cdr.FormatUsage(layout)
+ cdrVal = cdr.FormatUsage(cfgCdrFld.Layout)
case utils.SETUP_TIME:
- cdrVal = cdr.SetupTime.Format(layout)
+ cdrVal = cdr.SetupTime.Format(cfgCdrFld.Layout)
case utils.ANSWER_TIME: // Format time based on layout
- cdrVal = cdr.AnswerTime.Format(layout)
+ cdrVal = cdr.AnswerTime.Format(cfgCdrFld.Layout)
case utils.DESTINATION:
cdrVal = cdr.FieldAsString(rsrFld)
- if maskLen != -1 && len(maskDestID) != 0 && CachedDestHasPrefix(maskDestID, cdrVal) {
- cdrVal = utils.MaskSuffix(cdrVal, maskLen)
+ if cfgCdrFld.MaskLen != -1 && len(cfgCdrFld.MaskDestID) != 0 && CachedDestHasPrefix(cfgCdrFld.MaskDestID, cdrVal) {
+ cdrVal = utils.MaskSuffix(cdrVal, cfgCdrFld.MaskLen)
}
default:
cdrVal = cdr.FieldAsString(rsrFld)
@@ -761,8 +731,7 @@ func (cdr *CDR) exportFieldValue(cfgCdrFld *config.CfgCdrField, costShiftDigits,
return retVal, nil
}
-func (cdr *CDR) formatField(cfgFld *config.CfgCdrField, costShiftDigits, roundDecimals int, timezone string,
- httpSkipTlsCheck bool, maskLen int, maskDestID string, groupedCDRs []*CDR) (fmtOut string, err error) {
+func (cdr *CDR) formatField(cfgFld *config.CfgCdrField, httpSkipTlsCheck bool, groupedCDRs []*CDR) (fmtOut string, err error) {
layout := cfgFld.Layout
if layout == "" {
layout = time.RFC3339
@@ -775,11 +744,11 @@ func (cdr *CDR) formatField(cfgFld *config.CfgCdrField, costShiftDigits, roundDe
case utils.META_CONSTANT:
outVal = cfgFld.Value.Id()
case utils.MetaDateTime: // Convert the requested field value into datetime with layout
- rawVal, err := cdr.exportFieldValue(cfgFld, costShiftDigits, roundDecimals, layout, maskLen, maskDestID)
+ rawVal, err := cdr.exportFieldValue(cfgFld)
if err != nil {
return "", err
}
- if dtFld, err := utils.ParseTimeDetectLayout(rawVal, timezone); err != nil { // Only one rule makes sense here
+ if dtFld, err := utils.ParseTimeDetectLayout(rawVal, cfgFld.Timezone); err != nil { // Only one rule makes sense here
return "", err
} else {
outVal = dtFld.Format(layout)
@@ -802,9 +771,9 @@ func (cdr *CDR) formatField(cfgFld *config.CfgCdrField, costShiftDigits, roundDe
case utils.META_COMBIMED:
outVal, err = cdr.combimedCdrFieldVal(cfgFld, groupedCDRs)
case utils.META_COMPOSED:
- outVal, err = cdr.exportFieldValue(cfgFld, costShiftDigits, roundDecimals, layout, maskLen, maskDestID)
+ outVal, err = cdr.exportFieldValue(cfgFld)
case utils.MetaMaskedDestination:
- if len(maskDestID) != 0 && CachedDestHasPrefix(maskDestID, cdr.Destination) {
+ if len(cfgFld.MaskDestID) != 0 && CachedDestHasPrefix(cfgFld.MaskDestID, cdr.Destination) {
outVal = "1"
} else {
outVal = "0"
@@ -819,10 +788,10 @@ func (cdr *CDR) formatField(cfgFld *config.CfgCdrField, costShiftDigits, roundDe
// Used in place where we need to export the CDR based on an export template
// ExportRecord is a []string to keep it compatible with encoding/csv Writer
-func (cdr *CDR) AsExportRecord(exportFields []*config.CfgCdrField, costShiftDigits, roundDecimals int, timezone string, httpSkipTlsCheck bool, maskLen int, maskDestID string, groupedCDRs []*CDR) (expRecord []string, err error) {
+func (cdr *CDR) AsExportRecord(exportFields []*config.CfgCdrField, httpSkipTlsCheck bool, groupedCDRs []*CDR) (expRecord []string, err error) {
expRecord = make([]string, len(exportFields))
for idx, cfgFld := range exportFields {
- if fmtOut, err := cdr.formatField(cfgFld, costShiftDigits, roundDecimals, timezone, httpSkipTlsCheck, maskLen, maskDestID, groupedCDRs); err != nil {
+ if fmtOut, err := cdr.formatField(cfgFld, httpSkipTlsCheck, groupedCDRs); err != nil {
return nil, err
} else {
expRecord[idx] += fmtOut
@@ -838,8 +807,16 @@ func (cdr *CDR) AsMapStringIface() (map[string]interface{}, error) {
// AsExportMap converts the CDR into a map[string]string based on export template
// Used in real-time replication as well as remote exports
-func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, costShiftDigits, roundDecimals int, timezone string, httpSkipTlsCheck bool, maskLen int, maskDestID string, groupedCDRs []*CDR) (map[string]string, error) {
- return nil, nil
+func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck bool, groupedCDRs []*CDR) (expMap map[string]string, err error) {
+ expMap = make(map[string]string)
+ for _, cfgFld := range exportFields {
+ if fmtOut, err := cdr.formatField(cfgFld, httpSkipTlsCheck, groupedCDRs); err != nil {
+ return nil, err
+ } else {
+ expMap[cfgFld.FieldId] += fmtOut
+ }
+ }
+ return
}
type ExternalCDR struct {
diff --git a/engine/cdr_test.go b/engine/cdr_test.go
index c8fc75a76..94d72ce24 100644
--- a/engine/cdr_test.go
+++ b/engine/cdr_test.go
@@ -200,6 +200,7 @@ func TestFormatUsage(t *testing.T) {
}
}
+/*
func TestCDRAsHttpForm(t *testing.T) {
storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf",
OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out",
@@ -261,6 +262,7 @@ func TestCDRAsHttpForm(t *testing.T) {
t.Errorf("Expected: %s, received: %s", "valextr2", cdrForm.Get("fieldextr2"))
}
}
+*/
func TestCDRForkCdr(t *testing.T) {
storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE,
@@ -501,36 +503,36 @@ func TestCDRAsExportRecord(t *testing.T) {
ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}}
val, _ := utils.ParseRSRFields(utils.DESTINATION, utils.INFIELD_SEP)
- cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val}
- if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err != nil {
+ cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val, Timezone: "UTC"}
+ if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, false, nil); err != nil {
t.Error(err)
} else if expRecord[0] != cdr.Destination {
t.Errorf("Expecting: %s, received: %s", cdr.Destination, expRecord[0])
}
fltr, _ := utils.ParseRSRFields("Tenant(itsyscom.com)", utils.INFIELD_SEP)
- cfgCdrFld = &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val, FieldFilter: fltr}
- if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil {
+ cfgCdrFld = &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val, FieldFilter: fltr, Timezone: "UTC"}
+ if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, false, nil); err == nil {
t.Error("Failed to use filter")
}
// Test MetaDateTime
val, _ = utils.ParseRSRFields("stop_time", utils.INFIELD_SEP)
layout := "2006-01-02 15:04:05"
- cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout}
- if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err != nil {
+ cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout, Timezone: "UTC"}
+ if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, false, nil); err != nil {
t.Error(err)
} else if expRecord[0] != "2014-06-11 19:19:00" {
t.Error("Expecting: 2014-06-11 19:19:00, got: ", expRecord[0])
}
// Test filter
fltr, _ = utils.ParseRSRFields("Tenant(itsyscom.com)", utils.INFIELD_SEP)
- cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, FieldFilter: fltr, Layout: layout}
- if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil {
+ cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, FieldFilter: fltr, Layout: layout, Timezone: "UTC"}
+ if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, false, nil); err == nil {
t.Error("Received empty error", err)
}
val, _ = utils.ParseRSRFields("fieldextr2", utils.INFIELD_SEP)
- cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout}
+ cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout, Timezone: "UTC"}
// Test time parse error
- if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil {
+ if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, false, nil); err == nil {
t.Error("Should give error here, got none.")
}
}
diff --git a/engine/cdrs.go b/engine/cdrs.go
index e9d3f9397..ad5a04612 100644
--- a/engine/cdrs.go
+++ b/engine/cdrs.go
@@ -22,6 +22,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
+ "net/url"
"path"
"reflect"
"strings"
@@ -462,7 +463,14 @@ func (self *CdrServer) replicateCdr(cdr *CDR) error {
switch rplCfg.Transport {
case utils.META_HTTP_POST:
content = utils.CONTENT_FORM
- body = cdr.AsHttpForm()
+ expMp, err := cdr.AsExportMap(rplCfg.ContentFields, self.cgrCfg.HttpSkipTlsVerify, nil)
+ if err != nil {
+ return err
+ }
+ body := url.Values{}
+ for fld, val := range expMp {
+ body.Set(fld, val)
+ }
case utils.META_HTTP_JSON:
content = utils.CONTENT_JSON
jsn, err := json.Marshal(cdr)
diff --git a/utils/apitpdata.go b/utils/apitpdata.go
index 937dfe2c5..88ae912e2 100644
--- a/utils/apitpdata.go
+++ b/utils/apitpdata.go
@@ -594,10 +594,6 @@ type AttrExpFileCdrs struct {
MmsUsageMultiplyFactor *float64 // Multiply mms usage before export (eg: convert from MMS unit to call duration for some billing systems)
GenericUsageMultiplyFactor *float64 // Multiply generic usage before export (eg: convert from GENERIC unit to call duration for some billing systems)
CostMultiplyFactor *float64 // Multiply the cost before export, eg: apply VAT
- CostShiftDigits *int // If defined it will shift cost digits before applying rouding (eg: convert from Eur->cents), -1 to use general config ones
- RoundDecimals *int // Overwrite configured roundDecimals with this dynamically, -1 to use general config ones
- MaskDestinationId *string // Overwrite configured MaskDestId
- MaskLength *int // Overwrite configured MaskLength, -1 to use general config ones
CgrIds []string // If provided, it will filter based on the cgrids present in list
MediationRunIds []string // If provided, it will filter on mediation runid
TORs []string // If provided, filter on TypeOfRecord
@@ -1087,10 +1083,6 @@ type AttrExportCdrsToFile struct {
MMSUsageMultiplyFactor *float64 // Multiply mms usage before export (eg: convert from MMS unit to call duration for some billing systems)
GenericUsageMultiplyFactor *float64 // Multiply generic usage before export (eg: convert from GENERIC unit to call duration for some billing systems)
CostMultiplyFactor *float64 // Multiply the cost before export, eg: apply VAT
- CostShiftDigits *int // If defined it will shift cost digits before applying rouding (eg: convert from Eur->cents), -1 to use general config ones
- RoundDecimals *int // Overwrite configured roundDecimals with this dynamically, -1 to use general config ones
- MaskDestinationID *string // Overwrite configured MaskDestId
- MaskLength *int // Overwrite configured MaskLength, -1 to use general config ones
Verbose bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds
RPCCDRsFilter // Inherit the CDR filter attributes
}