예제 #1
0
func GetUB() *Account {
	uc := &UnitCounter{
		BalanceType: utils.SMS,
		Balances:    BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
	}
	at := &ActionTrigger{
		Id:                    "some_uuid",
		BalanceType:           utils.MONETARY,
		BalanceDirections:     utils.NewStringMap(utils.OUT),
		ThresholdValue:        100.0,
		BalanceDestinationIds: utils.NewStringMap("NAT"),
		Weight:                10.0,
		ActionsId:             "Commando",
	}
	var zeroTime time.Time
	zeroTime = zeroTime.UTC() // for deep equal to find location
	ub := &Account{
		Id:             "rif",
		AllowNegative:  true,
		BalanceMap:     map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
		UnitCounters:   UnitCounters{uc, uc},
		ActionTriggers: ActionTriggers{at, at, at},
	}
	return ub
}
예제 #2
0
func GetUB() *Account {
	uc := &UnitCounter{
		Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
	}
	at := &ActionTrigger{
		ID:             "some_uuid",
		ThresholdValue: 100.0,
		Balance: &BalanceFilter{
			Type:           utils.StringPointer(utils.MONETARY),
			Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
			DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
		},
		Weight:    10.0,
		ActionsID: "Commando",
	}
	var zeroTime time.Time
	zeroTime = zeroTime.UTC() // for deep equal to find location
	ub := &Account{
		ID:             "rif",
		AllowNegative:  true,
		BalanceMap:     map[string]Balances{utils.SMS: Balances{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA: Balances{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: Balances{&Balance{Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
		UnitCounters:   UnitCounters{utils.SMS: []*UnitCounter{uc, uc}},
		ActionTriggers: ActionTriggers{at, at, at},
	}
	return ub
}
예제 #3
0
func testOnStorITCacheActions(t *testing.T) {
	acts := Actions{
		&Action{
			Id:               "MINI",
			ActionType:       TOPUP_RESET,
			ExpirationString: UNLIMITED,
			Weight:           10,
			Balance: &BalanceFilter{
				Type:       utils.StringPointer(utils.MONETARY),
				Uuid:       utils.StringPointer(utils.GenUUID()),
				Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
				Value: &utils.ValueFormula{Static: 10,
					Params: make(map[string]interface{})},
				Weight:   utils.Float64Pointer(10),
				Disabled: utils.BoolPointer(false),
				Timings:  make([]*RITiming, 0),
				Blocker:  utils.BoolPointer(false),
			},
		},
		&Action{
			Id:               "MINI",
			ActionType:       TOPUP,
			ExpirationString: UNLIMITED,
			Weight:           10,
			Balance: &BalanceFilter{
				Type:       utils.StringPointer(utils.VOICE),
				Uuid:       utils.StringPointer(utils.GenUUID()),
				Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
				Value: &utils.ValueFormula{Static: 100,
					Params: make(map[string]interface{})},
				Weight:         utils.Float64Pointer(10),
				RatingSubject:  utils.StringPointer("test"),
				DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
				Disabled:       utils.BoolPointer(false),
				Timings:        make([]*RITiming, 0),
				Blocker:        utils.BoolPointer(false),
			},
		},
	}
	if err := onStor.SetActions(acts[0].Id, acts, utils.NonTransactional); err != nil {
		t.Error(err)
	}
	if _, hasIt := cache.Get(utils.ACTION_PREFIX + acts[0].Id); hasIt {
		t.Error("Already in cache")
	}
	if err := onStor.CacheDataFromDB(utils.ACTION_PREFIX, []string{acts[0].Id}, false); err != nil {
		t.Error(err)
	}
	if itm, hasIt := cache.Get(utils.ACTION_PREFIX + acts[0].Id); !hasIt {
		t.Error("Did not cache")
	} else if rcv := itm.(Actions); !reflect.DeepEqual(acts, rcv) {
		t.Errorf("Expecting: %+v, received: %+v", acts, rcv)
	}
}
예제 #4
0
func TestLoadAccountActions(t *testing.T) {
	if len(csvr.accountActions) != 17 {
		t.Error("Failed to load account actions: ", len(csvr.accountActions))
	}
	aa := csvr.accountActions["vdf:minitsboy"]
	expected := &Account{
		ID: "vdf:minitsboy",
		UnitCounters: UnitCounters{
			utils.VOICE: []*UnitCounter{
				&UnitCounter{
					CounterType: "*event",
					Counters: CounterFilters{
						&CounterFilter{
							Value: 0,
							Filter: &BalanceFilter{
								ID:             utils.StringPointer("st0"),
								Type:           utils.StringPointer(utils.VOICE),
								Directions:     utils.StringMapPointer(utils.NewStringMap("*out")),
								DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
								SharedGroups:   nil,
								Categories:     nil,
								TimingIDs:      nil,
							},
						},
					},
				},
			},
		},
		ActionTriggers: csvr.actionsTriggers["STANDARD_TRIGGER"],
	}
	// set propper uuid
	for i, atr := range aa.ActionTriggers {
		csvr.actionsTriggers["STANDARD_TRIGGER"][i].ID = atr.ID
	}
	for i, b := range aa.UnitCounters[utils.VOICE][0].Counters {
		expected.UnitCounters[utils.VOICE][0].Counters[i].Filter.ID = b.Filter.ID
	}
	if !reflect.DeepEqual(aa.UnitCounters[utils.VOICE][0].Counters[0], expected.UnitCounters[utils.VOICE][0].Counters[0]) {
		t.Errorf("Error loading account action: %+v", utils.ToIJSON(aa.UnitCounters[utils.VOICE][0].Counters[0].Filter))
	}
	// test that it does not overwrite balances
	existing, err := accountingStorage.GetAccount(aa.ID)
	if err != nil || len(existing.BalanceMap) != 2 {
		t.Errorf("The account was not set before load: %+v", existing)
	}
	accountingStorage.SetAccount(aa)
	existing, err = accountingStorage.GetAccount(aa.ID)
	if err != nil || len(existing.BalanceMap) != 2 {
		t.Errorf("The set account altered the balances: %+v", existing)
	}
}
예제 #5
0
func TestLoadActionTriggers(t *testing.T) {
	if len(csvr.actionsTriggers) != 7 {
		t.Error("Failed to load action triggers: ", len(csvr.actionsTriggers))
	}
	atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0]
	expected := &ActionTrigger{
		ID:             "STANDARD_TRIGGER",
		UniqueID:       "st0",
		ThresholdType:  utils.TRIGGER_MIN_EVENT_COUNTER,
		ThresholdValue: 10,
		Balance: &BalanceFilter{
			ID:             nil,
			Type:           utils.StringPointer(utils.VOICE),
			Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
			DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
			Categories:     nil,
			TimingIDs:      nil,
			SharedGroups:   nil,
			Disabled:       nil,
			Blocker:        nil,
		},
		Weight:    10,
		ActionsID: "SOME_1",
		Executed:  false,
	}
	if !reflect.DeepEqual(atr, expected) {
		t.Errorf("Error loading action trigger: %+v", utils.ToIJSON(atr.Balance))
	}
	atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1]
	expected = &ActionTrigger{
		ID:             "STANDARD_TRIGGER",
		UniqueID:       "st1",
		ThresholdType:  utils.TRIGGER_MAX_BALANCE,
		ThresholdValue: 200,
		Balance: &BalanceFilter{
			Type:           utils.StringPointer(utils.VOICE),
			Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
			DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY")),
			Categories:     nil,
			TimingIDs:      nil,
			SharedGroups:   nil,
		},
		Weight:    10,
		ActionsID: "SOME_2",
		Executed:  false,
	}
	if !reflect.DeepEqual(atr, expected) {
		t.Errorf("Error loading action trigger: %+v", atr)
	}
}
예제 #6
0
func TestBalanceClone(t *testing.T) {
	mb1 := &Balance{Value: 1, Weight: 2, RatingSubject: "test", DestinationIds: utils.NewStringMap("5")}
	mb2 := mb1.Clone()
	if mb1 == mb2 || !mb1.Equal(mb2) {
		t.Errorf("Cloning failure: \n%+v\n%+v", mb1, mb2)
	}
}
예제 #7
0
func TestLoadAccountActions(t *testing.T) {
	if len(csvr.accountActions) != 11 {
		t.Error("Failed to load account actions: ", len(csvr.accountActions))
	}
	aa := csvr.accountActions["vdf:minitsboy"]
	expected := &Account{
		Id: "vdf:minitsboy",
		UnitCounters: UnitCounters{
			&UnitCounter{
				BalanceType: "*voice",
				CounterType: "*event",
				Balances: BalanceChain{
					&Balance{
						Id:             "2c2ce3c9-d62b-49dc-82a5-2a17bdc6eb4e",
						Value:          0,
						Directions:     utils.NewStringMap("*out"),
						DestinationIds: utils.NewStringMap("GERMANY_O2"),
						SharedGroups:   utils.StringMap{},
						Categories:     utils.StringMap{},
						TimingIDs:      utils.StringMap{},
					},
				},
			},
		},
		ActionTriggers: csvr.actionsTriggers["STANDARD_TRIGGER"],
	}
	// set propper uuid
	for i, atr := range aa.ActionTriggers {
		csvr.actionsTriggers["STANDARD_TRIGGER"][i].Id = atr.Id
	}
	for i, b := range aa.UnitCounters[0].Balances {
		expected.UnitCounters[0].Balances[i].Id = b.Id
	}
	if !reflect.DeepEqual(aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0]) {
		t.Errorf("Error loading account action: %+v \n %+v", aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0])
	}
	// test that it does not overwrite balances
	existing, err := accountingStorage.GetAccount(aa.Id)
	if err != nil || len(existing.BalanceMap) != 2 {
		t.Errorf("The account was not set before load: %+v", existing)
	}
	accountingStorage.SetAccount(aa)
	existing, err = accountingStorage.GetAccount(aa.Id)
	if err != nil || len(existing.BalanceMap) != 2 {
		t.Errorf("The set account altered the balances: %+v", existing)
	}
}
func TestHandleDeivedChargersMatchDestNegativeSpec(t *testing.T) {
	dcs := &utils.DerivedChargers{
		DestinationIDs: utils.NewStringMap("NAT", "!SPEC"),
	}
	if DerivedChargersMatchesDest(dcs, "0723045326") {
		t.Error("Derived charger failed to match dest")
	}
}
func TestHandleDeivedChargersMatchDestRet(t *testing.T) {
	dcs := &utils.DerivedChargers{
		DestinationIDs: utils.NewStringMap("RET"),
	}
	if !DerivedChargersMatchesDest(dcs, "0723045326") {
		t.Error("Derived charger failed to match dest")
	}
}
예제 #10
0
func TestLoadActionTriggers(t *testing.T) {
	if len(csvr.actionsTriggers) != 7 {
		t.Error("Failed to load action triggers: ", len(csvr.actionsTriggers))
	}
	atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0]
	expected := &ActionTrigger{
		ID:                    "STANDARD_TRIGGER",
		UniqueID:              "st0",
		BalanceType:           utils.VOICE,
		BalanceDirections:     utils.NewStringMap(utils.OUT),
		ThresholdType:         utils.TRIGGER_MIN_EVENT_COUNTER,
		ThresholdValue:        10,
		BalanceDestinationIds: utils.NewStringMap("GERMANY_O2"),
		BalanceCategories:     utils.StringMap{},
		BalanceTimingTags:     utils.StringMap{},
		BalanceSharedGroups:   utils.StringMap{},
		Weight:                10,
		ActionsId:             "SOME_1",
		Executed:              false,
	}
	if !reflect.DeepEqual(atr, expected) {
		t.Errorf("Error loading action trigger: %+v", atr)
	}
	atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1]
	expected = &ActionTrigger{
		ID:                    "STANDARD_TRIGGER",
		UniqueID:              "st1",
		BalanceType:           utils.VOICE,
		BalanceDirections:     utils.NewStringMap(utils.OUT),
		ThresholdType:         utils.TRIGGER_MAX_BALANCE,
		ThresholdValue:        200,
		BalanceDestinationIds: utils.NewStringMap("GERMANY"),
		BalanceCategories:     utils.StringMap{},
		BalanceTimingTags:     utils.StringMap{},
		BalanceSharedGroups:   utils.StringMap{},
		Weight:                10,
		ActionsId:             "SOME_2",
		Executed:              false,
	}
	if !reflect.DeepEqual(atr, expected) {
		t.Errorf("Error loading action trigger: %+v", atr)
	}
}
예제 #11
0
func TestUnitsCounterAddBalance(t *testing.T) {
	uc := &UnitCounter{
		BalanceType: utils.SMS,
		Balances:    BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
	}
	UnitCounters{uc}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
	if len(uc.Balances) != 3 {
		t.Error("Error adding minute bucket: ", uc.Balances)
	}
}
예제 #12
0
func TestBalanceMatchActionTriggerSharedGroup(t *testing.T) {
	at := &ActionTrigger{Balance: &BalanceFilter{SharedGroups: utils.StringMapPointer(utils.NewStringMap("test"))}}
	b := &Balance{SharedGroups: utils.NewStringMap("test")}
	if !b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.SharedGroups = utils.NewStringMap("test1")
	if b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.SharedGroups = utils.NewStringMap("")
	if b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.SharedGroups = utils.NewStringMap("test")
	at.Balance.SharedGroups = nil
	if !b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
}
예제 #13
0
func TestGetDC(t *testing.T) {
	attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "dan", Subject: "dan"}
	eDcs := utils.DerivedChargers{DestinationIds: utils.NewStringMap(),
		Chargers: []*utils.DerivedCharger{
			&utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default",
				AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"},
			&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default",
				AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"},
		}}
	var dcs utils.DerivedChargers
	if err := apierDcT.GetDerivedChargers(attrs, &dcs); err != nil {
		t.Error("Unexpected error", err.Error())
	} else if !reflect.DeepEqual(dcs, eDcs) {
		t.Errorf("Expecting: %v, received: %v", eDcs.DestinationIds, dcs.DestinationIds)
	}
}
예제 #14
0
func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *string) (err error) {
	if len(attrs.DerivedChargers) == 0 {
		return utils.NewErrMandatoryIeMissing("DerivedChargers")
	}
	if len(attrs.Direction) == 0 {
		attrs.Direction = utils.OUT
	}
	if len(attrs.Tenant) == 0 {
		attrs.Tenant = utils.ANY
	}
	if len(attrs.Category) == 0 {
		attrs.Category = utils.ANY
	}
	if len(attrs.Account) == 0 {
		attrs.Account = utils.ANY
	}
	if len(attrs.Subject) == 0 {
		attrs.Subject = utils.ANY
	}
	for _, dc := range attrs.DerivedChargers {
		if _, err = utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP); err != nil { // Make sure rules are OK before loading in db
			return fmt.Errorf("%s:%s", utils.ErrParserError.Error(), err.Error())
		}
	}
	dcKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject)
	if !attrs.Overwrite {
		if exists, err := self.RatingDb.HasData(utils.DERIVEDCHARGERS_PREFIX, dcKey); err != nil {
			return utils.NewErrServerError(err)
		} else if exists {
			return utils.ErrExists
		}
	}
	dstIds := strings.Split(attrs.DestinationIds, utils.INFIELD_SEP)
	dcs := &utils.DerivedChargers{DestinationIDs: utils.NewStringMap(dstIds...), Chargers: attrs.DerivedChargers}
	if err := self.RatingDb.SetDerivedChargers(dcKey, dcs); err != nil {
		return utils.NewErrServerError(err)
	}
	if err := self.RatingDb.CacheRatingPrefixValues(map[string][]string{
		utils.DERIVEDCHARGERS_PREFIX: []string{utils.DERIVEDCHARGERS_PREFIX + dcKey},
	}); err != nil {
		return utils.NewErrServerError(err)
	}
	*reply = utils.OK
	return nil
}
예제 #15
0
func TestSharedSetGet(t *testing.T) {
	id := "TEST_SG100"
	sg := &SharedGroup{
		Id: id,
		AccountParameters: map[string]*SharingParameters{
			"test": &SharingParameters{Strategy: STRATEGY_HIGHEST},
		},
		MemberIds: utils.NewStringMap("1", "2", "3"),
	}
	err := ratingStorage.SetSharedGroup(sg, utils.NonTransactional)
	if err != nil {
		t.Error("Error storing Shared groudp: ", err)
	}
	received, err := ratingStorage.GetSharedGroup(id, true, utils.NonTransactional)
	if err != nil || received == nil || !reflect.DeepEqual(sg, received) {
		t.Error("Error getting shared group: ", err, received)
	}
	received, err = ratingStorage.GetSharedGroup(id, false, utils.NonTransactional)
	if err != nil || received == nil || !reflect.DeepEqual(sg, received) {
		t.Error("Error getting cached shared group: ", err, received)
	}

}
예제 #16
0
func TestBalanceMatchActionTriggerDestination(t *testing.T) {
	at := &ActionTrigger{BalanceDestinationIds: utils.NewStringMap("test")}
	b := &Balance{DestinationIds: utils.NewStringMap("test")}
	if !b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.DestinationIds = utils.NewStringMap("test1")
	if b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.DestinationIds = utils.NewStringMap("")
	if b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
	b.DestinationIds = utils.NewStringMap("test")
	at.BalanceDestinationIds = utils.NewStringMap("")
	if !b.MatchActionTrigger(at) {
		t.Errorf("Error matching action trigger: %+v %+v", b, at)
	}
}
예제 #17
0
func TestUnitsCounterAddBalanceExists(t *testing.T) {
	uc := &UnitCounter{
		Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Value: 10, Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
	}
	UnitCounters{utils.SMS: []*UnitCounter{uc}}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
	if len(uc.Counters) != 3 || uc.Counters[1].Value != 15 {
		t.Error("Error adding minute bucket!")
	}
}
예제 #18
0
func (self *ApierV1) SetActionTrigger(attr AttrSetActionTrigger, reply *string) error {

	if missing := utils.MissingStructFields(&attr, []string{"GroupID"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}

	atrs, _ := self.RatingDb.GetActionTriggers(attr.GroupID, false, utils.NonTransactional)
	var newAtr *engine.ActionTrigger
	if attr.UniqueID != "" {
		//search for exiting one
		for _, atr := range atrs {
			if atr.UniqueID == attr.UniqueID {
				newAtr = atr
				break
			}
		}
	}

	if newAtr == nil {
		newAtr = &engine.ActionTrigger{}
		atrs = append(atrs, newAtr)
	}
	newAtr.ID = attr.GroupID
	if attr.UniqueID != "" {
		newAtr.UniqueID = attr.UniqueID
	} else {
		newAtr.UniqueID = utils.GenUUID()
	}

	if attr.ThresholdType != nil {
		newAtr.ThresholdType = *attr.ThresholdType
	}
	if attr.ThresholdValue != nil {
		newAtr.ThresholdValue = *attr.ThresholdValue
	}
	if attr.Recurrent != nil {
		newAtr.Recurrent = *attr.Recurrent
	}
	if attr.MinSleep != nil {
		minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep)
		if err != nil {
			*reply = err.Error()
			return err
		}
		newAtr.MinSleep = minSleep
	}
	if attr.ExpirationDate != nil {
		expTime, err := utils.ParseTimeDetectLayout(*attr.ExpirationDate, self.Config.DefaultTimezone)
		if err != nil {
			*reply = err.Error()
			return err
		}
		newAtr.ExpirationDate = expTime
	}
	if attr.ActivationDate != nil {
		actTime, err := utils.ParseTimeDetectLayout(*attr.ActivationDate, self.Config.DefaultTimezone)
		if err != nil {
			*reply = err.Error()
			return err
		}
		newAtr.ActivationDate = actTime
	}
	newAtr.Balance = &engine.BalanceFilter{}
	if attr.BalanceID != nil {
		newAtr.Balance.ID = attr.BalanceID
	}
	if attr.BalanceType != nil {
		newAtr.Balance.Type = attr.BalanceType
	}
	if attr.BalanceDirections != nil {
		newAtr.Balance.Directions = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDirections...))
	}
	if attr.BalanceDestinationIds != nil {
		newAtr.Balance.DestinationIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDestinationIds...))
	}
	if attr.BalanceWeight != nil {
		newAtr.Balance.Weight = attr.BalanceWeight
	}
	if attr.BalanceExpirationDate != nil {
		balanceExpTime, err := utils.ParseDate(*attr.BalanceExpirationDate)
		if err != nil {
			*reply = err.Error()
			return err
		}
		newAtr.Balance.ExpirationDate = &balanceExpTime
	}
	if attr.BalanceTimingTags != nil {
		newAtr.Balance.TimingIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceTimingTags...))
	}
	if attr.BalanceRatingSubject != nil {
		newAtr.Balance.RatingSubject = attr.BalanceRatingSubject
	}
	if attr.BalanceCategories != nil {
		newAtr.Balance.Categories = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceCategories...))
	}
	if attr.BalanceSharedGroups != nil {
		newAtr.Balance.SharedGroups = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceSharedGroups...))
	}
	if attr.BalanceBlocker != nil {
		newAtr.Balance.Blocker = attr.BalanceBlocker
	}
	if attr.BalanceDisabled != nil {
		newAtr.Balance.Disabled = attr.BalanceDisabled
	}
	if attr.MinQueuedItems != nil {
		newAtr.MinQueuedItems = *attr.MinQueuedItems
	}
	if attr.ActionsID != nil {
		newAtr.ActionsID = *attr.ActionsID
	}

	if err := self.RatingDb.SetActionTriggers(attr.GroupID, atrs, utils.NonTransactional); err != nil {
		*reply = err.Error()
		return err
	}
	//no cache for action triggers
	*reply = utils.OK
	return nil
}
예제 #19
0
func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers, reply *string) error {

	if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
		return utils.NewErrMandatoryIeMissing(missing...)
	}
	accID := utils.AccountKey(attr.Tenant, attr.Account)
	var account *engine.Account
	_, err := engine.Guardian.Guard(func() (interface{}, error) {
		if acc, err := self.AccountDb.GetAccount(accID); err == nil {
			account = acc
		} else {
			return 0, err
		}
		for _, at := range account.ActionTriggers {
			if (attr.UniqueID == "" || at.UniqueID == attr.UniqueID) &&
				(attr.GroupID == "" || at.ID == attr.GroupID) {
				// we have a winner
				if attr.ThresholdType != nil {
					at.ThresholdType = *attr.ThresholdType
				}
				if attr.ThresholdValue != nil {
					at.ThresholdValue = *attr.ThresholdValue
				}
				if attr.Recurrent != nil {
					at.Recurrent = *attr.Recurrent
				}
				if attr.Executed != nil {
					at.Executed = *attr.Executed
				}
				if attr.MinSleep != nil {
					minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep)
					if err != nil {
						return 0, err
					}
					at.MinSleep = minSleep
				}
				if attr.ExpirationDate != nil {
					expTime, err := utils.ParseTimeDetectLayout(*attr.ExpirationDate, self.Config.DefaultTimezone)
					if err != nil {
						return 0, err
					}
					at.ExpirationDate = expTime
				}
				if attr.ActivationDate != nil {
					actTime, err := utils.ParseTimeDetectLayout(*attr.ActivationDate, self.Config.DefaultTimezone)
					if err != nil {
						return 0, err
					}
					at.ActivationDate = actTime
				}
				at.Balance = &engine.BalanceFilter{}
				if attr.BalanceID != nil {
					at.Balance.ID = attr.BalanceID
				}
				if attr.BalanceType != nil {
					at.Balance.Type = attr.BalanceType
				}
				if attr.BalanceDirections != nil {
					at.Balance.Directions = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDirections...))
				}
				if attr.BalanceDestinationIds != nil {
					at.Balance.DestinationIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDestinationIds...))
				}
				if attr.BalanceWeight != nil {
					at.Balance.Weight = attr.BalanceWeight
				}
				if attr.BalanceExpirationDate != nil {
					balanceExpTime, err := utils.ParseDate(*attr.BalanceExpirationDate)
					if err != nil {
						return 0, err
					}
					at.Balance.ExpirationDate = &balanceExpTime
				}
				if attr.BalanceTimingTags != nil {
					at.Balance.TimingIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceTimingTags...))
				}
				if attr.BalanceRatingSubject != nil {
					at.Balance.RatingSubject = attr.BalanceRatingSubject
				}
				if attr.BalanceCategories != nil {
					at.Balance.Categories = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceCategories...))
				}
				if attr.BalanceSharedGroups != nil {
					at.Balance.SharedGroups = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceSharedGroups...))
				}
				if attr.BalanceBlocker != nil {
					at.Balance.Blocker = attr.BalanceBlocker
				}
				if attr.BalanceDisabled != nil {
					at.Balance.Disabled = attr.BalanceDisabled
				}
				if attr.MinQueuedItems != nil {
					at.MinQueuedItems = *attr.MinQueuedItems
				}
				if attr.ActionsID != nil {
					at.ActionsID = *attr.ActionsID
				}
			}

		}
		account.ExecuteActionTriggers(nil)
		if err := self.AccountDb.SetAccount(account); err != nil {
			return 0, err
		}
		return 0, nil
	}, 0, accID)
	if err != nil {
		*reply = err.Error()
		return err
	}
	*reply = utils.OK
	return nil
}
예제 #20
0
func TestUnitCountersCountAllMonetary(t *testing.T) {
	a := &Account{
		ActionTriggers: ActionTriggers{
			&ActionTrigger{
				UniqueID:      "TestTR1",
				ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.MONETARY),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR11",
				ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.MONETARY),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR2",
				ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.VOICE),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR3",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.VOICE),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR4",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.SMS),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR5",
				ThresholdType: utils.TRIGGER_MAX_BALANCE,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.SMS),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT, utils.IN)),
					Weight:     utils.Float64Pointer(10),
				},
			},
		},
	}
	a.InitCounters()
	a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)

	if len(a.UnitCounters) != 3 ||
		len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
		a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
		a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
		for key, counters := range a.UnitCounters {
			t.Log(key)
			for _, uc := range counters {
				t.Logf("UC: %+v", uc)
				for _, b := range uc.Counters {
					t.Logf("B: %+v", b)
				}
			}
		}
		t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
	}
}
예제 #21
0
func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
	a := &Account{
		ActionTriggers: ActionTriggers{
			&ActionTrigger{
				UniqueID:          "TestTR1",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.MONETARY,
				BalanceDirections: utils.NewStringMap(utils.OUT),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR11",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.MONETARY,
				BalanceDirections: utils.NewStringMap(utils.OUT),
				BalanceWeight:     20,
			},
			&ActionTrigger{
				UniqueID:              "TestTR2",
				ThresholdType:         utils.TRIGGER_MAX_EVENT_COUNTER,
				BalanceType:           utils.VOICE,
				BalanceDirections:     utils.NewStringMap(utils.OUT),
				BalanceDestinationIds: utils.NewStringMap("NAT"),
				BalanceWeight:         10,
			},
			&ActionTrigger{
				UniqueID:              "TestTR22",
				ThresholdType:         utils.TRIGGER_MAX_EVENT_COUNTER,
				BalanceType:           utils.VOICE,
				BalanceDestinationIds: utils.NewStringMap("RET"),
				BalanceWeight:         10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR3",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.VOICE,
				BalanceDirections: utils.NewStringMap(utils.OUT),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR4",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.SMS,
				BalanceDirections: utils.NewStringMap(utils.OUT),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR5",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE,
				BalanceType:       utils.SMS,
				BalanceDirections: utils.NewStringMap(utils.OUT),
				BalanceWeight:     10,
			},
		},
	}
	a.InitCounters()
	a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)

	if len(a.UnitCounters) != 4 ||
		len(a.UnitCounters[1].Balances) != 2 ||
		a.UnitCounters[1].Balances[0].Value != 10 ||
		a.UnitCounters[1].Balances[1].Value != 10 {
		for _, uc := range a.UnitCounters {
			t.Logf("UC: %+v", uc)
			for _, b := range uc.Balances {
				t.Logf("B: %+v", b)
			}
		}
		t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
	}
	a.InitCounters()

	if len(a.UnitCounters) != 4 ||
		len(a.UnitCounters[1].Balances) != 2 ||
		a.UnitCounters[1].Balances[0].Value != 10 ||
		a.UnitCounters[1].Balances[1].Value != 10 {
		for _, uc := range a.UnitCounters {
			t.Logf("UC: %+v", uc)
			for _, b := range uc.Balances {
				t.Logf("B: %+v", b)
			}
		}
		t.Errorf("Error keeping counter values after init: %v", len(a.UnitCounters))
	}
}
예제 #22
0
func TestBalanceMatchFilterId(t *testing.T) {
	mb1 := &Balance{ID: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIDs: utils.NewStringMap("NAT")}
	mb2 := &BalanceFilter{ID: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
	if !mb1.MatchFilter(mb2, false) {
		t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
	}
}
예제 #23
0
func TestLoadActions(t *testing.T) {
	if len(csvr.actions) != 9 {
		t.Error("Failed to load actions: ", len(csvr.actions))
	}
	as1 := csvr.actions["MINI"]
	expected := []*Action{
		&Action{
			Id:               "MINI0",
			ActionType:       TOPUP_RESET,
			BalanceType:      utils.MONETARY,
			ExpirationString: UNLIMITED,
			ExtraParameters:  "",
			Weight:           10,
			Balance: &Balance{
				Uuid:         as1[0].Balance.Uuid,
				Directions:   utils.NewStringMap(utils.OUT),
				Value:        10,
				Weight:       10,
				TimingIDs:    utils.StringMap{},
				SharedGroups: utils.StringMap{},
			},
		},
		&Action{
			Id:               "MINI1",
			ActionType:       TOPUP,
			BalanceType:      utils.VOICE,
			ExpirationString: UNLIMITED,
			ExtraParameters:  "",
			Weight:           10,
			Balance: &Balance{
				Uuid:           as1[1].Balance.Uuid,
				Directions:     utils.NewStringMap(utils.OUT),
				Value:          100,
				Weight:         10,
				RatingSubject:  "test",
				DestinationIds: utils.NewStringMap("NAT"),
				TimingIDs:      utils.StringMap{},
				SharedGroups:   utils.StringMap{},
			},
		},
	}
	if !reflect.DeepEqual(as1[1], expected[1]) {
		t.Errorf("Error loading action1: %+v", as1[0].Balance)
	}
	as2 := csvr.actions["SHARED"]
	expected = []*Action{
		&Action{
			Id:               "SHARED0",
			ActionType:       TOPUP,
			BalanceType:      utils.MONETARY,
			ExpirationString: UNLIMITED,
			Weight:           10,
			Balance: &Balance{
				Directions:     utils.NewStringMap(utils.OUT),
				DestinationIds: utils.StringMap{},
				Uuid:           as2[0].Balance.Uuid,
				Value:          100,
				Weight:         10,
				SharedGroups:   utils.NewStringMap("SG1"),
				TimingIDs:      utils.StringMap{},
			},
		},
	}
	if !reflect.DeepEqual(as2[0], expected[0]) {
		t.Errorf("Error loading action: %+v", as2[0].Balance)
	}
	as3 := csvr.actions["DEFEE"]
	expected = []*Action{
		&Action{
			Id:              "DEFEE0",
			ActionType:      CDRLOG,
			ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`,
			Weight:          10,
			Balance: &Balance{
				Uuid:           as3[0].Balance.Uuid,
				Directions:     utils.StringMap{},
				DestinationIds: utils.StringMap{},
				TimingIDs:      utils.StringMap{},
				SharedGroups:   utils.StringMap{},
			},
		},
	}
	if !reflect.DeepEqual(as3, expected) {
		t.Errorf("Error loading action: %+v", as3[0].Balance)
	}
}
예제 #24
0
func TestUnitCountersCountAllMonetary(t *testing.T) {
	a := &Account{
		ActionTriggers: ActionTriggers{
			&ActionTrigger{
				UniqueID:          "TestTR1",
				ThresholdType:     utils.TRIGGER_MAX_EVENT_COUNTER,
				BalanceType:       utils.MONETARY,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR11",
				ThresholdType:     utils.TRIGGER_MAX_EVENT_COUNTER,
				BalanceType:       utils.MONETARY,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR2",
				ThresholdType:     utils.TRIGGER_MAX_EVENT_COUNTER,
				BalanceType:       utils.VOICE,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR3",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.VOICE,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR4",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE_COUNTER,
				BalanceType:       utils.SMS,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
			&ActionTrigger{
				UniqueID:          "TestTR5",
				ThresholdType:     utils.TRIGGER_MAX_BALANCE,
				BalanceType:       utils.SMS,
				BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN),
				BalanceWeight:     10,
			},
		},
	}
	a.InitCounters()
	a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)

	if len(a.UnitCounters) != 4 ||
		len(a.UnitCounters[0].Balances) != 2 ||
		a.UnitCounters[0].Balances[0].Value != 10 ||
		a.UnitCounters[0].Balances[1].Value != 10 {
		for _, uc := range a.UnitCounters {
			t.Logf("UC: %+v", uc)
			for _, b := range uc.Balances {
				t.Logf("B: %+v", b)
			}
		}
		t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
	}
}
예제 #25
0
func TestUnitsCounterAddBalanceExists(t *testing.T) {
	uc := &UnitCounter{
		BalanceType: utils.SMS,
		Balances:    BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
	}
	UnitCounters{uc}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
	if len(uc.Balances) != 3 || uc.Balances[1].GetValue() != 15 {
		t.Error("Error adding minute bucket!")
	}
}
예제 #26
0
func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
	a := &Account{
		ActionTriggers: ActionTriggers{
			&ActionTrigger{
				UniqueID:      "TestTR1",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.MONETARY),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR11",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.MONETARY),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					Weight:     utils.Float64Pointer(20),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR2",
				ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
				Balance: &BalanceFilter{
					Type:           utils.StringPointer(utils.VOICE),
					Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
					Weight:         utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR22",
				ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
				Balance: &BalanceFilter{
					Type:           utils.StringPointer(utils.VOICE),
					DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
					Weight:         utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR3",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.VOICE),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR4",
				ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.SMS),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					Weight:     utils.Float64Pointer(10),
				},
			},
			&ActionTrigger{
				UniqueID:      "TestTR5",
				ThresholdType: utils.TRIGGER_MAX_BALANCE,
				Balance: &BalanceFilter{
					Type:       utils.StringPointer(utils.SMS),
					Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
					Weight:     utils.Float64Pointer(10),
				},
			},
		},
	}
	a.InitCounters()
	a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)

	if len(a.UnitCounters) != 3 ||
		len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
		a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
		a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
		for key, counters := range a.UnitCounters {
			t.Log(key)
			for _, uc := range counters {
				t.Logf("UC: %+v", uc)
				for _, b := range uc.Counters {
					t.Logf("B: %+v", b)
				}
			}
		}
		t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
	}
	a.InitCounters()

	if len(a.UnitCounters) != 3 ||
		len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
		a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
		a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
		for key, counters := range a.UnitCounters {
			t.Log(key)
			for _, uc := range counters {
				t.Logf("UC: %+v", uc)
				for _, b := range uc.Counters {
					t.Logf("B: %+v", b)
				}
			}
		}
		t.Errorf("Error keeping counter values after init: %v", len(a.UnitCounters))
	}
}
예제 #27
0
func populateDB() {
	ats := []*Action{
		&Action{ActionType: "*topup", BalanceType: utils.MONETARY, Balance: &Balance{Value: 10}},
		&Action{ActionType: "*topup", BalanceType: utils.VOICE, Balance: &Balance{Weight: 20, Value: 10, DestinationIds: utils.NewStringMap("NAT")}},
	}

	ats1 := []*Action{
		&Action{ActionType: "*topup", BalanceType: utils.MONETARY, Balance: &Balance{Value: 10}, Weight: 10},
		&Action{ActionType: "*reset_account", Weight: 20},
	}

	minu := &Account{
		Id: "vdf:minu",
		BalanceMap: map[string]BalanceChain{
			utils.MONETARY: BalanceChain{&Balance{Value: 50}},
			utils.VOICE: BalanceChain{
				&Balance{Value: 200, DestinationIds: utils.NewStringMap("NAT"), Weight: 10},
				&Balance{Value: 100, DestinationIds: utils.NewStringMap("RET"), Weight: 20},
			}},
	}
	broker := &Account{
		Id: "vdf:broker",
		BalanceMap: map[string]BalanceChain{
			utils.VOICE: BalanceChain{
				&Balance{Value: 20, DestinationIds: utils.NewStringMap("NAT"), Weight: 10, RatingSubject: "rif"},
				&Balance{Value: 100, DestinationIds: utils.NewStringMap("RET"), Weight: 20},
			}},
	}
	luna := &Account{
		Id: "vdf:luna",
		BalanceMap: map[string]BalanceChain{
			utils.MONETARY: BalanceChain{
				&Balance{Value: 0, Weight: 20},
			}},
	}
	// this is added to test if csv load tests account will not overwrite balances
	minitsboy := &Account{
		Id: "vdf:minitsboy",
		BalanceMap: map[string]BalanceChain{
			utils.VOICE: BalanceChain{
				&Balance{Value: 20, DestinationIds: utils.NewStringMap("NAT"), Weight: 10, RatingSubject: "rif"},
				&Balance{Value: 100, DestinationIds: utils.NewStringMap("RET"), Weight: 20},
			},
			utils.MONETARY: BalanceChain{
				&Balance{Value: 100, Weight: 10},
			},
		},
	}
	max := &Account{
		Id: "cgrates.org:max",
		BalanceMap: map[string]BalanceChain{
			utils.MONETARY: BalanceChain{
				&Balance{Value: 11, Weight: 20},
			}},
	}
	money := &Account{
		Id: "cgrates.org:money",
		BalanceMap: map[string]BalanceChain{
			utils.MONETARY: BalanceChain{
				&Balance{Value: 10000, Weight: 10},
			}},
	}
	if accountingStorage != nil && ratingStorage != nil {
		ratingStorage.SetActions("TEST_ACTIONS", ats)
		ratingStorage.SetActions("TEST_ACTIONS_ORDER", ats1)
		accountingStorage.SetAccount(broker)
		accountingStorage.SetAccount(minu)
		accountingStorage.SetAccount(minitsboy)
		accountingStorage.SetAccount(luna)
		accountingStorage.SetAccount(max)
		accountingStorage.SetAccount(money)
	} else {
		log.Fatal("Could not connect to db!")
	}
}
예제 #28
0
func TestBalanceMatchFilterId(t *testing.T) {
	mb1 := &Balance{Id: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIds: utils.NewStringMap("NAT")}
	mb2 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}}
	if !mb1.MatchFilter(mb2, false) {
		t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
	}
}
예제 #29
0
func TestLoadActions(t *testing.T) {
	if len(csvr.actions) != 15 {
		t.Error("Failed to load actions: ", len(csvr.actions))
	}
	as1 := csvr.actions["MINI"]
	expected := []*Action{
		&Action{
			Id:               "MINI",
			ActionType:       TOPUP_RESET,
			ExpirationString: UNLIMITED,
			ExtraParameters:  "",
			Weight:           10,
			Balance: &BalanceFilter{
				Type:           utils.StringPointer(utils.MONETARY),
				Uuid:           as1[0].Balance.Uuid,
				Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
				Value:          &utils.ValueFormula{Static: 10},
				Weight:         utils.Float64Pointer(10),
				DestinationIDs: nil,
				TimingIDs:      nil,
				SharedGroups:   nil,
				Categories:     nil,
				Disabled:       utils.BoolPointer(false),
				Blocker:        utils.BoolPointer(false),
			},
		},
		&Action{
			Id:               "MINI",
			ActionType:       TOPUP,
			ExpirationString: UNLIMITED,
			ExtraParameters:  "",
			Weight:           10,
			Balance: &BalanceFilter{
				Type:           utils.StringPointer(utils.VOICE),
				Uuid:           as1[1].Balance.Uuid,
				Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
				Value:          &utils.ValueFormula{Static: 100},
				Weight:         utils.Float64Pointer(10),
				RatingSubject:  utils.StringPointer("test"),
				DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
				TimingIDs:      nil,
				SharedGroups:   nil,
				Categories:     nil,
				Disabled:       utils.BoolPointer(false),
				Blocker:        utils.BoolPointer(false),
			},
		},
	}
	if !reflect.DeepEqual(as1, expected) {
		t.Errorf("Error loading action1: %s", utils.ToIJSON(as1))
	}
	as2 := csvr.actions["SHARED"]
	expected = []*Action{
		&Action{
			Id:               "SHARED",
			ActionType:       TOPUP,
			ExpirationString: UNLIMITED,
			Weight:           10,
			Balance: &BalanceFilter{
				Type:           utils.StringPointer(utils.MONETARY),
				Directions:     utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
				DestinationIDs: nil,
				Uuid:           as2[0].Balance.Uuid,
				Value:          &utils.ValueFormula{Static: 100},
				Weight:         utils.Float64Pointer(10),
				SharedGroups:   utils.StringMapPointer(utils.NewStringMap("SG1")),
				TimingIDs:      nil,
				Categories:     nil,
				Disabled:       utils.BoolPointer(false),
				Blocker:        utils.BoolPointer(false),
			},
		},
	}
	if !reflect.DeepEqual(as2, expected) {
		t.Errorf("Error loading action: %s", utils.ToIJSON(as2))
	}
	as3 := csvr.actions["DEFEE"]
	expected = []*Action{
		&Action{
			Id:              "DEFEE",
			ActionType:      CDRLOG,
			ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`,
			Weight:          10,
			Balance: &BalanceFilter{
				Uuid:           as3[0].Balance.Uuid,
				Directions:     nil,
				DestinationIDs: nil,
				TimingIDs:      nil,
				Categories:     nil,
				SharedGroups:   nil,
				Blocker:        utils.BoolPointer(false),
				Disabled:       utils.BoolPointer(false),
			},
		},
	}
	if !reflect.DeepEqual(as3, expected) {
		t.Errorf("Error loading action: %+v", as3[0].Balance)
	}
}
예제 #30
0
파일: account.go 프로젝트: eloycoto/cgrates
func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bool, goNegative bool) (cc *CallCost, err error) {
	usefulUnitBalances := ub.getAlldBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, cd.TOR)
	usefulMoneyBalances := ub.getAlldBalancesForPrefix(cd.Destination, cd.Category, cd.Direction, utils.MONETARY)
	//utils.Logger.Info(fmt.Sprintf("%+v, %+v", usefulMoneyBalances, usefulUnitBalances))
	//utils.Logger.Info(fmt.Sprintf("STARTCD: %+v", cd))
	//log.Printf("%+v, %+v", usefulMoneyBalances, usefulUnitBalances)
	var leftCC *CallCost
	cc = cd.CreateCallCost()

	generalBalanceChecker := true
	for generalBalanceChecker {
		generalBalanceChecker = false

		// debit minutes
		unitBalanceChecker := true
		for unitBalanceChecker {
			// try every balance multiple times in case one becomes active or ratig changes
			unitBalanceChecker = false
			//log.Printf("InitialCD: %+v", cd)
			for _, balance := range usefulUnitBalances {
				//utils.Logger.Info(fmt.Sprintf("Unit balance: %+v", balance))
				//utils.Logger.Info(fmt.Sprintf("CD BEFORE UNIT: %+v", cd))

				partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0)
				if debitErr != nil {
					return nil, debitErr
				}
				//utils.Logger.Info(fmt.Sprintf("CD AFTER UNIT: %+v", cd))
				if partCC != nil {
					//log.Printf("partCC: %+v", partCC.Timespans[0])
					cc.Timespans = append(cc.Timespans, partCC.Timespans...)
					cc.negativeConnectFee = partCC.negativeConnectFee
					// for i, ts := range cc.Timespans {
					//  log.Printf("cc.times[an[%d]: %+v\n", i, ts)
					// }
					cd.TimeStart = cc.GetEndTime()
					//log.Printf("CD: %+v", cd)
					//log.Printf("CD: %+v - %+v", cd.TimeStart, cd.TimeEnd)
					// check if the calldescriptor is covered
					if cd.GetDuration() <= 0 {
						goto COMMIT
					}
					unitBalanceChecker = true
					generalBalanceChecker = true
					// check for max cost disconnect
					if dryRun && partCC.maxCostDisconect {
						// only return if we are in dry run (max call duration)
						return
					}
				}
				// check for blocker
				if dryRun && balance.Blocker {
					//log.Print("BLOCKER!")
					return // don't go to next balances
				}
			}
		}
		// debit money
		moneyBalanceChecker := true
		for moneyBalanceChecker {
			// try every balance multiple times in case one becomes active or ratig changes
			moneyBalanceChecker = false
			for _, balance := range usefulMoneyBalances {
				//utils.Logger.Info(fmt.Sprintf("Money balance: %+v", balance))
				//utils.Logger.Info(fmt.Sprintf("CD BEFORE MONEY: %+v", cd))
				partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0)
				if debitErr != nil {
					return nil, debitErr
				}
				//utils.Logger.Info(fmt.Sprintf("CD AFTER MONEY: %+v", cd))
				if partCC != nil {
					cc.Timespans = append(cc.Timespans, partCC.Timespans...)
					cc.negativeConnectFee = partCC.negativeConnectFee

					/*for i, ts := range cc.Timespans {
						log.Printf("cc.times[an[%d]: %+v\n", i, ts)
					}*/
					cd.TimeStart = cc.GetEndTime()
					//log.Printf("CD: %+v", cd)
					//log.Printf("CD: %+v - %+v", cd.TimeStart, cd.TimeEnd)
					// check if the calldescriptor is covered
					if cd.GetDuration() <= 0 {
						goto COMMIT
					}
					moneyBalanceChecker = true
					generalBalanceChecker = true
					if dryRun && partCC.maxCostDisconect {
						// only return if we are in dry run (max call duration)
						return
					}
				}
				// check for blocker
				if dryRun && balance.Blocker {
					//log.Print("BLOCKER!")
					return // don't go to next balances
				}
			}
		}
		//log.Printf("END CD: %+v", cd)
		//log.Print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
	}
	//log.Printf("After balances CD: %+v", cd)
	leftCC, err = cd.getCost()
	if err != nil {
		utils.Logger.Err(fmt.Sprintf("Error getting new cost for balance subject: %v", err))
	}
	if leftCC.Cost == 0 && len(leftCC.Timespans) > 0 {
		// put AccountID ubformation in increments
		for _, ts := range leftCC.Timespans {
			for _, inc := range ts.Increments {
				if inc.BalanceInfo == nil {
					inc.BalanceInfo = &DebitInfo{}
				}
				inc.BalanceInfo.AccountID = ub.ID
			}
		}
		cc.Timespans = append(cc.Timespans, leftCC.Timespans...)
	}

	if leftCC.Cost > 0 && goNegative {
		initialLength := len(cc.Timespans)
		cc.Timespans = append(cc.Timespans, leftCC.Timespans...)
		if initialLength == 0 {
			// this is the first add, debit the connect fee
			ub.DebitConnectionFee(cc, usefulMoneyBalances, count, true)
		}
		//log.Printf("Left CC: %+v ", leftCC)
		// get the default money balanance
		// and go negative on it with the amount still unpaid
		if len(leftCC.Timespans) > 0 && leftCC.Cost > 0 && !ub.AllowNegative && !dryRun {
			utils.Logger.Err(fmt.Sprintf("<Rater> Going negative on account %s with AllowNegative: false", cd.GetAccountKey()))
		}
		leftCC.Timespans.Decompress()
		for _, ts := range leftCC.Timespans {
			if ts.Increments == nil {
				ts.createIncrementsSlice()
			}
			for _, increment := range ts.Increments {
				cost := increment.Cost
				defaultBalance := ub.GetDefaultMoneyBalance()
				defaultBalance.SubstractValue(cost)
				increment.BalanceInfo.Monetary = &MonetaryInfo{
					UUID:  defaultBalance.Uuid,
					ID:    defaultBalance.ID,
					Value: defaultBalance.Value,
				}
				increment.BalanceInfo.AccountID = ub.ID
				increment.paid = true
				if count {
					ub.countUnits(
						cost,
						utils.MONETARY,
						leftCC,
						&Balance{
							Directions:     utils.StringMap{leftCC.Direction: true},
							Value:          cost,
							DestinationIDs: utils.NewStringMap(leftCC.Destination),
						})
				}
			}
		}
	}

COMMIT:
	if !dryRun {
		// save darty shared balances
		usefulMoneyBalances.SaveDirtyBalances(ub)
		usefulUnitBalances.SaveDirtyBalances(ub)
	}
	//log.Printf("Final CC: %+v", cc)
	return
}