mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
AccountS - unifying unitFactor, balanceLimit, costIncrement logic
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user