mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Merge branch 'master' into load
This commit is contained in:
@@ -159,28 +159,28 @@ func TestV2CdrsMysqlGetCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
// CDRs with errors
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(-1.0), CostEnd: utils.Float64Pointer(0.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)}
|
||||
if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// CDRs Rated
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 3 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// CDRs non rated OR SkipRated
|
||||
req = utils.RpcCdrsFilter{CostEnd: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MaxCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// Skip Errors
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(0.0), CostEnd: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
|
||||
@@ -157,28 +157,28 @@ func TestV2CdrsPsqlGetCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
// CDRs with errors
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(-1.0), CostEnd: utils.Float64Pointer(0.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)}
|
||||
if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// CDRs Rated
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 3 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// CDRs non rated OR SkipRated
|
||||
req = utils.RpcCdrsFilter{CostEnd: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MaxCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", reply)
|
||||
}
|
||||
// Skip Errors
|
||||
req = utils.RpcCdrsFilter{CostStart: utils.Float64Pointer(0.0), CostEnd: utils.Float64Pointer(-1.0)}
|
||||
req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)}
|
||||
if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
|
||||
@@ -21,6 +21,7 @@ CREATE TABLE cdrs_primary (
|
||||
setup_time datetime NOT NULL,
|
||||
answer_time datetime NOT NULL,
|
||||
`usage` DECIMAL(30,9) NOT NULL,
|
||||
pdd DECIMAL(12,9) NOT NULL,
|
||||
supplier varchar(128) NOT NULL,
|
||||
disconnect_cause varchar(64) NOT NULL,
|
||||
created_at TIMESTAMP,
|
||||
@@ -93,6 +94,7 @@ CREATE TABLE `rated_cdrs` (
|
||||
setup_time datetime NOT NULL,
|
||||
answer_time datetime NOT NULL,
|
||||
`usage` DECIMAL(30,9) NOT NULL,
|
||||
pdd DECIMAL(12,9) NOT NULL,
|
||||
supplier varchar(128) NOT NULL,
|
||||
disconnect_cause varchar(64) NOT NULL,
|
||||
cost DECIMAL(20,4) DEFAULT NULL,
|
||||
|
||||
@@ -21,6 +21,7 @@ CREATE TABLE cdrs_primary (
|
||||
setup_time TIMESTAMP NOT NULL,
|
||||
answer_time TIMESTAMP NOT NULL,
|
||||
usage NUMERIC(30,9) NOT NULL,
|
||||
pdd NUMERIC(12,9) NOT NULL,
|
||||
supplier VARCHAR(128) NOT NULL,
|
||||
disconnect_cause VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP,
|
||||
@@ -89,6 +90,7 @@ CREATE TABLE rated_cdrs (
|
||||
setup_time TIMESTAMP NOT NULL,
|
||||
answer_time TIMESTAMP NOT NULL,
|
||||
usage NUMERIC(30,9) NOT NULL,
|
||||
pdd NUMERIC(12,9) NOT NULL,
|
||||
supplier VARCHAR(128) NOT NULL,
|
||||
disconnect_cause VARCHAR(64) NOT NULL,
|
||||
cost NUMERIC(20,4) DEFAULT NULL,
|
||||
|
||||
@@ -114,7 +114,7 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT
|
||||
ReqTypes: reqTypes, Directions: directions, Tenants: tenants, Categories: categories, Accounts: accounts,
|
||||
Subjects: subjects, DestPrefixes: destPrefixes, RatedAccounts: ratedAccounts, RatedSubjects: ratedSubjects,
|
||||
OrderIdStart: orderIdStart, OrderIdEnd: orderIdEnd, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd,
|
||||
CostStart: costStart, CostEnd: costEnd})
|
||||
MinCost: costStart, MaxCost: costEnd})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -273,8 +273,9 @@ func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) {
|
||||
dcDurFld, _ := utils.NewRSRField(dc.UsageField)
|
||||
dcSupplFld, _ := utils.NewRSRField(dc.SupplierField)
|
||||
dcDCausseld, _ := utils.NewRSRField(dc.DisconnectCauseField)
|
||||
dcPddFld, _ := utils.NewRSRField("0") // FixMe
|
||||
forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld,
|
||||
dcSTimeFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCausseld, []*utils.RSRField{}, true)
|
||||
dcSTimeFld, dcATimeFld, dcDurFld, dcPddFld, dcSupplFld, dcDCausseld, []*utils.RSRField{}, true)
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", storedCdr.CgrId, dc.RunId, err.Error()))
|
||||
continue // do not add it to the forked CDR list
|
||||
|
||||
@@ -40,6 +40,7 @@ type Event interface {
|
||||
GetAnswerTime(string) (time.Time, error)
|
||||
GetEndTime() (time.Time, error)
|
||||
GetDuration(string) (time.Duration, error)
|
||||
GetPdd(string) (time.Duration, error)
|
||||
GetSupplier(string) string
|
||||
GetDisconnectCause(string) string
|
||||
GetOriginatorIP(string) string
|
||||
|
||||
@@ -334,6 +334,7 @@ type TblCdrsPrimary struct {
|
||||
SetupTime time.Time
|
||||
AnswerTime time.Time
|
||||
Usage float64
|
||||
Pdd float64
|
||||
Supplier string
|
||||
DisconnectCause string
|
||||
CreatedAt time.Time
|
||||
@@ -393,6 +394,7 @@ type TblRatedCdr struct {
|
||||
SetupTime time.Time
|
||||
AnswerTime time.Time
|
||||
Usage float64
|
||||
Pdd float64
|
||||
Supplier string
|
||||
DisconnectCause string
|
||||
Cost float64
|
||||
|
||||
@@ -95,7 +95,7 @@ func (self *MySQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost)
|
||||
}
|
||||
|
||||
func (self *MySQLStorage) SetRatedCdr(storedCdr *StoredCdr) (err error) {
|
||||
_, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,supplier,disconnect_cause,cost,extra_info,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,'%s','%s',%f,'%s','%s') ON DUPLICATE KEY UPDATE reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),cost=values(cost),supplier=values(supplier),disconnect_cause=values(disconnect_cause),extra_info=values(extra_info), updated_at='%s'",
|
||||
_, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,pdd,supplier,disconnect_cause,cost,extra_info,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,%v,'%s','%s',%f,'%s','%s') ON DUPLICATE KEY UPDATE reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),pdd=values(pdd),cost=values(cost),supplier=values(supplier),disconnect_cause=values(disconnect_cause),extra_info=values(extra_info), updated_at='%s'",
|
||||
utils.TBL_RATED_CDRS,
|
||||
storedCdr.CgrId,
|
||||
storedCdr.MediationRunId,
|
||||
@@ -109,6 +109,7 @@ func (self *MySQLStorage) SetRatedCdr(storedCdr *StoredCdr) (err error) {
|
||||
storedCdr.SetupTime,
|
||||
storedCdr.AnswerTime,
|
||||
storedCdr.Usage.Seconds(),
|
||||
storedCdr.Pdd.Seconds(),
|
||||
storedCdr.Supplier,
|
||||
storedCdr.DisconnectCause,
|
||||
storedCdr.Cost,
|
||||
|
||||
@@ -477,23 +477,23 @@ func TestMySQLSetCdr(t *testing.T) {
|
||||
}
|
||||
cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z",
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
|
||||
|
||||
cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z",
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
|
||||
if err := mysqlDb.SetCdr(cdr.AsStoredCdr()); err != nil {
|
||||
@@ -503,21 +503,21 @@ func TestMySQLSetCdr(t *testing.T) {
|
||||
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(12) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(12) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
|
||||
@@ -536,21 +536,21 @@ func TestMySQLSetRatedCdr(t *testing.T) {
|
||||
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(12) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(12) * time.Second, Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1",
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: "wholesale_run", Cost: 1.201}
|
||||
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
|
||||
@@ -805,7 +805,7 @@ func TestMySQLGetStoredCdrs(t *testing.T) {
|
||||
}
|
||||
// Filter on ignoreRated
|
||||
var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CostEnd: utils.Float64Pointer(0.0)}); err != nil {
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
@@ -845,6 +845,24 @@ func TestMySQLGetStoredCdrs(t *testing.T) {
|
||||
} else if len(storedCdrs) != 2 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on minPdd
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on maxPdd
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxPdd: utils.Float64Pointer(3)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on minPdd, maxPdd
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3), MaxPdd: utils.Float64Pointer(5)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Combined filter
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil {
|
||||
t.Error(err.Error())
|
||||
@@ -852,7 +870,7 @@ func TestMySQLGetStoredCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on ignoreDerived
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnDerived: true}); err != nil {
|
||||
if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnRated: true}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 0 { // ToDo: Recheck this value
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
@@ -894,3 +912,80 @@ func TestMySQLRemStoredCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that what we get is what we set
|
||||
func TestMySQLStoreRestoreCdr(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
strCdr := &StoredCdr{TOR: utils.VOICE, AccId: "ccc1", CdrHost: "192.168.1.1", CdrSource: "TEST_CDR", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr.CgrId = utils.Sha1(strCdr.AccId, strCdr.SetupTime.String())
|
||||
if err := mysqlDb.SetCdr(strCdr); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
if err := mysqlDb.SetRatedCdr(strCdr); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
// Check RawCdr
|
||||
if rcvCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(rcvCdrs) != 1 {
|
||||
t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs)
|
||||
} else {
|
||||
rcvCdr := rcvCdrs[0]
|
||||
if strCdr.CgrId != rcvCdr.CgrId ||
|
||||
strCdr.TOR != rcvCdr.TOR ||
|
||||
strCdr.AccId != rcvCdr.AccId ||
|
||||
strCdr.CdrHost != rcvCdr.CdrHost ||
|
||||
strCdr.ReqType != rcvCdr.ReqType ||
|
||||
strCdr.Direction != rcvCdr.Direction ||
|
||||
strCdr.Tenant != rcvCdr.Tenant ||
|
||||
strCdr.Category != rcvCdr.Category ||
|
||||
strCdr.Account != rcvCdr.Account ||
|
||||
strCdr.Subject != rcvCdr.Subject ||
|
||||
strCdr.Destination != rcvCdr.Destination ||
|
||||
!strCdr.SetupTime.Equal(rcvCdr.SetupTime) ||
|
||||
!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) ||
|
||||
strCdr.Usage != rcvCdr.Usage ||
|
||||
strCdr.Pdd != rcvCdr.Pdd ||
|
||||
strCdr.Supplier != rcvCdr.Supplier ||
|
||||
strCdr.DisconnectCause != rcvCdr.DisconnectCause ||
|
||||
!reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0])
|
||||
}
|
||||
}
|
||||
// Check RatedCdr
|
||||
if rcvCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}, FilterOnRated: true}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(rcvCdrs) != 1 {
|
||||
t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs)
|
||||
} else {
|
||||
rcvCdr := rcvCdrs[0]
|
||||
if strCdr.CgrId != rcvCdr.CgrId ||
|
||||
strCdr.TOR != rcvCdr.TOR ||
|
||||
strCdr.AccId != rcvCdr.AccId ||
|
||||
strCdr.CdrHost != rcvCdr.CdrHost ||
|
||||
strCdr.ReqType != rcvCdr.ReqType ||
|
||||
strCdr.Direction != rcvCdr.Direction ||
|
||||
strCdr.Tenant != rcvCdr.Tenant ||
|
||||
strCdr.Category != rcvCdr.Category ||
|
||||
strCdr.Account != rcvCdr.Account ||
|
||||
strCdr.Subject != rcvCdr.Subject ||
|
||||
strCdr.Destination != rcvCdr.Destination ||
|
||||
//!strCdr.SetupTime.Equal(rcvCdr.SetupTime) || // FixMe
|
||||
//!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || // FixMe
|
||||
strCdr.Usage != rcvCdr.Usage ||
|
||||
strCdr.Pdd != rcvCdr.Pdd ||
|
||||
strCdr.Supplier != rcvCdr.Supplier ||
|
||||
strCdr.DisconnectCause != rcvCdr.DisconnectCause ||
|
||||
strCdr.Cost != rcvCdr.Cost ||
|
||||
!reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ func (self *PostgresStorage) SetRatedCdr(cdr *StoredCdr) (err error) {
|
||||
SetupTime: cdr.SetupTime,
|
||||
AnswerTime: cdr.AnswerTime,
|
||||
Usage: cdr.Usage.Seconds(),
|
||||
Pdd: cdr.Pdd.Seconds(),
|
||||
Supplier: cdr.Supplier,
|
||||
DisconnectCause: cdr.DisconnectCause,
|
||||
Cost: cdr.Cost,
|
||||
@@ -131,7 +132,8 @@ func (self *PostgresStorage) SetRatedCdr(cdr *StoredCdr) (err error) {
|
||||
tx = self.db.Begin()
|
||||
updated := tx.Model(TblRatedCdr{}).Where(&TblRatedCdr{Cgrid: cdr.CgrId, Runid: cdr.MediationRunId}).Updates(&TblRatedCdr{Reqtype: cdr.ReqType,
|
||||
Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination,
|
||||
SetupTime: cdr.SetupTime, AnswerTime: cdr.AnswerTime, Usage: cdr.Usage.Seconds(), Supplier: cdr.Supplier, DisconnectCause: cdr.DisconnectCause, Cost: cdr.Cost, ExtraInfo: cdr.ExtraInfo,
|
||||
SetupTime: cdr.SetupTime, AnswerTime: cdr.AnswerTime, Usage: cdr.Usage.Seconds(), Pdd: cdr.Pdd.Seconds(), Supplier: cdr.Supplier, DisconnectCause: cdr.DisconnectCause,
|
||||
Cost: cdr.Cost, ExtraInfo: cdr.ExtraInfo,
|
||||
UpdatedAt: time.Now()})
|
||||
if updated.Error != nil {
|
||||
tx.Rollback()
|
||||
|
||||
@@ -472,22 +472,23 @@ func TestPSQLSetCdr(t *testing.T) {
|
||||
}
|
||||
cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z",
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
|
||||
|
||||
cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z",
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
|
||||
utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
|
||||
utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z",
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
|
||||
|
||||
for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
|
||||
if err := psqlDb.SetCdr(cdr.AsStoredCdr()); err != nil {
|
||||
@@ -497,19 +498,22 @@ func TestPSQLSetCdr(t *testing.T) {
|
||||
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(12) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
|
||||
|
||||
@@ -571,19 +575,22 @@ func TestPSQLSetRatedCdr(t *testing.T) {
|
||||
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(12) * time.Second, Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: "wholesale_run", Cost: 1.201}
|
||||
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
|
||||
|
||||
@@ -793,7 +800,7 @@ func TestPSQLGetStoredCdrs(t *testing.T) {
|
||||
}
|
||||
// Filter on ignoreRated
|
||||
var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CostEnd: utils.Float64Pointer(0.0)}); err != nil {
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
@@ -833,6 +840,24 @@ func TestPSQLGetStoredCdrs(t *testing.T) {
|
||||
} else if len(storedCdrs) != 2 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on minPdd
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on maxPdd
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxPdd: utils.Float64Pointer(3)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 5 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on minPdd, maxPdd
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3), MaxPdd: utils.Float64Pointer(5)}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 3 {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Combined filter
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil {
|
||||
t.Error(err.Error())
|
||||
@@ -840,7 +865,7 @@ func TestPSQLGetStoredCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
// Filter on ignoreDerived
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnDerived: true}); err != nil {
|
||||
if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnRated: true}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(storedCdrs) != 0 { // ToDo: Recheck this value
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
@@ -882,3 +907,80 @@ func TestPSQLRemStoredCdrs(t *testing.T) {
|
||||
t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that what we get is what we set
|
||||
func TestPSQLStoreRestoreCdr(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
strCdr := &StoredCdr{TOR: utils.VOICE, AccId: "ccc1", CdrHost: "192.168.1.1", CdrSource: "TEST_CDR", ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr.CgrId = utils.Sha1(strCdr.AccId, strCdr.SetupTime.String())
|
||||
if err := psqlDb.SetCdr(strCdr); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
if err := psqlDb.SetRatedCdr(strCdr); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
// Check RawCdr
|
||||
if rcvCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(rcvCdrs) != 1 {
|
||||
t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs)
|
||||
} else {
|
||||
rcvCdr := rcvCdrs[0]
|
||||
if strCdr.CgrId != rcvCdr.CgrId ||
|
||||
strCdr.TOR != rcvCdr.TOR ||
|
||||
strCdr.AccId != rcvCdr.AccId ||
|
||||
strCdr.CdrHost != rcvCdr.CdrHost ||
|
||||
strCdr.ReqType != rcvCdr.ReqType ||
|
||||
strCdr.Direction != rcvCdr.Direction ||
|
||||
strCdr.Tenant != rcvCdr.Tenant ||
|
||||
strCdr.Category != rcvCdr.Category ||
|
||||
strCdr.Account != rcvCdr.Account ||
|
||||
strCdr.Subject != rcvCdr.Subject ||
|
||||
strCdr.Destination != rcvCdr.Destination ||
|
||||
!strCdr.SetupTime.Equal(rcvCdr.SetupTime) ||
|
||||
!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) ||
|
||||
strCdr.Usage != rcvCdr.Usage ||
|
||||
strCdr.Pdd != rcvCdr.Pdd ||
|
||||
strCdr.Supplier != rcvCdr.Supplier ||
|
||||
strCdr.DisconnectCause != rcvCdr.DisconnectCause ||
|
||||
!reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0])
|
||||
}
|
||||
}
|
||||
// Check RatedCdr
|
||||
if rcvCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}, FilterOnRated: true}); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if len(rcvCdrs) != 1 {
|
||||
t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs)
|
||||
} else {
|
||||
rcvCdr := rcvCdrs[0]
|
||||
if strCdr.CgrId != rcvCdr.CgrId ||
|
||||
strCdr.TOR != rcvCdr.TOR ||
|
||||
strCdr.AccId != rcvCdr.AccId ||
|
||||
strCdr.CdrHost != rcvCdr.CdrHost ||
|
||||
strCdr.ReqType != rcvCdr.ReqType ||
|
||||
strCdr.Direction != rcvCdr.Direction ||
|
||||
strCdr.Tenant != rcvCdr.Tenant ||
|
||||
strCdr.Category != rcvCdr.Category ||
|
||||
strCdr.Account != rcvCdr.Account ||
|
||||
strCdr.Subject != rcvCdr.Subject ||
|
||||
strCdr.Destination != rcvCdr.Destination ||
|
||||
//!strCdr.SetupTime.Equal(rcvCdr.SetupTime) || // FixMe
|
||||
//!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || // FixMe
|
||||
strCdr.Usage != rcvCdr.Usage ||
|
||||
strCdr.Pdd != rcvCdr.Pdd ||
|
||||
strCdr.Supplier != rcvCdr.Supplier ||
|
||||
strCdr.DisconnectCause != rcvCdr.DisconnectCause ||
|
||||
strCdr.Cost != rcvCdr.Cost ||
|
||||
!reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,6 +618,7 @@ func (self *SQLStorage) SetCdr(cdr *StoredCdr) error {
|
||||
SetupTime: cdr.SetupTime,
|
||||
AnswerTime: cdr.AnswerTime,
|
||||
Usage: cdr.Usage.Seconds(),
|
||||
Pdd: cdr.Pdd.Seconds(),
|
||||
Supplier: cdr.Supplier,
|
||||
DisconnectCause: cdr.DisconnectCause,
|
||||
CreatedAt: time.Now()})
|
||||
@@ -642,16 +643,16 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
var cdrs []*StoredCdr
|
||||
// Select string
|
||||
var selectStr string
|
||||
if qryFltr.FilterOnDerived { // We use different tables to query account data in case of derived
|
||||
selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans",
|
||||
utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS,
|
||||
if qryFltr.FilterOnRated { // We use different tables to query account data in case of derived
|
||||
selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.pdd,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans",
|
||||
utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS,
|
||||
utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS,
|
||||
utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS,
|
||||
utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS)
|
||||
} else {
|
||||
selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans",
|
||||
utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY,
|
||||
selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.pdd,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans",
|
||||
utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY,
|
||||
utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY,
|
||||
utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS,
|
||||
utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS)
|
||||
|
||||
@@ -697,91 +698,91 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
}
|
||||
if len(qryFltr.ReqTypes) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".reqtype in (?)", qryFltr.ReqTypes)
|
||||
}
|
||||
if len(qryFltr.NotReqTypes) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".reqtype not in (?)", qryFltr.NotReqTypes)
|
||||
}
|
||||
if len(qryFltr.Directions) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".direction in (?)", qryFltr.Directions)
|
||||
}
|
||||
if len(qryFltr.NotDirections) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".direction not in (?)", qryFltr.NotDirections)
|
||||
}
|
||||
if len(qryFltr.Tenants) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".tenant in (?)", qryFltr.Tenants)
|
||||
}
|
||||
if len(qryFltr.NotTenants) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".tenant not in (?)", qryFltr.NotTenants)
|
||||
}
|
||||
if len(qryFltr.Categories) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".category in (?)", qryFltr.Categories)
|
||||
}
|
||||
if len(qryFltr.NotCategories) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".category not in (?)", qryFltr.NotCategories)
|
||||
}
|
||||
if len(qryFltr.Accounts) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".account in (?)", qryFltr.Accounts)
|
||||
}
|
||||
if len(qryFltr.NotAccounts) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".account not in (?)", qryFltr.NotAccounts)
|
||||
}
|
||||
if len(qryFltr.Subjects) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".subject in (?)", qryFltr.Subjects)
|
||||
}
|
||||
if len(qryFltr.NotSubjects) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".subject not in (?)", qryFltr.NotSubjects)
|
||||
}
|
||||
if len(qryFltr.DestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
qIds := bytes.NewBufferString("(")
|
||||
@@ -796,7 +797,7 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
}
|
||||
if len(qryFltr.NotDestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
qIds := bytes.NewBufferString("(")
|
||||
@@ -811,28 +812,28 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
}
|
||||
if len(qryFltr.Suppliers) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".supplier in (?)", qryFltr.Subjects)
|
||||
}
|
||||
if len(qryFltr.NotSuppliers) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".supplier not in (?)", qryFltr.NotSubjects)
|
||||
}
|
||||
if len(qryFltr.DisconnectCauses) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".disconnect_cause in (?)", qryFltr.DisconnectCauses)
|
||||
}
|
||||
if len(qryFltr.NotDisconnectCauses) != 0 {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".disconnect_cause not in (?)", qryFltr.NotDisconnectCauses)
|
||||
@@ -889,89 +890,103 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
}
|
||||
if qryFltr.SetupTimeStart != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".setup_time >= ?", qryFltr.SetupTimeStart)
|
||||
}
|
||||
if qryFltr.SetupTimeEnd != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".setup_time < ?", qryFltr.SetupTimeEnd)
|
||||
}
|
||||
if qryFltr.AnswerTimeStart != nil && !qryFltr.AnswerTimeStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".answer_time >= ?", qryFltr.AnswerTimeStart)
|
||||
}
|
||||
if qryFltr.AnswerTimeEnd != nil && !qryFltr.AnswerTimeEnd.IsZero() {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".answer_time < ?", qryFltr.AnswerTimeEnd)
|
||||
}
|
||||
if qryFltr.CreatedAtStart != nil && !qryFltr.CreatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".created_at >= ?", qryFltr.CreatedAtStart)
|
||||
}
|
||||
if qryFltr.CreatedAtEnd != nil && !qryFltr.CreatedAtEnd.IsZero() {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".created_at < ?", qryFltr.CreatedAtEnd)
|
||||
}
|
||||
if qryFltr.UpdatedAtStart != nil && !qryFltr.UpdatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".updated_at >= ?", qryFltr.UpdatedAtStart)
|
||||
}
|
||||
if qryFltr.UpdatedAtEnd != nil && !qryFltr.UpdatedAtEnd.IsZero() {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".updated_at < ?", qryFltr.UpdatedAtEnd)
|
||||
}
|
||||
if qryFltr.UsageStart != nil {
|
||||
if qryFltr.MinUsage != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".usage >= ?", qryFltr.UsageStart)
|
||||
q = q.Where(tblName+".usage >= ?", qryFltr.MinUsage)
|
||||
}
|
||||
if qryFltr.UsageEnd != nil {
|
||||
if qryFltr.MaxUsage != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnDerived {
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".usage < ?", qryFltr.UsageEnd)
|
||||
q = q.Where(tblName+".usage < ?", qryFltr.MaxUsage)
|
||||
}
|
||||
if qryFltr.MinPdd != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".pdd >= ?", qryFltr.MinPdd)
|
||||
}
|
||||
if qryFltr.MaxPdd != nil {
|
||||
tblName := utils.TBL_CDRS_PRIMARY
|
||||
if qryFltr.FilterOnRated {
|
||||
tblName = utils.TBL_RATED_CDRS
|
||||
}
|
||||
q = q.Where(tblName+".pdd < ?", qryFltr.MaxPdd)
|
||||
}
|
||||
|
||||
if qryFltr.CostStart != nil {
|
||||
if qryFltr.CostEnd == nil {
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.CostStart)
|
||||
} else if *qryFltr.CostStart == 0.0 && *qryFltr.CostEnd == -1.0 { // Special case when we want to skip errors
|
||||
if qryFltr.MinCost != nil {
|
||||
if qryFltr.MaxCost == nil {
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost)
|
||||
} else if *qryFltr.MinCost == 0.0 && *qryFltr.MaxCost == -1.0 { // Special case when we want to skip errors
|
||||
q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost >= 0.0 )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS))
|
||||
} else {
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.CostStart)
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost < ?", *qryFltr.CostEnd)
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost)
|
||||
q = q.Where(utils.TBL_RATED_CDRS+".cost < ?", *qryFltr.MaxCost)
|
||||
}
|
||||
} else if qryFltr.CostEnd != nil {
|
||||
if *qryFltr.CostEnd == -1.0 { // Non-rated CDRs
|
||||
} else if qryFltr.MaxCost != nil {
|
||||
if *qryFltr.MaxCost == -1.0 { // Non-rated CDRs
|
||||
q = q.Where(utils.TBL_RATED_CDRS + ".cost IS NULL") // Need to include it otherwise all CDRs will be returned
|
||||
} else { // Above limited CDRs, since costStart is empty, make sure we query also NULL cost
|
||||
q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost < %f )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, *qryFltr.CostEnd))
|
||||
} else { // Above limited CDRs, since MinCost is empty, make sure we query also NULL cost
|
||||
q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost < %f )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, *qryFltr.MaxCost))
|
||||
}
|
||||
}
|
||||
if qryFltr.Paginator.Limit != nil {
|
||||
@@ -1000,11 +1015,11 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
var extraFields, ccTimespansBytes []byte
|
||||
var setupTime, answerTime mysql.NullTime
|
||||
var orderid int64
|
||||
var usage, cost, ccCost sql.NullFloat64
|
||||
var usage, pdd, cost, ccCost sql.NullFloat64
|
||||
var extraFieldsMp map[string]string
|
||||
var ccTimespans TimeSpans
|
||||
if err := rows.Scan(&cgrid, &orderid, &tor, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &category, &account, &subject, &destination,
|
||||
&setupTime, &answerTime, &usage, &ccSupplier, &ccDisconnectCause,
|
||||
&setupTime, &answerTime, &usage, &pdd, &ccSupplier, &ccDisconnectCause,
|
||||
&extraFields, &runid, &cost, &ccTor, &ccDirection, &ccTenant, &ccCategory, &ccAccount, &ccSubject, &ccDestination, &ccCost, &ccTimespansBytes); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -1019,11 +1034,12 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr,
|
||||
}
|
||||
}
|
||||
usageDur, _ := time.ParseDuration(strconv.FormatFloat(usage.Float64, 'f', -1, 64) + "s")
|
||||
pddDur, _ := time.ParseDuration(strconv.FormatFloat(pdd.Float64, 'f', -1, 64) + "s")
|
||||
storCdr := &StoredCdr{
|
||||
CgrId: cgrid.String, OrderId: orderid, TOR: tor.String, AccId: accid.String, CdrHost: cdrhost.String, CdrSource: cdrsrc.String, ReqType: reqtype.String,
|
||||
Direction: direction.String, Tenant: tenant.String,
|
||||
Category: category.String, Account: account.String, Subject: subject.String, Destination: destination.String,
|
||||
SetupTime: setupTime.Time, AnswerTime: answerTime.Time, Usage: usageDur, Supplier: ccSupplier.String, DisconnectCause: ccDisconnectCause.String,
|
||||
SetupTime: setupTime.Time, AnswerTime: answerTime.Time, Usage: usageDur, Pdd: pddDur, Supplier: ccSupplier.String, DisconnectCause: ccDisconnectCause.String,
|
||||
ExtraFields: extraFieldsMp, MediationRunId: runid.String, RatedAccount: ccAccount.String, RatedSubject: ccSubject.String, Cost: cost.Float64,
|
||||
}
|
||||
if ccTimespans != nil {
|
||||
|
||||
@@ -46,6 +46,9 @@ func NewStoredCdrFromExternalCdr(extCdr *ExternalCdr) (*StoredCdr, error) {
|
||||
if storedCdr.Usage, err = utils.ParseDurationWithSecs(extCdr.Usage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if storedCdr.Pdd, err = utils.ParseDurationWithSecs(extCdr.Pdd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(extCdr.CostDetails) != 0 {
|
||||
if err = json.Unmarshal([]byte(extCdr.CostDetails), storedCdr.CostDetails); err != nil {
|
||||
return nil, err
|
||||
@@ -72,6 +75,7 @@ type StoredCdr struct {
|
||||
SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
|
||||
AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
|
||||
Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call)
|
||||
Pdd time.Duration // PDD value
|
||||
Supplier string // Supplier information when available
|
||||
DisconnectCause string // Disconnect cause of the event
|
||||
ExtraFields map[string]string // Extra fields to be stored in CDR
|
||||
@@ -157,6 +161,8 @@ func (storedCdr *StoredCdr) FieldAsString(rsrFld *utils.RSRField) string {
|
||||
return rsrFld.ParseValue(storedCdr.AnswerTime.Format(time.RFC3339))
|
||||
case utils.USAGE:
|
||||
return strconv.FormatFloat(utils.Round(storedCdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case utils.PDD:
|
||||
return strconv.FormatFloat(utils.Round(storedCdr.Pdd.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case utils.SUPPLIER:
|
||||
return rsrFld.ParseValue(storedCdr.Supplier)
|
||||
case utils.DISCONNECT_CAUSE:
|
||||
@@ -220,6 +226,7 @@ func (storedCdr *StoredCdr) AsHttpForm() url.Values {
|
||||
v.Set(utils.SETUP_TIME, storedCdr.SetupTime.Format(time.RFC3339))
|
||||
v.Set(utils.ANSWER_TIME, storedCdr.AnswerTime.Format(time.RFC3339))
|
||||
v.Set(utils.USAGE, storedCdr.FormatUsage(utils.SECONDS))
|
||||
v.Set(utils.PDD, storedCdr.FieldAsString(&utils.RSRField{Id: utils.PDD}))
|
||||
v.Set(utils.SUPPLIER, storedCdr.Supplier)
|
||||
v.Set(utils.DISCONNECT_CAUSE, storedCdr.DisconnectCause)
|
||||
if storedCdr.CostDetails != nil {
|
||||
@@ -230,7 +237,7 @@ func (storedCdr *StoredCdr) AsHttpForm() url.Values {
|
||||
|
||||
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored
|
||||
func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld,
|
||||
answerTimeFld, durationFld, supplierFld, disconnectCauseFld *utils.RSRField,
|
||||
answerTimeFld, durationFld, pddFld, supplierFld, disconnectCauseFld *utils.RSRField,
|
||||
extraFlds []*utils.RSRField, primaryMandatory bool) (*StoredCdr, error) {
|
||||
if reqTypeFld == nil {
|
||||
reqTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT)
|
||||
@@ -292,6 +299,12 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena
|
||||
if durationFld.Id == utils.META_DEFAULT {
|
||||
durationFld.Id = utils.USAGE
|
||||
}
|
||||
if pddFld == nil {
|
||||
pddFld, _ = utils.NewRSRField(utils.META_DEFAULT)
|
||||
}
|
||||
if pddFld.Id == utils.META_DEFAULT {
|
||||
pddFld.Id = utils.PDD
|
||||
}
|
||||
if supplierFld == nil {
|
||||
supplierFld, _ = utils.NewRSRField(utils.META_DEFAULT)
|
||||
}
|
||||
@@ -359,6 +372,12 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena
|
||||
} else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pddStr := storedCdr.FieldAsString(pddFld)
|
||||
if primaryMandatory && len(pddStr) == 0 {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.PDD, pddFld.Id))
|
||||
} else if frkStorCdr.Pdd, err = utils.ParseDurationWithSecs(pddStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frkStorCdr.Supplier = storedCdr.FieldAsString(supplierFld)
|
||||
frkStorCdr.DisconnectCause = storedCdr.FieldAsString(disconnectCauseFld)
|
||||
frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds))
|
||||
@@ -385,6 +404,7 @@ func (storedCdr *StoredCdr) AsExternalCdr() *ExternalCdr {
|
||||
SetupTime: storedCdr.SetupTime.Format(time.RFC3339),
|
||||
AnswerTime: storedCdr.AnswerTime.Format(time.RFC3339),
|
||||
Usage: storedCdr.FormatUsage(utils.SECONDS),
|
||||
Pdd: storedCdr.FieldAsString(&utils.RSRField{Id: utils.PDD}),
|
||||
Supplier: storedCdr.Supplier,
|
||||
DisconnectCause: storedCdr.DisconnectCause,
|
||||
ExtraFields: storedCdr.ExtraFields,
|
||||
@@ -523,6 +543,18 @@ func (storedCdr *StoredCdr) GetDuration(fieldName string) (time.Duration, error)
|
||||
}
|
||||
return utils.ParseDurationWithSecs(durVal)
|
||||
}
|
||||
func (storedCdr *StoredCdr) GetPdd(fieldName string) (time.Duration, error) {
|
||||
if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) {
|
||||
return storedCdr.Pdd, nil
|
||||
}
|
||||
var pddVal string
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
pddVal = fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
} else {
|
||||
pddVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
|
||||
}
|
||||
return utils.ParseDurationWithSecs(pddVal)
|
||||
}
|
||||
func (storedCdr *StoredCdr) GetSupplier(fieldName string) string {
|
||||
if utils.IsSliceMember([]string{utils.SUPPLIER, utils.META_DEFAULT}, fieldName) {
|
||||
return storedCdr.Supplier
|
||||
@@ -576,6 +608,7 @@ type ExternalCdr struct {
|
||||
SetupTime string
|
||||
AnswerTime string
|
||||
Usage string
|
||||
Pdd string
|
||||
Supplier string
|
||||
DisconnectCause string
|
||||
ExtraFields map[string]string
|
||||
|
||||
@@ -37,13 +37,13 @@ func TestNewStoredCdrFromExternalCdr(t *testing.T) {
|
||||
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1",
|
||||
SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: "0.00000001", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
Usage: "0.00000001", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
}
|
||||
eStorCdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
|
||||
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10), ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
Usage: time.Duration(10), Pdd: time.Duration(7) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
}
|
||||
if storedCdr, err := NewStoredCdrFromExternalCdr(extCdr); err != nil {
|
||||
t.Error(err)
|
||||
@@ -57,7 +57,7 @@ func TestFieldAsString(t *testing.T) {
|
||||
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(5) * time.Second, Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
|
||||
}
|
||||
if cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CgrId ||
|
||||
@@ -75,6 +75,7 @@ func TestFieldAsString(t *testing.T) {
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339) ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339) ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.PDD}) != "5" ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.SUPPLIER}) != cdr.Supplier ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.MediationRunId ||
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01" ||
|
||||
@@ -99,6 +100,7 @@ func TestFieldAsString(t *testing.T) {
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339),
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339),
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10",
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.PDD}) != "5",
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.SUPPLIER}) != cdr.Supplier,
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.MediationRunId,
|
||||
cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_ACCOUNT}) != "dan",
|
||||
@@ -341,8 +343,9 @@ func TestStoredCdrForkCdr(t *testing.T) {
|
||||
Cost: 1.01, RatedSubject: "dans"}
|
||||
rtSampleCdrOut, err := storCdr.ForkCdr("sample_run1", &utils.RSRField{Id: utils.REQTYPE}, &utils.RSRField{Id: utils.DIRECTION}, &utils.RSRField{Id: utils.TENANT},
|
||||
&utils.RSRField{Id: utils.CATEGORY}, &utils.RSRField{Id: utils.ACCOUNT}, &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION},
|
||||
&utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, &utils.RSRField{Id: utils.SUPPLIER},
|
||||
&utils.RSRField{Id: utils.DISCONNECT_CAUSE}, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "field_extr2"}}, true)
|
||||
&utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, &utils.RSRField{Id: utils.PDD},
|
||||
&utils.RSRField{Id: utils.SUPPLIER}, &utils.RSRField{Id: utils.DISCONNECT_CAUSE},
|
||||
[]*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "field_extr2"}}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
@@ -374,22 +377,24 @@ func TestStoredCdrForkCdrStaticVals(t *testing.T) {
|
||||
rsrStDur, _ := utils.NewRSRField("^12s")
|
||||
rsrStSuppl, _ := utils.NewRSRField("^supplier1")
|
||||
rsrStDCause, _ := utils.NewRSRField("^HANGUP_COMPLETE")
|
||||
rsrPdd, _ := utils.NewRSRField("^3")
|
||||
rtCdrOut2, err := storCdr.ForkCdr("wholesale_run", rsrStPostpaid, rsrStIn, rsrStCgr, rsrStPC, rsrStFA, rsrStFS, &utils.RSRField{Id: "destination"},
|
||||
rsrStST, rsrStAT, rsrStDur, rsrStSuppl, rsrStDCause, []*utils.RSRField{}, true)
|
||||
rsrStST, rsrStAT, rsrStDur, rsrPdd, rsrStSuppl, rsrStDCause, []*utils.RSRField{}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr2 := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID,
|
||||
Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(12) * time.Second, Supplier: "supplier1", DisconnectCause: "HANGUP_COMPLETE",
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(12) * time.Second, Pdd: time.Duration(3) * time.Second,
|
||||
Supplier: "supplier1", DisconnectCause: "HANGUP_COMPLETE",
|
||||
ExtraFields: map[string]string{}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) {
|
||||
t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2)
|
||||
}
|
||||
_, err = storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: "dummy_header"}, &utils.RSRField{Id: "direction"}, &utils.RSRField{Id: "tenant"},
|
||||
&utils.RSRField{Id: "tor"}, &utils.RSRField{Id: "account"}, &utils.RSRField{Id: "subject"}, &utils.RSRField{Id: "destination"},
|
||||
&utils.RSRField{Id: "setup_time"}, &utils.RSRField{Id: "answer_time"}, &utils.RSRField{Id: "duration"}, &utils.RSRField{Id: utils.SUPPLIER},
|
||||
&utils.RSRField{Id: "setup_time"}, &utils.RSRField{Id: "answer_time"}, &utils.RSRField{Id: "duration"}, &utils.RSRField{Id: utils.PDD}, &utils.RSRField{Id: utils.SUPPLIER},
|
||||
&utils.RSRField{Id: utils.DISCONNECT_CAUSE}, []*utils.RSRField{}, true)
|
||||
if err == nil {
|
||||
t.Error("Failed to detect missing header")
|
||||
@@ -401,17 +406,18 @@ func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) {
|
||||
CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL3", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL3", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
}
|
||||
expctCdr := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED,
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: time.Duration(10) * time.Second, Supplier: "SUPPL3",
|
||||
Usage: time.Duration(10) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL3",
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
cdrOut, err := storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
|
||||
&utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
|
||||
&utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
|
||||
&utils.RSRField{Id: utils.META_DEFAULT}, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true)
|
||||
&utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
|
||||
[]*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error received", err)
|
||||
}
|
||||
@@ -420,7 +426,7 @@ func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) {
|
||||
t.Errorf("Expected: %v, received: %v", expctCdr, cdrOut)
|
||||
}
|
||||
// Should also accept nil as defaults
|
||||
if cdrOut, err := storCdr.ForkCdr("wholesale_run", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
if cdrOut, err := storCdr.ForkCdr("wholesale_run", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
[]*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true); err != nil {
|
||||
t.Fatal("Unexpected error received", err)
|
||||
} else if !reflect.DeepEqual(expctCdr, cdrOut) {
|
||||
@@ -433,14 +439,14 @@ func TestStoredCdrAsExternalCdr(t *testing.T) {
|
||||
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(10), Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: time.Duration(10), Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
|
||||
}
|
||||
expectOutCdr := &ExternalCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
|
||||
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", MediationRunId: utils.DEFAULT_RUNID,
|
||||
Usage: "0.00000001", Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Usage: "0.00000001", Pdd: "7", Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
|
||||
}
|
||||
if cdrOut := storCdr.AsExternalCdr(); !reflect.DeepEqual(expectOutCdr, cdrOut) {
|
||||
|
||||
@@ -292,7 +292,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnDerived: true}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
|
||||
@@ -380,7 +380,7 @@ func TestTutKamCallsCdrs(t *testing.T) {
|
||||
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnDerived: true}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
|
||||
@@ -290,7 +290,7 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnDerived: true}
|
||||
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
|
||||
@@ -37,36 +37,39 @@ type FSEvent map[string]string
|
||||
|
||||
const (
|
||||
// Freswitch event proprities names
|
||||
DIRECTION = "Call-Direction"
|
||||
SUBJECT = "variable_cgr_subject"
|
||||
ACCOUNT = "variable_cgr_account"
|
||||
DESTINATION = "variable_cgr_destination"
|
||||
REQTYPE = "variable_cgr_reqtype" //prepaid or postpaid
|
||||
Category = "variable_cgr_category"
|
||||
VAR_CGR_SUPPLIER = "variable_" + utils.CGR_SUPPLIER
|
||||
UUID = "Unique-ID" // -Unique ID for this call leg
|
||||
CSTMID = "variable_cgr_tenant"
|
||||
CALL_DEST_NR = "Caller-Destination-Number"
|
||||
SIP_REQ_USER = "variable_sip_req_user"
|
||||
PARK_TIME = "Caller-Profile-Created-Time"
|
||||
SETUP_TIME = "Caller-Channel-Created-Time"
|
||||
ANSWER_TIME = "Caller-Channel-Answered-Time"
|
||||
END_TIME = "Caller-Channel-Hangup-Time"
|
||||
DURATION = "variable_billsec"
|
||||
NAME = "Event-Name"
|
||||
HEARTBEAT = "HEARTBEAT"
|
||||
ANSWER = "CHANNEL_ANSWER"
|
||||
HANGUP = "CHANNEL_HANGUP_COMPLETE"
|
||||
PARK = "CHANNEL_PARK"
|
||||
AUTH_OK = "+AUTH_OK"
|
||||
DISCONNECT = "+SWITCH DISCONNECT"
|
||||
INSUFFICIENT_FUNDS = "-INSUFFICIENT_FUNDS"
|
||||
MISSING_PARAMETER = "-MISSING_PARAMETER"
|
||||
SYSTEM_ERROR = "-SYSTEM_ERROR"
|
||||
MANAGER_REQUEST = "+MANAGER_REQUEST"
|
||||
USERNAME = "Caller-Username"
|
||||
FS_IPv4 = "FreeSWITCH-IPv4"
|
||||
HANGUP_CAUSE = "Hangup-Cause"
|
||||
DIRECTION = "Call-Direction"
|
||||
SUBJECT = "variable_cgr_subject"
|
||||
ACCOUNT = "variable_cgr_account"
|
||||
DESTINATION = "variable_cgr_destination"
|
||||
REQTYPE = "variable_cgr_reqtype" //prepaid or postpaid
|
||||
Category = "variable_cgr_category"
|
||||
VAR_CGR_SUPPLIER = "variable_" + utils.CGR_SUPPLIER
|
||||
UUID = "Unique-ID" // -Unique ID for this call leg
|
||||
CSTMID = "variable_cgr_tenant"
|
||||
CALL_DEST_NR = "Caller-Destination-Number"
|
||||
SIP_REQ_USER = "variable_sip_req_user"
|
||||
PARK_TIME = "Caller-Profile-Created-Time"
|
||||
SETUP_TIME = "Caller-Channel-Created-Time"
|
||||
ANSWER_TIME = "Caller-Channel-Answered-Time"
|
||||
END_TIME = "Caller-Channel-Hangup-Time"
|
||||
DURATION = "variable_billsec"
|
||||
NAME = "Event-Name"
|
||||
HEARTBEAT = "HEARTBEAT"
|
||||
ANSWER = "CHANNEL_ANSWER"
|
||||
HANGUP = "CHANNEL_HANGUP_COMPLETE"
|
||||
PARK = "CHANNEL_PARK"
|
||||
AUTH_OK = "+AUTH_OK"
|
||||
DISCONNECT = "+SWITCH DISCONNECT"
|
||||
INSUFFICIENT_FUNDS = "-INSUFFICIENT_FUNDS"
|
||||
MISSING_PARAMETER = "-MISSING_PARAMETER"
|
||||
SYSTEM_ERROR = "-SYSTEM_ERROR"
|
||||
MANAGER_REQUEST = "+MANAGER_REQUEST"
|
||||
USERNAME = "Caller-Username"
|
||||
FS_IPv4 = "FreeSWITCH-IPv4"
|
||||
HANGUP_CAUSE = "Hangup-Cause"
|
||||
PDD_MEDIA_MS = "variable_progress_mediamsec"
|
||||
PDD_NOMEDIA_MS = "variable_progressmsec"
|
||||
|
||||
VAR_CGR_DISCONNECT_CAUSE = "variable_" + utils.CGR_DISCONNECT_CAUSE
|
||||
)
|
||||
|
||||
@@ -206,7 +209,7 @@ func (fsev FSEvent) GetEndTime() (t time.Time, err error) {
|
||||
return utils.ParseTimeDetectLayout(fsev[END_TIME])
|
||||
}
|
||||
|
||||
func (fsev FSEvent) GetDuration(fieldName string) (dur time.Duration, err error) {
|
||||
func (fsev FSEvent) GetDuration(fieldName string) (time.Duration, error) {
|
||||
durStr := utils.FirstNonEmpty(fsev[fieldName], fsev[DURATION])
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
durStr = fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
@@ -214,6 +217,21 @@ func (fsev FSEvent) GetDuration(fieldName string) (dur time.Duration, err error)
|
||||
return utils.ParseDurationWithSecs(durStr)
|
||||
}
|
||||
|
||||
func (fsev FSEvent) GetPdd(fieldName string) (time.Duration, error) {
|
||||
var pddStr string
|
||||
if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) {
|
||||
pddStr = utils.FirstNonEmpty(fsev[PDD_MEDIA_MS], fsev[PDD_MEDIA_MS])
|
||||
if len(pddStr) != 0 {
|
||||
pddStr = "0." + pddStr // PDD is in milliseconds and CGR expects it in seconds
|
||||
}
|
||||
} else if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
pddStr = fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
} else {
|
||||
pddStr = fsev[fieldName]
|
||||
}
|
||||
return utils.ParseDurationWithSecs(pddStr)
|
||||
}
|
||||
|
||||
func (fsev FSEvent) GetSupplier(fieldName string) string {
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
@@ -281,6 +299,9 @@ func (fsev FSEvent) ParseEventValue(rsrFld *utils.RSRField) string {
|
||||
case utils.USAGE:
|
||||
dur, _ := fsev.GetDuration("")
|
||||
return rsrFld.ParseValue(strconv.FormatInt(dur.Nanoseconds(), 10))
|
||||
case utils.PDD:
|
||||
pdd, _ := fsev.GetPdd(utils.META_DEFAULT)
|
||||
return rsrFld.ParseValue(strconv.FormatFloat(pdd.Seconds(), 'f', -1, 64))
|
||||
case utils.SUPPLIER:
|
||||
return rsrFld.ParseValue(fsev.GetSupplier(""))
|
||||
case utils.DISCONNECT_CAUSE:
|
||||
@@ -332,6 +353,7 @@ func (fsev FSEvent) AsStoredCdr() *engine.StoredCdr {
|
||||
storCdr.SetupTime, _ = fsev.GetSetupTime(utils.META_DEFAULT)
|
||||
storCdr.AnswerTime, _ = fsev.GetAnswerTime(utils.META_DEFAULT)
|
||||
storCdr.Usage, _ = fsev.GetDuration(utils.META_DEFAULT)
|
||||
storCdr.Pdd, _ = fsev.GetPdd(utils.META_DEFAULT)
|
||||
storCdr.ExtraFields = fsev.GetExtraFields()
|
||||
storCdr.Cost = -1
|
||||
storCdr.Supplier = fsev.GetSupplier(utils.META_DEFAULT)
|
||||
|
||||
@@ -566,6 +566,9 @@ func TestParseEventValue(t *testing.T) {
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.USAGE}); parsed != "5000000000" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.PDD}); parsed != "0.28" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.SUPPLIER}); parsed != "supplier1" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
@@ -639,7 +642,7 @@ func TestFsEvAsStoredCdr(t *testing.T) {
|
||||
TOR: utils.VOICE, AccId: "37e9b766-5256-4e4b-b1ed-3767b930fec8", CdrHost: "10.0.2.15", CdrSource: "FS_CHANNEL_HANGUP_COMPLETE", ReqType: utils.META_PSEUDOPREPAID,
|
||||
Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003",
|
||||
Destination: "1002", SetupTime: setupTime, AnswerTime: aTime,
|
||||
Usage: time.Duration(5) * time.Second, Supplier: "supplier1", DisconnectCause: "NORMAL_CLEARING", ExtraFields: make(map[string]string), Cost: -1}
|
||||
Usage: time.Duration(5) * time.Second, Pdd: time.Duration(280) * time.Millisecond, Supplier: "supplier1", DisconnectCause: "NORMAL_CLEARING", ExtraFields: make(map[string]string), Cost: -1}
|
||||
if storedCdr := ev.AsStoredCdr(); !reflect.DeepEqual(eStoredCdr, storedCdr) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ const (
|
||||
CGR_ANSWERTIME = "cgr_answertime"
|
||||
CGR_STOPTIME = "cgr_stoptime"
|
||||
CGR_DURATION = "cgr_duration"
|
||||
CGR_PDD = "cgr_pdd"
|
||||
|
||||
KAM_TR_INDEX = "tr_index"
|
||||
KAM_TR_LABEL = "tr_label"
|
||||
@@ -51,7 +52,7 @@ const (
|
||||
)
|
||||
|
||||
var primaryFields = []string{EVENT, CALLID, FROM_TAG, HASH_ENTRY, HASH_ID, CGR_ACCOUNT, CGR_SUBJECT, CGR_DESTINATION,
|
||||
CGR_CATEGORY, CGR_TENANT, CGR_REQTYPE, CGR_ANSWERTIME, CGR_SETUPTIME, CGR_STOPTIME, CGR_DURATION, utils.CGR_SUPPLIER, utils.CGR_DISCONNECT_CAUSE}
|
||||
CGR_CATEGORY, CGR_TENANT, CGR_REQTYPE, CGR_ANSWERTIME, CGR_SETUPTIME, CGR_STOPTIME, CGR_DURATION, CGR_PDD, utils.CGR_SUPPLIER, utils.CGR_DISCONNECT_CAUSE}
|
||||
|
||||
type KamAuthReply struct {
|
||||
Event string // Kamailio will use this to differentiate between requests and replies
|
||||
@@ -186,7 +187,17 @@ func (kev KamEvent) GetDuration(fieldName string) (time.Duration, error) {
|
||||
}
|
||||
return utils.ParseDurationWithSecs(durStr)
|
||||
}
|
||||
|
||||
func (kev KamEvent) GetPdd(fieldName string) (time.Duration, error) {
|
||||
var pddStr string
|
||||
if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) {
|
||||
pddStr = kev[CGR_PDD]
|
||||
} else if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
pddStr = fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
} else {
|
||||
pddStr = kev[fieldName]
|
||||
}
|
||||
return utils.ParseDurationWithSecs(pddStr)
|
||||
}
|
||||
func (kev KamEvent) GetSupplier(fieldName string) string {
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
@@ -292,6 +303,8 @@ func (kev KamEvent) ParseEventValue(rsrFld *utils.RSRField) string {
|
||||
return rsrFld.ParseValue(aTime.String())
|
||||
case utils.USAGE:
|
||||
return rsrFld.ParseValue(strconv.FormatFloat(utils.Round(duration.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64))
|
||||
case utils.PDD:
|
||||
return rsrFld.ParseValue(strconv.FormatFloat(utils.Round(duration.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64))
|
||||
case utils.SUPPLIER:
|
||||
return rsrFld.ParseValue(kev.GetSupplier(utils.META_DEFAULT))
|
||||
case utils.DISCONNECT_CAUSE:
|
||||
@@ -325,6 +338,7 @@ func (kev KamEvent) AsStoredCdr() *engine.StoredCdr {
|
||||
storCdr.SetupTime, _ = kev.GetSetupTime(utils.META_DEFAULT)
|
||||
storCdr.AnswerTime, _ = kev.GetAnswerTime(utils.META_DEFAULT)
|
||||
storCdr.Usage, _ = kev.GetDuration(utils.META_DEFAULT)
|
||||
storCdr.Pdd, _ = kev.GetPdd(utils.META_DEFAULT)
|
||||
storCdr.Supplier = kev.GetSupplier(utils.META_DEFAULT)
|
||||
storCdr.DisconnectCause = kev.GetDisconnectCause(utils.META_DEFAULT)
|
||||
storCdr.ExtraFields = kev.GetExtraFields()
|
||||
|
||||
@@ -47,9 +47,11 @@ func TestNewKamEvent(t *testing.T) {
|
||||
"cgr_answertime":"1419839310",
|
||||
"cgr_duration":"3",
|
||||
"cgr_supplier":"supplier2",
|
||||
"cgr_disconnectcause": "200"}`
|
||||
"cgr_disconnectcause": "200",
|
||||
"cgr_pdd": "4"}`
|
||||
eKamEv := KamEvent{"event": "CGR_CALL_END", "callid": "46c01a5c249b469e76333fc6bfa87f6a@0:0:0:0:0:0:0:0", "from_tag": "bf71ad59", "to_tag": "7351fecf",
|
||||
"cgr_reqtype": utils.META_POSTPAID, "cgr_account": "1001", "cgr_destination": "1002", "cgr_answertime": "1419839310", "cgr_duration": "3", utils.CGR_SUPPLIER: "supplier2",
|
||||
"cgr_reqtype": utils.META_POSTPAID, "cgr_account": "1001", "cgr_destination": "1002", "cgr_answertime": "1419839310", "cgr_duration": "3", CGR_PDD: "4",
|
||||
utils.CGR_SUPPLIER: "supplier2",
|
||||
utils.CGR_DISCONNECT_CAUSE: "200"}
|
||||
if kamEv, err := NewKamEvent([]byte(evStr)); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -175,6 +175,17 @@ func (osipsev *OsipsEvent) GetDuration(fieldName string) (time.Duration, error)
|
||||
}
|
||||
return utils.ParseDurationWithSecs(durStr)
|
||||
}
|
||||
func (osipsev *OsipsEvent) GetPdd(fieldName string) (time.Duration, error) {
|
||||
var pddStr string
|
||||
if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) {
|
||||
pddStr = osipsev.osipsEvent.AttrValues[CGR_PDD]
|
||||
} else if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
pddStr = fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
} else {
|
||||
pddStr = osipsev.osipsEvent.AttrValues[fieldName]
|
||||
}
|
||||
return utils.ParseDurationWithSecs(pddStr)
|
||||
}
|
||||
func (osipsev *OsipsEvent) GetSupplier(fieldName string) string {
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
@@ -236,7 +247,7 @@ func (osipsev *OsipsEvent) PassesFieldFilter(*utils.RSRField) (bool, string) {
|
||||
}
|
||||
func (osipsev *OsipsEvent) GetExtraFields() map[string]string {
|
||||
primaryFields := []string{TO_TAG, SETUP_DURATION, OSIPS_SETUP_TIME, "method", "callid", "sip_reason", OSIPS_EVENT_TIME, "sip_code", "duration", "from_tag", "dialog_id",
|
||||
CGR_TENANT, CGR_CATEGORY, CGR_REQTYPE, CGR_ACCOUNT, CGR_SUBJECT, CGR_DESTINATION, utils.CGR_SUPPLIER}
|
||||
CGR_TENANT, CGR_CATEGORY, CGR_REQTYPE, CGR_ACCOUNT, CGR_SUBJECT, CGR_DESTINATION, utils.CGR_SUPPLIER, CGR_PDD}
|
||||
extraFields := make(map[string]string)
|
||||
for field, val := range osipsev.osipsEvent.AttrValues {
|
||||
if !utils.IsSliceMember(primaryFields, field) {
|
||||
@@ -267,6 +278,7 @@ func (osipsEv *OsipsEvent) AsStoredCdr() *engine.StoredCdr {
|
||||
storCdr.SetupTime, _ = osipsEv.GetSetupTime(utils.META_DEFAULT)
|
||||
storCdr.AnswerTime, _ = osipsEv.GetAnswerTime(utils.META_DEFAULT)
|
||||
storCdr.Usage, _ = osipsEv.GetDuration(utils.META_DEFAULT)
|
||||
storCdr.Pdd, _ = osipsEv.GetPdd(utils.META_DEFAULT)
|
||||
storCdr.Supplier = osipsEv.GetSupplier(utils.META_DEFAULT)
|
||||
storCdr.DisconnectCause = osipsEv.GetDisconnectCause(utils.META_DEFAULT)
|
||||
storCdr.ExtraFields = osipsEv.GetExtraFields()
|
||||
|
||||
@@ -34,7 +34,7 @@ var addr, _ = net.ResolveUDPAddr("udp", "172.16.254.77:42574")
|
||||
var osipsEv = &OsipsEvent{osipsEvent: &osipsdagram.OsipsEvent{Name: "E_ACC_CDR",
|
||||
AttrValues: map[string]string{"to_tag": "4ea9687f", "cgr_account": "dan", "setuptime": "7", "created": "1406370492", "method": "INVITE", "callid": "ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ",
|
||||
"sip_reason": "OK", "time": "1406370499", "cgr_reqtype": utils.META_PREPAID, "cgr_subject": "dan", "cgr_destination": "+4986517174963", "cgr_tenant": "itsyscom.com", "sip_code": "200",
|
||||
"duration": "20", "from_tag": "eb082607", "extra1": "val1", "extra2": "val2", "cgr_supplier": "supplier3"}, OriginatorAddress: addr}}
|
||||
"duration": "20", CGR_PDD: "3s", "from_tag": "eb082607", "extra1": "val1", "extra2": "val2", "cgr_supplier": "supplier3"}, OriginatorAddress: addr}}
|
||||
|
||||
func TestOsipsEventInterface(t *testing.T) {
|
||||
var _ engine.Event = engine.Event(osipsEv)
|
||||
@@ -44,6 +44,7 @@ func TestOsipsEventParseStatic(t *testing.T) {
|
||||
setupTime, _ := osipsEv.GetSetupTime("^2013-12-07 08:42:24")
|
||||
answerTime, _ := osipsEv.GetAnswerTime("^2013-12-07 08:42:24")
|
||||
dur, _ := osipsEv.GetDuration("^60s")
|
||||
pdd, _ := osipsEv.GetPdd("^10s")
|
||||
if osipsEv.GetReqType("^test") != "test" ||
|
||||
osipsEv.GetDirection("^test") != "test" ||
|
||||
osipsEv.GetTenant("^test") != "test" ||
|
||||
@@ -54,6 +55,7 @@ func TestOsipsEventParseStatic(t *testing.T) {
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
dur != time.Duration(60)*time.Second ||
|
||||
pdd != time.Duration(10)*time.Second ||
|
||||
osipsEv.GetSupplier("^test") != "test" ||
|
||||
osipsEv.GetDisconnectCause("^test") != "test" {
|
||||
t.Error("Values out of static not matching",
|
||||
@@ -67,6 +69,7 @@ func TestOsipsEventParseStatic(t *testing.T) {
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
dur != time.Duration(60)*time.Second,
|
||||
pdd != time.Duration(10)*time.Second,
|
||||
osipsEv.GetSupplier("^test") != "test",
|
||||
osipsEv.GetDisconnectCause("^test") != "test")
|
||||
}
|
||||
@@ -80,6 +83,7 @@ func TestOsipsEventGetValues(t *testing.T) {
|
||||
answerTime, _ := osipsEv.GetAnswerTime(utils.META_DEFAULT)
|
||||
eAnswerTime, _ := utils.ParseTimeDetectLayout("1406370499")
|
||||
dur, _ := osipsEv.GetDuration(utils.META_DEFAULT)
|
||||
pdd, _ := osipsEv.GetPdd(utils.META_DEFAULT)
|
||||
endTime, _ := osipsEv.GetEndTime()
|
||||
if osipsEv.GetName() != "E_ACC_CDR" ||
|
||||
osipsEv.GetCgrId() != utils.Sha1("ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", setupTime.UTC().String()) ||
|
||||
@@ -96,6 +100,7 @@ func TestOsipsEventGetValues(t *testing.T) {
|
||||
!answerTime.Equal(eAnswerTime) ||
|
||||
!endTime.Equal(eAnswerTime.Add(dur)) ||
|
||||
dur != time.Duration(20*time.Second) ||
|
||||
pdd != time.Duration(3)*time.Second ||
|
||||
osipsEv.GetSupplier(utils.META_DEFAULT) != "supplier3" ||
|
||||
osipsEv.GetDisconnectCause(utils.META_DEFAULT) != "200" ||
|
||||
osipsEv.GetOriginatorIP(utils.META_DEFAULT) != "172.16.254.77" {
|
||||
@@ -114,6 +119,7 @@ func TestOsipsEventGetValues(t *testing.T) {
|
||||
!answerTime.Equal(time.Date(2014, 7, 26, 12, 28, 19, 0, time.Local)),
|
||||
!endTime.Equal(time.Date(2014, 7, 26, 12, 28, 39, 0, time.Local)),
|
||||
dur != time.Duration(20*time.Second),
|
||||
pdd != time.Duration(3)*time.Second,
|
||||
osipsEv.GetSupplier(utils.META_DEFAULT) != "supplier3",
|
||||
osipsEv.GetDisconnectCause(utils.META_DEFAULT) != "200",
|
||||
osipsEv.GetOriginatorIP(utils.META_DEFAULT) != "172.16.254.77",
|
||||
@@ -142,7 +148,7 @@ func TestOsipsEventAsStoredCdr(t *testing.T) {
|
||||
ReqType: utils.META_PREPAID,
|
||||
Direction: utils.OUT, Tenant: "itsyscom.com", Category: "call", Account: "dan", Subject: "dan",
|
||||
Destination: "+4986517174963", SetupTime: setupTime, AnswerTime: answerTime,
|
||||
Usage: time.Duration(20) * time.Second, Supplier: "supplier3", DisconnectCause: "200", ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1}
|
||||
Usage: time.Duration(20) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "supplier3", DisconnectCause: "200", ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1}
|
||||
if storedCdr := osipsEv.AsStoredCdr(); !reflect.DeepEqual(eStoredCdr, storedCdr) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr)
|
||||
}
|
||||
|
||||
@@ -620,10 +620,10 @@ func (self *AttrExpFileCdrs) AsCdrsFilter() (*CdrsFilter, error) {
|
||||
}
|
||||
}
|
||||
if self.SkipRated {
|
||||
cdrFltr.CostEnd = Float64Pointer(-1.0)
|
||||
cdrFltr.MaxCost = Float64Pointer(-1.0)
|
||||
} else if self.SkipRated {
|
||||
cdrFltr.CostStart = Float64Pointer(0.0)
|
||||
cdrFltr.CostEnd = Float64Pointer(-1.0)
|
||||
cdrFltr.MinCost = Float64Pointer(0.0)
|
||||
cdrFltr.MaxCost = Float64Pointer(-1.0)
|
||||
}
|
||||
return cdrFltr, nil
|
||||
}
|
||||
@@ -696,10 +696,10 @@ func (self *AttrGetCdrs) AsCdrsFilter() (*CdrsFilter, error) {
|
||||
}
|
||||
}
|
||||
if self.SkipRated {
|
||||
cdrFltr.CostEnd = Float64Pointer(-1.0)
|
||||
cdrFltr.MaxCost = Float64Pointer(-1.0)
|
||||
} else if self.SkipRated {
|
||||
cdrFltr.CostStart = Float64Pointer(0.0)
|
||||
cdrFltr.CostEnd = Float64Pointer(-1.0)
|
||||
cdrFltr.MinCost = Float64Pointer(0.0)
|
||||
cdrFltr.MaxCost = Float64Pointer(-1.0)
|
||||
}
|
||||
return cdrFltr, nil
|
||||
}
|
||||
@@ -837,11 +837,13 @@ type CdrsFilter struct {
|
||||
CreatedAtEnd *time.Time // End interval, smaller than
|
||||
UpdatedAtStart *time.Time // Start of interval, bigger or equal than configured
|
||||
UpdatedAtEnd *time.Time // End interval, smaller than
|
||||
UsageStart *float64 // Start of the usage interval (>=)
|
||||
UsageEnd *float64 // End of the usage interval (<)
|
||||
CostStart *float64 // Start of the cost interval (>=)
|
||||
CostEnd *float64 // End of the usage interval (<)
|
||||
FilterOnDerived bool // Do not consider derived CDRs but original one
|
||||
MinUsage *float64 // Start of the usage interval (>=)
|
||||
MaxUsage *float64 // End of the usage interval (<)
|
||||
MinPdd *float64 // Start of the pdd interval (>=)
|
||||
MaxPdd *float64 // End of the pdd interval (<)
|
||||
MinCost *float64 // Start of the cost interval (>=)
|
||||
MaxCost *float64 // End of the usage interval (<)
|
||||
FilterOnRated bool // Do not consider rated CDRs but raw one
|
||||
Count bool // If true count the items instead of returning data
|
||||
Paginator
|
||||
}
|
||||
@@ -894,11 +896,13 @@ type RpcCdrsFilter struct {
|
||||
CreatedAtEnd string // End interval, smaller than
|
||||
UpdatedAtStart string // Start of interval, bigger or equal than configured
|
||||
UpdatedAtEnd string // End interval, smaller than
|
||||
UsageStart *float64 // Start of the usage interval (>=)
|
||||
UsageEnd *float64 // End of the usage interval (<)
|
||||
CostStart *float64 // Start of the cost interval (>=)
|
||||
CostEnd *float64 // End of the usage interval (<)
|
||||
FilterOnDerived bool // Do not consider derived CDRs but original one
|
||||
MinUsage *float64 // Start of the usage interval (>=)
|
||||
MaxUsage *float64 // End of the usage interval (<)
|
||||
MinPdd *float64 // Start of the pdd interval (>=)
|
||||
MaxPdd *float64 // End of the pdd interval (<)
|
||||
MinCost *float64 // Start of the cost interval (>=)
|
||||
MaxCost *float64 // End of the usage interval (<)
|
||||
FilterOnRated bool // Do not consider derived CDRs but original one
|
||||
Paginator // Add pagination
|
||||
}
|
||||
|
||||
@@ -942,11 +946,13 @@ func (self *RpcCdrsFilter) AsCdrsFilter() (*CdrsFilter, error) {
|
||||
NotExtraFields: self.NotExtraFields,
|
||||
OrderIdStart: self.OrderIdStart,
|
||||
OrderIdEnd: self.OrderIdEnd,
|
||||
UsageStart: self.UsageStart,
|
||||
UsageEnd: self.UsageEnd,
|
||||
CostStart: self.CostStart,
|
||||
CostEnd: self.CostEnd,
|
||||
FilterOnDerived: self.FilterOnDerived,
|
||||
MinUsage: self.MinUsage,
|
||||
MaxUsage: self.MaxUsage,
|
||||
MinPdd: self.MinPdd,
|
||||
MaxPdd: self.MaxPdd,
|
||||
MinCost: self.MinCost,
|
||||
MaxCost: self.MaxCost,
|
||||
FilterOnRated: self.FilterOnRated,
|
||||
Paginator: self.Paginator,
|
||||
}
|
||||
if len(self.SetupTimeStart) != 0 {
|
||||
|
||||
@@ -92,6 +92,7 @@ const (
|
||||
SETUP_TIME = "setup_time"
|
||||
ANSWER_TIME = "answer_time"
|
||||
USAGE = "usage"
|
||||
PDD = "pdd"
|
||||
SUPPLIER = "supplier"
|
||||
MEDI_RUNID = "mediation_runid"
|
||||
RATED_ACCOUNT = "rated_account"
|
||||
|
||||
Reference in New Issue
Block a user