Different GetCallCost for MySQL and Postgres

This commit is contained in:
DanB
2014-11-13 12:01:42 +01:00
parent afb4a7e39f
commit cbd3e57397
8 changed files with 183 additions and 95 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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
}

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
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
}

View File

@@ -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) {

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
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

View File

@@ -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

View File

@@ -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()))
}