diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go
index 353cb5191..10e75b5d6 100644
--- a/accounts/abstractbalance.go
+++ b/accounts/abstractbalance.go
@@ -19,8 +19,6 @@ along with this program. If not, see
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
diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go
index 0e6bd6235..288eafdad 100644
--- a/accounts/abstractbalance_test.go
+++ b/accounts/abstractbalance_test.go
@@ -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)
diff --git a/accounts/concretebalance.go b/accounts/concretebalance.go
index 3573bbb08..0d8fbcea2 100644
--- a/accounts/concretebalance.go
+++ b/accounts/concretebalance.go
@@ -19,7 +19,7 @@ along with this program. If not, see
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
diff --git a/accounts/libaccounts.go b/accounts/libaccounts.go
index 04ce32737..d27c8503a 100644
--- a/accounts/libaccounts.go
+++ b/accounts/libaccounts.go
@@ -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
+}