diff --git a/engine/cdr.go b/engine/cdr.go index 6c33eef33..5f6b246d8 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -175,7 +175,11 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { case utils.ANSWER_TIME: return rsrFld.ParseValue(cdr.AnswerTime.Format(time.RFC3339)) case utils.USAGE: +<<<<<<< HEAD return cdr.Usage.String() +======= + return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update case utils.MEDI_RUNID: return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: @@ -380,7 +384,11 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, tenantFld, categFld, accou durStr := cdr.FieldAsString(durationFld) if primaryMandatory && len(durStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.USAGE, durationFld.Id) +<<<<<<< HEAD } else if frkStorCdr.Usage, err = utils.ParseDurationWithNanosecs(durStr); err != nil { +======= + } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } ratedStr := cdr.FieldAsString(ratedFld) @@ -425,7 +433,11 @@ func (cdr *CDR) AsExternalCDR() *ExternalCDR { Destination: cdr.Destination, SetupTime: cdr.SetupTime.Format(time.RFC3339), AnswerTime: cdr.AnswerTime.Format(time.RFC3339), +<<<<<<< HEAD Usage: usageStr, +======= + Usage: cdr.FormatUsage(utils.SECONDS), +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: cdr.ExtraFields, CostSource: cdr.CostSource, Cost: cdr.Cost, @@ -554,7 +566,11 @@ func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { } else { durVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } +<<<<<<< HEAD return utils.ParseDurationWithNanosecs(durVal) +======= + return utils.ParseDurationWithSecs(durVal) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { @@ -768,7 +784,11 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck // AsCDRsTBL converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { cdrSql = new(CDRsql) +<<<<<<< HEAD cdrSql.Cgrid = cdr.CGRID +======= + cdrSql.CGRID = cdr.CGRID +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdrSql.RunID = cdr.RunID cdrSql.OriginHost = cdr.OriginHost cdrSql.Source = cdr.Source @@ -795,12 +815,19 @@ func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { // NewCDRFromSQL converts the CDRsql into CDR func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr = new(CDR) +<<<<<<< HEAD cdr.CGRID = cdrSql.Cgrid +======= + cdr.CGRID = cdrSql.CGRID +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.RunID = cdrSql.RunID cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source cdr.OriginID = cdrSql.OriginID +<<<<<<< HEAD cdr.OrderID = cdrSql.ID +======= +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.ToR = cdrSql.TOR cdr.RequestType = cdrSql.RequestType cdr.Tenant = cdrSql.Tenant @@ -811,6 +838,10 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr.SetupTime = cdrSql.SetupTime cdr.AnswerTime = cdrSql.AnswerTime cdr.Usage = time.Duration(cdrSql.Usage) +<<<<<<< HEAD +======= + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.CostSource = cdrSql.CostSource cdr.Cost = cdrSql.Cost cdr.ExtraInfo = cdrSql.ExtraInfo @@ -820,7 +851,11 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { } } if cdrSql.CostDetails != "" { +<<<<<<< HEAD if err = json.Unmarshal([]byte(cdrSql.CostDetails), &cdr.CostDetails); err != nil { +======= + if err = json.Unmarshal([]byte(cdrSql.CostDetails), cdr.CostDetails); err != nil { +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } } diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 94a4b2451..858d1f750 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -98,7 +98,11 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination || cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339) || cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339) || +<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s" || +======= + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" || +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.RunID || cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01" || cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"] || @@ -118,7 +122,11 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination, cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339), cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339), +<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s", +======= + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10", +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.RunID, cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01", cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"], @@ -395,7 +403,11 @@ func TestCDRAsExternalCDR(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), +<<<<<<< HEAD RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10 * time.Second), Cost: 1.01, +======= + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} expectOutCdr := &ExternalCDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -403,7 +415,11 @@ func TestCDRAsExternalCDR(t *testing.T) { Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.DEFAULT_RUNID, +<<<<<<< HEAD Usage: "10s", Cost: 1.01, CostDetails: "null", +======= + Usage: "0.00000001", Cost: 1.01, CostDetails: "null", +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) @@ -497,9 +513,15 @@ func TestUsageReqAsCD(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", +<<<<<<< HEAD Usage: "10", } eCD := &CallDescriptor{CgrID: "c4630df20b2a0c5b11311e4b5a8c3178cf314344", TOR: req.ToR, +======= + Usage: "0.00000001", + } + eCD := &CallDescriptor{CgrID: "48ca1a2eb82b028fbfc809e36a585061a775ffc3", TOR: req.ToR, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update Direction: utils.OUT, Tenant: req.Tenant, Category: req.Category, Account: req.Account, Subject: req.Subject, Destination: req.Destination, diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index 71ad57a00..106cbc3ba 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -38,7 +38,11 @@ func TestCgrCdrAsCDR(t *testing.T) { utils.TENANT: "cgrates.org", utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-07T08:42:20Z", utils.ANSWER_TIME: "2013-11-07T08:42:26Z", +<<<<<<< HEAD utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} +======= + utils.USAGE: "10", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], diff --git a/engine/models.go b/engine/models.go index 2f1379da6..230de04b5 100755 --- a/engine/models.go +++ b/engine/models.go @@ -535,3 +535,61 @@ type TpLCR struct { Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time } + +type CDRsql struct { + ID int64 + CGRID string + RunID string + OriginHost string + Source string + OriginID string + TOR string + RequestType string + Tenant string + Category string + Account string + Subject string + Destination string + SetupTime time.Time + AnswerTime time.Time + Usage int64 + ExtraFields string + CostSource string + Cost float64 + CostDetails string + ExtraInfo string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time +} + +func (t CDRsql) TableName() string { + return utils.CDRsTBL +} + +type SMCostSQL struct { + ID int64 + Cgrid string + RunID string + OriginHost string + OriginID string + CostSource string + Usage float64 + CostDetails string + CreatedAt time.Time + DeletedAt *time.Time +} + +func (t SMCostSQL) TableName() string { + return utils.SMCostsTBL +} + +type TBLVersion struct { + ID uint + Item string + Version int64 +} + +func (t TBLVersion) TableName() string { + return utils.TBLVersions +} diff --git a/engine/responder_test.go b/engine/responder_test.go index 5eb31fd53..824374b9b 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -473,7 +473,11 @@ func TestResponderGetLCR(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry) } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { +<<<<<<< HEAD t.Errorf("Expecting: %s\n, received: %+v", utils.ToJSON(eLcLcr.SupplierCosts), utils.ToJSON(lcrLc.SupplierCosts)) +======= + t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } /* // Test *qos_threshold strategy here, @@ -505,6 +509,7 @@ func TestResponderGetLCR(t *testing.T) { t.Error(err) } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) +<<<<<<< HEAD } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) @@ -535,6 +540,38 @@ func TestResponderGetLCR(t *testing.T) { } +======= + + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) + } + + cdr := &CDR{AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + cdr = &CDR{AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + + eQTLcr = &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", + Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}}, + }, + } + if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %s, received: %s", + utils.ToJSON(eQTLcr.SupplierCosts), utils.ToJSON(lcrQT.SupplierCosts)) + } + + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update // Test *qos strategy here cdQos := &CallDescriptor{ TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 7cf9f7db1..0978785d0 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -725,7 +725,11 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { OriginID: smc.OriginID, CostSource: smc.CostSource, CostDetails: smc.CostDetails.AsJSON(), +<<<<<<< HEAD Usage: smc.Usage.Nanoseconds(), +======= + Usage: smc.Usage, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update 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) @@ -811,7 +815,11 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { } tx = self.db.Begin() cdrSql.UpdatedAt = time.Now() +<<<<<<< HEAD updated := tx.Model(&CDRsql{}).Where(&CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) +======= + updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update if updated.Error != nil { tx.Rollback() return updated.Error @@ -997,6 +1005,7 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, maxUsage, err := utils.ParseDurationWithNanosecs(qryFltr.MaxUsage) if err != nil { return nil, 0, err +<<<<<<< HEAD } if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) @@ -1005,6 +1014,32 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } } +======= + } + if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage + q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) + } else { + q = q.Where("usage < ?", maxUsage.Nanoseconds()) + } + + } + if len(qryFltr.MinPDD) != 0 { + if minPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd >= ?", minPDD.Nanoseconds()) + } + + } + if len(qryFltr.MaxPDD) != 0 { + if maxPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd < ?", maxPDD.Nanoseconds()) + } + } + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { q = q.Where("cost >= ?", *qryFltr.MinCost) diff --git a/engine/version.go b/engine/version.go index b17a29228..b0959e32c 100644 --- a/engine/version.go +++ b/engine/version.go @@ -24,6 +24,9 @@ import ( "github.com/cgrates/cgrates/utils" ) +// Versions will keep trac of various item versions +type Versions map[string]int64 // map[item]versionNr + func CheckVersions(storage Storage) error { // get current db version storType := storage.GetStorageType() @@ -104,29 +107,6 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } -func CurrentDBVersions(storType string) Versions { - dataDbVersions := CurrentDataDBVersions() - storDbVersions := CurrentStorDBVersions() - - allVersions := make(Versions) - for k, v := range dataDbVersions { - allVersions[k] = v - } - for k, v := range storDbVersions { - allVersions[k] = v - } - - switch storType { - case utils.MONGO, utils.MAPSTOR: - return allVersions - case utils.POSTGRES, utils.MYSQL: - return storDbVersions - case utils.REDIS: - return dataDbVersions - } - return nil -} - func CurrentDataDBVersions() Versions { return Versions{ utils.StatS: 2, @@ -184,5 +164,25 @@ func CurrentStorDBVersions() Versions { } } -// Versions will keep trac of various item versions -type Versions map[string]int64 // map[item]versionNr +func CurrentDBVersions(storType string) Versions { + dataDbVersions := CurrentDataDBVersions() + storDbVersions := CurrentStorDBVersions() + + allVersions := make(Versions) + for k, v := range dataDbVersions { + allVersions[k] = v + } + for k, v := range storDbVersions { + allVersions[k] = v + } + + switch storType { + case utils.MONGO, utils.MAPSTOR: + return allVersions + case utils.POSTGRES, utils.MYSQL: + return storDbVersions + case utils.REDIS: + return dataDbVersions + } + return nil +}