mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Updated EventCost Rounding. Fixes #3018
This commit is contained in:
committed by
Dan Christian Bogos
parent
d9d8df250f
commit
0dd7a37f9b
@@ -98,7 +98,7 @@ type ResponderInterface interface {
|
||||
Debit(arg *engine.CallDescriptorWithArgDispatcher, reply *engine.CallCost) (err error)
|
||||
MaxDebit(arg *engine.CallDescriptorWithArgDispatcher, reply *engine.CallCost) (err error)
|
||||
RefundIncrements(arg *engine.CallDescriptorWithArgDispatcher, reply *engine.Account) (err error)
|
||||
RefundRounding(arg *engine.CallDescriptorWithArgDispatcher, reply *float64) (err error)
|
||||
RefundRounding(arg *engine.CallDescriptorWithArgDispatcher, reply *engine.Account) (err error)
|
||||
GetMaxSessionTime(arg *engine.CallDescriptorWithArgDispatcher, reply *time.Duration) (err error)
|
||||
Shutdown(arg *utils.TenantWithArgDispatcher, reply *string) (err error)
|
||||
GetCostOnRatingPlans(arg *utils.GetCostOnRatingPlansArgs, reply *map[string]interface{}) (err error)
|
||||
|
||||
@@ -523,7 +523,7 @@ func (dS *DispatcherResponder) RefundIncrements(args *engine.CallDescriptorWithA
|
||||
return dS.dS.ResponderRefundIncrements(args, reply)
|
||||
}
|
||||
|
||||
func (dS *DispatcherResponder) RefundRounding(args *engine.CallDescriptorWithArgDispatcher, reply *float64) error {
|
||||
func (dS *DispatcherResponder) RefundRounding(args *engine.CallDescriptorWithArgDispatcher, reply *engine.Account) error {
|
||||
return dS.dS.ResponderRefundRounding(args, reply)
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ func (dS *DispatcherService) ResponderRefundIncrements(args *engine.CallDescript
|
||||
}
|
||||
|
||||
func (dS *DispatcherService) ResponderRefundRounding(args *engine.CallDescriptorWithArgDispatcher,
|
||||
reply *float64) (err error) {
|
||||
reply *engine.Account) (err error) {
|
||||
if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
|
||||
if args.ArgDispatcher == nil {
|
||||
return utils.NewErrMandatoryIeMissing(utils.ArgDispatcherField)
|
||||
|
||||
@@ -157,10 +157,6 @@ func (cc *CallCost) GetLongestRounding() (roundingDecimals int, roundingMethod s
|
||||
return
|
||||
}
|
||||
|
||||
func (cc *CallCost) AsJSON() string {
|
||||
return utils.ToJSON(cc)
|
||||
}
|
||||
|
||||
// public function to update final (merged) callcost
|
||||
func (cc *CallCost) UpdateCost() {
|
||||
cc.deductConnectFee = true
|
||||
|
||||
@@ -777,7 +777,7 @@ func (cd *CallDescriptor) debit(account *Account, dryRun bool, goNegative bool)
|
||||
if len(roundIncrements) != 0 {
|
||||
rcd := cc.CreateCallDescriptor()
|
||||
rcd.Increments = roundIncrements
|
||||
rcd.refundRounding()
|
||||
rcd.refundRounding(cd.account)
|
||||
}
|
||||
}
|
||||
//log.Printf("OUT CC: ", cc)
|
||||
@@ -952,10 +952,14 @@ func (cd *CallDescriptor) RefundIncrements() (acnt *Account, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) refundRounding() (err error) {
|
||||
func (cd *CallDescriptor) refundRounding(old *Account) (accountsCache map[string]*Account, err error) {
|
||||
// get account list for locking
|
||||
// all must be locked in order to use cache
|
||||
accountsCache := make(map[string]*Account)
|
||||
accountsCache = make(map[string]*Account)
|
||||
if old != nil {
|
||||
accountsCache[old.ID] = old
|
||||
defer dm.SetAccount(old)
|
||||
}
|
||||
for _, increment := range cd.Increments {
|
||||
account, found := accountsCache[increment.BalanceInfo.AccountID]
|
||||
if !found {
|
||||
@@ -983,13 +987,17 @@ func (cd *CallDescriptor) refundRounding() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) RefundRounding() (err error) {
|
||||
func (cd *CallDescriptor) RefundRounding() (acc *Account, err error) {
|
||||
accMap := make(utils.StringMap)
|
||||
for _, inc := range cd.Increments {
|
||||
accMap[utils.ACCOUNT_PREFIX+inc.BalanceInfo.AccountID] = true
|
||||
}
|
||||
_, err = guardian.Guardian.Guard(func() (iface interface{}, err error) {
|
||||
err = cd.refundRounding()
|
||||
guardian.Guardian.Guard(func() (_ interface{}, _ error) {
|
||||
var accCache map[string]*Account
|
||||
if accCache, err = cd.refundRounding(nil); err != nil {
|
||||
return
|
||||
}
|
||||
acc = accCache[utils.ConcatenatedKey(cd.Tenant, cd.Account)]
|
||||
return
|
||||
}, config.CgrConfig().GeneralCfg().LockingTimeout, accMap.Slice()...)
|
||||
return
|
||||
|
||||
@@ -810,6 +810,10 @@ func (cdrS *CDRServer) V2StoreSessionCost(args *ArgsV2CDRSStoreSMCost, reply *st
|
||||
}
|
||||
// end of RPC caching
|
||||
cc := args.Cost.CostDetails.AsCallCost(utils.EmptyString)
|
||||
if args.Cost.CostDetails.AccountSummary != nil {
|
||||
cc.Tenant = args.Cost.CostDetails.AccountSummary.Tenant
|
||||
cc.Account = args.Cost.CostDetails.AccountSummary.ID
|
||||
}
|
||||
cc.Round()
|
||||
roundIncrements := cc.GetRoundIncrements()
|
||||
if len(roundIncrements) != 0 {
|
||||
@@ -817,15 +821,18 @@ func (cdrS *CDRServer) V2StoreSessionCost(args *ArgsV2CDRSStoreSMCost, reply *st
|
||||
cd.CgrID = args.Cost.CGRID
|
||||
cd.RunID = args.Cost.RunID
|
||||
cd.Increments = roundIncrements
|
||||
var response float64
|
||||
response := new(Account)
|
||||
if err := cdrS.connMgr.Call(cdrS.cgrCfg.CdrsCfg().RaterConns, nil,
|
||||
utils.ResponderRefundRounding,
|
||||
&CallDescriptorWithArgDispatcher{CallDescriptor: cd},
|
||||
&response); err != nil {
|
||||
response); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<CDRS> RefundRounding for cc: %+v, got error: %s",
|
||||
cc, err.Error()))
|
||||
}
|
||||
if response != nil {
|
||||
cc.AccountSummary = response.AsAccountSummary()
|
||||
}
|
||||
}
|
||||
if err = cdrS.storeSMCost(
|
||||
&SMCost{
|
||||
|
||||
@@ -62,9 +62,7 @@ func NewEventCostFromCallCost(cc *CallCost, cgrID, runID string) (ec *EventCost)
|
||||
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)
|
||||
cIl.Increments = append(cIl.Increments, ec.newChargingIncrement(ts.RoundIncrement, rf, true))
|
||||
}
|
||||
ec.Charges[i] = cIl
|
||||
}
|
||||
@@ -401,7 +399,6 @@ func (ec *EventCost) AsCallCost(tor string) *CallCost {
|
||||
l--
|
||||
incrs = incrs[:l]
|
||||
ts.RoundIncrement = ec.newIntervalFromCharge(cIl.Increments[l-1])
|
||||
ts.RoundIncrement.Cost = -ts.RoundIncrement.Cost
|
||||
}
|
||||
ts.Increments = make(Increments, l)
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
RatingPlanId: "RPL_RETAIL1",
|
||||
CompressFactor: 1,
|
||||
RoundIncrement: &Increment{
|
||||
Cost: 0.1,
|
||||
Cost: -0.1,
|
||||
BalanceInfo: &DebitInfo{
|
||||
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
|
||||
ID: utils.MetaDefault,
|
||||
@@ -586,7 +586,7 @@ func TestNewEventCostFromCallCost(t *testing.T) {
|
||||
AccountID: "cgrates.org:dan",
|
||||
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
|
||||
RatingID: "*rounding",
|
||||
Units: 0.1,
|
||||
Units: -0.1,
|
||||
ExtraChargeID: "",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -267,7 +267,7 @@ func (rs *Responder) RefundIncrements(arg *CallDescriptorWithArgDispatcher, repl
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) RefundRounding(arg *CallDescriptorWithArgDispatcher, reply *float64) (err error) {
|
||||
func (rs *Responder) RefundRounding(arg *CallDescriptorWithArgDispatcher, reply *Account) (err error) {
|
||||
// RPC caching
|
||||
if config.CgrConfig().CacheCfg()[utils.CacheRPCResponses].Limit != 0 {
|
||||
cacheKey := utils.ConcatenatedKey(utils.ResponderRefundRounding, arg.CgrID)
|
||||
@@ -278,7 +278,7 @@ func (rs *Responder) RefundRounding(arg *CallDescriptorWithArgDispatcher, reply
|
||||
if itm, has := Cache.Get(utils.CacheRPCResponses, cacheKey); has {
|
||||
cachedResp := itm.(*utils.CachedRPCResponse)
|
||||
if cachedResp.Error == nil {
|
||||
*reply = *cachedResp.Result.(*float64)
|
||||
*reply = *cachedResp.Result.(*Account)
|
||||
}
|
||||
return cachedResp.Error
|
||||
}
|
||||
@@ -294,7 +294,11 @@ func (rs *Responder) RefundRounding(arg *CallDescriptorWithArgDispatcher, reply
|
||||
err = utils.ErrMaxUsageExceeded
|
||||
return
|
||||
}
|
||||
err = arg.RefundRounding()
|
||||
var acc *Account
|
||||
if acc, err = arg.RefundRounding(); err != nil || acc == nil {
|
||||
return
|
||||
}
|
||||
*reply = *acc
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ func TestResponderRefundRoundingMaxUsageANY(t *testing.T) {
|
||||
TimeEnd: tEnd,
|
||||
},
|
||||
}
|
||||
var reply float64
|
||||
var reply Account
|
||||
if err := rsponder.RefundRounding(cd, &reply); err == nil ||
|
||||
err.Error() != utils.ErrMaxUsageExceeded.Error() {
|
||||
t.Errorf("Expected %+v, received : %+v", utils.ErrMaxUsageExceeded, err)
|
||||
@@ -414,7 +414,7 @@ func TestResponderRefundRoundingMaxUsageVOICE(t *testing.T) {
|
||||
TimeEnd: tEnd,
|
||||
},
|
||||
}
|
||||
var reply float64
|
||||
var reply Account
|
||||
if err := rsponder.RefundRounding(cd, &reply); err == nil ||
|
||||
err.Error() != utils.ErrMaxUsageExceeded.Error() {
|
||||
t.Errorf("Expected %+v, received : %+v", utils.ErrMaxUsageExceeded, err)
|
||||
|
||||
395
general_tests/session_rounding_it_test.go
Normal file
395
general_tests/session_rounding_it_test.go
Normal file
@@ -0,0 +1,395 @@
|
||||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licensesRnd/>
|
||||
*/
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
sesRndCfgPath string
|
||||
sesRndCfgDIR string
|
||||
sesRndCfg *config.CGRConfig
|
||||
sesRndRPC *rpc.Client
|
||||
sesRndAccount = "testAccount"
|
||||
sesRndTenant = "cgrates.org"
|
||||
|
||||
sesRndExpCost float64
|
||||
sesRndExpMaxUsage time.Duration
|
||||
sesRndExpBalanceValue float64
|
||||
|
||||
sesRndCgrEv = &utils.CGREvent{
|
||||
Tenant: sesRndTenant,
|
||||
Event: map[string]interface{}{
|
||||
utils.Tenant: sesRndTenant,
|
||||
utils.Category: utils.CALL,
|
||||
utils.ToR: utils.VOICE,
|
||||
utils.Account: sesRndAccount,
|
||||
utils.Destination: "TEST",
|
||||
utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC),
|
||||
utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC),
|
||||
utils.Usage: 10 * time.Second,
|
||||
utils.SessionTTL: 0,
|
||||
utils.CGRDebitInterval: time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
sTestSesRndIt = []func(t *testing.T){
|
||||
testSesRndItLoadConfig,
|
||||
testSesRndItResetDataDB,
|
||||
testSesRndItResetStorDb,
|
||||
testSesRndItStartEngine,
|
||||
testSesRndItRPCConn,
|
||||
testSesRndItLoadRating,
|
||||
testSesRndItAddCharger,
|
||||
|
||||
testSesRndItPreparePostpaidUP,
|
||||
testSesRndItAddVoiceBalance,
|
||||
testSesRndItPrepareCDRs,
|
||||
testSesRndItCheckCdrs,
|
||||
|
||||
testSesRndItPreparePostpaidDOWN,
|
||||
testSesRndItAddVoiceBalance,
|
||||
testSesRndItPrepareCDRs,
|
||||
testSesRndItCheckCdrs,
|
||||
|
||||
testSesRndItPreparePrepaidUP,
|
||||
testSesRndItAddVoiceBalance,
|
||||
testSesRndItPrepareCDRs,
|
||||
testSesRndItCheckCdrs,
|
||||
|
||||
testSesRndItPreparePrepaidDOWN,
|
||||
testSesRndItAddVoiceBalance,
|
||||
testSesRndItPrepareCDRs,
|
||||
testSesRndItCheckCdrs,
|
||||
|
||||
testSesRndItStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestSesRndIt(t *testing.T) {
|
||||
switch *dbType {
|
||||
case utils.MetaInternal:
|
||||
sesRndCfgDIR = "sessions_internal"
|
||||
case utils.MetaMySQL:
|
||||
sesRndCfgDIR = "sessions_mysql"
|
||||
case utils.MetaMongo:
|
||||
sesRndCfgDIR = "sessions_mongo"
|
||||
case utils.MetaPostgres:
|
||||
t.SkipNow()
|
||||
default:
|
||||
t.Fatal("Unknown Database type")
|
||||
}
|
||||
for _, stest := range sTestSesRndIt {
|
||||
t.Run(sesRndCfgDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItPreparePostpaidUP(t *testing.T) {
|
||||
sesRndCgrEv.Event[utils.Subject] = "up"
|
||||
sesRndCgrEv.Event[utils.RequestType] = utils.META_POSTPAID
|
||||
sesRndCgrEv.Event[utils.OriginID] = "RndupMETA_POSTPAID"
|
||||
sesRndExpMaxUsage = 10 * time.Second
|
||||
sesRndExpCost = 0.4
|
||||
sesRndExpBalanceValue = 3599999999999.5977
|
||||
}
|
||||
|
||||
func testSesRndItPreparePostpaidDOWN(t *testing.T) {
|
||||
sesRndCgrEv.Event[utils.Subject] = "down"
|
||||
sesRndCgrEv.Event[utils.RequestType] = utils.META_POSTPAID
|
||||
sesRndCgrEv.Event[utils.OriginID] = "RnddownMETA_POSTPAID"
|
||||
sesRndExpMaxUsage = 10 * time.Second
|
||||
sesRndExpCost = 0.3
|
||||
sesRndExpBalanceValue = 3599999999999.697
|
||||
}
|
||||
|
||||
func testSesRndItPreparePrepaidUP(t *testing.T) {
|
||||
sesRndCgrEv.Event[utils.Subject] = "up"
|
||||
sesRndCgrEv.Event[utils.RequestType] = utils.META_PREPAID
|
||||
sesRndCgrEv.Event[utils.OriginID] = "RndupMETA_PREPAID"
|
||||
sesRndExpMaxUsage = 3 * time.Hour
|
||||
sesRndExpCost = 0.4
|
||||
sesRndExpBalanceValue = 3599999999999.5977
|
||||
}
|
||||
|
||||
func testSesRndItPreparePrepaidDOWN(t *testing.T) {
|
||||
sesRndCgrEv.Event[utils.Subject] = "down"
|
||||
sesRndCgrEv.Event[utils.RequestType] = utils.META_PREPAID
|
||||
sesRndCgrEv.Event[utils.OriginID] = "RnddownMETA_PREPAID"
|
||||
sesRndExpMaxUsage = 3 * time.Hour
|
||||
sesRndExpCost = 0.3
|
||||
sesRndExpBalanceValue = 3599999999999.697
|
||||
}
|
||||
|
||||
// test for 0 balance with sesRndsion terminate with 1s usage
|
||||
func testSesRndItLoadConfig(t *testing.T) {
|
||||
sesRndCfgPath = path.Join(*dataDir, "conf", "samples", sesRndCfgDIR)
|
||||
if sesRndCfg, err = config.NewCGRConfigFromPath(sesRndCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItResetDataDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(sesRndCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(sesRndCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(sesRndCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItRPCConn(t *testing.T) {
|
||||
var err error
|
||||
if sesRndRPC, err = newRPCClient(sesRndCfg.ListenCfg()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItLoadRating(t *testing.T) {
|
||||
var reply string
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPRate, &utils.TPRate{
|
||||
TPid: utils.TEST_SQL,
|
||||
ID: "RT1",
|
||||
RateSlots: []*utils.RateSlot{
|
||||
{ConnectFee: 0, Rate: 0.033, RateUnit: "1s", RateIncrement: "1s", GroupIntervalStart: "0s"},
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPRate: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPRate: ", reply)
|
||||
}
|
||||
|
||||
dr := &utils.TPDestinationRate{
|
||||
TPid: utils.TEST_SQL,
|
||||
ID: "DR_UP",
|
||||
DestinationRates: []*utils.DestinationRate{
|
||||
{DestinationId: utils.ANY, RateId: "RT1", RoundingMethod: utils.ROUNDING_UP, RoundingDecimals: 1},
|
||||
},
|
||||
}
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPDestinationRate, dr, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPDestinationRate: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPDestinationRate: ", reply)
|
||||
}
|
||||
dr.ID = "DR_DOWN"
|
||||
dr.DestinationRates[0].RoundingMethod = utils.ROUNDING_DOWN
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPDestinationRate, dr, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPDestinationRate: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPDestinationRate: ", reply)
|
||||
}
|
||||
|
||||
rp := &utils.TPRatingPlan{
|
||||
TPid: utils.TEST_SQL,
|
||||
ID: "RP_UP",
|
||||
RatingPlanBindings: []*utils.TPRatingPlanBinding{
|
||||
{DestinationRatesId: "DR_UP", TimingId: utils.ANY, Weight: 10},
|
||||
},
|
||||
}
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPRatingPlan, rp, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPRatingPlan: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPRatingPlan: ", reply)
|
||||
}
|
||||
rp.ID = "RP_DOWN"
|
||||
rp.RatingPlanBindings[0].DestinationRatesId = "DR_DOWN"
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPRatingPlan, rp, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPRatingPlan: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPRatingPlan: ", reply)
|
||||
}
|
||||
|
||||
rpf := &utils.TPRatingProfile{
|
||||
TPid: utils.TEST_SQL,
|
||||
LoadId: utils.TEST_SQL,
|
||||
Tenant: sesRndTenant,
|
||||
Category: utils.CALL,
|
||||
Subject: "up",
|
||||
RatingPlanActivations: []*utils.TPRatingActivation{{
|
||||
RatingPlanId: "RP_UP",
|
||||
FallbackSubjects: utils.EmptyString,
|
||||
}},
|
||||
}
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPRatingProfile, rpf, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPRatingProfile: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPRatingProfile: ", reply)
|
||||
}
|
||||
rpf.Subject = "down"
|
||||
rpf.RatingPlanActivations[0].RatingPlanId = "RP_DOWN"
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetTPRatingProfile, rpf, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.SetTPRatingProfile: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply received when calling APIerSv1.SetTPRatingProfile: ", reply)
|
||||
}
|
||||
|
||||
if err := sesRndRPC.Call(utils.APIerSv1LoadRatingPlan, &v1.AttrLoadRatingPlan{TPid: utils.TEST_SQL}, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.LoadRatingPlan: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Calling APIerSv1.LoadRatingPlan got reply: ", reply)
|
||||
}
|
||||
|
||||
if err := sesRndRPC.Call(utils.APIerSv1LoadRatingProfile, &utils.TPRatingProfile{
|
||||
TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL,
|
||||
Tenant: sesRndTenant, Category: utils.CALL}, &reply); err != nil {
|
||||
t.Error("Got error on APIerSv1.VOICE: ", err.Error())
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Calling APIerSv1.LoadRatingProfile got reply: ", reply)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testSesRndItAddCharger(t *testing.T) {
|
||||
//add a default charger
|
||||
var result string
|
||||
if err := sesRndRPC.Call(utils.APIerSv1SetChargerProfile, &engine.ChargerProfile{
|
||||
Tenant: sesRndTenant,
|
||||
ID: "default",
|
||||
RunID: utils.MetaDefault,
|
||||
AttributeIDs: []string{utils.META_NONE},
|
||||
Weight: 20,
|
||||
}, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItAddVoiceBalance(t *testing.T) {
|
||||
var reply string
|
||||
if err := sesRndRPC.Call(utils.APIerSv2SetBalance, utils.AttrSetBalance{
|
||||
Tenant: sesRndTenant,
|
||||
Account: sesRndAccount,
|
||||
BalanceType: utils.MONETARY,
|
||||
Value: float64(time.Hour),
|
||||
Balance: map[string]interface{}{
|
||||
utils.ID: "TestSesBal1",
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.OK {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
|
||||
var acnt engine.Account
|
||||
if err := sesRndRPC.Call(utils.APIerSv2GetAccount,
|
||||
&utils.AttrGetAccount{
|
||||
Tenant: sesRndTenant,
|
||||
Account: sesRndAccount,
|
||||
}, &acnt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := float64(time.Hour)
|
||||
if rply := acnt.BalanceMap[utils.MONETARY].GetTotalValue(); rply != expected {
|
||||
t.Errorf("Expected: %v, received: %v", expected, rply)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItPrepareCDRs(t *testing.T) {
|
||||
var reply sessions.V1InitSessionReply
|
||||
if err := sesRndRPC.Call(utils.SessionSv1InitiateSession,
|
||||
&sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
CGREvent: sesRndCgrEv,
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
} else if reply.MaxUsage != sesRndExpMaxUsage {
|
||||
t.Errorf("Unexpected MaxUsage: %v", reply.MaxUsage)
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
var rply string
|
||||
if err := sesRndRPC.Call(utils.SessionSv1TerminateSession,
|
||||
&sessions.V1TerminateSessionArgs{
|
||||
TerminateSession: true,
|
||||
CGREvent: sesRndCgrEv,
|
||||
}, &rply); err != nil {
|
||||
t.Error(err)
|
||||
} else if rply != utils.OK {
|
||||
t.Errorf("Unexpected reply: %s", rply)
|
||||
}
|
||||
|
||||
if err := sesRndRPC.Call(utils.SessionSv1ProcessCDR,
|
||||
sesRndCgrEv, &rply); err != nil {
|
||||
t.Error(err)
|
||||
} else if rply != utils.OK {
|
||||
t.Errorf("Received reply: %s", rply)
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testSesRndItCheckCdrs(t *testing.T) {
|
||||
var cdrs []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{sesRndAccount}, OriginIDs: []string{utils.IfaceAsString(sesRndCgrEv.Event[utils.OriginID])}}
|
||||
if err := sesRndRPC.Call(utils.APIerSv2GetCDRs, req, &cdrs); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(cdrs) != 1 {
|
||||
t.Fatal("Wrong number of CDRs")
|
||||
} else if cd, err := engine.IfaceAsEventCost(cdrs[0].CostDetails); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cd.Cost == nil ||
|
||||
*cd.Cost != sesRndExpCost ||
|
||||
*cd.Cost != cdrs[0].Cost {
|
||||
t.Errorf("CDR cost= %v", utils.ToJSON(cdrs[0].Cost))
|
||||
t.Errorf("CostDetails cost= %v", utils.ToJSON(cd.Cost))
|
||||
t.Errorf("Expected cost=%v", utils.ToJSON(sesRndExpCost))
|
||||
t.Log(cdrs[0].CostDetails)
|
||||
} else if len(cd.AccountSummary.BalanceSummaries) != 1 ||
|
||||
cd.AccountSummary.BalanceSummaries[0].Value != sesRndExpBalanceValue {
|
||||
t.Errorf("Unexpected AccountSummary: %v", utils.ToJSON(cd.AccountSummary))
|
||||
}
|
||||
var acnt engine.Account
|
||||
if err := sesRndRPC.Call(utils.APIerSv2GetAccount,
|
||||
&utils.AttrGetAccount{
|
||||
Tenant: sesRndTenant,
|
||||
Account: sesRndAccount,
|
||||
}, &acnt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rply := acnt.BalanceMap[utils.MONETARY].GetTotalValue(); rply != sesRndExpBalanceValue {
|
||||
t.Errorf("Expected: %+v, received: %v", utils.ToJSON(sesRndExpBalanceValue), utils.ToJSON(rply))
|
||||
}
|
||||
}
|
||||
|
||||
func testSesRndItStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -651,19 +651,30 @@ 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)
|
||||
if sr.CD != nil {
|
||||
cc.Category = sr.CD.Category
|
||||
cc.Subject = sr.CD.Subject
|
||||
cc.Tenant = sr.CD.Tenant
|
||||
cc.Account = sr.CD.Account
|
||||
cc.Destination = sr.CD.Destination
|
||||
cc.ToR = sr.CD.ToR
|
||||
}
|
||||
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
|
||||
response := new(engine.Account)
|
||||
if err = sS.connMgr.Call(sS.cgrCfg.SessionSCfg().RALsConns, nil,
|
||||
utils.ResponderRefundRounding,
|
||||
&engine.CallDescriptorWithArgDispatcher{CallDescriptor: cd},
|
||||
&response); err != nil {
|
||||
response); err != nil {
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
cc.AccountSummary = response.AsAccountSummary()
|
||||
}
|
||||
}
|
||||
sr.EventCost = engine.NewEventCostFromCallCost(cc, s.CGRID, runID)
|
||||
return
|
||||
|
||||
@@ -934,8 +934,8 @@ func testSessionsVoiceSessionTTL(t *testing.T) {
|
||||
if cdrs[0].Usage != "2m30.05s" {
|
||||
t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0])
|
||||
}
|
||||
if cdrs[0].Cost != 1.5332 {
|
||||
t.Errorf("Unexpected CDR Cost received, cdr: %v %+v ", cdrs[0].Cost, cdrs[0])
|
||||
if cdrs[0].Cost != 1.5334 {
|
||||
t.Errorf("Unexpected CDR Cost received, cdr: %v %+v ", cdrs[0].Cost, utils.ToJSON(cdrs[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user