diff --git a/agents/libdmt.go b/agents/libdmt.go index 510879f9e..ed5086d3c 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -85,7 +85,7 @@ func loadDictionaries(dictsDir, componentId string) error { } // Returns reqType, requestNr and ccTime in seconds -func disectUsageForCCR(usage time.Duration, debitInterval time.Duration, callEnded bool) (reqType, reqNr, ccTime int) { +func disectUsageForCCR(usage time.Duration, debitInterval time.Duration, callEnded bool) (reqType, reqNr, reqCCTime, usedCCTime int) { usageSecs := usage.Seconds() debitIntervalSecs := debitInterval.Seconds() reqType = 1 @@ -103,14 +103,23 @@ func disectUsageForCCR(usage time.Duration, debitInterval time.Duration, callEnd if callEnded { ccTimeFloat = math.Mod(usageSecs, debitIntervalSecs) } - return reqType, reqNr, int(ccTimeFloat) + if reqType == 1 { // Initial does not have usedCCTime + reqCCTime = int(ccTimeFloat) + } else if reqType == 2 { + reqCCTime = int(ccTimeFloat) + usedCCTime = int(math.Mod(usageSecs, debitIntervalSecs)) + } else if reqType == 3 { + usedCCTime = int(ccTimeFloat) // Termination does not have requestCCTime + } + return } -func usageFromCCR(reqType, reqNr, ccTime int, debitIterval time.Duration) time.Duration { +func usageFromCCR(reqType, reqNr, reqCCTime, usedCCTime int, debitIterval time.Duration) time.Duration { dISecs := debitIterval.Seconds() + var ccTime int if reqType == 3 { reqNr -= 1 // decrease request number to reach the real number - ccTime += int(dISecs) * reqNr + ccTime = usedCCTime + (int(dISecs) * reqNr) } else { ccTime = int(dISecs) } @@ -121,7 +130,7 @@ func usageFromCCR(reqType, reqNr, ccTime int, debitIterval time.Duration) time.D func storedCdrToCCR(cdr *engine.StoredCdr, originHost, originRealm string, vendorId int, productName string, firmwareRev int, debitInterval time.Duration, callEnded bool) *CCR { //sid := "session;" + strconv.Itoa(int(rand.Uint32())) - reqType, reqNr, ccTime := disectUsageForCCR(cdr.Usage, debitInterval, callEnded) + reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(cdr.Usage, debitInterval, callEnded) ccr := &CCR{SessionId: cdr.CgrId, OriginHost: originHost, OriginRealm: originRealm, DestinationHost: originHost, DestinationRealm: originRealm, AuthApplicationId: 4, ServiceContextId: cdr.ExtraFields["Service-Context-Id"], CCRequestType: reqType, CCRequestNumber: reqNr, EventTimestamp: cdr.AnswerTime, ServiceIdentifier: 0} @@ -131,7 +140,8 @@ func storedCdrToCCR(cdr *engine.StoredCdr, originHost, originRealm string, vendo }, 1) ccr.SubscriptionId[0].SubscriptionIdType = 0 ccr.SubscriptionId[0].SubscriptionIdData = cdr.Account - ccr.RequestedServiceUnit.CCTime = ccTime + ccr.RequestedServiceUnit.CCTime = reqCCTime + ccr.UsedServiceUnit.CCTime = usedCCTime ccr.ServiceInformation.INInformation.CallingPartyAddress = cdr.Account ccr.ServiceInformation.INInformation.CalledPartyAddress = cdr.Destination ccr.ServiceInformation.INInformation.RealCalledNumber = cdr.Destination @@ -176,6 +186,9 @@ type CCR struct { RequestedServiceUnit struct { CCTime int `avp:"CC-Time"` } `avp:"Requested-Service-Unit"` + UsedServiceUnit struct { + CCTime int `avp:"CC-Time"` + } `avp:"Used-Service-Unit"` ServiceInformation struct { INInformation struct { CallingPartyAddress string `avp:"Calling-Party-Address"` @@ -246,6 +259,11 @@ func (self *CCR) AsDiameterMessage() (*diam.Message, error) { diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(self.RequestedServiceUnit.CCTime))}}); err != nil { // CC-Time return nil, err } + if _, err := m.NewAVP("Used-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{ + AVP: []*diam.AVP{ + diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(self.UsedServiceUnit.CCTime))}}); err != nil { // CC-Time + return nil, err + } if _, err := m.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information @@ -286,7 +304,7 @@ func avpValAsString(a *diam.AVP) string { func (self *CCR) metaHandler(tag, arg string) (string, error) { switch tag { case META_CCR_USAGE: - usage := usageFromCCR(self.CCRequestType, self.CCRequestNumber, self.RequestedServiceUnit.CCTime, self.debitInterval) + usage := usageFromCCR(self.CCRequestType, self.CCRequestNumber, self.RequestedServiceUnit.CCTime, self.UsedServiceUnit.CCTime, self.debitInterval) return strconv.FormatFloat(usage.Seconds(), 'f', -1, 64), nil } return "", nil diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index dc57d4704..99a43a453 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -30,46 +30,46 @@ import ( ) func TestDisectUsageForCCR(t *testing.T) { - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(0)*time.Second, time.Duration(300)*time.Second, false); reqType != 1 || reqNr != 0 || ccTime != 300 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(0)*time.Second, time.Duration(300)*time.Second, false); reqType != 1 || reqNr != 0 || reqCCTime != 300 || usedCCTime != 0 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 0 || ccTime != 300 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 0 || reqCCTime != 300 || usedCCTime != 35 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 3 || ccTime != 300 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 3 || reqCCTime != 300 || usedCCTime != 35 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 1 || ccTime != 35 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 1 || reqCCTime != 0 || usedCCTime != 35 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(610)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 3 || ccTime != 10 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(610)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 3 || reqCCTime != 0 || usedCCTime != 10 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } - if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 4 || ccTime != 35 { - t.Error(reqType, reqNr, ccTime) + if reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 4 || reqCCTime != 0 || usedCCTime != 35 { + t.Error(reqType, reqNr, reqCCTime, usedCCTime) } } func TestUsageFromCCR(t *testing.T) { - if usage := usageFromCCR(1, 0, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(1, 0, 300, 0, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { t.Error(usage) } - if usage := usageFromCCR(2, 0, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(2, 0, 300, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { t.Error(usage) } - if usage := usageFromCCR(2, 3, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(2, 3, 300, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + t.Error(usage.Seconds()) + } + if usage := usageFromCCR(3, 3, 0, 10, time.Duration(300)*time.Second); usage != time.Duration(610)*time.Second { t.Error(usage) } - if usage := usageFromCCR(3, 3, 10, time.Duration(300)*time.Second); usage != time.Duration(610)*time.Second { + if usage := usageFromCCR(3, 4, 0, 35, time.Duration(300)*time.Second); usage != time.Duration(935)*time.Second { t.Error(usage) } - if usage := usageFromCCR(3, 4, 35, time.Duration(300)*time.Second); usage != time.Duration(935)*time.Second { + if usage := usageFromCCR(3, 1, 0, 35, time.Duration(300)*time.Second); usage != time.Duration(35)*time.Second { t.Error(usage) } - if usage := usageFromCCR(3, 1, 35, time.Duration(300)*time.Second); usage != time.Duration(35)*time.Second { - t.Error(usage) - } - if usage := usageFromCCR(1, 0, 360, time.Duration(360)*time.Second); usage != time.Duration(360)*time.Second { + if usage := usageFromCCR(1, 0, 360, 0, time.Duration(360)*time.Second); usage != time.Duration(360)*time.Second { t.Error(usage) } } diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 943ad7dd5..861b33768 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -204,7 +204,7 @@ func (self SMGenericEvent) GetOriginatorIP(fieldName string) string { } func (self SMGenericEvent) GetCdrSource() string { - return utils.SMG // Needs to match the one in the SMGEvent.saveOperations + return utils.SMG + "_" + self.GetName() } func (self SMGenericEvent) GetExtraFields() map[string]string { diff --git a/sessionmanager/smg_event_test.go b/sessionmanager/smg_event_test.go index 60f75ca24..055d3821a 100644 --- a/sessionmanager/smg_event_test.go +++ b/sessionmanager/smg_event_test.go @@ -148,7 +148,7 @@ func TestSMGenericEventAsStoredCdr(t *testing.T) { smGev["Extra1"] = "Value1" smGev["Extra2"] = 5 eStoredCdr := &engine.StoredCdr{CgrId: "0711eaa78e53937f1593dabc08c83ea04a915f2e", - TOR: utils.VOICE, AccId: "12345", CdrHost: "10.0.3.15", CdrSource: "SMG", ReqType: utils.META_PREPAID, + TOR: utils.VOICE, AccId: "12345", CdrHost: "10.0.3.15", CdrSource: "SMG_TEST_EVENT", ReqType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "account1", Subject: "subject1", Destination: "+4986517174963", SetupTime: time.Date(2015, 11, 9, 14, 21, 24, 0, time.UTC), AnswerTime: time.Date(2015, 11, 9, 14, 22, 2, 0, time.UTC), Usage: time.Duration(83) * time.Second, Pdd: time.Duration(300) * time.Millisecond, Supplier: "supplier1", DisconnectCause: "NORMAL_DISCONNECT", diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index c064afd8e..2ee36f58e 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -206,7 +206,7 @@ func (self *SMGSession) saveOperations() error { var reply string err := self.cdrsrv.LogCallCost(&engine.CallCostLog{ CgrId: self.eventStart.GetCgrId(self.timezone), - Source: utils.SMG, + Source: utils.SESSION_MANAGER_SOURCE, RunId: self.runId, CallCost: firstCC, CheckDuplicate: true,