Example #1
0
func (self *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) 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.DefaultTimezone)
		if err != nil {
			*reply = err.Error()
			return err
		}
		expTime = &expTimeVal
	}
	accID := utils.AccountKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(accID); err != nil {
		return utils.ErrNotFound
	}

	at := &engine.ActionTiming{}
	at.SetAccountIDs(utils.StringMap{accID: true})
	a := &engine.Action{
		ActionType: engine.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: *attr.Value}
	}
	if attr.Directions != nil {
		a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
	}
	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))
	}
	at.SetActions(engine.Actions{a})
	if err := at.Execute(); err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #2
0
func (tpr *TpReader) LoadActions() (err error) {
	tps, err := tpr.lr.GetTpActions(tpr.tpid, "")
	if err != nil {
		return err
	}

	storActs, err := TpActions(tps).GetActions()
	if err != nil {
		return err
	}
	// map[string][]*Action
	for tag, tpacts := range storActs {
		acts := make([]*Action, len(tpacts))
		for idx, tpact := range tpacts {
			acts[idx] = &Action{
				Id:               tag + strconv.Itoa(idx),
				ActionType:       tpact.Identifier,
				BalanceType:      tpact.BalanceType,
				Weight:           tpact.Weight,
				ExtraParameters:  tpact.ExtraParameters,
				ExpirationString: tpact.ExpiryTime,
				Balance: &Balance{
					Id:             tpact.BalanceId,
					Value:          tpact.Units,
					Weight:         tpact.BalanceWeight,
					RatingSubject:  tpact.RatingSubject,
					Categories:     utils.ParseStringMap(tpact.Categories),
					Directions:     utils.ParseStringMap(tpact.Directions),
					DestinationIds: utils.ParseStringMap(tpact.DestinationIds),
					SharedGroups:   utils.ParseStringMap(tpact.SharedGroups),
					TimingIDs:      utils.ParseStringMap(tpact.TimingTags),
				},
			}
			// load action timings from tags
			if tpact.TimingTags != "" {
				timingIds := strings.Split(tpact.TimingTags, utils.INFIELD_SEP)
				for _, timingID := range timingIds {
					if timing, found := tpr.timings[timingID]; found {
						acts[idx].Balance.Timings = append(acts[idx].Balance.Timings, &RITiming{
							Years:     timing.Years,
							Months:    timing.Months,
							MonthDays: timing.MonthDays,
							WeekDays:  timing.WeekDays,
							StartTime: timing.StartTime,
							EndTime:   timing.EndTime,
						})
					} else {
						return fmt.Errorf("could not find timing: %v", timingID)
					}
				}
			}
		}
		tpr.actions[tag] = acts
	}
	return nil
}
Example #3
0
func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *string) error {
	if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone)
	if err != nil {
		*reply = err.Error()
		return err
	}
	accID := utils.AccountKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(accID); err != nil {
		// create account if not exists
		account := &engine.Account{
			Id: accID,
		}
		if err := self.AccountDb.SetAccount(account); err != nil {
			*reply = err.Error()
			return err
		}
	}
	at := &engine.ActionTiming{}
	at.SetAccountIDs(utils.StringMap{accID: true})

	if attr.Overwrite {
		aType += "_reset" // => *topup_reset/*debit_reset
	}
	at.SetActions(engine.Actions{
		&engine.Action{
			ActionType:  aType,
			BalanceType: attr.BalanceType,
			Balance: &engine.Balance{
				Uuid:           attr.BalanceUuid,
				Id:             attr.BalanceId,
				Value:          attr.Value,
				ExpirationDate: expTime,
				RatingSubject:  attr.RatingSubject,
				Directions:     utils.ParseStringMap(attr.Directions),
				DestinationIds: utils.ParseStringMap(attr.DestinationIds),
				Categories:     utils.ParseStringMap(attr.Categories),
				Weight:         attr.Weight,
				SharedGroups:   utils.ParseStringMap(attr.SharedGroups),
				TimingIDs:      utils.ParseStringMap(attr.TimingIds),
				Blocker:        attr.Blocker,
				Disabled:       attr.Disabled,
			},
		},
	})
	if err := at.Execute(); err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #4
0
func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error {
	expTime, err := utils.ParseDate(attr.ExpiryTime)
	if err != nil {
		*reply = err.Error()
		return err
	}
	tag := utils.ConcatenatedKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(tag); err != nil {
		// create user balance if not exists
		account := &engine.Account{
			Id: tag,
		}
		if err := self.AccountDb.SetAccount(account); err != nil {
			*reply = err.Error()
			return err
		}
	}
	at := &engine.ActionPlan{
		AccountIds: []string{tag},
	}
	aType := engine.DEBIT
	// reverse the sign as it is a debit
	attr.Value = -attr.Value

	if attr.Overwrite {
		aType = engine.DEBIT_RESET
	}
	at.SetActions(engine.Actions{
		&engine.Action{
			ActionType:  aType,
			BalanceType: attr.BalanceType,
			Balance: &engine.Balance{
				Uuid:           attr.BalanceUuid,
				Id:             attr.BalanceId,
				Value:          attr.Value,
				ExpirationDate: expTime,
				RatingSubject:  attr.RatingSubject,
				Directions:     utils.ParseStringMap(attr.Directions),
				DestinationIds: utils.ParseStringMap(attr.DestinationIds),
				Weight:         attr.Weight,
				SharedGroups:   utils.ParseStringMap(attr.SharedGroups),
				Disabled:       attr.Disabled,
			},
		},
	})
	if err := at.Execute(); err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #5
0
func (self *ApierV1) SetActions(attrs V1AttrSetActions, reply *string) (err error) {
	if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	for _, action := range attrs.Actions {
		requiredFields := []string{"Identifier", "Weight"}
		if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions
			requiredFields = append(requiredFields, "Direction", "Units")
		}
		if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 {
			return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), action.Identifier, missing)
		}
	}
	if !attrs.Overwrite {
		if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, attrs.ActionsId); err != nil {
			return utils.NewErrServerError(err)
		} else if exists {
			return utils.ErrExists
		}
	}
	storeActions := make(engine.Actions, len(attrs.Actions))
	for idx, apiAct := range attrs.Actions {
		a := &engine.Action{
			Id:               attrs.ActionsId,
			ActionType:       apiAct.Identifier,
			Weight:           apiAct.Weight,
			ExpirationString: apiAct.ExpiryTime,
			ExtraParameters:  apiAct.ExtraParameters,
			Filter:           apiAct.Filter,
			Balance: &engine.BalanceFilter{ // TODO: update this part
				Uuid:           utils.StringPointer(apiAct.BalanceUuid),
				ID:             utils.StringPointer(apiAct.BalanceId),
				Type:           utils.StringPointer(apiAct.BalanceType),
				Value:          &utils.ValueFormula{Static: apiAct.Units},
				Weight:         apiAct.BalanceWeight,
				Directions:     utils.StringMapPointer(utils.ParseStringMap(apiAct.Directions)),
				DestinationIDs: utils.StringMapPointer(utils.ParseStringMap(apiAct.DestinationIds)),
				RatingSubject:  utils.StringPointer(apiAct.RatingSubject),
				SharedGroups:   utils.StringMapPointer(utils.ParseStringMap(apiAct.SharedGroups)),
			},
		}
		storeActions[idx] = a
	}
	if err := self.RatingDb.SetActions(attrs.ActionsId, storeActions, utils.NonTransactional); err != nil {
		return utils.NewErrServerError(err)
	}
	if err = self.RatingDb.CacheDataFromDB(utils.ACTION_PREFIX, []string{attrs.ActionsId}, true); err != nil {
		utils.NewErrServerError(err)
	}
	*reply = OK
	return nil
}
Example #6
0
func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error {
	if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	for _, action := range attrs.Actions {
		requiredFields := []string{"Identifier", "Weight"}
		if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions
			requiredFields = append(requiredFields, "Direction", "Units")
		}
		if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 {
			return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), action.Identifier, missing)
		}
	}
	if !attrs.Overwrite {
		if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, attrs.ActionsId); err != nil {
			return utils.NewErrServerError(err)
		} else if exists {
			return utils.ErrExists
		}
	}
	storeActions := make(engine.Actions, len(attrs.Actions))
	for idx, apiAct := range attrs.Actions {
		a := &engine.Action{
			Id:               utils.GenUUID(),
			ActionType:       apiAct.Identifier,
			BalanceType:      apiAct.BalanceType,
			Weight:           apiAct.Weight,
			ExpirationString: apiAct.ExpiryTime,
			ExtraParameters:  apiAct.ExtraParameters,
			Filter:           apiAct.Filter,
			Balance: &engine.Balance{
				Uuid:           utils.GenUUID(),
				Id:             apiAct.BalanceId,
				Value:          apiAct.Units,
				Weight:         apiAct.BalanceWeight,
				Directions:     utils.ParseStringMap(apiAct.Directions),
				DestinationIds: utils.ParseStringMap(apiAct.DestinationIds),
				RatingSubject:  apiAct.RatingSubject,
				SharedGroups:   utils.ParseStringMap(apiAct.SharedGroups),
			},
		}
		storeActions[idx] = a
	}
	if err := self.RatingDb.SetActions(attrs.ActionsId, storeActions); err != nil {
		return utils.NewErrServerError(err)
	}
	self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PREFIX: []string{utils.ACTION_PREFIX + attrs.ActionsId}})
	*reply = OK
	return nil
}
Example #7
0
func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error {
	if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone)
	if err != nil {
		*reply = err.Error()
		return err
	}
	accID := utils.AccountKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(accID); err != nil {
		return utils.ErrNotFound
	}

	at := &engine.ActionTiming{}
	at.SetAccountIDs(utils.StringMap{accID: true})
	at.SetActions(engine.Actions{
		&engine.Action{
			ActionType:  engine.REMOVE_BALANCE,
			BalanceType: attr.BalanceType,
			Balance: &engine.Balance{
				Uuid:           attr.BalanceUuid,
				Id:             attr.BalanceId,
				Value:          attr.Value,
				ExpirationDate: expTime,
				RatingSubject:  attr.RatingSubject,
				Directions:     utils.ParseStringMap(attr.Directions),
				DestinationIds: utils.ParseStringMap(attr.DestinationIds),
				Categories:     utils.ParseStringMap(attr.Categories),
				Weight:         attr.Weight,
				SharedGroups:   utils.ParseStringMap(attr.SharedGroups),
				TimingIDs:      utils.ParseStringMap(attr.TimingIds),
				Blocker:        attr.Blocker,
				Disabled:       attr.Disabled,
			},
		},
	})
	if err := at.Execute(); err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #8
