diff --git a/apier/v2/apier.go b/apier/v2/apier.go index cd455dbc8..754adb1cf 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -336,7 +336,7 @@ func (self *ApierV2) SetActions(attrs utils.AttrSetActions, reply *string) error for idx, apiAct := range attrs.Actions { var vf *utils.ValueFormula if apiAct.Units != "" { - if x, err := utils.ParseBalanceFilterValue(apiAct.Units); err == nil { + if x, err := utils.ParseBalanceFilterValue(apiAct.BalanceType, apiAct.Units); err == nil { vf = x } else { return err diff --git a/engine/account.go b/engine/account.go index c6f225b51..bcaeca80b 100644 --- a/engine/account.go +++ b/engine/account.go @@ -393,7 +393,6 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulUnitBalances { //utils.Logger.Info(fmt.Sprintf("Unit balance: %+v", balance)) //utils.Logger.Info(fmt.Sprintf("CD BEFORE UNIT: %+v", cd)) - partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { @@ -441,7 +440,8 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulMoneyBalances { //utils.Logger.Info(fmt.Sprintf("Money balance: %+v", balance)) //utils.Logger.Info(fmt.Sprintf("CD BEFORE MONEY: %+v", cd)) - partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) + partCC, debitErr := balance.debitMoney(cd, balance.account, + usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } diff --git a/engine/balances.go b/engine/balances.go index b445eba7c..84a1c35f5 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -517,7 +517,7 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala } } else { inc.paid = false - // delete the rest of the unpiad increments/timespans + // delete the rest of the unpaid increments/timespans if incIndex == 0 { // cut the entire current timespan cc.Timespans = cc.Timespans[:tsIndex] diff --git a/engine/eventcost.go b/engine/eventcost.go index 84f9cdf4e..55325274c 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -265,7 +265,6 @@ func (ec *EventCost) AsCallCost() *CallCost { ts.TimeEnd = ts.TimeStart.Add( time.Duration(cIl.Usage().Nanoseconds() * int64(cIl.CompressFactor))) if cIl.RatingID != "" { - //fmt.Printf("Checking RatingID: <%s>\n", cIl.RatingID) if ec.Rating[cIl.RatingID].RatingFiltersID != "" { rfs := ec.RatingFilters[ec.Rating[cIl.RatingID].RatingFiltersID] ts.MatchedSubject = rfs["Subject"].(string) diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 4ac0f1ab2..26b264004 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -594,7 +594,7 @@ func (tpr *TpReader) LoadActions() (err error) { } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } @@ -1056,7 +1056,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } @@ -1399,7 +1399,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index 01935f450..096139b6f 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -29,13 +29,13 @@ import ( var dataDB *engine.DataManager -func TestSetStorage(t *testing.T) { +func TestDZ1SetStorage(t *testing.T) { data, _ := engine.NewMapStorageJson() dataDB = engine.NewDataManager(data) engine.SetDataStorage(dataDB) } -func TestLoadCsvTp(t *testing.T) { +func TestDZ1LoadCsvTp(t *testing.T) { timings := `ALWAYS,*any,*any,*any,*any,00:00:00 ASAP,*any,*any,*any,*any,*asap` destinations := `DST_UK_Mobile_BIG5,447596 @@ -51,7 +51,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` sharedGroups := `` lcrs := `` actions := `TOPUP10_AC,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,10,10,false,false,10 -TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,false,false,10` +TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40000000000,10,false,false,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10 TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` @@ -64,8 +64,12 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` - csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + csvr := engine.NewTpReader(dataDB.DataDB(), + engine.NewStringCSVStorage(',', destinations, timings, rates, + destinationRates, ratingPlans, ratingProfiles, + sharedGroups, lcrs, actions, actionPlans, actionTriggers, + accountActions, derivedCharges, cdrStats, users, aliases, + resLimits, stats, thresholds, filters), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -112,37 +116,41 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + /* + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { - t.Error("Wrong number of cached destinations found", cachedDests) - } - if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 2 { - t.Error("Wrong number of cached rating plans found", cachedRPlans) - } - if cachedRProfiles := cache.CountEntries(utils.RATING_PROFILE_PREFIX); cachedRProfiles != 0 { - t.Error("Wrong number of cached rating profiles found", cachedRProfiles) - } - if cachedActions := cache.CountEntries(utils.ACTION_PREFIX); cachedActions != 0 { - t.Error("Wrong number of cached actions found", cachedActions) - } + if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { + t.Error("Wrong number of cached destinations found", cachedDests) + } + if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 2 { + t.Error("Wrong number of cached rating plans found", cachedRPlans) + } + if cachedRProfiles := cache.CountEntries(utils.RATING_PROFILE_PREFIX); cachedRProfiles != 0 { + t.Error("Wrong number of cached rating profiles found", cachedRProfiles) + } + if cachedActions := cache.CountEntries(utils.ACTION_PREFIX); cachedActions != 0 { + t.Error("Wrong number of cached actions found", cachedActions) + } + */ } -func TestExecuteActions(t *testing.T) { +func TestDZ1ExecuteActions(t *testing.T) { scheduler.NewScheduler(dataDB).Reload() time.Sleep(10 * time.Millisecond) // Give time to scheduler to topup the account if acnt, err := dataDB.DataDB().GetAccount("cgrates.org:12344"); err != nil { t.Error(err) } else if len(acnt.BalanceMap) != 2 { t.Error("Account does not have enough balances: ", acnt.BalanceMap) - } else if acnt.BalanceMap[utils.VOICE][0].Value != 40 { - t.Error("Account does not have enough minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) + } else if acnt.BalanceMap[utils.VOICE][0].Value != 40000000000 { + t.Error("Account does not have enough minutes in balance", + acnt.BalanceMap[utils.VOICE][0].Value) } else if acnt.BalanceMap[utils.MONETARY][0].Value != 10 { - t.Error("Account does not have enough monetary balance", acnt.BalanceMap[utils.MONETARY][0].Value) + t.Error("Account does not have enough monetary balance", + acnt.BalanceMap[utils.MONETARY][0].Value) } } -func TestDebit(t *testing.T) { +func TestDZ1Debit(t *testing.T) { cd := &engine.CallDescriptor{ Direction: "*out", Category: "call", @@ -162,10 +170,12 @@ func TestDebit(t *testing.T) { if err != nil { t.Error(err) } - if acnt.BalanceMap[utils.VOICE][0].Value != 20 { - t.Error("Account does not have expected minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) + if acnt.BalanceMap[utils.VOICE][0].Value != 20000000000 { + t.Error("Account does not have expected *voice units in balance", + acnt.BalanceMap[utils.VOICE][0].Value) } if acnt.BalanceMap[utils.MONETARY][0].Value != 9.99 { - t.Error("Account does not have expected monetary balance", acnt.BalanceMap[utils.MONETARY][0].Value) + t.Error("Account does not have expected *monetary units in balance", + acnt.BalanceMap[utils.MONETARY][0].Value) } } diff --git a/utils/value_formula.go b/utils/value_formula.go index 4c292a108..9ee2217e7 100644 --- a/utils/value_formula.go +++ b/utils/value_formula.go @@ -33,9 +33,12 @@ type ValueFormula struct { Static float64 } -func ParseBalanceFilterValue(val string) (*ValueFormula, error) { - u, err := strconv.ParseFloat(val, 64) - if err == nil { +func ParseBalanceFilterValue(tor string, val string) (*ValueFormula, error) { + if tor == VOICE { // VOICE balance is parsed as nanoseconds with support for time duration strings + if d, err := ParseDurationWithNanosecs(val); err == nil { + return &ValueFormula{Static: float64(d.Nanoseconds())}, err + } + } else if u, err := strconv.ParseFloat(val, 64); err == nil { return &ValueFormula{Static: u}, err } var vf ValueFormula diff --git a/utils/value_formula_test.go b/utils/value_formula_test.go index 3a42ee9b0..2f3da0086 100644 --- a/utils/value_formula_test.go +++ b/utils/value_formula_test.go @@ -19,6 +19,7 @@ package utils import ( "encoding/json" + "reflect" "testing" "time" ) @@ -54,3 +55,24 @@ func TestValueFormulaDayYear(t *testing.T) { t.Error("error caclulating value using formula: ", x) } } + +func TestValueFormulaParseBalanceFilterValue(t *testing.T) { + eVF := &ValueFormula{Static: 10000000000.0} + if vf, err := ParseBalanceFilterValue(VOICE, "10s"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } + eVF = &ValueFormula{Static: 1024.0} + if vf, err := ParseBalanceFilterValue(DATA, "1024"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } + eVF = &ValueFormula{Static: 10.0} + if vf, err := ParseBalanceFilterValue(MONETARY, "10"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } +}