Files
cgrates/accounts/abstractbalance.go
2021-10-08 11:07:45 +03:00

212 lines
6.6 KiB
Go

/*
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package accounts
import (
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/ericlagergren/decimal"
)
// newAbstractBalance constructs an abstractBalanceOperator
func newAbstractBalanceOperator(ctx *context.Context, acntID string, blnCfg *utils.Balance,
cncrtBlncs []*concreteBalance,
fltrS *engine.FilterS, connMgr *engine.ConnManager,
attrSConns, rateSConns []string) balanceOperator {
return &abstractBalance{acntID, blnCfg, cncrtBlncs, fltrS, connMgr, ctx, attrSConns, rateSConns}
}
// abstractBalance is the operator for *abstract balance type
type abstractBalance struct {
acntID string
blnCfg *utils.Balance
cncrtBlncs []*concreteBalance // paying balances
fltrS *engine.FilterS
connMgr *engine.ConnManager
ctx *context.Context
attrSConns []string
rateSConns []string
}
// id implements the balanceOperator interface
func (aB *abstractBalance) id() string {
return aB.blnCfg.ID
}
// debitAbstracts implements the balanceOperator interface
func (aB *abstractBalance) debitAbstracts(ctx *context.Context, usage *decimal.Big,
cgrEv *utils.CGREvent, dbted *decimal.Big) (ec *utils.EventCharges, err error) {
evNm := utils.MapStorage{
utils.MetaOpts: cgrEv.APIOpts,
utils.MetaReq: cgrEv.Event,
}
// pass the general balance filters
var pass bool
if pass, err = aB.fltrS.Pass(ctx, cgrEv.Tenant, aB.blnCfg.FilterIDs, evNm); err != nil {
return
} else if !pass {
return nil, utils.ErrFilterNotPassingNoCaps
}
// balanceLimit
var hasLmt bool
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
}
// costIncrement
var costIcrm *utils.CostIncrement
if costIcrm, err = costIncrement(ctx, aB.blnCfg.CostIncrements, aB.fltrS,
cgrEv.Tenant, evNm); err != nil {
return
}
// unitFactor
var uF *utils.UnitFactor
if uF, err = unitFactor(ctx, aB.blnCfg.UnitFactors, aB.fltrS, cgrEv.Tenant, evNm); err != nil {
return
}
var hasUF bool
if uF != nil && uF.Factor.Cmp(decimal.New(1, 0)) != 0 {
//dbtUnits = utils.MultiplyBig(dbtUnits, uF.Factor.Big)
hasUF = true
}
if blncLmt != nil {
maxBlcDbt := new(decimal.Big).Copy(aB.blnCfg.Units.Big)
if hasUF {
maxBlcDbt = utils.DivideBig(maxBlcDbt, uF.Factor.Big) // common units with debit and increments
}
maxBlcDbt = roundUnitsWithIncrements(maxBlcDbt, costIcrm.Increment.Big)
if maxBlcDbt.Cmp(usage) == -1 { // balance smaller than usage, correct usage
usage = maxBlcDbt
}
}
var ecCost *utils.EventCharges
if (costIcrm.FixedFee == nil && costIcrm.RecurrentFee == nil) ||
(costIcrm.FixedFee != nil && costIcrm.FixedFee.Cmp(decimal.New(0, 0)) != 0) ||
(costIcrm.RecurrentFee != nil && costIcrm.RecurrentFee.Cmp(decimal.New(0, 0)) != 0) {
// attempt to debit usage with cost
if ecCost, err = maxDebitAbstractsFromConcretes(ctx, usage,
aB.acntID, aB.cncrtBlncs,
aB.connMgr, cgrEv,
aB.attrSConns, aB.blnCfg.AttributeIDs,
aB.rateSConns, aB.blnCfg.RateProfileIDs,
costIcrm, dbted); err != nil {
return
} else if ecCost.Abstracts.Compare(utils.NewDecimal(0, 0)) == 0 {
// no debit performed
return ecCost, nil
}
}
var dbtUnits *decimal.Big
if ecCost != nil {
usage = ecCost.Abstracts.Big
dbtUnits = ecCost.Abstracts.Big
} else {
dbtUnits = new(decimal.Big).Copy(usage)
}
if hasUF {
dbtUnits = utils.MultiplyBig(dbtUnits, uF.Factor.Big)
}
if dbtUnits.Cmp(decimal.New(0, 0)) != 0 {
aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, dbtUnits)
}
if hasLmt { // put back the limit
aB.blnCfg.Units.Big = utils.SumBig(aB.blnCfg.Units.Big, blncLmt.Big)
}
// EvenCharges building
ec = utils.NewEventCharges()
ec.Abstracts = &utils.Decimal{usage}
if ecCost != nil {
ec.Concretes = ecCost.Concretes
}
// UnitFactors
var ufID string
if hasUF {
ufID = utils.UUIDSha1Prefix()
ec.UnitFactors[ufID] = uF
}
// RatingID
var ratingID, rateID string
if costIcrm != nil {
ratingID = utils.UUIDSha1Prefix()
rateID = utils.UUIDSha1Prefix()
ec.Rating[ratingID] = &utils.RateSInterval{
Increments: []*utils.RateSIncrement{
{
RateID: rateID,
CompressFactor: 1,
},
},
CompressFactor: 1,
}
ec.Rates[rateID] = &utils.IntervalRate{
FixedFee: costIcrm.FixedFee,
RecurrentFee: costIcrm.RecurrentFee,
}
} else { // take it from first increment, not copying since it will be done bellow
ratingID = ecCost.Accounting[ecCost.Charges[0].ChargingID].RatingID
}
// AccountingID
acntID := utils.UUIDSha1Prefix()
ec.Accounting[acntID] = &utils.AccountCharge{
AccountID: aB.acntID,
BalanceID: aB.blnCfg.ID,
Units: &utils.Decimal{usage},
BalanceLimit: blncLmt,
UnitFactorID: ufID,
RatingID: ratingID,
}
if ecCost != nil {
for _, ival := range ecCost.Charges {
ec.Accounting[acntID].JoinedChargeIDs = append(ec.Accounting[acntID].JoinedChargeIDs, ival.ChargingID)
ec.Accounting[ival.ChargingID] = ecCost.Accounting[ival.ChargingID]
// Copy the unitFactor data
if ecCost.Accounting[ival.ChargingID].UnitFactorID != utils.EmptyString {
ec.UnitFactors[ecCost.Accounting[ival.ChargingID].UnitFactorID] = ecCost.UnitFactors[ecCost.Accounting[ival.ChargingID].UnitFactorID]
}
// Copy the Rating data
if ecCost.Accounting[ival.ChargingID].RatingID != utils.EmptyString {
ec.Rating[ecCost.Accounting[ival.ChargingID].RatingID] = ecCost.Rating[ecCost.Accounting[ival.ChargingID].RatingID]
}
}
}
ec.Charges = []*utils.ChargeEntry{
{
ChargingID: acntID,
CompressFactor: 1,
},
}
return
}
// debitConcretes implements the balanceOperator interface
func (aB *abstractBalance) debitConcretes(_ *context.Context, _ *decimal.Big,
_ *utils.CGREvent, _ *decimal.Big) (ec *utils.EventCharges, err error) {
return nil, utils.ErrNotImplemented
}