0
func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string) error {
	if attr.BalanceDirection == "" {
		attr.BalanceDirection = utils.OUT
	}
	balExpiryTime, err := utils.ParseTimeDetectLayout(attr.BalanceExpiryTime, self.Config.DefaultTimezone)
	if err != nil {
		return utils.NewErrServerError(err)
	}
	at := &engine.ActionTrigger{
		Id:                    attr.ActionTriggersId,
		ThresholdType:         attr.ThresholdType,
		ThresholdValue:        attr.ThresholdValue,
		BalanceId:             attr.BalanceId,
		BalanceType:           attr.BalanceType,
		BalanceDirections:     utils.ParseStringMap(attr.BalanceDirection),
		BalanceDestinationIds: utils.ParseStringMap(attr.BalanceDestinationIds),
		BalanceWeight:         attr.BalanceWeight,
		BalanceExpirationDate: balExpiryTime,
		Weight:                attr.Weight,
		ActionsId:             attr.ActionsId,
		Executed:              false,
	}

	tag := utils.AccountKey(attr.Tenant, attr.Account)
	_, err = engine.Guardian.Guard(func() (interface{}, error) {
		userBalance, err := self.AccountDb.GetAccount(tag)
		if err != nil {
			return 0, err
		}

		userBalance.ActionTriggers = append(userBalance.ActionTriggers, at)

		if err = self.AccountDb.SetAccount(userBalance); err != nil {
			return 0, err
		}
		return 0, nil
	}, 0, tag)
	if err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #9
0
func (tpr *TpReader) LoadActionTriggers() (err error) {
	tps, err := tpr.lr.GetTpActionTriggers(tpr.tpid, "")
	if err != nil {
		return err
	}
	storAts, err := TpActionTriggers(tps).GetActionTriggers()
	if err != nil {
		return err
	}
	for key, atrsLst := range storAts {
		atrs := make([]*ActionTrigger, len(atrsLst))
		for idx, atr := range atrsLst {
			balanceExpirationDate, _ := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone)
			minSleep, err := utils.ParseDurationWithSecs(atr.MinSleep)
			if err != nil {
				return err
			}
			atrs[idx] = &ActionTrigger{
				ThresholdType:         atr.ThresholdType,
				ThresholdValue:        atr.ThresholdValue,
				Recurrent:             atr.Recurrent,
				MinSleep:              minSleep,
				BalanceId:             atr.BalanceId,
				BalanceType:           atr.BalanceType,
				BalanceDirections:     utils.ParseStringMap(atr.BalanceDirections),
				BalanceDestinationIds: utils.ParseStringMap(atr.BalanceDestinationIds),
				BalanceWeight:         atr.BalanceWeight,
				BalanceExpirationDate: balanceExpirationDate,
				BalanceTimingTags:     utils.ParseStringMap(atr.BalanceTimingTags),
				BalanceRatingSubject:  atr.BalanceRatingSubject,
				BalanceCategories:     utils.ParseStringMap(atr.BalanceCategories),
				BalanceSharedGroups:   utils.ParseStringMap(atr.BalanceSharedGroups),
				Weight:                atr.Weight,
				ActionsId:             atr.ActionsId,
				MinQueuedItems:        atr.MinQueuedItems,
			}
		}
		tpr.actionsTriggers[key] = atrs
	}

	return nil
}
Example #10
0
func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error {
	expTime, err := utils.ParseDate(attr.ExpiryTime)
	if err != nil {
		*reply = err.Error()
		return err
	}
	accId := utils.ConcatenatedKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(accId); err != nil {
		return utils.ErrNotFound
	}
	at := &engine.ActionPlan{
		AccountIds: []string{accId},
	}
	at.SetActions(engine.Actions{
		&engine.Action{
			ActionType:  engine.REMOVE_BALANCE,
			BalanceType: attr.BalanceType,
			Balance: &engine.Balance{
				Uuid:           attr.BalanceUuid,
				Id:             attr.BalanceId,
				Value:          attr.Value,
				ExpirationDate: expTime,
				RatingSubject:  attr.RatingSubject,
				Directions:     utils.ParseStringMap(attr.Directions),
				DestinationIds: utils.ParseStringMap(attr.DestinationIds),
				Weight:         attr.Weight,
				SharedGroups:   utils.ParseStringMap(attr.SharedGroups),
				Disabled:       attr.Disabled,
			},
		},
	})
	if err := at.Execute(); err != nil {
		*reply = err.Error()
		return err
	}
	*reply = OK
	return nil
}
Example #11
0
// returns true if the field of the action timing are equeal to the non empty
// fields of the action
func (at *ActionTrigger) Match(a *Action) bool {
	if a == nil {
		return true
	}
	// if we have Id than we can draw an early conclusion
	if a.Id != "" {
		match, _ := regexp.MatchString(a.Id, at.Id)
		return match
	}
	id := a.BalanceType == "" || at.BalanceType == a.BalanceType
	thresholdType, thresholdValue, direction, destinationId, weight, ratingSubject, categories, sharedGroup, timings, disabled := true, true, true, true, true, true, true, true, true, true
	if a.ExtraParameters != "" {
		t := struct {
			ThresholdType        string
			ThresholdValue       float64
			DestinationIds       string
			BalanceDirections    string
			BalanceWeight        float64
			BalanceRatingSubject string
			BalanceCategories    string
			BalanceSharedGroups  string
			BalanceTimingTags    string
			BalanceDisabled      bool
		}{}
		json.Unmarshal([]byte(a.ExtraParameters), &t)
		thresholdType = t.ThresholdType == "" || at.ThresholdType == t.ThresholdType
		thresholdValue = t.ThresholdValue == 0 || at.ThresholdValue == t.ThresholdValue
		direction = len(t.BalanceDirections) == 0 || at.BalanceDirections.Equal(utils.ParseStringMap(t.BalanceDirections))
		destinationId = len(t.DestinationIds) == 0 || at.BalanceDestinationIds.Equal(utils.ParseStringMap(t.DestinationIds))
		categories = len(t.BalanceCategories) == 0 || at.BalanceCategories.Equal(utils.ParseStringMap(t.BalanceCategories))
		timings = len(t.BalanceTimingTags) == 0 || at.BalanceTimingTags.Equal(utils.ParseStringMap(t.BalanceTimingTags))
		sharedGroup = len(t.BalanceSharedGroups) == 0 || at.BalanceSharedGroups.Equal(utils.ParseStringMap(t.BalanceSharedGroups))
		weight = t.BalanceWeight == 0 || at.BalanceWeight == t.BalanceWeight
		ratingSubject = t.BalanceRatingSubject == "" || at.BalanceRatingSubject == t.BalanceRatingSubject
		disabled = at.BalanceDisabled == t.BalanceDisabled
	}
	return id && direction && thresholdType && thresholdValue && destinationId && weight && ratingSubject && categories && sharedGroup && timings && disabled
}
Example #12
0
func (tpr *TpReader) LoadDerivedChargersFiltered(filter *TpDerivedCharger, save bool) (err error) {
	tps, err := tpr.lr.GetTpDerivedChargers(filter)
	if err != nil {
		return err
	}
	storDcs, err := TpDerivedChargers(tps).GetDerivedChargers()
	if err != nil {
		return err
	}
	for _, tpDcs := range storDcs {
		tag := tpDcs.GetDerivedChargersKey()
		if _, hasIt := tpr.derivedChargers[tag]; !hasIt {
			tpr.derivedChargers[tag] = &utils.DerivedChargers{
				DestinationIds: make(utils.StringMap),
				Chargers:       make([]*utils.DerivedCharger, 0),
			} // Load object map since we use this method also from LoadDerivedChargers
		}
		for _, tpDc := range tpDcs.DerivedChargers {
			dc, err := utils.NewDerivedCharger(tpDc.RunId, tpDc.RunFilters, tpDc.ReqTypeField, tpDc.DirectionField, tpDc.TenantField, tpDc.CategoryField,
				tpDc.AccountField, tpDc.SubjectField, tpDc.DestinationField, tpDc.SetupTimeField, tpDc.PddField, tpDc.AnswerTimeField, tpDc.UsageField, tpDc.SupplierField,
				tpDc.DisconnectCauseField, tpDc.RatedField, tpDc.CostField)
			if err != nil {
				return err
			}
			tpr.derivedChargers[tag].DestinationIds.Copy(utils.ParseStringMap(tpDcs.DestinationIds))
			tpr.derivedChargers[tag].Chargers = append(tpr.derivedChargers[tag].Chargers, dc)
		}
	}
	if save {
		for dcsKey, dcs := range tpr.derivedChargers {
			if err := tpr.ratingStorage.SetDerivedChargers(dcsKey, dcs); err != nil {
				return err
			}
		}
	}
	return nil
}
Example #13
0
func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
	tps, err := tpr.lr.GetTpCdrStats(tpr.tpid, tag)
	if err != nil {
		return err
	}
	storStats, err := TpCdrStats(tps).GetCdrStats()
	if err != nil {
		return err
	}
	var actionsIds []string // collect action ids
	for tag, tpStats := range storStats {
		for _, tpStat := range tpStats {
			var cs *CdrStats
			var exists bool
			if cs, exists = tpr.cdrStats[tag]; !exists {
				cs = &CdrStats{Id: tag}
			}
			// action triggers
			triggerTag := tpStat.ActionTriggers
			if triggerTag != "" {
				_, exists := tpr.actionsTriggers[triggerTag]
				if !exists {
					tpatrs, err := tpr.lr.GetTpActionTriggers(tpr.tpid, triggerTag)
					if err != nil {
						return errors.New(err.Error() + " (ActionTriggers): " + triggerTag)
					}
					atrsM, err := TpActionTriggers(tpatrs).GetActionTriggers()
					if err != nil {
						return err
					}

					for _, atrsLst := range atrsM {
						atrs := make([]*ActionTrigger, len(atrsLst))
						for idx, apiAtr := range atrsLst {
							minSleep, _ := utils.ParseDurationWithSecs(apiAtr.MinSleep)
							expTime, _ := utils.ParseDate(apiAtr.BalanceExpirationDate)
							atrs[idx] = &ActionTrigger{
								ThresholdType:         apiAtr.ThresholdType,
								ThresholdValue:        apiAtr.ThresholdValue,
								Recurrent:             apiAtr.Recurrent,
								MinSleep:              minSleep,
								BalanceId:             apiAtr.BalanceId,
								BalanceType:           apiAtr.BalanceType,
								BalanceDirections:     utils.ParseStringMap(apiAtr.BalanceDirections),
								BalanceDestinationIds: utils.ParseStringMap(apiAtr.BalanceDestinationIds),
								BalanceWeight:         apiAtr.BalanceWeight,
								BalanceExpirationDate: expTime,
								BalanceRatingSubject:  apiAtr.BalanceRatingSubject,
								BalanceCategories:     utils.ParseStringMap(apiAtr.BalanceCategories),
								BalanceSharedGroups:   utils.ParseStringMap(apiAtr.BalanceSharedGroups),
								BalanceTimingTags:     utils.ParseStringMap(apiAtr.BalanceTimingTags),
								Weight:                apiAtr.Weight,
								ActionsId:             apiAtr.ActionsId,
							}
						}
						tpr.actionsTriggers[triggerTag] = atrs
					}
				}
				// collect action ids from triggers
				for _, atr := range tpr.actionsTriggers[triggerTag] {
					actionsIds = append(actionsIds, atr.ActionsId)
				}
			}
			triggers, exists := tpr.actionsTriggers[triggerTag]
			if triggerTag != "" && !exists {
				// only return error if there was something there for the tag
				return fmt.Errorf("could not get action triggers for cdr stats id %s: %s", cs.Id, triggerTag)
			}
			// write action triggers
			err = tpr.ratingStorage.SetActionTriggers(triggerTag, triggers)
			if err != nil {
				return errors.New(err.Error() + " (SetActionTriggers): " + triggerTag)
			}
			UpdateCdrStats(cs, triggers, tpStat, tpr.timezone)
			tpr.cdrStats[tag] = cs
		}
	}
	// actions
	for _, actId := range actionsIds {
		_, exists := tpr.actions[actId]
		if !exists {
			tpas, err := tpr.lr.GetTpActions(tpr.tpid, actId)
			if err != nil {
				return err
			}
			as, err := TpActions(tpas).GetActions()
			if err != nil {
				return err
			}
			for tag, tpacts := range as {
				enacts := make([]*Action, len(tpacts))
				for idx, tpact := range tpacts {
					enacts[idx] = &Action{
						Id:               tag + strconv.Itoa(idx),
						ActionType:       tpact.Identifier,
						BalanceType:      tpact.BalanceType,
						Weight:           tpact.Weight,
						ExtraParameters:  tpact.ExtraParameters,
						ExpirationString: tpact.ExpiryTime,
						Balance: &Balance{
							Value:          tpact.Units,
							Weight:         tpact.BalanceWeight,
							RatingSubject:  tpact.RatingSubject,
							Directions:     utils.ParseStringMap(tpact.Directions),
							DestinationIds: utils.ParseStringMap(tpact.DestinationIds),
							SharedGroups:   utils.ParseStringMap(tpact.SharedGroups),
							TimingIDs:      utils.ParseStringMap(tpact.TimingTags),
						},
					}
				}
				tpr.actions[tag] = enacts
			}
		}
	}

	if save {
		// write actions
		for k, as := range tpr.actions {
			err = tpr.ratingStorage.SetActions(k, as)
			if err != nil {
				return err
			}
		}
		for _, stat := range tpr.cdrStats {
			if err := tpr.ratingStorage.SetCdrStats(stat); err != nil {
				return err
			}
		}
	}
	return nil
}
Example #14
0
func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error {
	accountActions, err := tpr.lr.GetTpAccountActions(qriedAA)
	if err != nil {
		return errors.New(err.Error() + ": " + fmt.Sprintf("%+v", qriedAA))
	}
	storAas, err := TpAccountActions(accountActions).GetAccountActions()
	if err != nil {
		return err
	}
	for _, accountAction := range storAas {
		id := accountAction.KeyId()
		var actionsIds []string // collects action ids
		// action timings
		if accountAction.ActionPlanId != "" {
			// get old userBalanceIds
			exitingAccountIds := make(utils.StringMap)
			existingActionPlan, err := tpr.ratingStorage.GetActionPlan(accountAction.ActionPlanId, true)
			if err == nil && existingActionPlan != nil {
				exitingAccountIds = existingActionPlan.AccountIDs
			}

			tpap, err := tpr.lr.GetTpActionPlans(tpr.tpid, accountAction.ActionPlanId)
			if err != nil {
				return errors.New(err.Error() + " (ActionPlan): " + accountAction.ActionPlanId)
			} else if len(tpap) == 0 {
				return fmt.Errorf("no action plan with id <%s>", accountAction.ActionPlanId)
			}
			aps, err := TpActionPlans(tpap).GetActionPlans()
			if err != nil {
				return err
			}
			var actionPlan *ActionPlan
			ats := aps[accountAction.ActionPlanId]
			for _, at := range ats {
				// Check action exists before saving it inside actionTiming key
				// ToDo: try saving the key after the actions was retrieved in order to save one query here.
				if actions, err := tpr.lr.GetTpActions(tpr.tpid, at.ActionsId); err != nil {
					return errors.New(err.Error() + " (Actions): " + at.ActionsId)
				} else if len(actions) == 0 {
					return fmt.Errorf("no action with id <%s>", at.ActionsId)
				}
				var t *utils.TPTiming
				if at.TimingId != utils.ASAP {
					tptm, err := tpr.lr.GetTpTimings(tpr.tpid, at.TimingId)
					if err != nil {
						return errors.New(err.Error() + " (Timing): " + at.TimingId)
					} else if len(tptm) == 0 {
						return fmt.Errorf("no timing with id <%s>", at.TimingId)
					}
					tm, err := TpTimings(tptm).GetTimings()
					if err != nil {
						return err
					}
					t = tm[at.TimingId]
				} else {
					t = tpr.timings[at.TimingId] // *asap
				}
				if actionPlan == nil {
					actionPlan = &ActionPlan{
						Id: accountAction.ActionPlanId,
					}
				}
				actionPlan.ActionTimings = append(actionPlan.ActionTimings, &ActionTiming{
					Uuid:   utils.GenUUID(),
					Weight: at.Weight,
					Timing: &RateInterval{
						Timing: &RITiming{
							Months:    t.Months,
							MonthDays: t.MonthDays,
							WeekDays:  t.WeekDays,
							StartTime: t.StartTime,
						},
					},
					ActionsID: at.ActionsId,
				})
				// collect action ids from timings
				actionsIds = append(actionsIds, at.ActionsId)
				exitingAccountIds[id] = true
				actionPlan.AccountIDs = exitingAccountIds
			}

			// write tasks
			for _, at := range actionPlan.ActionTimings {
				if at.IsASAP() {
					for accID := range actionPlan.AccountIDs {
						t := &Task{
							Uuid:      utils.GenUUID(),
							AccountID: accID,
							ActionsID: at.ActionsID,
						}
						if err = tpr.ratingStorage.PushTask(t); err != nil {
							return err
						}
					}
				}
			}
			// write action plan
			err = tpr.ratingStorage.SetActionPlan(accountAction.ActionPlanId, actionPlan, false)
			if err != nil {
				return errors.New(err.Error() + " (SetActionPlan): " + accountAction.ActionPlanId)
			}
		}
		// action triggers
		var actionTriggers ActionTriggers
		//ActionTriggerPriotityList []*ActionTrigger
		if accountAction.ActionTriggersId != "" {
			tpatrs, err := tpr.lr.GetTpActionTriggers(tpr.tpid, accountAction.ActionTriggersId)
			if err != nil {
				return errors.New(err.Error() + " (ActionTriggers): " + accountAction.ActionTriggersId)
			}
			atrs, err := TpActionTriggers(tpatrs).GetActionTriggers()
			if err != nil {
				return err
			}

			atrsMap := make(map[string][]*ActionTrigger)
			for key, atrsLst := range atrs {
				atrs := make([]*ActionTrigger, len(atrsLst))
				for idx, apiAtr := range atrsLst {
					minSleep, _ := utils.ParseDurationWithSecs(apiAtr.MinSleep)
					balanceExpTime, _ := utils.ParseDate(apiAtr.BalanceExpirationDate)
					expTime, _ := utils.ParseTimeDetectLayout(apiAtr.ExpirationDate, tpr.timezone)
					actTime, _ := utils.ParseTimeDetectLayout(apiAtr.ActivationDate, tpr.timezone)
					if apiAtr.UniqueID == "" {
						apiAtr.UniqueID = utils.GenUUID()
					}
					atrs[idx] = &ActionTrigger{
						ID:                    key,
						UniqueID:              apiAtr.UniqueID,
						ThresholdType:         apiAtr.ThresholdType,
						ThresholdValue:        apiAtr.ThresholdValue,
						Recurrent:             apiAtr.Recurrent,
						MinSleep:              minSleep,
						ExpirationDate:        expTime,
						ActivationDate:        actTime,
						BalanceId:             apiAtr.BalanceId,
						BalanceType:           apiAtr.BalanceType,
						BalanceDirections:     utils.ParseStringMap(apiAtr.BalanceDirections),
						BalanceDestinationIds: utils.ParseStringMap(apiAtr.BalanceDestinationIds),
						BalanceWeight:         apiAtr.BalanceWeight,
						BalanceExpirationDate: balanceExpTime,
						BalanceTimingTags:     utils.ParseStringMap(apiAtr.BalanceTimingTags),
						BalanceRatingSubject:  apiAtr.BalanceRatingSubject,
						BalanceCategories:     utils.ParseStringMap(apiAtr.BalanceCategories),
						BalanceSharedGroups:   utils.ParseStringMap(apiAtr.BalanceSharedGroups),
						BalanceBlocker:        apiAtr.BalanceBlocker,
						BalanceDisabled:       apiAtr.BalanceDisabled,
						Weight:                apiAtr.Weight,
						ActionsId:             apiAtr.ActionsId,
					}
				}
				atrsMap[key] = atrs
			}
			actionTriggers = atrsMap[accountAction.ActionTriggersId]
			// collect action ids from triggers
			for _, atr := range actionTriggers {
				actionsIds = append(actionsIds, atr.ActionsId)
			}
			// write action triggers
			err = tpr.ratingStorage.SetActionTriggers(accountAction.ActionTriggersId, actionTriggers)
			if err != nil {
				return errors.New(err.Error() + " (SetActionTriggers): " + accountAction.ActionTriggersId)
			}
		}

		// actions
		acts := make(map[string][]*Action)
		for _, actId := range actionsIds {
			tpas, err := tpr.lr.GetTpActions(tpr.tpid, actId)
			if err != nil {
				return err
			}
			as, err := TpActions(tpas).GetActions()
			if err != nil {
				return err
			}
			for tag, tpacts := range as {
				enacts := make([]*Action, len(tpacts))
				for idx, tpact := range tpacts {
					// check filter field
					if len(tpact.Filter) > 0 {
						if _, err := structmatcher.NewStructMatcher(tpact.Filter); err != nil {
							return fmt.Errorf("error parsing action %s filter field: %v", tag, err)
						}
					}
					enacts[idx] = &Action{
						Id:               tag + strconv.Itoa(idx),
						ActionType:       tpact.Identifier,
						BalanceType:      tpact.BalanceType,
						Weight:           tpact.Weight,
						ExtraParameters:  tpact.ExtraParameters,
						ExpirationString: tpact.ExpiryTime,
						Filter:           tpact.Filter,
						Balance: &Balance{
							Id:             tpact.BalanceId,
							Value:          tpact.Units,
							Weight:         tpact.BalanceWeight,
							RatingSubject:  tpact.RatingSubject,
							Categories:     utils.ParseStringMap(tpact.Categories),
							Directions:     utils.ParseStringMap(tpact.Directions),
							DestinationIds: utils.ParseStringMap(tpact.DestinationIds),
							SharedGroups:   utils.ParseStringMap(tpact.SharedGroups),
							TimingIDs:      utils.ParseStringMap(tpact.TimingTags),
							Blocker:        tpact.BalanceBlocker,
							Disabled:       tpact.BalanceDisabled,
						},
					}
				}
				acts[tag] = enacts
			}
		}
		// write actions
		for k, as := range acts {
			err = tpr.ratingStorage.SetActions(k, as)
			if err != nil {
				return err
			}
		}
		ub, err := tpr.accountingStorage.GetAccount(id)
		if err != nil {
			ub = &Account{
				Id: id,
			}
		}
		ub.ActionTriggers = actionTriggers
		// init counters
		ub.InitCounters()
		if err := tpr.accountingStorage.SetAccount(ub); err != nil {
			return err
		}
	}
	return nil
}
Example #15
0
func (self *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.DefaultTimezone)
		if err != nil {
			*reply = err.Error()
			return err
		}
		expTime = &expTimeVal
	}
	accID := utils.AccountKey(attr.Tenant, attr.Account)
	if _, err := self.AccountDb.GetAccount(accID); err != nil {
		// create account if does not exist
		account := &engine.Account{
			ID: accID,
		}
		if err := self.AccountDb.SetAccount(account); err != nil {
			*reply = err.Error()
			return err
		}
	}
	at := &engine.ActionTiming{}
	at.SetAccountIDs(utils.StringMap{accID: true})

	if attr.Overwrite {
		aType += "_reset" // => *topup_reset/*debit_reset
	}
	a := &engine.Action{
		ActionType: aType,
		Balance: &engine.BalanceFilter{
			Uuid:           attr.BalanceUuid,
			ID:             attr.BalanceId,
			Type:           utils.StringPointer(attr.BalanceType),
			Value:          &utils.ValueFormula{Static: attr.Value},
			ExpirationDate: expTime,
			RatingSubject:  attr.RatingSubject,
			Weight:         attr.Weight,
			Blocker:        attr.Blocker,
			Disabled:       attr.Disabled,
		},
	}
	if attr.Directions != nil {
		a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
	}
	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))
	}
	at.SetActions(engine.Actions{a})
	if err := at.Execute(); err != nil {
		return err
	}
	*reply = OK
	return nil
}
Example #16
0
func (mig MigratorRC8) migrateActions() error {
	keys, err := mig.db.Cmd("KEYS", utils.ACTION_PREFIX+"*").List()
	if err != nil {
		return err
	}
	newAcsMap := make(map[string]engine.Actions, len(keys))
	for _, key := range keys {
		log.Printf("Migrating action: %s...", key)
		var oldAcs Actions
		var values []byte
		if values, err = mig.db.Cmd("GET", key).Bytes(); err == nil {
			if err := mig.ms.Unmarshal(values, &oldAcs); err != nil {
				return err
			}
		}
		newAcs := make(engine.Actions, len(oldAcs))
		for index, oldAc := range oldAcs {
			a := &engine.Action{
				Id:               oldAc.Id,
				ActionType:       oldAc.ActionType,
				ExtraParameters:  oldAc.ExtraParameters,
				ExpirationString: oldAc.ExpirationString,
				Weight:           oldAc.Weight,
				Balance:          &engine.BalanceFilter{},
			}
			bf := a.Balance
			if oldAc.Balance.Uuid != "" {
				bf.Uuid = utils.StringPointer(oldAc.Balance.Uuid)
			}
			if oldAc.Balance.Id != "" {
				bf.ID = utils.StringPointer(oldAc.Balance.Id)
			}
			if oldAc.BalanceType != "" {
				bf.Type = utils.StringPointer(oldAc.BalanceType)
			}
			if oldAc.Balance.Value != 0 {
				bf.Value = &utils.ValueFormula{Static: oldAc.Balance.Value}
			}
			if oldAc.Balance.RatingSubject != "" {
				bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject)
			}
			if oldAc.Balance.DestinationIds != "" {
				bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.DestinationIds))
			}
			if oldAc.Balance.TimingIDs != "" {
				bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.TimingIDs))
			}
			if oldAc.Balance.Category != "" {
				bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.Category))
			}
			if oldAc.Balance.SharedGroup != "" {
				bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAc.Balance.SharedGroup))
			}
			if oldAc.Balance.Weight != 0 {
				bf.Weight = utils.Float64Pointer(oldAc.Balance.Weight)
			}
			if oldAc.Balance.Disabled != false {
				bf.Disabled = utils.BoolPointer(oldAc.Balance.Disabled)
			}
			if !oldAc.Balance.ExpirationDate.IsZero() {
				bf.ExpirationDate = utils.TimePointer(oldAc.Balance.ExpirationDate)
			}
			bf.Timings = oldAc.Balance.Timings
			newAcs[index] = a
		}
		newAcsMap[key] = newAcs
	}
	// write data back
	for key, acs := range newAcsMap {
		result, err := mig.ms.Marshal(&acs)
		if err != nil {
			return err
		}
		if err = mig.db.Cmd("SET", key, result).Err; err != nil {
			return err
		}
	}
	return nil
}
Example #17
0
func (mig MigratorRC8) migrateActionTriggers() error {
	keys, err := mig.db.Cmd("KEYS", utils.ACTION_TRIGGER_PREFIX+"*").List()
	if err != nil {
		return err
	}
	newAtrsMap := make(map[string]engine.ActionTriggers, len(keys))
	for _, key := range keys {
		log.Printf("Migrating action trigger: %s...", key)
		var oldAtrs ActionTriggers
		var values []byte
		if values, err = mig.db.Cmd("GET", key).Bytes(); err == nil {
			if err := mig.ms.Unmarshal(values, &oldAtrs); err != nil {
				return err
			}
		}
		newAtrs := make(engine.ActionTriggers, len(oldAtrs))
		for index, oldAtr := range oldAtrs {
			at := &engine.ActionTrigger{
				UniqueID:       oldAtr.Id,
				ThresholdType:  oldAtr.ThresholdType,
				ThresholdValue: oldAtr.ThresholdValue,
				Recurrent:      oldAtr.Recurrent,
				MinSleep:       oldAtr.MinSleep,
				Weight:         oldAtr.Weight,
				ActionsID:      oldAtr.ActionsId,
				MinQueuedItems: oldAtr.MinQueuedItems,
				Executed:       oldAtr.Executed,
			}
			bf := &engine.BalanceFilter{}
			if oldAtr.BalanceId != "" {
				bf.ID = utils.StringPointer(oldAtr.BalanceId)
			}
			if oldAtr.BalanceType != "" {
				bf.Type = utils.StringPointer(oldAtr.BalanceType)
			}
			if oldAtr.BalanceRatingSubject != "" {
				bf.RatingSubject = utils.StringPointer(oldAtr.BalanceRatingSubject)
			}
			if oldAtr.BalanceDirection != "" {
				bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDirection))
			}
			if oldAtr.BalanceDestinationIds != "" {
				bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDestinationIds))
			}
			if oldAtr.BalanceTimingTags != "" {
				bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceTimingTags))
			}
			if oldAtr.BalanceCategory != "" {
				bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceCategory))
			}
			if oldAtr.BalanceSharedGroup != "" {
				bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceSharedGroup))
			}
			if oldAtr.BalanceWeight != 0 {
				bf.Weight = utils.Float64Pointer(oldAtr.BalanceWeight)
			}
			if oldAtr.BalanceDisabled != false {
				bf.Disabled = utils.BoolPointer(oldAtr.BalanceDisabled)
			}
			if !oldAtr.BalanceExpirationDate.IsZero() {
				bf.ExpirationDate = utils.TimePointer(oldAtr.BalanceExpirationDate)
			}
			at.Balance = bf
			newAtrs[index] = at
			if newAtrs[index].ThresholdType == "*min_counter" ||
				newAtrs[index].ThresholdType == "*max_counter" {
				newAtrs[index].ThresholdType = strings.Replace(newAtrs[index].ThresholdType, "_", "_event_", 1)
			}
		}
		newAtrsMap[key] = newAtrs
	}
	// write data back
	for key, atrs := range newAtrsMap {
		result, err := mig.ms.Marshal(&atrs)
		if err != nil {
			return err
		}
		if err = mig.db.Cmd("SET", key, result).Err; err != nil {
			return err
		}
	}
	return nil
}
Example #18
0
func (mig MigratorRC8) migrateAccounts() error {
	keys, err := mig.db.Cmd("KEYS", OLD_ACCOUNT_PREFIX+"*").List()
	if err != nil {
		return err
	}
	newAccounts := make([]*engine.Account, 0)
	var migratedKeys []string
	// get existing accounts
	for _, key := range keys {
		log.Printf("Migrating account: %s...", key)
		values, err := mig.db.Cmd("GET", key).Bytes()
		if err != nil {
			continue
		}
		var oldAcc Account
		if err = mig.ms.Unmarshal(values, &oldAcc); err != nil {
			return err
		}
		// transfer data into new structurse
		newAcc := &engine.Account{
			ID:             oldAcc.Id,
			BalanceMap:     make(map[string]engine.Balances, len(oldAcc.BalanceMap)),
			UnitCounters:   make(engine.UnitCounters, len(oldAcc.UnitCounters)),
			ActionTriggers: make(engine.ActionTriggers, len(oldAcc.ActionTriggers)),
			AllowNegative:  oldAcc.AllowNegative,
			Disabled:       oldAcc.Disabled,
		}
		// fix id
		idElements := strings.Split(newAcc.ID, utils.CONCATENATED_KEY_SEP)
		if len(idElements) != 3 {
			log.Printf("Malformed account ID %s", oldAcc.Id)
			continue
		}
		newAcc.ID = fmt.Sprintf("%s:%s", idElements[1], idElements[2])
		// balances
		balanceErr := false
		for oldBalKey, oldBalChain := range oldAcc.BalanceMap {
			keyElements := strings.Split(oldBalKey, "*")
			if len(keyElements) != 3 {
				log.Printf("Malformed balance key in %s: %s", oldAcc.Id, oldBalKey)
				balanceErr = true
				break
			}
			newBalKey := "*" + keyElements[1]
			newBalDirection := "*" + keyElements[2]
			newAcc.BalanceMap[newBalKey] = make(engine.Balances, len(oldBalChain))
			for index, oldBal := range oldBalChain {
				// check default to set new id
				if oldBal.IsDefault() {
					oldBal.Id = utils.META_DEFAULT
				}
				newAcc.BalanceMap[newBalKey][index] = &engine.Balance{
					Uuid:           oldBal.Uuid,
					ID:             oldBal.Id,
					Value:          oldBal.Value,
					Directions:     utils.ParseStringMap(newBalDirection),
					ExpirationDate: oldBal.ExpirationDate,
					Weight:         oldBal.Weight,
					DestinationIDs: utils.ParseStringMap(oldBal.DestinationIds),
					RatingSubject:  oldBal.RatingSubject,
					Categories:     utils.ParseStringMap(oldBal.Category),
					SharedGroups:   utils.ParseStringMap(oldBal.SharedGroup),
					Timings:        oldBal.Timings,
					TimingIDs:      utils.ParseStringMap(oldBal.TimingIDs),
					Disabled:       oldBal.Disabled,
				}
			}
		}
		if balanceErr {
			continue
		}
		// unit counters
		for _, oldUc := range oldAcc.UnitCounters {
			newUc := &engine.UnitCounter{
				Counters: make(engine.CounterFilters, len(oldUc.Balances)),
			}
			for index, oldUcBal := range oldUc.Balances {
				bf := &engine.BalanceFilter{}
				if oldUcBal.Uuid != "" {
					bf.Uuid = utils.StringPointer(oldUcBal.Uuid)
				}
				if oldUcBal.Id != "" {
					bf.ID = utils.StringPointer(oldUcBal.Id)
				}
				if oldUc.BalanceType != "" {
					bf.Type = utils.StringPointer(oldUc.BalanceType)
				}
				// the value was used for counter value
				/*if oldUcBal.Value != 0 {
					bf.Value = utils.Float64Pointer(oldUcBal.Value)
				}*/
				if oldUc.Direction != "" {
					bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldUc.Direction))
				}
				if !oldUcBal.ExpirationDate.IsZero() {
					bf.ExpirationDate = utils.TimePointer(oldUcBal.ExpirationDate)
				}
				if oldUcBal.Weight != 0 {
					bf.Weight = utils.Float64Pointer(oldUcBal.Weight)
				}
				if oldUcBal.DestinationIds != "" {
					bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.DestinationIds))
				}
				if oldUcBal.RatingSubject != "" {
					bf.RatingSubject = utils.StringPointer(oldUcBal.RatingSubject)
				}
				if oldUcBal.Category != "" {
					bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.Category))
				}
				if oldUcBal.SharedGroup != "" {
					bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.SharedGroup))
				}
				if oldUcBal.TimingIDs != "" {
					bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.TimingIDs))
				}
				if oldUcBal.Disabled != false {
					bf.Disabled = utils.BoolPointer(oldUcBal.Disabled)
				}
				bf.Timings = oldUcBal.Timings
				cf := &engine.CounterFilter{
					Value:  oldUcBal.Value,
					Filter: bf,
				}
				newUc.Counters[index] = cf
			}
			newAcc.UnitCounters[oldUc.BalanceType] = append(newAcc.UnitCounters[oldUc.BalanceType], newUc)
		}
		// action triggers
		for index, oldAtr := range oldAcc.ActionTriggers {
			at := &engine.ActionTrigger{
				UniqueID:       oldAtr.Id,
				ThresholdType:  oldAtr.ThresholdType,
				ThresholdValue: oldAtr.ThresholdValue,
				Recurrent:      oldAtr.Recurrent,
				MinSleep:       oldAtr.MinSleep,
				Weight:         oldAtr.Weight,
				ActionsID:      oldAtr.ActionsId,
				MinQueuedItems: oldAtr.MinQueuedItems,
				Executed:       oldAtr.Executed,
			}
			bf := &engine.BalanceFilter{}
			if oldAtr.BalanceId != "" {
				bf.ID = utils.StringPointer(oldAtr.BalanceId)
			}
			if oldAtr.BalanceType != "" {
				bf.Type = utils.StringPointer(oldAtr.BalanceType)
			}
			if oldAtr.BalanceRatingSubject != "" {
				bf.RatingSubject = utils.StringPointer(oldAtr.BalanceRatingSubject)
			}
			if oldAtr.BalanceDirection != "" {
				bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDirection))
			}
			if oldAtr.BalanceDestinationIds != "" {
				bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDestinationIds))
			}
			if oldAtr.BalanceTimingTags != "" {
				bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceTimingTags))
			}
			if oldAtr.BalanceCategory != "" {
				bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceCategory))
			}
			if oldAtr.BalanceSharedGroup != "" {
				bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceSharedGroup))
			}
			if oldAtr.BalanceWeight != 0 {
				bf.Weight = utils.Float64Pointer(oldAtr.BalanceWeight)
			}
			if oldAtr.BalanceDisabled != false {
				bf.Disabled = utils.BoolPointer(oldAtr.BalanceDisabled)
			}
			if !oldAtr.BalanceExpirationDate.IsZero() {
				bf.ExpirationDate = utils.TimePointer(oldAtr.BalanceExpirationDate)
			}
			at.Balance = bf
			newAcc.ActionTriggers[index] = at
			if newAcc.ActionTriggers[index].ThresholdType == "*min_counter" ||
				newAcc.ActionTriggers[index].ThresholdType == "*max_counter" {
				newAcc.ActionTriggers[index].ThresholdType = strings.Replace(newAcc.ActionTriggers[index].ThresholdType, "_", "_event_", 1)
			}
		}
		newAcc.InitCounters()
		newAccounts = append(newAccounts, newAcc)
		migratedKeys = append(migratedKeys, key)
	}
	// write data back
	for _, newAcc := range newAccounts {
		result, err := mig.ms.Marshal(newAcc)
		if err != nil {
			return err
		}
		if err := mig.db.Cmd("SET", utils.ACCOUNT_PREFIX+newAcc.ID, result).Err; err != nil {
			return err
		}
	}
	// delete old data
	log.Printf("Deleting migrated accounts...")
	for _, key := range migratedKeys {
		if err := mig.db.Cmd("DEL", key).Err; err != nil {
			return err
		}
	}
	notMigrated := len(keys) - len(migratedKeys)
	if notMigrated > 0 {
		log.Printf("WARNING: there are %d accounts that failed migration!", notMigrated)
	}
	return err
}
Example #19
0
func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error {
	if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	for _, action := range attrs.Actions {
		requiredFields := []string{"Identifier", "Weight"}
		if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions
			requiredFields = append(requiredFields, "Direction", "Units")
		}
		if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 {
			return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), action.Identifier, missing)
		}
	}
	if !attrs.Overwrite {
		if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, attrs.ActionsId); err != nil {
			return utils.NewErrServerError(err)
		} else if exists {
			return utils.ErrExists
		}
	}
	storeActions := make(engine.Actions, len(attrs.Actions))
	for idx, apiAct := range attrs.Actions {
		var vf *utils.ValueFormula
		if apiAct.Units != "" {
			if x, err := utils.ParseBalanceFilterValue(apiAct.Units); err == nil {
				vf = x
			} else {
				return err
			}
		}

		var weight *float64
		if apiAct.BalanceWeight != "" {
			if x, err := strconv.ParseFloat(apiAct.BalanceWeight, 64); err == nil {
				weight = &x
			} else {
				return err
			}
		}

		a := &engine.Action{
			Id:               attrs.ActionsId,
			ActionType:       apiAct.Identifier,
			Weight:           apiAct.Weight,
			ExpirationString: apiAct.ExpiryTime,
			ExtraParameters:  apiAct.ExtraParameters,
			Filter:           apiAct.Filter,
			Balance: &engine.BalanceFilter{ // TODO: update this part
				Uuid:           utils.StringPointer(apiAct.BalanceUuid),
				ID:             utils.StringPointer(apiAct.BalanceId),
				Type:           utils.StringPointer(apiAct.BalanceType),
				Value:          vf,
				Weight:         weight,
				Directions:     utils.StringMapPointer(utils.ParseStringMap(apiAct.Directions)),
				DestinationIDs: utils.StringMapPointer(utils.ParseStringMap(apiAct.DestinationIds)),
				RatingSubject:  utils.StringPointer(apiAct.RatingSubject),
				SharedGroups:   utils.StringMapPointer(utils.ParseStringMap(apiAct.SharedGroups)),
			},
		}
		storeActions[idx] = a
	}
	if err := self.RatingDb.SetActions(attrs.ActionsId, storeActions); err != nil {
		return utils.NewErrServerError(err)
	}
	self.RatingDb.CacheRatingPrefixValues("SetActionsAPI", map[string][]string{utils.ACTION_PREFIX: []string{utils.ACTION_PREFIX + attrs.ActionsId}})
	*reply = OK
	return nil
}
Example #20
0
func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error {
	accountActions, err := tpr.lr.GetTpAccountActions(qriedAA)
	if err != nil {
		return errors.New(err.Error() + ": " + fmt.Sprintf("%+v", qriedAA))
	}
	storAas, err := TpAccountActions(accountActions).GetAccountActions()
	if err != nil {
		return err
	}
	for _, accountAction := range storAas {
		id := accountAction.KeyId()
		var actionsIds []string // collects action ids
		// action timings
		if accountAction.ActionPlanId != "" {
			// get old userBalanceIds
			var exitingAccountIds []string
			existingActionPlans, err := tpr.ratingStorage.GetActionPlans(accountAction.ActionPlanId, true)
			if err == nil && len(existingActionPlans) > 0 {
				// all action timings from a specific tag shuld have the same list of user balances from the first one
				exitingAccountIds = existingActionPlans[0].AccountIds
			}

			tpap, err := tpr.lr.GetTpActionPlans(tpr.tpid, accountAction.ActionPlanId)
			if err != nil {
				return errors.New(err.Error() + " (ActionPlan): " + accountAction.ActionPlanId)
			} else if len(tpap) == 0 {
				return fmt.Errorf("no action plan with id <%s>", accountAction.ActionPlanId)
			}
			aps, err := TpActionPlans(tpap).GetActionPlans()
			if err != nil {
				return err
			}
			var actionTimings []*ActionPlan
			ats := aps[accountAction.ActionPlanId]
			for _, at := range ats {
				// Check action exists before saving it inside actionTiming key
				// ToDo: try saving the key after the actions was retrieved in order to save one query here.
				if actions, err := tpr.lr.GetTpActions(tpr.tpid, at.ActionsId); err != nil {
					return errors.New(err.Error() + " (Actions): " + at.ActionsId)
				} else if len(actions) == 0 {
					return fmt.Errorf("no action with id <%s>", at.ActionsId)
				}
				var t *utils.TPTiming
				if at.TimingId != utils.ASAP {
					tptm, err := tpr.lr.GetTpTimings(tpr.tpid, at.TimingId)
					if err != nil {
						return errors.New(err.Error() + " (Timing): " + at.TimingId)
					} else if len(tptm) == 0 {
						return fmt.Errorf("no timing with id <%s>", at.TimingId)
					}
					tm, err := TpTimings(tptm).GetTimings()
					if err != nil {
						return err
					}
					t = tm[at.TimingId]
				} else {
					t = tpr.timings[at.TimingId] // *asap
				}
				actPln := &ActionPlan{
					Uuid:   utils.GenUUID(),
					Id:     accountAction.ActionPlanId,
					Weight: at.Weight,
					Timing: &RateInterval{
						Timing: &RITiming{
							Months:    t.Months,
							MonthDays: t.MonthDays,
							WeekDays:  t.WeekDays,
							StartTime: t.StartTime,
						},
					},
					ActionsId: at.ActionsId,
				}
				// collect action ids from timings
				actionsIds = append(actionsIds, actPln.ActionsId)
				//add user balance id if no already in
				found := false
				for _, ubId := range exitingAccountIds {
					if ubId == id {
						found = true
						break
					}
				}
				if !found {
					actPln.AccountIds = append(exitingAccountIds, id)
				}
				actionTimings = append(actionTimings, actPln)
			}

			// write action triggers
			err = tpr.ratingStorage.SetActionPlans(accountAction.ActionPlanId, actionTimings)
			if err != nil {
				return errors.New(err.Error() + " (SetActionPlan): " + accountAction.ActionPlanId)
			}
		}
		// action triggers
		var actionTriggers ActionTriggers
		//ActionTriggerPriotityList []*ActionTrigger
		if accountAction.ActionTriggersId != "" {
			tpatrs, err := tpr.lr.GetTpActionTriggers(tpr.tpid, accountAction.ActionTriggersId)
			if err != nil {
				return errors.New(err.Error() + " (ActionTriggers): " + accountAction.ActionTriggersId)
			}
			atrs, err := TpActionTriggers(tpatrs).GetActionTriggers()
			if err != nil {
				return err
			}

			atrsMap := make(map[string][]*ActionTrigger)
			for key, atrsLst := range atrs {
				atrs := make([]*ActionTrigger, len(atrsLst))
				for idx, apiAtr := range atrsLst {
					minSleep, _ := utils.ParseDurationWithSecs(apiAtr.MinSleep)
					expTime, _ := utils.ParseDate(apiAtr.BalanceExpirationDate)
					atrs[idx] = &ActionTrigger{
						ThresholdType:         apiAtr.ThresholdType,
						ThresholdValue:        apiAtr.ThresholdValue,
						Recurrent:             apiAtr.Recurrent,
						MinSleep:              minSleep,
						BalanceId:             apiAtr.BalanceId,
						BalanceType:           apiAtr.BalanceType,
						BalanceDirections:     utils.ParseStringMap(apiAtr.BalanceDirections),
						BalanceDestinationIds: utils.ParseStringMap(apiAtr.BalanceDestinationIds),
						BalanceWeight:         apiAtr.BalanceWeight,
						BalanceExpirationDate: expTime,
						BalanceRatingSubject:  apiAtr.BalanceRatingSubject,
						BalanceCategories:     utils.ParseStringMap(apiAtr.BalanceCategories),
						BalanceSharedGroups:   utils.ParseStringMap(apiAtr.BalanceSharedGroups),
						Weight:                apiAtr.Weight,
						ActionsId:             apiAtr.ActionsId,
					}
				}
				atrsMap[key] = atrs
			}
			actionTriggers = atrsMap[accountAction.ActionTriggersId]
			// collect action ids from triggers
			for _, atr := range actionTriggers {
				actionsIds = append(actionsIds, atr.ActionsId)
			}
			// write action triggers
			err = tpr.ratingStorage.SetActionTriggers(accountAction.ActionTriggersId, actionTriggers)
			if err != nil {
				return errors.New(err.Error() + " (SetActionTriggers): " + accountAction.ActionTriggersId)
			}
		}

		// actions
		acts := make(map[string][]*Action)
		for _, actId := range actionsIds {
			tpas, err := tpr.lr.GetTpActions(tpr.tpid, actId)
			if err != nil {
				return err
			}
			as, err := TpActions(tpas).GetActions()
			if err != nil {
				return err
			}
			for tag, tpacts := range as {
				enacts := make([]*Action, len(tpacts))
				for idx, tpact := range tpacts {
					enacts[idx] = &Action{
						Id:               tag + strconv.Itoa(idx),
						ActionType:       tpact.Identifier,
						BalanceType:      tpact.BalanceType,
						Weight:           tpact.Weight,
						ExtraParameters:  tpact.ExtraParameters,
						ExpirationString: tpact.ExpiryTime,
						Balance: &Balance{
							Value:          tpact.Units,
							Weight:         tpact.BalanceWeight,
							RatingSubject:  tpact.RatingSubject,
							Directions:     utils.ParseStringMap(tpact.Directions),
							DestinationIds: utils.ParseStringMap(tpact.DestinationIds),
							SharedGroups:   utils.ParseStringMap(tpact.SharedGroups),
							TimingIDs:      utils.ParseStringMap(tpact.TimingTags),
						},
					}
				}
				acts[tag] = enacts
			}
		}
		// write actions
		for k, as := range acts {
			err = tpr.ratingStorage.SetActions(k, as)
			if err != nil {
				return err
			}
		}
		ub, err := tpr.accountingStorage.GetAccount(id)
		if err != nil {
			ub = &Account{
				Id: id,
			}
		}
		ub.ActionTriggers = actionTriggers.Clone()
		// init counters
		ub.InitCounters()
		if err := tpr.accountingStorage.SetAccount(ub); err != nil {
			return err
		}
	}
	return nil
}