diff --git a/apier/tpactiontriggers.go b/apier/tpactiontriggers.go index 6b1bd4056..eff6b5c1a 100644 --- a/apier/tpactiontriggers.go +++ b/apier/tpactiontriggers.go @@ -38,12 +38,12 @@ func (self *Apier) SetTPActionTriggers(attrs utils.ApiTPActionTriggers, reply *s } aTriggers := make([]*engine.ActionTrigger, len(attrs.ActionTriggers)) for idx, at := range attrs.ActionTriggers { - requiredFields := []string{"BalanceId", "Direction", "ThresholdType", "ThresholdValue", "ActionsId", "Weight"} + requiredFields := []string{"BalanceType", "Direction", "ThresholdType", "ThresholdValue", "ActionsId", "Weight"} if missing := utils.MissingStructFields(&at, requiredFields); len(missing) != 0 { - return fmt.Errorf("%s:Balance:%s:%v", utils.ERR_MANDATORY_IE_MISSING, at.BalanceId, missing) + return fmt.Errorf("%s:Balance:%s:%v", utils.ERR_MANDATORY_IE_MISSING, at.BalanceType, missing) } at := &engine.ActionTrigger{ - BalanceId: at.BalanceId, + BalanceId: at.BalanceType, Direction: at.Direction, ThresholdType: at.ThresholdType, ThresholdValue: at.ThresholdValue, @@ -82,7 +82,7 @@ func (self *Apier) GetTPActionTriggers(attrs AttrGetTPActionTriggers, reply *uti aTriggers := make([]utils.ApiActionTrigger, len(ats[attrs.ActionTriggersId])) for idx, row := range ats[attrs.ActionTriggersId] { aTriggers[idx] = utils.ApiActionTrigger{ - BalanceId: row.BalanceId, + BalanceType: row.BalanceId, Direction: row.Direction, ThresholdType: row.ThresholdType, ThresholdValue: row.ThresholdValue, diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 7dd2e999a..3f75dabe0 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -252,7 +252,7 @@ func main() { } defer loggerDb.Close() engine.SetStorageLogger(loggerDb) - engine.SetRoundingMethodAndDecimals(cfg.RaterRoundingMethod, cfg.RaterRoundingDecimals) + engine.SetRoundingMethodAndDecimals(cfg.RoundingMethod, cfg.RoundingDecimals) if cfg.SMDebitInterval > 0 { if dp, err := time.ParseDuration(fmt.Sprintf("%vs", cfg.SMDebitInterval)); err == nil { diff --git a/config/config.go b/config/config.go index 9b6c2bca8..a8a835b86 100644 --- a/config/config.go +++ b/config/config.go @@ -35,10 +35,7 @@ const ( REDIS = "redis" SAME = "same" FS = "freeswitch" - PREPAID = "prepaid" - POSTPAID = "postpaid" - PSEUDOPREPAID = "pseudoprepaid" - RATED = "rated" + ) // Holds system configuration, defaults are overwritten with values from config file if found @@ -60,11 +57,11 @@ type CGRConfig struct { DefaultTOR string // set default type of record DefaultTenant string // set default tenant DefaultSubject string // set default rating subject, useful in case of fallback + RoundingMethod string // Rounding method for the end price: <*up|*middle|*down> + RoundingDecimals int // Number of decimals to round end prices at RaterEnabled bool // start standalone server (no balancer) RaterBalancer string // balancer address host:port RaterListen string // listening address host:port - RaterRoundingMethod string // Rounding method for the end price: - RaterRoundingDecimals int // Number of decimals to round end prices at BalancerEnabled bool BalancerListen string // Json RPC server address SchedulerEnabled bool @@ -114,15 +111,15 @@ func (self *CGRConfig) setDefaults() error { self.StorDBUser = "cgrates" self.StorDBPass = "CGRateS.org" self.RPCEncoding = JSON - self.DefaultReqType = "rated" + self.DefaultReqType = utils.RATED self.DefaultTOR = "0" self.DefaultTenant = "0" self.DefaultSubject = "0" + self.RoundingMethod = utils.ROUNDING_MIDDLE + self.RoundingDecimals = 4 self.RaterEnabled = false self.RaterBalancer = DISABLED self.RaterListen = "127.0.0.1:2012" - self.RaterRoundingMethod = utils.ROUNDING_MIDDLE - self.RaterRoundingDecimals = 4 self.BalancerEnabled = false self.BalancerListen = "127.0.0.1:2013" self.SchedulerEnabled = false @@ -239,6 +236,12 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) { if hasOpt = c.HasOption("global", "default_subject"); hasOpt { cfg.DefaultSubject, _ = c.GetString("global", "default_subject") } + if hasOpt = c.HasOption("global", "rounding_method"); hasOpt { + cfg.RoundingMethod, _ = c.GetString("global", "rounding_method") + } + if hasOpt = c.HasOption("global", "rounding_decimals"); hasOpt { + cfg.RoundingDecimals, _ = c.GetInt("global", "rounding_decimals") + } if hasOpt = c.HasOption("rater", "enabled"); hasOpt { cfg.RaterEnabled, _ = c.GetBool("rater", "enabled") } @@ -248,12 +251,6 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) { if hasOpt = c.HasOption("rater", "listen"); hasOpt { cfg.RaterListen, _ = c.GetString("rater", "listen") } - if hasOpt = c.HasOption("rater", "rounding_method"); hasOpt { - cfg.RaterRoundingMethod, _ = c.GetString("rater", "rounding_method") - } - if hasOpt = c.HasOption("rater", "rounding_decimals"); hasOpt { - cfg.RaterRoundingDecimals, _ = c.GetInt("rater", "rounding_decimals") - } if hasOpt = c.HasOption("balancer", "enabled"); hasOpt { cfg.BalancerEnabled, _ = c.GetBool("balancer", "enabled") } diff --git a/config/config_test.go b/config/config_test.go index 0911bccbf..5b1efcbda 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -47,15 +47,15 @@ func TestDefaults(t *testing.T) { eCfg.StorDBUser = "cgrates" eCfg.StorDBPass = "CGRateS.org" eCfg.RPCEncoding = JSON - eCfg.DefaultReqType = RATED + eCfg.DefaultReqType = utils.RATED eCfg.DefaultTOR = "0" eCfg.DefaultTenant = "0" eCfg.DefaultSubject = "0" + eCfg.RoundingMethod = utils.ROUNDING_MIDDLE + eCfg.RoundingDecimals = 4 eCfg.RaterEnabled = false eCfg.RaterBalancer = DISABLED eCfg.RaterListen = "127.0.0.1:2012" - eCfg.RaterRoundingMethod = utils.ROUNDING_MIDDLE - eCfg.RaterRoundingDecimals = 4 eCfg.BalancerEnabled = false eCfg.BalancerListen = "127.0.0.1:2013" eCfg.SchedulerEnabled = false @@ -142,11 +142,11 @@ func TestConfigFromFile(t *testing.T) { eCfg.DefaultTOR = "test" eCfg.DefaultTenant = "test" eCfg.DefaultSubject = "test" + eCfg.RoundingMethod = "test" + eCfg.RoundingDecimals = 99 eCfg.RaterEnabled = true eCfg.RaterBalancer = "test" eCfg.RaterListen = "test" - eCfg.RaterRoundingMethod = "test" - eCfg.RaterRoundingDecimals = 99 eCfg.BalancerEnabled = true eCfg.BalancerListen = "test" eCfg.SchedulerEnabled = true diff --git a/config/test_data.txt b/config/test_data.txt index b8ed219d9..d4ffed71e 100644 --- a/config/test_data.txt +++ b/config/test_data.txt @@ -19,6 +19,8 @@ default_reqtype = test # Default request type to consider when missing from r default_tor = test # Default Type of Record to consider when missing from requests. default_tenant = test # Default Tenant to consider when missing from requests. default_subject = test # Default rating Subject to consider when missing from requests. +rounding_method = test # Rounding method for floats/costs: +rounding_decimals = 99 # Number of decimals to round floats/costs at [balancer] @@ -29,8 +31,6 @@ listen = test # Balancer listen interface: . enabled = true # Enable Rater service: . balancer = test # Register to Balancer as worker: . listen = test # Rater's listening interface: . -rounding_method = test # Rounding method for the end price: -rounding_decimals = 99 # Number of decimals to round prices at [scheduler] enabled = true # Starts Scheduler service: . diff --git a/data/conf/cgrates.cfg b/data/conf/cgrates.cfg index ace34ff03..72b70a6f1 100644 --- a/data/conf/cgrates.cfg +++ b/data/conf/cgrates.cfg @@ -22,6 +22,8 @@ # default_tor = 0 # Default Type of Record to consider when missing from requests. # default_tenant = 0 # Default Tenant to consider when missing from requests. # default_subject = 0 # Default rating Subject to consider when missing from requests. +# rounding_method = *middle # Rounding method for floats/costs: <*up|*middle|*down> +# rounding_decimals = 4 # Number of decimals to round float/costs at [balancer] @@ -32,8 +34,6 @@ # enabled = false # Enable Rater service: . # balancer = disabled # Register to Balancer as worker: . # listen = 127.0.0.1:2012 # Rater's listening interface: . -# rounding_method = middle # Rounding method for the end price: -# rounding_decimals = 4 # Number of decimals to round end prices at [scheduler] # enabled = false # Starts Scheduler service: . diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index e0051da29..dffcc8c23 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -117,11 +117,11 @@ CREATE TABLE `tp_actions` ( `action` varchar(24) NOT NULL, `balance_type` varchar(24) NOT NULL, `direction` varchar(8) NOT NULL, - `units` DECIMAL(5,2) NOT NULL, + `units` DECIMAL(8,4) NOT NULL, `expiry_time` int(16) NOT NULL, `destination_tag` varchar(24) NOT NULL, `rate_type` varchar(8) NOT NULL, - `rate` DECIMAL(5,4) NOT NULL, + `rate` DECIMAL(8,4) NOT NULL, `minutes_weight` DECIMAL(5,2) NOT NULL, `weight` DECIMAL(5,2) NOT NULL, PRIMARY KEY (`id`), @@ -155,8 +155,8 @@ CREATE TABLE `tp_action_triggers` ( `tag` varchar(24) NOT NULL, `balance_type` varchar(24) NOT NULL, `direction` varchar(8) NOT NULL, - `threshold_type` char(11) NOT NULL, - `threshold_value` DECIMAL(5,4) NOT NULL, + `threshold_type` char(12) NOT NULL, + `threshold_value` DECIMAL(8,4) NOT NULL, `destination_tag` varchar(24) NOT NULL, `actions_tag` varchar(24) NOT NULL, `weight` DECIMAL(5,2) NOT NULL, diff --git a/docs/api_tpactions.rst b/docs/api_tpactions.rst index 4bcebbc46..cd7852b6c 100644 --- a/docs/api_tpactions.rst +++ b/docs/api_tpactions.rst @@ -134,7 +134,7 @@ Queries specific Actions profile on tariff plan. Units float64 // Number of units to add/deduct ExpiryTime int64 // Time when the units will expire DestinationId string // Destination profile id - RateType string // Type of price + RateType string // Type of price <*absolute|*percent> Rate float64 // Price value MinutesWeight float64 // Minutes weight Weight float64 // Action's weight diff --git a/docs/api_tpactiontriggers.rst b/docs/api_tpactiontriggers.rst index 1d1156018..35a2f4132 100644 --- a/docs/api_tpactiontriggers.rst +++ b/docs/api_tpactiontriggers.rst @@ -16,7 +16,7 @@ Creates a new ActionTriggers profile within a tariff plan. } type ApiActionTrigger struct { - BalanceId string // Id of the balance this trigger monitors + BalanceType string // Id of the balance this trigger monitors Direction string // Traffic direction ThresholdType string // This threshold type ThresholdValue float64 // Threshold @@ -25,7 +25,7 @@ Creates a new ActionTriggers profile within a tariff plan. Weight float64 // weight } - Mandatory parameters: ``[]string{"TPid", "ActionTriggersId","BalanceId", "Direction", "ThresholdType", "ThresholdValue", "ActionsId", "Weight"}`` + Mandatory parameters: ``[]string{"TPid", "ActionTriggersId","BalanceType", "Direction", "ThresholdType", "ThresholdValue", "ActionsId", "Weight"}`` *JSON sample*: :: @@ -38,7 +38,7 @@ Creates a new ActionTriggers profile within a tariff plan. "ActionTriggers": [ { "ActionsId": "ACTION_1", - "BalanceId": "MONETARY", + "BalanceType": "MONETARY", "DestinationId": "", "Direction": "OUT", "ThresholdType": "MIN_BALANCE", @@ -124,7 +124,7 @@ Queries specific ActionTriggers profile on tariff plan. } type ApiActionTrigger struct { - BalanceId string // Id of the balance this trigger monitors + BalanceType string // Id of the balance this trigger monitors Direction string // Traffic direction ThresholdType string // This threshold type ThresholdValue float64 // Threshold @@ -143,9 +143,9 @@ Queries specific ActionTriggers profile on tariff plan. "ActionTriggers": [ { "ActionsId": "ACTION_1", - "BalanceId": "MONETARY", + "BalanceType": "*monetary", "DestinationId": "", - "Direction": "OUT", + "Direction": "*out", "ThresholdType": "MIN_BALANCE", "ThresholdValue": 5, "Weight": 10 diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index b2f59a523..503e0b290 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -375,6 +375,53 @@ func (self *TPCSVImporter) importActionTimings(fn string) error { } func (self *TPCSVImporter) importActionTriggers(fn string) error { + log.Printf("Processing file: <%s> ", fn) + fParser, err := NewTPCSVFileParser(self.DirPath, fn) + if err != nil { + return err + } + lineNr := 0 + for { + lineNr++ + record, err := fParser.ParseNextLine() + if err == io.EOF { // Reached end of file + break + } else if err != nil { + if self.Verbose { + log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) + } + continue + } + tag, balanceType, direction, thresholdType, destinationTag, actionsTag := record[0], record[1], record[2], record[3], record[5], record[6] + threshold, err := strconv.ParseFloat(record[4], 64) + if err != nil { + if self.Verbose { + log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) + } + continue + } + weight, err := strconv.ParseFloat(record[7], 64) + if err != nil { + if self.Verbose { + log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) + } + continue + } + at := &ActionTrigger{ + BalanceId: balanceType, + Direction: direction, + ThresholdType: thresholdType, + ThresholdValue: threshold, + DestinationId: destinationTag, + Weight: weight, + ActionsId: actionsTag, + } + if err := self.StorDb.SetTPActionTriggers(self.TPid, map[string][]*ActionTrigger{tag: []*ActionTrigger{at}}); err != nil { + if self.Verbose { + log.Printf("Ignoring line %d, storDb operational error: <%s> ", lineNr, err.Error()) + } + } + } return nil } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 38a7aab55..fc784e15d 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -123,7 +123,7 @@ type ApiTPActionTriggers struct { } type ApiActionTrigger struct { - BalanceId string // Id of the balance this trigger monitors + BalanceType string // Type of balance this trigger monitors Direction string // Traffic direction ThresholdType string // This threshold type ThresholdValue float64 // Threshold diff --git a/utils/consts.go b/utils/consts.go index 944def977..9ea654ec8 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -49,8 +49,8 @@ const ( ACTION_TIMINGS_NRCOLS = 4 ACTION_TRIGGERS_NRCOLS = 8 ACCOUNT_ACTIONS_NRCOLS = 5 - ROUNDING_UP = "up" - ROUNDING_MIDDLE = "middle" - ROUNDING_DOWN = "down" + ROUNDING_UP = "*up" + ROUNDING_MIDDLE = "*middle" + ROUNDING_DOWN = "*down" COMMENT_CHAR = '#' ) diff --git a/utils/coreutils.go b/utils/coreutils.go index defc797c0..51a588610 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -78,11 +78,11 @@ func Round(x float64, prec int, method string) float64 { _, frac := math.Modf(intermed) switch method { - case "*up": + case ROUNDING_UP: rounder = math.Ceil(intermed) - case "*down": + case ROUNDING_DOWN: rounder = math.Floor(intermed) - case "*middle": + case ROUNDING_MIDDLE: if frac >= 0.5 { rounder = math.Ceil(intermed) } else { diff --git a/utils/utils_test.go b/utils/utils_test.go index fc9a2f2ed..e55775f10 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -41,7 +41,7 @@ func TestUUID(t *testing.T) { } func TestRoundUp(t *testing.T) { - result := Round(12.52, 0, "*middle") + result := Round(12.52, 0, ROUNDING_UP) expected := 13.0 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -49,7 +49,7 @@ func TestRoundUp(t *testing.T) { } func TestRoundUpMiddle(t *testing.T) { - result := Round(12.5, 0, "*middle") + result := Round(12.5, 0, ROUNDING_UP) expected := 13.0 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -57,7 +57,7 @@ func TestRoundUpMiddle(t *testing.T) { } func TestRoundDown(t *testing.T) { - result := Round(12.49, 0, "*middle") + result := Round(12.49, 0, ROUNDING_MIDDLE) expected := 12.0 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -65,7 +65,7 @@ func TestRoundDown(t *testing.T) { } func TestRoundPrec(t *testing.T) { - result := Round(12.49, 1, "*middle") + result := Round(12.49, 1, ROUNDING_UP) expected := 12.5 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -73,7 +73,7 @@ func TestRoundPrec(t *testing.T) { } func TestRoundPrecNothing(t *testing.T) { - result := Round(12.49, 2, "*middle") + result := Round(12.49, 2, ROUNDING_MIDDLE) expected := 12.49 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -89,7 +89,7 @@ func TestRoundPrecNoTouch(t *testing.T) { } func TestRoundByMethodUp1(t *testing.T) { - result := Round(12.49, 1, "*up") + result := Round(12.49, 1, ROUNDING_UP) expected := 12.5 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -97,7 +97,7 @@ func TestRoundByMethodUp1(t *testing.T) { } func TestRoundByMethodUp2(t *testing.T) { - result := Round(12.21, 1, "*up") + result := Round(12.21, 1, ROUNDING_UP) expected := 12.3 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result) @@ -105,15 +105,15 @@ func TestRoundByMethodUp2(t *testing.T) { } func TestRoundByMethodDown1(t *testing.T) { - result := Round(12.49, 1, "*down") + result := Round(12.49, 1, ROUNDING_DOWN) expected := 12.4 if result != expected { - t.Errorf("Error rounding up: sould be %v was %v", expected, result) + t.Errorf("Error rounding down: sould be %v was %v", expected, result) } } func TestRoundByMethodDown2(t *testing.T) { - result := Round(12.21, 1, "*down") + result := Round(12.21, 1, ROUNDING_DOWN) expected := 12.2 if result != expected { t.Errorf("Error rounding up: sould be %v was %v", expected, result)