Adding FiltersID field for ExportCdrs api

This commit is contained in:
gezimbll
2023-08-08 07:59:17 -04:00
committed by Dan Christian Bogos
parent 16340546c9
commit f18c118cb0
5 changed files with 167 additions and 8 deletions

View File

@@ -225,6 +225,12 @@ func (api *APIerSv1) ExportCDRs(arg ArgExportCDRs, reply *RplExportedCDRs) (err
if !utils.CDRExportFormats.Has(exportFormat) {
return utils.NewErrMandatoryIeMissing("CdrFormat")
}
if fltrs, has := arg.ExportArgs[utils.FilterIDs]; has {
if exportTemplate.Filters, err = utils.IfaceAsSliceString(fltrs); err != nil {
return
}
}
synchronous := exportTemplate.Synchronous
if sync, has := arg.ExportArgs[utils.Synchronous]; has {
if synchronous, err = utils.IfaceAsBool(sync); err != nil {

View File

@@ -49,6 +49,7 @@ var (
testCDReRPCConn,
testCDReAddCDRs,
testCDReExportCDRs,
testCDReExportCDRs2,
testCDReFromFolder,
testCDReProcessExternalCdr,
testCDReKillEngine,
@@ -182,6 +183,50 @@ func testCDReExportCDRs(t *testing.T) {
}
}
func testCDReExportCDRs2(t *testing.T) {
storedCdrs := []*engine.CDR{
{CGRID: "Cdr5",
OrderID: 1234, ToR: utils.VOICE, OriginID: "OriginCDR1", OriginHost: "192.168.1.1", Source: "test",
RequestType: utils.META_RATED, Tenant: "cgrates.org",
Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(),
AnswerTime: time.Now(), RunID: utils.MetaDefault, Usage: time.Duration(10) * time.Second,
ExtraFields: map[string]string{"DisconnectCause": "ORIGINATOR_CANCEL"}, Cost: 13.7,
},
{CGRID: "Cdr6",
OrderID: 124343, ToR: utils.VOICE, OriginID: "OriginCDR2", OriginHost: "192.168.1.1", Source: "test2",
RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call",
Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(),
AnswerTime: time.Now(), RunID: utils.MetaDefault, Usage: time.Duration(5) * time.Second,
ExtraFields: map[string]string{"DisconnectCause": "UNALLOCATED_NUMBER"}, Cost: 2.21,
},
}
for _, cdr := range storedCdrs {
var reply string
if err := cdreRPC.Call(utils.CDRsV1ProcessCDR, &engine.CDRWithArgDispatcher{CDR: cdr}, &reply); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if reply != utils.OK {
t.Error("Unexpected reply received: ", reply)
}
}
attr := ArgExportCDRs{
ExportArgs: map[string]any{
utils.ExportTemplate: "TemplateWithFilter",
utils.FilterIDs: []string{"*string:~*req.DisconnectCause:UNALLOCATED_NUMBER"},
utils.ExportPath: "/tmp",
utils.ExportFileName: "TestFilteredCsv.csv",
},
Verbose: true,
}
var rply *RplExportedCDRs
if err := cdreRPC.Call(utils.APIerSv1ExportCDRs, attr, &rply); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if len(rply.ExportedCGRIDs) != 1 {
t.Errorf("Unexpected number of CDR exported: %s ", utils.ToJSON(rply))
}
}
func testCDReFromFolder(t *testing.T) {
var reply string
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}

View File

@@ -31,14 +31,15 @@ import (
)
type AttrExportCdrsToFile struct {
CdrFormat *string // Cdr output file format <utils.CdreCdrFormats>
FieldSeparator *string // Separator used between fields
ExportID *string // Optional exportid
ExportDirectory *string // If provided it overwrites the configured export directory
ExportFileName *string // If provided the output filename will be set to this
ExportTemplate *string // Exported fields template <""|fld1,fld2|>
Verbose bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds
utils.RPCCDRsFilter // Inherit the CDR filter attributes
CdrFormat *string // Cdr output file format <utils.CdreCdrFormats>
FieldSeparator *string // Separator used between fields
ExportID *string // Optional exportid
ExportDirectory *string // If provided it overwrites the configured export directory
ExportFileName *string // If provided the output filename will be set to this
FiltersIDs []string // Will overwrite exporter filters
ExportTemplate *string // Exported fields template <""|fld1,fld2|>
Verbose bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds
utils.RPCCDRsFilter // Inherit the CDR filter attributes
}
// Deprecated, please use APIerSv1.ExportCDRs instead
@@ -70,6 +71,9 @@ func (apiv2 *APIerSv2) ExportCdrsToFile(attr AttrExportCdrsToFile, reply *utils.
if attr.ExportDirectory != nil && len(*attr.ExportDirectory) != 0 {
eDir = *attr.ExportDirectory
}
if len(attr.FiltersIDs) != 0 {
exportTemplate.Filters = attr.FiltersIDs
}
exportID := strconv.FormatInt(time.Now().Unix(), 10)
if attr.ExportID != nil && len(*attr.ExportID) != 0 {
exportID = *attr.ExportID

View File

@@ -67,6 +67,7 @@ var (
testv2CDRsGetCDRsDest,
testV2ExportCDRsToFile,
testV2CDRsKillEngine,
}
)
@@ -837,6 +838,108 @@ func testv2CDRsGetCDRsDest(t *testing.T) {
}
}
func testV2ExportCDRsToFile(t *testing.T) {
var (
reply string
replyCdr []*engine.ExternalCDR
replyExp utils.ExportedFileCdrs
)
cgrEvs := []*utils.CGREvent{
{
Tenant: "cgrates.org",
Event: map[string]any{
utils.ToR: utils.VOICE,
utils.CGRID: "9b3cd5e698af94f8916220866c831a982ed163322",
utils.OriginID: "testCDREProcessCdr2",
utils.OriginHost: "192.168.1.1",
utils.Source: "TestTutITExportCDR",
utils.RequestType: utils.META_POSTPAID,
utils.Category: "call",
utils.Account: "1001",
utils.Subject: "1001",
utils.Destination: "1003",
utils.SetupTime: time.Date(2022, 11, 30, 17, 5, 24, 0, time.UTC),
utils.AnswerTime: time.Date(2023, 11, 30, 17, 6, 4, 0, time.UTC),
utils.Usage: time.Duration(21) * time.Second,
"DisconnectCause": "UNALLOCATED_NUMBER",
},
},
{
Tenant: "cgrates.org",
Event: map[string]any{
utils.CGRID: "9b3cd5e698af94f8916220866c831a982ed1623432",
utils.ToR: utils.VOICE,
utils.OriginID: "testCDREProcessCdr3",
utils.OriginHost: "192.168.1.1",
utils.Source: "TestTutITExportCDR",
utils.RequestType: utils.META_PREPAID,
utils.Category: "call",
utils.Account: "1002",
utils.Subject: "1002",
utils.Destination: "1004",
utils.SetupTime: time.Date(2022, 12, 30, 17, 5, 24, 0, time.UTC),
utils.AnswerTime: time.Date(2022, 12, 30, 17, 6, 4, 0, time.UTC),
utils.Usage: time.Duration(98) * time.Second,
"DisconnectCause": "ORIGINATOR_CANCEL",
},
},
{
Tenant: "cgrates.org",
Event: map[string]any{
utils.CGRID: "9b3cd5e698af94f353216220866c831a982ed163322",
utils.ToR: utils.VOICE,
utils.OriginID: "testCDREProcessCdr1",
utils.OriginHost: "192.168.1.1",
utils.Source: "TestTutITExportCDR",
utils.RequestType: utils.META_RATED,
utils.Tenant: "cgrates.org",
utils.Category: "call",
utils.Account: "1003",
utils.Subject: "1003",
utils.Destination: "1007",
utils.SetupTime: time.Date(2023, 3, 30, 17, 5, 24, 0, time.UTC),
utils.AnswerTime: time.Date(2023, 3, 30, 17, 6, 4, 0, time.UTC),
utils.Usage: time.Duration(10) * time.Second,
"DisconnectCause": "USER_BUSY"},
},
}
for _, cgrEv := range cgrEvs {
if err := cdrsRpc.Call(utils.CDRsV1ProcessEvent,
&engine.ArgV1ProcessEvent{
Flags: []string{utils.ConcatenatedKey(utils.MetaChargers, "false")},
CGREvent: *cgrEv,
}, &reply); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if reply != utils.OK {
t.Error("Unexpected reply received: ", reply)
}
}
req := utils.RPCCDRsFilter{
ExtraFields: map[string]string{
"DisconnectCause": "USER_BUSY",
},
}
if err := cdrsRpc.Call(utils.APIerSv2GetCDRs, req, &replyCdr); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if len(replyCdr) != 1 {
t.Errorf("Received %v", len(replyCdr))
}
attr := AttrExportCdrsToFile{
ExportFileName: utils.StringPointer("TestTutITExportCDR.csv"),
ExportDirectory: utils.StringPointer("/tmp"),
ExportTemplate: utils.StringPointer("*default"),
FiltersIDs: []string{"*string:~*req.DisconnectCause:ORIGINATOR_CANCEL"},
}
if err := cdrsRpc.Call(utils.APIerSv2ExportCdrsToFile, attr, &replyExp); err != nil {
t.Error(err)
} else if len(replyExp.ExportedCgrIds) != 1 {
t.Errorf("Exported records: %+v", len(replyExp.ExportedCgrIds))
}
}
func testV2CDRsKillEngine(t *testing.T) {
if err := engine.KillEngine(*waitRater); err != nil {
t.Error(err)

View File

@@ -1195,6 +1195,7 @@ const (
APIerSv2ExecuteAction = "APIerSv2.ExecuteAction"
APIerSv2ResetAccountActionTriggers = "APIerSv2.ResetAccountActionTriggers"
APIerSv2RemoveActions = "APIerSv2.RemoveActions"
APIerSv2ExportCdrsToFile = "APIerSv2.ExportCdrsToFile"
)
const (