diff --git a/data/tariffplans/tutorial/Users.csv b/data/tariffplans/tutorial/Users.csv index d9e8d855c..357d629a4 100644 --- a/data/tariffplans/tutorial/Users.csv +++ b/data/tariffplans/tutorial/Users.csv @@ -5,8 +5,15 @@ cgrates.org,1001,Cli,+4986517174963 cgrates.org,1001,Account,1001 cgrates.org,1001,Subject,1001 cgrates.org,1001,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e +cgrates.org,1001,ReqType,*prepaid cgrates.org,1002,SysUserName,rif cgrates.org,1002,RifAttr,RifVal cgrates.org,1002,Account,1002 cgrates.org,1002,Subject,1002 cgrates.org,1002,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5 +cgrates.org,1004,SysUserName,danb4 +cgrates.org,1004,SysPassword,hisPass321 +cgrates.org,1004,Cli,+4986517174964 +cgrates.org,1004,Account,1004 +cgrates.org,1004,Subject,1004 +cgrates.org,1004,ReqType,*rated diff --git a/engine/cdrs.go b/engine/cdrs.go index 1bebe26ff..4525d86f1 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -148,9 +148,22 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT // Returns error if not able to properly store the CDR, mediation is async since we can always recover offline func (self *CdrServer) processCdr(storedCdr *StoredCdr) (err error) { + if storedCdr.Direction == "" { + storedCdr.Direction = utils.OUT + } + if storedCdr.ReqType == "" { + storedCdr.ReqType = self.cgrCfg.DefaultReqType + } + if storedCdr.Tenant == "" { + storedCdr.Tenant = self.cgrCfg.DefaultTenant + } + if storedCdr.Category == "" { + storedCdr.Category = self.cgrCfg.DefaultCategory + } if storedCdr.Subject == "" { // Use account information as rating subject if missing storedCdr.Subject = storedCdr.Account } + if upData, err := LoadUserProfile(storedCdr, "ExtraFields"); err != nil { return err } else { diff --git a/engine/fscdr.go b/engine/fscdr.go index 7952220c5..befb4a7cb 100644 --- a/engine/fscdr.go +++ b/engine/fscdr.go @@ -33,13 +33,7 @@ const ( // Freswitch event property names FS_CDR_MAP = "variables" FS_DIRECTION = "direction" - FS_SUBJECT = "cgr_subject" - FS_ACCOUNT = "cgr_account" - FS_DESTINATION = "cgr_destination" - FS_REQTYPE = "cgr_reqtype" //prepaid or postpaid - FS_CATEGORY = "cgr_category" FS_UUID = "uuid" // -Unique ID for this call leg - FS_CSTMID = "cgr_tenant" FS_CALL_DEST_NR = "dialed_extension" FS_PARK_TIME = "start_epoch" FS_SETUP_TIME = "start_epoch" @@ -125,20 +119,19 @@ func (fsCdr FSCdr) searchExtraField(field string, body map[string]interface{}) ( } func (fsCdr FSCdr) AsStoredCdr(timezone string) *StoredCdr { - storCdr := new(StoredCdr) storCdr.CgrId = fsCdr.getCgrId(timezone) storCdr.TOR = utils.VOICE storCdr.AccId = fsCdr.vars[FS_UUID] storCdr.CdrHost = fsCdr.vars[FS_IP] storCdr.CdrSource = FS_CDR_SOURCE - storCdr.ReqType = utils.FirstNonEmpty(fsCdr.vars[FS_REQTYPE], fsCdr.cgrCfg.DefaultReqType) + storCdr.ReqType = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_REQTYPE], fsCdr.cgrCfg.DefaultReqType) storCdr.Direction = "*out" - storCdr.Tenant = utils.FirstNonEmpty(fsCdr.vars[FS_CSTMID], fsCdr.cgrCfg.DefaultTenant) - storCdr.Category = utils.FirstNonEmpty(fsCdr.vars[FS_CATEGORY], fsCdr.cgrCfg.DefaultCategory) - storCdr.Account = utils.FirstNonEmpty(fsCdr.vars[FS_ACCOUNT], fsCdr.vars[FS_USERNAME]) - storCdr.Subject = utils.FirstNonEmpty(fsCdr.vars[FS_SUBJECT], fsCdr.vars[FS_USERNAME]) - storCdr.Destination = utils.FirstNonEmpty(fsCdr.vars[FS_DESTINATION], fsCdr.vars[FS_CALL_DEST_NR], fsCdr.vars[FS_SIP_REQUSER]) + storCdr.Tenant = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_TENANT], fsCdr.cgrCfg.DefaultTenant) + storCdr.Category = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_CATEGORY], fsCdr.cgrCfg.DefaultCategory) + storCdr.Account = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_ACCOUNT], fsCdr.vars[FS_USERNAME]) + storCdr.Subject = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_SUBJECT], fsCdr.vars[utils.CGR_ACCOUNT], fsCdr.vars[FS_USERNAME]) + storCdr.Destination = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_DESTINATION], fsCdr.vars[FS_CALL_DEST_NR], fsCdr.vars[FS_SIP_REQUSER]) storCdr.SetupTime, _ = utils.ParseTimeDetectLayout(fsCdr.vars[FS_SETUP_TIME], timezone) // Not interested to process errors, should do them if necessary in a previous step pddStr := utils.FirstNonEmpty(fsCdr.vars[FS_PROGRESS_MEDIAMSEC], fsCdr.vars[FS_PROGRESSMS]) pddStr = pddStr + "ms" diff --git a/general_tests/tutorial_local_test.go b/general_tests/tutorial_local_test.go index 132ecbda2..fc770cfd0 100644 --- a/general_tests/tutorial_local_test.go +++ b/general_tests/tutorial_local_test.go @@ -118,7 +118,7 @@ func TestTutLocalCacheStats(t *testing.T) { var rcvStats *utils.CacheStats expectedStats := &utils.CacheStats{Destinations: 4, RatingPlans: 3, RatingProfiles: 8, Actions: 7, SharedGroups: 1, Aliases: 3, - DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 2} + DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3} var args utils.AttrCacheStats if err := tutLocalRpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) @@ -190,7 +190,7 @@ func TestTutLocalGetUsers(t *testing.T) { var users engine.UserProfiles if err := tutLocalRpc.Call("UsersV1.GetUsers", engine.UserProfile{}, &users); err != nil { t.Error("Got error on UsersV1.GetUsers: ", err.Error()) - } else if len(users) != 2 { + } else if len(users) != 3 { t.Error("Calling UsersV1.GetUsers got users:", len(users)) } } @@ -554,6 +554,45 @@ func TestTutLocalProcessExternalCdr(t *testing.T) { } } +// Test CDR from external sources +func TestTutLocalProcessExternalCdrUP(t *testing.T) { + if !*testLocal { + return + } + cdr := &engine.ExternalCdr{TOR: utils.VOICE, + AccId: "testextcdr2", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, Direction: utils.OUT, + ReqType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", Supplier: "SUPPL1", + SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", + Usage: "2", Pdd: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": utils.USERS}, + } + var reply string + if err := tutLocalRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + eCdr := &engine.ExternalCdr{CgrId: "63a8d2bfeca2cfb790826c3ec461696d6574cfde", OrderId: 2, + TOR: utils.VOICE, + AccId: "testextcdr2", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", Supplier: "SUPPL1", + SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), + Usage: "2", Pdd: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": "danb4"}, + MediationRunId: utils.DEFAULT_RUNID, Cost: 1} + var cdrs []*engine.ExternalCdr + req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1004"}, DestPrefixes: []string{"1001"}} + if err := tutLocalRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if !reflect.DeepEqual(eCdr, cdrs[0]) { + t.Errorf("Expecting: %+v, received: %+v", eCdr, cdrs[0]) + } + } +} + // Make sure queueids were created func TestTutFsCallsCdrStats(t *testing.T) { if !*testLocal {