From c5fb456ea93591df04b875df3f382530d2ccead8 Mon Sep 17 00:00:00 2001 From: TeoV Date: Thu, 28 Mar 2019 12:39:01 +0200 Subject: [PATCH] Add ExtraData in Add/Set/Modify Balance API's fixes #1463 --- apier/v1/accounts.go | 13 ++++++++ apier/v1/accounts_it_test.go | 60 ++++++++++++++++++++++++++++++++++++ engine/action.go | 19 ++++++++++-- utils/apitpdata.go | 1 + 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index 0e8918abe..bdb70b444 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -421,6 +421,7 @@ type AttrAddBalance struct { Blocker *bool Disabled *bool Cdrlog *bool + ExtraData *map[string]interface{} } func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { @@ -456,6 +457,10 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st } } at := &engine.ActionTiming{} + //check if we have extra data + if attr.ExtraData != nil && len(*attr.ExtraData) != 0 { + at.ExtraData = *attr.ExtraData + } at.SetAccountIDs(utils.StringMap{accID: true}) if attr.Overwrite { @@ -534,6 +539,10 @@ func (self *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) error } } at := &engine.ActionTiming{} + //check if we have extra data + if attr.ExtraData != nil && len(*attr.ExtraData) != 0 { + at.ExtraData = *attr.ExtraData + } at.SetAccountIDs(utils.StringMap{accID: true}) a := &engine.Action{ @@ -601,6 +610,10 @@ func (self *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) e } at := &engine.ActionTiming{} + //check if we have extra data + if attr.ExtraData != nil && len(*attr.ExtraData) != 0 { + at.ExtraData = *attr.ExtraData + } at.SetAccountIDs(utils.StringMap{accID: true}) a := &engine.Action{ ActionType: engine.REMOVE_BALANCE, diff --git a/apier/v1/accounts_it_test.go b/apier/v1/accounts_it_test.go index 9b72dd47e..c0d4b6c5c 100644 --- a/apier/v1/accounts_it_test.go +++ b/apier/v1/accounts_it_test.go @@ -50,6 +50,8 @@ var ( testAccITDebitBalance, testAccITAddBalance, testAccITSetBalance, + testAccITSetBalanceWithExtraData, + testAccITSetBalanceWithExtraData2, testAccITStopCgrEngine, } ) @@ -223,6 +225,64 @@ func testAccITSetBalance(t *testing.T) { } } +func testAccITSetBalanceWithExtraData(t *testing.T) { + extraDataMap := map[string]interface{}{ + "ExtraField": "ExtraValue", + "ExtraField2": "RandomValue", + } + var reply string + attrs := &AttrAddBalance{Tenant: "cgrates.org", Account: "testAccITSetBalanceWithExtraData", + BalanceId: utils.StringPointer("testAccITSetBalanceWithExtraData"), + BalanceType: "*monetary", Value: 1.5, Cdrlog: utils.BoolPointer(true), + ExtraData: &extraDataMap} + if err := accRPC.Call("ApierV1.SetBalance", attrs, &reply); err != nil { + t.Error("Got error on ApierV1.SetBalance: ", err.Error()) + } else if reply != "OK" { + t.Errorf("Calling ApierV1.SetBalance received: %s", reply) + } + time.Sleep(50 * time.Millisecond) + // verify the cdr from CdrLog + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Sources: []string{engine.CDRLOG}, Accounts: []string{"testAccITSetBalanceWithExtraData"}} + if err := accRPC.Call(utils.ApierV2GetCDRs, req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else if len(cdrs[0].ExtraFields) != 2 { + t.Error("Unexpected number of ExtraFields returned: ", len(cdrs[0].ExtraFields)) + } +} + +func testAccITSetBalanceWithExtraData2(t *testing.T) { + extraDataMap := map[string]interface{}{ + "ExtraField": "ExtraValue", + "ActionVal": "~ActionValue", + } + var reply string + attrs := &AttrAddBalance{Tenant: "cgrates.org", Account: "testAccITSetBalanceWithExtraData2", + BalanceId: utils.StringPointer("testAccITSetBalanceWithExtraData2"), + BalanceType: "*monetary", Value: 1.5, Cdrlog: utils.BoolPointer(true), + ExtraData: &extraDataMap} + if err := accRPC.Call("ApierV1.SetBalance", attrs, &reply); err != nil { + t.Error("Got error on ApierV1.SetBalance: ", err.Error()) + } else if reply != "OK" { + t.Errorf("Calling ApierV1.SetBalance received: %s", reply) + } + time.Sleep(50 * time.Millisecond) + // verify the cdr from CdrLog + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Sources: []string{engine.CDRLOG}, Accounts: []string{"testAccITSetBalanceWithExtraData2"}} + if err := accRPC.Call(utils.ApierV2GetCDRs, req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else if len(cdrs[0].ExtraFields) != 2 { + t.Error("Unexpected number of ExtraFields returned: ", len(cdrs[0].ExtraFields)) + } else if cdrs[0].ExtraFields["ActionVal"] != 1.5 { + t.Error("Unexpected value of ExtraFields[ActionVal] returned: ", cdrs[0].ExtraFields["ActionVal"]) + } +} + func testAccITStopCgrEngine(t *testing.T) { if err := engine.KillEngine(100); err != nil { t.Error(err) diff --git a/engine/action.go b/engine/action.go index ed69ab31e..719c7f916 100644 --- a/engine/action.go +++ b/engine/action.go @@ -166,10 +166,25 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, extraData interface{}) ( return } for field, rsr := range template { - defaultTemplate[field] = config.NewRSRParsersMustCompile(rsr, - true, config.CgrConfig().GeneralCfg().RsrSepatarot) + if defaultTemplate[field], err = config.NewRSRParsers(rsr, + true, config.CgrConfig().GeneralCfg().RsrSepatarot); err != nil { + return + } } } + //In case that we have extra data we populate default templates + mapExtraData, _ := extraData.(map[string]interface{}) + var strVal string + for key, val := range mapExtraData { + if strVal, err = utils.IfaceAsString(val); err != nil { + return + } + if defaultTemplate[key], err = config.NewRSRParsers(strVal, + true, config.CgrConfig().GeneralCfg().RsrSepatarot); err != nil { + return + } + } + // set stored cdr values var cdrs []*CDR for _, action := range acs { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 49cf640c9..b6ced0f7b 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -983,6 +983,7 @@ type AttrSetBalance struct { Blocker *bool Disabled *bool Cdrlog *bool + ExtraData *map[string]interface{} } // TPResourceProfile is used in APIs to manage remotely offline ResourceProfile