lcr loading

This commit is contained in:
Radu Ioan Fericean
2014-04-26 01:33:48 +03:00
parent 393d9091b6
commit f1731cccb7
10 changed files with 322 additions and 30 deletions

View File

@@ -211,31 +211,54 @@ CREATE TABLE `tp_account_actions` (
UNIQUE KEY `unique_tp_account` (`tpid`,`loadid`,`tenant`,`account`,`direction`)
);
--
-- Table structure for table `tp_lcrs`
--
DROP TABLE IF EXISTS tp_lcrs;
CREATE TABLE tp_lcrs (
`tbid` int(11) NOT NULL AUTO_INCREMENT,
`tpid` varchar(64) NOT NULL,
`direction` varchar(8) NOT NULL,
`tenant` varchar(64) NOT NULL,
`customer` varchar(64) NOT NULL,
`destination`_id varchar(64) NOT NULL,
`category` varchar(16) NOT NULL,
`strategy` varchar(16) NOT NULL,
`suppliers` varchar(64) NOT NULL,
`activation_time` varchar(24) NOT NULL,
`weight` double(8,2) NOT NULL,
PRIMARY KEY (`tbid`),
KEY `tpid` (`tpid`)
);
--
-- Table structure for table `tp_derived_chargers`
--
DROP TABLE IF EXISTS tp_derived_chargers;
CREATE TABLE tp_derived_chargers (
tbid int(11) NOT NULL AUTO_INCREMENT,
tpid varchar(64) NOT NULL,
loadid varchar(64) NOT NULL,
direction varchar(8) NOT NULL,
tenant varchar(64) NOT NULL,
tor varchar(16) NOT NULL,
account varchar(24) NOT NULL,
subject varchar(64) NOT NULL,
runid_field varchar(24) NOT NULL,
reqtype_field varchar(24) NOT NULL,
direction_field varchar(24) NOT NULL,
tenant_field varchar(24) NOT NULL,
tor_field varchar(24) NOT NULL,
account_field varchar(24) NOT NULL,
subject_field varchar(24) NOT NULL,
destination_field varchar(24) NOT NULL,
setup_time_field varchar(24) NOT NULL,
answer_time_field varchar(24) NOT NULL,
duration_field varchar(24) NOT NULL,
`tbid` int(11) NOT NULL AUTO_INCREMENT,
`tpid` varchar(64) NOT NULL,
`loadid` varchar(64) NOT NULL,
`direction` varchar(8) NOT NULL,
`tenant` varchar(64) NOT NULL,
`category` varchar(16) NOT NULL,
`account` varchar(24) NOT NULL,
`subject` varchar(64) NOT NULL,
`runid_field` varchar(24) NOT NULL,
`reqtype_field` varchar(24) NOT NULL,
`direction_field` varchar(24) NOT NULL,
`tenant_field` varchar(24) NOT NULL,
`tor_field` varchar(24) NOT NULL,
`account_field` varchar(24) NOT NULL,
`subject_field` varchar(24) NOT NULL,
`destination_field` varchar(24) NOT NULL,
`setup_time`_field varchar(24) NOT NULL,
`answer_time`_field varchar(24) NOT NULL,
`duration_field` varchar(24) NOT NULL,
PRIMARY KEY (`tbid`),
KEY `tpid` (`tpid`)
);

View File

