mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-12 02:26:26 +05:00
value formula passing test
This commit is contained in:
@@ -426,7 +426,7 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st
|
||||
Uuid: attr.BalanceUuid,
|
||||
ID: attr.BalanceId,
|
||||
Type: utils.StringPointer(attr.BalanceType),
|
||||
Value: &engine.ValueFormula{Static: attr.Value},
|
||||
Value: &utils.ValueFormula{Static: attr.Value},
|
||||
ExpirationDate: expTime,
|
||||
RatingSubject: attr.RatingSubject,
|
||||
Weight: attr.Weight,
|
||||
@@ -522,7 +522,7 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error {
|
||||
},
|
||||
}
|
||||
if attr.Value != nil {
|
||||
a.Balance.Value = &engine.ValueFormula{Static: *attr.Value}
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *attr.Value}
|
||||
}
|
||||
if attr.Directions != nil {
|
||||
a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
|
||||
@@ -582,7 +582,7 @@ func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error {
|
||||
},
|
||||
}
|
||||
if attr.Value != nil {
|
||||
a.Balance.Value = &engine.ValueFormula{Static: *attr.Value}
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *attr.Value}
|
||||
}
|
||||
if attr.Directions != nil {
|
||||
a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
|
||||
|
||||
@@ -504,9 +504,9 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error
|
||||
}
|
||||
storeActions := make(engine.Actions, len(attrs.Actions))
|
||||
for idx, apiAct := range attrs.Actions {
|
||||
var vf *engine.ValueFormula
|
||||
var vf *utils.ValueFormula
|
||||
if apiAct.Units != "" {
|
||||
if x, err := engine.ParseBalanceFilterValue(apiAct.Units); err == nil {
|
||||
if x, err := utils.ParseBalanceFilterValue(apiAct.Units); err == nil {
|
||||
vf = x
|
||||
} else {
|
||||
return err
|
||||
|
||||
@@ -482,7 +482,7 @@ func (mig MigratorRC8) migrateActions() error {
|
||||
bf.Type = utils.StringPointer(oldAc.BalanceType)
|
||||
}
|
||||
if oldAc.Balance.Value != 0 {
|
||||
bf.Value = &engine.ValueFormula{Static: oldAc.Balance.Value}
|
||||
bf.Value = &utils.ValueFormula{Static: oldAc.Balance.Value}
|
||||
}
|
||||
if oldAc.Balance.RatingSubject != "" {
|
||||
bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject)
|
||||
|
||||
@@ -364,7 +364,7 @@ func (mig MigratorRC8) migrateActionsInt() error {
|
||||
bf.Type = utils.StringPointer(oldAc.BalanceType)
|
||||
}
|
||||
if oldAc.Balance.Value != 0 {
|
||||
bf.Value = &engine.ValueFormula{Static: oldAc.Balance.Value}
|
||||
bf.Value = &utils.ValueFormula{Static: oldAc.Balance.Value}
|
||||
}
|
||||
if oldAc.Balance.RatingSubject != "" {
|
||||
bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject)
|
||||
|
||||
@@ -170,6 +170,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error {
|
||||
return errors.New("nil action")
|
||||
}
|
||||
bClone := a.Balance.CreateBalance()
|
||||
//log.Print("Bclone: ", utils.ToJSON(a.Balance))
|
||||
if bClone == nil {
|
||||
return errors.New("nil balance")
|
||||
}
|
||||
|
||||
@@ -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: &ValueFormula{Static: -10},
|
||||
Value: &utils.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: &ValueFormula{Static: -10},
|
||||
Value: &utils.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: &ValueFormula{Static: -10},
|
||||
Value: &utils.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: &ValueFormula{Static: -10},
|
||||
Value: &utils.ValueFormula{Static: -10},
|
||||
Type: utils.StringPointer(utils.VOICE),
|
||||
DestinationIDs: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
|
||||
@@ -291,7 +291,6 @@ func (at *ActionTiming) Execute() (err error) {
|
||||
transactionFailed := false
|
||||
removeAccountActionFound := false
|
||||
for _, a := range aac {
|
||||
//log.Print("A: ", utils.ToJSON(a))
|
||||
// check action filter
|
||||
if len(a.Filter) > 0 {
|
||||
matched, err := acc.matchActionFilter(a.Filter)
|
||||
|
||||
@@ -413,7 +413,7 @@ func TestActionPlanLogFunction(t *testing.T) {
|
||||
ActionType: "*log",
|
||||
Balance: &BalanceFilter{
|
||||
Type: utils.StringPointer("test"),
|
||||
Value: &ValueFormula{Static: 1.1},
|
||||
Value: &utils.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: &ValueFormula{Static: 1.1},
|
||||
Value: &utils.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: &ValueFormula{Static: 2},
|
||||
Value: &utils.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: &ValueFormula{Static: 2},
|
||||
Value: &utils.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: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
|
||||
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.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: &ValueFormula{Static: 10},
|
||||
Value: &utils.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: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
|
||||
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: &utils.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: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
|
||||
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.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: &ValueFormula{Static: 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: &utils.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: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
|
||||
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.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: &ValueFormula{Static: 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: &utils.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: &ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
|
||||
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.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: &ValueFormula{Static: 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: &utils.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: &ValueFormula{Static: 10}}}
|
||||
a := &Action{Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 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: &utils.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: &ValueFormula{Static: 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: &utils.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: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
},
|
||||
&Action{
|
||||
ActionType: DEBIT_RESET,
|
||||
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
},
|
||||
&Action{
|
||||
ActionType: DEBIT_RESET,
|
||||
Balance: &BalanceFilter{Value: &ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)},
|
||||
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)},
|
||||
},
|
||||
&Action{
|
||||
ActionType: "VALID_FUNCTION_TYPE",
|
||||
Balance: &BalanceFilter{Value: &ValueFormula{Static: 1.1}, Type: utils.StringPointer("test")},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.VOICE)},
|
||||
Balance: &BalanceFilter{Value: &utils.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: &ValueFormula{Static: 15},
|
||||
Value: &utils.ValueFormula{Static: 15},
|
||||
},
|
||||
},
|
||||
&Action{
|
||||
ActionType: TOPUP,
|
||||
Balance: &BalanceFilter{
|
||||
Type: utils.StringPointer(utils.VOICE),
|
||||
Value: &ValueFormula{Static: 30},
|
||||
Value: &utils.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: &ValueFormula{Static: 11},
|
||||
Value: &utils.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: &ValueFormula{Static: 11},
|
||||
Value: &utils.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: &ValueFormula{Static: 11},
|
||||
Value: &utils.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: &ValueFormula{Static: 11},
|
||||
Value: &utils.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: &ValueFormula{Static: 1.1},
|
||||
Value: &utils.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: &ValueFormula{Static: 2.1},
|
||||
Value: &utils.ValueFormula{Static: 2.1},
|
||||
Type: utils.StringPointer(utils.MONETARY),
|
||||
},
|
||||
},
|
||||
@@ -2222,6 +2222,22 @@ func TestCgrRpcAction(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueFormulaDebit(t *testing.T) {
|
||||
if _, err := accountingStorage.GetAccount("cgrates.org:vf"); err != nil {
|
||||
t.Errorf("account to be removed not found: %v", err)
|
||||
}
|
||||
|
||||
at := &ActionTiming{
|
||||
accountIDs: utils.StringMap{"cgrates.org:vf": true},
|
||||
ActionsID: "VF",
|
||||
}
|
||||
at.Execute()
|
||||
afterUb, err := accountingStorage.GetAccount("cgrates.org:vf")
|
||||
if err != nil || afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != -0.333334 {
|
||||
t.Error("error debiting account: ", err, utils.ToIJSON(afterUb))
|
||||
}
|
||||
}
|
||||
|
||||
/**************** Benchmarks ********************************/
|
||||
|
||||
func BenchmarkUUID(b *testing.B) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
@@ -14,7 +11,7 @@ type BalanceFilter struct {
|
||||
Uuid *string
|
||||
ID *string
|
||||
Type *string
|
||||
Value *ValueFormula
|
||||
Value *utils.ValueFormula
|
||||
Directions *utils.StringMap
|
||||
ExpirationDate *time.Time
|
||||
Weight *float64
|
||||
@@ -61,7 +58,7 @@ func (bf *BalanceFilter) Clone() *BalanceFilter {
|
||||
*result.ID = *bf.ID
|
||||
}
|
||||
if bf.Value != nil {
|
||||
result.Value = new(ValueFormula)
|
||||
result.Value = new(utils.ValueFormula)
|
||||
*result.Value = *bf.Value
|
||||
}
|
||||
if bf.RatingSubject != nil {
|
||||
@@ -180,7 +177,7 @@ func (bp *BalanceFilter) GetValue() float64 {
|
||||
return bp.Value.Static
|
||||
}
|
||||
// calculate using formula
|
||||
formula, exists := valueFormulas[bp.Value.Method]
|
||||
formula, exists := utils.ValueFormulas[bp.Value.Method]
|
||||
if !exists {
|
||||
return 0.0
|
||||
}
|
||||
@@ -189,7 +186,7 @@ func (bp *BalanceFilter) GetValue() float64 {
|
||||
|
||||
func (bp *BalanceFilter) SetValue(v float64) {
|
||||
if bp.Value == nil {
|
||||
bp.Value = new(ValueFormula)
|
||||
bp.Value = new(utils.ValueFormula)
|
||||
}
|
||||
bp.Value.Static = v
|
||||
}
|
||||
@@ -334,37 +331,3 @@ 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
|
||||
}
|
||||
|
||||
@@ -41,12 +41,12 @@ func init() {
|
||||
|
||||
func populateDB() {
|
||||
ats := []*Action{
|
||||
&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"))}},
|
||||
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}}},
|
||||
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: &utils.ValueFormula{Static: 10}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
|
||||
}
|
||||
|
||||
ats1 := []*Action{
|
||||
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &ValueFormula{Static: 10}}, Weight: 10},
|
||||
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}}, Weight: 10},
|
||||
&Action{ActionType: "*reset_account", Weight: 20},
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ BLOCK_EMPTY,*topup,,,bfree,*monetary,*out,,,,,*unlimited,,20,10,false,false,10
|
||||
FILTER,*topup,,"{""*and"":[{""Value"":{""*lt"":0}},{""Id"":{""*eq"":""*default""}}]}",bfree,*monetary,*out,,,,,*unlimited,,20,10,false,false,10
|
||||
EXP,*topup,,,,*voice,*out,,,,,*monthly,*any,300,10,false,false,10
|
||||
NOEXP,*topup,,,,*voice,*out,,,,,*unlimited,*any,50,10,false,false,10
|
||||
VF,*debit,,,,*monetary,*out,,,,,*unlimited,*any,"{""Method"":""*periodic"",""Params"":{""Units"":10, ""Interval"":""month"", ""Increment"":""day""}}",10,false,false,10
|
||||
`
|
||||
actionPlans = `
|
||||
MORE_MINUTES,MINI,ONE_TIME_RUN,10
|
||||
@@ -223,6 +224,7 @@ cgrates.org,block,BLOCK_AT,,false,false
|
||||
cgrates.org,block_empty,BLOCK_EMPTY_AT,,false,false
|
||||
cgrates.org,expo,EXP_AT,,false,false
|
||||
cgrates.org,expnoexp,,,false,false
|
||||
cgrates.org,vf,,,false,false
|
||||
`
|
||||
|
||||
derivedCharges = `
|
||||
@@ -825,7 +827,7 @@ func TestLoadRatingProfiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActions(t *testing.T) {
|
||||
if len(csvr.actions) != 14 {
|
||||
if len(csvr.actions) != 15 {
|
||||
t.Error("Failed to load actions: ", len(csvr.actions))
|
||||
}
|
||||
as1 := csvr.actions["MINI"]
|
||||
@@ -840,7 +842,7 @@ func TestLoadActions(t *testing.T) {
|
||||
Type: utils.StringPointer(utils.MONETARY),
|
||||
Uuid: as1[0].Balance.Uuid,
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
Value: &ValueFormula{Static: 10},
|
||||
Value: &utils.ValueFormula{Static: 10},
|
||||
Weight: utils.Float64Pointer(10),
|
||||
DestinationIDs: nil,
|
||||
TimingIDs: nil,
|
||||
@@ -860,7 +862,7 @@ func TestLoadActions(t *testing.T) {
|
||||
Type: utils.StringPointer(utils.VOICE),
|
||||
Uuid: as1[1].Balance.Uuid,
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
Value: &ValueFormula{Static: 100},
|
||||
Value: &utils.ValueFormula{Static: 100},
|
||||
Weight: utils.Float64Pointer(10),
|
||||
RatingSubject: utils.StringPointer("test"),
|
||||
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
|
||||
@@ -887,7 +889,7 @@ func TestLoadActions(t *testing.T) {
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
DestinationIDs: nil,
|
||||
Uuid: as2[0].Balance.Uuid,
|
||||
Value: &ValueFormula{Static: 100},
|
||||
Value: &utils.ValueFormula{Static: 100},
|
||||
Weight: utils.Float64Pointer(10),
|
||||
SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")),
|
||||
TimingIDs: nil,
|
||||
@@ -1106,7 +1108,7 @@ func TestLoadActionTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadAccountActions(t *testing.T) {
|
||||
if len(csvr.accountActions) != 15 {
|
||||
if len(csvr.accountActions) != 16 {
|
||||
t.Error("Failed to load account actions: ", len(csvr.accountActions))
|
||||
}
|
||||
aa := csvr.accountActions["vdf:minitsboy"]
|
||||
|
||||
@@ -274,7 +274,7 @@ func TestDifferentUuid(t *testing.T) {
|
||||
|
||||
func TestStorageTask(t *testing.T) {
|
||||
// clean previous unused tasks
|
||||
for i := 0; i < 19; i++ {
|
||||
for i := 0; i < 20; i++ {
|
||||
ratingStorage.PopTask()
|
||||
}
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ func (tpr *TpReader) LoadActions() (err error) {
|
||||
}
|
||||
|
||||
if tpact.Units != "" && tpact.Units != utils.ANY {
|
||||
vf, err := ParseBalanceFilterValue(tpact.Units)
|
||||
vf, err := utils.ParseBalanceFilterValue(tpact.Units)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1007,7 +1007,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
|
||||
}
|
||||
|
||||
if tpact.Units != "" && tpact.Units != utils.ANY {
|
||||
vf, err := ParseBalanceFilterValue(tpact.Units)
|
||||
vf, err := utils.ParseBalanceFilterValue(tpact.Units)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1355,7 +1355,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
|
||||
}
|
||||
|
||||
if tpact.Units != "" && tpact.Units != utils.ANY {
|
||||
vf, err := ParseBalanceFilterValue(tpact.Units)
|
||||
vf, err := utils.ParseBalanceFilterValue(tpact.Units)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -277,3 +277,13 @@ func (wd WeekDays) Serialize(sep string) string {
|
||||
}
|
||||
return wdStr
|
||||
}
|
||||
|
||||
func DaysInMonth(year int, month time.Month) float64 {
|
||||
return float64(time.Date(year, month, 1, 0, 0, 0, 0, time.UTC).AddDate(0, 1, -1).Day())
|
||||
}
|
||||
|
||||
func DaysInYear(year int) float64 {
|
||||
first := time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
last := first.AddDate(1, 0, 0)
|
||||
return float64(last.Sub(first).Hours() / 24)
|
||||
}
|
||||
|
||||
@@ -161,3 +161,30 @@ func TestDateseriesMonthsIsCompleteYes(t *testing.T) {
|
||||
t.Error("Error months IsComplete: ", months)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateseriesDaysInMonth(t *testing.T) {
|
||||
if n := DaysInMonth(2016, 4); n != 30 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
if n := DaysInMonth(2016, 2); n != 29 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
if n := DaysInMonth(2016, 1); n != 31 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
if n := DaysInMonth(2016, 12); n != 31 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
if n := DaysInMonth(2015, 2); n != 28 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateseriesDaysInYear(t *testing.T) {
|
||||
if n := DaysInYear(2016); n != 366 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
if n := DaysInYear(2015); n != 365 {
|
||||
t.Error("error calculating days: ", n)
|
||||
}
|
||||
}
|
||||
|
||||
85
utils/value_formula.go
Normal file
85
utils/value_formula.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
//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
|
||||
if err := json.Unmarshal([]byte(val), &vf); 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 {
|
||||
// check parameters
|
||||
unitsInterface, unitsFound := params["Units"]
|
||||
intervalInterface, intervalFound := params["Interval"]
|
||||
incrementInterface, incrementFound := params["Increment"]
|
||||
|
||||
if !unitsFound || !intervalFound || !incrementFound {
|
||||
return 0.0
|
||||
}
|
||||
units, ok := unitsInterface.(float64)
|
||||
if !ok {
|
||||
log.Print("units")
|
||||
return 0.0
|
||||
}
|
||||
var interval string
|
||||
switch intr := intervalInterface.(type) {
|
||||
case string:
|
||||
interval = intr
|
||||
case []byte:
|
||||
interval = string(intr)
|
||||
default:
|
||||
return 0.0
|
||||
}
|
||||
var increment string
|
||||
switch incr := incrementInterface.(type) {
|
||||
case string:
|
||||
increment = incr
|
||||
case []byte:
|
||||
increment = string(incr)
|
||||
default:
|
||||
return 0.0
|
||||
}
|
||||
now := time.Now()
|
||||
if increment == "day" {
|
||||
if interval == "week" {
|
||||
return units / 7
|
||||
}
|
||||
if interval == "month" {
|
||||
return units / DaysInMonth(now.Year(), now.Month())
|
||||
}
|
||||
if interval == "year" {
|
||||
return units / DaysInYear(now.Year())
|
||||
}
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
39
utils/value_formula_test.go
Normal file
39
utils/value_formula_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestValueFormulaDayWeek(t *testing.T) {
|
||||
params := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(`{"Units":10, "Interval":"week", "Increment":"day"}`), ¶ms); err != nil {
|
||||
t.Error("error unmarshalling params: ", err)
|
||||
}
|
||||
if x := periodicFormula(params); x != 10/7.0 {
|
||||
t.Error("error caclulating value using formula: ", x)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueFormulaDayMonth(t *testing.T) {
|
||||
params := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(`{"Units":10, "Interval":"month", "Increment":"day"}`), ¶ms); err != nil {
|
||||
t.Error("error unmarshalling params: ", err)
|
||||
}
|
||||
now := time.Now()
|
||||
if x := periodicFormula(params); x != 10/DaysInMonth(now.Year(), now.Month()) {
|
||||
t.Error("error caclulating value using formula: ", x)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueFormulaDayYear(t *testing.T) {
|
||||
params := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(`{"Units":10, "Interval":"year", "Increment":"day"}`), ¶ms); err != nil {
|
||||
t.Error("error unmarshalling params: ", err)
|
||||
}
|
||||
now := time.Now()
|
||||
if x := periodicFormula(params); x != 10/DaysInYear(now.Year()) {
|
||||
t.Error("error caclulating value using formula: ", x)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user