started value formula

This commit is contained in:
Radu Ioan Fericean
2016-04-21 20:35:48 +03:00
parent e1d8d96402
commit b16cc28389
15 changed files with 149 additions and 127 deletions

View File

@@ -127,7 +127,7 @@ func (acc *Account) setBalanceAction(a *Action) error {
if a.Balance.ID != nil && *a.Balance.ID == utils.META_DEFAULT {
balance.ID = utils.META_DEFAULT
if a.Balance.Value != nil {
balance.Value = *a.Balance.Value
balance.Value = a.Balance.GetValue()
}
} else {
a.Balance.ModifyBalance(balance)

View File

@@ -856,7 +856,7 @@ func TestAccountdebitBalanceExists(t *testing.T) {
BalanceMap: map[string]Balances{utils.SMS: Balances{&Balance{Value: 14}}, utils.DATA: Balances{&Balance{Value: 1024}}, utils.VOICE: Balances{&Balance{Value: 15, Weight: 20, DestinationIDs: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.StringMap{"RET": true}}}},
}
newMb := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Value: &ValueFormula{Static: -10},
Type: utils.StringPointer(utils.VOICE),
Weight: utils.Float64Pointer(20),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
@@ -883,19 +883,19 @@ func TestAccountAddMinuteNil(t *testing.T) {
func TestAccountAddMinutBucketEmpty(t *testing.T) {
mb1 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Value: &ValueFormula{Static: -10},
Type: utils.StringPointer(utils.VOICE),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb2 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Value: &ValueFormula{Static: -10},
Type: utils.StringPointer(utils.VOICE),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb3 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Value: &ValueFormula{Static: -10},
Type: utils.StringPointer(utils.VOICE),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),

View File

@@ -93,59 +93,36 @@ func (a *Action) Clone() *Action {
type actionTypeFunc func(*Account, *StatsQueueTriggered, *Action, Actions) error
func getActionFunc(typ string) (actionTypeFunc, bool) {
switch typ {
case LOG:
return logAction, true
case CDRLOG:
return cdrLogAction, true
case RESET_TRIGGERS:
return resetTriggersAction, true
case SET_RECURRENT:
return setRecurrentAction, true
case UNSET_RECURRENT:
return unsetRecurrentAction, true
case ALLOW_NEGATIVE:
return allowNegativeAction, true
case DENY_NEGATIVE:
return denyNegativeAction, true
case RESET_ACCOUNT:
return resetAccountAction, true
case TOPUP_RESET:
return topupResetAction, true
case TOPUP:
return topupAction, true
case DEBIT_RESET:
return debitResetAction, true
case DEBIT:
return debitAction, true
case RESET_COUNTERS:
return resetCountersAction, true
case ENABLE_ACCOUNT:
return enableUserAction, true
case DISABLE_ACCOUNT:
return disableUserAction, true
//case ENABLE_DISABLE_BALANCE:
// return enableDisableBalanceAction, true
case CALL_URL:
return callUrl, true
case CALL_URL_ASYNC:
return callUrlAsync, true
case MAIL_ASYNC:
return mailAsync, true
case SET_DDESTINATIONS:
return setddestinations, true
case REMOVE_ACCOUNT:
return removeAccountAction, true
case REMOVE_BALANCE:
return removeBalanceAction, true
case SET_BALANCE:
return setBalanceAction, true
case TRANSFER_MONETARY_DEFAULT:
return transferMonetaryDefaultAction, true
case CGR_RPC:
return cgrRPCAction, true
actionFuncMap := map[string]actionTypeFunc{
LOG: logAction,
CDRLOG: cdrLogAction,
RESET_TRIGGERS: resetTriggersAction,
SET_RECURRENT: setRecurrentAction,
UNSET_RECURRENT: unsetRecurrentAction,
ALLOW_NEGATIVE: allowNegativeAction,
DENY_NEGATIVE: denyNegativeAction,
RESET_ACCOUNT: resetAccountAction,
TOPUP_RESET: topupResetAction,
TOPUP: topupAction,
DEBIT_RESET: debitResetAction,
DEBIT: debitAction,
RESET_COUNTERS: resetCountersAction,
ENABLE_ACCOUNT: enableUserAction,
DISABLE_ACCOUNT: disableUserAction,
//case ENABLE_DISABLE_BALANCE:
// return enableDisableBalanceAction, true
CALL_URL: callUrl,
CALL_URL_ASYNC: callUrlAsync,
MAIL_ASYNC: mailAsync,
SET_DDESTINATIONS: setddestinations,
REMOVE_ACCOUNT: removeAccountAction,
REMOVE_BALANCE: removeBalanceAction,
SET_BALANCE: setBalanceAction,
TRANSFER_MONETARY_DEFAULT: transferMonetaryDefaultAction,
CGR_RPC: cgrRPCAction,
}
return nil, false
f, exists := actionFuncMap[typ]
return f, exists
}
func logAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) {

View File

@@ -413,7 +413,7 @@ func TestActionPlanLogFunction(t *testing.T) {
ActionType: "*log",
Balance: &BalanceFilter{
Type: utils.StringPointer("test"),
Value: utils.Float64Pointer(1.1),
Value: &ValueFormula{Static: 1.1},
},
}
at := &ActionTiming{
@@ -430,7 +430,7 @@ func TestActionPlanFunctionNotAvailable(t *testing.T) {
ActionType: "VALID_FUNCTION_TYPE",
Balance: &BalanceFilter{
Type: utils.StringPointer("test"),
Value: utils.Float64Pointer(1.1),
Value: &ValueFormula{Static: 1.1},
},
}
at := &ActionTiming{
@@ -659,7 +659,7 @@ func TestActionTriggerMatchAll(t *testing.T) {
Type: utils.StringPointer(utils.MONETARY),
RatingSubject: utils.StringPointer("test1"),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(2),
Value: &ValueFormula{Static: 2},
Weight: utils.Float64Pointer(1.0),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
@@ -669,7 +669,7 @@ func TestActionTriggerMatchAll(t *testing.T) {
Type: utils.StringPointer(utils.MONETARY),
RatingSubject: utils.StringPointer("test1"),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(2),
Value: &ValueFormula{Static: 2},
Weight: utils.Float64Pointer(1.0),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
@@ -799,7 +799,7 @@ func TestActionTopupResetCredit(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 10 ||
@@ -818,7 +818,7 @@ func TestActionTopupValueFactor(t *testing.T) {
a := &Action{
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(10),
Value: &ValueFormula{Static: 10},
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
},
ExtraParameters: `{"*monetary":2.0}`,
@@ -839,7 +839,7 @@ func TestActionTopupResetCreditId(t *testing.T) {
},
},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
@@ -858,7 +858,7 @@ func TestActionTopupResetCreditNoId(t *testing.T) {
},
},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 20 ||
@@ -876,7 +876,7 @@ func TestActionTopupResetMinutes(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 5 ||
@@ -895,7 +895,7 @@ func TestActionTopupCredit(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
@@ -913,7 +913,7 @@ func TestActionTopupMinutes(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 15 ||
@@ -932,7 +932,7 @@ func TestActionDebitCredit(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 90 ||
@@ -950,7 +950,7 @@ func TestActionDebitMinutes(t *testing.T) {
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 5 ||
@@ -1119,7 +1119,7 @@ func TestActionPlanLogging(t *testing.T) {
}
func TestActionMakeNegative(t *testing.T) {
a := &Action{Balance: &BalanceFilter{Value: utils.Float64Pointer(10)}}
a := &Action{Balance: &BalanceFilter{Value: &ValueFormula{Static: 10}}}
genericMakeNegative(a)
if a.Balance.GetValue() > 0 {
t.Error("Failed to make negative: ", a)
@@ -1153,7 +1153,7 @@ func TestTopupAction(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minu")
a := &Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1174,7 +1174,7 @@ func TestTopupActionLoaded(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minitsboy")
a := &Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1201,7 +1201,7 @@ func TestActionCdrlogEmpty(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1223,11 +1223,11 @@ func TestActionCdrlogWithParams(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1250,11 +1250,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1335,11 +1335,11 @@ func TestActionTransactionFuncType(t *testing.T) {
actions: []*Action{
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)},
},
&Action{
ActionType: "VALID_FUNCTION_TYPE",
Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer("test")},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 1.1}, Type: utils.StringPointer("test")},
},
},
}
@@ -1371,7 +1371,7 @@ func TestActionTransactionBalanceType(t *testing.T) {
actions: []*Action{
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.MONETARY)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)},
},
&Action{
ActionType: TOPUP,
@@ -1407,7 +1407,7 @@ func TestActionTransactionBalanceNotType(t *testing.T) {
actions: []*Action{
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.VOICE)},
Balance: &BalanceFilter{Value: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.VOICE)},
},
&Action{
ActionType: TOPUP,
@@ -1445,14 +1445,14 @@ func TestActionWithExpireWithoutExpire(t *testing.T) {
ActionType: TOPUP,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Value: utils.Float64Pointer(15),
Value: &ValueFormula{Static: 15},
},
},
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Value: utils.Float64Pointer(30),
Value: &ValueFormula{Static: 30},
ExpirationDate: utils.TimePointer(time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC)),
},
},
@@ -1672,7 +1672,7 @@ func TestActionConditionalTopup(t *testing.T) {
Filter: `{"Type":"*monetary","Value":1,"Weight":10}`,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Value: &ValueFormula{Static: 11},
Weight: utils.Float64Pointer(30),
},
}
@@ -1736,7 +1736,7 @@ func TestActionConditionalTopupNoMatch(t *testing.T) {
Filter: `{"Type":"*monetary","Value":2,"Weight":10}`,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Value: &ValueFormula{Static: 11},
Weight: utils.Float64Pointer(30),
},
}
@@ -1800,7 +1800,7 @@ func TestActionConditionalTopupExistingBalance(t *testing.T) {
Filter: `{"Type":"*voice","Value":{"*gte":100}}`,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Value: &ValueFormula{Static: 11},
Weight: utils.Float64Pointer(10),
},
}
@@ -2021,7 +2021,7 @@ func TestActionSetBalance(t *testing.T) {
Balance: &BalanceFilter{
ID: utils.StringPointer("m2"),
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Value: &ValueFormula{Static: 11},
Weight: utils.Float64Pointer(10),
},
}
@@ -2122,7 +2122,7 @@ func TestActionCdrlogBalanceValue(t *testing.T) {
Balance: &BalanceFilter{
ID: utils.StringPointer("*default"),
Uuid: utils.StringPointer("25a02c82-f09f-4c6e-bacf-8ed4b076475a"),
Value: utils.Float64Pointer(1.1),
Value: &ValueFormula{Static: 1.1},
Type: utils.StringPointer(utils.MONETARY),
},
},
@@ -2132,7 +2132,7 @@ func TestActionCdrlogBalanceValue(t *testing.T) {
Balance: &BalanceFilter{
ID: utils.StringPointer("*default"),
Uuid: utils.StringPointer("25a02c82-f09f-4c6e-bacf-8ed4b076475a"),
Value: utils.Float64Pointer(2.1),
Value: &ValueFormula{Static: 2.1},
Type: utils.StringPointer(utils.MONETARY),
},
},

View File

@@ -1,7 +1,10 @@
package engine
import (
"encoding/json"
"errors"
"reflect"
"strconv"
"time"
"github.com/cgrates/cgrates/utils"
@@ -11,7 +14,7 @@ type BalanceFilter struct {
Uuid *string
ID *string
Type *string
Value *float64
Value *ValueFormula
Directions *utils.StringMap
ExpirationDate *time.Time
Weight *float64
@@ -58,7 +61,7 @@ func (bf *BalanceFilter) Clone() *BalanceFilter {
*result.ID = *bf.ID
}
if bf.Value != nil {
result.Value = new(float64)
result.Value = new(ValueFormula)
*result.Value = *bf.Value
}
if bf.RatingSubject != nil {
@@ -116,7 +119,7 @@ func (bf *BalanceFilter) LoadFromBalance(b *Balance) *BalanceFilter {
bf.ID = &b.ID
}
if b.Value != 0 {
bf.Value = &b.Value
bf.Value.Static = b.Value
}
if !b.Directions.IsEmpty() {
bf.Directions = &b.Directions
@@ -173,14 +176,22 @@ func (bp *BalanceFilter) GetValue() float64 {
if bp == nil || bp.Value == nil {
return 0.0
}
return *bp.Value
if bp.Value.Method == "" {
return bp.Value.Static
}
// calculate using formula
formula, exists := valueFormulas[bp.Value.Method]
if !exists {
return 0.0
}
return formula(bp.Value.Params)
}
func (bp *BalanceFilter) SetValue(v float64) {
if bp.Value == nil {
bp.Value = new(float64)
bp.Value = new(ValueFormula)
}
*bp.Value = v
bp.Value.Static = v
}
func (bp *BalanceFilter) GetUuid() string {
@@ -292,7 +303,7 @@ func (bf *BalanceFilter) ModifyBalance(b *Balance) {
b.Directions = *bf.Directions
}
if bf.Value != nil {
b.Value = *bf.Value
b.Value = bf.GetValue()
}
if bf.ExpirationDate != nil {
b.ExpirationDate = *bf.ExpirationDate
@@ -323,3 +334,37 @@ func (bf *BalanceFilter) ModifyBalance(b *Balance) {
}
b.SetDirty() // Mark the balance as dirty since we have modified and it should be checked by action triggers
}
//for computing a dynamic value for Value field
type ValueFormula struct {
Method string
Params map[string]interface{}
Static float64
}
func ParseBalanceFilterValue(val string) (*ValueFormula, error) {
u, err := strconv.ParseFloat(val, 64)
if err == nil {
return &ValueFormula{Static: u}, err
}
var vf ValueFormula
err = json.Unmarshal([]byte(val), &vf)
if err == nil {
return &vf, err
}
return nil, errors.New("Invalid value: " + val)
}
type valueFormula func(map[string]interface{}) float64
const (
PERIODIC = "*periodic"
)
var valueFormulas = map[string]valueFormula{
PERIODIC: periodicFormula,
}
func periodicFormula(params map[string]interface{}) float64 {
return 0.0
}

View File

@@ -41,12 +41,12 @@ func init() {
func populateDB() {
ats := []*Action{
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}}},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: &ValueFormula{Static: 10}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
}
ats1 := []*Action{
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}, Weight: 10},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}}, Weight: 10},
&Action{ActionType: "*reset_account", Weight: 20},
}

View File

@@ -840,7 +840,7 @@ func TestLoadActions(t *testing.T) {
Type: utils.StringPointer(utils.MONETARY),
Uuid: as1[0].Balance.Uuid,
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(10),
Value: &ValueFormula{Static: 10},
Weight: utils.Float64Pointer(10),
DestinationIDs: nil,
TimingIDs: nil,
@@ -860,7 +860,7 @@ func TestLoadActions(t *testing.T) {
Type: utils.StringPointer(utils.VOICE),
Uuid: as1[1].Balance.Uuid,
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(100),
Value: &ValueFormula{Static: 100},
Weight: utils.Float64Pointer(10),
RatingSubject: utils.StringPointer("test"),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
@@ -873,7 +873,7 @@ func TestLoadActions(t *testing.T) {
},
}
if !reflect.DeepEqual(as1, expected) {
t.Errorf("Error loading action1: %+v", as1[0].Balance)
t.Errorf("Error loading action1: %s", utils.ToIJSON(as1))
}
as2 := csvr.actions["SHARED"]
expected = []*Action{
@@ -887,7 +887,7 @@ func TestLoadActions(t *testing.T) {
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIDs: nil,
Uuid: as2[0].Balance.Uuid,
Value: utils.Float64Pointer(100),
Value: &ValueFormula{Static: 100},
Weight: utils.Float64Pointer(10),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")),
TimingIDs: nil,
@@ -898,7 +898,7 @@ func TestLoadActions(t *testing.T) {
},
}
if !reflect.DeepEqual(as2, expected) {
t.Errorf("Error loading action: %+v", as2[0].Balance)
t.Errorf("Error loading action: %s", utils.ToIJSON(as2))
}
as3 := csvr.actions["DEFEE"]
expected = []*Action{

View File

@@ -531,11 +531,11 @@ func (tpr *TpReader) LoadActions() (err error) {
}
if tpact.Units != "" && tpact.Units != utils.ANY {
u, err := strconv.ParseFloat(tpact.Units, 64)
vf, err := ParseBalanceFilterValue(tpact.Units)
if err != nil {
return err
}
acts[idx].Balance.Value = utils.Float64Pointer(u)
acts[idx].Balance.Value = vf
}
if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY {
@@ -1007,11 +1007,11 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
}
if tpact.Units != "" && tpact.Units != utils.ANY {
u, err := strconv.ParseFloat(tpact.Units, 64)
vf, err := ParseBalanceFilterValue(tpact.Units)
if err != nil {
return err
}
acts[idx].Balance.Value = utils.Float64Pointer(u)
acts[idx].Balance.Value = vf
}
if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY {
@@ -1355,11 +1355,11 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
}
if tpact.Units != "" && tpact.Units != utils.ANY {
u, err := strconv.ParseFloat(tpact.Units, 64)
vf, err := ParseBalanceFilterValue(tpact.Units)
if err != nil {
return err
}
acts[idx].Balance.Value = utils.Float64Pointer(u)
acts[idx].Balance.Value = vf
}
if tpact.BalanceWeight != "" && tpact.BalanceWeight != utils.ANY {