@@ -724,7 +724,7 @@ func (cd *CallDescriptor) GetLCR() (*LCRCost, error) {
}
} else {
// find rating profiles
ratingProfileSearchKey := fmt.Sprintf("%s:%s:%s:", lcr.Direction, lcr.Tenant, ts.Entry.TOR)
ratingProfileSearchKey := fmt.Sprintf("%s:%s:%s:", lcr.Direction, lcr.Tenant, ts.Entry.Category)
suppliers := cache2go.GetEntriesKeys(LCR_PREFIX + ratingProfileSearchKey)
for _, supplier := range suppliers {
split := strings.Split(supplier, ":")

View File

@@ -34,9 +34,9 @@ const (
)
type LCR struct {
Direction string
Tenant string
Customer string
Direction string
Activations []*LCRActivation
}
type LCRActivation struct {
@@ -45,7 +45,7 @@ type LCRActivation struct {
}
type LCREntry struct {
DestinationId string
TOR string
Category string
Strategy string
Suppliers string
Weight float64

View File

@@ -54,11 +54,11 @@ type CSVReader struct {
derivedChargers map[string]utils.DerivedChargers
// file names
destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn,
sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn string
sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn string
}
func NewFileCSVReader(dataStorage RatingStorage, accountingStorage AccountingStorage, sep rune,
destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn,
destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn,
actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn string) *CSVReader {
c := new(CSVReader)
c.sep = sep
@@ -80,16 +80,16 @@ func NewFileCSVReader(dataStorage RatingStorage, accountingStorage AccountingSto
c.rpAliases = make(map[string]string)
c.accAliases = make(map[string]string)
c.destinationsFn, c.timingsFn, c.ratesFn, c.destinationratesFn, c.destinationratetimingsFn, c.ratingprofilesFn,
c.sharedgroupsFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn = destinationsFn, timingsFn,
ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn
c.sharedgroupsFn, c.lcrFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn = destinationsFn, timingsFn,
ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn
return c
}
func NewStringCSVReader(dataStorage RatingStorage, accountingStorage AccountingStorage, sep rune,
destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn,
destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn,
actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn string) *CSVReader {
c := NewFileCSVReader(dataStorage, accountingStorage, sep, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn,
ratingprofilesFn, sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn)
ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn)
c.readerFunc = openStringCSVReader
return c
}
@@ -167,6 +167,8 @@ func (csvr *CSVReader) ShowStatistics() {
log.Print("Account actions: ", len(csvr.accountActions))
// derivedChargers
log.Print("DerivedChargers: ", len(csvr.derivedChargers))
// lcr rules
log.Print("LCR rules: ", len(csvr.lcrs))
}
func (csvr *CSVReader) WriteToDatabase(flush, verbose bool) (err error) {
@@ -238,6 +240,18 @@ func (csvr *CSVReader) WriteToDatabase(flush, verbose bool) (err error) {
log.Println(k)
}
}
if verbose {
log.Print("LCR Rules")
}
for k, lcr := range csvr.lcrs {
err = dataStorage.SetLCR(lcr)
if err != nil {
return err
}
if verbose {
log.Println(k)
}
}
if verbose {
log.Print("Actions")
}
@@ -558,6 +572,60 @@ func (csvr *CSVReader) LoadSharedGroups() (err error) {
return
}
func (csvr *CSVReader) LoadLCRs() (err error) {
csvReader, fp, err := csvr.readerFunc(csvr.lcrFn, csvr.sep, utils.LCRS_NRCOLS)
if err != nil {
log.Print("Could not load LCR rules file: ", err)
// allow writing of the other values
return nil
}
if fp != nil {
defer fp.Close()
}
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
direction, tenant, customer := record[0], record[1], record[2]
id := fmt.Sprintf("%s:%s:%s", direction, tenant, customer)
lcr, found := csvr.lcrs[id]
activationTime, err := utils.ParseTimeDetectLayout(record[7])
if err != nil {
return fmt.Errorf("Could not parse LCR activation time: %v", err)
}
weight, err := strconv.ParseFloat(record[8], 64)
if err != nil {
return fmt.Errorf("Could not parse LCR weight: %v", err)
}
if !found {
lcr = &LCR{
Direction: direction,
Tenant: tenant,
Customer: customer,
}
}
var act *LCRActivation
for _, existingAct := range lcr.Activations {
if existingAct.ActivationTime.Equal(activationTime) {
act = existingAct
break
}
}
if act == nil {
act = &LCRActivation{
ActivationTime: activationTime,
}
lcr.Activations = append(lcr.Activations, act)
}
act.Entries = append(act.Entries, &LCREntry{
DestinationId: record[3],
Category: record[4],
Strategy: record[5],
Suppliers: record[6],
Weight: weight,
})
csvr.lcrs[id] = lcr
}
return
}
func (csvr *CSVReader) LoadActions() (err error) {
csvReader, fp, err := csvr.readerFunc(csvr.actionsFn, csvr.sep, utils.ACTIONS_NRCOLS)
if err != nil {

View File

@@ -133,6 +133,11 @@ RP_DATA,DATA_RATE,ALWAYS,10
SG1,*any,*lowest,
SG2,*any,*lowest,one
SG3,*any,*lowest,
`
lcrs = `
*in,cgrates.org,*any,EU_LANDLINE,LCR_STANDARD,*static,ivo;dan;rif,2012-01-01T00:00:00Z,10
*in,cgrates.org,*any,*any,LCR_STANDARD,*lowest_cost,,2012-01-01T00:00:00Z,20
`
actions = `
@@ -184,7 +189,7 @@ var csvr *CSVReader
func init() {
csvr = NewStringCSVReader(dataStorage, accountingStorage, ',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles,
sharedGroups, actions, actionTimings, actionTriggers, accountActions, derivedCharges)
sharedGroups, lcrs, actions, actionTimings, actionTriggers, accountActions, derivedCharges)
csvr.LoadDestinations()
csvr.LoadTimings()
csvr.LoadRates()
@@ -192,6 +197,7 @@ func init() {
csvr.LoadRatingPlans()
csvr.LoadRatingProfiles()
csvr.LoadSharedGroups()
csvr.LoadLCRs()
csvr.LoadActions()
csvr.LoadActionTimings()
csvr.LoadActionTriggers()
@@ -709,7 +715,7 @@ func TestLoadActions(t *testing.T) {
func TestLoadSharedGroups(t *testing.T) {
if len(csvr.sharedGroups) != 3 {
t.Error("Failed to load actions: ", csvr.sharedGroups)
t.Error("Failed to shared groups: ", csvr.sharedGroups)
}
sg1 := csvr.sharedGroups["SG1"]
@@ -754,6 +760,43 @@ func TestLoadSharedGroups(t *testing.T) {
}*/
}
func TestLoadLCRs(t *testing.T) {
if len(csvr.lcrs) != 1 {
t.Error("Failed to load LCRs: ", csvr.lcrs)
}
lcr := csvr.lcrs["*in:cgrates.org:*any"]
expected := &LCR{
Direction: "*in",
Tenant: "cgrates.org",
Customer: "*any",
Activations: []*LCRActivation{
&LCRActivation{
ActivationTime: time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC),
Entries: []*LCREntry{
&LCREntry{
DestinationId: "EU_LANDLINE",
Category: "LCR_STANDARD",
Strategy: "*static",
Suppliers: "ivo;dan;rif",
Weight: 10,
},
&LCREntry{
DestinationId: "*any",
Category: "LCR_STANDARD",
Strategy: "*lowest_cost",
Suppliers: "",
Weight: 20,
},
},
},
},
}
if !reflect.DeepEqual(lcr, expected) {
t.Errorf("Error loading lcr %+v: ", lcr.Activations)
}
}
func TestLoadActionTimings(t *testing.T) {
if len(csvr.actionsTimings) != 5 {
t.Error("Failed to load action timings: ", csvr.actionsTimings)

View File

@@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"log"
"strconv"
"strings"
"github.com/cgrates/cgrates/utils"
@@ -47,6 +48,7 @@ type DbReader struct {
ratingPlans map[string]*RatingPlan
ratingProfiles map[string]*RatingProfile
sharedGroups map[string]*SharedGroup
lcrs map[string]*LCR
derivedChargers map[string]utils.DerivedChargers
}
@@ -62,6 +64,7 @@ func NewDbReader(storDB LoadStorage, ratingDb RatingStorage, accountDb Accountin
c.ratingPlans = make(map[string]*RatingPlan)
c.ratingProfiles = make(map[string]*RatingProfile)
c.sharedGroups = make(map[string]*SharedGroup)
c.lcrs = make(map[string]*LCR)
c.rpAliases = make(map[string]string)
c.accAliases = make(map[string]string)
c.accountActions = make(map[string]*Account)
@@ -121,6 +124,8 @@ func (dbr *DbReader) ShowStatistics() {
log.Print("Account actions: ", len(dbr.accountActions))
// derivedChargers
log.Print("DerivedChargers: ", len(dbr.derivedChargers))
// lcr rules
log.Print("LCR rules: ", len(dbr.lcrs))
}
func (dbr *DbReader) WriteToDatabase(flush, verbose bool) (err error) {
@@ -188,6 +193,18 @@ func (dbr *DbReader) WriteToDatabase(flush, verbose bool) (err error) {
log.Println(k)
}
}
if verbose {
log.Print("LCR Rules")
}
for k, lcr := range dbr.lcrs {
err = dataStorage.SetLCR(lcr)
if err != nil {
return err
}
if verbose {
log.Println(k)
}
}
if verbose {
log.Print("Actions")
}
@@ -456,6 +473,62 @@ func (dbr *DbReader) LoadSharedGroups() (err error) {
return err
}
func (dbr *DbReader) LoadLCRs() (err error) {
dbr.sharedGroups, err = dbr.storDb.GetTpSharedGroups(dbr.tpid, "")
return err
csvReader, fp, err := csvr.readerFunc(csvr.lcrFn, csvr.sep, utils.LCRS_NRCOLS)
if err != nil {
log.Print("Could not load LCR rules file: ", err)
// allow writing of the other values
return nil
}
if fp != nil {
defer fp.Close()
}
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
direction, tenant, customer := record[0], record[1], record[2]
id := fmt.Sprintf("%s:%s:%s", direction, tenant, customer)
lcr, found := csvr.lcrs[id]
activationTime, err := utils.ParseTimeDetectLayout(record[7])
if err != nil {
return fmt.Errorf("Could not parse LCR activation time: %v", err)
}
weight, err := strconv.ParseFloat(record[8], 64)
if err != nil {
return fmt.Errorf("Could not parse LCR weight: %v", err)
}
if !found {
lcr = &LCR{
Direction: direction,
Tenant: tenant,
Customer: customer,
}
}
var act *LCRActivation
for _, existingAct := range lcr.Activations {
if existingAct.ActivationTime.Equal(activationTime) {
act = existingAct
break
}
}
if act == nil {
act = &LCRActivation{
ActivationTime: activationTime,
}
lcr.Activations = append(lcr.Activations, act)
}
act.Entries = append(act.Entries, &LCREntry{
DestinationId: record[3],
Category: record[4],
Strategy: record[5],
Suppliers: record[6],
Weight: weight,
})
csvr.lcrs[id] = lcr
}
return
}
func (dbr *DbReader) LoadActions() (err error) {
storActs, err := dbr.storDb.GetTpActions(dbr.tpid, "")
if err != nil {

View File

@@ -127,6 +127,7 @@ func TestLoadFromCSV(t *testing.T) {
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.RATING_PLANS_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.RATING_PROFILES_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.SHARED_GROUPS_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.LCRS_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.ACTIONS_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.ACTION_PLANS_CSV),
path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.ACTION_TRIGGERS_CSV),

View File

@@ -155,6 +155,9 @@ type LoadStorage interface {
SetTPSharedGroups(string, map[string]*SharedGroup) error
GetTpSharedGroups(string, string) (map[string]*SharedGroup, error)
SetTPLCRs(string, map[string]*LCR) error
GetTpLCRs(string, string) (map[string]*LCR, error)
SetTPActions(string, map[string][]*utils.TPAction) error
GetTpActions(string, string) (map[string][]*utils.TPAction, error)

View File

@@ -305,6 +305,31 @@ func (self *SQLStorage) SetTPSharedGroups(tpid string, sgs map[string]*SharedGro
return nil
}
func (self *SQLStorage) SetTPLCRs(tpid string, lcrs map[string]*LCR) error {
if len(lcrs) == 0 {
return nil //Nothing to set
}
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("INSERT INTO %s (tpid,direction,tenant,customer,destination_id,category,strategy,suppliers,activation_time,weight) VALUES ", utils.TBL_TP_LCRS))
i := 0
for _, lcr := range lcrs {
for _, act := range lcr.Activations {
for _, entry := range act.Entries {
if i != 0 { //Consecutive values after the first will be prefixed with "," as separator
buffer.WriteRune(',')
}
buffer.WriteString(fmt.Sprintf("('%s','%s','%s','%s','%s','%s','%s','%v','%v')",
tpid, lcr.Direction, lcr.Tenant, lcr.Customer, entry.DestinationId, entry.Category, entry.Strategy, entry.Suppliers, act.ActivationTime, entry.Weight))
i++
}
}
}
if _, err := self.Db.Exec(buffer.String()); err != nil {
return err
}
return nil
}
func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*utils.TPAction) error {
if len(acts) == 0 {
return nil //Nothing to set
@@ -1086,6 +1111,59 @@ func (self *SQLStorage) GetTpSharedGroups(tpid, tag string) (map[string]*SharedG
return sgs, nil
}
func (self *SQLStorage) GetTpLCRs(tpid, tag string) (map[string]*LCR, error) {
lcrs := make(map[string]*LCR)
q := fmt.Sprintf("SELECT * FROM %s WHERE tpid='%s'", utils.TBL_TP_LCRS, tpid)
if tag != "" {
q += fmt.Sprintf(" AND id='%s'", tag)
}
rows, err := self.Db.Query(q)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var id int
var tpid, direction, tenant, customer, destinationId, category, strategy, suppliers, activationTimeString string
var weight float64
if err := rows.Scan(&id, &tpid, &direction, &tenant, &customer, &destinationId, &category, &strategy, &suppliers, &activationTimeString, &weight); err != nil {
return nil, err
}
tag := fmt.Sprintf("%s:%s:%s", direction, tenant, customer)
lcr, found := lcrs[tag]
activationTime, _ := utils.ParseTimeDetectLayout(activationTimeString)
if !found {
lcr = &LCR{
Direction: direction,
Tenant: tenant,
Customer: customer,
}
}
var act *LCRActivation
for _, existingAct := range lcr.Activations {
if existingAct.ActivationTime.Equal(activationTime) {
act = existingAct
break
}
}
if act == nil {
act = &LCRActivation{
ActivationTime: activationTime,
}
lcr.Activations = append(lcr.Activations, act)
}
act.Entries = append(act.Entries, &LCREntry{
DestinationId: destinationId,
Category: category,
Strategy: strategy,
Suppliers: suppliers,
Weight: weight,
})
lcrs[tag] = lcr
}
return lcrs, nil
}
func (self *SQLStorage) GetTpActions(tpid, tag string) (map[string][]*utils.TPAction, error) {
as := make(map[string][]*utils.TPAction)
q := fmt.Sprintf("SELECT * FROM %s WHERE tpid='%s'", utils.TBL_TP_ACTIONS, tpid)

View File

@@ -27,6 +27,7 @@ const (
TBL_TP_RATING_PLANS = "tp_rating_plans"
TBL_TP_RATE_PROFILES = "tp_rating_profiles"
TBL_TP_SHARED_GROUPS = "tp_shared_groups"
TBL_TP_LCRS = "tp_lcrs"
TBL_TP_ACTIONS = "tp_actions"
TBL_TP_ACTION_PLANS = "tp_action_plans"
TBL_TP_ACTION_TRIGGERS = "tp_action_triggers"
@@ -42,6 +43,7 @@ const (
RATING_PLANS_CSV = "RatingPlans.csv"
RATING_PROFILES_CSV = "RatingProfiles.csv"
SHARED_GROUPS_CSV = "SharedGroups.csv"
LCRS_CSV = "LCRRules.csv"
ACTIONS_CSV = "Actions.csv"
ACTION_PLANS_CSV = "ActionPlans.csv"
ACTION_TRIGGERS_CSV = "ActionTriggers.csv"
@@ -54,6 +56,7 @@ const (
DESTRATE_TIMINGS_NRCOLS = 4
RATE_PROFILES_NRCOLS = 7
SHARED_GROUPS_NRCOLS = 4
LCRS_NRCOLS = 9
ACTIONS_NRCOLS = 12
ACTION_PLANS_NRCOLS = 4
ACTION_TRIGGERS_NRCOLS = 9