diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index f9104a103..db28d969b 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -98,7 +98,7 @@ CREATE TABLE `tp_rating_profiles` ( `tor` varchar(16) NOT NULL, `direction` varchar(8) NOT NULL, `subject` varchar(64) NOT NULL, - `activation_time` int(11) NOT NULL, + `activation_time` varchar(24) NOT NULL, `destrates_timing_tag` varchar(24) NOT NULL, `rates_fallback_subject` varchar(64), PRIMARY KEY (`id`), @@ -117,13 +117,8 @@ CREATE TABLE `tp_actions` ( `action` varchar(24) NOT NULL, `balance_type` varchar(24) NOT NULL, `direction` varchar(8) NOT NULL, -<<<<<<< HEAD - `units` DECIMAL(5,2) NOT NULL, - `expiration_time` varchar(24) NOT NULL, -======= `units` DECIMAL(8,4) NOT NULL, - `expiry_time` int(16) NOT NULL, ->>>>>>> 2f733525b215e608478e1cddf2b001fb92fb8cbd + `expiry_time` varchar(24) NOT NULL, `destination_tag` varchar(24) NOT NULL, `rate_type` varchar(8) NOT NULL, `rate` DECIMAL(8,4) NOT NULL, diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 51e5d1c89..c6c79e039 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -27,7 +27,6 @@ import ( "os" "strconv" "strings" - "time" ) type CSVReader struct { @@ -306,7 +305,7 @@ func (csvr *CSVReader) LoadRatingProfiles() (err error) { } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tenant, tor, direction, subject, fallbacksubject := record[0], record[1], record[2], record[3], record[6] - at, err := time.Parse(time.RFC3339, record[4]) + at, err := utils.ParseDate(record[4]) if err != nil { return errors.New(fmt.Sprintf("Cannot parse activation time from %v", record[4])) } diff --git a/engine/loader_db.go b/engine/loader_db.go index 0d7287fda..26fd5e7d7 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -23,7 +23,6 @@ import ( "fmt" "github.com/cgrates/cgrates/utils" "log" - "time" ) type DbReader struct { @@ -184,7 +183,10 @@ func (dbr *DbReader) LoadRatingProfiles() error { return err } for _, rp := range rpfs { - at := time.Unix(rp.ActivationTime, 0) + at, err := utils.ParseDate(rp.ActivationTime) + if err != nil { + return errors.New(fmt.Sprintf("Cannot parse activation time from %v", rp.ActivationTime)) + } for _, d := range dbr.destinations { ap, exists := dbr.activationPeriods[rp.DestRatesTimingTag] if !exists { @@ -211,7 +213,10 @@ func (dbr *DbReader) LoadRatingProfileByTag(tag string) error { } for _, ratingProfile := range rpm { resultRatingProfile.FallbackKey = ratingProfile.FallbackKey // it will be the last fallback key - at := time.Unix(ratingProfile.ActivationTime, 0) + at, err := utils.ParseDate(ratingProfile.ActivationTime) + if err != nil { + return errors.New(fmt.Sprintf("Cannot parse activation time from %v", ratingProfile.ActivationTime)) + } drtm, err := dbr.storDb.GetTpDestinationRateTimings(dbr.tpid, ratingProfile.DestRatesTimingTag) if err != nil { return err diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index 431d4fd2a..4199ddd8b 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -29,11 +29,10 @@ const ( ) type RatingProfile struct { - Id string - FallbackKey string // FallbackKey is used as complete combination of Tenant:TOR:Direction:Subject - DestinationMap map[string][]*ActivationPeriod - Tag, Tenant, TOR, Direction, Subject, DestRatesTimingTag, RatesFallbackSubject string // used only for loading - ActivationTime int64 + Id string + FallbackKey string // FallbackKey is used as complete combination of Tenant:TOR:Direction:Subject + DestinationMap map[string][]*ActivationPeriod + Tag, Tenant, TOR, Direction, Subject, DestRatesTimingTag, RatesFallbackSubject, ActivationTime string // used only for loading } // Adds an activation period that applyes to current rating profile if not already present. diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 124488f0f..633bb9752 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -478,8 +478,7 @@ func (self *SQLStorage) GetTPRatingProfile(tpid, rpId string) (*utils.TPRatingPr i := 0 for rows.Next() { i++ //Keep here a reference so we know we got at least one result - var tenant, tor, direction, subject, drtId, fallbackSubj string - var aTime int64 + var tenant, tor, direction, subject, drtId, fallbackSubj, aTime string err = rows.Scan(&tenant, &tor, &direction, &subject, &aTime, &drtId, &fallbackSubj) if err != nil { return nil, err @@ -1076,8 +1075,7 @@ func (self *SQLStorage) GetTpRatingProfiles(tpid, tag string) (map[string]*Ratin } defer rows.Close() for rows.Next() { - var tag, tenant, tor, direction, subject, fallback_subject, destrates_timing_tag string - var activation_time int64 + var tag, tenant, tor, direction, subject, fallback_subject, destrates_timing_tag, activation_time string if err := rows.Scan(&tag, &tenant, &tor, &direction, &subject, &activation_time, &destrates_timing_tag, &fallback_subject); err != nil { return nil, err } diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 8a466bb51..b4cdd77b3 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -239,11 +239,12 @@ func (self *TPCSVImporter) importRatingProfiles(fn string) error { continue } tenant, tor, direction, subject, destRatesTimingTag, fallbacksubject := record[0], record[1], record[2], record[3], record[5], record[6] - at, err := time.Parse(time.RFC3339, record[4]) + _, err = utils.ParseDate(record[4]) if err != nil { if self.Verbose { log.Printf("Ignoring line %d, warning: <%s> ", lineNr, err.Error()) } + continue } rpTag := "TPCSV" //Autogenerate rating profile id if self.ImportId != "" { @@ -254,7 +255,7 @@ func (self *TPCSVImporter) importRatingProfiles(fn string) error { TOR: tor, Direction: direction, Subject: subject, - ActivationTime: at.Unix(), + ActivationTime: record[4], DestRatesTimingTag: destRatesTimingTag, RatesFallbackSubject: fallbacksubject, } @@ -303,7 +304,7 @@ func (self *TPCSVImporter) importActions(fn string) error { continue } } - rateValue, _ := strconv.ParseFloat(record[8], 64) // Ignore errors since empty string is error, we can find out based on rateType if defined + rateValue, _ := strconv.ParseFloat(record[8], 64) // Ignore errors since empty string is error, we can find out based on rateType if defined minutesWeight, _ := strconv.ParseFloat(record[9], 64) weight, err := strconv.ParseFloat(record[10], 64) if err != nil { @@ -313,16 +314,16 @@ func (self *TPCSVImporter) importActions(fn string) error { continue } act := &Action{ - ActionType: actionType, - BalanceId: balanceType, - Direction: direction, + ActionType: actionType, + BalanceId: balanceType, + Direction: direction, Units: units, ExpirationDate: expiryTime, DestinationTag: destTag, - RateType: rateType, - RateValue: rateValue, - MinutesWeight: minutesWeight, - Weight: weight, + RateType: rateType, + RateValue: rateValue, + MinutesWeight: minutesWeight, + Weight: weight, } if err := self.StorDb.SetTPActions(self.TPid, map[string][]*Action{actId: []*Action{act}}); err != nil { if self.Verbose { @@ -359,11 +360,11 @@ func (self *TPCSVImporter) importActionTimings(fn string) error { } continue } - at := &ActionTiming{ - Tag: tag, + at := &ActionTiming{ + Tag: tag, ActionsTag: actionsTag, - TimingsTag: timingTag, - Weight: weight, + TimingsTag: timingTag, + Weight: weight, } if err := self.StorDb.SetTPActionTimings(self.TPid, map[string][]*ActionTiming{tag: []*ActionTiming{at}}); err != nil { if self.Verbose { @@ -407,14 +408,14 @@ func (self *TPCSVImporter) importActionTriggers(fn string) error { } continue } - at := &ActionTrigger{ - BalanceId: balanceType, - Direction: direction, - ThresholdType: thresholdType, + at := &ActionTrigger{ + BalanceId: balanceType, + Direction: direction, + ThresholdType: thresholdType, ThresholdValue: threshold, - DestinationId: destinationTag, - Weight: weight, - ActionsId: actionsTag, + DestinationId: destinationTag, + Weight: weight, + ActionsId: actionsTag, } if err := self.StorDb.SetTPActionTriggers(self.TPid, map[string][]*ActionTrigger{tag: []*ActionTrigger{at}}); err != nil { if self.Verbose { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index e88d638d1..8f32021c6 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -72,7 +72,7 @@ type TPRatingProfile struct { } type RatingActivation struct { - ActivationTime int64 // Time when this profile will become active, defined as unix epoch time + ActivationTime string // Time when this profile will become active, defined as unix epoch time DestRateTimingId string // Id of DestRateTiming profile } diff --git a/utils/coreutils.go b/utils/coreutils.go index df1fab17a..fb41718bc 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -19,6 +19,7 @@ along with this program. If not, see package utils import ( + "bytes" "crypto/rand" "crypto/sha1" "encoding/hex" @@ -108,6 +109,8 @@ func ParseDate(date string) (expDate time.Time, err error) { expDate = time.Now().Add(d) case string(expirationTime) == "*monthly": expDate = time.Now().AddDate(0, 1, 0) // add one month + case bytes.Contains(expirationTime, []byte("Z")): + expDate, err = time.Parse(time.RFC3339, date) default: unix, err := strconv.ParseInt(string(expirationTime), 10, 64) if err != nil { diff --git a/utils/utils_test.go b/utils/utils_test.go index 25dea5bc6..318611fb0 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -150,3 +150,11 @@ func TestParseDateMonthly(t *testing.T) { t.Error("error parsing date: ", expected.Sub(date).Seconds()) } } + +func TestParseDateRFC3339(t *testing.T) { + date, err := ParseDate("2013-07-30T19:33:10Z") + expected := time.Date(2013, 7, 30, 19, 33, 10, 0, time.UTC) + if err != nil || !date.Equal(expected) { + t.Error("error parsing date: ", expected.Sub(date)) + } +}