From 3adf5809c0bef2bfe53444559fa8af4f069e3022 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 5 May 2015 19:13:14 +0200 Subject: [PATCH] ApierV2.ExportCdrsToFile method --- apier/v2/cdre.go | 130 +++++++++++++++++++++++++++++++++++++++++ console/cdrs_export.go | 8 +-- utils/apitpdata.go | 18 ++++++ 3 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 apier/v2/cdre.go diff --git a/apier/v2/cdre.go b/apier/v2/cdre.go new file mode 100644 index 000000000..a867b1a48 --- /dev/null +++ b/apier/v2/cdre.go @@ -0,0 +1,130 @@ +/* +Real-time Charging System for Telecom & ISP environments +Copyright (C) 2012-2015 ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package v2 + +import ( + "fmt" + "path" + "strconv" + "strings" + "time" + "unicode/utf8" + + "github.com/cgrates/cgrates/cdre" + "github.com/cgrates/cgrates/utils" +) + +// Export Cdrs to file +func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *utils.ExportedFileCdrs) error { + var err error + exportTemplate := self.Config.CdreProfiles[utils.META_DEFAULT] + if attr.ExportTemplate != nil && len(*attr.ExportTemplate) != 0 { // Export template prefered, use it + var hasIt bool + if exportTemplate, hasIt = self.Config.CdreProfiles[*attr.ExportTemplate]; !hasIt { + return fmt.Errorf("%s:ExportTemplate", utils.ERR_NOT_FOUND) + } + } + cdrFormat := exportTemplate.CdrFormat + if attr.CdrFormat != nil && len(*attr.CdrFormat) != 0 { + cdrFormat = strings.ToLower(*attr.CdrFormat) + } + if !utils.IsSliceMember(utils.CdreCdrFormats, cdrFormat) { + return fmt.Errorf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, "CdrFormat") + } + fieldSep := exportTemplate.FieldSeparator + if attr.FieldSeparator != nil && len(*attr.FieldSeparator) != 0 { + fieldSep, _ = utf8.DecodeRuneInString(*attr.FieldSeparator) + if fieldSep == utf8.RuneError { + return fmt.Errorf("%s:FieldSeparator:%s", utils.ERR_SERVER_ERROR, "Invalid") + } + } + exportDir := exportTemplate.ExportDir + if attr.ExportDir != nil && len(*attr.ExportDir) != 0 { + exportDir = *attr.ExportDir + } + exportId := strconv.FormatInt(time.Now().Unix(), 10) + if attr.ExportId != nil && len(*attr.ExportId) != 0 { + exportId = *attr.ExportId + } + fileName := fmt.Sprintf("cdre_%s.%s", exportId, cdrFormat) + if attr.ExportFileName != nil && len(*attr.ExportFileName) != 0 { + fileName = *attr.ExportFileName + } + filePath := path.Join(exportDir, fileName) + if cdrFormat == utils.DRYRUN { + filePath = utils.DRYRUN + } + dataUsageMultiplyFactor := exportTemplate.DataUsageMultiplyFactor + if attr.DataUsageMultiplyFactor != nil && *attr.DataUsageMultiplyFactor != 0.0 { + dataUsageMultiplyFactor = *attr.DataUsageMultiplyFactor + } + smsUsageMultiplyFactor := exportTemplate.SmsUsageMultiplyFactor + if attr.SmsUsageMultiplyFactor != nil && *attr.SmsUsageMultiplyFactor != 0.0 { + smsUsageMultiplyFactor = *attr.SmsUsageMultiplyFactor + } + costMultiplyFactor := exportTemplate.CostMultiplyFactor + if attr.CostMultiplyFactor != nil && *attr.CostMultiplyFactor != 0.0 { + costMultiplyFactor = *attr.CostMultiplyFactor + } + costShiftDigits := exportTemplate.CostShiftDigits + if attr.CostShiftDigits != nil { + costShiftDigits = *attr.CostShiftDigits + } + roundingDecimals := exportTemplate.CostRoundingDecimals + if attr.RoundDecimals != nil { + roundingDecimals = *attr.RoundDecimals + } + maskDestId := exportTemplate.MaskDestId + if attr.MaskDestinationId != nil && len(*attr.MaskDestinationId) != 0 { + maskDestId = *attr.MaskDestinationId + } + maskLen := exportTemplate.MaskLength + if attr.MaskLength != nil { + maskLen = *attr.MaskLength + } + cdrsFltr, err := attr.RpcCdrsFilter.AsCdrsFilter() + if err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + cdrs, _, err := self.CdrDb.GetStoredCdrs(cdrsFltr) + if err != nil { + return err + } else if len(cdrs) == 0 { + *reply = utils.ExportedFileCdrs{ExportedFilePath: ""} + return nil + } + cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, exportId, dataUsageMultiplyFactor, smsUsageMultiplyFactor, + costMultiplyFactor, costShiftDigits, roundingDecimals, self.Config.RoundingDecimals, maskDestId, maskLen, self.Config.HttpSkipTlsVerify) + if err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + if cdrexp.TotalExportedCdrs() == 0 { + *reply = utils.ExportedFileCdrs{ExportedFilePath: ""} + return nil + } + if err := cdrexp.WriteToFile(filePath); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + *reply = utils.ExportedFileCdrs{ExportedFilePath: filePath, TotalRecords: len(cdrs), TotalCost: cdrexp.TotalCost(), FirstOrderId: cdrexp.FirstOrderId(), LastOrderId: cdrexp.LastOrderId()} + if !attr.SuppressCgrIds { + reply.ExportedCgrIds = cdrexp.PositiveExports() + reply.UnexportedCgrIds = cdrexp.NegativeExports() + } + return nil +} diff --git a/console/cdrs_export.go b/console/cdrs_export.go index 16d309b67..85ac82e89 100644 --- a/console/cdrs_export.go +++ b/console/cdrs_export.go @@ -23,7 +23,7 @@ import "github.com/cgrates/cgrates/utils" func init() { c := &CmdExportCdrs{ name: "cdrs_export", - rpcMethod: "ApierV1.ExportCdrsToFile", + rpcMethod: "ApierV2.ExportCdrsToFile", } commands[c.Name()] = c c.CommandExecuter = &CommandExecuter{c} @@ -33,7 +33,7 @@ func init() { type CmdExportCdrs struct { name string rpcMethod string - rpcParams *utils.AttrExpFileCdrs + rpcParams *utils.AttrExportCdrsToFile *CommandExecuter } @@ -47,7 +47,7 @@ func (self *CmdExportCdrs) RpcMethod() string { func (self *CmdExportCdrs) RpcParams() interface{} { if self.rpcParams == nil { - self.rpcParams = &utils.AttrExpFileCdrs{} + self.rpcParams = &utils.AttrExportCdrsToFile{} } return self.rpcParams } @@ -57,5 +57,5 @@ func (self *CmdExportCdrs) PostprocessRpcParams() error { } func (self *CmdExportCdrs) RpcResult() interface{} { - return &utils.ExportedFileCdrs{} + return &utils.AttrExportCdrsToFile{} } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index f39c6e538..8c50bef0d 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1116,6 +1116,24 @@ func (self *RpcCdrsFilter) AsCdrsFilter() (*CdrsFilter, error) { return cdrFltr, nil } +type AttrExportCdrsToFile struct { + CdrFormat *string // Cdr output file format + FieldSeparator *string // Separator used between fields + ExportId *string // Optional exportid + ExportDir *string // If provided it overwrites the configured export directory + ExportFileName *string // If provided the output filename will be set to this + ExportTemplate *string // Exported fields template <""|fld1,fld2|*xml:instance_name> + DataUsageMultiplyFactor *float64 // Multiply data usage before export (eg: convert from KBytes to Bytes) + SmsUsageMultiplyFactor *float64 // Multiply sms usage before export (eg: convert from SMS unit to call duration for some billing systems) + CostMultiplyFactor *float64 // Multiply the cost before export, eg: apply VAT + CostShiftDigits *int // If defined it will shift cost digits before applying rouding (eg: convert from Eur->cents), -1 to use general config ones + RoundDecimals *int // Overwrite configured roundDecimals with this dynamically, -1 to use general config ones + MaskDestinationId *string // Overwrite configured MaskDestId + MaskLength *int // Overwrite configured MaskLength, -1 to use general config ones + SuppressCgrIds bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds + RpcCdrsFilter // Inherit the CDR filter attributes +} + type AttrSetActions struct { ActionsId string // Actions id Overwrite bool // If previously defined, will be overwritten