diff --git a/agents/diam_it_test.go b/agents/diam_it_test.go index 305855754..06b192813 100644 --- a/agents/diam_it_test.go +++ b/agents/diam_it_test.go @@ -859,11 +859,14 @@ func testDiamItCCRSMS(t *testing.T) { func testDiamInitWithSessionDisconnect(t *testing.T) { attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", - Account: "testDiamInitWithSessionDisconnect", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("testDiamInitWithSessionDisconnect"), - Value: utils.Float64Pointer(1 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero1ms")} + Account: "testDiamInitWithSessionDisconnect", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "testDiamInitWithSessionDisconnect", + utils.Value: float64(time.Second), + utils.RatingSubject: "*zero1ms", + }, + } var reply string if err := apierRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) diff --git a/agents/httpagent_it_test.go b/agents/httpagent_it_test.go index 9e09e7a27..eadf18cf9 100644 --- a/agents/httpagent_it_test.go +++ b/agents/httpagent_it_test.go @@ -185,12 +185,14 @@ func testHAitAuth1001(t *testing.T) { maxDuration := 60 attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: acnt, - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(float64(maxDuration) * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero5ms"), + Tenant: "cgrates.org", + Account: acnt, + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: float64(maxDuration) * float64(time.Second), + utils.RatingSubject: "*zero5ms", + }, } var reply string if err := haRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index b9227230f..4371c9d00 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -37,19 +37,19 @@ type AccountActionTiming struct { NextExecTime time.Time // Next execution time } -func (self *ApierV1) GetAccountActionPlan(attrs utils.TenantAccount, reply *[]*AccountActionTiming) error { +func (api *ApierV1) GetAccountActionPlan(attrs utils.TenantAccount, reply *[]*AccountActionTiming) error { if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(strings.Join(missing, ","), "") } acntID := utils.ConcatenatedKey(attrs.Tenant, attrs.Account) acntATsIf, err := guardian.Guardian.Guard(func() (interface{}, error) { - acntAPids, err := self.DataManager.GetAccountActionPlans(acntID, false, utils.NonTransactional) + acntAPids, err := api.DataManager.GetAccountActionPlans(acntID, false, utils.NonTransactional) if err != nil && err != utils.ErrNotFound { return nil, utils.NewErrServerError(err) } var acntAPs []*engine.ActionPlan for _, apID := range acntAPids { - if ap, err := self.DataManager.GetActionPlan(apID, false, utils.NonTransactional); err != nil { + if ap, err := api.DataManager.GetActionPlan(apID, false, utils.NonTransactional); err != nil { return nil, err } else if ap != nil { acntAPs = append(acntAPs, ap) @@ -85,7 +85,7 @@ type AttrRemoveActionTiming struct { } // Removes an ActionTimings or parts of it depending on filters being set -func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *string) (err error) { +func (api *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *string) (err error) { if missing := utils.MissingStructFields(&attrs, []string{"ActionPlanId"}); len(missing) != 0 { // Only mandatory ActionPlanId return utils.NewErrMandatoryIeMissing(missing...) } @@ -99,7 +99,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str var remAcntAPids []string // list of accounts who's indexes need modification _, err = guardian.Guardian.Guard(func() (interface{}, error) { - ap, err := self.DataManager.GetActionPlan(attrs.ActionPlanId, false, utils.NonTransactional) + ap, err := api.DataManager.GetActionPlan(attrs.ActionPlanId, false, utils.NonTransactional) if err != nil { return 0, err } else if ap == nil { @@ -108,7 +108,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str if accID != "" { delete(ap.AccountIDs, accID) remAcntAPids = append(remAcntAPids, accID) - err = self.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) + err = api.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) goto UPDATE } if attrs.ActionTimingId != "" { // delete only a action timing from action plan @@ -119,7 +119,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str break } } - err = self.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) + err = api.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) goto UPDATE } if attrs.ActionPlanId != "" { // delete the entire action plan @@ -127,7 +127,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str for acntID := range ap.AccountIDs { // Make sure we clear indexes for all accounts remAcntAPids = append(remAcntAPids, acntID) } - err = self.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) + err = api.DataManager.SetActionPlan(ap.Id, ap, true, utils.NonTransactional) goto UPDATE } @@ -135,16 +135,16 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str if err != nil { return 0, err } - if err = self.DataManager.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, []string{attrs.ActionPlanId}, true); err != nil { + if err = api.DataManager.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, []string{attrs.ActionPlanId}, true); err != nil { return 0, err } for _, acntID := range remAcntAPids { - if err = self.DataManager.RemAccountActionPlans(acntID, []string{attrs.ActionPlanId}); err != nil { + if err = api.DataManager.RemAccountActionPlans(acntID, []string{attrs.ActionPlanId}); err != nil { return 0, nil } } if len(remAcntAPids) != 0 { - if err = self.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, remAcntAPids, true); err != nil { + if err = api.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, remAcntAPids, true); err != nil { return 0, nil } } @@ -155,7 +155,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str return utils.NewErrServerError(err) } if attrs.ReloadScheduler { - sched := self.SchedulerService.GetScheduler() + sched := api.SchedulerService.GetScheduler() if sched == nil { return errors.New(utils.SchedulerNotRunningCaps) } @@ -166,7 +166,7 @@ func (self *ApierV1) RemoveActionTiming(attrs AttrRemoveActionTiming, reply *str } // Ads a new account into dataDb. If already defined, returns success. -func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err error) { +func (api *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err error) { if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } @@ -174,7 +174,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e dirtyActionPlans := make(map[string]*engine.ActionPlan) _, err = guardian.Guardian.Guard(func() (interface{}, error) { var ub *engine.Account - if bal, _ := self.DataManager.GetAccount(accID); bal != nil { + if bal, _ := api.DataManager.GetAccount(accID); bal != nil { ub = bal } else { // Not found in db, create it here ub = &engine.Account{ @@ -183,7 +183,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e } if attr.ActionPlanId != "" { _, err := guardian.Guardian.Guard(func() (interface{}, error) { - acntAPids, err := self.DataManager.GetAccountActionPlans(accID, false, utils.NonTransactional) + acntAPids, err := api.DataManager.GetAccountActionPlans(accID, false, utils.NonTransactional) if err != nil && err != utils.ErrNotFound { return 0, err } @@ -194,7 +194,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e i++ // increase index since we don't remove from slice continue } - ap, err := self.DataManager.GetActionPlan(apID, false, utils.NonTransactional) + ap, err := api.DataManager.GetActionPlan(apID, false, utils.NonTransactional) if err != nil { return 0, err } @@ -203,7 +203,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e acntAPids = append(acntAPids[:i], acntAPids[i+1:]...) // remove the item from the list so we can overwrite the real list } if !utils.IsSliceMember(acntAPids, attr.ActionPlanId) { // Account not yet attached to action plan, do it here - ap, err := self.DataManager.GetActionPlan(attr.ActionPlanId, false, utils.NonTransactional) + ap, err := api.DataManager.GetActionPlan(attr.ActionPlanId, false, utils.NonTransactional) if err != nil { return 0, err } @@ -221,7 +221,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e AccountID: accID, ActionsID: at.ActionsID, } - if err = self.DataManager.DataDB().PushTask(t); err != nil { + if err = api.DataManager.DataDB().PushTask(t); err != nil { return 0, err } } @@ -230,19 +230,19 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e apIDs := make([]string, len(dirtyActionPlans)) i := 0 for actionPlanID, ap := range dirtyActionPlans { - if err := self.DataManager.SetActionPlan(actionPlanID, ap, true, utils.NonTransactional); err != nil { + if err := api.DataManager.SetActionPlan(actionPlanID, ap, true, utils.NonTransactional); err != nil { return 0, err } apIDs[i] = actionPlanID i++ } - if err := self.DataManager.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, apIDs, true); err != nil { + if err := api.DataManager.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, apIDs, true); err != nil { return 0, err } - if err := self.DataManager.SetAccountActionPlans(accID, acntAPids, true); err != nil { + if err := api.DataManager.SetAccountActionPlans(accID, acntAPids, true); err != nil { return 0, err } - if err = self.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{accID}, true); err != nil { + if err = api.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{accID}, true); err != nil { return 0, err } return 0, nil @@ -253,7 +253,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e } if attr.ActionTriggersId != "" { - atrs, err := self.DataManager.GetActionTriggers(attr.ActionTriggersId, false, utils.NonTransactional) + atrs, err := api.DataManager.GetActionTriggers(attr.ActionTriggersId, false, utils.NonTransactional) if err != nil { return 0, err } @@ -268,7 +268,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e ub.Disabled = *attr.Disabled } // All prepared, save account - if err := self.DataManager.SetAccount(ub); err != nil { + if err := api.DataManager.SetAccount(ub); err != nil { return 0, err } return 0, nil @@ -277,7 +277,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e return utils.NewErrServerError(err) } if attr.ReloadScheduler && len(dirtyActionPlans) != 0 { - sched := self.SchedulerService.GetScheduler() + sched := api.SchedulerService.GetScheduler() if sched == nil { return errors.New(utils.SchedulerNotRunningCaps) } @@ -287,7 +287,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) (err e return nil } -func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) (err error) { +func (api *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) (err error) { if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } @@ -296,7 +296,7 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) _, err = guardian.Guardian.Guard(func() (interface{}, error) { // remove it from all action plans _, err := guardian.Guardian.Guard(func() (interface{}, error) { - actionPlansMap, err := self.DataManager.GetAllActionPlans() + actionPlansMap, err := api.DataManager.GetAllActionPlans() if err == utils.ErrNotFound { // no action plans return 0, nil @@ -313,7 +313,7 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) } for actionPlanID, ap := range dirtyActionPlans { - if err := self.DataManager.SetActionPlan(actionPlanID, ap, true, + if err := api.DataManager.SetActionPlan(actionPlanID, ap, true, utils.NonTransactional); err != nil { return 0, err } @@ -323,7 +323,7 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) if err != nil { return 0, err } - if err := self.DataManager.RemoveAccount(accID); err != nil { + if err := api.DataManager.RemoveAccount(accID); err != nil { return 0, err } return 0, nil @@ -331,11 +331,11 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) if err != nil { return utils.NewErrServerError(err) } - if err = self.DataManager.RemAccountActionPlans(accID, nil); err != nil && + if err = api.DataManager.RemAccountActionPlans(accID, nil); err != nil && err.Error() != utils.ErrNotFound.Error() { return err } - if err = self.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, + if err = api.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{accID}, true); err != nil && err.Error() != utils.ErrNotFound.Error() { return err @@ -344,14 +344,14 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) return nil } -func (self *ApierV1) GetAccounts(attr utils.AttrGetAccounts, reply *[]interface{}) error { +func (api *ApierV1) GetAccounts(attr utils.AttrGetAccounts, reply *[]interface{}) error { if len(attr.Tenant) == 0 { return utils.NewErrMandatoryIeMissing("Tenant") } var accountKeys []string var err error if len(attr.AccountIds) == 0 { - if accountKeys, err = self.DataManager.DataDB().GetKeysForPrefix(utils.ACCOUNT_PREFIX + attr.Tenant); err != nil { + if accountKeys, err = api.DataManager.DataDB().GetKeysForPrefix(utils.ACCOUNT_PREFIX + attr.Tenant); err != nil { return err } } else { @@ -374,7 +374,7 @@ func (self *ApierV1) GetAccounts(attr utils.AttrGetAccounts, reply *[]interface{ } retAccounts := make([]interface{}, 0) for _, acntKey := range limitedAccounts { - if acnt, err := self.DataManager.GetAccount(acntKey[len(utils.ACCOUNT_PREFIX):]); err != nil && err != utils.ErrNotFound { // Not found is not an error here + if acnt, err := api.DataManager.GetAccount(acntKey[len(utils.ACCOUNT_PREFIX):]); err != nil && err != utils.ErrNotFound { // Not found is not an error here return err } else if acnt != nil { if attr.Disabled != nil && *attr.Disabled != acnt.Disabled { @@ -388,9 +388,9 @@ func (self *ApierV1) GetAccounts(attr utils.AttrGetAccounts, reply *[]interface{ } // Get balance -func (self *ApierV1) GetAccount(attr *utils.AttrGetAccount, reply *interface{}) error { +func (api *ApierV1) GetAccount(attr *utils.AttrGetAccount, reply *interface{}) error { tag := utils.ConcatenatedKey(attr.Tenant, attr.Account) - userBalance, err := self.DataManager.GetAccount(tag) + userBalance, err := api.DataManager.GetAccount(tag) if err != nil { return err } @@ -421,21 +421,21 @@ type AttrAddBalance struct { ExtraData *map[string]interface{} } -func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { - return self.modifyBalance(utils.TOPUP, attr, reply) +func (api *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { + return api.modifyBalance(utils.TOPUP, attr, reply) } -func (self *ApierV1) DebitBalance(attr *AttrAddBalance, reply *string) error { - return self.modifyBalance(utils.DEBIT, attr, reply) +func (api *ApierV1) DebitBalance(attr *AttrAddBalance, reply *string) error { + return api.modifyBalance(utils.DEBIT, attr, reply) } -func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *string) error { +func (api *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType", "Value"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } var expTime *time.Time if attr.ExpiryTime != nil { expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, - self.Config.GeneralCfg().DefaultTimezone) + api.Config.GeneralCfg().DefaultTimezone) if err != nil { *reply = err.Error() return err @@ -443,12 +443,12 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st expTime = &expTimeVal } accID := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.DataManager.GetAccount(accID); err != nil { + if _, err := api.DataManager.GetAccount(accID); err != nil { // create account if does not exist account := &engine.Account{ ID: accID, } - if err := self.DataManager.SetAccount(account); err != nil { + if err := api.DataManager.SetAccount(account); err != nil { *reply = err.Error() return err } @@ -490,7 +490,7 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st if attr.TimingIds != nil { a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) for _, timingID := range strings.Split(*attr.TimingIds, utils.INFIELD_SEP) { - tmg, err := self.DataManager.GetTiming(timingID, false, utils.NonTransactional) + tmg, err := api.DataManager.GetTiming(timingID, false, utils.NonTransactional) if err != nil { return err } @@ -521,75 +521,45 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st return nil } -func (self *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) error { +// SetBalance sets the balance for the given account +// if the account is not already created it will create the account also +func (api *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) (err error) { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - if (attr.BalanceID == nil || *attr.BalanceID == "") && - (attr.BalanceUUID == nil || *attr.BalanceUUID == "") { + var balance *engine.BalanceFilter + if balance, err = engine.NewBalanceFilter(attr.Balance, api.Config.GeneralCfg().DefaultTimezone); err != nil { + return + } + balance.Type = utils.StringPointer(attr.BalanceType) + if (balance.ID == nil || *balance.ID == "") && + (balance.Uuid == nil || *balance.Uuid == "") { return utils.NewErrMandatoryIeMissing("BalanceID", "or", "BalanceUUID") } - var expTime *time.Time - if attr.ExpiryTime != nil { - expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, - self.Config.GeneralCfg().DefaultTimezone) - if err != nil { - *reply = err.Error() - return err - } - expTime = &expTimeVal - } + accID := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.DataManager.GetAccount(accID); err != nil { + if _, err = api.DataManager.GetAccount(accID); err != nil { // create account if not exists account := &engine.Account{ ID: accID, } - if err := self.DataManager.SetAccount(account); err != nil { - *reply = err.Error() - return err + if err = api.DataManager.SetAccount(account); err != nil { + return } } at := &engine.ActionTiming{} //check if we have extra data - if attr.ExtraData != nil && len(*attr.ExtraData) != 0 { - at.ExtraData = *attr.ExtraData + if attr.ActionExtraData != nil && len(*attr.ActionExtraData) != 0 { + at.ExtraData = *attr.ActionExtraData } at.SetAccountIDs(utils.StringMap{accID: true}) - - a := &engine.Action{ - ActionType: utils.SET_BALANCE, - Balance: &engine.BalanceFilter{ - Uuid: attr.BalanceUUID, - ID: attr.BalanceID, - Type: utils.StringPointer(attr.BalanceType), - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Weight: attr.Weight, - Blocker: attr.Blocker, - Disabled: attr.Disabled, - }, - } - if attr.Value != nil { - a.Balance.Value = &utils.ValueFormula{Static: math.Abs(*attr.Value)} - } - if attr.DestinationIds != nil { - a.Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.DestinationIds)) - } - if attr.Categories != nil { - a.Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(*attr.Categories)) - } - if attr.SharedGroups != nil { - a.Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(*attr.SharedGroups)) - } - if attr.TimingIds != nil { - a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) - for _, timingID := range strings.Split(*attr.TimingIds, utils.INFIELD_SEP) { - tmg, err := self.DataManager.GetTiming(timingID, false, utils.NonTransactional) - if err != nil { - return err + if balance.TimingIDs != nil { + for _, timingID := range balance.TimingIDs.Slice() { + var tmg *utils.TPTiming + if tmg, err = api.DataManager.GetTiming(timingID, false, utils.NonTransactional); err != nil { + return } - a.Balance.Timings = append(a.Balance.Timings, &engine.RITiming{ + balance.Timings = append(balance.Timings, &engine.RITiming{ Years: tmg.Years, Months: tmg.Months, MonthDays: tmg.MonthDays, @@ -599,75 +569,53 @@ func (self *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) error }) } } + + a := &engine.Action{ + ActionType: utils.SET_BALANCE, + Balance: balance, + } publishAction := &engine.Action{ ActionType: utils.MetaPublishBalance, } acts := engine.Actions{a, publishAction} - if attr.Cdrlog != nil && *attr.Cdrlog { + if attr.Cdrlog { acts = engine.Actions{a, publishAction, &engine.Action{ ActionType: utils.CDRLOG, }} } at.SetActions(acts) - if err := at.Execute(nil, nil); err != nil { - return err + if err = at.Execute(nil, nil); err != nil { + return } *reply = utils.OK - return nil + return } -func (self *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) error { +// RemoveBalances remove the matching balances for the account +func (api *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) (err error) { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - var expTime *time.Time - if attr.ExpiryTime != nil { - expTimeVal, err := utils.ParseTimeDetectLayout(*attr.ExpiryTime, - self.Config.GeneralCfg().DefaultTimezone) - if err != nil { - *reply = err.Error() - return err - } - expTime = &expTimeVal + var balance *engine.BalanceFilter + if balance, err = engine.NewBalanceFilter(attr.Balance, api.Config.GeneralCfg().DefaultTimezone); err != nil { + return } + balance.Type = utils.StringPointer(attr.BalanceType) + accID := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.DataManager.GetAccount(accID); err != nil { + if _, err := api.DataManager.GetAccount(accID); err != nil { return utils.ErrNotFound } at := &engine.ActionTiming{} //check if we have extra data - if attr.ExtraData != nil && len(*attr.ExtraData) != 0 { - at.ExtraData = *attr.ExtraData + if attr.ActionExtraData != nil && len(*attr.ActionExtraData) != 0 { + at.ExtraData = *attr.ActionExtraData } at.SetAccountIDs(utils.StringMap{accID: true}) a := &engine.Action{ ActionType: utils.REMOVE_BALANCE, - Balance: &engine.BalanceFilter{ - Uuid: attr.BalanceUUID, - ID: attr.BalanceID, - Type: utils.StringPointer(attr.BalanceType), - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Weight: attr.Weight, - Blocker: attr.Blocker, - Disabled: attr.Disabled, - }, - } - if attr.Value != nil { - a.Balance.Value = &utils.ValueFormula{Static: math.Abs(*attr.Value)} - } - if attr.DestinationIds != nil { - a.Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.DestinationIds)) - } - if attr.Categories != nil { - a.Balance.Categories = utils.StringMapPointer(utils.ParseStringMap(*attr.Categories)) - } - if attr.SharedGroups != nil { - a.Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(*attr.SharedGroups)) - } - if attr.TimingIds != nil { - a.Balance.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(*attr.TimingIds)) + Balance: balance, } at.SetActions(engine.Actions{a}) if err := at.Execute(nil, nil); err != nil { diff --git a/apier/v1/accounts_it_test.go b/apier/v1/accounts_it_test.go index 4f46bc160..75cbc3575 100644 --- a/apier/v1/accounts_it_test.go +++ b/apier/v1/accounts_it_test.go @@ -148,13 +148,15 @@ func testBalanceIfExists(t *testing.T, acc, ten, balType, balID string) (has boo func testAccITAddVoiceBalance(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: accTenant, - Account: accAcount, - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer(accBallID), - Value: utils.Float64Pointer(2 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero5ms"), - ExpiryTime: utils.StringPointer(time.Now().Add(5 * time.Second).Format("2006-01-02 15:04:05")), + Tenant: accTenant, + Account: accAcount, + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: accBallID, + utils.Value: 2 * float64(time.Second), + utils.RatingSubject: "*zero5ms", + utils.ExpiryTime: time.Now().Add(5 * time.Second).Format("2006-01-02 15:04:05"), + }, } var reply string if err := accRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -192,9 +194,11 @@ func testAccITSetBalanceTimingIds(t *testing.T) { args := &utils.AttrSetBalance{ Tenant: accTenant, Account: accAcount, - TimingIds: utils.StringPointer("Timing"), BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("testBalanceID"), + Balance: map[string]interface{}{ + utils.ID: "testBalanceID", + utils.TimingIDs: "Timing", + }, } if err := accRPC.Call(utils.ApierV1SetBalance, args, &reply); err != nil { t.Error("Got error on SetBalance: ", err.Error()) @@ -287,10 +291,12 @@ func testAccITSetBalance(t *testing.T) { attrs := &utils.AttrSetBalance{ Tenant: "cgrates.org", Account: "testAccSetBalance", - BalanceID: utils.StringPointer("testAccSetBalance"), BalanceType: "*monetary", - Value: utils.Float64Pointer(1.5), - Cdrlog: utils.BoolPointer(true), + Balance: map[string]interface{}{ + utils.ID: "testAccSetBalance", + utils.Value: 1.5, + }, + Cdrlog: true, } if err := accRPC.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error("Got error on ApierV1.SetBalance: ", err.Error()) @@ -317,11 +323,13 @@ func testAccITSetBalanceWithExtraData(t *testing.T) { attrs := &utils.AttrSetBalance{ Tenant: "cgrates.org", Account: "testAccITSetBalanceWithExtraData", - BalanceID: utils.StringPointer("testAccITSetBalanceWithExtraData"), BalanceType: "*monetary", - Value: utils.Float64Pointer(1.5), - Cdrlog: utils.BoolPointer(true), - ExtraData: &extraDataMap, + Balance: map[string]interface{}{ + utils.ID: "testAccITSetBalanceWithExtraData", + utils.Value: 1.5, + }, + Cdrlog: true, + ActionExtraData: &extraDataMap, } if err := accRPC.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error("Got error on ApierV1.SetBalance: ", err.Error()) @@ -350,11 +358,13 @@ func testAccITSetBalanceWithExtraData2(t *testing.T) { attrs := &utils.AttrSetBalance{ Tenant: "cgrates.org", Account: "testAccITSetBalanceWithExtraData2", - BalanceID: utils.StringPointer("testAccITSetBalanceWithExtraData2"), BalanceType: "*monetary", - Value: utils.Float64Pointer(1.5), - Cdrlog: utils.BoolPointer(true), - ExtraData: &extraDataMap, + Balance: map[string]interface{}{ + utils.ID: "testAccITSetBalanceWithExtraData2", + utils.Value: 1.5, + }, + Cdrlog: true, + ActionExtraData: &extraDataMap, } if err := accRPC.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error("Got error on ApierV1.SetBalance: ", err.Error()) diff --git a/apier/v1/dm_remote_it_test.go b/apier/v1/dm_remote_it_test.go index e0f1d21a2..80a33f6ec 100644 --- a/apier/v1/dm_remote_it_test.go +++ b/apier/v1/dm_remote_it_test.go @@ -780,9 +780,11 @@ func testInternalAccountBalanceOperations(t *testing.T) { attrs := &utils.AttrSetBalance{ Tenant: "cgrates.org", Account: "testAccount1", - BalanceID: utils.StringPointer("testAccSetBalance"), BalanceType: utils.MONETARY, - Value: utils.Float64Pointer(17.4), + Balance: map[string]interface{}{ + utils.ID: "testAccSetBalance", + utils.Value: 17.4, + }, } if err := internalRPC.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error(err) diff --git a/apier/v1/sessionsv1_it_test.go b/apier/v1/sessionsv1_it_test.go index 9c3e59f18..09443be72 100644 --- a/apier/v1/sessionsv1_it_test.go +++ b/apier/v1/sessionsv1_it_test.go @@ -840,12 +840,15 @@ func testSSv1ItForceUpdateSession(t *testing.T) { func testSSv1ItDynamicDebit(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "TestDynamicDebit", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(2 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero5ms")} + Tenant: "cgrates.org", + Account: "TestDynamicDebit", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 2 * float64(time.Second), + utils.RatingSubject: "*zero5ms", + }, + } var reply string if err := sSApierRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) diff --git a/apier/v2/apier.go b/apier/v2/apier.go index 6e8e64894..cd1366bea 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -228,6 +228,9 @@ func (apiv2 *ApierV2) GetDestinations(attr AttrGetDestinations, reply *[]*engine if attr.DestinationIDs, err = apiv2.DataManager.DataDB().GetKeysForPrefix(utils.DESTINATION_PREFIX); err != nil { return } + for i, destID := range attr.DestinationIDs { + attr.DestinationIDs[i] = destID[len(utils.DESTINATION_PREFIX):] + } } dests := make([]*engine.Destination, len(attr.DestinationIDs)) for i, destID := range attr.DestinationIDs { diff --git a/apier/v2/apierv2_it_test.go b/apier/v2/apierv2_it_test.go index 1cecfabf1..14d339c35 100644 --- a/apier/v2/apierv2_it_test.go +++ b/apier/v2/apierv2_it_test.go @@ -110,9 +110,11 @@ func TestApierV2itAddBalance(t *testing.T) { Tenant: "cgrates.org", Account: "dan", BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer(utils.META_DEFAULT), - Value: utils.Float64Pointer(5.0), - Weight: utils.Float64Pointer(10.0), + Balance: map[string]interface{}{ + utils.ID: utils.META_DEFAULT, + utils.Value: 5.0, + utils.Weight: 10.0, + }, } var reply string if err := apierRPC.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { @@ -178,9 +180,11 @@ func TestApierV2itFraudMitigation(t *testing.T) { Tenant: "cgrates.org", Account: "dan", BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer(utils.META_DEFAULT), - Value: utils.Float64Pointer(60.0), - Weight: utils.Float64Pointer(10.0), + Balance: map[string]interface{}{ + utils.ID: utils.META_DEFAULT, + utils.Value: 60.0, + utils.Weight: 10.0, + }, } var reply string if err := apierRPC.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { diff --git a/apier/v2/cdrs_offline_it_test.go b/apier/v2/cdrs_offline_it_test.go index 09f33c353..4bcd5a5c7 100644 --- a/apier/v2/cdrs_offline_it_test.go +++ b/apier/v2/cdrs_offline_it_test.go @@ -125,9 +125,11 @@ func testV2CDRsOfflineBalanceUpdate(t *testing.T) { Tenant: "cgrates.org", Account: "test", BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer(utils.META_DEFAULT), - Value: utils.Float64Pointer(10.0), - Weight: utils.Float64Pointer(10.0), + Balance: map[string]interface{}{ + utils.ID: utils.META_DEFAULT, + utils.Value: 10.0, + utils.Weight: 10.0, + }, } var reply string if err := cdrsOfflineRpc.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { @@ -336,15 +338,17 @@ func testV2CDRsBalancesWithSameWeight(t *testing.T) { Tenant: "cgrates.org", Account: "specialTest", BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer("SpecialBalance1"), - Value: utils.Float64Pointer(10.0), - Weight: utils.Float64Pointer(10.0), + Balance: map[string]interface{}{ + utils.ID: "SpecialBalance1", + utils.Value: 10.0, + utils.Weight: 10.0, + }, } var reply string if err := cdrsOfflineRpc.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { t.Fatal(err) } - attrs.BalanceID = utils.StringPointer("SpecialBalance2") + attrs.Balance[utils.ID] = "SpecialBalance2" if err := cdrsOfflineRpc.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { t.Fatal(err) } diff --git a/dispatchers/sessions_it_test.go b/dispatchers/sessions_it_test.go index 95cec66f8..408ec807e 100755 --- a/dispatchers/sessions_it_test.go +++ b/dispatchers/sessions_it_test.go @@ -69,12 +69,14 @@ func TestDspSessionSMongo(t *testing.T) { func testDspSessionAddBalacne(t *testing.T) { initUsage := 40 * time.Minute attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "1001", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("SessionBalance"), - Value: utils.Float64Pointer(float64(initUsage)), - RatingSubject: utils.StringPointer("*zero5ms"), + Tenant: "cgrates.org", + Account: "1001", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "SessionBalance", + utils.Value: float64(initUsage), + utils.RatingSubject: "*zero5ms", + }, } var reply string if err := allEngine.RCP.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/engine/balance_filter.go b/engine/balance_filter.go index dcf103f3f..d3c6d20c0 100644 --- a/engine/balance_filter.go +++ b/engine/balance_filter.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "math" "reflect" "time" @@ -43,6 +44,71 @@ type BalanceFilter struct { Blocker *bool } +// NewBalanceFilter creates a new BalanceFilter based on given filter +func NewBalanceFilter(filter map[string]interface{}, defaultTimezone string) (bf *BalanceFilter, err error) { + bf = new(BalanceFilter) + if id, has := filter[utils.ID]; has { + bf.ID = utils.StringPointer(utils.IfaceAsString(id)) + } + if uuid, has := filter[utils.UUID]; has { + bf.Uuid = utils.StringPointer(utils.IfaceAsString(uuid)) + } + // if ty, has := filter[utils.Type]; has { + // bf.Uuid = utils.StringPointer(utils.IfaceAsString(ty)) + // } + if val, has := filter[utils.Value]; has { + var value float64 + if value, err = utils.IfaceAsFloat64(val); err != nil { + return + } + bf.Value = &utils.ValueFormula{Static: math.Abs(value)} + } + if exp, has := filter[utils.ExpiryTime]; has { + var expTime time.Time + if expTime, err = utils.IfaceAsTime(exp, defaultTimezone); err != nil { + return + } + bf.ExpirationDate = utils.TimePointer(expTime) + } + if weight, has := filter[utils.Weight]; has { + var value float64 + if value, err = utils.IfaceAsFloat64(weight); err != nil { + return + } + bf.Weight = utils.Float64Pointer(value) + } + if dst, has := filter[utils.DestinationIDs]; has { + bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(utils.IfaceAsString(dst))) + } + if rs, has := filter[utils.RatingSubject]; has { + bf.RatingSubject = utils.StringPointer(utils.IfaceAsString(rs)) + } + if cat, has := filter[utils.Categories]; has { + bf.Categories = utils.StringMapPointer(utils.ParseStringMap(utils.IfaceAsString(cat))) + } + if grps, has := filter[utils.SharedGroups]; has { + bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(utils.IfaceAsString(grps))) + } + if tim, has := filter[utils.TimingIDs]; has { + bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(utils.IfaceAsString(tim))) + } + if dis, has := filter[utils.Disabled]; has { + var value bool + if value, err = utils.IfaceAsBool(dis); err != nil { + return + } + bf.Disabled = utils.BoolPointer(value) + } + if blk, has := filter[utils.Blocker]; has { + var value bool + if value, err = utils.IfaceAsBool(blk); err != nil { + return + } + bf.Blocker = utils.BoolPointer(value) + } + return +} + func (bp *BalanceFilter) CreateBalance() *Balance { b := &Balance{ Uuid: bp.GetUuid(), diff --git a/general_tests/accounts_it_test.go b/general_tests/accounts_it_test.go index dd9aeb14f..1ffbd453a 100644 --- a/general_tests/accounts_it_test.go +++ b/general_tests/accounts_it_test.go @@ -26,7 +26,6 @@ import ( "testing" "time" - v1 "github.com/cgrates/cgrates/apier/v1" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -264,9 +263,15 @@ func testV1AccSendToThreshold(t *testing.T) { t.Error("Unexpected reply returned", reply) } // Add an account - attrs := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "testAccThreshold", - BalanceId: utils.StringPointer("testAccSetBalance"), - BalanceType: "*monetary", Value: 1.5} + attrs := &utils.AttrSetBalance{ + Tenant: "cgrates.org", + Account: "testAccThreshold", + BalanceType: "*monetary", + Balance: map[string]interface{}{ + utils.ID: "testAccSetBalance", + utils.Value: 1.5, + }, + } if err := accRpc.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error("Got error on ApierV1.SetBalance: ", err.Error()) } else if reply != "OK" { diff --git a/general_tests/data_it_test.go b/general_tests/data_it_test.go index d8675463a..754ca5572 100644 --- a/general_tests/data_it_test.go +++ b/general_tests/data_it_test.go @@ -125,13 +125,15 @@ func testV1DataLoadTarrifPlans(t *testing.T) { func testV1DataDataDebitUsageWith10Kilo(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "testV1DataDataCost", - BalanceType: utils.DATA, - Categories: utils.StringPointer("data"), - BalanceID: utils.StringPointer("testV1DataDataCost"), - Value: utils.Float64Pointer(356000000), - RatingSubject: utils.StringPointer("*zero10000ns"), + Tenant: "cgrates.org", + Account: "testV1DataDataCost", + BalanceType: utils.DATA, + Balance: map[string]interface{}{ + utils.Categories: "data", + utils.ID: "testV1DataDataCost", + utils.Value: 356000000, + utils.RatingSubject: "*zero10000ns", + }, } var reply string if err := dataRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -202,13 +204,15 @@ func testV1DataGetCostWith10Kilo(t *testing.T) { func testV1DataDebitBalanceWith10Kilo(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "testV1DataDebitBalance", - BalanceType: utils.DATA, - Categories: utils.StringPointer("data"), - BalanceID: utils.StringPointer("testV1DataDebitBalance"), - Value: utils.Float64Pointer(356000000), - RatingSubject: utils.StringPointer("*zero10000ns"), + Tenant: "cgrates.org", + Account: "testV1DataDebitBalance", + BalanceType: utils.DATA, + Balance: map[string]interface{}{ + utils.Categories: "data", + utils.ID: "testV1DataDebitBalance", + utils.Value: 356000000, + utils.RatingSubject: "*zero10000ns", + }, } var reply string if err := dataRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -259,13 +263,15 @@ func testV1DataDebitBalanceWith10Kilo(t *testing.T) { func testV1DataDataDebitUsage1G0(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "testV1DataDataDebitUsage1G0", - BalanceType: utils.DATA, - Categories: utils.StringPointer("data"), - BalanceID: utils.StringPointer("testV1DataDataDebitUsage1G0"), - Value: utils.Float64Pointer(1100000000), - RatingSubject: utils.StringPointer("*zero10000ns"), + Tenant: "cgrates.org", + Account: "testV1DataDataDebitUsage1G0", + BalanceType: utils.DATA, + Balance: map[string]interface{}{ + utils.Categories: "data", + utils.ID: "testV1DataDataDebitUsage1G0", + utils.Value: 1100000000, + utils.RatingSubject: "*zero10000ns", + }, } var reply string if err := dataRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -336,13 +342,15 @@ func testV1DataGetCost1G0(t *testing.T) { func testV1DataDebitBalance1G0(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "testV1DataDebitBalance1G0", - BalanceType: utils.DATA, - Categories: utils.StringPointer("data"), - BalanceID: utils.StringPointer("testV1DataDebitBalance1G0"), - Value: utils.Float64Pointer(1100000000), - RatingSubject: utils.StringPointer("*zero10000ns"), + Tenant: "cgrates.org", + Account: "testV1DataDebitBalance1G0", + BalanceType: utils.DATA, + Balance: map[string]interface{}{ + utils.Categories: "data", + utils.ID: "testV1DataDebitBalance1G0", + utils.Value: 1100000000, + utils.RatingSubject: "*zero10000ns", + }, } var reply string if err := dataRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -393,13 +401,15 @@ func testV1DataDebitBalance1G0(t *testing.T) { func testV1DataInitSession(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "testV1DataInitSession", - BalanceType: utils.DATA, - Categories: utils.StringPointer("data"), - BalanceID: utils.StringPointer("testV1DataInitSession"), - Value: utils.Float64Pointer(1100000000), - RatingSubject: utils.StringPointer("*zero10000ns"), + Tenant: "cgrates.org", + Account: "testV1DataInitSession", + BalanceType: utils.DATA, + Balance: map[string]interface{}{ + utils.Categories: "data", + utils.ID: "testV1DataInitSession", + utils.Value: 1100000000, + utils.RatingSubject: "*zero10000ns", + }, } var reply string if err := dataRpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/general_tests/session2_it_test.go b/general_tests/session2_it_test.go index 651476c0a..6f092684e 100644 --- a/general_tests/session2_it_test.go +++ b/general_tests/session2_it_test.go @@ -114,8 +114,10 @@ func testSes2ItInitSession(t *testing.T) { Tenant: "cgrates.org", Account: "1001", BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(float64(time.Hour)), + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: float64(time.Hour), + }, } var reply string if err := ses2RPC.Call(utils.ApierV2SetBalance, diff --git a/general_tests/session3_it_test.go b/general_tests/session3_it_test.go index f9b2d8f2d..f238071be 100644 --- a/general_tests/session3_it_test.go +++ b/general_tests/session3_it_test.go @@ -247,12 +247,14 @@ func testSes3ItStatMetricsAfter2(t *testing.T) { func testSes3ItAddVoiceBalance(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "1002", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(5 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero5ms"), + Tenant: "cgrates.org", + Account: "1002", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 5 * float64(time.Second), + utils.RatingSubject: "*zero5ms", + }, } var reply string if err := ses3RPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/general_tests/session_it_test.go b/general_tests/session_it_test.go index f41f78326..adc58455b 100644 --- a/general_tests/session_it_test.go +++ b/general_tests/session_it_test.go @@ -118,12 +118,14 @@ func testAccountBalance2(t *testing.T, sracc, srten, balType string, expected fl func testSesItAddVoiceBalance(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: sesTenant, - Account: sesAccount, - BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(0), - RatingSubject: utils.StringPointer("*zero1s"), + Tenant: sesTenant, + Account: sesAccount, + BalanceType: utils.MONETARY, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 0, + utils.RatingSubject: "*zero1s", + }, } var reply string if err := sesRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/general_tests/session_replications_automaticdebit_it_test.go b/general_tests/session_replications_automaticdebit_it_test.go index 726f27920..9dd7d115c 100644 --- a/general_tests/session_replications_automaticdebit_it_test.go +++ b/general_tests/session_replications_automaticdebit_it_test.go @@ -63,12 +63,14 @@ func TestSessionSRpl(t *testing.T) { //topup func testSessionSRplAddVoiceBalance(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "1005", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(5 * float64(time.Second)), //value -> 20ms for future - RatingSubject: utils.StringPointer("*zero5ms"), + Tenant: "cgrates.org", + Account: "1005", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 5 * float64(time.Second), //value -> 20ms for future + utils.RatingSubject: "*zero5ms", + }, } var reply string if err := smgRplcMstrRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/general_tests/sessionrefund_it_test.go b/general_tests/sessionrefund_it_test.go index cf9d2ce52..7386b8e31 100644 --- a/general_tests/sessionrefund_it_test.go +++ b/general_tests/sessionrefund_it_test.go @@ -120,12 +120,14 @@ func testAccountBalance(t *testing.T, sracc, srten, balType string, expected flo func testSrItAddVoiceBalance(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: srtenant, - Account: sraccount, - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(5 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero5ms"), + Tenant: srtenant, + Account: sraccount, + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 5 * float64(time.Second), + utils.RatingSubject: "*zero5ms", + }, } var reply string if err := srrpc.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -211,8 +213,10 @@ func testSrItAddMonetaryBalance(t *testing.T) { Tenant: srtenant, Account: sraccount, BalanceType: utils.MONETARY, - BalanceID: utils.StringPointer(utils.META_DEFAULT), - Value: utils.Float64Pointer(10.65), + Balance: map[string]interface{}{ + utils.ID: utils.META_DEFAULT, + utils.Value: 10.65, + }, } var reply string if err := srrpc.Call(utils.ApierV2SetBalance, attrs, &reply); err != nil { diff --git a/general_tests/tutorial2_it_test.go b/general_tests/tutorial2_it_test.go index 7c23aaee0..8bced2509 100644 --- a/general_tests/tutorial2_it_test.go +++ b/general_tests/tutorial2_it_test.go @@ -276,9 +276,15 @@ func testTutAccounts(t *testing.T) { t.Errorf("received account: %s", utils.ToIJSON(acnt)) } // test ActionTriggers - attrs := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", - BalanceId: utils.StringPointer(utils.MetaDefault), - BalanceType: utils.MONETARY, Value: 101} + attrs := utils.AttrSetBalance{ + Tenant: "cgrates.org", + Account: "1001", + BalanceType: utils.MONETARY, + Balance: map[string]interface{}{ + utils.ID: utils.MetaDefault, + utils.Value: 101, + }, + } var reply string if err := tutRpc.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil { t.Error("Got error on ApierV1.SetBalance: ", err.Error()) diff --git a/sessions/sessions_bench_test.go b/sessions/sessions_bench_test.go index 30ee09636..c50b00ca7 100644 --- a/sessions/sessions_bench_test.go +++ b/sessions/sessions_bench_test.go @@ -78,8 +78,10 @@ func addBalance(sBenchRPC *rpc.Client, sraccount string) { Tenant: "cgrates.org", Account: sraccount, BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestDynamicDebitBalance"), - Value: utils.Float64Pointer(5 * float64(time.Hour)), + Balance: map[string]interface{}{ + utils.ID: "TestDynamicDebitBalance", + utils.Value: 5 * float64(time.Hour), + }, } var reply string if err := sBenchRPC.Call(utils.ApierV2SetBalance, diff --git a/sessions/sessions_birpc_it_test.go b/sessions/sessions_birpc_it_test.go index 583139253..456cd957d 100644 --- a/sessions/sessions_birpc_it_test.go +++ b/sessions/sessions_birpc_it_test.go @@ -110,11 +110,14 @@ func TestSessionsBiRPCTPFromFolder(t *testing.T) { func TestSessionsBiRPCSessionAutomaticDisconnects(t *testing.T) { // Create a balance with 1 second inside and rating increments of 1ms (to be compatible with debit interval) attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", - Account: "TestSessionsBiRPCSessionAutomaticDisconnects", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestSessionsBiRPCSessionAutomaticDisconnects"), - Value: utils.Float64Pointer(0.01 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero1ms")} + Account: "TestSessionsBiRPCSessionAutomaticDisconnects", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestSessionsBiRPCSessionAutomaticDisconnects", + utils.Value: 0.01 * float64(time.Second), + utils.RatingSubject: "*zero1ms", + }, + } var reply string if err := sessionsRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) @@ -122,8 +125,10 @@ func TestSessionsBiRPCSessionAutomaticDisconnects(t *testing.T) { t.Errorf("Received: %s", reply) } var acnt *engine.Account - attrGetAcnt := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, - Account: attrSetBalance.Account} + attrGetAcnt := &utils.AttrGetAccount{ + Tenant: attrSetBalance.Tenant, + Account: attrSetBalance.Account, + } eAcntVal := 0.01 * float64(time.Second) if err := sessionsRPC.Call(utils.ApierV2GetAccount, attrGetAcnt, &acnt); err != nil { t.Error(err) @@ -230,12 +235,16 @@ func TestSessionsBiRPCSessionAutomaticDisconnects(t *testing.T) { } func TestSessionsBiRPCSessionOriginatorTerminate(t *testing.T) { - attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", - Account: "TestSessionsBiRPCSessionOriginatorTerminate", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestSessionsBiRPCSessionOriginatorTerminate"), - Value: utils.Float64Pointer(1 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero1ms")} + attrSetBalance := utils.AttrSetBalance{ + Tenant: "cgrates.org", + Account: "TestSessionsBiRPCSessionOriginatorTerminate", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestSessionsBiRPCSessionOriginatorTerminate", + utils.Value: float64(time.Second), + utils.RatingSubject: "*zero1ms", + }, + } var reply string if err := sessionsRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) diff --git a/sessions/sessions_data_it_test.go b/sessions/sessions_data_it_test.go index ceb56db1c..5d461f476 100644 --- a/sessions/sessions_data_it_test.go +++ b/sessions/sessions_data_it_test.go @@ -236,8 +236,11 @@ func TestSessionsDataLastUsedMultipleUpdates(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, BalanceType: utils.DATA, - BalanceID: utils.StringPointer("TestSessionsDataLastUsedMultipleData"), - Value: utils.Float64Pointer(eAcntVal)} + Balance: map[string]interface{}{ + utils.ID: "TestSessionsDataLastUsedMultipleData", + utils.Value: eAcntVal, + }, + } var reply string if err := sDataRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) @@ -495,8 +498,11 @@ func TestSessionsDataTTLExpired(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, BalanceType: utils.DATA, - BalanceID: utils.StringPointer("TestSessionsDataTTLExpired"), - Value: utils.Float64Pointer(eAcntVal)} + Balance: map[string]interface{}{ + utils.ID: "TestSessionsDataTTLExpired", + utils.Value: eAcntVal, + }, + } var reply string if err := sDataRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) @@ -569,8 +575,11 @@ func TestSessionsDataTTLExpMultiUpdates(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, BalanceType: utils.DATA, - BalanceID: utils.StringPointer("TestSessionsDataTTLExpMultiUpdates"), - Value: utils.Float64Pointer(eAcntVal)} + Balance: map[string]interface{}{ + utils.ID: "TestSessionsDataTTLExpMultiUpdates", + utils.Value: eAcntVal, + }, + } var reply string if err := sDataRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) @@ -692,8 +701,11 @@ func TestSessionsDataMultipleDataNoUsage(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, BalanceType: utils.DATA, - BalanceID: utils.StringPointer("TestSessionsDataTTLExpMultiUpdates"), - Value: utils.Float64Pointer(eAcntVal)} + Balance: map[string]interface{}{ + utils.ID: "TestSessionsDataTTLExpMultiUpdates", + utils.Value: eAcntVal, + }, + } var reply string if err := sDataRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { t.Error(err) @@ -896,8 +908,10 @@ func TestSessionsDataTTLUsageProtection(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, BalanceType: utils.DATA, - BalanceID: utils.StringPointer("TestSessionsDataTTLUsageProtection"), - Value: utils.Float64Pointer(eAcntVal), + Balance: map[string]interface{}{ + utils.ID: "TestSessionsDataTTLUsageProtection", + utils.Value: eAcntVal, + }, } var reply string if err := sDataRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/sessions/sessions_it_test.go b/sessions/sessions_it_test.go index 5fab0212b..7472965c2 100644 --- a/sessions/sessions_it_test.go +++ b/sessions/sessions_it_test.go @@ -335,12 +335,14 @@ func TestSessionsItTerminatePassive(t *testing.T) { func TestSessionsItEventCostCompressing(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "TestSessionsItEventCostCompressing", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestSessionsItEventCostCompressing"), - Value: utils.Float64Pointer(float64(5) * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero50ms"), + Tenant: "cgrates.org", + Account: "TestSessionsItEventCostCompressing", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestSessionsItEventCostCompressing", + utils.Value: float64(5) * float64(time.Second), + utils.RatingSubject: "*zero50ms", + }, } var reply string if err := sItRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { diff --git a/sessions/sessions_voice_it_test.go b/sessions/sessions_voice_it_test.go index 049fe907b..3e3aef2a8 100644 --- a/sessions/sessions_voice_it_test.go +++ b/sessions/sessions_voice_it_test.go @@ -892,12 +892,14 @@ func TestSessionsVoiceSessionTTL(t *testing.T) { func TestSessionsVoiceSessionTTLWithRelocate(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "TestTTLWithRelocate", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestTTLWithRelocate"), - Value: utils.Float64Pointer(300 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero50ms"), + Tenant: "cgrates.org", + Account: "TestTTLWithRelocate", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestTTLWithRelocate", + utils.Value: 300 * float64(time.Second), + utils.RatingSubject: "*zero50ms", + }, } var reply string if err := sessionsRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -906,8 +908,10 @@ func TestSessionsVoiceSessionTTLWithRelocate(t *testing.T) { t.Errorf("Received: %s", reply) } var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, - Account: attrSetBalance.Account} + attrs := &utils.AttrGetAccount{ + Tenant: attrSetBalance.Tenant, + Account: attrSetBalance.Account, + } eAcntVal := 300.0 * float64(time.Second) if err := sessionsRPC.Call(utils.ApierV2GetAccount, attrs, &acnt); err != nil { t.Error(err) @@ -1061,12 +1065,14 @@ func TestSessionsVoiceSessionTTLWithRelocate(t *testing.T) { func TestSessionsVoiceRelocateWithOriginIDPrefix(t *testing.T) { attrSetBalance := utils.AttrSetBalance{ - Tenant: "cgrates.org", - Account: "TestRelocateWithOriginIDPrefix", - BalanceType: utils.VOICE, - BalanceID: utils.StringPointer("TestRelocateWithOriginIDPrefix"), - Value: utils.Float64Pointer(300 * float64(time.Second)), - RatingSubject: utils.StringPointer("*zero1s"), + Tenant: "cgrates.org", + Account: "TestRelocateWithOriginIDPrefix", + BalanceType: utils.VOICE, + Balance: map[string]interface{}{ + utils.ID: "TestRelocateWithOriginIDPrefix", + utils.Value: 300 * float64(time.Second), + utils.RatingSubject: "*zero1s", + }, } var reply string if err := sessionsRPC.Call(utils.ApierV2SetBalance, attrSetBalance, &reply); err != nil { @@ -1075,8 +1081,10 @@ func TestSessionsVoiceRelocateWithOriginIDPrefix(t *testing.T) { t.Errorf("Received: %s", reply) } var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, - Account: attrSetBalance.Account} + attrs := &utils.AttrGetAccount{ + Tenant: attrSetBalance.Tenant, + Account: attrSetBalance.Account, + } eAcntVal := 300.0 * float64(time.Second) if err := sessionsRPC.Call(utils.ApierV2GetAccount, attrs, &acnt); err != nil { t.Error(err) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 92d12d12b..61c8eb05c 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -919,24 +919,12 @@ type AttrGetCallCost struct { } type AttrSetBalance struct { - Tenant string - Account string - BalanceType string - BalanceUUID *string - BalanceID *string - Directions *string - Value *float64 - ExpiryTime *string - RatingSubject *string - Categories *string - DestinationIds *string - TimingIds *string - Weight *float64 - SharedGroups *string - Blocker *bool - Disabled *bool - Cdrlog *bool - ExtraData *map[string]interface{} + Tenant string + Account string + BalanceType string + Balance map[string]interface{} + ActionExtraData *map[string]interface{} + Cdrlog bool } // TPResourceProfile is used in APIs to manage remotely offline ResourceProfile diff --git a/utils/consts.go b/utils/consts.go index d21ea87e8..1317ff090 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -375,6 +375,7 @@ const ( ActionPlans = "ActionPlans" ActionTriggers = "ActionTriggers" SharedGroups = "SharedGroups" + TimingIDs = "TimingIDs" Timings = "Timings" Rates = "Rates" DestinationRates = "DestinationRates" @@ -448,6 +449,10 @@ const ( MetaReds = "*reds" Weight = "Weight" Cost = "Cost" + DestinationIDs = "DestinationIDs" + RatingSubject = "RatingSubject" + Categories = "Categories" + Blocker = "Blocker" RatingPlanID = "RatingPlanID" MetaSessionS = "*sessions" MetaDefault = "*default"