diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql
index 43ffe8412..4f93413dc 100644
--- a/data/storage/mysql/create_cdrs_tables.sql
+++ b/data/storage/mysql/create_cdrs_tables.sql
@@ -49,7 +49,6 @@ CREATE TABLE cdrs_extra (
DROP TABLE IF EXISTS cost_details;
CREATE TABLE cost_details (
id int(11) NOT NULL AUTO_INCREMENT,
- cost_time datetime NOT NULL,
cgrid char(40) NOT NULL,
runid varchar(64) NOT NULL,
tor varchar(16) NOT NULL,
@@ -75,7 +74,6 @@ CREATE TABLE cost_details (
DROP TABLE IF EXISTS rated_cdrs;
CREATE TABLE `rated_cdrs` (
id int(11) NOT NULL AUTO_INCREMENT,
- mediation_time datetime NOT NULL,
cgrid char(40) NOT NULL,
runid varchar(64) NOT NULL,
reqtype varchar(24) NOT NULL,
diff --git a/data/storage/postgres/create_cdrs_tables.sql b/data/storage/postgres/create_cdrs_tables.sql
index 63b3cbef0..0f2f22ee3 100644
--- a/data/storage/postgres/create_cdrs_tables.sql
+++ b/data/storage/postgres/create_cdrs_tables.sql
@@ -47,8 +47,6 @@ CREATE TABLE cdrs_extra (
DROP TABLE IF EXISTS cost_details;
CREATE TABLE cost_details (
id SERIAL PRIMARY KEY,
- cost_time TIMESTAMP NOT NULL,
- cost_source VARCHAR(64) NOT NULL,
cgrid CHAR(40) NOT NULL,
runid VARCHAR(64) NOT NULL,
tor VARCHAR(16) NOT NULL,
@@ -60,6 +58,7 @@ CREATE TABLE cost_details (
destination VARCHAR(128) NOT NULL,
cost NUMERIC(20,4) NOT NULL,
timespans text,
+ cost_source VARCHAR(64) NOT NULL,
created_at TIMESTAMP,
updated_at TIMESTAMP,
deleted_at TIMESTAMP,
@@ -72,7 +71,6 @@ CREATE TABLE cost_details (
DROP TABLE IF EXISTS rated_cdrs;
CREATE TABLE rated_cdrs (
id SERIAL PRIMARY KEY,
- mediation_time TIMESTAMP NOT NULL,
cgrid CHAR(40) NOT NULL,
runid VARCHAR(64) NOT NULL,
reqtype VARCHAR(24) NOT NULL,
diff --git a/engine/models.go b/engine/models.go
index c6743a38c..6b18e41e9 100644
--- a/engine/models.go
+++ b/engine/models.go
@@ -296,7 +296,7 @@ type TblCdrsPrimary struct {
}
func (t TblCdrsPrimary) TableName() string {
- return "cdrs_primary"
+ return utils.TBL_CDRS_PRIMARY
}
type TblCdrsExtra struct {
@@ -308,12 +308,11 @@ type TblCdrsExtra struct {
}
func (t TblCdrsExtra) TableName() string {
- return "cdrs_extra"
+ return utils.TBL_CDRS_EXTRA
}
type TblCostDetail struct {
Id int64
- CostSource string
Cgrid string
Runid string
Tor string
@@ -325,29 +324,37 @@ type TblCostDetail struct {
Destination string
Cost float64
Timespans string
+ CostSource string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
-type TblRatedCdr struct {
- Id int64
- MediationTime time.Time
- Cgrid string
- Runid string
- Reqtype string
- Direction string
- Tenant string
- Category string
- Account string
- Subject string
- Destination string
- SetupTime time.Time
- AnswerTime time.Time
- Usage float64
- Cost float64
- ExtraInfo string
- CreatedAt time.Time
- UpdatedAt time.Time
- DeletedAt time.Time
+func (t TblCostDetail) TableName() string {
+ return utils.TBL_COST_DETAILS
+}
+
+type TblRatedCdr struct {
+ Id int64
+ Cgrid string
+ Runid string
+ Reqtype string
+ Direction string
+ Tenant string
+ Category string
+ Account string
+ Subject string
+ Destination string
+ SetupTime time.Time
+ AnswerTime time.Time
+ Usage float64
+ Cost float64
+ ExtraInfo string
+ CreatedAt time.Time
+ UpdatedAt time.Time
+ DeletedAt time.Time
+}
+
+func (t TblRatedCdr) TableName() string {
+ return utils.TBL_RATED_CDRS
}
diff --git a/engine/storage_mysql.go b/engine/storage_mysql.go
index 6520f8ed7..852e17f32 100644
--- a/engine/storage_mysql.go
+++ b/engine/storage_mysql.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package engine
import (
+ "encoding/json"
"fmt"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
@@ -75,3 +76,32 @@ func (self *MySQLStorage) SetTPTiming(tm *utils.ApierTPTiming) error {
}
return nil
}
+
+func (self *MySQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (err error) {
+ tss, err := json.Marshal(cc.Timespans)
+ if err != nil {
+ Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err))
+ return err
+ }
+ _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,tor,direction,tenant,category,account,subject,destination,cost,timespans,cost_source,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s',%f,'%s','%s',%d) ON DUPLICATE KEY UPDATE tor=values(tor),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),cost=values(cost),timespans=values(timespans),cost_source=values(cost_source),updated_at=%d",
+ utils.TBL_COST_DETAILS,
+ cgrid,
+ runid,
+ cc.TOR,
+ cc.Direction,
+ cc.Tenant,
+ cc.Category,
+ cc.Account,
+ cc.Subject,
+ cc.Destination,
+ cc.Cost,
+ tss,
+ source,
+ time.Now().Unix(),
+ time.Now().Unix()))
+ if err != nil {
+ Logger.Err(fmt.Sprintf("failed to execute insert statement: %v", err))
+ return err
+ }
+ return nil
+}
diff --git a/engine/storage_mysql_local_test.go b/engine/storage_mysql_local_test.go
index d2dea9c59..2d82dd9d5 100644
--- a/engine/storage_mysql_local_test.go
+++ b/engine/storage_mysql_local_test.go
@@ -69,6 +69,16 @@ func TestMySQLSetGetTPTiming(t *testing.T) {
} else if !reflect.DeepEqual(tm, tmgs[tm.TimingId]) {
t.Errorf("Expecting: %+v, received: %+v", tm, tmgs[tm.TimingId])
}
+ // Update
+ tm.Time = "00:00:01"
+ if err := mysqlDb.SetTPTiming(tm); err != nil {
+ t.Error(err.Error())
+ }
+ if tmgs, err := mysqlDb.GetTpTimings(TEST_SQL, tm.TimingId); err != nil {
+ t.Error(err.Error())
+ } else if !reflect.DeepEqual(tm, tmgs[tm.TimingId]) {
+ t.Errorf("Expecting: %+v, received: %+v", tmgs[tm.TimingId])
+ }
}
func TestMySQLSetGetTPDestination(t *testing.T) {
@@ -532,6 +542,16 @@ func TestMySQLCallCost(t *testing.T) {
} else if !reflect.DeepEqual(cc, ccRcv) {
t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv)
}
+ // UPDATE test here
+ cc.Category = "premium_call"
+ if err := mysqlDb.LogCallCost(cgrId, TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil {
+ t.Error(err.Error())
+ }
+ if ccRcv, err := mysqlDb.GetCallCostLog(cgrId, TEST_SQL, utils.DEFAULT_RUNID); err != nil {
+ t.Error(err.Error())
+ } else if !reflect.DeepEqual(cc, ccRcv) {
+ t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv)
+ }
}
func TestMySQLGetStoredCdrs(t *testing.T) {
diff --git a/engine/storage_postgres.go b/engine/storage_postgres.go
index 338a0ac00..26a3ab6e8 100644
--- a/engine/storage_postgres.go
+++ b/engine/storage_postgres.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package engine
import (
+ "encoding/json"
"fmt"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
@@ -70,13 +71,51 @@ func (self *PostgresStorage) SetTPTiming(tm *utils.ApierTPTiming) error {
return nil //Nothing to set
}
tx := self.db.Begin()
- if err := tx.Where(&TpTiming{Tpid: tm.TPid, Tag: tm.TimingId}).Delete(TpTiming{}).Error; err != nil {
- tx.Rollback()
- return err
- }
if err := tx.Save(&TpTiming{Tpid: tm.TPid, Tag: tm.TimingId, Years: tm.Years, Months: tm.Months, MonthDays: tm.MonthDays, WeekDays: tm.WeekDays, Time: tm.Time, CreatedAt: time.Now()}).Error; err != nil {
tx.Rollback()
- return err
+ tx = self.db.Begin()
+ updated := tx.Model(TpTiming{}).Where(&TpTiming{Tpid: tm.TPid, Tag: tm.TimingId}).Updates(&TpTiming{Years: tm.Years, Months: tm.Months, MonthDays: tm.MonthDays, WeekDays: tm.WeekDays, Time: tm.Time})
+ if updated.Error != nil {
+ tx.Rollback()
+ return updated.Error
+ }
+ }
+ tx.Commit()
+ return nil
+}
+
+func (self *PostgresStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (err error) {
+ tss, err := json.Marshal(cc.Timespans)
+ if err != nil {
+ Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err))
+ return err
+ }
+ tx := self.db.Begin()
+ cd := &TblCostDetail{
+ Cgrid: cgrid,
+ Runid: runid,
+ Tor: cc.TOR,
+ Direction: cc.Direction,
+ Tenant: cc.Tenant,
+ Category: cc.Category,
+ Account: cc.Account,
+ Subject: cc.Subject,
+ Destination: cc.Destination,
+ Cost: cc.Cost,
+ Timespans: string(tss),
+ CostSource: source,
+ CreatedAt: time.Now(),
+ }
+
+ if tx.Save(cd).Error != nil { // Check further since error does not properly reflect duplicates here (sql: no rows in result set)
+ tx.Rollback()
+ tx = self.db.Begin()
+ updated := tx.Model(TblCostDetail{}).Where(&TblCostDetail{Cgrid: cgrid, Runid: runid}).Updates(&TblCostDetail{Tor: cc.TOR, Direction: cc.Direction, Tenant: cc.Tenant, Category: cc.Category,
+ Account: cc.Account, Subject: cc.Subject, Destination: cc.Destination, Cost: cc.Cost, Timespans: string(tss), CostSource: source, UpdatedAt: time.Now()})
+ if updated.Error != nil {
+ tx.Rollback()
+ return updated.Error
+ }
}
tx.Commit()
return nil
diff --git a/engine/storage_psql_local_test.go b/engine/storage_psql_local_test.go
index 6e5084591..8f404d1b0 100644
--- a/engine/storage_psql_local_test.go
+++ b/engine/storage_psql_local_test.go
@@ -69,6 +69,16 @@ func TestPSQLSetGetTPTiming(t *testing.T) {
} else if !reflect.DeepEqual(tm, tmgs[tm.TimingId]) {
t.Errorf("Expecting: %+v, received: %+v", tmgs[tm.TimingId])
}
+ // Update
+ tm.Time = "00:00:01"
+ if err := psqlDb.SetTPTiming(tm); err != nil {
+ t.Error(err.Error())
+ }
+ if tmgs, err := psqlDb.GetTpTimings(TEST_SQL, tm.TimingId); err != nil {
+ t.Error(err.Error())
+ } else if !reflect.DeepEqual(tm, tmgs[tm.TimingId]) {
+ t.Errorf("Expecting: %+v, received: %+v", tmgs[tm.TimingId])
+ }
}
func TestPSQLSetGetTPDestination(t *testing.T) {
@@ -472,38 +482,6 @@ func TestPSQLSetCdr(t *testing.T) {
}
}
-/*
-func TestPSQLSetRatedCdr(t *testing.T) {
- if !*testLocal {
- return
- }
- strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: "rated",
- Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
- Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
- strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
- strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: "prepaid",
- Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
- Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
- strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
- strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: "rated",
- Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
- SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
- Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- MediationRunId: "wholesale_run", Cost: 1.201}
- strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
-
- for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
- if err := psqlDb.SetRatedCdr(cdr, ""); err != nil {
- t.Error(err.Error())
- }
- }
-}
-
-
func TestPSQLCallCost(t *testing.T) {
if !*testLocal {
return
@@ -536,9 +514,51 @@ func TestPSQLCallCost(t *testing.T) {
} else if !reflect.DeepEqual(cc, ccRcv) {
t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv)
}
+ // UPDATE test here
+ cc.Category = "premium_call"
+ if err := psqlDb.LogCallCost(cgrId, TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil {
+ t.Error(err.Error())
+ }
+ if ccRcv, err := psqlDb.GetCallCostLog(cgrId, TEST_SQL, utils.DEFAULT_RUNID); err != nil {
+ t.Error(err.Error())
+ } else if !reflect.DeepEqual(cc, ccRcv) {
+ t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv)
+ }
}
+/*
+func TestPSQLSetRatedCdr(t *testing.T) {
+ if !*testLocal {
+ return
+ }
+ strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: "rated",
+ Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
+ SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
+ Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
+ MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
+ strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
+ strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: "prepaid",
+ Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
+ SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
+ Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
+ MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
+ strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
+ strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: "rated",
+ Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
+ SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
+ Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
+ MediationRunId: "wholesale_run", Cost: 1.201}
+ strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
+ for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
+ if err := psqlDb.SetRatedCdr(cdr, ""); err != nil {
+ t.Error(err.Error())
+ }
+ }
+}
+*/
+
+/*
func TestPSQLGetStoredCdrs(t *testing.T) {
if !*testLocal {
return
diff --git a/engine/storage_sql.go b/engine/storage_sql.go
index ae97b9dd6..60aa4bfb0 100644
--- a/engine/storage_sql.go
+++ b/engine/storage_sql.go
@@ -647,7 +647,7 @@ func (self *SQLStorage) SetTPAccountActions(tpid string, aas map[string]*utils.T
tx.Rollback()
return err
}
- saved := tx.Save(TpAccountAction{
+ saved := tx.Save(&TpAccountAction{
Tpid: aa.TPid,
Loadid: aa.LoadId,
Tenant: aa.Tenant,
@@ -668,33 +668,7 @@ func (self *SQLStorage) SetTPAccountActions(tpid string, aas map[string]*utils.T
}
func (self *SQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (err error) {
- //ToDo: Add cgrid to logCallCost
- if self.Db == nil {
- //timespans.Logger.Warning("Cannot write log to database.")
- return
- }
- tss, err := json.Marshal(cc.Timespans)
- if err != nil {
- Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err))
- }
- _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cost_time,cost_source,cgrid,runid,tor,direction,tenant,category,account,subject,destination,cost,timespans) VALUES (now(),'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%f,'%s') ON DUPLICATE KEY UPDATE cost_time=now(),cost_source=values(cost_source),tor=values(tor),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),cost=values(cost),timespans=values(timespans)",
- utils.TBL_COST_DETAILS,
- source,
- cgrid,
- runid,
- cc.TOR,
- cc.Direction,
- cc.Tenant,
- cc.Category,
- cc.Account,
- cc.Subject,
- cc.Destination,
- cc.Cost,
- tss))
- if err != nil {
- Logger.Err(fmt.Sprintf("failed to execute insert statement: %v", err))
- }
- return
+ return errors.New(utils.ERR_NOT_IMPLEMENTED)
}
func (self *SQLStorage) GetCallCostLog(cgrid, source, runid string) (cc *CallCost, err error) {
@@ -763,7 +737,7 @@ func (self *SQLStorage) SetCdr(cdr *utils.StoredCdr) (err error) {
}
func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string) (err error) {
- _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (mediation_time,cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,cost,extra_info) VALUES (now(),'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,%f,'%s') ON DUPLICATE KEY UPDATE mediation_time=now(),reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),cost=values(cost),extra_info=values(extra_info)",
+ _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,cost,extra_info,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,%f,'%s',%d) ON DUPLICATE KEY UPDATE reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),cost=values(cost),extra_info=values(extra_info), updated_at=%d",
utils.TBL_RATED_CDRS,
storedCdr.CgrId,
storedCdr.MediationRunId,
@@ -778,7 +752,9 @@ func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string
storedCdr.AnswerTime,
storedCdr.Usage.Seconds(),
storedCdr.Cost,
- extraInfo))
+ extraInfo,
+ time.Now().Unix(),
+ time.Now().Unix()))
if err != nil {
Logger.Err(fmt.Sprintf("failed to execute cdr insert statement: %s", err.Error()))
}