mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
API for CdrExporter fixed_width, RemCdr separated from exporter due to buggy scenario discovered
This commit is contained in:
@@ -25,10 +25,12 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Export Cdrs to file
|
||||
func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.ExportedFileCdrs) error {
|
||||
var tStart, tEnd time.Time
|
||||
var err error
|
||||
@@ -36,12 +38,6 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E
|
||||
if !utils.IsSliceMember(utils.CdreCdrFormats, cdrFormat) {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, "CdrFormat")
|
||||
}
|
||||
exportedFields := self.Config.CdreExportedFields
|
||||
if len(attr.ExportedFields) != 0 {
|
||||
if exportedFields, err = config.ParseRSRFields(attr.ExportedFields); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
}
|
||||
if len(attr.TimeStart) != 0 {
|
||||
if tStart, err = utils.ParseTimeDetectLayout(attr.TimeStart); err != nil {
|
||||
return err
|
||||
@@ -52,38 +48,93 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E
|
||||
return err
|
||||
}
|
||||
}
|
||||
cdrs, err := self.CdrDb.GetStoredCdrs(attr.MediationRunId, attr.CdrHost, attr.CdrSource, attr.ReqType, attr.Direction,
|
||||
fileName := attr.ExportFileName
|
||||
exportId := attr.ExportId
|
||||
if len(exportId) == 0 {
|
||||
exportId = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
}
|
||||
roundDecimals := attr.RoundingDecimals
|
||||
if roundDecimals == 0 {
|
||||
roundDecimals = self.Config.RoundingDecimals
|
||||
}
|
||||
cdrs, err := self.CdrDb.GetStoredCdrs(attr.CgrIds, attr.MediationRunId, attr.CdrHost, attr.CdrSource, attr.ReqType, attr.Direction,
|
||||
attr.Tenant, attr.Tor, attr.Account, attr.Subject, attr.DestinationPrefix, tStart, tEnd, attr.SkipErrors, attr.SkipRated)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(cdrs) == 0 {
|
||||
*reply = utils.ExportedFileCdrs{"", 0}
|
||||
return nil
|
||||
}
|
||||
var fileName string
|
||||
if cdrFormat == utils.CDRE_CSV && len(cdrs) != 0 {
|
||||
fileName = path.Join(self.Config.CdreDir, fmt.Sprintf("cdrs_%d.csv", time.Now().Unix()))
|
||||
fileOut, err := os.Create(fileName)
|
||||
switch cdrFormat {
|
||||
case utils.CDRE_CSV:
|
||||
if len(fileName) == 0 {
|
||||
fileName = fmt.Sprintf("cdre_%s.csv", exportId)
|
||||
}
|
||||
exportedFields := self.Config.CdreExportedFields
|
||||
if len(attr.ExportTemplate) != 0 {
|
||||
if exportedFields, err = config.ParseRSRFields(attr.ExportTemplate); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
}
|
||||
if len(exportedFields) == 0 {
|
||||
return fmt.Errorf("%s:ExportTemplate", utils.ERR_MANDATORY_IE_MISSING)
|
||||
}
|
||||
filePath := path.Join(self.Config.CdreDir, fileName)
|
||||
fileOut, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer fileOut.Close()
|
||||
}
|
||||
csvWriter := cdre.NewCsvCdrWriter(fileOut, self.Config.RoundingDecimals, exportedFields)
|
||||
defer fileOut.Close()
|
||||
csvWriter := cdre.NewCsvCdrWriter(fileOut, roundDecimals, exportedFields)
|
||||
for _, cdr := range cdrs {
|
||||
if err := csvWriter.WriteCdr(cdr); err != nil {
|
||||
os.Remove(fileName)
|
||||
os.Remove(filePath)
|
||||
return err
|
||||
}
|
||||
}
|
||||
csvWriter.Close()
|
||||
if attr.RemoveFromDb {
|
||||
cgrIds := make([]string, len(cdrs))
|
||||
for idx, cdr := range cdrs {
|
||||
cgrIds[idx] = cdr.CgrId
|
||||
case utils.CDRE_FIXED_WIDTH:
|
||||
if len(fileName) == 0 {
|
||||
fileName = fmt.Sprintf("cdre_%s.fwv", exportId)
|
||||
}
|
||||
exportTemplate := self.Config.CdreFWXmlTemplate
|
||||
if len(attr.ExportTemplate) != 0 && self.Config.XmlCfgDocument != nil {
|
||||
if xmlTemplate, err := self.Config.XmlCfgDocument.GetCdreFWCfg(attr.ExportTemplate[len(utils.XML_PROFILE_PREFIX):]); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
} else if xmlTemplate != nil {
|
||||
exportTemplate = xmlTemplate
|
||||
}
|
||||
if err := self.CdrDb.RemStoredCdrs(cgrIds); err != nil {
|
||||
}
|
||||
if exportTemplate == nil {
|
||||
return fmt.Errorf("%s:ExportTemplate", utils.ERR_MANDATORY_IE_MISSING)
|
||||
}
|
||||
filePath := path.Join(self.Config.CdreDir, fileName)
|
||||
fileOut, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileOut.Close()
|
||||
fww, _ := cdre.NewFWCdrWriter(self.LogDb, fileOut, exportTemplate, exportId, roundDecimals)
|
||||
for _, cdr := range cdrs {
|
||||
if err := fww.WriteCdr(cdr); err != nil {
|
||||
os.Remove(filePath)
|
||||
return err
|
||||
}
|
||||
}
|
||||
fww.Close()
|
||||
}
|
||||
*reply = utils.ExportedFileCdrs{fileName, len(cdrs)}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove Cdrs out of CDR storage
|
||||
func (self *ApierV1) RemCdrs(attrs utils.AttrRemCdrs, reply *string) error {
|
||||
if len(attrs.CgrIds) == 0 {
|
||||
return fmt.Errorf("%s:CgrIds", utils.ERR_MANDATORY_IE_MISSING)
|
||||
}
|
||||
if err := self.CdrDb.RemStoredCdrs(attrs.CgrIds); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
*reply = "OK"
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -50,12 +51,23 @@ const (
|
||||
|
||||
var err error
|
||||
|
||||
func NewFWCdrWriter(logDb engine.LogStorage, outFile *os.File, exportTpl *config.CgrXmlCdreFwCfg, exportId string, roundDecimals int) (*FixedWidthCdrWriter, error) {
|
||||
return &FixedWidthCdrWriter{
|
||||
logDb: logDb,
|
||||
writer: outFile,
|
||||
exportTemplate: exportTpl,
|
||||
exportId: exportId,
|
||||
roundDecimals: roundDecimals,
|
||||
header: &bytes.Buffer{},
|
||||
content: &bytes.Buffer{},
|
||||
trailer: &bytes.Buffer{}}, nil
|
||||
}
|
||||
|
||||
type FixedWidthCdrWriter struct {
|
||||
logDb engine.LogStorage // Used to extract cost_details if these are requested
|
||||
writer io.Writer
|
||||
exportTemplate *config.CgrXmlCdreFwCfg
|
||||
exportId string // Unique identifier or this export
|
||||
exportFileName string // If defined it will overwrite the file name
|
||||
roundDecimals int
|
||||
header, content, trailer *bytes.Buffer
|
||||
firstCdrTime, lastCdrTime time.Time
|
||||
|
||||
@@ -283,7 +283,7 @@ func (self *CGRConfig) setDefaults() error {
|
||||
|
||||
func (self *CGRConfig) checkConfigSanity() error {
|
||||
// Cdre sanity check for fixed_width
|
||||
if self.CdreCdrFormat == utils.FIXED_WIDTH {
|
||||
if self.CdreCdrFormat == utils.CDRE_FIXED_WIDTH {
|
||||
if self.XmlCfgDocument == nil {
|
||||
return errors.New("Need XmlConfigurationDocument for fixed_width cdr export")
|
||||
} else if self.CdreFWXmlTemplate == nil {
|
||||
@@ -492,7 +492,7 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
}
|
||||
if hasOpt = c.HasOption("cdre", "export_template"); hasOpt { // Load configs for csv normally from template, fixed_width from xml file
|
||||
exportTemplate, _ := c.GetString("cdre", "export_template")
|
||||
if cfg.CdreCdrFormat != utils.FIXED_WIDTH { // Csv most likely
|
||||
if cfg.CdreCdrFormat != utils.CDRE_FIXED_WIDTH { // Csv most likely
|
||||
if extraFields, err := ParseRSRFields(exportTemplate); err != nil {
|
||||
return nil, errParse
|
||||
} else {
|
||||
|
||||
@@ -184,7 +184,7 @@ func TestSanityCheck(t *testing.T) {
|
||||
t.Error("Failed to detect config insanity")
|
||||
}
|
||||
cfg = &CGRConfig{}
|
||||
cfg.CdreCdrFormat = utils.FIXED_WIDTH
|
||||
cfg.CdreCdrFormat = utils.CDRE_FIXED_WIDTH
|
||||
if err := cfg.checkConfigSanity(); err == nil {
|
||||
t.Error("Failed to detect fixed_width dependency on xml configuration")
|
||||
}
|
||||
|
||||
@@ -83,18 +83,18 @@ type CgrXmlCfgCdrField struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
Width int `xml:"width,attr"` // Field width
|
||||
Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
|
||||
Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
|
||||
Layout string `xml:"layout,attr"` // Eg. time format layout
|
||||
Mandatory bool `xml:"layout,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
|
||||
Width int `xml:"width,attr"` // Field width
|
||||
Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
|
||||
Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
|
||||
Layout string `xml:"layout,attr"` // Eg. time format layout
|
||||
Mandatory bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
|
||||
}
|
||||
|
||||
// Avoid building from raw config string always, so build cache here
|
||||
func (xmlCfg *CgrXmlCfgDocument) cacheCdreFWCfgs() error {
|
||||
xmlCfg.cdrefws = make(map[string]*CgrXmlCdreFwCfg)
|
||||
for _, cfgInst := range xmlCfg.Configurations {
|
||||
if cfgInst.Section == utils.CDRE || cfgInst.Type == utils.FIXED_WIDTH {
|
||||
if cfgInst.Section == utils.CDRE || cfgInst.Type == utils.CDRE_FIXED_WIDTH {
|
||||
cdrefwCfg := new(CgrXmlCdreFwCfg)
|
||||
rawConfig := append([]byte("<element>"), cfgInst.RawConfig...) // Encapsulate the rawConfig in one element so we can Unmarshall into one struct
|
||||
rawConfig = append(rawConfig, []byte("</element>")...)
|
||||
|
||||
@@ -44,7 +44,7 @@ func TestParseXmlConfig(t *testing.T) {
|
||||
<content>
|
||||
<fields>
|
||||
<field name="RecordType" type="constant" value="20" width="2"/>
|
||||
<field name="SIPTrunkID" type="cdrfield" value="cgrid" width="12"/>
|
||||
<field name="SIPTrunkID" type="cdrfield" value="cgrid" width="12" mandatory="true"/>
|
||||
<field name="ConnectionNumber" type="cdrfield" value="subject" strip="left" padding="left" width="5"/>
|
||||
<field name="ANumber" type="cdrfield" value="cli" strip="xright" width="15"/>
|
||||
<field name="CalledNumber" type="cdrfield" value="destination" strip="xright" width="24"/>
|
||||
|
||||
@@ -106,7 +106,7 @@ type CdrStorage interface {
|
||||
Storage
|
||||
SetCdr(utils.RawCDR) error
|
||||
SetRatedCdr(*utils.StoredCdr, string) error
|
||||
GetStoredCdrs(string, string, string, string, string, string, string, string, string, string, time.Time, time.Time, bool, bool) ([]*utils.StoredCdr, error)
|
||||
GetStoredCdrs([]string, string, string, string, string, string, string, string, string, string, string, time.Time, time.Time, bool, bool) ([]*utils.StoredCdr, error)
|
||||
RemStoredCdrs([]string) error
|
||||
}
|
||||
|
||||
|
||||
@@ -577,97 +577,111 @@ func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string
|
||||
// Return a slice of CDRs from storDb using optional filters.a
|
||||
// ignoreErr - do not consider cdrs with rating errors
|
||||
// ignoreRated - do not consider cdrs which were already rated, including here the ones with errors
|
||||
func (self *SQLStorage) GetStoredCdrs(runId, cdrHost, cdrSource, reqType, direction, tenant, tor, account, subject, destPrefix string,
|
||||
func (self *SQLStorage) GetStoredCdrs(cgrIds []string, runId string, cdrHost, cdrSource, reqType, direction, tenant, tor, account, subject, destPrefix string,
|
||||
timeStart, timeEnd time.Time, ignoreErr, ignoreRated bool) ([]*utils.StoredCdr, error) {
|
||||
var cdrs []*utils.StoredCdr
|
||||
q := fmt.Sprintf("SELECT %s.cgrid,accid,cdrhost,cdrsource,reqtype,direction,tenant,tor,account,%s.subject,destination,setup_time,answer_time,duration,extra_fields,runid,cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS)
|
||||
fltr := ""
|
||||
if len(cgrIds) != 0 {
|
||||
qIds := " ("
|
||||
for idxId, cgrId := range cgrIds {
|
||||
if idxId != 0 {
|
||||
qIds += " OR"
|
||||
}
|
||||
qIds += fmt.Sprintf(" %s.cgrid='%s'", utils.TBL_CDRS_PRIMARY, cgrId)
|
||||
}
|
||||
qIds += " )"
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += qIds
|
||||
}
|
||||
if len(runId) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" runid='%s'", runId)
|
||||
}
|
||||
if len(cdrHost) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" cdrhost='%s'", cdrHost)
|
||||
}
|
||||
if len(cdrSource) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" cdrsource='%s'", cdrSource)
|
||||
}
|
||||
if len(reqType) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" reqtype='%s'", reqType)
|
||||
}
|
||||
if len(direction) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" direction='%s'", direction)
|
||||
}
|
||||
if len(tenant) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" tenant='%s'", tenant)
|
||||
}
|
||||
if len(tor) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" tor='%s'", tor)
|
||||
}
|
||||
if len(account) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" account='%s'", account)
|
||||
}
|
||||
if len(subject) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" %s.subject='%s'", utils.TBL_CDRS_PRIMARY, subject)
|
||||
}
|
||||
if len(destPrefix) != 0 {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" destination LIKE '%s%%'", destPrefix)
|
||||
}
|
||||
if !timeStart.IsZero() {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" answer_time>='%s'", timeStart)
|
||||
}
|
||||
if !timeEnd.IsZero() {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += fmt.Sprintf(" answer_time<'%s'", timeEnd)
|
||||
}
|
||||
if ignoreRated {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
if ignoreErr {
|
||||
fltr += "cost IS NULL"
|
||||
fltr += " cost IS NULL"
|
||||
} else {
|
||||
fltr += "(cost=-1 OR cost IS NULL)"
|
||||
fltr += " (cost=-1 OR cost IS NULL)"
|
||||
}
|
||||
} else if ignoreErr {
|
||||
if len(fltr) != 0 {
|
||||
fltr += " AND "
|
||||
fltr += " AND"
|
||||
}
|
||||
fltr += "(cost!=-1 OR cost IS NULL)"
|
||||
fltr += " (cost!=-1 OR cost IS NULL)"
|
||||
}
|
||||
if len(fltr) != 0 {
|
||||
q += fmt.Sprintf(" WHERE %s", fltr)
|
||||
|
||||
@@ -213,93 +213,93 @@ func TestGetStoredCdrs(t *testing.T) {
|
||||
}
|
||||
var timeStart, timeEnd time.Time
|
||||
// All CDRs, no filter
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 8 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on runId
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(utils.DEFAULT_RUNID, "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, utils.DEFAULT_RUNID, "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 2 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on cdrHost
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "192.168.1.2", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "192.168.1.2", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on cdrSource
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "UNKNOWN", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "UNKNOWN", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 1 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on reqType
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "prepaid", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "prepaid", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 2 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on direction
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "*out", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "*out", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 8 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on tenant
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "itsyscom.com", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "itsyscom.com", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on tor
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "premium_call", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "premium_call", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 1 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on account
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "1002", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "1002", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on subject
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "1000", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "1000", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 1 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on ignoreErr
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, true, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, true, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 8 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on ignoreRated
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, true); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, true); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on timeStart
|
||||
timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC)
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on timeStart and timeEnd
|
||||
timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC)
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 2 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Combined filter
|
||||
if storedCdrs, err := mysql.GetStoredCdrs("", "", "", "rated", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
if storedCdrs, err := mysql.GetStoredCdrs(nil, "", "", "", "rated", "", "", "", "", "", "", timeStart, timeEnd, false, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 1 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
|
||||
@@ -161,7 +161,7 @@ func (self *Mediator) RateCdr(dbcdr utils.RawCDR) error {
|
||||
}
|
||||
|
||||
func (self *Mediator) RateCdrs(timeStart, timeEnd time.Time, rerateErrors, rerateRated bool) error {
|
||||
cdrs, err := self.cdrDb.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, !rerateErrors, !rerateRated)
|
||||
cdrs, err := self.cdrDb.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", timeStart, timeEnd, !rerateErrors, !rerateRated)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -150,12 +150,12 @@ func TestPostCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond) // Give time for CDRs to reach database
|
||||
if storedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, false); err != nil {
|
||||
if storedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, false); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(storedCdrs) != 2 { // Make sure CDRs made it into StorDb
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs)))
|
||||
}
|
||||
if nonErrorCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, false); err != nil {
|
||||
if nonErrorCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, false); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(nonErrorCdrs) != 0 { // Just two of them should be without errors
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(nonErrorCdrs)))
|
||||
@@ -178,12 +178,12 @@ func TestInjectCdrs(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
if storedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, false); err != nil {
|
||||
if storedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, false); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(storedCdrs) != 4 { // Make sure CDRs made it into StorDb
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs)))
|
||||
}
|
||||
if nonRatedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, true); err != nil {
|
||||
if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, true); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(nonRatedCdrs) != 2 { // Just two of them should be non-rated
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs)))
|
||||
@@ -215,12 +215,12 @@ func TestRateCdrs(t *testing.T) {
|
||||
} else if reply != utils.OK {
|
||||
t.Errorf("Unexpected reply: %s", reply)
|
||||
}
|
||||
if nonRatedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, true); err != nil {
|
||||
if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, true, true); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(nonRatedCdrs) != 0 { // Just two of them should be non-rated
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs)))
|
||||
}
|
||||
if errRatedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, true); err != nil {
|
||||
if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, true); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(errRatedCdrs) != 2 { // The first 2 with errors should be still there before rerating
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs)))
|
||||
@@ -230,7 +230,7 @@ func TestRateCdrs(t *testing.T) {
|
||||
} else if reply != utils.OK {
|
||||
t.Errorf("Unexpected reply: %s", reply)
|
||||
}
|
||||
if errRatedCdrs, err := cdrStor.GetStoredCdrs("", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, true); err != nil {
|
||||
if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, "", "", "", "", "", "", "", "", "", "", time.Time{}, time.Time{}, false, true); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(errRatedCdrs) != 1 { // One CDR with errors should be fixed now by rerating
|
||||
t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs)))
|
||||
|
||||
@@ -316,23 +316,30 @@ type CachedItemAge struct {
|
||||
}
|
||||
|
||||
type AttrExpFileCdrs struct {
|
||||
CdrFormat string // Cdr output file format <utils.CdreCdrFormats>
|
||||
ExportedFields string // Optional comma separated list of fields ot be exported in a CDR
|
||||
MediationRunId string // If provided, it will filter on mediation runid
|
||||
CdrHost string // If provided, it will filter cdrhost
|
||||
CdrSource string // If provided, it will filter cdrsource
|
||||
ReqType string // If provided, it will fiter reqtype
|
||||
Direction string // If provided, it will fiter direction
|
||||
Tenant string // If provided, it will filter tenant
|
||||
Tor string // If provided, it will filter tor
|
||||
Account string // If provided, it will filter account
|
||||
Subject string // If provided, it will filter the rating subject
|
||||
DestinationPrefix string // If provided, it will filter on destination prefix
|
||||
TimeStart string // If provided, it will represent the starting of the CDRs interval (>=)
|
||||
TimeEnd string // If provided, it will represent the end of the CDRs interval (<)
|
||||
SkipErrors bool // Do not export errored CDRs
|
||||
SkipRated bool // Do not export rated CDRs
|
||||
RemoveFromDb bool // If true the CDRs will be also deleted after export
|
||||
CdrFormat string // Cdr output file format <utils.CdreCdrFormats>
|
||||
ExportId string // Optional exportid
|
||||
ExportFileName string // If provided the output filename will be set to this
|
||||
ExportTemplate string // Exported fields template <""|fld1,fld2|*xml:instance_name>
|
||||
RoundingDecimals int // Overwrite configured roundDecimals with this dynamically
|
||||
CgrIds []string // If provided, it will filter based on the cgrids present in list
|
||||
MediationRunId string // If provided, it will filter on mediation runid
|
||||
CdrHost string // If provided, it will filter cdrhost
|
||||
CdrSource string // If provided, it will filter cdrsource
|
||||
ReqType string // If provided, it will fiter reqtype
|
||||
Direction string // If provided, it will fiter direction
|
||||
Tenant string // If provided, it will filter tenant
|
||||
Tor string // If provided, it will filter tor
|
||||
Account string // If provided, it will filter account
|
||||
Subject string // If provided, it will filter the rating subject
|
||||
DestinationPrefix string // If provided, it will filter on destination prefix
|
||||
TimeStart string // If provided, it will represent the starting of the CDRs interval (>=)
|
||||
TimeEnd string // If provided, it will represent the end of the CDRs interval (<)
|
||||
SkipErrors bool // Do not export errored CDRs
|
||||
SkipRated bool // Do not export rated CDRs
|
||||
}
|
||||
|
||||
type AttrRemCdrs struct {
|
||||
CgrIds []string // List of CgrIds to remove from storeDb
|
||||
}
|
||||
|
||||
type ExportedFileCdrs struct {
|
||||
|
||||
@@ -91,11 +91,11 @@ const (
|
||||
INTERNAL = "internal"
|
||||
ZERO_RATING_SUBJECT_PREFIX = "*zero"
|
||||
OK = "OK"
|
||||
FIXED_WIDTH = "fixed_width"
|
||||
CDRE_FIXED_WIDTH = "fixed_width"
|
||||
XML_PROFILE_PREFIX = "*xml:"
|
||||
CDRE = "cdre"
|
||||
)
|
||||
|
||||
var (
|
||||
CdreCdrFormats = []string{CDRE_CSV, CDRE_DRYRUN}
|
||||
CdreCdrFormats = []string{CDRE_CSV, CDRE_DRYRUN, CDRE_FIXED_WIDTH}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user