diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go index 1504467df..6d583d486 100644 --- a/accounts/abstractbalance.go +++ b/accounts/abstractbalance.go @@ -156,6 +156,7 @@ func (aB *abstractBalance) debitUsageFromConcrete(cBs []*concreteBalance, usage tCost = utils.SumBig(tCost, rcrntCost) } } + clnedUnts := cloneUnitsFromConcretes(cBs) for _, cB := range cBs { ev := utils.MapStorage{ utils.MetaOpts: cgrEv.Opts, @@ -163,13 +164,16 @@ func (aB *abstractBalance) debitUsageFromConcrete(cBs []*concreteBalance, usage } var dbted *utils.Decimal if dbted, _, err = cB.debitUnits(&utils.Decimal{tCost}, cgrEv.Tenant, ev); err != nil { + restoreUnitsFromClones(cBs, clnedUnts) return } tCost = utils.SubstractBig(tCost, dbted.Big) if tCost.Cmp(decimal.New(0, 0)) <= 0 { - return // have debitted all, total is smaller or equal to 0 + return // have debited all, total is smaller or equal to 0 } } + // we could not debit all, put back what we have debited + restoreUnitsFromClones(cBs, clnedUnts) return utils.ErrInsufficientCredit } @@ -207,30 +211,35 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, startTime time.Time, } } - blcVal := aB.blnCfg.Units + origBlclVal := new(decimal.Big).Copy(aB.blnCfg.Units.Big) // so we can restore on errors // balanceLimit var hasLmt bool blncLmt := aB.balanceLimit() if blncLmt != nil && blncLmt.Cmp(decimal.New(0, 0)) != 0 { - blcVal = utils.SubstractDecimal(blcVal, blncLmt) + aB.blnCfg.Units.Big = utils.SubstractBig(aB.blnCfg.Units.Big, blncLmt.Big) hasLmt = true } - // balance smaller than usage, correct usage - if blcVal.Compare(usage) == -1 && blncLmt != nil { - // will use special rounding to 0 since otherwise we go negative (ie: 0.05 as increment) - maxIncrm := &utils.Decimal{ - decimal.WithContext( - decimal.Context{RoundingMode: decimal.ToZero}).Quo(blcVal.Big, - costIcrm.Increment.Big).RoundToInt()} - usage = utils.MultiplyDecimal(maxIncrm, costIcrm.Increment) // decrease the usage to match the maximum increments - } // unitFactor var uF *utils.UnitFactor if uF, err = aB.unitFactor(cgrEv.Tenant, evNm); err != nil { return } + var hasUF bool + if uF != nil && uF.Factor.Cmp(decimal.New(1, 0)) != 0 { + usage.Big = utils.MultiplyBig(usage.Big, uF.Factor.Big) + hasUF = true + } + + // balance smaller than usage, correct usage + if aB.blnCfg.Units.Compare(usage) == -1 { + // will use special rounding to 0 since otherwise we go negative (ie: 0.05 as increment) + maxIncrm := decimal.WithContext( + decimal.Context{RoundingMode: decimal.ToZero}).Quo(aB.blnCfg.Units.Big, + costIcrm.Increment.Big).RoundToInt() + usage.Big = utils.MultiplyBig(maxIncrm, costIcrm.Increment.Big) // decrease the usage to match the maximum increments + } // attempt to debit usage with cost // fix the maximum number of iterations @@ -238,7 +247,8 @@ func (aB *abstractBalance) debitUsage(usage *utils.Decimal, startTime time.Time, continue } - fmt.Printf("costIcrm: %+v, blncLmt: %+v, hasLmt: %+v, uF: %+v", costIcrm, blncLmt, hasLmt, uF) + fmt.Printf("costIcrm: %+v, blncLmt: %+v, hasLmt: %+v, uF: %+v, origBlclVal: %s, hasUF: %v", + costIcrm, blncLmt, hasLmt, uF, origBlclVal, hasUF) return } diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go index 2149ab0d2..a61bc858d 100644 --- a/accounts/abstractbalance_test.go +++ b/accounts/abstractbalance_test.go @@ -98,9 +98,9 @@ func TestABDebitUsageFromConcrete(t *testing.T) { RecurrentFee: utils.NewDecimal(1, 0)}, new(utils.CGREvent)); err == nil || err != utils.ErrInsufficientCredit { t.Error(err) - } else if cBs[0].blnCfg.Units.Compare(utils.NewDecimal(-200, 0)) != 0 { + } else if cBs[0].blnCfg.Units.Compare(utils.NewDecimal(500, 0)) != 0 { t.Errorf("Unexpected units in first balance: %s", cBs[0].blnCfg.Units) - } else if cBs[1].blnCfg.Units.Compare(utils.NewDecimal(-1, 0)) != 0 { + } else if cBs[1].blnCfg.Units.Compare(utils.NewDecimal(125, 2)) != 0 { t.Errorf("Unexpected units in first balance: %s", cBs[1].blnCfg.Units) } } diff --git a/accounts/concretebalance.go b/accounts/concretebalance.go index 67743969b..8c90e19c1 100644 --- a/accounts/concretebalance.go +++ b/accounts/concretebalance.go @@ -159,13 +159,19 @@ func (cB *concreteBalance) debitUnits(dUnts *utils.Decimal, tnt string, } // cloneUnitsFromConcretes returns cloned units from the concrete balances passed as parameters -func cloneUnitsFromConcretes(cBs []*concreteBalance) (clnUnits []*utils.Decimal) { +func cloneUnitsFromConcretes(cBs []*concreteBalance) (clnedUnts []*utils.Decimal) { if cBs == nil { return } - clnUnits = make([]*utils.Decimal, len(cBs)) + clnedUnts = make([]*utils.Decimal, len(cBs)) for i := range cBs { - clnUnits[i] = cBs[i].blnCfg.Units.Clone() + clnedUnts[i] = cBs[i].blnCfg.Units.Clone() } return } + +func restoreUnitsFromClones(cBs []*concreteBalance, clnedUnts []*utils.Decimal) { + for i, clnedUnt := range clnedUnts { + cBs[i].blnCfg.Units.Big = clnedUnt.Big + } +}