diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go index 70689f21c..ccb5b61b2 100644 --- a/accounts/abstractbalance.go +++ b/accounts/abstractbalance.go @@ -41,57 +41,6 @@ type abstractBalance struct { rateSConns []string } -// costIncrement finds out the cost increment for the event -func (aB *abstractBalance) costIncrement(tnt string, ev utils.DataProvider) (costIcrm *utils.CostIncrement, err error) { - for _, cIcrm := range aB.blnCfg.CostIncrements { - var pass bool - if pass, err = aB.fltrS.Pass(tnt, cIcrm.FilterIDs, ev); err != nil { - return - } else if !pass { - continue - } - costIcrm = cIcrm - break - } - if costIcrm == nil { - costIcrm = new(utils.CostIncrement) - } - if costIcrm.Increment == nil { - costIcrm.Increment = utils.NewDecimal(1, 0) - } - if costIcrm.RecurrentFee == nil { - costIcrm.RecurrentFee = utils.NewDecimal(-1, 0) - } - return -} - -// unitFactor returns the unitFactor for the event -func (aB *abstractBalance) unitFactor(tnt string, ev utils.DataProvider) (uF *utils.UnitFactor, err error) { - for _, uF = range aB.blnCfg.UnitFactors { - var pass bool - if pass, err = aB.fltrS.Pass(tnt, uF.FilterIDs, ev); err != nil { - return - } else if !pass { - continue - } - return - } - return -} - -// balanceLimit returns the balance's limit -func (aB *abstractBalance) balanceLimit() (bL *utils.Decimal) { - if _, isUnlimited := aB.blnCfg.Opts[utils.MetaBalanceUnlimited]; isUnlimited { - return - } - if lmtIface, has := aB.blnCfg.Opts[utils.MetaBalanceLimit]; has { - bL = lmtIface.(*utils.Decimal) - } - // nothing matched, return default - bL = utils.NewDecimal(0, 0) - return -} - // debitUsage implements the balanceOperator interface func (aB *abstractBalance) debitUsage(usage *utils.Decimal, cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) { @@ -111,7 +60,8 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, // costIncrement var costIcrm *utils.CostIncrement - if costIcrm, err = aB.costIncrement(cgrEv.Tenant, evNm); err != nil { + if costIcrm, err = costIncrement(aB.blnCfg.CostIncrements, aB.fltrS, + cgrEv.Tenant, evNm); err != nil { return } if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 && @@ -129,7 +79,10 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, // balanceLimit var hasLmt bool - blncLmt := aB.balanceLimit() + var blncLmt *utils.Decimal + if blncLmt, err = balanceLimit(aB.blnCfg.Opts); err != nil { + return + } if blncLmt != nil && blncLmt.Cmp(decimal.New(0, 0)) != 0 { aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, blncLmt.Big) hasLmt = true @@ -137,7 +90,7 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, // unitFactor var uF *utils.UnitFactor - if uF, err = aB.unitFactor(cgrEv.Tenant, evNm); err != nil { + if uF, err = unitFactor(aB.blnCfg.UnitFactors, aB.fltrS, cgrEv.Tenant, evNm); err != nil { return } var hasUF bool @@ -167,7 +120,7 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, return nil, nil, utils.ErrMaxIncrementsExceeded } qriedUsage := usage.Big // so we can detect loops - if err = debitUsageFromConcrete(aB.cncrtBlncs, usage, costIcrm, cgrEv, + if err = debitUsageFromConcretes(aB.cncrtBlncs, usage, costIcrm, cgrEv, aB.connMgr, aB.rateSConns, aB.blnCfg.RateProfileIDs); err != nil { if err != utils.ErrInsufficientCredit { return diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go index f5b323793..acaabd5b6 100644 --- a/accounts/abstractbalance_test.go +++ b/accounts/abstractbalance_test.go @@ -26,7 +26,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -func TestDebitUsageFromConcrete(t *testing.T) { +func TestdebitUsageFromConcretes(t *testing.T) { aB := &abstractBalance{ cncrtBlncs: []*concreteBalance{ { @@ -56,7 +56,7 @@ func TestDebitUsageFromConcrete(t *testing.T) { }, }} // consume only from first balance - if err := debitUsageFromConcrete(aB.cncrtBlncs, + if err := debitUsageFromConcretes(aB.cncrtBlncs, utils.NewDecimal(int64(time.Duration(5*time.Minute)), 0), &utils.CostIncrement{ Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0), @@ -73,7 +73,7 @@ func TestDebitUsageFromConcrete(t *testing.T) { aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(500, 0) aB.cncrtBlncs[1].blnCfg.Units = utils.NewDecimal(125, 2) - if err := debitUsageFromConcrete(aB.cncrtBlncs, + if err := debitUsageFromConcretes(aB.cncrtBlncs, utils.NewDecimal(int64(time.Duration(9*time.Minute)), 0), &utils.CostIncrement{ Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0), @@ -90,7 +90,7 @@ func TestDebitUsageFromConcrete(t *testing.T) { aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(500, 0) aB.cncrtBlncs[1].blnCfg.Units = utils.NewDecimal(125, 2) - if err := debitUsageFromConcrete(aB.cncrtBlncs, + if err := debitUsageFromConcretes(aB.cncrtBlncs, utils.NewDecimal(int64(time.Duration(10*time.Minute)), 0), &utils.CostIncrement{ Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0), diff --git a/accounts/concretebalance.go b/accounts/concretebalance.go index 6cd822bd4..9de195a32 100644 --- a/accounts/concretebalance.go +++ b/accounts/concretebalance.go @@ -43,58 +43,6 @@ type concreteBalance struct { rateSConns []string } -// costIncrement finds out the cost increment for the event -func (cB *concreteBalance) costIncrement(tnt string, ev utils.DataProvider) (costIcrm *utils.CostIncrement, err error) { - for _, cIcrm := range cB.blnCfg.CostIncrements { - var pass bool - if pass, err = cB.fltrS.Pass(tnt, cIcrm.FilterIDs, ev); err != nil { - return - } else if !pass { - continue - } - costIcrm = cIcrm - break - } - if costIcrm == nil { - costIcrm = new(utils.CostIncrement) - } - if costIcrm.Increment == nil { - costIcrm.Increment = utils.NewDecimal(1, 0) - } - if costIcrm.RecurrentFee == nil { - costIcrm.RecurrentFee = utils.NewDecimal(-1, 0) - } - return -} - -// unitFactor returns the unitFactor for the event -func (cB *concreteBalance) unitFactor(tnt string, ev utils.DataProvider) (uF *utils.UnitFactor, err error) { - for _, uF = range cB.blnCfg.UnitFactors { - var pass bool - if pass, err = cB.fltrS.Pass(tnt, uF.FilterIDs, ev); err != nil { - return - } else if !pass { - continue - } - return - } - return -} - -// balanceLimit returns the balance's limit -func (cB *concreteBalance) balanceLimit() (bL *utils.Decimal) { - if _, isUnlimited := cB.blnCfg.Opts[utils.MetaBalanceUnlimited]; isUnlimited { - return - } - if lmtIface, has := cB.blnCfg.Opts[utils.MetaBalanceLimit]; has { - bL = lmtIface.(*utils.Decimal) - return - } - // nothing matched, return default - bL = utils.NewDecimal(0, 0) - 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) { @@ -109,7 +57,7 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string, // unitFactor var hasUF bool - if uF, err = cB.unitFactor(tnt, ev); err != nil { + 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 { @@ -119,7 +67,10 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string, // balanceLimit var hasLmt bool - blncLmt := cB.balanceLimit() + 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 @@ -161,7 +112,8 @@ func (cB *concreteBalance) debitUsage(usage *utils.Decimal, // costIncrement var costIcrm *utils.CostIncrement - if costIcrm, err = cB.costIncrement(cgrEv.Tenant, evNm); err != nil { + if costIcrm, err = costIncrement(cB.blnCfg.CostIncrements, + cB.fltrS, cgrEv.Tenant, evNm); err != nil { return } if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 && @@ -179,7 +131,10 @@ func (cB *concreteBalance) debitUsage(usage *utils.Decimal, // balanceLimit var hasLmt bool - blncLmt := cB.balanceLimit() + var blncLmt *utils.Decimal + if blncLmt, err = balanceLimit(cB.blnCfg.Opts); err != nil { + return + } if blncLmt != nil && blncLmt.Cmp(decimal.New(0, 0)) != 0 { cB.blnCfg.Units.Big = utils.SubstractBig(cB.blnCfg.Units.Big, blncLmt.Big) hasLmt = true @@ -187,7 +142,7 @@ func (cB *concreteBalance) debitUsage(usage *utils.Decimal, // unitFactor var uF *utils.UnitFactor - if uF, err = cB.unitFactor(cgrEv.Tenant, evNm); err != nil { + if uF, err = unitFactor(cB.blnCfg.UnitFactors, cB.fltrS, cgrEv.Tenant, evNm); err != nil { return } var hasUF bool diff --git a/accounts/concretebalance_test.go b/accounts/concretebalance_test.go index fec478d08..160839182 100644 --- a/accounts/concretebalance_test.go +++ b/accounts/concretebalance_test.go @@ -34,7 +34,7 @@ func TestCBDebitUnits(t *testing.T) { ID: "TestCBDebitUnits", Type: utils.MetaConcrete, Opts: map[string]interface{}{ - utils.MetaBalanceLimit: utils.NewDecimal(-200, 0), + utils.MetaBalanceLimit: -200.0, }, UnitFactors: []*utils.UnitFactor{ { @@ -63,7 +63,7 @@ func TestCBDebitUnits(t *testing.T) { ID: "TestCBDebitUnits", Type: utils.MetaConcrete, Opts: map[string]interface{}{ - utils.MetaBalanceLimit: utils.NewDecimal(-1, 0), + utils.MetaBalanceLimit: -1.0, }, Units: utils.NewDecimal(125, 2), // 1.25 }, @@ -107,7 +107,7 @@ func TestCBDebitUnits(t *testing.T) { ID: "TestCBDebitUnits", Type: utils.MetaConcrete, Opts: map[string]interface{}{ - utils.MetaBalanceLimit: utils.NewDecimal(5, 1), // 0.5 as limit + utils.MetaBalanceLimit: 0.5, // 0.5 as limit }, Units: utils.NewDecimal(125, 2), // 1.25 }, diff --git a/accounts/libaccounts.go b/accounts/libaccounts.go index a1dc0783e..d0b06ecac 100644 --- a/accounts/libaccounts.go +++ b/accounts/libaccounts.go @@ -19,6 +19,7 @@ along with this program. If not, see package accounts import ( + "errors" "fmt" "github.com/cgrates/cgrates/engine" @@ -138,9 +139,66 @@ func rateSCostForEvent(connMgr *engine.ConnManager, cgrEv *utils.CGREvent, return } +// costIncrement computes the costIncrement for the event +func costIncrement(cfgCostIncrmts []*utils.CostIncrement, + fltrS *engine.FilterS, tnt string, ev utils.DataProvider) (costIcrm *utils.CostIncrement, err error) { + for _, cIcrm := range cfgCostIncrmts { + var pass bool + if pass, err = fltrS.Pass(tnt, cIcrm.FilterIDs, ev); err != nil { + return + } else if !pass { + continue + } + costIcrm = cIcrm + break + } + if costIcrm == nil { + costIcrm = new(utils.CostIncrement) + } + if costIcrm.Increment == nil { + costIcrm.Increment = utils.NewDecimal(1, 0) + } + if costIcrm.RecurrentFee == nil { + costIcrm.RecurrentFee = utils.NewDecimal(-1, 0) + } + return +} + +// unitFactor detects the unitFactor for the event +func unitFactor(cfgUnitFactors []*utils.UnitFactor, + fltrS *engine.FilterS, tnt string, ev utils.DataProvider) (uF *utils.UnitFactor, err error) { + for _, uF = range cfgUnitFactors { + var pass bool + if pass, err = fltrS.Pass(tnt, uF.FilterIDs, ev); err != nil { + return + } else if !pass { + continue + } + return + } + return +} + +// balanceLimit returns the balance limit based on configuration +func balanceLimit(optsCfg map[string]interface{}) (bL *utils.Decimal, err error) { + if _, isUnlimited := optsCfg[utils.MetaBalanceUnlimited]; isUnlimited { + return // unlimited is nil pointer + } + if lmtIface, has := optsCfg[utils.MetaBalanceLimit]; has { + flt64Lmt, canCast := lmtIface.(float64) + if !canCast { + return nil, errors.New("unsupported *balanceLimit format") + } + return utils.NewDecimalFromFloat64(flt64Lmt), nil + } + // nothing matched, return default + bL = utils.NewDecimal(0, 0) + return +} + // debitUsageFromConcrete attempts to debit the usage out of concrete balances // returns utils.ErrInsufficientCredit if complete usage cannot be debitted -func debitUsageFromConcrete(cncrtBlncs []*concreteBalance, usage *utils.Decimal, +func debitUsageFromConcretes(cncrtBlncs []*concreteBalance, usage *utils.Decimal, costIcrm *utils.CostIncrement, cgrEv *utils.CGREvent, connMgr *engine.ConnManager, rateSConns, rpIDs []string) (err error) { if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 && @@ -149,6 +207,7 @@ func debitUsageFromConcrete(cncrtBlncs []*concreteBalance, usage *utils.Decimal, if rplyCost, err = rateSCostForEvent(connMgr, cgrEv, rateSConns, rpIDs); err != nil { return } + costIcrm = costIcrm.Clone() // so we don't modify the original costIcrm.FixedFee = utils.NewDecimalFromFloat64(rplyCost.Cost) } var tCost *decimal.Big