diff --git a/cmd/cgr-loader/cgr-mediator.go b/cmd/cgr-loader/cgr-mediator.go
deleted file mode 100644
index 1e4af7936..000000000
--- a/cmd/cgr-loader/cgr-mediator.go
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2012 Radu Ioan Fericean
-
-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 main
-
-import (
- "bufio"
- "database/sql"
- "encoding/csv"
- "flag"
- "fmt"
- _ "github.com/bmizerany/pq"
- "github.com/cgrates/cgrates/timespans"
- "log"
- "net/rpc/jsonrpc"
- "os"
- "time"
-)
-
-var (
- cdrFile = flag.String("freeswitchcdr", "Master.csv", "Freeswitch Master CSV CDR file.")
- resultFile = flag.String("resultfile", "out.csv", "Generated file containing CDR and price info.")
- host = flag.String("host", "localhost", "The host to connect to. Values that start with / are for UNIX domain sockets.")
- port = flag.String("port", "5432", "The port to bind to.")
- dbName = flag.String("dbname", "cgrates", "The name of the database to connect to.")
- user = flag.String("user", "", "The user to sign in as.")
- password = flag.String("password", "", "The user's password.")
-)
-
-func readDbRecord(db *sql.DB, searchedUUID string) (cc *timespans.CallCost, timespansText string, err error) {
- row := db.QueryRow(fmt.Sprintf("SELECT * FROM callcosts WHERE uuid='%s'", searchedUUID))
- var uuid string
- cc = ×pans.CallCost{}
- err = row.Scan(&uuid, &cc.Direction, &cc.Tenant, &cc.TOR, &cc.Subject, &cc.Destination, &cc.Cost, &cc.ConnectFee, ×pansText)
- return
-}
-
-func main() {
- flag.Parse()
- useDB := true
- file, err := os.Open(*cdrFile)
- defer file.Close()
- if err != nil {
- log.Fatal(err)
- }
- db, err := sql.Open("postgres", fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable", *host, *port, *dbName, *user, *password))
- defer db.Close()
- if err != nil {
- log.Printf("failed to open the database: %v", err)
- useDB = false
- }
- csvReader := csv.NewReader(bufio.NewReader(file))
- client, err := jsonrpc.Dial("tcp", "localhost:2001")
- useRPC := true
- if err != nil {
- log.Printf("Could not connect to rater server: %v!", err)
- useRPC = false
- }
- for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
- uuid := record[10]
- t, _ := time.Parse("2012-05-21 17:48:20", record[5])
- fmt.Println(t)
- if useDB {
- cc, timespansText, err := readDbRecord(db, uuid)
- if err != nil && useRPC {
- // try getting the price from the rater
-
- tenant := record[0]
- subject := record[1]
- dest := record[2]
- t1, _ := time.Parse("2012-05-21 17:48:20", record[5])
- t2, _ := time.Parse("2012-05-21 17:48:20", record[6])
- cd := timespans.CallDescriptor{
- Direction: "OUT",
- Tenant: tenant,
- TOR: "0",
- Subject: subject,
- Destination: dest,
- TimeStart: t1,
- TimeEnd: t2}
- client.Call("Responder.GetCost", cd, cc)
- }
- _ = timespansText
- //log.Print(cc, timespansText)
- }
- }
-}
diff --git a/cmd/cgr-loader/helpers.go b/cmd/cgr-loader/helpers.go
index 5c2fd8e54..1f4bd87ed 100644
--- a/cmd/cgr-loader/helpers.go
+++ b/cmd/cgr-loader/helpers.go
@@ -27,11 +27,11 @@ import (
)
type Rate struct {
- DestinationsTag string
- ConnectFee, Price, BillingUnit float64
+ DestinationsTag string
+ ConnectFee, Price, PricedUnits, RateIncrements float64
}
-func NewRate(destinationsTag, connectFee, price, billingUnit string) (r *Rate, err error) {
+func NewRate(destinationsTag, connectFee, price, pricedUnits, rateIncrements string) (r *Rate, err error) {
cf, err := strconv.ParseFloat(connectFee, 64)
if err != nil {
log.Printf("Error parsing connect fee from: %v", connectFee)
@@ -42,16 +42,22 @@ func NewRate(destinationsTag, connectFee, price, billingUnit string) (r *Rate, e
log.Printf("Error parsing price from: %v", price)
return
}
- bu, err := strconv.ParseFloat(billingUnit, 64)
+ pu, err := strconv.ParseFloat(pricedUnits, 64)
if err != nil {
- log.Printf("Error parsing billing unit from: %v", billingUnit)
+ log.Printf("Error parsing priced units from: %v", pricedUnits)
+ return
+ }
+ ri, err := strconv.ParseFloat(rateIncrements, 64)
+ if err != nil {
+ log.Printf("Error parsing rates increments from: %v", rateIncrements)
return
}
r = &Rate{
DestinationsTag: destinationsTag,
ConnectFee: cf,
Price: p,
- BillingUnit: bu,
+ PricedUnits: pu,
+ RateIncrements: ri,
}
return
}
@@ -99,14 +105,15 @@ func NewRateTiming(ratesTag string, timing *Timing, weight string) (rt *RateTimi
func (rt *RateTiming) GetInterval(r *Rate) (i *timespans.Interval) {
i = ×pans.Interval{
- Months: rt.timing.Months,
- MonthDays: rt.timing.MonthDays,
- WeekDays: rt.timing.WeekDays,
- StartTime: rt.timing.StartTime,
- Weight: rt.Weight,
- ConnectFee: r.ConnectFee,
- Price: r.Price,
- BillingUnit: r.BillingUnit,
+ Months: rt.timing.Months,
+ MonthDays: rt.timing.MonthDays,
+ WeekDays: rt.timing.WeekDays,
+ StartTime: rt.timing.StartTime,
+ Weight: rt.Weight,
+ ConnectFee: r.ConnectFee,
+ Price: r.Price,
+ PricedUnits: r.PricedUnits,
+ RateIncrements: r.RateIncrements,
}
return
}
diff --git a/cmd/cgr-loader/rates.go b/cmd/cgr-loader/rates.go
index e80395fdf..5cd9d269d 100644
--- a/cmd/cgr-loader/rates.go
+++ b/cmd/cgr-loader/rates.go
@@ -19,9 +19,9 @@ along with this program. If not, see
package main
import (
+ "fmt"
"github.com/cgrates/cgrates/timespans"
"log"
- "fmt"
"time"
)
@@ -78,7 +78,7 @@ func (csvr *CSVReader) loadRates(fn string) {
// skip header line
continue
}
- r, err := NewRate(record[1], record[2], record[3], record[4])
+ r, err := NewRate(record[1], record[2], record[3], record[4], record[5])
if err != nil {
continue
}
diff --git a/data/Rates.csv b/data/Rates.csv
index e6946c608..043c42d1a 100644
--- a/data/Rates.csv
+++ b/data/Rates.csv
@@ -1,9 +1,9 @@
-Tag,DestinationsTag,ConnectFee,Price,BillingUnit
-RT_STANDARD,GERMANY,0,0.2,1
-RT_STANDARD,GERMANY_O2,0,0.1,1
-RT_STANDARD,GERMANY_PREMIUM,0,0.1,1
-RT_DEFAULT,ALL,0,0.1,1
-RT_STD_WEEKEND,GERMANY,0,0.1,1
-RT_STD_WEEKEND,GERMANY_O2,0,0.05,1
-P1,NAT,0,1,1
-P2,NAT,0,0.5,1
\ No newline at end of file
+Tag,DestinationsTag,ConnectFee,Price,PricedUnits,RateIncrements
+RT_STANDARD,GERMANY,0,0.2,60,1
+RT_STANDARD,GERMANY_O2,0,0.1,60,1
+RT_STANDARD,GERMANY_PREMIUM,0,0.1,60,1
+RT_DEFAULT,ALL,0,0.1,60,1
+RT_STD_WEEKEND,GERMANY,0,0.1,60,1
+RT_STD_WEEKEND,GERMANY_O2,0,0.05,60,1
+P1,NAT,0,1,1,1
+P2,NAT,0,0.5,1,1
diff --git a/timespans/actions_test.go b/timespans/actions_test.go
index 0d82d69b7..23ab5c9fb 100644
--- a/timespans/actions_test.go
+++ b/timespans/actions_test.go
@@ -31,15 +31,16 @@ func init() {
func TestActionTimingStoreRestore(t *testing.T) {
i := &Interval{
- Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December},
- MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
- WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
- StartTime: "18:00:00",
- EndTime: "00:00:00",
- Weight: 10.0,
- ConnectFee: 0.0,
- Price: 1.0,
- BillingUnit: 1.0,
+ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December},
+ MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
+ WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
+ StartTime: "18:00:00",
+ EndTime: "00:00:00",
+ Weight: 10.0,
+ ConnectFee: 0.0,
+ Price: 1.0,
+ PricedUnits: 60,
+ RateIncrements: 1,
}
at := &ActionTiming{
Id: "some uuid",
@@ -50,7 +51,7 @@ func TestActionTimingStoreRestore(t *testing.T) {
ActionsId: "Commando",
}
r := at.store()
- if string(r) != "some uuid|test|one,two,three|1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5;18:00:00;00:00:00;10;0;1;1|10|Commando" {
+ if string(r) != "some uuid|test|one,two,three|1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5;18:00:00;00:00:00;10;0;1;60;1|10|Commando" {
t.Errorf("Error serializing action timing: %v", string(r))
}
o := &ActionTiming{}
diff --git a/timespans/activationperiod_test.go b/timespans/activationperiod_test.go
index 6fe1ac5df..20e15e068 100644
--- a/timespans/activationperiod_test.go
+++ b/timespans/activationperiod_test.go
@@ -19,9 +19,9 @@ along with this program. If not, see
package timespans
import (
+ "encoding/json"
"reflect"
"testing"
- "encoding/json"
"time"
//"log"
)
@@ -42,7 +42,7 @@ func TestApStoreRestore(t *testing.T) {
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
result := ap.store()
- expected := "1328106601000000000|2;1;3,4;14:30:00;15:00:00;0;0;0;0"
+ expected := "1328106601000000000|2;1;3,4;14:30:00;15:00:00;0;0;0;0;0"
if result != expected {
t.Errorf("Expected %q was %q", expected, result)
}
@@ -76,7 +76,7 @@ func TestApStoreRestoreJson(t *testing.T) {
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
result, _ := json.Marshal(ap)
- expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":[2],\"MonthDays\":[1],\"WeekDays\":[3,4],\"StartTime\":\"14:30:00\",\"EndTime\":\"15:00:00\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"BillingUnit\":0}]}"
+ expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":[2],\"MonthDays\":[1],\"WeekDays\":[3,4],\"StartTime\":\"14:30:00\",\"EndTime\":\"15:00:00\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0}]}"
if string(result) != expected {
t.Errorf("Expected %q was %q", expected, result)
}
@@ -93,7 +93,7 @@ func TestApStoreRestoreBlank(t *testing.T) {
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
result, _ := json.Marshal(ap)
- expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":null,\"MonthDays\":null,\"WeekDays\":null,\"StartTime\":\"\",\"EndTime\":\"\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"BillingUnit\":0}]}"
+ expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":null,\"MonthDays\":null,\"WeekDays\":null,\"StartTime\":\"\",\"EndTime\":\"\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"PricedUnits\":0,\"RateIncrements\":0}]}"
if string(result) != expected {
t.Errorf("Expected %q was %q", expected, result)
}
diff --git a/timespans/interval.go b/timespans/interval.go
index cc5326757..d0266e099 100644
--- a/timespans/interval.go
+++ b/timespans/interval.go
@@ -31,11 +31,11 @@ import (
Defines a time interval for which a certain set of prices will apply
*/
type Interval struct {
- Months Months
- MonthDays MonthDays
- WeekDays WeekDays
- StartTime, EndTime string // ##:##:## format
- Weight, ConnectFee, Price, BillingUnit float64
+ Months Months
+ MonthDays MonthDays
+ WeekDays WeekDays
+ StartTime, EndTime string // ##:##:## format
+ Weight, ConnectFee, Price, PricedUnits, RateIncrements float64
}
/*
@@ -139,7 +139,8 @@ func (i *Interval) store() (result string) {
result += strconv.FormatFloat(i.Weight, 'f', -1, 64) + ";"
result += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + ";"
result += strconv.FormatFloat(i.Price, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64)
+ result += strconv.FormatFloat(i.PricedUnits, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(i.RateIncrements, 'f', -1, 64)
return
}
@@ -156,5 +157,6 @@ func (i *Interval) restore(input string) {
i.Weight, _ = strconv.ParseFloat(is[5], 64)
i.ConnectFee, _ = strconv.ParseFloat(is[6], 64)
i.Price, _ = strconv.ParseFloat(is[7], 64)
- i.BillingUnit, _ = strconv.ParseFloat(is[8], 64)
+ i.PricedUnits, _ = strconv.ParseFloat(is[8], 64)
+ i.RateIncrements, _ = strconv.ParseFloat(is[9], 64)
}
diff --git a/timespans/interval_test.go b/timespans/interval_test.go
index 9276db1f2..88c2d6916 100644
--- a/timespans/interval_test.go
+++ b/timespans/interval_test.go
@@ -26,18 +26,19 @@ import (
func TestIntervalStoreRestore(t *testing.T) {
i := &Interval{
- Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December},
- MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
- WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
- StartTime: "18:00:00",
- EndTime: "00:00:00",
- Weight: 10.0,
- ConnectFee: 0.0,
- Price: 1.0,
- BillingUnit: 1.0,
+ Months: Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December},
+ MonthDays: MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
+ WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
+ StartTime: "18:00:00",
+ EndTime: "00:00:00",
+ Weight: 10.0,
+ ConnectFee: 0.0,
+ Price: 1.0,
+ PricedUnits: 60,
+ RateIncrements: 1,
}
r := i.store()
- if string(r) != "1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5;18:00:00;00:00:00;10;0;1;1" {
+ if string(r) != "1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5;18:00:00;00:00:00;10;0;1;60;1" {
t.Errorf("Error serializing interval: %v", string(r))
}
o := &Interval{}
diff --git a/timespans/timespans.go b/timespans/timespans.go
index 16034a3d4..3f074310f 100644
--- a/timespans/timespans.go
+++ b/timespans/timespans.go
@@ -21,6 +21,7 @@ package timespans
import (
"fmt"
//"log"
+ "math"
"time"
)
@@ -59,10 +60,15 @@ func (ts *TimeSpan) getCost(cd *CallDescriptor) (cost float64) {
if ts.Interval == nil {
return 0
}
- if ts.Interval.BillingUnit > 0 {
- cost = (ts.GetDuration().Seconds() / ts.Interval.BillingUnit) * ts.Interval.Price
+ duration := ts.GetDuration().Seconds()
+ i := ts.Interval
+ if i.RateIncrements == 0 {
+ i.RateIncrements = 1
+ }
+ if i.PricedUnits != 0 {
+ cost = math.Ceil(duration/i.RateIncrements) * i.RateIncrements * (i.Price / i.PricedUnits)
} else {
- cost = ts.GetDuration().Seconds() * ts.Interval.Price
+ cost = math.Ceil(duration/i.RateIncrements) * i.RateIncrements * i.Price
}
// if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
// userBalance.mux.RLock()
diff --git a/timespans/timespans_test.go b/timespans/timespans_test.go
index a65056a4f..40b40f005 100644
--- a/timespans/timespans_test.go
+++ b/timespans/timespans_test.go
@@ -196,8 +196,9 @@ func TestTimespanGetCost(t *testing.T) {
if ts1.getCost(cd) != 600 {
t.Error("Expected 10 got ", ts1.getCost(cd))
}
- ts1.Interval.BillingUnit = .1
- if ts1.getCost(cd) != 6000 {
+ ts1.Interval.PricedUnits = 60
+ ts1.Interval.RateIncrements = 1
+ if ts1.getCost(cd) != 10 {
t.Error("Expected 6000 got ", ts1.getCost(cd))
}
}