diff --git a/apier/derivedcharging.go b/apier/derivedcharging.go
new file mode 100644
index 000000000..3756823cd
--- /dev/null
+++ b/apier/derivedcharging.go
@@ -0,0 +1,54 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 ITsysCOM GmbH
+
+This program is free software: you can Storagetribute 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 WITH*out 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
+*/
+
+package apier
+
+import (
+ "fmt"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// Get DerivedChargers applying to our call, appends general configured to account specific ones if that is configured
+func (self *ApierV1) DerivedChargers(attrs utils.AttrDerivedChargers, reply *utils.DerivedChargers) (err error) {
+ if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Direction", "Account", "Subject"}); len(missing) != 0 {
+ return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
+ }
+ if hDc, err := engine.HandleGetDerivedChargers(self.AccountDb, self.Config, attrs); err != nil {
+ return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
+ } else if hDc != nil {
+ *reply = hDc
+ }
+ return nil
+}
+
+type AttrSetDerivedChargers struct {
+ Tenant, Tor, Direction, Account, Subject string
+ DerivedChargers utils.DerivedChargers
+}
+
+func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *utils.DerivedChargers) (err error) {
+ if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Direction", "Account", "Subject", "DerivedChargers"}); len(missing) != 0 {
+ return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
+ }
+ if err := self.AccountDb.SetDerivedChargers(utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, attrs.Subject),
+ attrs.DerivedChargers); err != nil {
+ return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
+ }
+ return nil
+}
diff --git a/apier/derivedcharging_test.go b/apier/derivedcharging_test.go
new file mode 100644
index 000000000..22db50f44
--- /dev/null
+++ b/apier/derivedcharging_test.go
@@ -0,0 +1,45 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 ITsysCOM GmbH
+
+This program is free software: you can Storagetribute 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 WITH*out 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
+*/
+
+package apier
+
+import (
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+ "reflect"
+ "testing"
+)
+
+var apierDcT *ApierV1
+
+func init() {
+ dataStorage, _ := engine.NewMapStorage()
+ cfg, _ := config.NewDefaultCGRConfig()
+ apierDcT = &ApierV1{AccountDb: engine.AccountingStorage(dataStorage), Config: cfg}
+}
+
+func TestGetEmptyDC(t *testing.T) {
+ attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "dan", Subject: "dan"}
+ var dcs utils.DerivedChargers
+ if err := apierDcT.DerivedChargers(attrs, &dcs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, apierDcT.Config.DerivedChargers) {
+ t.Error("Returned DerivedChargers not matching the configured ones")
+ }
+}
diff --git a/engine/derivedcharging.go b/engine/derivedcharging.go
new file mode 100644
index 000000000..dcd30c8e9
--- /dev/null
+++ b/engine/derivedcharging.go
@@ -0,0 +1,52 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 ITsysCOM GmbH
+
+This program is free software: you can Storagetribute 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 WITH*out 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
+*/
+
+package engine
+
+import (
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// Transparently handles merging between storage data and configuration, useful as local handler
+func HandleGetDerivedChargers(acntStorage AccountingStorage, cfg *config.CGRConfig, attrs utils.AttrDerivedChargers) (utils.DerivedChargers, error) {
+ var dcs utils.DerivedChargers
+ var err error
+ strictKey := utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, attrs.Subject)
+ anySubjKey := utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, utils.ANY)
+ for _, dcKey := range []string{strictKey, anySubjKey} {
+ if dcsDb, err := acntStorage.GetDerivedChargers(dcKey, false); err != nil && err.Error() != utils.ERR_NOT_FOUND {
+ return nil, err
+ } else if dcsDb != nil {
+ dcs = dcsDb
+ break
+ }
+ }
+ if dcs == nil {
+ dcs = cfg.DerivedChargers
+ return dcs, nil
+ }
+ if cfg.CombinedDerivedChargers {
+ for _, cfgDc := range cfg.DerivedChargers {
+ if dcs, err = dcs.Append(cfgDc); err != nil {
+ return nil, err
+ }
+ }
+ }
+ return dcs, nil
+}
diff --git a/engine/derivedcharging_test.go b/engine/derivedcharging_test.go
new file mode 100644
index 000000000..10f0f20cb
--- /dev/null
+++ b/engine/derivedcharging_test.go
@@ -0,0 +1,88 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 ITsysCOM GmbH
+
+This program is free software: you can Storagetribute 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 WITH*out 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
+*/
+
+package engine
+
+import (
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+ "reflect"
+ "testing"
+)
+
+var cfgDcT *config.CGRConfig
+var acntDb AccountingStorage
+
+func init() {
+ cfgDcT, _ = config.NewDefaultCGRConfig()
+ acntDb, _ = NewMapStorage()
+ acntDb.CacheAccounting(nil, nil, nil, nil)
+}
+
+// Accounting db has no DerivedChargers nor configured defaults
+func TestHandleGetEmptyDC(t *testing.T) {
+ attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "test2", Subject: "test2"}
+ if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, cfgDcT.DerivedChargers) {
+ t.Error("Returned DerivedChargers not matching the configured ones")
+ }
+}
+
+// Accounting db has no DerivedChargers, configured defaults
+func TestHandleGetConfiguredDC(t *testing.T) {
+ cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
+ TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
+ cfgDcT.DerivedChargers = cfgedDC
+ attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "test3", Subject: "test3"}
+ if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, cfgedDC) {
+ t.Error("Returned DerivedChargers not matching the configured ones")
+ }
+}
+
+// Receive composed derived chargers
+func TestHandleGetStoredDC(t *testing.T) {
+ keyCharger1 := utils.DerivedChargersKey("cgrates.org", "call", "*out", "rif", "rif")
+ charger1 := utils.DerivedChargers{
+ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
+ AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
+ &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
+ AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
+ }
+ if err := acntDb.SetDerivedChargers(keyCharger1, charger1); err != nil {
+ t.Error("Error on setDerivedChargers", err.Error())
+ }
+ // Expected Charger should have default configured values added
+ expCharger1 := append(charger1, &utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
+ TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"})
+ acntDb.CacheAccounting(nil, nil, nil, nil)
+ attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "rif", Subject: "rif"}
+ if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, expCharger1) {
+ t.Error("Returned DerivedChargers not matching the configured ones")
+ }
+ cfgDcT.CombinedDerivedChargers = false
+ if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, charger1) {
+ t.Error("Returned DerivedChargers not matching the configured ones")
+ }
+}
diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go
index 412051f0b..987806287 100644
--- a/engine/loader_csv_test.go
+++ b/engine/loader_csv_test.go
@@ -839,7 +839,7 @@ func TestLoadDerivedChargers(t *testing.T) {
&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
}
- keyCharger1 := utils.ConcatenatedKey("cgrates.org", "call", "*out", "dan", "dan")
+ keyCharger1 := utils.DerivedChargersKey("cgrates.org", "call", "*out", "dan", "dan")
if !reflect.DeepEqual(csvr.derivedChargers[keyCharger1], expCharger1) {
t.Error("Unexpected charger", csvr.derivedChargers[keyCharger1])
}
diff --git a/engine/responder.go b/engine/responder.go
index 75907f2ed..f01348330 100644
--- a/engine/responder.go
+++ b/engine/responder.go
@@ -116,7 +116,7 @@ func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err
return
}
-func (rs *Responder) DerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
+func (rs *Responder) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
// ToDo: Make it work with balancer if needed
if dcsH, err := HandleGetDerivedChargers(accountingStorage, config.CgrConfig(), attrs); err != nil {
@@ -332,7 +332,7 @@ type Connector interface {
MaxDebit(CallDescriptor, *CallCost) error
RefundIncrements(CallDescriptor, *float64) error
GetMaxSessionTime(CallDescriptor, *float64) error
- DerivedChargers(utils.AttrDerivedChargers, utils.DerivedChargers) error
+ GetDerivedChargers(utils.AttrDerivedChargers, utils.DerivedChargers) error
}
type RPCClientConnector struct {
@@ -359,6 +359,6 @@ func (rcc *RPCClientConnector) GetMaxSessionTime(cd CallDescriptor, resp *float6
return rcc.Client.Call("Responder.GetMaxSessionTime", cd, resp)
}
-func (rcc *RPCClientConnector) DerivedChargers(attrs utils.AttrDerivedChargers, dcs utils.DerivedChargers) error {
+func (rcc *RPCClientConnector) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs utils.DerivedChargers) error {
return rcc.Client.Call("ApierV1.DerivedChargers", attrs, dcs)
}
diff --git a/engine/responder_test.go b/engine/responder_test.go
new file mode 100644
index 000000000..00b322280
--- /dev/null
+++ b/engine/responder_test.go
@@ -0,0 +1,43 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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
+*/
+
+package engine
+
+import (
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+ "reflect"
+ "testing"
+)
+
+// Test internal abilites of GetDerivedChargers
+func TestResponderGetDerivedChargers(t *testing.T) {
+ cfg, _ := config.NewDefaultCGRConfig()
+ cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
+ TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
+ cfg.DerivedChargers = cfgedDC
+ config.SetCgrConfig(cfg)
+ r := Responder{}
+ attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "dan", Subject: "dan"}
+ var dcs utils.DerivedChargers
+ if err := r.GetDerivedChargers(attrs, &dcs); err != nil {
+ t.Error("Unexpected error", err.Error())
+ } else if !reflect.DeepEqual(dcs, cfgedDC) {
+ t.Errorf("Expecting: %v, received: %v ", cfgedDC, dcs)
+ }
+}
diff --git a/engine/storage_map.go b/engine/storage_map.go
index 29bdeec12..b2e4121e0 100644
--- a/engine/storage_map.go
+++ b/engine/storage_map.go
@@ -449,7 +449,7 @@ func (ms *MapStorage) GetDerivedChargers(key string, checkDb bool) (dcs utils.De
err = ms.ms.Unmarshal(values, &dcs)
cache2go.Cache(key, dcs)
} else {
- return nil, errors.New("not found")
+ return nil, errors.New(utils.ERR_NOT_FOUND)
}
return
}