mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Diameter integrating AttributeS/ResourceS/Suppliers/Threshold APIs, fixes #999
This commit is contained in:
@@ -133,7 +133,6 @@ func (da DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProce
|
||||
return false, ErrDiameterRatingFailed
|
||||
}
|
||||
}
|
||||
procVars[CGRResultCode] = strconv.Itoa(diam.Success)
|
||||
if reqProcessor.DryRun { // DryRun does not send over network
|
||||
utils.Logger.Info(fmt.Sprintf("<DiameterAgent> SMGenericEvent: %+v", smgEv))
|
||||
procVars[CGRResultCode] = strconv.Itoa(diam.LimitedSuccess)
|
||||
@@ -190,36 +189,11 @@ func (da DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProce
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Processing message: %+v, API error: %s", ccr.diamMessage, err))
|
||||
switch { // Prettify some errors
|
||||
case strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()):
|
||||
procVars[CGRError] = utils.ErrAccountNotFound.Error()
|
||||
case strings.HasSuffix(err.Error(), utils.ErrUserNotFound.Error()):
|
||||
procVars[CGRError] = utils.ErrUserNotFound.Error()
|
||||
case strings.HasSuffix(err.Error(), utils.ErrInsufficientCredit.Error()):
|
||||
procVars[CGRError] = utils.ErrInsufficientCredit.Error()
|
||||
case strings.HasSuffix(err.Error(), utils.ErrAccountDisabled.Error()):
|
||||
procVars[CGRError] = utils.ErrAccountDisabled.Error()
|
||||
case strings.HasSuffix(err.Error(), utils.ErrRatingPlanNotFound.Error()):
|
||||
procVars[CGRError] = utils.ErrRatingPlanNotFound.Error()
|
||||
case strings.HasSuffix(err.Error(), utils.ErrUnauthorizedDestination.Error()):
|
||||
procVars[CGRError] = utils.ErrUnauthorizedDestination.Error()
|
||||
default: // Unknown error
|
||||
procVars[CGRError] = err.Error()
|
||||
procVars[CGRResultCode] = strconv.Itoa(DiameterRatingFailed)
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*if prevMaxUsageStr, hasKey := procVars[CGRMaxUsage]; hasKey {
|
||||
prevMaxUsage, _ := utils.ParseDurationWithNanosecs(prevMaxUsageStr)
|
||||
if prevMaxUsage < maxUsage {
|
||||
maxUsage = prevMaxUsage
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
diamCode, _ := procVars.valAsString(CGRResultCode)
|
||||
diamCode := strconv.Itoa(diam.Success)
|
||||
if procVars.hasVar(CGRResultCode) {
|
||||
diamCode, _ = procVars.valAsString(CGRResultCode)
|
||||
}
|
||||
if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, diamCode,
|
||||
false, da.cgrCfg.DiameterAgentCfg().Timezone); err != nil {
|
||||
return false, err
|
||||
|
||||
@@ -207,14 +207,12 @@ func TestDmtAgentResetStorDb(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Start CGR Engine
|
||||
func TestDmtAgentStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(daCfgPath, 4000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestDmtAgentApierRpcConn(t *testing.T) {
|
||||
@@ -245,8 +243,8 @@ func TestDmtAgentConnectDiameterClient(t *testing.T) {
|
||||
|
||||
// cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"'
|
||||
func TestDmtAgentSendCCRInit(t *testing.T) {
|
||||
cdr := &engine.CDR{CGRID: utils.Sha1("testccr1",
|
||||
time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()),
|
||||
cdr := &engine.CDR{
|
||||
CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()),
|
||||
OrderID: 123, ToR: utils.VOICE, OriginID: "testccr1", OriginHost: "192.168.1.1",
|
||||
Source: utils.UNIT_TEST, RequestType: utils.META_RATED,
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001",
|
||||
@@ -259,7 +257,8 @@ func TestDmtAgentSendCCRInit(t *testing.T) {
|
||||
ccr := storedCdrToCCR(cdr, "UNIT_TEST",
|
||||
daCfg.DiameterAgentCfg().OriginRealm,
|
||||
daCfg.DiameterAgentCfg().VendorId,
|
||||
daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION,
|
||||
daCfg.DiameterAgentCfg().ProductName,
|
||||
utils.DIAMETER_FIRMWARE_REVISION,
|
||||
daCfg.DiameterAgentCfg().DebitInterval, false)
|
||||
m, err := ccr.AsDiameterMessage()
|
||||
if err != nil {
|
||||
@@ -366,14 +365,23 @@ func TestDmtAgentSendCCRUpdate2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDmtAgentSendCCRTerminate(t *testing.T) {
|
||||
cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE,
|
||||
OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED,
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004",
|
||||
SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(610) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"},
|
||||
cdr := &engine.CDR{
|
||||
CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()),
|
||||
OrderID: 123, ToR: utils.VOICE,
|
||||
OriginID: "testccr1", OriginHost: "192.168.1.1",
|
||||
Source: utils.UNIT_TEST, RequestType: utils.META_RATED,
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001",
|
||||
Subject: "1001", Destination: "1004",
|
||||
SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
RunID: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(610) * time.Second,
|
||||
ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"},
|
||||
}
|
||||
ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId,
|
||||
daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, true)
|
||||
ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm,
|
||||
daCfg.DiameterAgentCfg().VendorId,
|
||||
daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION,
|
||||
daCfg.DiameterAgentCfg().DebitInterval, true)
|
||||
m, err := ccr.AsDiameterMessage()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -386,20 +394,14 @@ func TestDmtAgentSendCCRTerminate(t *testing.T) {
|
||||
if msg == nil {
|
||||
t.Fatal("No answer to CCR terminate received")
|
||||
}
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Granted-Service-Unit not found")
|
||||
} else if strCCTime := avpValAsString(avps[0]); strCCTime != "0" {
|
||||
t.Errorf("Expecting 0, received: %s", strCCTime)
|
||||
}
|
||||
var acnt *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
eAcntVal := 9.243500
|
||||
if err := apierRpc.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if acnt.BalanceMap[utils.MONETARY].GetTotalValue() != eAcntVal { // Should also consider derived charges which double the cost of 6m10s - 2x0.7584
|
||||
t.Errorf("Expected: %v, received: %v", eAcntVal, acnt.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
t.Errorf("Expected: %v, received: %v",
|
||||
eAcntVal, acnt.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,12 +279,18 @@ func passesFieldFilter(m *diam.Message, fieldFilter *utils.RSRField, procVars pr
|
||||
if fieldFilter == nil {
|
||||
return true, 0
|
||||
}
|
||||
if val, hasIt := procVars[fieldFilter.Id]; hasIt { // ProcessorVars have priority
|
||||
valStr, _ := utils.CastFieldIfToString(val)
|
||||
if fieldFilter.FilterPasses(valStr) {
|
||||
return true, 0
|
||||
// check procVars before AVPs
|
||||
if val, err := procVars.valAsString(fieldFilter.Id); err != utils.ErrNotFoundNoCaps {
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<RSRFilter> parsing value: <%s> as string, error: <%s>",
|
||||
fieldFilter.Id, err.Error()))
|
||||
return false, 0
|
||||
}
|
||||
return false, 0
|
||||
if !fieldFilter.FilterPasses(val) {
|
||||
return false, 0
|
||||
}
|
||||
return true, 0
|
||||
}
|
||||
avps, err := avpsWithPath(m, fieldFilter)
|
||||
if err != nil {
|
||||
@@ -303,36 +309,52 @@ func passesFieldFilter(m *diam.Message, fieldFilter *utils.RSRField, procVars pr
|
||||
return false, 0
|
||||
}
|
||||
|
||||
func composedFieldvalue(m *diam.Message, outTpl utils.RSRFields, avpIdx int, procVars processorVars) string {
|
||||
var outVal string
|
||||
func composedFieldvalue(m *diam.Message, outTpl utils.RSRFields, avpIdx int, procVars processorVars) (outVal string) {
|
||||
var err error
|
||||
for _, rsrTpl := range outTpl {
|
||||
if rsrTpl.IsStatic() {
|
||||
outVal += rsrTpl.ParseValue("")
|
||||
} else {
|
||||
if val, hasIt := procVars[rsrTpl.Id]; hasIt { // ProcessorVars have priority
|
||||
valStr, _ := utils.CastFieldIfToString(val)
|
||||
outVal += rsrTpl.ParseValue(valStr)
|
||||
continue
|
||||
}
|
||||
matchingAvps, err := avpsWithPath(m, rsrTpl)
|
||||
if err != nil || len(matchingAvps) == 0 {
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Error matching AVPS: %s", err.Error()))
|
||||
var valToParse string
|
||||
if !rsrTpl.IsStatic() { // for Static we will parse empty valToParse bellow
|
||||
// check procVars before AVPs
|
||||
if valToParse, err = procVars.valAsString(rsrTpl.Id); err != nil {
|
||||
if err != utils.ErrNotFoundNoCaps {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s", utils.DiameterAgent, err.Error()))
|
||||
continue
|
||||
}
|
||||
continue
|
||||
// not found in processorVars, look in AVPs
|
||||
// AVPs from here
|
||||
matchingAvps, err := avpsWithPath(m, rsrTpl)
|
||||
if err != nil || len(matchingAvps) == 0 {
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error matching AVPS: %s",
|
||||
utils.DiameterAgent, err.Error()))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(matchingAvps) <= avpIdx {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> Cannot retrieve AVP with index %d for field template with id: %s",
|
||||
utils.DiameterAgent, avpIdx, rsrTpl.Id))
|
||||
continue // Not convertible, ignore
|
||||
}
|
||||
if matchingAvps[0].Data.Type() == diam.GroupedAVPType {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> Value for field template with id: %s is matching a group AVP, ignoring.",
|
||||
utils.DiameterAgent, rsrTpl.Id))
|
||||
continue // Not convertible, ignore
|
||||
}
|
||||
valToParse = avpValAsString(matchingAvps[avpIdx])
|
||||
}
|
||||
if len(matchingAvps) <= avpIdx {
|
||||
utils.Logger.Warning(fmt.Sprintf("<Diameter> Cannot retrieve AVP with index %d for field template with id: %s", avpIdx, rsrTpl.Id))
|
||||
continue // Not convertible, ignore
|
||||
}
|
||||
if matchingAvps[0].Data.Type() == diam.GroupedAVPType {
|
||||
utils.Logger.Warning(fmt.Sprintf("<Diameter> Value for field template with id: %s is matching a group AVP, ignoring.", rsrTpl.Id))
|
||||
continue // Not convertible, ignore
|
||||
}
|
||||
outVal += rsrTpl.ParseValue(avpValAsString(matchingAvps[avpIdx]))
|
||||
}
|
||||
if parsed, err := rsrTpl.Parse(valToParse); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s",
|
||||
utils.DiameterAgent, err.Error()))
|
||||
} else {
|
||||
outVal += parsed
|
||||
}
|
||||
}
|
||||
return outVal
|
||||
return
|
||||
}
|
||||
|
||||
// Used to return the encoded value based on what AVP understands for it's type
|
||||
|
||||
@@ -76,7 +76,7 @@ func (pv processorVars) valAsString(fldPath string) (val string, err error) {
|
||||
fldName = utils.MetaCGRReply
|
||||
}
|
||||
if !pv.hasVar(fldName) {
|
||||
return "", errors.New("not found")
|
||||
return "", utils.ErrNotFoundNoCaps
|
||||
}
|
||||
if fldName == utils.MetaCGRReply {
|
||||
cgrRply := pv[utils.MetaCGRReply].(utils.CGRReply)
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*constant", "value": "2048"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
{"tag": "ResultCode", "field_filter": "*cgrReply>MaxUsage(^0$)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -49,8 +49,8 @@
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
{"tag": "ResultCode", "field_filter": "*cgrReply>MaxUsage(^0$)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -76,8 +76,8 @@
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
{"tag": "ResultCode", "field_filter": "*cgrReply>MaxUsage(^0$)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -100,9 +100,6 @@
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "type": "*handler", "handler_id": "*sum",
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "Requested-Service-Unit>CC-Time", "mandatory": true},
|
||||
],
|
||||
"cca_fields":[
|
||||
{"tag": "ResultCode", "field_filter":"CGRError(ACCOUNT_NOT_FOUND)",
|
||||
{"tag": "ResultCode", "field_filter":"*cgrReply>Error(ACCOUNT_NOT_FOUND)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030"},
|
||||
{"tag": "ResultCode", "field_filter":"CGRError(USER_NOT_FOUND)",
|
||||
{"tag": "ResultCode", "field_filter":"*cgrReply>Error(USER_NOT_FOUND)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030"},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -25,14 +25,13 @@
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
"cca_fields":[
|
||||
{"tag": "ResultCode", "field_filter":"CGRError(ACCOUNT_NOT_FOUND)",
|
||||
{"tag": "ResultCode", "field_filter":"*cgrReply>Error(ACCOUNT_NOT_FOUND)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030"},
|
||||
{"tag": "ResultCode", "field_filter":"CGRError(USER_NOT_FOUND)",
|
||||
{"tag": "ResultCode", "field_filter":"*cgrReply>Error(USER_NOT_FOUND)",
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030"},
|
||||
{"tag": "GrantedUnits", "field_filter":"CGRError(^$)",
|
||||
"field_id": "Granted-Service-Unit>CC-Time",
|
||||
"type": "*handler", "handler_id": "*value_exponent",
|
||||
"value": "CGRMaxUsage;^|-9", "mandatory": true},
|
||||
{"tag": "GrantedUnits", "field_filter":"*cgrReply>Error(^$)",
|
||||
"field_id": "Granted-Service-Unit>CC-Time", "type": "*composed",
|
||||
"value": "*cgrReply>MaxUsage{*duration_seconds}", "mandatory": true},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -56,10 +55,9 @@
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
"cca_fields":[ // fields returned in CCA
|
||||
{"tag": "GrantedUnits", "field_filter":"CGRError(^$)",
|
||||
"field_id": "Granted-Service-Unit>CC-Time",
|
||||
"type": "*handler", "handler_id": "*value_exponent",
|
||||
"value": "CGRMaxUsage;^|-9", "mandatory": true},
|
||||
{"tag": "GrantedUnits", "field_filter":"*cgrReply>Error(^$)",
|
||||
"field_id": "Granted-Service-Unit>CC-Time", "type": "*composed",
|
||||
"value": "*cgrReply>MaxUsage{*duration_seconds}", "mandatory": true},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -82,12 +80,6 @@
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*ccr_usage", "mandatory": true},
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
"cca_fields":[ // fields returned in CCA
|
||||
{"tag": "GrantedUnits", "field_filter":"CGRError(^$)",
|
||||
"field_id": "Granted-Service-Unit>CC-Time",
|
||||
"type": "*handler", "handler_id": "*value_exponent",
|
||||
"value": "CGRMaxUsage;^|-9", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1348,6 +1348,7 @@ func (v1AuthReply *V1AuthorizeReply) AsCGRReply() (cgrReply utils.CGRReply, err
|
||||
if v1AuthReply.ThresholdHits != nil {
|
||||
cgrReply[utils.CapThresholdHits] = *v1AuthReply.ThresholdHits
|
||||
}
|
||||
cgrReply[utils.Error] = "" // so we can compare in filters
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1545,6 +1546,7 @@ func (v1Rply *V1InitSessionReply) AsCGRReply() (cgrReply utils.CGRReply, err err
|
||||
if v1Rply.ThresholdHits != nil {
|
||||
cgrReply[utils.CapThresholdHits] = *v1Rply.ThresholdHits
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1705,6 +1707,7 @@ func (v1Rply *V1UpdateSessionReply) AsCGRReply() (cgrReply utils.CGRReply, err e
|
||||
if v1Rply.MaxUsage != nil {
|
||||
cgrReply[utils.CapMaxUsage] = *v1Rply.MaxUsage
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1874,6 +1877,7 @@ func (v1Rply *V1ProcessEventReply) AsCGRReply() (cgrReply utils.CGRReply, err er
|
||||
}
|
||||
cgrReply[utils.CapAttributes] = attrs
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ var (
|
||||
ErrPartiallyExecuted = errors.New("PARTIALLY_EXECUTED")
|
||||
ErrMaxUsageExceeded = errors.New("MAX_USAGE_EXCEEDED")
|
||||
ErrUnallocatedResource = errors.New("UNALLOCATED_RESOURCE")
|
||||
ErrNotFoundNoCaps = errors.New("not found")
|
||||
)
|
||||
|
||||
// NewCGRError initialises a new CGRError
|
||||
|
||||
Reference in New Issue
Block a user