mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
DurationMangle is now bidirectional, cdr exporter properly formating duration
This commit is contained in:
@@ -64,6 +64,9 @@ func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*utils.StoredCdr
|
||||
attrs.OrderIdStart, attrs.OrderIdEnd, tStart, tEnd, attrs.SkipErrors, attrs.SkipRated, false); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
} else {
|
||||
for _, cdr := range cdrs {
|
||||
cdr.MangleDataUsage(utils.CDR_EXPORT) // Convert data usage to the right format
|
||||
}
|
||||
*reply = cdrs
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -304,7 +304,9 @@ func (fwv *FixedWidthCdrWriter) WriteCdr(cdr *utils.StoredCdr) error {
|
||||
fwv.lastCdrATime = cdr.AnswerTime
|
||||
}
|
||||
fwv.numberOfRecords += 1
|
||||
fwv.totalDuration += cdr.Usage
|
||||
if !utils.IsSliceMember([]string{utils.DATA, utils.SMS}, cdr.TOR) { // Only count duration for non data cdrs
|
||||
fwv.totalDuration += cdr.Usage
|
||||
}
|
||||
fwv.totalCost += cdr.Cost
|
||||
fwv.totalCost = utils.Round(fwv.totalCost, fwv.roundDecimals, utils.ROUNDING_MIDDLE)
|
||||
if fwv.firstExpOrderId > cdr.OrderId || fwv.firstExpOrderId == 0 {
|
||||
|
||||
@@ -37,6 +37,7 @@ var (
|
||||
|
||||
// Returns error if not able to properly store the CDR, mediation is async since we can always recover offline
|
||||
func storeAndMediate(storedCdr *utils.StoredCdr) error {
|
||||
storedCdr.MangleDataUsage(utils.CDR_IMPORT) // Fix the data usage here
|
||||
if err := storage.SetCdr(storedCdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ func TestMediatePseudoprepaid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Duration(*startDelay) * time.Millisecond) // Give time for debits to happen
|
||||
expectBalance := 5.998
|
||||
expectBalance := 6.0
|
||||
if err := cgrRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[engine.CREDIT+attrs.Direction].GetTotalValue() != expectBalance { // 5 from voice, 0.002 from DATA
|
||||
|
||||
@@ -117,6 +117,8 @@ const (
|
||||
NANOSECONDS = "nanoseconds"
|
||||
SECONDS = "seconds"
|
||||
OUT = "*out"
|
||||
CDR_IMPORT = "cdr_import"
|
||||
CDR_EXPORT = "cdr_export"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -51,9 +51,14 @@ type StoredCdr struct {
|
||||
}
|
||||
|
||||
// Should only be used for display purposes, bad otherwise.
|
||||
func (storedCdr *StoredCdr) MangleDataUsage() {
|
||||
// cdrDirection: CDR_IMPORT or CDR_EXPORT
|
||||
func (storedCdr *StoredCdr) MangleDataUsage(cdrDirection string) {
|
||||
if IsSliceMember([]string{DATA, SMS}, storedCdr.TOR) {
|
||||
storedCdr.Usage = time.Duration(int(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE))) // 0.1 should be reflected as 1 and not 0
|
||||
if cdrDirection == CDR_IMPORT { // On import CDRs usages are converted to nanoseconds, for data we need seconds, fix it here.
|
||||
storedCdr.Usage = time.Duration(storedCdr.Usage.Nanoseconds()) * time.Second
|
||||
} else if cdrDirection == CDR_EXPORT { // On exports we need to show the data back in seconds instead of internally stored as nanoseconds
|
||||
storedCdr.Usage = time.Duration(int(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +122,9 @@ func (storedCdr *StoredCdr) FieldAsString(rsrFld *RSRField) string {
|
||||
case ANSWER_TIME:
|
||||
return rsrFld.ParseValue(storedCdr.AnswerTime.String())
|
||||
case USAGE:
|
||||
if IsSliceMember([]string{DATA, SMS}, storedCdr.TOR) {
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
}
|
||||
return rsrFld.ParseValue(strconv.FormatInt(storedCdr.Usage.Nanoseconds(), 10))
|
||||
case MEDI_RUNID:
|
||||
return rsrFld.ParseValue(storedCdr.MediationRunId)
|
||||
|
||||
@@ -76,15 +76,27 @@ func TestFieldAsString(t *testing.T) {
|
||||
cdr.FieldAsString(&RSRField{Id: "fieldextr2"}) != cdr.ExtraFields["fieldextr2"],
|
||||
cdr.FieldAsString(&RSRField{Id: "dummy_field"}) != "")
|
||||
}
|
||||
cdr.TOR = DATA
|
||||
if formated := cdr.FieldAsString(&RSRField{Id: USAGE}); formated != "10" {
|
||||
t.Error("Wrong exported value for data field: ", formated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMangleDataUsage(t *testing.T) {
|
||||
cdr := StoredCdr{TOR: DATA, Usage: time.Duration(1640113000000000)}
|
||||
if cdr.MangleDataUsage(); cdr.Usage != time.Duration(1640113) {
|
||||
cdr := StoredCdr{TOR: DATA, Usage: time.Duration(1640113)}
|
||||
if cdr.MangleDataUsage(CDR_IMPORT); cdr.Usage != time.Duration(1640113000000000) {
|
||||
t.Error("Unexpected usage after mangling: ", cdr.Usage)
|
||||
}
|
||||
cdr = StoredCdr{TOR: VOICE, Usage: time.Duration(1640113000000000)}
|
||||
if cdr.MangleDataUsage(); cdr.Usage != time.Duration(1640113000000000) {
|
||||
if cdr.MangleDataUsage(CDR_IMPORT); cdr.Usage != time.Duration(1640113000000000) {
|
||||
t.Error("Unexpected usage after mangling: ", cdr.Usage)
|
||||
}
|
||||
cdr = StoredCdr{TOR: DATA, Usage: time.Duration(1640113000000000)}
|
||||
if cdr.MangleDataUsage(CDR_EXPORT); cdr.Usage != time.Duration(1640113) {
|
||||
t.Error("Unexpected usage after mangling: ", cdr.Usage)
|
||||
}
|
||||
cdr = StoredCdr{TOR: VOICE, Usage: time.Duration(1640113000000000)}
|
||||
if cdr.MangleDataUsage(CDR_EXPORT); cdr.Usage != time.Duration(1640113000000000) {
|
||||
t.Error("Unexpected usage after mangling: ", cdr.Usage)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user