AccountS - debitUsage without startTime, standalone processAttributes method

This commit is contained in:
DanB
2021-01-29 18:38:37 +01:00
parent 79965a939b
commit 7b208bd10c
4 changed files with 107 additions and 62 deletions

View File

@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package accounts
import (
"time"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/ericlagergren/decimal"
@@ -94,30 +92,6 @@ func (aB *abstractBalance) balanceLimit() (bL *utils.Decimal) {
return
}
// processAttributeS will process the event with AttributeS
func (aB *abstractBalance) processAttributeS(cgrEv *utils.CGREvent) (rplyEv *engine.AttrSProcessEventReply, err error) {
if len(aB.attrSConns) == 0 {
return nil, utils.NewErrNotConnected(utils.AttributeS)
}
var procRuns *int
if val, has := cgrEv.Opts[utils.OptsAttributesProcessRuns]; has {
if v, err := utils.IfaceAsTInt64(val); err == nil {
procRuns = utils.IntPointer(int(v))
}
}
attrArgs := &engine.AttrArgsProcessEvent{
Context: utils.StringPointer(utils.FirstNonEmpty(
engine.MapEvent(cgrEv.Opts).GetStringIgnoreErrors(utils.OptsContext),
utils.MetaAccountS)),
CGREvent: cgrEv,
AttributeIDs: aB.blnCfg.AttributeIDs,
ProcessRuns: procRuns,
}
err = aB.connMgr.Call(aB.attrSConns, nil, utils.AttributeSv1ProcessEvent,
attrArgs, &rplyEv)
return
}
// rateSCostForEvent will process the event with RateS in order to get the cost
func (aB *abstractBalance) rateSCostForEvent(cgrEv *utils.CGREvent) (rplyCost *engine.RateProfileCost, err error) {
if len(aB.rateSConns) == 0 {
@@ -177,7 +151,7 @@ func (aB *abstractBalance) debitUsageFromConcrete(usage *utils.Decimal,
}
// debitUsage implements the balanceOperator interface
func (aB *abstractBalance) debitUsage(usage *utils.Decimal, startTime time.Time,
func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
@@ -202,7 +176,8 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, startTime time.Time,
costIcrm.FixedFee == nil &&
len(aB.blnCfg.AttributeIDs) != 0 { // cost unknown, apply AttributeS to query from RateS
var rplyAttrS *engine.AttrSProcessEventReply
if rplyAttrS, err = aB.processAttributeS(cgrEv); err != nil {
if rplyAttrS, err = processAttributeS(aB.connMgr, cgrEv, aB.attrSConns,
aB.blnCfg.AttributeIDs); err != nil {
return
}
if len(rplyAttrS.AlteredFields) != 0 { // event was altered

View File

@@ -133,8 +133,8 @@ func TestABDebitUsage(t *testing.T) {
fltrS: new(engine.FilterS),
}
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0),
time.Now(), new(utils.CGREvent)); err != nil {
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0),
new(utils.CGREvent)); err != nil {
t.Error(err)
} else if dbted.Compare(utils.NewDecimal(int64(30*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", dbted)
@@ -148,8 +148,8 @@ func TestABDebitUsage(t *testing.T) {
aB.blnCfg.Units = utils.NewDecimal(int64(time.Duration(60*time.Second)), 0)
aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(29, 0) // not enough concrete
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0),
time.Now(), new(utils.CGREvent)); err != nil {
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0),
new(utils.CGREvent)); err != nil {
t.Error(err)
} else if dbted.Compare(utils.NewDecimal(int64(29*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", dbted)
@@ -162,12 +162,12 @@ func TestABDebitUsage(t *testing.T) {
// limited by concrete
aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(0, 0) // not enough concrete
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0),
time.Now(), new(utils.CGREvent)); err != nil {
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0),
new(utils.CGREvent)); err != nil {
t.Error(err)
} else if dbted.Compare(utils.NewDecimal(0, 0)) != 0 {
t.Errorf("Unexpected debited units: %s", dbted)
} else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(31*time.Second)), 0)) != 0 { // same as above
} else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(31*time.Second), 0)) != 0 { // same as above
t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units)
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(0, 0)) != 0 { // same as above
t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units)
@@ -177,10 +177,10 @@ func TestABDebitUsage(t *testing.T) {
aB.blnCfg.Units = utils.NewDecimal(int64(time.Duration(29*time.Second)), 0) // not enough abstract
aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(60, 0)
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0),
time.Now(), new(utils.CGREvent)); err != nil {
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0),
new(utils.CGREvent)); err != nil {
t.Error(err)
} else if dbted.Compare(utils.NewDecimal(int64(time.Duration(29*time.Second)), 0)) != 0 {
} else if dbted.Compare(utils.NewDecimal(int64(29*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", dbted)
} else if aB.blnCfg.Units.Compare(utils.NewDecimal(0, 0)) != 0 { // should be all used
t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units)

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package accounts
import (
"time"
"fmt"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
@@ -91,26 +91,6 @@ func (cB *concreteBalance) balanceLimit() (bL *utils.Decimal) {
return
}
// debit implements the balanceOperator interface
func (cB *concreteBalance) debitUsage(usage *utils.Decimal, startTime time.Time,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
utils.MetaReq: cgrEv.Event,
}
// pass the general balance filters
var pass bool
if pass, err = cB.fltrS.Pass(cgrEv.Tenant, cB.blnCfg.FilterIDs, evNm); err != nil {
return
} else if !pass {
return nil, nil, utils.ErrFilterNotPassingNoCaps
}
return
}
// debitUnits is a direct debit of balance units
func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string,
ev utils.DataProvider) (dbted *utils.Decimal, uF *utils.UnitFactor, err error) {
@@ -158,6 +138,72 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string,
return
}
// debit implements the balanceOperator interface
func (cB *concreteBalance) debitUsage(usage *utils.Decimal,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
utils.MetaReq: cgrEv.Event,
}
// pass the general balance filters
var pass bool
if pass, err = cB.fltrS.Pass(cgrEv.Tenant, cB.blnCfg.FilterIDs, evNm); err != nil {
return
} else if !pass {
return nil, nil, utils.ErrFilterNotPassingNoCaps
}
// costIncrement
var costIcrm *utils.CostIncrement
if costIcrm, err = cB.costIncrement(cgrEv.Tenant, evNm); err != nil {
return
}
if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 &&
costIcrm.FixedFee == nil &&
len(cB.blnCfg.AttributeIDs) != 0 { // cost unknown, apply AttributeS to query from RateS
var rplyAttrS *engine.AttrSProcessEventReply
if rplyAttrS, err = processAttributeS(cB.connMgr, cgrEv, cB.attrSConns,
cB.blnCfg.AttributeIDs); err != nil {
return
}
if len(rplyAttrS.AlteredFields) != 0 { // event was altered
cgrEv = rplyAttrS.CGREvent
}
}
// balanceLimit
var hasLmt bool
blncLmt := cB.balanceLimit()
if blncLmt != nil && blncLmt.Cmp(decimal.New(0, 0)) != 0 {
cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, blncLmt.Big)
hasLmt = true
}
// unitFactor
var uF *utils.UnitFactor
if uF, err = cB.unitFactor(cgrEv.Tenant, evNm); err != nil {
return
}
var hasUF bool
if uF != nil && uF.Factor.Cmp(decimal.New(1, 0)) != 0 {
usage.Big = utils.MultiplyBig(usage.Big, uF.Factor.Big)
hasUF = true
}
// balance smaller than usage, correct usage
if cB.blnCfg.Units.Compare(usage) == -1 {
// decrease the usage to match the maximum increments
// will use special rounding to 0 since otherwise we go negative (ie: 0.05 as increment)
usage.Big = roundedUsageWithIncrements(cB.blnCfg.Units.Big, costIcrm.Increment.Big)
}
fmt.Printf("hasLmt: %v, hasUF: %v\n", hasLmt, hasUF)
return
}
// cloneUnitsFromConcretes returns cloned units from the concrete balances passed as parameters
func cloneUnitsFromConcretes(cBs []*concreteBalance) (clnedUnts []*utils.Decimal) {
if cBs == nil {
@@ -170,6 +216,7 @@ func cloneUnitsFromConcretes(cBs []*concreteBalance) (clnedUnts []*utils.Decimal
return
}
// restoreUnitsFromClones will restore the units from the clones
func restoreUnitsFromClones(cBs []*concreteBalance, clnedUnts []*utils.Decimal) {
for i, clnedUnt := range clnedUnts {
cBs[i].blnCfg.Units.Big = clnedUnt.Big

View File

@@ -20,7 +20,6 @@ package accounts
import (
"fmt"
"time"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
@@ -91,8 +90,7 @@ func newBalanceOperator(blncCfg *utils.Balance, cncrtBlncs []*concreteBalance,
// balanceOperator is the implementation of a balance type
type balanceOperator interface {
debitUsage(usage *utils.Decimal, startTime time.Time,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error)
debitUsage(usage *utils.Decimal, cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error)
}
// roundUsageWithIncrements rounds the usage based on increments
@@ -103,3 +101,28 @@ func roundedUsageWithIncrements(usage, incrm *decimal.Big) (rndedUsage *decimal.
rndedUsage = utils.MultiplyBig(usgMaxIncrm, incrm)
return
}
// processAttributeS will process the event with AttributeS
func processAttributeS(connMgr *engine.ConnManager, cgrEv *utils.CGREvent,
attrSConns, attrIDs []string) (rplyEv *engine.AttrSProcessEventReply, err error) {
if len(attrSConns) == 0 {
return nil, utils.NewErrNotConnected(utils.AttributeS)
}
var procRuns *int
if val, has := cgrEv.Opts[utils.OptsAttributesProcessRuns]; has {
if v, err := utils.IfaceAsTInt64(val); err == nil {
procRuns = utils.IntPointer(int(v))
}
}
attrArgs := &engine.AttrArgsProcessEvent{
Context: utils.StringPointer(utils.FirstNonEmpty(
engine.MapEvent(cgrEv.Opts).GetStringIgnoreErrors(utils.OptsContext),
utils.MetaAccountS)),
CGREvent: cgrEv,
AttributeIDs: attrIDs,
ProcessRuns: procRuns,
}
err = connMgr.Call(attrSConns, nil, utils.AttributeSv1ProcessEvent,
attrArgs, &rplyEv)
return
}