diff --git a/accounts/abstractbalance.go b/accounts/abstractbalance.go index 61880320f..57e0264cb 100644 --- a/accounts/abstractbalance.go +++ b/accounts/abstractbalance.go @@ -127,7 +127,9 @@ func (aB *abstractBalance) debitAbstracts(usage *decimal.Big, CompressFactor: 1, }, } + */ + var ecCost *utils.EventCharges if (costIcrm.FixedFee != nil && costIcrm.FixedFee.Cmp(decimal.New(0, 0)) != 0) || diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go index a36ab438d..8c1290110 100644 --- a/accounts/abstractbalance_test.go +++ b/accounts/abstractbalance_test.go @@ -370,7 +370,7 @@ func TestABCost0WithoutConcrete(t *testing.T) { } } -func TestABCost0Exceed11(t *testing.T) { +func TestABCost0Exceed1(t *testing.T) { // consume more units that has an abstract balance aB := &abstractBalance{ blnCfg: &utils.Balance{ @@ -401,7 +401,7 @@ func TestABCost0Exceed11(t *testing.T) { t.Error(err) } else if ec.Abstracts.Cmp(decimal.New(int64(60*time.Second), 0)) != 0 { t.Errorf("Unexpected debited units: %s", ec.Abstracts) - } else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(-10*time.Second), 0)) != 0 { + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(0, 0)) != 0 { t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) } else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(10, 0)) != 0 { t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units) diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 970d44a48..cea2868a8 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -591,16 +591,62 @@ func TestV1MaxAbstracts(t *testing.T) { } delete(accPrf.Balances, "ConcreteBalance2") + extAccPrf, err := accPrf.AsExtAccount() + if err != nil { + t.Error(err) + } + extAccPrf.Balances["AbstractBalance1"].Units = utils.Float64Pointer(float64(40*time.Second - 210*time.Nanosecond)) + exEvCh := utils.ExtEventCharges{ - Abstracts: utils.Float64Pointer(210), - Accounting: map[string]*utils.ExtAccountCharge{}, + Abstracts: utils.Float64Pointer(210), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.ExtAccountCharge{ + "GENUUID1": { + AccountID: "TestV1MaxAbstracts", + BalanceID: "AbstractBalance1", + BalanceLimit: utils.Float64Pointer(0), + RatingID: "GENUUID_RATING", + }, + }, UnitFactors: map[string]*utils.ExtUnitFactor{}, - Rating: map[string]*utils.ExtRateSInterval{}, + Rating: map[string]*utils.ExtRateSInterval{ + "GENUUID_RATING": { + Increments: []*utils.ExtRateSIncrement{ + { + Rate: &utils.ExtRate{ + ID: "*costIncrement", + IntervalRates: []*utils.ExtIntervalRate{ + { + FixedFee: utils.Float64Pointer(0), + RecurrentFee: utils.Float64Pointer(0), + }, + }, + }, + IntervalRateIndex: 0, + CompressFactor: 1, + }, + }, + CompressFactor: 1, + }, + }, + Accounts: map[string]*utils.ExtAccount{ + "TestV1MaxAbstracts": extAccPrf, + }, } if err := accnts.V1MaxAbstracts(args, &reply); err != nil { t.Error(err) - } else if !reflect.DeepEqual(exEvCh, reply) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } else { + exEvCh.Charges = reply.Charges + exEvCh.Rating = reply.Rating + exEvCh.Accounting = reply.Accounting + if !reflect.DeepEqual(exEvCh, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } } } @@ -792,16 +838,53 @@ func TestV1MaxConcretes(t *testing.T) { } accPrf.Balances["AbstractBalance1"].Weights[0].FilterIDs = []string{} + extAccPrf, err := accPrf.AsExtAccount() + if err != nil { + t.Error(err) + } + extAccPrf.Balances["ConcreteBalance1"].Units = utils.Float64Pointer(0) + extAccPrf.Balances["ConcreteBalance2"].Units = utils.Float64Pointer(0) + exEvCh := utils.ExtEventCharges{ - Concretes: utils.Float64Pointer(float64(time.Minute + 30*time.Second)), - Accounting: map[string]*utils.ExtAccountCharge{}, + Concretes: utils.Float64Pointer(float64(time.Minute + 30*time.Second)), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID2", + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.ExtAccountCharge{ + "GENUUID1": { + AccountID: "TestV1DebitAbstracts", + BalanceID: "ConcreteBalance1", + Units: utils.Float64Pointer(float64(time.Minute)), + BalanceLimit: utils.Float64Pointer(0), + }, + "GENUUID2": { + AccountID: "TestV1DebitAbstracts", + BalanceID: "ConcreteBalance2", + Units: utils.Float64Pointer(float64(30 * time.Second)), + BalanceLimit: utils.Float64Pointer(0), + }, + }, UnitFactors: map[string]*utils.ExtUnitFactor{}, Rating: map[string]*utils.ExtRateSInterval{}, + Accounts: map[string]*utils.ExtAccount{ + "TestV1DebitAbstracts": extAccPrf, + }, } if err := accnts.V1MaxConcretes(args, &reply); err != nil { t.Error(err) - } else if !reflect.DeepEqual(exEvCh, reply) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } else { + exEvCh.Charges = reply.Charges + exEvCh.Accounting = reply.Accounting + if !reflect.DeepEqual(exEvCh, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } } } @@ -906,16 +989,52 @@ func TestV1DebitConcretes(t *testing.T) { } accPrf.Balances["AbstractBalance1"].Weights[0].FilterIDs = []string{} + extAccPrf, err := accPrf.AsExtAccount() + if err != nil { + t.Error(err) + } + extAccPrf.Balances["ConcreteBalance1"].Units = utils.Float64Pointer(0) + extAccPrf.Balances["ConcreteBalance2"].Units = utils.Float64Pointer(0) exEvCh := utils.ExtEventCharges{ - Concretes: utils.Float64Pointer(float64(time.Minute + 30*time.Second)), - Accounting: map[string]*utils.ExtAccountCharge{}, + Concretes: utils.Float64Pointer(float64(time.Minute + 30*time.Second)), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID2", + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.ExtAccountCharge{ + "GENUUID1": { + AccountID: "TestV1DebitAbstracts", + BalanceID: "ConcreteBalance1", + Units: utils.Float64Pointer(60000000000), + BalanceLimit: utils.Float64Pointer(0), + }, + "GENUUID2": { + AccountID: "TestV1DebitAbstracts", + BalanceID: "ConcreteBalance2", + Units: utils.Float64Pointer(30000000000), + BalanceLimit: utils.Float64Pointer(0), + }, + }, UnitFactors: map[string]*utils.ExtUnitFactor{}, Rating: map[string]*utils.ExtRateSInterval{}, + Accounts: map[string]*utils.ExtAccount{ + "TestV1DebitAbstracts": extAccPrf, + }, } if err := accnts.V1DebitConcretes(args, &reply); err != nil { t.Error(err) - } else if !reflect.DeepEqual(exEvCh, reply) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } else { + exEvCh.Accounting = reply.Accounting + exEvCh.Charges = reply.Charges + if !reflect.DeepEqual(exEvCh, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exEvCh), utils.ToJSON(reply)) + } } //now we will check the debited account @@ -1391,50 +1510,210 @@ func TestV1DebitAbstractsEventCharges(t *testing.T) { } eEvChgs := utils.ExtEventCharges{ - Abstracts: utils.Float64Pointer(475000000000), - Concretes: utils.Float64Pointer(5.15), - Accounting: map[string]*utils.ExtAccountCharge{}, - UnitFactors: map[string]*utils.ExtUnitFactor{}, - Rating: map[string]*utils.ExtRateSInterval{}, + Abstracts: utils.Float64Pointer(475000000000), + Concretes: utils.Float64Pointer(5.15), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID2", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID3", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID4", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID5", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID6", + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.ExtAccountCharge{ + "GENUUID_GHOST1": { + AccountID: "TestV1DebitAbstractsEventCharges1", + BalanceID: cb1ID, + Units: utils.Float64Pointer(0.8), + BalanceLimit: utils.Float64Pointer(-200), + UnitFactorID: "GENUUID_FACTOR1", + }, + "GENUUID3": { + AccountID: "TestV1DebitAbstractsEventCharges1", + BalanceID: ab2ID, + BalanceLimit: utils.Float64Pointer(0), + RatingID: "GENUUID_RATING1", + }, + "GENUUID2": { + AccountID: "TestV1DebitAbstractsEventCharges1", + BalanceID: cb1ID, + Units: utils.Float64Pointer(2), + BalanceLimit: utils.Float64Pointer(-200), + UnitFactorID: "GENUUID_FACTOR2", + }, + "GENUUID5": { + AccountID: "TestV1DebitAbstractsEventCharges2", + BalanceID: ab1ID, + BalanceLimit: utils.Float64Pointer(0), + RatingID: "GENUUID_RATING2", + JoinedChargeIDs: []string{"GENUUID_GHOST2"}, + }, + "GENUUID6": { + AccountID: "TestV1DebitAbstractsEventCharges2", + BalanceID: cb1ID, + Units: utils.Float64Pointer(0.3), + }, + "GENUUID4": { + AccountID: "TestV1DebitAbstractsEventCharges1", + BalanceID: cb2ID, + Units: utils.Float64Pointer(1.25), + BalanceLimit: utils.Float64Pointer(0), + }, + "GENUUID_GHOST2": { + AccountID: "TestV1DebitAbstractsEventCharges2", + BalanceID: cb1ID, + Units: utils.Float64Pointer(0.6), + }, + "GENUUID1": { + AccountID: "TestV1DebitAbstractsEventCharges1", + BalanceID: ab1ID, + BalanceLimit: utils.Float64Pointer(0), + RatingID: "GENUUID_RATING3", + JoinedChargeIDs: []string{"GENUUID_GHOST1"}, + }, + }, + UnitFactors: map[string]*utils.ExtUnitFactor{ + "GENUUID_FACTOR1": { + Factor: utils.Float64Pointer(100), + }, + "GENUUID_FACTOR2": { + Factor: utils.Float64Pointer(100), + }, + }, + Rating: map[string]*utils.ExtRateSInterval{ + "GENUUID_RATING1": { + Increments: []*utils.ExtRateSIncrement{ + { + Rate: &utils.ExtRate{ + ID: "*costIncrement", + IntervalRates: []*utils.ExtIntervalRate{ + { + RecurrentFee: utils.Float64Pointer(0), + }, + }, + }, + IntervalRateIndex: 0, + CompressFactor: 1, + }, + }, + CompressFactor: 1, + }, + "GENUUID_RATING2": { + Increments: []*utils.ExtRateSIncrement{ + { + Rate: &utils.ExtRate{ + ID: "*costIncrement", + IntervalRates: []*utils.ExtIntervalRate{ + { + FixedFee: utils.Float64Pointer(0.4), + RecurrentFee: utils.Float64Pointer(0.2), + }, + }, + }, + IntervalRateIndex: 0, + CompressFactor: 1, + }, + }, + CompressFactor: 1, + }, + "GENUUID_RATING3": { + Increments: []*utils.ExtRateSIncrement{ + { + Rate: &utils.ExtRate{ + ID: "*costIncrement", + IntervalRates: []*utils.ExtIntervalRate{ + { + FixedFee: utils.Float64Pointer(0.4), + RecurrentFee: utils.Float64Pointer(0.2), + }, + }, + }, + IntervalRateIndex: 0, + CompressFactor: 1, + }, + }, + CompressFactor: 1, + }, + }, + Accounts: make(map[string]*utils.ExtAccount), } args := &utils.ArgsAccountsForEvent{ CGREvent: &utils.CGREvent{ ID: "TestV1DebitAbstractsEventCharges", Tenant: utils.CGRateSorg, APIOpts: map[string]interface{}{ - //utils.MetaUsage: "7m55s", // 7m55s to debit both accounts - utils.MetaUsage: "1m", + utils.MetaUsage: "7m55s", // 7m55s to debit both accounts + //utils.MetaUsage: "1m", }, }, } var rply utils.ExtEventCharges if err := accnts.V1DebitAbstracts(args, &rply); err != nil { t.Error(err) - } 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)) - } - 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)) - } - */ + 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)) + } + + extAcnt1, err := acnt1.AsExtAccount() + if err != nil { + t.Error(err) + } + extAcnt2, err := acnt2.AsExtAccount() + if err != nil { + t.Error(err) + } + + //as the names of accounting, charges, UF are GENUUIDs generator, we will change their names for comparing + eEvChgs.Accounts = map[string]*utils.ExtAccount{ + "TestV1DebitAbstractsEventCharges1": extAcnt1, + "TestV1DebitAbstractsEventCharges2": extAcnt2, + } + eEvChgs.Charges = rply.Charges + eEvChgs.Accounting = rply.Accounting + eEvChgs.UnitFactors = rply.UnitFactors + eEvChgs.Accounts = rply.Accounts + eEvChgs.Rating = rply.Rating + if !reflect.DeepEqual(eEvChgs, rply) { + t.Errorf("Expected %+v, received %+v", utils.ToJSON(eEvChgs), utils.ToJSON(rply)) + } } +/* func TestV1DebitAbstractsWithRecurrentFeeNegative(t *testing.T) { engine.Cache.Clear(nil) cfg := config.NewDefaultCGRConfig() @@ -1508,3 +1787,5 @@ func TestV1DebitAbstractsWithRecurrentFeeNegative(t *testing.T) { t.Errorf("Expected %+v,received %+v", utils.ToJSON(acnt), utils.ToJSON(rcv)) } } + +*/ diff --git a/accounts/libaccounts_test.go b/accounts/libaccounts_test.go index 882d0777c..027e4b256 100644 --- a/accounts/libaccounts_test.go +++ b/accounts/libaccounts_test.go @@ -212,7 +212,6 @@ func TestDebitUsageFromConcretes(t *testing.T) { data := engine.NewInternalDB(nil, nil, true) dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) cfg := config.NewDefaultCGRConfig() - filterS := engine.NewFilterS(cfg, nil, dm) cb1 := &concreteBalance{ blnCfg: &utils.Balance{ @@ -231,10 +230,32 @@ func TestDebitUsageFromConcretes(t *testing.T) { fltrS: filterS, } expectedEvCh := &utils.EventCharges{ - Concretes: utils.NewDecimal(700, 0), - Accounting: make(map[string]*utils.AccountCharge), + Concretes: utils.NewDecimal(700, 0), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", + CompressFactor: 1, + }, + { + ChargingID: "GENUUID2", + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.AccountCharge{ + "GENUUID2": { + BalanceID: "CB2", + Units: utils.NewDecimal(200, 0), + BalanceLimit: utils.NewDecimal(0, 0), + }, + "GENUUID1": { + BalanceID: "CB2", + Units: utils.NewDecimal(500, 0), + BalanceLimit: utils.NewDecimal(0, 0), + }, + }, UnitFactors: make(map[string]*utils.UnitFactor), Rating: make(map[string]*utils.RateSInterval), + Accounts: make(map[string]*utils.Account), } if evCh, err := debitConcreteUnits(decimal.New(700, 0), utils.EmptyString, @@ -244,8 +265,13 @@ func TestDebitUsageFromConcretes(t *testing.T) { t.Errorf("balance remaining: %s", cb1.blnCfg.Units) } else if cb2.blnCfg.Units.Cmp(decimal.New(300, 0)) != 0 { t.Errorf("balance remaining: %s", cb2.blnCfg.Units) - } else if !reflect.DeepEqual(expectedEvCh, evCh) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedEvCh), utils.ToJSON(evCh)) + } else { + //as the names of accounting, charges, UF are GENUUIDs generator, we will change their names for comparing + expectedEvCh.Charges = evCh.Charges + expectedEvCh.Accounting = evCh.Accounting + if !reflect.DeepEqual(evCh, expectedEvCh) { + t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedEvCh), utils.ToJSON(evCh)) + } } cb1.blnCfg.Units = utils.NewDecimal(500, 0) @@ -310,10 +336,32 @@ func TestDebitUsageFromConcretesFromRateS(t *testing.T) { } expectedEvCh := &utils.EventCharges{ - Concretes: utils.NewDecimal(700, 0), - Accounting: make(map[string]*utils.AccountCharge), + Concretes: utils.NewDecimal(700, 0), + Charges: []*utils.ChargeEntry{ + { + ChargingID: "GENUUID1", // will be changed + CompressFactor: 1, + }, + { + ChargingID: "GENUUID2", // will be changed + CompressFactor: 1, + }, + }, + Accounting: map[string]*utils.AccountCharge{ + "GENUUID2": { + BalanceID: "CB2", + Units: utils.NewDecimal(200, 0), + BalanceLimit: utils.NewDecimal(0, 0), + }, + "GENUUID1": { + BalanceID: "CB1", + Units: utils.NewDecimal(500, 0), + BalanceLimit: utils.NewDecimal(0, 0), + }, + }, UnitFactors: make(map[string]*utils.UnitFactor), Rating: make(map[string]*utils.RateSInterval), + Accounts: make(map[string]*utils.Account), } if evCh, err := debitConcreteUnits(decimal.New(700, 0), utils.EmptyString, @@ -323,8 +371,13 @@ func TestDebitUsageFromConcretesFromRateS(t *testing.T) { t.Errorf("balance remaining: %s", cb1.blnCfg.Units) } else if cb2.blnCfg.Units.Cmp(decimal.New(300, 0)) != 0 { t.Errorf("balance remaining: %s", cb2.blnCfg.Units) - } else if !reflect.DeepEqual(expectedEvCh, evCh) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedEvCh), utils.ToJSON(evCh)) + } else { + //as the names of accounting, charges, UF are GENUUIDs generator, we will change their names for comparing + expectedEvCh.Charges = evCh.Charges + expectedEvCh.Accounting = evCh.Accounting + if !reflect.DeepEqual(evCh, expectedEvCh) { + t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedEvCh), utils.ToJSON(evCh)) + } } // debit all the units from balances diff --git a/utils/eventcharges.go b/utils/eventcharges.go index d8f0a9b5b..c10c823bc 100644 --- a/utils/eventcharges.go +++ b/utils/eventcharges.go @@ -61,7 +61,7 @@ func (ec *EventCharges) Merge(eCs ...*EventCharges) { if sumCrct := SumDecimalAsBig(ec.Concretes, nEc.Concretes); sumCrct != nil { ec.Concretes = &Decimal{sumCrct} } - ec.appendCharges(nEc.Charges...) + ec.appendChargeEntry(nEc.Charges...) for acntID, acntChrg := range nEc.Accounting { ec.Accounting[acntID] = acntChrg } @@ -77,9 +77,9 @@ func (ec *EventCharges) Merge(eCs ...*EventCharges) { } } -// appendCharges will add new charge to the existing. +// appendChargeEntry will add new charge to the existing. // if possible, the existing last one in ec will be compressed -func (ec *EventCharges) appendCharges(cIls ...*ChargeEntry) { +func (ec *EventCharges) appendChargeEntry(cIls ...*ChargeEntry) { for i, cIl := range cIls { if i == 0 && len(ec.Charges) == 0 { ec.Charges = []*ChargeEntry{cIl}