Add APIAccountProfile struct + commands in cgr-console

This commit is contained in:
TeoV
2021-01-07 14:32:49 +02:00
committed by Dan Christian Bogos
parent d7d7a4f914
commit 9c32b2310a
12 changed files with 466 additions and 62 deletions

View File

@@ -138,7 +138,7 @@ func (cB *concreteBalance) debitUnits(dUnts *decimal.Big, incrm *decimal.Big,
hasUF = true
}
blcVal := new(decimal.Big).SetFloat64(cB.blnCfg.Units) // FixMe without float64
blcVal := cB.blnCfg.Units.Big
// balanceLimit
var hasLmt bool
@@ -166,6 +166,6 @@ func (cB *concreteBalance) debitUnits(dUnts *decimal.Big, incrm *decimal.Big,
if !ok {
return nil, nil, fmt.Errorf("failed representing decimal <%s> as float64", rmain)
}
cB.blnCfg.Units = rmainFlt64
cB.blnCfg.Units, err = utils.NewDecimalFromFloat64(rmainFlt64)
return
}

View File

@@ -41,7 +41,7 @@ func TestCBDebitUnits(t *testing.T) {
Factor: &utils.Decimal{decimal.New(100, 0)}, // EuroCents
},
},
Units: 500, // 500 EURcents
Units: &utils.Decimal{decimal.New(500, 0)}, // 500 EURcents
},
fltrS: new(engine.FilterS),
}
@@ -53,7 +53,7 @@ func TestCBDebitUnits(t *testing.T) {
t.Errorf("received unit factor: %+v", uFctr)
} else if dbted.Cmp(toDebit) != 0 {
t.Errorf("debited: %s", dbted)
} else if cb.blnCfg.Units != -100.0 {
} else if cb.blnCfg.Units.String() != "-100" {
t.Errorf("balance remaining: %f", cb.blnCfg.Units)
}
//with increment and not enough balance
@@ -64,7 +64,7 @@ func TestCBDebitUnits(t *testing.T) {
Opts: map[string]interface{}{
utils.MetaBalanceLimit: decimal.New(-1, 0),
},
Units: 1.25,
Units: &utils.Decimal{decimal.New(125, 2)},
},
fltrS: new(engine.FilterS),
}
@@ -75,7 +75,7 @@ func TestCBDebitUnits(t *testing.T) {
t.Error(err)
} else if dbted.Cmp(decimal.New(22, 1)) != 0 { // only 1.2 is possible due to increment
t.Errorf("debited: %s, cmp: %v", dbted, dbted.Cmp(new(decimal.Big).SetFloat64(1.2)))
} else if cb.blnCfg.Units != -0.95 {
} else if cb.blnCfg.Units.String() != "-0.95" {
t.Errorf("balance remaining: %f", cb.blnCfg.Units)
}
//with increment and unlimited balance
@@ -86,7 +86,7 @@ func TestCBDebitUnits(t *testing.T) {
Opts: map[string]interface{}{
utils.MetaBalanceUnlimited: true,
},
Units: 1.25,
Units: &utils.Decimal{decimal.New(125, 2)},
},
fltrS: new(engine.FilterS),
}
@@ -97,7 +97,7 @@ func TestCBDebitUnits(t *testing.T) {
t.Error(err)
} else if dbted.Cmp(decimal.New(25, 1)) != 0 { // only 1.2 is possible due to increment
t.Errorf("debited: %s, cmp: %v", dbted, dbted.Cmp(new(decimal.Big).SetFloat64(1.2)))
} else if cb.blnCfg.Units != -1.25 {
} else if cb.blnCfg.Units.String() != "-1.25" {
t.Errorf("balance remaining: %f", cb.blnCfg.Units)
}
//with increment and positive limit
@@ -108,7 +108,7 @@ func TestCBDebitUnits(t *testing.T) {
Opts: map[string]interface{}{
utils.MetaBalanceLimit: decimal.New(5, 1), // 0.5 as limit
},
Units: 1.25,
Units: &utils.Decimal{decimal.New(125, 2)},
},
fltrS: new(engine.FilterS),
}
@@ -119,7 +119,7 @@ func TestCBDebitUnits(t *testing.T) {
t.Error(err)
} else if dbted.Cmp(decimal.New(7, 1)) != 0 { // only 1.2 is possible due to increment
t.Errorf("debited: %s, cmp: %v", dbted, dbted.Cmp(new(decimal.Big).SetFloat64(1.2)))
} else if cb.blnCfg.Units != 0.55 {
} else if cb.blnCfg.Units.String() != "0.55" {
t.Errorf("balance remaining: %f", cb.blnCfg.Units)
}
}

