diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index a374c91c9..40bd8e346 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -78,7 +78,7 @@ func (self *ApierV1) RemActionTiming(attrs AttrRemActionTiming, reply *string) e return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } } - _, err := engine.AccLock.Guard(engine.ACTION_TIMING_PREFIX, func() (float64, error) { // ToDo: Expand the scheduler to consider the locks also + _, err := engine.AccLock.Guard(engine.ACTION_TIMING_PREFIX, func() (float64, error) { ats, err := self.AccountDb.GetActionTimings(attrs.ActionTimingsId) if err != nil { return 0, err @@ -154,3 +154,73 @@ func (self *ApierV1) RemAccountActionTriggers(attrs AttrRemAcntActionTriggers, r *reply = OK return nil } + + +type AttrSetAccount struct { + Tenant string + Direction string + Account string + Type string // <*prepaid|*postpaid> + ActionTimingsId string +} + +// Ads a new account into dataDb. If already defined, returns success. +func (self *ApierV1) SetAccount(attr AttrSetAccount, reply *string) error { + if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Direction", "Account"}); len(missing) != 0 { + return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) + } + balanceId := utils.BalanceKey(attr.Tenant, attr.Account, attr.Direction) + var ub *engine.UserBalance + var ats engine.ActionTimings + _, err := engine.AccLock.Guard(balanceId, func() (float64, error) { + if bal, _ := self.AccountDb.GetUserBalance(balanceId); bal != nil { + ub = bal + } else { // Not found in db, create it here + if len(attr.Type) == 0 { + attr.Type = engine.UB_TYPE_PREPAID + } else if !utils.IsSliceMember([]string{engine.UB_TYPE_POSTPAID, engine.UB_TYPE_PREPAID}, attr.Type) { + return 0, fmt.Errorf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, "Type") + } + ub = &engine.UserBalance{ + Id: balanceId, + Type: attr.Type, + } + } + + if len(attr.ActionTimingsId) != 0 { + var err error + ats, err = self.AccountDb.GetActionTimings(attr.ActionTimingsId) + if err != nil { + return 0, err + } + for _, at := range ats { + at.UserBalanceIds = append(at.UserBalanceIds, balanceId) + } + } + // All prepared, save account + if err := self.AccountDb.SetUserBalance(ub); err != nil { + return 0, err + } + return 0, nil + }) + if err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + if len(ats) != 0 { + _, err := engine.AccLock.Guard(engine.ACTION_TIMING_PREFIX, func() (float64, error) { // ToDo: Try locking it above on read somehow + if err := self.AccountDb.SetActionTimings(attr.ActionTimingsId, ats); err != nil { + return 0, err + } + return 0, nil + }) + if err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + if self.Sched != nil { + self.Sched.LoadActionTimings(self.AccountDb) + self.Sched.Restart() + } + } + *reply = OK // This will mark saving of the account, error still can show up in actionTimingsId + return nil +} diff --git a/apier/v1/apier.go b/apier/v1/apier.go index b337c3410..0fb805ece 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -403,49 +403,6 @@ func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string return nil } -type AttrAddAccount struct { - Tenant string - Direction string - Account string - Type string // prepaid-postpaid - ActionTimingsId string -} - -// Ads a new account into dataDb. If already defined, returns success. -func (self *ApierV1) AddAccount(attr AttrAddAccount, reply *string) error { - if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Direction", "Account", "Type", "ActionTimingsId"}); len(missing) != 0 { - return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) - } - tag := utils.BalanceKey(attr.Tenant, attr.Account, attr.Direction) - ub := &engine.UserBalance{ - Id: tag, - Type: attr.Type, - } - - if attr.ActionTimingsId != "" { - if ats, err := self.AccountDb.GetActionTimings(attr.ActionTimingsId); err == nil { - for _, at := range ats { - engine.Logger.Debug(fmt.Sprintf("Found action timings: %v", at)) - at.UserBalanceIds = append(at.UserBalanceIds, tag) - } - err = self.AccountDb.SetActionTimings(attr.ActionTimingsId, ats) - if err != nil { - if self.Sched != nil { - self.Sched.LoadActionTimings(self.AccountDb) - self.Sched.Restart() - } - } - if err := self.AccountDb.SetUserBalance(ub); err != nil { - return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) - } - } else { - return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) - } - } - *reply = OK - return nil -} - // Process dependencies and load a specific AccountActions profile from storDb into dataDb. func (self *ApierV1) LoadAccountActions(attrs utils.TPAccountActions, reply *string) error { if missing := utils.MissingStructFields(&attrs, []string{"TPid", "LoadId", "Tenant", "Account", "Direction"}); len(missing) != 0 { diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 71e9b2255..bc9a86f51 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -1062,35 +1062,36 @@ func TestApierRemAccountActionTriggers(t *testing.T) { } -// Test here AddAccount -func TestApierAddAccount(t *testing.T) { - if !*testLocal { - return - } - reply := "" - attrs := &AttrAddAccount{Tenant: "cgrates.org", Direction: "*out", Account: "dan4", Type: "prepaid", ActionTimingsId: "ATMS_1"} - if err := rater.Call("ApierV1.AddAccount", attrs, &reply); err != nil { - t.Error("Got error on ApierV1.AddAccount: ", err.Error()) - } else if reply != "OK" { - t.Errorf("Calling ApierV1.AddAccount received: %s", reply) - } - reply2 := "" - attrs2 := new(AttrAddAccount) - *attrs2 = *attrs - attrs2.ActionTimingsId = "DUMMY_DATA" // Does not exist so it should error when adding triggers on it - // Add account with actions timing which does not exist - if err := rater.Call("ApierV1.AddAccount", attrs2, &reply2); err == nil || reply2 == "OK" { - t.Error("Expecting error on ApierV1.AddAccount.", err, reply2) - } +// Test here SetAccount +func TestApierSetAccount(t *testing.T) { + if !*testLocal { + return + } + reply := "" + attrs := &AttrSetAccount{Tenant: "cgrates.org", Direction: "*out", Account: "dan7", Type: "*prepaid", ActionTimingsId: "ATMS_1"} + if err := rater.Call("ApierV1.SetAccount", attrs, &reply); err != nil { + t.Error("Got error on ApierV1.SetAccount: ", err.Error()) + } else if reply != "OK" { + t.Errorf("Calling ApierV1.SetAccount received: %s", reply) + } + reply2 := "" + attrs2 := new(AttrSetAccount) + *attrs2 = *attrs + attrs2.ActionTimingsId = "DUMMY_DATA" // Does not exist so it should error when adding triggers on it + // Add account with actions timing which does not exist + if err := rater.Call("ApierV1.SetAccount", attrs2, &reply2); err == nil || reply2 == "OK" { // OK is not welcomed + t.Error("Expecting error on ApierV1.SetAccount.", err, reply2) + } } + // Test here GetAccountActionTimings func TestApierGetAccountActionTimings(t *testing.T) { if !*testLocal { return } var reply []*AccountActionTiming - req := AttrAcntAction{Tenant: "cgrates.org", Account:"dan4", Direction: "*out"} + req := AttrAcntAction{Tenant: "cgrates.org", Account:"dan7", Direction: "*out"} if err := rater.Call("ApierV1.GetAccountActionTimings", req, &reply); err != nil { t.Error("Got error on ApierV1.GetAccountActionTimings: ", err.Error()) } else if len(reply) != 1 { diff --git a/console/add_account.go b/console/add_account.go index 85ce27d52..ade30f214 100644 --- a/console/add_account.go +++ b/console/add_account.go @@ -30,7 +30,7 @@ func init() { // Commander implementation type CmdAddAccount struct { rpcMethod string - rpcParams *apier.AttrAddAccount + rpcParams *apier.AttrSetAccount rpcResult string } @@ -41,8 +41,8 @@ func (self *CmdAddAccount) Usage(name string) string { // set param defaults func (self *CmdAddAccount) defaults() error { - self.rpcMethod = "ApierV1.AddAccount" - self.rpcParams = &apier.AttrAddAccount{Direction: "*out"} + self.rpcMethod = "ApierV1.SetAccount" + self.rpcParams = &apier.AttrSetAccount{Direction: "*out"} return nil } diff --git a/docs/apicalls.rst b/docs/apicalls.rst index 0b6b94fdd..51e77717e 100644 --- a/docs/apicalls.rst +++ b/docs/apicalls.rst @@ -326,21 +326,21 @@ AddTriggeredAction Example AddTriggeredAction(attr \*AttrAddActionTrigger, reply \*float64) -AddAcount +SetAcount +++++++++ :: - type AttrAddAccount struct { + type AttrSetAccount struct { Tenant string Direction string Account string - Type string // prepaid-postpaid + Type string // <*prepaid|*postpaid> ActionTimingsId string } Example - AddAccount(attr \*AttrAddAccount, reply \*float64) + AddAccount(attr \*AttrAddAccount, reply \*string)