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