diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 92857c141..b63c6f31f 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -1441,7 +1441,7 @@ func TestLocalGetCdrs(t *testing.T) { if !*testLocal { return } - var reply []*engine.CgrExtCdr + var reply []*engine.ExternalCdr req := utils.AttrGetCdrs{} if err := rater.Call("ApierV1.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -1465,7 +1465,7 @@ func TestLocalProcessCdr(t *testing.T) { } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.CgrExtCdr + var cdrs []*engine.ExternalCdr req := utils.AttrGetCdrs{} if err := rater.Call("ApierV1.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) diff --git a/apier/v1/cdrs.go b/apier/v1/cdrs.go index e3f3c98d1..4b903831b 100644 --- a/apier/v1/cdrs.go +++ b/apier/v1/cdrs.go @@ -46,7 +46,7 @@ func (apier *ApierV1) GetCallCostLog(attrs AttrGetCallCost, reply *engine.CallCo } // Retrieves CDRs based on the filters -func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*engine.CgrExtCdr) error { +func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*engine.ExternalCdr) error { cdrsFltr, err := attrs.AsCdrsFilter() if err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) @@ -54,10 +54,10 @@ func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*engine.CgrExtCd if cdrs, _, err := apier.CdrDb.GetStoredCdrs(cdrsFltr); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if len(cdrs) == 0 { - *reply = make([]*engine.CgrExtCdr, 0) + *reply = make([]*engine.ExternalCdr, 0) } else { for _, cdr := range cdrs { - *reply = append(*reply, cdr.AsCgrExtCdr()) + *reply = append(*reply, cdr.AsExternalCdr()) } } return nil diff --git a/apier/v1/cdrsv1.go b/apier/v1/cdrsv1.go index 361e4072d..657edcd98 100644 --- a/apier/v1/cdrsv1.go +++ b/apier/v1/cdrsv1.go @@ -30,12 +30,17 @@ type CDRSV1 struct { } func (cdrsrv *CDRSV1) ProcessCdr(cdr *engine.StoredCdr, reply *string) error { - if cdrsrv.CdrSrv == nil { - return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, "CDRS_NOT_RUNNING") - } if err := cdrsrv.CdrSrv.ProcessCdr(cdr); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } *reply = utils.OK return nil } + +func (cdrsrv *CDRSV1) ProcessExternalCdr(cdr *engine.ExternalCdr, reply *string) error { + if err := cdrsrv.CdrSrv.ProcessExternalCdr(cdr); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + *reply = utils.OK + return nil +} diff --git a/apier/v2/cdrs.go b/apier/v2/cdrs.go index 253365ac2..3f433d460 100644 --- a/apier/v2/cdrs.go +++ b/apier/v2/cdrs.go @@ -27,7 +27,7 @@ import ( ) // Retrieves CDRs based on the filters -func (apier *ApierV2) GetCdrs(attrs utils.RpcCdrsFilter, reply *[]*engine.CgrExtCdr) error { +func (apier *ApierV2) GetCdrs(attrs utils.RpcCdrsFilter, reply *[]*engine.ExternalCdr) error { cdrsFltr, err := attrs.AsCdrsFilter() if err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) @@ -35,10 +35,10 @@ func (apier *ApierV2) GetCdrs(attrs utils.RpcCdrsFilter, reply *[]*engine.CgrExt if cdrs, _, err := apier.CdrDb.GetStoredCdrs(cdrsFltr); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if len(cdrs) == 0 { - *reply = make([]*engine.CgrExtCdr, 0) + *reply = make([]*engine.ExternalCdr, 0) } else { for _, cdr := range cdrs { - *reply = append(*reply, cdr.AsCgrExtCdr()) + *reply = append(*reply, cdr.AsExternalCdr()) } } return nil diff --git a/apier/v2/cdrs_mysql_local_test.go b/apier/v2/cdrs_mysql_local_test.go index d39c5d665..881440742 100644 --- a/apier/v2/cdrs_mysql_local_test.go +++ b/apier/v2/cdrs_mysql_local_test.go @@ -155,7 +155,7 @@ func TestV2CdrsMysqlGetCdrs(t *testing.T) { if !*testLocal { return } - var reply []*engine.CgrExtCdr + var reply []*engine.ExternalCdr req := utils.RpcCdrsFilter{} if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) diff --git a/apier/v2/cdrs_psql_local_test.go b/apier/v2/cdrs_psql_local_test.go index 500d316d6..1ba90d138 100644 --- a/apier/v2/cdrs_psql_local_test.go +++ b/apier/v2/cdrs_psql_local_test.go @@ -149,7 +149,7 @@ func TestV2CdrsPsqlGetCdrs(t *testing.T) { if !*testLocal { return } - var reply []*engine.CgrExtCdr + var reply []*engine.ExternalCdr req := utils.RpcCdrsFilter{} if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) diff --git a/engine/cdrs.go b/engine/cdrs.go index b4a6142d6..4cabb0987 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -137,3 +137,12 @@ func (cdrs *CDRS) RegisterHanlersToServer(server *Server) { func (cdrs *CDRS) ProcessCdr(cdr *StoredCdr) error { return storeAndMediate(cdr) } + +// Used to process external CDR +func (cdrs *CDRS) ProcessExternalCdr(cdr *ExternalCdr) error { + storedCdr, err := NewStoredCdrFromExternalCdr(cdr) + if err != nil { + return err + } + return storeAndMediate(storedCdr) +} diff --git a/engine/cdrs_local_test.go b/engine/cdrs_local_test.go index b407ea0ef..564e6c27b 100644 --- a/engine/cdrs_local_test.go +++ b/engine/cdrs_local_test.go @@ -102,7 +102,7 @@ func TestCdrsHttpJsonRpcCdrReplication(t *testing.T) { } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var rcvedCdrs []*CgrExtCdr + var rcvedCdrs []*ExternalCdr if err := cdrsHttpJsonRpc.Call("ApierV2.GetCdrs", utils.RpcCdrsFilter{CgrIds: []string{testCdr1.CgrId}}, &rcvedCdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(rcvedCdrs) != 1 { diff --git a/engine/storedcdr.go b/engine/storedcdr.go index 989c06ff5..a5923660c 100644 --- a/engine/storedcdr.go +++ b/engine/storedcdr.go @@ -31,6 +31,28 @@ import ( "github.com/cgrates/cgrates/utils" ) +func NewStoredCdrFromExternalCdr(extCdr *ExternalCdr) (*StoredCdr, error) { + var err error + storedCdr := &StoredCdr{CgrId: extCdr.CgrId, OrderId: extCdr.OrderId, TOR: extCdr.TOR, AccId: extCdr.AccId, CdrHost: extCdr.CdrHost, CdrSource: extCdr.CdrSource, ReqType: extCdr.ReqType, + Direction: extCdr.Direction, Tenant: extCdr.Tenant, Category: extCdr.Category, Account: extCdr.Account, Subject: extCdr.Subject, Destination: extCdr.Destination, + ExtraFields: extCdr.ExtraFields, MediationRunId: extCdr.MediationRunId, RatedAccount: extCdr.RatedAccount, RatedSubject: extCdr.RatedSubject, Cost: extCdr.Cost, Rated: extCdr.Rated} + if storedCdr.SetupTime, err = utils.ParseTimeDetectLayout(extCdr.SetupTime); err != nil { + return nil, err + } + if storedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(extCdr.AnswerTime); err != nil { + return nil, err + } + if storedCdr.Usage, err = utils.ParseDurationWithSecs(extCdr.Usage); err != nil { + return nil, err + } + if len(extCdr.CostDetails) != 0 { + if err = json.Unmarshal([]byte(extCdr.CostDetails), storedCdr.CostDetails); err != nil { + return nil, err + } + } + return storedCdr, nil +} + // Kinda standard of internal CDR, complies to CDR interface also type StoredCdr struct { CgrId string @@ -321,8 +343,8 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena return frkStorCdr, nil } -func (storedCdr *StoredCdr) AsCgrExtCdr() *CgrExtCdr { - return &CgrExtCdr{CgrId: storedCdr.CgrId, +func (storedCdr *StoredCdr) AsExternalCdr() *ExternalCdr { + return &ExternalCdr{CgrId: storedCdr.CgrId, OrderId: storedCdr.OrderId, TOR: storedCdr.TOR, AccId: storedCdr.AccId, @@ -498,7 +520,7 @@ func (storedCdr *StoredCdr) String() string { return string(mrsh) } -type CgrExtCdr struct { +type ExternalCdr struct { CgrId string OrderId int64 TOR string @@ -521,4 +543,5 @@ type CgrExtCdr struct { RatedSubject string Cost float64 CostDetails string + Rated bool // Mark the CDR as rated so we do not process it during mediation } diff --git a/engine/storedcdr_local_test.go b/engine/storedcdr_local_test.go index 67726af4e..0f7cdffed 100644 --- a/engine/storedcdr_local_test.go +++ b/engine/storedcdr_local_test.go @@ -34,7 +34,7 @@ func TestHttpJsonPost(t *testing.T) { if !*testLocal { return } - cdrOut := &CgrExtCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", + cdrOut := &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: "account1", Subject: "tgooiscs0014", Destination: "1002", diff --git a/engine/storedcdr_test.go b/engine/storedcdr_test.go index b7967acb5..b1bc46c62 100644 --- a/engine/storedcdr_test.go +++ b/engine/storedcdr_test.go @@ -31,6 +31,26 @@ func TestStoredCdrInterfaces(t *testing.T) { var _ Event = storedCdr } +func TestNewStoredCdrFromExternalCdr(t *testing.T) { + extCdr := &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", 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", + 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, + } + if storedCdr, err := NewStoredCdrFromExternalCdr(extCdr); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eStorCdr, storedCdr) { + t.Errorf("Expected: %+v, received: %+v", eStorCdr, storedCdr) + } +} + func TestFieldAsString(t *testing.T) { cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", @@ -397,20 +417,20 @@ func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) { } } -func TestStoredCdrAsCgrExtCdr(t *testing.T) { +func TestStoredCdrAsExternalCdr(t *testing.T) { storCdr := 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", 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", } - expectOutCdr := &CgrExtCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, + 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", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", } - if cdrOut := storCdr.AsCgrExtCdr(); !reflect.DeepEqual(expectOutCdr, cdrOut) { + if cdrOut := storCdr.AsExternalCdr(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) } } diff --git a/general_tests/tutorial_fs_calls_test.go b/general_tests/tutorial_fs_calls_test.go index 3c920bd85..4c8da0b63 100644 --- a/general_tests/tutorial_fs_calls_test.go +++ b/general_tests/tutorial_fs_calls_test.go @@ -163,7 +163,7 @@ func TestTutFsCallsCdrs1001(t *testing.T) { if !*testCalls { return } - var reply []*engine.CgrExtCdr + var reply []*engine.ExternalCdr req := utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error())