mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-14 20:59:53 +05:00
AccountS - enhancing Abstracts with joined charges in EventCharges
This commit is contained in:
@@ -61,6 +61,8 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big,
|
||||
return nil, utils.ErrFilterNotPassingNoCaps
|
||||
}
|
||||
|
||||
dbtUnits := new(decimal.Big).Copy(usage)
|
||||
|
||||
// balanceLimit
|
||||
var hasLmt bool
|
||||
var blncLmt *utils.Decimal
|
||||
@@ -71,16 +73,6 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big,
|
||||
aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, blncLmt.Big)
|
||||
hasLmt = true
|
||||
}
|
||||
// unitFactor
|
||||
var uF *utils.UnitFactor
|
||||
if uF, err = unitFactor(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 {
|
||||
usage = utils.MultiplyBig(usage, uF.Factor.Big)
|
||||
hasUF = true
|
||||
}
|
||||
|
||||
// costIncrement
|
||||
var costIcrm *utils.CostIncrement
|
||||
@@ -88,71 +80,62 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big,
|
||||
cgrEv.Tenant, evNm); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// unitFactor
|
||||
var uF *utils.UnitFactor
|
||||
if uF, err = unitFactor(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
|
||||
}
|
||||
// balance smaller than usage, correct usage if the balance has limit
|
||||
if aB.blnCfg.Units.Big.Cmp(usage) == -1 && blncLmt != nil {
|
||||
if aB.blnCfg.Units.Big.Cmp(dbtUnits) == -1 && blncLmt != nil {
|
||||
// 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 = roundUnitsWithIncrements(aB.blnCfg.Units.Big, costIcrm.Increment.Big)
|
||||
}
|
||||
if costIcrm.RecurrentFee != nil &&
|
||||
costIcrm.RecurrentFee.Cmp(decimal.New(0, 0)) == 0 &&
|
||||
(costIcrm.FixedFee == nil ||
|
||||
costIcrm.FixedFee.Cmp(decimal.New(0, 0)) == 0) {
|
||||
// cost 0, no need of concrete
|
||||
ec = utils.NewEventCharges()
|
||||
ec.Abstracts = &utils.Decimal{usage}
|
||||
// UnitFactors
|
||||
var ufID string
|
||||
maxDbt := new(decimal.Big).Copy(aB.blnCfg.Units.Big)
|
||||
if hasUF {
|
||||
ufID = utils.UUIDSha1Prefix()
|
||||
ec.UnitFactors[ufID] = uF
|
||||
maxDbt = utils.DivideBig(maxDbt, uF.Factor.Big)
|
||||
}
|
||||
// Rating
|
||||
ratingID := utils.UUIDSha1Prefix()
|
||||
ec.Rating[ratingID] = &utils.RateSInterval{
|
||||
IntervalStart: utils.NewDecimal(0, 0),
|
||||
Increments: []*utils.RateSIncrement{
|
||||
usage = roundUnitsWithIncrements(maxDbt, costIcrm.Increment.Big)
|
||||
}
|
||||
|
||||
/*
|
||||
if costIcrm.RecurrentFee.Cmp(decimal.New(0, 0)) == 0 &&
|
||||
(costIcrm.FixedFee == nil ||
|
||||
costIcrm.FixedFee.Cmp(decimal.New(0, 0)) == 0) {
|
||||
|
||||
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,
|
||||
}
|
||||
ec.ChargingIntervals = []*utils.ChargingInterval{
|
||||
{
|
||||
IncrementStart: utils.NewDecimal(0, 0),
|
||||
Rate: &utils.Rate{
|
||||
ID: utils.MetaCostIncrement,
|
||||
IntervalRates: []*utils.IntervalRate{
|
||||
{
|
||||
FixedFee: utils.NewDecimal(0, 0),
|
||||
},
|
||||
Increments: []*utils.ChargingIncrement{
|
||||
{
|
||||
Units: &utils.Decimal{usage},
|
||||
AccountChargeID: acntID,
|
||||
CompressFactor: 1,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
Usage: &utils.Decimal{usage},
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
}
|
||||
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,
|
||||
}
|
||||
ec.ChargingIntervals = []*utils.ChargingInterval{
|
||||
{
|
||||
Increments: []*utils.ChargingIncrement{
|
||||
{
|
||||
Units: &utils.Decimal{usage},
|
||||
AccountChargeID: acntID,
|
||||
CompressFactor: 1,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
}
|
||||
*/
|
||||
var ecCost *utils.EventCharges
|
||||
if (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 ec, err = maxDebitAbstractsFromConcretes(usage,
|
||||
if ecCost, err = maxDebitAbstractsFromConcretes(usage,
|
||||
aB.acntID, aB.cncrtBlncs,
|
||||
aB.connMgr, cgrEv,
|
||||
aB.attrSConns, aB.blnCfg.AttributeIDs,
|
||||
@@ -160,16 +143,95 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big,
|
||||
costIcrm); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ec.Abstracts.Cmp(decimal.New(0, 0)) != 0 {
|
||||
aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, ec.Abstracts.Big)
|
||||
if ecCost != nil {
|
||||
usage = ecCost.Abstracts.Big
|
||||
dbtUnits = ecCost.Abstracts.Big
|
||||
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 {
|
||||
usage = utils.DivideBig(usage, uF.Factor.Big)
|
||||
ufID = utils.UUIDSha1Prefix()
|
||||
ec.UnitFactors[ufID] = uF
|
||||
}
|
||||
// RatingID
|
||||
var ratingID string
|
||||
if costIcrm != nil {
|
||||
ratingID = utils.UUIDSha1Prefix()
|
||||
ec.Rating[ratingID] = &utils.RateSInterval{
|
||||
Increments: []*utils.RateSIncrement{
|
||||
{
|
||||
Rate: &utils.Rate{
|
||||
ID: utils.MetaCostIncrement,
|
||||
IntervalRates: []*utils.IntervalRate{
|
||||
{
|
||||
FixedFee: costIcrm.FixedFee,
|
||||
RecurrentFee: costIcrm.RecurrentFee,
|
||||
},
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
}
|
||||
} else { // take it from first increment, not copying since it will be done bellow
|
||||
ratingID = ecCost.Accounting[ecCost.ChargingIntervals[0].Increments[0].AccountChargeID].RatingID
|
||||
}
|
||||
// AccountingID
|
||||
acntID := utils.UUIDSha1Prefix()
|
||||
ec.Accounting[acntID] = &utils.AccountCharge{
|
||||
AccountID: aB.acntID,
|
||||
BalanceID: aB.blnCfg.ID,
|
||||
BalanceLimit: blncLmt,
|
||||
UnitFactorID: ufID,
|
||||
RatingID: ratingID,
|
||||
}
|
||||
if ecCost != nil {
|
||||
for _, ival := range ecCost.ChargingIntervals {
|
||||
for _, icrm := range ival.Increments {
|
||||
ec.Accounting[acntID].JoinedChargeIDs = append(ec.Accounting[acntID].JoinedChargeIDs, icrm.AccountChargeID)
|
||||
ec.Accounting[icrm.AccountChargeID] = ecCost.Accounting[icrm.AccountChargeID]
|
||||
// Copy the unitFactor data
|
||||
if ecCost.Accounting[icrm.AccountChargeID].UnitFactorID != utils.EmptyString {
|
||||
ec.UnitFactors[ecCost.Accounting[icrm.AccountChargeID].UnitFactorID] = ecCost.UnitFactors[ecCost.Accounting[icrm.AccountChargeID].UnitFactorID]
|
||||
}
|
||||
// Copy the Rating data
|
||||
if ecCost.Accounting[icrm.AccountChargeID].RatingID != utils.EmptyString {
|
||||
ec.Rating[ecCost.Accounting[icrm.AccountChargeID].RatingID] = ecCost.Rating[ecCost.Accounting[icrm.AccountChargeID].RatingID]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ec.ChargingIntervals = []*utils.ChargingInterval{
|
||||
{
|
||||
Increments: []*utils.ChargingIncrement{
|
||||
{
|
||||
Units: &utils.Decimal{usage},
|
||||
AccountChargeID: acntID,
|
||||
CompressFactor: 1,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -245,6 +245,7 @@ func (aS *AccountS) accountDebit(acnt *utils.Account, usage *decimal.Big,
|
||||
}
|
||||
usage = utils.SubstractBig(usage, used)
|
||||
ec.Merge(ecDbt)
|
||||
ec.Accounts[acnt.ID] = acnt
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1402,7 +1402,8 @@ func TestV1DebitAbstractsEventCharges(t *testing.T) {
|
||||
ID: "TestV1DebitAbstractsEventCharges",
|
||||
Tenant: utils.CGRateSorg,
|
||||
APIOpts: map[string]interface{}{
|
||||
utils.MetaUsage: "7m55s", // 7m55s to debit both accounts
|
||||
//utils.MetaUsage: "7m55s", // 7m55s to debit both accounts
|
||||
utils.MetaUsage: "1m",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1412,24 +1413,25 @@ func TestV1DebitAbstractsEventCharges(t *testing.T) {
|
||||
} else if !reflect.DeepEqual(eEvChgs, rply) {
|
||||
t.Errorf("expecting: %s\n, received: %s", utils.ToIJSON(eEvChgs), utils.ToIJSON(rply))
|
||||
}
|
||||
/*
|
||||
acnt1.Balances[ab1ID].Units = utils.NewDecimal(int64(10*time.Second), 0)
|
||||
acnt1.Balances[cb1ID].Units = utils.NewDecimal(-200, 0)
|
||||
acnt1.Balances[ab2ID].Units = &utils.Decimal{new(decimal.Big).CopySign(decimal.New(0, 0), decimal.New(-1, 0))} // negative 0
|
||||
acnt1.Balances[cb2ID].Units = utils.NewDecimal(0, 0)
|
||||
if rcv, err := dm.GetAccount(acnt1.Tenant, acnt1.ID); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rcv, acnt1) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(acnt1), utils.ToJSON(rcv))
|
||||
}
|
||||
|
||||
acnt1.Balances[ab1ID].Units = utils.NewDecimal(int64(10*time.Second), 0)
|
||||
acnt1.Balances[cb1ID].Units = utils.NewDecimal(-200, 0)
|
||||
acnt1.Balances[ab2ID].Units = &utils.Decimal{new(decimal.Big).CopySign(decimal.New(0, 0), decimal.New(-1, 0))} // negative 0
|
||||
acnt1.Balances[cb2ID].Units = utils.NewDecimal(0, 0)
|
||||
if rcv, err := dm.GetAccount(acnt1.Tenant, acnt1.ID); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rcv, acnt1) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(acnt1), utils.ToJSON(rcv))
|
||||
}
|
||||
|
||||
acnt2.Balances[ab1ID].Units = utils.NewDecimal(int64(10*time.Second), 0)
|
||||
acnt2.Balances[cb1ID].Units = utils.NewDecimal(-1, 1)
|
||||
if rcv, err := dm.GetAccount(acnt2.Tenant, acnt2.ID); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rcv, acnt2) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(acnt2), utils.ToJSON(rcv))
|
||||
}
|
||||
acnt2.Balances[ab1ID].Units = utils.NewDecimal(int64(10*time.Second), 0)
|
||||
acnt2.Balances[cb1ID].Units = utils.NewDecimal(-1, 1)
|
||||
if rcv, err := dm.GetAccount(acnt2.Tenant, acnt2.ID); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rcv, acnt2) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(acnt2), utils.ToJSON(rcv))
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ func NewEventCharges() (ec *EventCharges) {
|
||||
Accounting: make(map[string]*AccountCharge),
|
||||
UnitFactors: make(map[string]*UnitFactor),
|
||||
Rating: make(map[string]*RateSInterval),
|
||||
Accounts: make(map[string]*Account),
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -38,16 +39,16 @@ type EventCharges struct {
|
||||
Concretes *Decimal // total concrete units charged
|
||||
|
||||
ChargingIntervals []*ChargingInterval
|
||||
Accounts []*Account
|
||||
|
||||
Accounting map[string]*AccountCharge
|
||||
UnitFactors map[string]*UnitFactor
|
||||
Rating map[string]*RateSInterval
|
||||
Accounts map[string]*Account
|
||||
}
|
||||
|
||||
// Merge will merge the event charges into existing
|
||||
func (ec *EventCharges) Merge(eCs ...*EventCharges) {
|
||||
ec.syncIDs(eCs...) // so we can compare properly
|
||||
//ec.SyncIDs(eCs...) // so we can compare properly
|
||||
for _, nEc := range eCs {
|
||||
if sumAbst := SumDecimalAsBig(ec.Abstracts, nEc.Abstracts); sumAbst != nil {
|
||||
ec.Abstracts = &Decimal{sumAbst}
|
||||
@@ -55,7 +56,19 @@ func (ec *EventCharges) Merge(eCs ...*EventCharges) {
|
||||
if sumCrct := SumDecimalAsBig(ec.Concretes, nEc.Concretes); sumCrct != nil {
|
||||
ec.Concretes = &Decimal{sumCrct}
|
||||
}
|
||||
ec.appendChargingIntervals(ec.ChargingIntervals...)
|
||||
ec.appendChargingIntervals(nEc.ChargingIntervals...)
|
||||
for acntID, acntChrg := range nEc.Accounting {
|
||||
ec.Accounting[acntID] = acntChrg
|
||||
}
|
||||
for ufID, uF := range nEc.UnitFactors {
|
||||
ec.UnitFactors[ufID] = uF
|
||||
}
|
||||
for riID, rI := range nEc.Rating {
|
||||
ec.Rating[riID] = rI
|
||||
}
|
||||
for acntID, acnt := range nEc.Accounts {
|
||||
ec.Accounts[acntID] = acnt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +88,8 @@ func (ec *EventCharges) appendChargingIntervals(cIls ...*ChargingInterval) {
|
||||
}
|
||||
}
|
||||
|
||||
// syncIDs will repopulate Accounting, UnitFactors and Rating IDs if they equal the references in ec
|
||||
func (ec *EventCharges) syncIDs(eCs ...*EventCharges) {
|
||||
// SyncIDs will repopulate Accounting, UnitFactors and Rating IDs if they equal the references in ec
|
||||
func (ec *EventCharges) SyncIDs(eCs ...*EventCharges) {
|
||||
for _, nEc := range eCs {
|
||||
for _, cIl := range nEc.ChargingIntervals {
|
||||
for _, cIcrm := range cIl.Increments {
|
||||
@@ -151,16 +164,6 @@ func (ec *EventCharges) AsExtEventCharges() (eEc *ExtEventCharges, err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ec.Accounts != nil {
|
||||
eEc.Accounts = make([]*ExtAccount, len(ec.Accounts))
|
||||
for idx, val := range ec.Accounts {
|
||||
if extAccs, err := val.AsExtAccount(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
eEc.Accounts[idx] = extAccs
|
||||
}
|
||||
}
|
||||
}
|
||||
if ec.Accounting != nil {
|
||||
eEc.Accounting = make(map[string]*ExtAccountCharge, len(eEc.Accounting))
|
||||
for key, val := range ec.Accounting {
|
||||
@@ -191,6 +194,16 @@ func (ec *EventCharges) AsExtEventCharges() (eEc *ExtEventCharges, err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ec.Accounts != nil {
|
||||
eEc.Accounts = make(map[string]*ExtAccount, len(ec.Accounts))
|
||||
for acntID, acnt := range ec.Accounts {
|
||||
if extAccs, err := acnt.AsExtAccount(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
eEc.Accounts[acntID] = extAccs
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -230,11 +243,11 @@ type ExtEventCharges struct {
|
||||
Concretes *float64
|
||||
|
||||
ChargingIntervals []*ExtChargingInterval
|
||||
Accounts []*ExtAccount
|
||||
|
||||
Accounting map[string]*ExtAccountCharge
|
||||
UnitFactors map[string]*ExtUnitFactor
|
||||
Rating map[string]*ExtRateSInterval
|
||||
Accounts map[string]*ExtAccount
|
||||
}
|
||||
|
||||
type ChargingInterval struct {
|
||||
|
||||
@@ -22,11 +22,11 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
/*
|
||||
func TestECNewEventCharges(t *testing.T) {
|
||||
expected := &EventCharges{
|
||||
Accounting: make(map[string]*AccountCharge),
|
||||
@@ -39,6 +39,7 @@ func TestECNewEventCharges(t *testing.T) {
|
||||
t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestECMergeAbstractsEmpty(t *testing.T) {
|
||||
ec1 := &EventCharges{
|
||||
@@ -473,7 +474,7 @@ func TestCompressEqualsChargingInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func TestAsExtEventCharges(t *testing.T) {
|
||||
evCh := &EventCharges{
|
||||
ChargingIntervals: []*ChargingInterval{
|
||||
@@ -626,3 +627,4 @@ func TestAsExtEventChargersCheckErrors(t *testing.T) {
|
||||
}
|
||||
evCh.Rating["first_rates_interval"].IntervalStart = NewDecimal(0, 0)
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user