From 7465f25ba0a61aeee85904f2b7748311b6f8a3af Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 8 Feb 2021 17:10:46 +0100 Subject: [PATCH] RateS - return ErrNotFound in case of no profile matched, AccountS - testAccountSv1MaxUsage --- accounts/abstractbalance.go | 1 - accounts/accounts.go | 27 ++++++++---- accounts/concretebalance.go | 1 - accounts/libaccounts.go | 18 +++++--- apier/v1/accountprofiles.go | 8 ++-- apier/v1/accountsv1_it_test.go | 41 ++++++++++++++----- .../tutaccounts/AccountProfiles.csv | 4 +- rates/rates.go | 10 ++++- utils/errors.go | 5 +++ utils/eventcharges.go | 6 +++ 10 files changed, 87 insertions(+), 34 deletions(-) diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go index db3a8e204..cd0647b14 100644 --- a/accounts/abstractbalance.go +++ b/accounts/abstractbalance.go @@ -93,7 +93,6 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, // will use special rounding to 0 since otherwise we go negative (ie: 0.05 as increment) usage.Big = roundedUsageWithIncrements(aB.blnCfg.Units.Big, costIcrm.Increment.Big) } - // attempt to debit usage with cost if ec, err = maxDebitUsageFromConcretes(aB.cncrtBlncs, usage, aB.connMgr, cgrEv, diff --git a/accounts/accounts.go b/accounts/accounts.go index 0739272b0..2a6c9ebc8 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -176,17 +176,20 @@ func (aS *AccountS) accountProcessEvent(acnt *utils.AccountProfile, } else { usage.Big = decimal.New(int64(usgEv), 0) } - - for _, blncOper := range blncOpers { + for i, blncOper := range blncOpers { + if i == 0 { + ec = utils.NewEventCharges() + } if usage.Big.Cmp(decimal.New(0, 0)) == 0 { return // no more debit } var ecDbt *utils.EventCharges - if ec, err = blncOper.debitUsage(usage, cgrEv); err != nil { + if ecDbt, err = blncOper.debitUsage(usage.Clone(), cgrEv); err != nil { if err == utils.ErrFilterNotPassingNoCaps { err = nil continue } + return } usage.Big = utils.SubstractBig(usage.Big, ecDbt.Usage) ec.Merge(ecDbt) @@ -209,7 +212,7 @@ func (aS *AccountS) V1AccountProfileForEvent(args *utils.ArgsAccountForEvent, ap } // V1MaxUsage returns the maximum usage for the event, based on matching Account -func (aS *AccountS) V1MaxUsage(args *utils.ArgsAccountForEvent, ec *utils.EventCharges) (err error) { +func (aS *AccountS) V1MaxUsage(args *utils.ArgsAccountForEvent, eEc *utils.ExtEventCharges) (err error) { var acnt *utils.AccountProfile var lkID string if acnt, lkID, err = aS.matchingAccountForEvent(args.CGREvent.Tenant, @@ -225,13 +228,16 @@ func (aS *AccountS) V1MaxUsage(args *utils.ArgsAccountForEvent, ec *utils.EventC if procEC, err = aS.accountProcessEvent(acnt, args.CGREvent); err != nil { return } - - *ec = *procEC + var rcvEec *utils.ExtEventCharges + if rcvEec, err = procEC.AsExtEventCharges(); err != nil { + return + } + *eEc = *rcvEec return } // V1DebitUsage performs debit for the provided event -func (aS *AccountS) V1DebitUsage(args *utils.ArgsAccountForEvent, ec *utils.EventCharges) (err error) { +func (aS *AccountS) V1DebitUsage(args *utils.ArgsAccountForEvent, eEc *utils.ExtEventCharges) (err error) { var acnt *utils.AccountProfile var lkID string if acnt, lkID, err = aS.matchingAccountForEvent(args.CGREvent.Tenant, @@ -248,10 +254,15 @@ func (aS *AccountS) V1DebitUsage(args *utils.ArgsAccountForEvent, ec *utils.Even return } + var rcvEec *utils.ExtEventCharges + if rcvEec, err = procEC.AsExtEventCharges(); err != nil { + return + } + if err = aS.dm.SetAccountProfile(acnt, false); err != nil { return // no need of revert since we did not save } - *ec = *procEC + *eEc = *rcvEec return } diff --git a/accounts/concretebalance.go b/accounts/concretebalance.go index d35242feb..0ce015145 100644 --- a/accounts/concretebalance.go +++ b/accounts/concretebalance.go @@ -112,7 +112,6 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string, // debit implements the balanceOperator interface func (cB *concreteBalance) debitUsage(usage *utils.Decimal, cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) { - evNm := utils.MapStorage{ utils.MetaOpts: cgrEv.Opts, utils.MetaReq: cgrEv.Event, diff --git a/accounts/libaccounts.go b/accounts/libaccounts.go index 86332a461..9776f85c4 100644 --- a/accounts/libaccounts.go +++ b/accounts/libaccounts.go @@ -40,13 +40,19 @@ func newAccountBalanceOperators(acnt *utils.AccountProfile, } blnCfgs.Sort() - var cncrtBlncs []*concreteBalance blncOpers = make([]balanceOperator, len(blnCfgs)) - for i, blnCfg := range blnCfgs { + var cncrtBlncs []*concreteBalance + for i, blnCfg := range blnCfgs { // build the concrete balances + if blnCfg.Type != utils.MetaConcrete { + continue + } + blncOpers[i] = newConcreteBalanceOperator(blnCfg, + fltrS, connMgr, attrSConns, rateSConns) + cncrtBlncs = append(cncrtBlncs, blncOpers[i].(*concreteBalance)) + } + + for i, blnCfg := range blnCfgs { // build the abstract balances if blnCfg.Type == utils.MetaConcrete { - blncOpers[i] = newConcreteBalanceOperator(blnCfg, - fltrS, connMgr, attrSConns, rateSConns) - cncrtBlncs = append(cncrtBlncs, blncOpers[i].(*concreteBalance)) continue } if blncOpers[i], err = newBalanceOperator(blnCfg, cncrtBlncs, fltrS, connMgr, @@ -189,6 +195,7 @@ func debitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Decimal costIcrm.FixedFee == nil { var rplyCost *engine.RateProfileCost if rplyCost, err = rateSCostForEvent(connMgr, cgrEv, rateSConns, rpIDs); err != nil { + err = utils.NewErrRateS(err) return } costIcrm = costIcrm.Clone() // so we don't modify the original @@ -235,7 +242,6 @@ func maxDebitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Deci connMgr *engine.ConnManager, cgrEv *utils.CGREvent, attrSConns, attributeIDs, rateSConns, rpIDs []string, costIcrm *utils.CostIncrement) (ec *utils.EventCharges, err error) { - // process AttributeS if needed if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 && costIcrm.FixedFee == nil && diff --git a/apier/v1/accountprofiles.go b/apier/v1/accountprofiles.go index 23e1dbb7f..8b17c268b 100644 --- a/apier/v1/accountprofiles.go +++ b/apier/v1/accountprofiles.go @@ -166,12 +166,12 @@ func (aSv1 *AccountSv1) AccountProfileForEvent(args *utils.ArgsAccountForEvent, // MaxUsage returns the maximum usage for the event, based on matching Account func (aSv1 *AccountSv1) MaxUsage(args *utils.ArgsAccountForEvent, - ec *utils.EventCharges) (err error) { - return aSv1.aS.V1MaxUsage(args, ec) + eEc *utils.ExtEventCharges) (err error) { + return aSv1.aS.V1MaxUsage(args, eEc) } // DebitUsage performs debit for the provided event func (aSv1 *AccountSv1) DebitUsage(args *utils.ArgsAccountForEvent, - ec *utils.EventCharges) (err error) { - return aSv1.aS.V1DebitUsage(args, ec) + eEc *utils.ExtEventCharges) (err error) { + return aSv1.aS.V1DebitUsage(args, eEc) } diff --git a/apier/v1/accountsv1_it_test.go b/apier/v1/accountsv1_it_test.go index 9fe4a5175..459e89836 100644 --- a/apier/v1/accountsv1_it_test.go +++ b/apier/v1/accountsv1_it_test.go @@ -51,6 +51,7 @@ func TestAccountSv1IT(t *testing.T) { testAccountSv1RPCConn, testAccountSv1LoadFromFolder, testAccountSv1AccountProfileForEvent, + testAccountSv1MaxUsage, } switch *dbType { case utils.MetaInternal: @@ -144,13 +145,9 @@ func testAccountSv1AccountProfileForEvent(t *testing.T) { AttributeIDs: []string{}, RateProfileIDs: []string{}, UnitFactors: []*utils.UnitFactor{ - &utils.UnitFactor{ - FilterIDs: []string{"*string:~*req.ToR:*voice"}, - Factor: &utils.Decimal{decimal.New(int64(time.Second), 0)}, - }, &utils.UnitFactor{ FilterIDs: []string{"*string:~*req.ToR:*data"}, - Factor: &utils.Decimal{decimal.New(int64(1024*time.Second), 0)}, + Factor: &utils.Decimal{decimal.New(1024, 3)}, }, }, Units: &utils.Decimal{decimal.New(int64(time.Hour), 0)}, @@ -180,11 +177,18 @@ func testAccountSv1AccountProfileForEvent(t *testing.T) { Units: &utils.Decimal{decimal.New(5, 0)}, }, "MonetaryBalance2": &utils.Balance{ - ID: "MonetaryBalance2", - FilterIDs: []string{}, - Weight: 10, - Type: utils.MetaConcrete, - CostIncrements: []*utils.CostIncrement{}, + ID: "MonetaryBalance2", + FilterIDs: []string{}, + Weight: 10, + Type: utils.MetaConcrete, + CostIncrements: []*utils.CostIncrement{ + &utils.CostIncrement{ + FilterIDs: []string{"*string:~*req.ToR:*voice"}, + Increment: &utils.Decimal{decimal.New(int64(time.Second), 0)}, + FixedFee: &utils.Decimal{decimal.New(0, 0)}, + RecurrentFee: &utils.Decimal{decimal.New(1, 0)}, + }, + }, AttributeIDs: []string{}, RateProfileIDs: []string{}, UnitFactors: []*utils.UnitFactor{}, @@ -206,3 +210,20 @@ func testAccountSv1AccountProfileForEvent(t *testing.T) { t.Errorf("Expecting : %s \n received: %s", utils.ToJSON(eAcnt), utils.ToJSON(acnt)) } } + +func testAccountSv1MaxUsage(t *testing.T) { + var eEc *utils.ExtEventCharges + if err := acntSRPC.Call(utils.AccountSv1MaxUsage, + &utils.ArgsAccountForEvent{CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAccountSv1MaxUsage", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.ToR: utils.MetaVoice, + utils.Usage: "15m", + }}}, &eEc); err != nil { + t.Error(err) + } else if eEc.Usage == nil || *eEc.Usage != 800000000000.0 { // 500s from first monetary + 300s from last monetary + t.Errorf("received usage: %v", *eEc.Usage) + } +} diff --git a/data/tariffplans/tutaccounts/AccountProfiles.csv b/data/tariffplans/tutaccounts/AccountProfiles.csv index 87413f880..e38a338c1 100644 --- a/data/tariffplans/tutaccounts/AccountProfiles.csv +++ b/data/tariffplans/tutaccounts/AccountProfiles.csv @@ -1,5 +1,5 @@ #Tenant,ID,FilterIDs,ActivationInterval,Weight,BalanceID,BalanceFilterIDs,BalanceWeight,BalanceBlocker,BalanceType,BalanceOpts,BalanceCostIncrements,BalanceAttributeIDs,BalanceRateProfileIDs,BalanceUnitFactors,BalanceUnits,ThresholdIDs cgrates.org,1001,*string:~*req.Account:1001,,,MonetaryBalance1,,30,,*concrete,,*string:~*req.ToR:*voice;1000000000;0;0.01;*string:~*req.ToR:*data;1024;0;0.01,,,,5,*none -cgrates.org,1001,,,,GenericBalance1,,20,,*abstract,,*string:~*req.ToR:*voice;1000000000;0;0.01;*string:~*req.ToR:*data;1024;0;0.01,,,*string:~*req.ToR:*voice;1000000000;*string:~*req.ToR:*data;1024000000000,3600000000000, -cgrates.org,1001,,,,MonetaryBalance2,,10,,*concrete,,,,,,3, +cgrates.org,1001,,,,GenericBalance1,,20,,*abstract,,*string:~*req.ToR:*voice;1000000000;0;0.01;*string:~*req.ToR:*data;1024;0;0.01,,,*string:~*req.ToR:*data;1.024,3600000000000, +cgrates.org,1001,,,,MonetaryBalance2,,10,,*concrete,,*string:~*req.ToR:*voice;1000000000;0;1,,,,3, cgrates.org,1002,*string:~*req.Account:1002,,10,MonetaryBalance1,,,,*concrete,,*string:~*req.ToR:*voice;1000000000;0;0.01;;1;0;1,,,,10,*none diff --git a/rates/rates.go b/rates/rates.go index c41a36c0d..9214e589b 100644 --- a/rates/rates.go +++ b/rates/rates.go @@ -198,10 +198,16 @@ func (rS *RateS) V1CostForEvent(args *utils.ArgsCostForEvent, rpCost *engine.Rat } var rtPrl *engine.RateProfile if rtPrl, err = rS.matchingRateProfileForEvent(args.Tenant, rPfIDs, args); err != nil { - return utils.NewErrServerError(err) + if err != utils.ErrNotFound { + err = utils.NewErrServerError(err) + } + return } if rcvCost, errCost := rS.rateProfileCostForEvent(rtPrl, args, rS.cfg.RateSCfg().Verbosity); errCost != nil { - return utils.NewErrServerError(errCost) + if errCost != utils.ErrNotFound { + errCost = utils.NewErrServerError(err) + } + return errCost } else { *rpCost = *rcvCost } diff --git a/utils/errors.go b/utils/errors.go index 539da27cd..80bf4e2a7 100644 --- a/utils/errors.go +++ b/utils/errors.go @@ -65,6 +65,7 @@ var ( ErrNotConnected = errors.New("NOT_CONNECTED") RalsErrorPrfx = "RALS_ERROR" DispatcherErrorPrefix = "DISPATCHER_ERROR" + RateSErrPrfx = "RATES_ERROR" ErrUnsupportedFormat = errors.New("UNSUPPORTED_FORMAT") ErrNoDatabaseConn = errors.New("NO_DATA_BASE_CONNECTION") ErrMaxIncrementsExceeded = errors.New("MAX_INCREMENTS_EXCEEDED") @@ -204,6 +205,10 @@ func NewErrDispatcherS(err error) error { return fmt.Errorf("%s:%s", DispatcherErrorPrefix, err.Error()) } +func NewErrRateS(err error) error { + return fmt.Errorf("%s:%s", RateSErrPrfx, err.Error()) +} + // Centralized returns for APIs func APIErrorHandler(errIn error) (err error) { cgrErr, ok := errIn.(*CGRError) diff --git a/utils/eventcharges.go b/utils/eventcharges.go index cc771bcdf..5f7627e92 100644 --- a/utils/eventcharges.go +++ b/utils/eventcharges.go @@ -24,6 +24,12 @@ import ( "github.com/ericlagergren/decimal" ) +// NewEventChargers instantiates the EventChargers in a central place +func NewEventCharges() (ec *EventCharges) { + ec = new(EventCharges) + return +} + // EventCharges records the charges applied to an Event type EventCharges struct { Usage *decimal.Big