mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Diameter UsedUnits support, smg_session saves callcost with SMR cost source
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user