mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-17 06:09:53 +05:00
SessionS - properly charge terminate without initiate event
This commit is contained in:
committed by
Dan Christian Bogos
parent
29d5e5d2b9
commit
19f30a418d
@@ -56,7 +56,8 @@ cgrates (0.10.1) UNRELEASED; urgency=medium
|
||||
* [SessionS] Use correctly SessionTTLUsage when calculate end usage in case of terminate session from ttl mechanism
|
||||
* [SessionS] Add SessionTLLLastUsage as option for an extra debit in case of ttl mechanism
|
||||
* [Templates] Added new dataconverter: *string2hex
|
||||
|
||||
* [SessionS] Properly charge terminate without initiate event
|
||||
|
||||
-- DanB <danb@cgrates.org> Wed, 5 May 2020 15:22:59 +0200
|
||||
|
||||
cgrates (0.10.0) UNRELEASED; urgency=medium
|
||||
|
||||
@@ -1420,17 +1420,17 @@ func (sS *SessionS) updateSession(s *Session, updtEv engine.MapEvent, isMsg, for
|
||||
}
|
||||
var maxUsageSet bool // so we know if we have set the 0 on purpose
|
||||
for i, sr := range s.SRuns {
|
||||
reqType := sr.Event.GetStringIgnoreErrors(utils.RequestType)
|
||||
if reqType == utils.META_NONE {
|
||||
continue
|
||||
}
|
||||
var rplyMaxUsage time.Duration
|
||||
if !authReqs.HasField(
|
||||
sr.Event.GetStringIgnoreErrors(utils.RequestType)) {
|
||||
if reqType != utils.META_PREPAID || s.debitStop != nil {
|
||||
rplyMaxUsage = reqMaxUsage
|
||||
} else if rplyMaxUsage, err = sS.debitSession(s, i, reqMaxUsage,
|
||||
updtEv.GetDurationPtrIgnoreErrors(utils.LastUsed)); err != nil {
|
||||
return
|
||||
}
|
||||
if rplyMaxUsage > reqMaxUsage {
|
||||
rplyMaxUsage = reqMaxUsage
|
||||
}
|
||||
if !maxUsageSet || rplyMaxUsage < maxUsage {
|
||||
maxUsage = rplyMaxUsage
|
||||
maxUsageSet = true
|
||||
@@ -1472,35 +1472,37 @@ func (sS *SessionS) endSession(s *Session, tUsage, lastUsage *time.Duration,
|
||||
sUsage = sr.TotalUsage
|
||||
}
|
||||
if sr.EventCost != nil {
|
||||
if notCharged := sUsage - sr.EventCost.GetUsage(); notCharged > 0 { // we did not charge enough, make a manual debit here
|
||||
if sr.CD.LoopIndex > 0 {
|
||||
sr.CD.TimeStart = sr.CD.TimeEnd
|
||||
if !isMsg { // in case of one time charge there is no need of corrections
|
||||
if notCharged := sUsage - sr.EventCost.GetUsage(); notCharged > 0 { // we did not charge enough, make a manual debit here
|
||||
if sr.CD.LoopIndex > 0 {
|
||||
sr.CD.TimeStart = sr.CD.TimeEnd
|
||||
}
|
||||
sr.CD.TimeEnd = sr.CD.TimeStart.Add(notCharged)
|
||||
sr.CD.DurationIndex += notCharged
|
||||
cc := new(engine.CallCost)
|
||||
if err = sS.connMgr.Call(sS.cgrCfg.SessionSCfg().RALsConns, nil, utils.ResponderDebit,
|
||||
&engine.CallDescriptorWithArgDispatcher{
|
||||
CallDescriptor: sr.CD,
|
||||
ArgDispatcher: s.ArgDispatcher}, cc); err == nil {
|
||||
sr.EventCost.Merge(
|
||||
engine.NewEventCostFromCallCost(cc, s.CGRID,
|
||||
sr.Event.GetStringIgnoreErrors(utils.RunID)))
|
||||
}
|
||||
} else if notCharged < 0 { // charged too much, try refund
|
||||
if err = sS.refundSession(s, sRunIdx, -notCharged); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf(
|
||||
"<%s> failed refunding session: <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
}
|
||||
sr.CD.TimeEnd = sr.CD.TimeStart.Add(notCharged)
|
||||
sr.CD.DurationIndex += notCharged
|
||||
cc := new(engine.CallCost)
|
||||
if err = sS.connMgr.Call(sS.cgrCfg.SessionSCfg().RALsConns, nil, utils.ResponderDebit,
|
||||
&engine.CallDescriptorWithArgDispatcher{
|
||||
CallDescriptor: sr.CD,
|
||||
ArgDispatcher: s.ArgDispatcher}, cc); err == nil {
|
||||
sr.EventCost.Merge(
|
||||
engine.NewEventCostFromCallCost(cc, s.CGRID,
|
||||
sr.Event.GetStringIgnoreErrors(utils.RunID)))
|
||||
}
|
||||
} else if notCharged < 0 { // charged too much, try refund
|
||||
if err = sS.refundSession(s, sRunIdx, -notCharged); err != nil {
|
||||
if err := sS.roundCost(s, sRunIdx); err != nil { // will round the cost and refund the extra increment
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf(
|
||||
"<%s> failed refunding session: <%s>, srIdx: <%d>, error: <%s>",
|
||||
fmt.Sprintf("<%s> failed rounding session cost for <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
}
|
||||
if err := sS.roundCost(s, sRunIdx); err != nil { // will round the cost and refund the extra increment
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> failed rounding session cost for <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
|
||||
}
|
||||
if sS.cgrCfg.SessionSCfg().StoreSCosts {
|
||||
if err := sS.storeSCost(s, sRunIdx); err != nil {
|
||||
utils.Logger.Warning(
|
||||
@@ -1508,7 +1510,6 @@ func (sS *SessionS) endSession(s *Session, tUsage, lastUsage *time.Duration,
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// set cost fields
|
||||
sr.Event[utils.Cost] = sr.EventCost.GetCost()
|
||||
sr.Event[utils.CostDetails] = utils.ToJSON(sr.EventCost) // avoid map[string]interface{} when decoding
|
||||
@@ -2538,6 +2539,7 @@ func (sS *SessionS) BiRPCv1TerminateSession(clnt rpcclient.ClientConnector,
|
||||
}
|
||||
var s *Session
|
||||
fib := utils.Fib()
|
||||
var isMsg bool // one time charging, do not perform indexing and sTerminator
|
||||
for i := 0; i < sS.cgrCfg.SessionSCfg().TerminateAttempts; i++ {
|
||||
if s = sS.getRelocateSession(cgrID,
|
||||
ev.GetStringIgnoreErrors(utils.InitialOriginID),
|
||||
@@ -2549,21 +2551,26 @@ func (sS *SessionS) BiRPCv1TerminateSession(clnt rpcclient.ClientConnector,
|
||||
time.Sleep(time.Duration(fib()) * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
isMsg = true
|
||||
if s, err = sS.initSession(args.CGREvent.Tenant,
|
||||
ev, sS.biJClntID(clnt),
|
||||
ev.GetStringIgnoreErrors(utils.OriginID), dbtItvl,
|
||||
args.ArgDispatcher, false, args.ForceDuration); err != nil {
|
||||
args.ArgDispatcher, isMsg, args.ForceDuration); err != nil {
|
||||
return utils.NewErrRALs(err)
|
||||
}
|
||||
if _, err = sS.updateSession(s, ev, isMsg, args.ForceDuration); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
if !isMsg {
|
||||
s.UpdateSRuns(ev, sS.cgrCfg.SessionSCfg().AlterableFields)
|
||||
}
|
||||
s.UpdateSRuns(ev, sS.cgrCfg.SessionSCfg().AlterableFields)
|
||||
if err = sS.terminateSession(s,
|
||||
ev.GetDurationPtrIgnoreErrors(utils.Usage),
|
||||
ev.GetDurationPtrIgnoreErrors(utils.LastUsed),
|
||||
ev.GetTimePtrIgnoreErrors(utils.AnswerTime, utils.EmptyString),
|
||||
false); err != nil {
|
||||
isMsg); err != nil {
|
||||
return utils.NewErrRALs(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ func testSessionsItUpdateUnexist(t *testing.T) {
|
||||
utils.SetupTime: time.Date(2016, time.January, 5, 18, 30, 49, 0, time.UTC),
|
||||
utils.AnswerTime: time.Date(2016, time.January, 5, 18, 31, 05, 0, time.UTC),
|
||||
utils.Usage: usage,
|
||||
utils.CGRDebitInterval: "10s",
|
||||
utils.CGRDebitInterval: "0s",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -242,7 +242,7 @@ func testSessionsItUpdateUnexist(t *testing.T) {
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
eAcntVal = 8.582900
|
||||
eAcntVal = 8.599600
|
||||
if err := sItRPC.Call(utils.APIerSv2GetAccount, attrs, &acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if acnt.BalanceMap[utils.MONETARY].GetTotalValue() != eAcntVal {
|
||||
|
||||
Reference in New Issue
Block a user