mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-14 20:59:53 +05:00
AccountS - debitUsageFromConcrete
This commit is contained in:
@@ -92,64 +92,6 @@ func (aB *abstractBalance) balanceLimit() (bL *utils.Decimal) {
|
||||
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 {
|
||||
return nil, utils.NewErrNotConnected(utils.RateS)
|
||||
}
|
||||
err = aB.connMgr.Call(aB.rateSConns, nil, utils.RateSv1CostForEvent,
|
||||
&utils.ArgsCostForEvent{CGREvent: cgrEv}, &rplyCost)
|
||||
return
|
||||
}
|
||||
|
||||
// debitUsageFromConcrete attempts to debit the usage out of concrete balances
|
||||
// returns utils.ErrInsufficientCredit if complete usage cannot be debitted
|
||||
func (aB *abstractBalance) debitUsageFromConcrete(usage *utils.Decimal,
|
||||
costIcrm *utils.CostIncrement, cgrEv *utils.CGREvent) (err error) {
|
||||
if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 &&
|
||||
costIcrm.FixedFee == nil {
|
||||
var rplyCost *engine.RateProfileCost
|
||||
if rplyCost, err = aB.rateSCostForEvent(cgrEv); err != nil {
|
||||
return
|
||||
}
|
||||
costIcrm.FixedFee = utils.NewDecimalFromFloat64(rplyCost.Cost)
|
||||
}
|
||||
var tCost *decimal.Big
|
||||
if costIcrm.FixedFee != nil {
|
||||
tCost = costIcrm.FixedFee.Big
|
||||
}
|
||||
// RecurrentFee is configured, used it with increments
|
||||
if costIcrm.RecurrentFee.Big.Cmp(decimal.New(-1, 0)) != 0 {
|
||||
rcrntCost := utils.MultiplyBig(
|
||||
utils.DivideBig(usage.Big, costIcrm.Increment.Big),
|
||||
costIcrm.RecurrentFee.Big)
|
||||
if tCost == nil {
|
||||
tCost = rcrntCost
|
||||
} else {
|
||||
tCost = utils.SumBig(tCost, rcrntCost)
|
||||
}
|
||||
}
|
||||
clnedUnts := cloneUnitsFromConcretes(aB.cncrtBlncs)
|
||||
for _, cB := range aB.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 {
|
||||
restoreUnitsFromClones(aB.cncrtBlncs, clnedUnts)
|
||||
return
|
||||
}
|
||||
tCost = utils.SubstractBig(tCost, dbted.Big)
|
||||
if tCost.Cmp(decimal.New(0, 0)) <= 0 {
|
||||
return // have debited all, total is smaller or equal to 0
|
||||
}
|
||||
}
|
||||
// we could not debit all, put back what we have debited
|
||||
restoreUnitsFromClones(aB.cncrtBlncs, clnedUnts)
|
||||
return utils.ErrInsufficientCredit
|
||||
}
|
||||
|
||||
// debitUsage implements the balanceOperator interface
|
||||
func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
|
||||
cgrEv *utils.CGREvent) (dbted *utils.Decimal, ec *utils.EventCharges, err error) {
|
||||
@@ -225,7 +167,8 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal,
|
||||
return nil, nil, utils.ErrMaxIncrementsExceeded
|
||||
}
|
||||
qriedUsage := usage.Big // so we can detect loops
|
||||
if err = aB.debitUsageFromConcrete(usage, costIcrm, cgrEv); err != nil {
|
||||
if err = debitUsageFromConcrete(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 TestABDebitUsageFromConcrete(t *testing.T) {
|
||||
func TestDebitUsageFromConcrete(t *testing.T) {
|
||||
aB := &abstractBalance{
|
||||
cncrtBlncs: []*concreteBalance{
|
||||
{
|
||||
@@ -56,12 +56,12 @@ func TestABDebitUsageFromConcrete(t *testing.T) {
|
||||
},
|
||||
}}
|
||||
// consume only from first balance
|
||||
if err := aB.debitUsageFromConcrete(
|
||||
if err := debitUsageFromConcrete(aB.cncrtBlncs,
|
||||
utils.NewDecimal(int64(time.Duration(5*time.Minute)), 0),
|
||||
&utils.CostIncrement{
|
||||
Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0),
|
||||
RecurrentFee: utils.NewDecimal(1, 0)},
|
||||
new(utils.CGREvent)); err != nil {
|
||||
new(utils.CGREvent), nil, nil, nil); err != nil {
|
||||
t.Error(err)
|
||||
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(0, 0)) != 0 {
|
||||
t.Errorf("Unexpected units in first balance: %s", aB.cncrtBlncs[0].blnCfg.Units)
|
||||
@@ -73,12 +73,12 @@ func TestABDebitUsageFromConcrete(t *testing.T) {
|
||||
aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(500, 0)
|
||||
aB.cncrtBlncs[1].blnCfg.Units = utils.NewDecimal(125, 2)
|
||||
|
||||
if err := aB.debitUsageFromConcrete(
|
||||
if err := debitUsageFromConcrete(aB.cncrtBlncs,
|
||||
utils.NewDecimal(int64(time.Duration(9*time.Minute)), 0),
|
||||
&utils.CostIncrement{
|
||||
Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0),
|
||||
RecurrentFee: utils.NewDecimal(1, 0)},
|
||||
new(utils.CGREvent)); err != nil {
|
||||
new(utils.CGREvent), nil, nil, nil); err != nil {
|
||||
t.Error(err)
|
||||
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(-200, 0)) != 0 {
|
||||
t.Errorf("Unexpected units in first balance: %s", aB.cncrtBlncs[0].blnCfg.Units)
|
||||
@@ -90,12 +90,12 @@ func TestABDebitUsageFromConcrete(t *testing.T) {
|
||||
aB.cncrtBlncs[0].blnCfg.Units = utils.NewDecimal(500, 0)
|
||||
aB.cncrtBlncs[1].blnCfg.Units = utils.NewDecimal(125, 2)
|
||||
|
||||
if err := aB.debitUsageFromConcrete(
|
||||
if err := debitUsageFromConcrete(aB.cncrtBlncs,
|
||||
utils.NewDecimal(int64(time.Duration(10*time.Minute)), 0),
|
||||
&utils.CostIncrement{
|
||||
Increment: utils.NewDecimal(int64(time.Duration(time.Minute)), 0),
|
||||
RecurrentFee: utils.NewDecimal(1, 0)},
|
||||
new(utils.CGREvent)); err == nil || err != utils.ErrInsufficientCredit {
|
||||
new(utils.CGREvent), nil, nil, nil); err == nil || err != utils.ErrInsufficientCredit {
|
||||
t.Error(err)
|
||||
} else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(500, 0)) != 0 {
|
||||
t.Errorf("Unexpected units in first balance: %s", aB.cncrtBlncs[0].blnCfg.Units)
|
||||
|
||||
@@ -52,14 +52,18 @@ func (cB *concreteBalance) costIncrement(tnt string, ev utils.DataProvider) (cos
|
||||
} else if !pass {
|
||||
continue
|
||||
}
|
||||
costIcrm = cIcrm.Clone() // need clone since we might modify
|
||||
return
|
||||
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)
|
||||
}
|
||||
// nothing matched, return default
|
||||
costIcrm = &utils.CostIncrement{
|
||||
Increment: &utils.Decimal{decimal.New(1, 0)},
|
||||
RecurrentFee: &utils.Decimal{decimal.New(-1, 0)}}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -126,3 +126,63 @@ func processAttributeS(connMgr *engine.ConnManager, cgrEv *utils.CGREvent,
|
||||
attrArgs, &rplyEv)
|
||||
return
|
||||
}
|
||||
|
||||
// rateSCostForEvent will process the event with RateS in order to get the cost
|
||||
func rateSCostForEvent(connMgr *engine.ConnManager, cgrEv *utils.CGREvent,
|
||||
rateSConns, rpIDs []string) (rplyCost *engine.RateProfileCost, err error) {
|
||||
if len(rateSConns) == 0 {
|
||||
return nil, utils.NewErrNotConnected(utils.RateS)
|
||||
}
|
||||
err = connMgr.Call(rateSConns, nil, utils.RateSv1CostForEvent,
|
||||
&utils.ArgsCostForEvent{CGREvent: cgrEv, RateProfileIDs: rpIDs}, &rplyCost)
|
||||
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,
|
||||
costIcrm *utils.CostIncrement, cgrEv *utils.CGREvent,
|
||||
connMgr *engine.ConnManager, rateSConns, rpIDs []string) (err error) {
|
||||
if costIcrm.RecurrentFee.Cmp(decimal.New(-1, 0)) == 0 &&
|
||||
costIcrm.FixedFee == nil {
|
||||
var rplyCost *engine.RateProfileCost
|
||||
if rplyCost, err = rateSCostForEvent(connMgr, cgrEv, rateSConns, rpIDs); err != nil {
|
||||
return
|
||||
}
|
||||
costIcrm.FixedFee = utils.NewDecimalFromFloat64(rplyCost.Cost)
|
||||
}
|
||||
var tCost *decimal.Big
|
||||
if costIcrm.FixedFee != nil {
|
||||
tCost = costIcrm.FixedFee.Big
|
||||
}
|
||||
// RecurrentFee is configured, used it with increments
|
||||
if costIcrm.RecurrentFee.Big.Cmp(decimal.New(-1, 0)) != 0 {
|
||||
rcrntCost := utils.MultiplyBig(
|
||||
utils.DivideBig(usage.Big, costIcrm.Increment.Big),
|
||||
costIcrm.RecurrentFee.Big)
|
||||
if tCost == nil {
|
||||
tCost = rcrntCost
|
||||
} else {
|
||||
tCost = utils.SumBig(tCost, rcrntCost)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
restoreUnitsFromClones(cncrtBlncs, clnedUnts)
|
||||
return
|
||||
}
|
||||
tCost = utils.SubstractBig(tCost, dbted.Big)
|
||||
if tCost.Cmp(decimal.New(0, 0)) <= 0 {
|
||||
return // have debited all, total is smaller or equal to 0
|
||||
}
|
||||
}
|
||||
// we could not debit all, put back what we have debited
|
||||
restoreUnitsFromClones(cncrtBlncs, clnedUnts)
|
||||
return utils.ErrInsufficientCredit
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build integration
|
||||
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
Reference in New Issue
Block a user