AccountS debitUsage returning usage within EventCharges

This commit is contained in:
DanB
2021-02-02 19:56:12 +01:00
parent c9b2c64b9c
commit 89aac43d25
6 changed files with 69 additions and 29 deletions

View File

@@ -43,7 +43,7 @@ type abstractBalance struct {
// debitUsage implements the balanceOperator interface
func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
@@ -55,7 +55,7 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
if pass, err = aB.fltrS.Pass(cgrEv.Tenant, aB.blnCfg.FilterIDs, evNm); err != nil {
return
} else if !pass {
return nil, nil, utils.ErrFilterNotPassingNoCaps
return nil, utils.ErrFilterNotPassingNoCaps
}
// balanceLimit
@@ -95,7 +95,7 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
}
// attempt to debit usage with cost
if dbted, ec, err = maxDebitUsageFromConcretes(aB.cncrtBlncs, usage,
if ec, err = maxDebitUsageFromConcretes(aB.cncrtBlncs, usage,
aB.connMgr, cgrEv,
aB.attrSConns, aB.blnCfg.AttributeIDs,
aB.rateSConns, aB.blnCfg.RateProfileIDs,
@@ -103,8 +103,8 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
return
}
if dbted.Cmp(decimal.New(0, 0)) != 0 {
aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, dbted.Big)
if ec.Usage.Cmp(decimal.New(0, 0)) != 0 {
aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, ec.Usage)
}
if hasLmt { // put back the limit
aB.blnCfg.Units.Big = utils.SumBig(aB.blnCfg.Units.Big, blncLmt.Big)

View File

@@ -24,6 +24,7 @@ import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/ericlagergren/decimal"
)
func TestdebitUsageFromConcretes(t *testing.T) {
@@ -133,11 +134,11 @@ func TestABDebitUsage(t *testing.T) {
fltrS: new(engine.FilterS),
}
if dbted, _, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0),
if ec, 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)
} else if ec.Usage.Cmp(decimal.New(int64(30*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", ec.Usage)
} else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(30*time.Second), 0)) != 0 {
t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units)
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(20, 0)) != 0 {
@@ -148,11 +149,11 @@ 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(30*time.Second), 0),
if ec, 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)
} else if ec.Usage.Cmp(decimal.New(int64(29*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", ec.Usage)
} else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(31*time.Second)), 0)) != 0 { // used 29 units
t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units)
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(0, 0)) != 0 {
@@ -162,11 +163,11 @@ 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(30*time.Second), 0),
if ec, 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 ec.Usage.Cmp(decimal.New(0, 0)) != 0 {
t.Errorf("Unexpected debited units: %s", ec.Usage)
} 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
@@ -177,11 +178,11 @@ 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(30*time.Second), 0),
if ec, 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)
} else if ec.Usage.Cmp(decimal.New(int64(29*time.Second), 0)) != 0 {
t.Errorf("Unexpected debited units: %s", ec.Usage)
} 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)
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(31, 0)) != 0 {

View File

@@ -151,14 +151,15 @@ func (aS *AccountS) accountProcessEvent(acnt *utils.AccountProfile,
if usage.Big.Cmp(decimal.New(0, 0)) == 0 {
return // no more debit
}
var dbted *utils.Decimal
if dbted, _, err = blncOper.debitUsage(usage, cgrEv); err != nil {
var ecDbt *utils.EventCharges
if ec, err = blncOper.debitUsage(usage, cgrEv); err != nil {
if err == utils.ErrFilterNotPassingNoCaps {
err = nil
continue
}
}
usage.Big = utils.SubstractBig(usage.Big, dbted.Big)
usage.Big = utils.SubstractBig(usage.Big, ecDbt.Usage)
ec.Merge(ecDbt)
}
return
}

View File

@@ -111,7 +111,7 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string,
// debit implements the balanceOperator interface
func (cB *concreteBalance) debitUsage(usage *utils.Decimal,
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
@@ -123,7 +123,7 @@ func (cB *concreteBalance) debitUsage(usage *utils.Decimal,
if pass, err = cB.fltrS.Pass(cgrEv.Tenant, cB.blnCfg.FilterIDs, evNm); err != nil {
return
} else if !pass {
return nil, nil, utils.ErrFilterNotPassingNoCaps
return nil, utils.ErrFilterNotPassingNoCaps
}
// costIncrement
@@ -145,7 +145,8 @@ func (cB *concreteBalance) debitUsage(usage *utils.Decimal,
}
}
return maxDebitUsageFromConcretes([]*concreteBalance{cB}, usage,
return maxDebitUsageFromConcretes(
[]*concreteBalance{cB}, usage,
cB.connMgr, cgrEv,
cB.attrSConns, cB.blnCfg.AttributeIDs,
cB.rateSConns, cB.blnCfg.RateProfileIDs,

View File

@@ -75,7 +75,7 @@ func newBalanceOperator(blncCfg *utils.Balance, cncrtBlncs []*concreteBalance,
// balanceOperator is the implementation of a balance type
type balanceOperator interface {
debitUsage(usage *utils.Decimal, cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error)
debitUsage(usage *utils.Decimal, cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error)
}
// roundUsageWithIncrements rounds the usage based on increments
@@ -234,7 +234,7 @@ func debitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Decimal
func maxDebitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Decimal,
connMgr *engine.ConnManager, cgrEv *utils.CGREvent,
attrSConns, attributeIDs, rateSConns, rpIDs []string,
costIcrm *utils.CostIncrement) (dbtedUsage *utils.Decimal, ec *utils.EventCharges, err error) {
costIcrm *utils.CostIncrement) (ec *utils.EventCharges, err error) {
// process AttributeS if needed
if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 &&
@@ -260,7 +260,7 @@ func maxDebitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Deci
restoreUnitsFromClones(cncrtBlncs, origConcrtUnts)
}
if i == maxItr {
return nil, nil, utils.ErrMaxIncrementsExceeded
return nil, utils.ErrMaxIncrementsExceeded
}
qriedUsage := usage.Big // so we can detect loops
if err = debitUsageFromConcretes(cncrtBlncs, usage, costIcrm, cgrEv,
@@ -308,5 +308,5 @@ func maxDebitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Deci
usagePaid = decimal.New(0, 0)
}
restoreUnitsFromClones(cncrtBlncs, paidConcrtUnts)
return &utils.Decimal{usagePaid}, nil, nil
return &utils.EventCharges{Usage: usagePaid}, nil
}

View File

@@ -19,14 +19,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package utils
import (
"time"
"errors"
"github.com/ericlagergren/decimal"
)
// EventCharges records the charges applied to an Event
type EventCharges struct {
StartTime *time.Time
Usage *decimal.Big
Cost *decimal.Big
Charges []*ChargedInterval
@@ -34,3 +33,41 @@ type EventCharges struct {
Accounting *ChargedAccounting
Rating *ChargedRating
}
// Merge will merge the event charges into existing
func (ec *EventCharges) Merge(eCs ...*EventCharges) {
for _, nEc := range eCs {
if ec.Usage == nil {
ec.Usage = nEc.Usage
continue
}
ec.Usage = SumBig(ec.Usage, nEc.Usage)
}
}
// AsExtEventCharges converts EventCharges to ExtEventCharges
func (ec *EventCharges) AsExtEventCharges() (eEc *ExtEventCharges, err error) {
eEc = new(ExtEventCharges)
if ec.Usage != nil {
if flt, ok := ec.Usage.Float64(); !ok {
return nil, errors.New("cannot convert decimal Usage to float64")
} else {
eEc.Usage = &flt
}
}
if ec.Cost != nil {
if flt, ok := ec.Cost.Float64(); !ok {
return nil, errors.New("cannot convert decimal Cost to float64")
} else {
eEc.Cost = &flt
}
}
// add here code for the rest of the fields
return
}
// ExtEventCharges is a generic EventCharges used in APIs
type ExtEventCharges struct {
Usage *float64
Cost *float64
}