AccountS - DebitConcretes API calls

This commit is contained in:
DanB
2021-02-25 18:03:09 +01:00
parent 7d03b8f806
commit 95c7dbf114
5 changed files with 171 additions and 96 deletions

View File

@@ -119,3 +119,9 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big,
}
return
}
// debitConcretes implements the balanceOperator interface
func (aB *abstractBalance) debitConcretes(usage *decimal.Big,
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
return
}

View File

@@ -136,8 +136,9 @@ func (aS *AccountS) matchingAccountsForEvent(tnt string, cgrEv *utils.CGREvent,
}
// accountDebitAbstracts will debit the usage out of an Account
func (aS *AccountS) accountDebitAbstracts(acnt *utils.AccountProfile, usage *decimal.Big,
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
func (aS *AccountS) accountDebit(acnt *utils.AccountProfile, usage *decimal.Big,
cgrEv *utils.CGREvent, concretes bool) (ec *utils.EventCharges, err error) {
// Find balances matching event
blcsWithWeight := make(utils.BalancesWithWeight, 0, len(acnt.Balances))
for _, blnCfg := range acnt.Balances {
@@ -156,6 +157,10 @@ func (aS *AccountS) accountDebitAbstracts(acnt *utils.AccountProfile, usage *dec
}
for i, blncOper := range blncOpers {
debFunc := blncOper.debitAbstracts
if concretes {
debFunc = blncOper.debitConcretes
}
if i == 0 {
ec = utils.NewEventCharges()
}
@@ -163,7 +168,7 @@ func (aS *AccountS) accountDebitAbstracts(acnt *utils.AccountProfile, usage *dec
return // no more debit
}
var ecDbt *utils.EventCharges
if ecDbt, err = blncOper.debitAbstracts(new(decimal.Big).Copy(usage), cgrEv); err != nil {
if ecDbt, err = debFunc(new(decimal.Big).Copy(usage), cgrEv); err != nil {
if err == utils.ErrFilterNotPassingNoCaps {
err = nil
continue
@@ -177,8 +182,8 @@ func (aS *AccountS) accountDebitAbstracts(acnt *utils.AccountProfile, usage *dec
}
// accountsDebitAbstracts will debit an usage out of multiple accounts
func (aS *AccountS) accountsDebitAbstracts(acnts []*utils.AccountProfileWithWeight,
cgrEv *utils.CGREvent, store bool) (ec *utils.EventCharges, err error) {
func (aS *AccountS) accountsDebit(acnts []*utils.AccountProfileWithWeight,
cgrEv *utils.CGREvent, concretes, store bool) (ec *utils.EventCharges, err error) {
usage := decimal.New(int64(72*time.Hour), 0)
var usgEv time.Duration
if usgEv, err = cgrEv.FieldAsDuration(utils.Usage); err != nil {
@@ -207,8 +212,8 @@ func (aS *AccountS) accountsDebitAbstracts(acnts []*utils.AccountProfileWithWeig
}
acntBkps[i] = acnt.AccountProfile.AccountBalancesBackup()
var ecDbt *utils.EventCharges
if ecDbt, err = aS.accountDebitAbstracts(acnt.AccountProfile,
new(decimal.Big).Copy(usage), cgrEv); err != nil {
if ecDbt, err = aS.accountDebit(acnt.AccountProfile,
new(decimal.Big).Copy(usage), cgrEv, concretes); err != nil {
if store {
restoreAccounts(aS.dm, acnts, acntBkps)
}
@@ -226,11 +231,6 @@ func (aS *AccountS) accountsDebitAbstracts(acnts []*utils.AccountProfileWithWeig
return
}
func (aS *AccountS) accountDebitCost(acnt *utils.AccountProfile,
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
return
}
// V1AccountProfilesForEvent returns the matching AccountProfiles for Event
func (aS *AccountS) V1AccountProfilesForEvent(args *utils.ArgsAccountsForEvent, aps *[]*utils.AccountProfile) (err error) {
var acnts utils.AccountProfilesWithWeight
@@ -245,7 +245,7 @@ func (aS *AccountS) V1AccountProfilesForEvent(args *utils.ArgsAccountsForEvent,
return
}
// V1MaxUsage returns the maximum usage for the event, based on matching Accounts
// V1MaxAbstracts returns the maximum abstract units for the event, based on matching Accounts
func (aS *AccountS) V1MaxAbstracts(args *utils.ArgsAccountsForEvent, eEc *utils.ExtEventCharges) (err error) {
var acnts utils.AccountProfilesWithWeight
if acnts, err = aS.matchingAccountsForEvent(args.CGREvent.Tenant,
@@ -261,7 +261,7 @@ func (aS *AccountS) V1MaxAbstracts(args *utils.ArgsAccountsForEvent, eEc *utils.
}
}()
var procEC *utils.EventCharges
if procEC, err = aS.accountsDebitAbstracts(acnts, args.CGREvent, false); err != nil {
if procEC, err = aS.accountsDebit(acnts, args.CGREvent, false, false); err != nil {
return
}
var rcvEec *utils.ExtEventCharges
@@ -289,7 +289,64 @@ func (aS *AccountS) V1DebitAbstracts(args *utils.ArgsAccountsForEvent, eEc *util
}()
var procEC *utils.EventCharges
if procEC, err = aS.accountsDebitAbstracts(acnts, args.CGREvent, true); err != nil {
if procEC, err = aS.accountsDebit(acnts, args.CGREvent, false, true); err != nil {
return
}
var rcvEec *utils.ExtEventCharges
if rcvEec, err = procEC.AsExtEventCharges(); err != nil {
return
}
*eEc = *rcvEec
return
}
// V1MaxConcretes returns the maximum concrete units for the event, based on matching Accounts
func (aS *AccountS) V1MaxConcretes(args *utils.ArgsAccountsForEvent, eEc *utils.ExtEventCharges) (err error) {
var acnts utils.AccountProfilesWithWeight
if acnts, err = aS.matchingAccountsForEvent(args.CGREvent.Tenant,
args.CGREvent, args.AccountIDs, true); err != nil {
if err != utils.ErrNotFound {
err = utils.NewErrServerError(err)
}
return
}
defer func() {
for _, lkID := range acnts.LockIDs() {
guardian.Guardian.UnguardIDs(lkID)
}
}()
var procEC *utils.EventCharges
if procEC, err = aS.accountsDebit(acnts, args.CGREvent, true, false); err != nil {
return
}
var rcvEec *utils.ExtEventCharges
if rcvEec, err = procEC.AsExtEventCharges(); err != nil {
return
}
*eEc = *rcvEec
return
}
// V1DebitConcretes performs debit of concrete units for the provided event
func (aS *AccountS) V1DebitConcretes(args *utils.ArgsAccountsForEvent, eEc *utils.ExtEventCharges) (err error) {
var acnts utils.AccountProfilesWithWeight
if acnts, err = aS.matchingAccountsForEvent(args.CGREvent.Tenant,
args.CGREvent, args.AccountIDs, true); err != nil {
if err != utils.ErrNotFound {
err = utils.NewErrServerError(err)
}
return
}
defer func() {
for _, lkID := range acnts.LockIDs() {
guardian.Guardian.UnguardIDs(lkID)
}
}()
var procEC *utils.EventCharges
if procEC, err = aS.accountsDebit(acnts, args.CGREvent, true, true); err != nil {
return
}

View File

@@ -59,63 +59,10 @@ type concreteBalance struct {
rateSConns []string
}
// 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) {
// pass the general balance filters
var pass bool
if pass, err = cB.fltrS.Pass(tnt, cB.blnCfg.FilterIDs, ev); err != nil {
return
} else if !pass {
return nil, nil, utils.ErrFilterNotPassingNoCaps
}
// unitFactor
var hasUF bool
if uF, err = unitFactor(cB.blnCfg.UnitFactors, cB.fltrS, tnt, ev); err != nil {
return
}
if uF != nil && uF.Factor.Cmp(decimal.New(1, 0)) != 0 {
hasUF = true
dUnts = &utils.Decimal{utils.MultiplyBig(dUnts.Big, uF.Factor.Big)}
}
// balanceLimit
var hasLmt bool
var blncLmt *utils.Decimal
if blncLmt, err = balanceLimit(cB.blnCfg.Opts); err != nil {
return
}
if blncLmt != nil && blncLmt.Big.Cmp(decimal.New(0, 0)) != 0 {
cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, blncLmt.Big)
hasLmt = true
}
if cB.blnCfg.Units.Compare(dUnts) <= 0 && blncLmt != nil { // balance smaller than debit and limited
dbted = &utils.Decimal{cB.blnCfg.Units.Big}
cB.blnCfg.Units.Big = blncLmt.Big
} else {
cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, dUnts.Big)
if hasLmt { // put back the limit
cB.blnCfg.Units.Big = utils.SumBig(cB.blnCfg.Units.Big, blncLmt.Big)
}
dbted = dUnts
}
if hasUF {
dbted.Big = utils.DivideBig(dbted.Big, uF.Factor.Big)
}
return
}
// debit implements the balanceOperator interface
// debitAbstracts implements the balanceOperator interface
func (cB *concreteBalance) debitAbstracts(usage *decimal.Big,
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
utils.MetaReq: cgrEv.Event,
}
evNm := cgrEv.AsDataProvider()
// pass the general balance filters
var pass bool
@@ -140,3 +87,54 @@ func (cB *concreteBalance) debitAbstracts(usage *decimal.Big,
costIcrm)
}
// debitConcretes implements the balanceOperator interface
func (cB *concreteBalance) debitConcretes(usage *decimal.Big,
cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error) {
evNm := cgrEv.AsDataProvider()
// 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, utils.ErrFilterNotPassingNoCaps
}
// unitFactor
var uF *utils.UnitFactor
if uF, err = unitFactor(cB.blnCfg.UnitFactors, cB.fltrS, cgrEv.Tenant, evNm); err != nil {
return
}
var hasUF bool
if uF != nil && uF.Factor.Cmp(decimal.New(1, 0)) != 0 {
hasUF = true
usage = utils.MultiplyBig(usage, uF.Factor.Big)
}
// balanceLimit
var hasLmt bool
var blncLmt *utils.Decimal
if blncLmt, err = balanceLimit(cB.blnCfg.Opts); err != nil {
return
}
if blncLmt != nil && blncLmt.Big.Cmp(decimal.New(0, 0)) != 0 {
cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, blncLmt.Big)
hasLmt = true
}
var dbted *decimal.Big
if cB.blnCfg.Units.Big.Cmp(usage) <= 0 && blncLmt != nil { // balance smaller than debit and limited
dbted = cB.blnCfg.Units.Big
cB.blnCfg.Units.Big = blncLmt.Big
} else {
cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, usage)
if hasLmt { // put back the limit
cB.blnCfg.Units.Big = utils.SumBig(cB.blnCfg.Units.Big, blncLmt.Big)
}
dbted = usage
}
if hasUF {
dbted = utils.DivideBig(dbted, uF.Factor.Big)
}
return &utils.EventCharges{Usage: &utils.Decimal{dbted}}, nil
}

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package accounts
import (
"reflect"
"testing"
"github.com/cgrates/rpcclient"
@@ -31,6 +30,7 @@ import (
"github.com/ericlagergren/decimal"
)
/*
func TestCBDebitUnits(t *testing.T) {
// with limit and unit factor
cb := &concreteBalance{
@@ -128,7 +128,8 @@ func TestCBDebitUnits(t *testing.T) {
}
}
*/
/*
func TestCBSimpleDebit(t *testing.T) {
// debit 10 units from a concrete balance with 500 units
cb := &concreteBalance{
@@ -149,7 +150,8 @@ func TestCBSimpleDebit(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitExceed(t *testing.T) {
// debit 510 units from a concrete balance with 500 units
cb := &concreteBalance{
@@ -169,7 +171,8 @@ func TestCBDebitExceed(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitUnlimited(t *testing.T) {
// debit 510 units from an unlimited concrete balance with 100 units
cb := &concreteBalance{
@@ -192,7 +195,8 @@ func TestCBDebitUnlimited(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitLimit(t *testing.T) {
// debit 190 units from a concrete balance with 500 units and limit of 300
cb := &concreteBalance{
@@ -216,7 +220,8 @@ func TestCBDebitLimit(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitLimitExceed(t *testing.T) {
// debit 210 units from a concrete balance with 500 units and limit of 300
cb := &concreteBalance{
@@ -239,7 +244,8 @@ func TestCBDebitLimitExceed(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitLimitExceed2(t *testing.T) {
// debit 510 units from a concrete balance with 500 units but because of limit it will debit only 200
cb := &concreteBalance{
@@ -262,7 +268,8 @@ func TestCBDebitLimitExceed2(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithUnitFactor(t *testing.T) {
// debit 1 unit from balance but because of unit factor it will debit 100
cb := &concreteBalance{
@@ -288,7 +295,8 @@ func TestCBDebitWithUnitFactor(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithUnitFactorWithLimit(t *testing.T) {
// debit 3 units from balance but because of unit factor and limit it will debit 200
cb := &concreteBalance{
@@ -316,7 +324,8 @@ func TestCBDebitWithUnitFactorWithLimit(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithUnitFactorWithUnlimited(t *testing.T) {
// debit 3 units from balance but because of unit factor and limit it will debit 200
cb := &concreteBalance{
@@ -344,7 +353,8 @@ func TestCBDebitWithUnitFactorWithUnlimited(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithUnitFactorWithFilters1(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -381,7 +391,8 @@ func TestCBDebitWithUnitFactorWithFilters1(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithUnitFactorWithFiltersWithLimit(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -418,7 +429,8 @@ func TestCBDebitWithUnitFactorWithFiltersWithLimit(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithMultipleUnitFactor(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -456,7 +468,8 @@ func TestCBDebitWithMultipleUnitFactor(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithBalanceFilter(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -485,7 +498,8 @@ func TestCBDebitWithBalanceFilter(t *testing.T) {
t.Errorf("balance remaining: %s", cb.blnCfg.Units)
}
}
*/
/*
func TestCBDebitWithBalanceFilterNotPassing(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -510,7 +524,8 @@ func TestCBDebitWithBalanceFilterNotPassing(t *testing.T) {
t.Error(err)
}
}
*/
/*
func TestCBDebitWithBalanceInvalidFilter(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -535,7 +550,8 @@ func TestCBDebitWithBalanceInvalidFilter(t *testing.T) {
t.Error(err)
}
}
*/
/*
func TestCBDebitWithInvalidUnitFactorFilter(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -565,7 +581,8 @@ func TestCBDebitWithInvalidUnitFactorFilter(t *testing.T) {
t.Error(err)
}
}
*/
/*
func TestCBDebitWithInvalidLimit(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := engine.NewInternalDB(nil, nil, true)
@@ -592,7 +609,7 @@ func TestCBDebitWithInvalidLimit(t *testing.T) {
t.Error(err)
}
}
*/
func TestCBSDebitUsage(t *testing.T) {
// debit 10 units from a concrete balance with 500 units
cb := &concreteBalance{

View File

@@ -76,6 +76,7 @@ func newBalanceOperator(blncCfg *utils.Balance, cncrtBlncs []*concreteBalance,
// balanceOperator is the implementation of a balance type
type balanceOperator interface {
debitAbstracts(usage *decimal.Big, cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error)
debitConcretes(usage *decimal.Big, cgrEv *utils.CGREvent) (ec *utils.EventCharges, err error)
}
// roundUnitsWithIncrements rounds the usage based on increments
@@ -219,16 +220,12 @@ func debitAbstractsFromConcretes(cncrtBlncs []*concreteBalance, usage *decimal.B
}
clnedUnts := cloneUnitsFromConcretes(cncrtBlncs)
for _, cB := range cncrtBlncs {
ev := utils.MapStorage{
utils.MetaOpts: cgrEv.Opts,
utils.MetaReq: cgrEv.Event,
}
var dbted *utils.Decimal
if dbted, _, err = cB.debitUnits(&utils.Decimal{tCost}, cgrEv.Tenant, ev); err != nil {
var ecCncrt *utils.EventCharges
if ecCncrt, err = cB.debitConcretes(tCost, cgrEv); err != nil {
restoreUnitsFromClones(cncrtBlncs, clnedUnts)
return
}
tCost = utils.SubstractBig(tCost, dbted.Big)
tCost = utils.SubstractBig(tCost, ecCncrt.Usage.Big)
if tCost.Cmp(decimal.New(0, 0)) <= 0 {
return // have debited all, total is smaller or equal to 0
}