DurationMangle is now bidirectional, cdr exporter properly formating duration

This commit is contained in:
DanB
2014-05-26 14:16:35 +02:00
parent 31881ea41c
commit 42e9719fed
7 changed files with 35 additions and 7 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -117,6 +117,8 @@ const (
NANOSECONDS = "nanoseconds"
SECONDS = "seconds"
OUT = "*out"
CDR_IMPORT = "cdr_import"
CDR_EXPORT = "cdr_export"
)
var (

View File

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

View File

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