mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
Added RoundIncrement to EventCost
This commit is contained in:
committed by
Dan Christian Bogos
parent
830103a200
commit
b1b9a81fc1
@@ -203,8 +203,9 @@ func (cc *CallCost) Round() {
|
||||
//log.Print(cost, roundedCost, correctionCost)
|
||||
if correctionCost != 0 {
|
||||
ts.RoundIncrement = &Increment{
|
||||
Cost: correctionCost,
|
||||
BalanceInfo: inc.BalanceInfo,
|
||||
Cost: correctionCost,
|
||||
BalanceInfo: inc.BalanceInfo,
|
||||
CompressFactor: 1,
|
||||
}
|
||||
totalCorrectionCost += correctionCost
|
||||
ts.Cost += correctionCost
|
||||
|
||||
@@ -174,7 +174,7 @@ func (cdrS *CDRServer) rateCDR(cdr *CDRWithArgDispatcher) ([]*CDR, error) {
|
||||
cdrClone.OriginID = smCost.OriginID
|
||||
if cdr.Usage == 0 {
|
||||
cdrClone.Usage = smCost.Usage
|
||||
} else if smCost.CostDetails.GetUsage() != cdr.Usage {
|
||||
} else if smCost.Usage != cdr.Usage {
|
||||
if err = cdrS.refundEventCost(smCost.CostDetails,
|
||||
cdrClone.RequestType, cdrClone.ToR); err != nil {
|
||||
return nil, err
|
||||
@@ -832,7 +832,7 @@ func (cdrS *CDRServer) V2StoreSessionCost(args *ArgsV2CDRSStoreSMCost, reply *st
|
||||
OriginID: args.Cost.OriginID,
|
||||
CostSource: args.Cost.CostSource,
|
||||
Usage: args.Cost.Usage,
|
||||
CostDetails: args.Cost.CostDetails},
|
||||
CostDetails: NewEventCostFromCallCost(cc, args.Cost.CGRID, args.Cost.RunID)},
|
||||
args.CheckDuplicate); err != nil {
|
||||
err = utils.NewErrServerError(err)
|
||||
return
|
||||
|
||||
@@ -56,53 +56,77 @@ func NewEventCostFromCallCost(cc *CallCost, cgrID, runID string) (ec *EventCost)
|
||||
"DestinationID": ts.MatchedDestId, "RatingPlanID": ts.RatingPlanId}
|
||||
cIl.RatingID = ec.ratingIDForRateInterval(ts.RateInterval, rf)
|
||||
if len(ts.Increments) != 0 {
|
||||
cIl.Increments = make([]*ChargingIncrement, len(ts.Increments))
|
||||
cIl.Increments = make([]*ChargingIncrement, 0, len(ts.Increments)+1)
|
||||
}
|
||||
for j, incr := range ts.Increments {
|
||||
cIt := &ChargingIncrement{
|
||||
Usage: incr.Duration,
|
||||
Cost: incr.Cost,
|
||||
CompressFactor: incr.CompressFactor}
|
||||
if incr.BalanceInfo == nil {
|
||||
continue
|
||||
}
|
||||
//AccountingID
|
||||
if incr.BalanceInfo.Unit != nil {
|
||||
// 2 balances work-around
|
||||
ecUUID := utils.META_NONE // populate no matter what due to Unit not nil
|
||||
if incr.BalanceInfo.Monetary != nil {
|
||||
if uuid := ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Monetary.UUID,
|
||||
Units: incr.Cost,
|
||||
RatingID: ec.ratingIDForRateInterval(incr.BalanceInfo.Monetary.RateInterval, rf),
|
||||
}); uuid != "" {
|
||||
ecUUID = uuid
|
||||
}
|
||||
}
|
||||
cIt.AccountingID = ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Unit.UUID,
|
||||
Units: incr.BalanceInfo.Unit.Consumed,
|
||||
RatingID: ec.ratingIDForRateInterval(incr.BalanceInfo.Unit.RateInterval, rf),
|
||||
ExtraChargeID: ecUUID})
|
||||
} else if incr.BalanceInfo.Monetary != nil { // Only monetary
|
||||
cIt.AccountingID = ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Monetary.UUID,
|
||||
Units: incr.Cost,
|
||||
RatingID: ec.ratingIDForRateInterval(incr.BalanceInfo.Monetary.RateInterval, rf)})
|
||||
}
|
||||
cIl.Increments[j] = cIt
|
||||
for _, incr := range ts.Increments {
|
||||
cIl.Increments = append(cIl.Increments, ec.newChargingIncrement(incr, rf, false))
|
||||
}
|
||||
if ts.RoundIncrement != nil {
|
||||
rIncr := ec.newChargingIncrement(ts.RoundIncrement, rf, true)
|
||||
rIncr.Cost = -rIncr.Cost
|
||||
cIl.Increments = append(cIl.Increments, rIncr)
|
||||
}
|
||||
ec.Charges[i] = cIl
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// newChargingIncrement creates ChargingIncrement from a Increment
|
||||
// special case if is the roundIncrement the rateID is *rounding
|
||||
func (ec *EventCost) newChargingIncrement(incr *Increment, rf RatingMatchedFilters, roundedIncrement bool) (cIt *ChargingIncrement) {
|
||||
cIt = &ChargingIncrement{
|
||||
Usage: incr.Duration,
|
||||
Cost: incr.Cost,
|
||||
CompressFactor: incr.CompressFactor,
|
||||
}
|
||||
if incr.BalanceInfo == nil {
|
||||
return
|
||||
}
|
||||
rateID := utils.MetaRounding
|
||||
//AccountingID
|
||||
if incr.BalanceInfo.Unit != nil {
|
||||
// 2 balances work-around
|
||||
ecUUID := utils.META_NONE // populate no matter what due to Unit not nil
|
||||
if incr.BalanceInfo.Monetary != nil {
|
||||
if !roundedIncrement {
|
||||
rateID = ec.ratingIDForRateInterval(incr.BalanceInfo.Monetary.RateInterval, rf)
|
||||
}
|
||||
if uuid := ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Monetary.UUID,
|
||||
Units: incr.Cost,
|
||||
RatingID: rateID,
|
||||
}); uuid != "" {
|
||||
ecUUID = uuid
|
||||
}
|
||||
}
|
||||
if !roundedIncrement {
|
||||
rateID = ec.ratingIDForRateInterval(incr.BalanceInfo.Unit.RateInterval, rf)
|
||||
}
|
||||
cIt.AccountingID = ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Unit.UUID,
|
||||
Units: incr.BalanceInfo.Unit.Consumed,
|
||||
RatingID: rateID,
|
||||
ExtraChargeID: ecUUID,
|
||||
})
|
||||
} else if incr.BalanceInfo.Monetary != nil { // Only monetary
|
||||
if !roundedIncrement {
|
||||
rateID = ec.ratingIDForRateInterval(incr.BalanceInfo.Monetary.RateInterval, rf)
|
||||
}
|
||||
cIt.AccountingID = ec.Accounting.GetIDWithSet(
|
||||
&BalanceCharge{
|
||||
AccountID: incr.BalanceInfo.AccountID,
|
||||
BalanceUUID: incr.BalanceInfo.Monetary.UUID,
|
||||
Units: incr.Cost,
|
||||
RatingID: rateID,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EventCost stores cost for an Event
|
||||
type EventCost struct {
|
||||
CGRID string
|
||||
@@ -343,71 +367,94 @@ func (ec *EventCost) AsCallCost(tor string) *CallCost {
|
||||
ToR: utils.FirstNonEmpty(tor, utils.VOICE),
|
||||
Cost: ec.GetCost(),
|
||||
RatedUsage: float64(ec.GetUsage().Nanoseconds()),
|
||||
AccountSummary: ec.AccountSummary}
|
||||
AccountSummary: ec.AccountSummary,
|
||||
}
|
||||
cc.Timespans = make(TimeSpans, len(ec.Charges))
|
||||
for i, cIl := range ec.Charges {
|
||||
ts := &TimeSpan{Cost: cIl.Cost(),
|
||||
ts := &TimeSpan{
|
||||
Cost: cIl.Cost(),
|
||||
DurationIndex: *cIl.Usage(),
|
||||
CompressFactor: cIl.CompressFactor}
|
||||
CompressFactor: cIl.CompressFactor,
|
||||
}
|
||||
if cIl.ecUsageIdx == nil { // index was not populated yet
|
||||
ec.ComputeEventCostUsageIndexes()
|
||||
}
|
||||
ts.TimeStart = ec.StartTime.Add(*cIl.ecUsageIdx)
|
||||
ts.TimeEnd = ts.TimeStart.Add(
|
||||
time.Duration(cIl.Usage().Nanoseconds() * int64(cIl.CompressFactor)))
|
||||
if cIl.RatingID != "" {
|
||||
if ec.Rating[cIl.RatingID].RatingFiltersID != "" {
|
||||
rfs := ec.RatingFilters[ec.Rating[cIl.RatingID].RatingFiltersID]
|
||||
ts.MatchedSubject = rfs[utils.Subject].(string)
|
||||
ts.MatchedPrefix = rfs[utils.DestinationPrefix].(string)
|
||||
ts.MatchedDestId = rfs[utils.DestinationID].(string)
|
||||
ts.RatingPlanId = rfs[utils.RatingPlanID].(string)
|
||||
}
|
||||
if cIl.RatingID != "" &&
|
||||
ec.Rating[cIl.RatingID].RatingFiltersID != "" {
|
||||
rfs := ec.RatingFilters[ec.Rating[cIl.RatingID].RatingFiltersID]
|
||||
ts.MatchedSubject = rfs[utils.Subject].(string)
|
||||
ts.MatchedPrefix = rfs[utils.DestinationPrefix].(string)
|
||||
ts.MatchedDestId = rfs[utils.DestinationID].(string)
|
||||
ts.RatingPlanId = rfs[utils.RatingPlanID].(string)
|
||||
}
|
||||
ts.RateInterval = ec.rateIntervalForRatingID(cIl.RatingID)
|
||||
if len(cIl.Increments) != 0 {
|
||||
ts.Increments = make(Increments, len(cIl.Increments))
|
||||
}
|
||||
for j, cInc := range cIl.Increments {
|
||||
incr := &Increment{Duration: cInc.Usage, Cost: cInc.Cost, CompressFactor: cInc.CompressFactor, BalanceInfo: new(DebitInfo)}
|
||||
if cInc.AccountingID != "" {
|
||||
cBC := ec.Accounting[cInc.AccountingID]
|
||||
incr.BalanceInfo.AccountID = cBC.AccountID
|
||||
var balanceType string
|
||||
if cBC.BalanceUUID != "" {
|
||||
if ec.AccountSummary != nil {
|
||||
for _, b := range ec.AccountSummary.BalanceSummaries {
|
||||
if b.UUID == cBC.BalanceUUID {
|
||||
balanceType = b.Type
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if utils.SliceHasMember([]string{utils.DATA, utils.VOICE}, balanceType) && cBC.ExtraChargeID == "" {
|
||||
cBC.ExtraChargeID = utils.META_NONE // mark the balance to be exported as Unit type
|
||||
}
|
||||
if cBC.ExtraChargeID != "" { // have both monetary and data
|
||||
// Work around, enforce logic with 2 balances for *voice/*monetary combination
|
||||
// so we can stay compatible with CallCost
|
||||
incr.BalanceInfo.Unit = &UnitInfo{UUID: cBC.BalanceUUID, Consumed: cBC.Units}
|
||||
incr.BalanceInfo.Unit.RateInterval = ec.rateIntervalForRatingID(cBC.RatingID)
|
||||
if cBC.ExtraChargeID != utils.META_NONE {
|
||||
cBC = ec.Accounting[cBC.ExtraChargeID] // overwrite original balance so we can process it in one place
|
||||
}
|
||||
}
|
||||
if cBC.ExtraChargeID != utils.META_NONE {
|
||||
incr.BalanceInfo.Monetary = &MonetaryInfo{UUID: cBC.BalanceUUID}
|
||||
incr.BalanceInfo.Monetary.RateInterval = ec.rateIntervalForRatingID(cBC.RatingID)
|
||||
}
|
||||
|
||||
incrs := cIl.Increments
|
||||
if l := len(cIl.Increments); l != 0 {
|
||||
if ec.Accounting[cIl.Increments[l-1].AccountingID].RatingID == utils.MetaRounding {
|
||||
// special case: if the last increment is has the ratingID equal to *roundig
|
||||
// we consider it as the roundIncrement
|
||||
l--
|
||||
incrs = incrs[:l]
|
||||
ts.RoundIncrement = ec.newIntervalFromCharge(cIl.Increments[l-1])
|
||||
ts.RoundIncrement.Cost = -ts.RoundIncrement.Cost
|
||||
}
|
||||
ts.Increments[j] = incr
|
||||
ts.Increments = make(Increments, l)
|
||||
}
|
||||
for j, cInc := range incrs {
|
||||
ts.Increments[j] = ec.newIntervalFromCharge(cInc)
|
||||
}
|
||||
cc.Timespans[i] = ts
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
// newIntervalFromCharge creates Increment from a ChargingIncrement
|
||||
func (ec *EventCost) newIntervalFromCharge(cInc *ChargingIncrement) (incr *Increment) {
|
||||
incr = &Increment{
|
||||
Duration: cInc.Usage,
|
||||
Cost: cInc.Cost,
|
||||
CompressFactor: cInc.CompressFactor,
|
||||
BalanceInfo: new(DebitInfo),
|
||||
}
|
||||
if len(cInc.AccountingID) == 0 {
|
||||
return
|
||||
}
|
||||
cBC := ec.Accounting[cInc.AccountingID]
|
||||
incr.BalanceInfo.AccountID = cBC.AccountID
|
||||
var balanceType string
|
||||
if cBC.BalanceUUID != "" {
|
||||
if ec.AccountSummary != nil {
|
||||
for _, b := range ec.AccountSummary.BalanceSummaries {
|
||||
if b.UUID == cBC.BalanceUUID {
|
||||
balanceType = b.Type
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if utils.SliceHasMember([]string{utils.DATA, utils.VOICE}, balanceType) && cBC.ExtraChargeID == "" {
|
||||
cBC.ExtraChargeID = utils.META_NONE // mark the balance to be exported as Unit type
|
||||
}
|
||||
if cBC.ExtraChargeID != "" { // have both monetary and data
|
||||
// Work around, enforce logic with 2 balances for *voice/*monetary combination
|
||||
// so we can stay compatible with CallCost
|
||||
incr.BalanceInfo.Unit = &UnitInfo{UUID: cBC.BalanceUUID, Consumed: cBC.Units}
|
||||
incr.BalanceInfo.Unit.RateInterval = ec.rateIntervalForRatingID(cBC.RatingID)
|
||||
if cBC.ExtraChargeID != utils.META_NONE {
|
||||
cBC = ec.Accounting[cBC.ExtraChargeID] // overwrite original balance so we can process it in one place
|
||||
}
|
||||
}
|
||||
if cBC.ExtraChargeID != utils.META_NONE {
|
||||
incr.BalanceInfo.Monetary = &MonetaryInfo{UUID: cBC.BalanceUUID}
|
||||
incr.BalanceInfo.Monetary.RateInterval = ec.rateIntervalForRatingID(cBC.RatingID)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ratingGetIDFomEventCost retrieves UUID based on data from another EventCost
|
||||
func (ec *EventCost) ratingGetIDFomEventCost(oEC *EventCost, oRatingID string) string {
|
||||
if oRatingID == "" {
|
||||
|
||||
@@ -323,13 +323,13 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
Account: "dan",
|
||||
Destination: "+4986517174963",
|
||||
ToR: utils.VOICE,
|
||||
Cost: 0.85,
|
||||
Cost: 0.75,
|
||||
RatedUsage: 120.0,
|
||||
Timespans: TimeSpans{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
|
||||
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
|
||||
Cost: 0.25,
|
||||
Cost: 0.15,
|
||||
RateInterval: &RateInterval{ // standard rating
|
||||
Timing: &RITiming{
|
||||
StartTime: "00:00:00",
|
||||
@@ -354,6 +354,16 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
MatchedDestId: "GERMANY",
|
||||
RatingPlanId: "RPL_RETAIL1",
|
||||
CompressFactor: 1,
|
||||
RoundIncrement: &Increment{
|
||||
Cost: 0.1,
|
||||
BalanceInfo: &DebitInfo{
|
||||
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
|
||||
ID: utils.MetaDefault,
|
||||
Value: 9.9},
|
||||
AccountID: "cgrates.org:dan",
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
Increments: Increments{
|
||||
&Increment{ // ConnectFee
|
||||
Cost: 0.1,
|
||||
@@ -500,10 +510,15 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
AccountingID: "906bfd0f-035c-40a3-93a8-46f71627983e",
|
||||
CompressFactor: 30,
|
||||
},
|
||||
{
|
||||
Cost: -0.1,
|
||||
AccountingID: "44e97dec-8a7e-43d0-8b0a-e34a152",
|
||||
CompressFactor: 1,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
usage: utils.DurationPointer(time.Duration(60 * time.Second)),
|
||||
cost: utils.Float64Pointer(0.25),
|
||||
cost: utils.Float64Pointer(0.15),
|
||||
ecUsageIdx: utils.DurationPointer(time.Duration(0)),
|
||||
},
|
||||
&ChargingInterval{
|
||||
@@ -568,6 +583,13 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
Units: 1,
|
||||
ExtraChargeID: "*none",
|
||||
},
|
||||
"44e97dec-8a7e-43d0-8b0a-e34a152": &BalanceCharge{
|
||||
AccountID: "cgrates.org:dan",
|
||||
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
|
||||
RatingID: "*rounding",
|
||||
Units: 0.1,
|
||||
ExtraChargeID: "",
|
||||
},
|
||||
},
|
||||
RatingFilters: RatingFilters{
|
||||
"7e73a00d-be53-4083-a1ee-8ee0b546c62a": RatingMatchedFilters{
|
||||
@@ -676,6 +698,21 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
utils.ToJSON(eEC.Rates[eEC.Rating[eEC.Accounting[eEC.Charges[0].Increments[2].AccountingID].RatingID].RatesID]),
|
||||
utils.ToJSON(ec.Rates[ec.Rating[ec.Accounting[ec.Charges[0].Increments[2].AccountingID].RatingID].RatesID]))
|
||||
}
|
||||
|
||||
// Compare to expected EC
|
||||
if !reflect.DeepEqual(eEC.Accounting[eEC.Charges[0].Increments[3].AccountingID],
|
||||
ec.Accounting[ec.Charges[0].Increments[3].AccountingID]) {
|
||||
t.Errorf("Expecting: %s, received: %s",
|
||||
utils.ToJSON(eEC.Accounting[eEC.Charges[0].Increments[3].AccountingID]),
|
||||
utils.ToJSON(ec.Accounting[ec.Charges[0].Increments[3].AccountingID]))
|
||||
}
|
||||
ec.Charges[0].Increments[3].AccountingID = eEC.Charges[0].Increments[3].AccountingID
|
||||
if !reflect.DeepEqual(eEC.Charges[0].Increments[3],
|
||||
ec.Charges[0].Increments[3]) {
|
||||
t.Errorf("Expecting: %s, received: %s",
|
||||
utils.ToJSON(eEC.Charges[0].Increments[3]),
|
||||
utils.ToJSON(ec.Charges[0].Increments[3]))
|
||||
}
|
||||
if len(ec.Accounting) != len(eEC.Accounting) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
|
||||
}
|
||||
|
||||
@@ -446,9 +446,8 @@ func (ts *TimeSpan) CalculateCost() float64 {
|
||||
return 0
|
||||
}
|
||||
return ts.RateInterval.GetCost(ts.GetDuration(), ts.GetGroupStart())
|
||||
} else {
|
||||
return ts.Increments.GetTotalCost() * float64(ts.GetCompressFactor())
|
||||
}
|
||||
return ts.Increments.GetTotalCost() * float64(ts.GetCompressFactor())
|
||||
}
|
||||
|
||||
func (ts *TimeSpan) setRatingInfo(rp *RatingInfo) {
|
||||
|
||||
@@ -598,14 +598,8 @@ func (sS *SessionS) refundSession(s *Session, sRunIdx int, rUsage time.Duration)
|
||||
// storeSCost will post the session cost to CDRs
|
||||
// not thread safe, need to be handled in a layer above
|
||||
func (sS *SessionS) storeSCost(s *Session, sRunIdx int) (err error) {
|
||||
if sRunIdx >= len(s.SRuns) {
|
||||
return errors.New("sRunIdx out of range")
|
||||
}
|
||||
sr := s.SRuns[sRunIdx]
|
||||
if sr.EventCost == nil {
|
||||
return // no costs to save, ignore the operation
|
||||
}
|
||||
smCost := &engine.V2SMCost{
|
||||
smCost := &engine.SMCost{
|
||||
CGRID: s.CGRID,
|
||||
CostSource: utils.MetaSessionS,
|
||||
RunID: sr.Event.GetStringIgnoreErrors(utils.RunID),
|
||||
@@ -614,7 +608,7 @@ func (sS *SessionS) storeSCost(s *Session, sRunIdx int) (err error) {
|
||||
Usage: sr.TotalUsage,
|
||||
CostDetails: sr.EventCost,
|
||||
}
|
||||
argSmCost := &engine.ArgsV2CDRSStoreSMCost{
|
||||
argSmCost := &engine.AttrCDRSStoreSMCost{
|
||||
Cost: smCost,
|
||||
CheckDuplicate: true,
|
||||
ArgDispatcher: s.ArgDispatcher,
|
||||
@@ -623,23 +617,46 @@ func (sS *SessionS) storeSCost(s *Session, sRunIdx int) (err error) {
|
||||
},
|
||||
}
|
||||
var reply string
|
||||
if err := sS.connMgr.Call(sS.cgrCfg.SessionSCfg().CDRsConns, nil, utils.CDRsV2StoreSessionCost,
|
||||
argSmCost, &reply); err != nil {
|
||||
if err == utils.ErrExists {
|
||||
// use the v1 because it doesn't do rounding refund
|
||||
if err := sS.connMgr.Call(sS.cgrCfg.SessionSCfg().CDRsConns, nil, utils.CDRsV1StoreSessionCost,
|
||||
argSmCost, &reply); err != nil && err == utils.ErrExists {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> refunding session: <%s> error: <%s>",
|
||||
utils.SessionS, s.CGRID, err.Error()))
|
||||
if err = sS.refundSession(s, sRunIdx, sr.CD.GetDuration()); err != nil { // refund entire duration
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> refunding session: <%s> error: <%s>",
|
||||
utils.SessionS, s.CGRID, err.Error()))
|
||||
if err = sS.refundSession(s, sRunIdx, sr.CD.GetDuration()); err != nil { // refund entire duration
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf(
|
||||
"<%s> failed refunding session: <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
fmt.Sprintf(
|
||||
"<%s> failed refunding session: <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// roundCost will round the EventCost and will refund the extra debited increments
|
||||
// should be called only at the endSession
|
||||
// not thread safe, need to be handled in a layer above
|
||||
func (sS *SessionS) roundCost(s *Session, sRunIdx int) (err error) {
|
||||
sr := s.SRuns[sRunIdx]
|
||||
runID := sr.Event.GetStringIgnoreErrors(utils.RunID)
|
||||
cc := sr.EventCost.AsCallCost(utils.EmptyString)
|
||||
cc.Round()
|
||||
if roundIncrements := cc.GetRoundIncrements(); len(roundIncrements) != 0 {
|
||||
cd := cc.CreateCallDescriptor()
|
||||
cd.CgrID = s.CGRID
|
||||
cd.RunID = runID
|
||||
cd.Increments = roundIncrements
|
||||
var response float64
|
||||
if err = sS.connMgr.Call(sS.cgrCfg.SessionSCfg().ResSConns, nil,
|
||||
utils.ResponderRefundRounding,
|
||||
&engine.CallDescriptorWithArgDispatcher{CallDescriptor: cd},
|
||||
&response); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return nil
|
||||
sr.EventCost = engine.NewEventCostFromCallCost(cc, s.CGRID, runID)
|
||||
return
|
||||
}
|
||||
|
||||
// disconnectSession will send disconnect from SessionS to clients
|
||||
@@ -1478,6 +1495,20 @@ func (sS *SessionS) endSession(s *Session, tUsage, lastUsage *time.Duration,
|
||||
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(
|
||||
fmt.Sprintf("<%s> failed storing session cost for <%s>, srIdx: <%d>, error: <%s>",
|
||||
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
|
||||
@@ -1491,14 +1522,6 @@ func (sS *SessionS) endSession(s *Session, tUsage, lastUsage *time.Duration,
|
||||
if aTime != nil {
|
||||
sr.Event[utils.AnswerTime] = *aTime
|
||||
}
|
||||
if sS.cgrCfg.SessionSCfg().StoreSCosts {
|
||||
if err := sS.storeSCost(s, sRunIdx); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> failed storing session cost for <%s>, srIdx: <%d>, error: <%s>",
|
||||
utils.SessionS, s.CGRID, sRunIdx, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
engine.Cache.Set(utils.CacheClosedSessions, s.CGRID, s,
|
||||
nil, true, utils.NonTransactional)
|
||||
|
||||
@@ -662,6 +662,7 @@ const (
|
||||
FileName = "FileName"
|
||||
MetaBusy = "*busy"
|
||||
MetaQueue = "*queue"
|
||||
MetaRounding = "*rounding"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
|
||||
Reference in New Issue
Block a user