View File

@@ -87,21 +87,24 @@ func (apierSv1 *APIerSv1) GetAccountProfileIDsCount(args *utils.TenantWithOpts,
return
}
type AccountProfileWithCache struct {
*utils.AccountProfileWithOpts
type APIAccountProfileWithCache struct {
*utils.APIAccountProfileWithOpts
Cache *string
}
//SetAccountProfile add/update a new Account Profile
func (apierSv1 *APIerSv1) SetAccountProfile(ap *AccountProfileWithCache, reply *string) error {
if missing := utils.MissingStructFields(ap.AccountProfile, []string{utils.ID}); len(missing) != 0 {
func (apierSv1 *APIerSv1) SetAccountProfile(extAp *APIAccountProfileWithCache, reply *string) error {
if missing := utils.MissingStructFields(extAp.APIAccountProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if ap.Tenant == utils.EmptyString {
ap.Tenant = apierSv1.Config.GeneralCfg().DefaultTenant
if extAp.Tenant == utils.EmptyString {
extAp.Tenant = apierSv1.Config.GeneralCfg().DefaultTenant
}
if err := apierSv1.DataManager.SetAccountProfile(ap.AccountProfile, true); err != nil {
ap, err := extAp.AsAccountProfile()
if err != nil {
return err
}
if err := apierSv1.DataManager.SetAccountProfile(ap, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAccountProfiles and store it in database

View File

@@ -39,7 +39,8 @@ var (
accPrfCfg *config.CGRConfig
accSRPC *rpc.Client
accPrfDataDir = "/usr/share/cgrates"
accPrf *AccountProfileWithCache
apiAccPrf *APIAccountProfileWithCache
accPrf *utils.AccountProfile
accPrfConfigDIR string //run tests for specific configuration
sTestsAccPrf = []func(t *testing.T){
@@ -157,7 +158,7 @@ func testAccountSGetAccountProfile(t *testing.T) {
Factor: &utils.Decimal{decimal.New(200, 0)},
},
},
Units: 14,
Units: &utils.Decimal{decimal.New(14, 0)},
},
&utils.Balance{
ID: "VoiceBalance",
@@ -167,7 +168,7 @@ func testAccountSGetAccountProfile(t *testing.T) {
CostIncrements: []*utils.CostIncrement{},
CostAttributes: []string{},
UnitFactors: []*utils.UnitFactor{},
Units: 3600000000000,
Units: &utils.Decimal{decimal.New(3600000000000, 0)},
},
},
ThresholdIDs: []string{utils.META_NONE},
@@ -197,48 +198,45 @@ func testAccountSPing(t *testing.T) {
}
func testAccountSSettAccountProfile(t *testing.T) {
accPrf = &AccountProfileWithCache{
AccountProfileWithOpts: &utils.AccountProfileWithOpts{
AccountProfile: &utils.AccountProfile{
apiAccPrf = &APIAccountProfileWithCache{
APIAccountProfileWithOpts: &utils.APIAccountProfileWithOpts{
APIAccountProfile: &utils.APIAccountProfile{
Tenant: "cgrates.org",
ID: "id_test",
Weight: 10,
Balances: []*utils.Balance{
&utils.Balance{
Balances: []*utils.APIBalance{
&utils.APIBalance{
ID: "MonetaryBalance",
FilterIDs: []string{},
Weight: 10,
Type: utils.MONETARY,
CostIncrements: []*utils.CostIncrement{
&utils.CostIncrement{
CostIncrements: []*utils.APICostIncrement{
&utils.APICostIncrement{
FilterIDs: []string{"fltr1", "fltr2"},
Increment: &utils.Decimal{decimal.New(13, 1)},
FixedFee: &utils.Decimal{decimal.New(23, 1)},
RecurrentFee: &utils.Decimal{decimal.New(33, 1)},
Increment: utils.Float64Pointer(1.3),
FixedFee: utils.Float64Pointer(2.3),
RecurrentFee: utils.Float64Pointer(3.3),
},
},
CostAttributes: []string{"attr1", "attr2"},
UnitFactors: []*utils.UnitFactor{
&utils.UnitFactor{
UnitFactors: []*utils.APIUnitFactor{
&utils.APIUnitFactor{
FilterIDs: []string{"fltr1", "fltr2"},
Factor: &utils.Decimal{decimal.New(100, 0)},
Factor: 100,
},
&utils.UnitFactor{
&utils.APIUnitFactor{
FilterIDs: []string{"fltr3"},
Factor: &utils.Decimal{decimal.New(200, 0)},
Factor: 200,
},
},
Units: 14,
},
&utils.Balance{
ID: "VoiceBalance",
FilterIDs: []string{},
Weight: 10,
Type: utils.VOICE,
CostIncrements: []*utils.CostIncrement{},
CostAttributes: []string{},
UnitFactors: []*utils.UnitFactor{},
Units: 3600000000000,
&utils.APIBalance{
ID: "VoiceBalance",
FilterIDs: []string{},
Weight: 10,
Type: utils.VOICE,
Units: 3600000000000,
},
},
ThresholdIDs: []string{utils.META_NONE},
@@ -253,17 +251,21 @@ func testAccountSSettAccountProfile(t *testing.T) {
t.Errorf("Expected error: %v received: %v", expErr, err)
}
var reply string
if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, accPrf, &reply); err != nil {
if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, apiAccPrf, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error("Unexpected reply returned", reply)
}
var err error
if accPrf, err = apiAccPrf.AsAccountProfile(); err != nil {
t.Error(err)
}
var reply2 *utils.AccountProfile
if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &reply2); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(accPrf.AccountProfile, reply2) {
t.Errorf("Expecting : %+v, received: %+v", accPrf.AccountProfile, reply2)
} else if !reflect.DeepEqual(accPrf, reply2) {
t.Errorf("Expecting : %+v, received: %+v", accPrf, reply2)
}
}
@@ -305,19 +307,23 @@ func testAccountSGetAccountProfileIDsCount(t *testing.T) {
func testAccountSUpdateAccountProfile(t *testing.T) {
var reply string
accPrf.Weight = 2
accPrf.Balances[0].CostIncrements[0].FixedFee = &utils.Decimal{decimal.New(1234, 1)}
if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, accPrf, &reply); err != nil {
apiAccPrf.Weight = 2
apiAccPrf.Balances[0].CostIncrements[0].FixedFee = utils.Float64Pointer(123.5)
if err := accSRPC.Call(utils.APIerSv1SetAccountProfile, apiAccPrf, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error("Unexpected reply returned", reply)
}
var err error
if accPrf, err = apiAccPrf.AsAccountProfile(); err != nil {
t.Error(err)
}
var reply2 *utils.AccountProfile
if err := accSRPC.Call(utils.APIerSv1GetAccountProfile, &utils.TenantIDWithOpts{
TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "id_test"}}, &reply2); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(accPrf.AccountProfile, reply2) {
t.Errorf("Expecting : %+v, received: %+v", accPrf.AccountProfile, reply2)
} else if !reflect.DeepEqual(accPrf, reply2) {
t.Errorf("Expecting : %+v, received: %+v", accPrf, reply2)
}
}

View File

@@ -0,0 +1,65 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import (
"github.com/cgrates/cgrates/utils"
)
func init() {
c := &CmdGetAccountsProfile{
name: "accounts_profile",
rpcMethod: utils.APIerSv1GetAccountProfile,
rpcParams: &utils.TenantID{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
// Commander implementation
type CmdGetAccountsProfile struct {
name string
rpcMethod string
rpcParams *utils.TenantID
*CommandExecuter
}
func (self *CmdGetAccountsProfile) Name() string {
return self.name
}
func (self *CmdGetAccountsProfile) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdGetAccountsProfile) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &utils.TenantID{}
}
return self.rpcParams
}
func (self *CmdGetAccountsProfile) PostprocessRpcParams() error {
return nil
}
func (self *CmdGetAccountsProfile) RpcResult() interface{} {
var atr utils.AccountProfile
return &atr
}

View File

@@ -0,0 +1,65 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import (
"github.com/cgrates/cgrates/utils"
)
func init() {
c := &CmdGetAccountsProfileIDs{
name: "accounts_profile_ids",
rpcMethod: utils.APIerSv1GetAccountProfileIDs,
rpcParams: &utils.PaginatorWithTenant{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
// Commander implementation
type CmdGetAccountsProfileIDs struct {
name string
rpcMethod string
rpcParams *utils.PaginatorWithTenant
*CommandExecuter
}
func (self *CmdGetAccountsProfileIDs) Name() string {
return self.name
}
func (self *CmdGetAccountsProfileIDs) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdGetAccountsProfileIDs) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &utils.PaginatorWithTenant{}
}
return self.rpcParams
}
func (self *CmdGetAccountsProfileIDs) PostprocessRpcParams() error {
return nil
}
func (self *CmdGetAccountsProfileIDs) RpcResult() interface{} {
var atr []string
return &atr
}

View File

@@ -0,0 +1,62 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import "github.com/cgrates/cgrates/utils"
func init() {
c := &CmdRemoveAccountsProfile{
name: "accounts_profile_remove",
rpcMethod: utils.APIerSv1RemoveAccountProfile,
rpcParams: &utils.TenantIDWithCache{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
type CmdRemoveAccountsProfile struct {
name string
rpcMethod string
rpcParams *utils.TenantIDWithCache
*CommandExecuter
}
func (self *CmdRemoveAccountsProfile) Name() string {
return self.name
}
func (self *CmdRemoveAccountsProfile) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdRemoveAccountsProfile) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &utils.TenantIDWithCache{Opts: make(map[string]interface{})}
}
return self.rpcParams
}
func (self *CmdRemoveAccountsProfile) PostprocessRpcParams() error {
return nil
}
func (self *CmdRemoveAccountsProfile) RpcResult() interface{} {
var s string
return &s
}

View File

@@ -0,0 +1,65 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import (
v1 "github.com/cgrates/cgrates/apier/v1"
"github.com/cgrates/cgrates/utils"
)
func init() {
c := &CmdSetAccountProfile{
name: "accounts_profile_set",
rpcMethod: utils.APIerSv1SetAccountProfile,
rpcParams: &v1.APIAccountProfileWithCache{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
type CmdSetAccountProfile struct {
name string
rpcMethod string
rpcParams *v1.APIAccountProfileWithCache
*CommandExecuter
}
func (self *CmdSetAccountProfile) Name() string {
return self.name
}
func (self *CmdSetAccountProfile) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdSetAccountProfile) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &v1.APIAccountProfileWithCache{APIAccountProfileWithOpts: new(utils.APIAccountProfileWithOpts)}
}
return self.rpcParams
}
func (self *CmdSetAccountProfile) PostprocessRpcParams() error {
return nil
}
func (self *CmdSetAccountProfile) RpcResult() interface{} {
var s string
return &s
}

View File

@@ -3726,7 +3726,9 @@ func APItoAccountProfile(tpAp *utils.TPAccountProfile, timezone string) (ap *uti
Weight: bal.Weight,
Blocker: bal.Blocker,
Type: bal.Type,
Units: bal.Units,
}
if ap.Balances[i].Units, err = utils.NewDecimalFromFloat64(bal.Units); err != nil {
return
}
if bal.Opts != utils.EmptyString {
ap.Balances[i].Opts = make(map[string]interface{})
@@ -3815,9 +3817,8 @@ func AccountProfileToAPI(ap *utils.AccountProfile) (tpAp *utils.TPAccountProfile
Weight: bal.Weight,
Blocker: bal.Blocker,
Type: bal.Type,
Units: bal.Units,
}
tpAp.Balances[i].Units, _ = bal.Units.Float64()
elems := make([]string, 0, len(bal.Opts))
for k, v := range bal.Opts {
elems = append(elems, utils.ConcatenatedKey(k, utils.IfaceAsString(v)))

View File

@@ -25,6 +25,8 @@ import (
"testing"
"time"
"github.com/ericlagergren/decimal"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
@@ -7230,7 +7232,7 @@ func TestApitoAccountProfileCase2(t *testing.T) {
FilterIDs: []string{"FLTR_RES_GR2"},
Weight: 10,
Type: utils.VOICE,
Units: 3600000000000,
Units: &utils.Decimal{decimal.New(3600000000000, 0)},
Opts: map[string]interface{}{
"key1": "val1",
},
@@ -7388,7 +7390,7 @@ func TestModelHelpersAccountProfileToAPI(t *testing.T) {
FilterIDs: []string{"FLTR_RES_GR2"},
Weight: 10,
Type: utils.VOICE,
Units: 3600000000000,
Units: &utils.Decimal{decimal.New(3600000000000, 0)},
Opts: map[string]interface{}{
"key1": "val1",
},

View File

@@ -46,7 +46,7 @@ type Balance struct {
CostIncrements []*CostIncrement
CostAttributes []string
UnitFactors []*UnitFactor
Units float64
Units *Decimal
}
// CostIncrement enforces cost calculation to specific balance increments
@@ -152,7 +152,6 @@ func (bL *Balance) Clone() (blnc *Balance) {
Blocker: bL.Blocker,
Type: bL.Type,
Opts: make(map[string]interface{}),
Units: bL.Units,
}
if bL.FilterIDs != nil {
blnc.FilterIDs = make([]string, len(bL.FilterIDs))
@@ -181,6 +180,9 @@ func (bL *Balance) Clone() (blnc *Balance) {
blnc.UnitFactors[i] = value.Clone()
}
}
if bL.Units != nil {
blnc.Units = new(Decimal).Copy(bL.Units)
}
return
}
@@ -200,6 +202,12 @@ func (blcs Balances) Sort() {
sort.Slice(blcs, func(i, j int) bool { return blcs[i].Weight > blcs[j].Weight })
}
// APIAccountProfileWithOpts is used in API calls
type APIAccountProfileWithOpts struct {
*APIAccountProfile
Opts map[string]interface{}
}
// AccountProfileWithOpts is used in API calls
type AccountProfileWithOpts struct {
*AccountProfile
@@ -217,3 +225,130 @@ type ReplyMaxUsage struct {
MaxUsage time.Duration
Cost *EventCharges
}
// APIAccountProfile represents one APIAccount on a Tenant
type APIAccountProfile struct {
Tenant string
ID string
FilterIDs []string
ActivationInterval *ActivationInterval
Weight float64
Opts map[string]interface{}
Balances []*APIBalance
ThresholdIDs []string
}
func (ext *APIAccountProfile) AsAccountProfile() (profile *AccountProfile, err error) {
profile = &AccountProfile{
Tenant: ext.Tenant,
ID: ext.ID,
FilterIDs: ext.FilterIDs,
ActivationInterval: ext.ActivationInterval,
Weight: ext.Weight,
Opts: ext.Opts,
ThresholdIDs: ext.ThresholdIDs,
}
if len(ext.Balances) != 0 {
profile.Balances = make([]*Balance, len(ext.Balances))
for i, bal := range ext.Balances {
if profile.Balances[i], err = bal.AsBalance(); err != nil {
return
}
}
}
return
}
// APIBalance represents one APIBalance inside an APIAccount
type APIBalance struct {
ID string // Balance identificator, unique within an Account
FilterIDs []string
Weight float64
Blocker bool
Type string
Opts map[string]interface{}
CostIncrements []*APICostIncrement
CostAttributes []string
UnitFactors []*APIUnitFactor
Units float64
}
func (ext *APIBalance) AsBalance() (balance *Balance, err error) {
balance = &Balance{
ID: ext.ID,
FilterIDs: ext.FilterIDs,
Weight: ext.Weight,
Blocker: ext.Blocker,
Type: ext.Type,
Opts: ext.Opts,
CostAttributes: ext.CostAttributes,
}
if len(ext.CostIncrements) != 0 {
balance.CostIncrements = make([]*CostIncrement, len(ext.CostIncrements))
for i, cIncr := range ext.CostIncrements {
if balance.CostIncrements[i], err = cIncr.AsCostIncrement(); err != nil {
return
}
}
}
if len(ext.UnitFactors) != 0 {
balance.UnitFactors = make([]*UnitFactor, len(ext.UnitFactors))
for i, uFct := range ext.UnitFactors {
if balance.UnitFactors[i], err = uFct.AsUnitFactor(); err != nil {
return
}
}
}
if balance.Units, err = NewDecimalFromFloat64(ext.Units); err != nil {
return
}
return
}
// APICostIncrement represent one CostIncrement inside an APIBalance
type APICostIncrement struct {
FilterIDs []string
Increment *float64
FixedFee *float64
RecurrentFee *float64
}
func (ext *APICostIncrement) AsCostIncrement() (cIncr *CostIncrement, err error) {
cIncr = &CostIncrement{
FilterIDs: ext.FilterIDs,
}
if ext.Increment != nil {
if cIncr.Increment, err = NewDecimalFromFloat64(*ext.Increment); err != nil {
return
}
}
if ext.FixedFee != nil {
if cIncr.FixedFee, err = NewDecimalFromFloat64(*ext.FixedFee); err != nil {
return
}
}
if ext.RecurrentFee != nil {
if cIncr.RecurrentFee, err = NewDecimalFromFloat64(*ext.RecurrentFee); err != nil {
return
}
}
return
}
// APIUnitFactor represent one UnitFactor inside an APIBalance
type APIUnitFactor struct {
FilterIDs []string
Factor float64
}
func (ext *APIUnitFactor) AsUnitFactor() (uFac *UnitFactor, err error) {
uFac = &UnitFactor{
FilterIDs: ext.FilterIDs,
}
if uFac.Factor, err = NewDecimalFromFloat64(ext.Factor); err != nil {
return
}
return
}

View File

@@ -51,7 +51,7 @@ func TestCloneBalance(t *testing.T) {
Factor: &Decimal{decimal.New(20, 2)},
},
},
Units: 1.25,
Units: &Decimal{decimal.New(125, 3)},
}
if rcv := expBlc.Clone(); !reflect.DeepEqual(rcv, expBlc) {
t.Errorf("Expected %+v \n, received %+v", ToJSON(expBlc), ToJSON(rcv))
@@ -96,7 +96,7 @@ func TestCloneAccountProfile(t *testing.T) {
Factor: &Decimal{decimal.New(20, 2)},
},
},
Units: 1.25,
Units: &Decimal{decimal.New(125, 3)},
},
},
ThresholdIDs: []string{"*none"},