mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-12 10:36:24 +05:00
228 lines
7.9 KiB
Go
228 lines
7.9 KiB
Go
/*
|
|
Real-time Charging System for Telecom & ISP environments
|
|
Copyright (C) 2012-2014 ITsysCOM GmbH
|
|
|
|
This program is free software: you can Storagetribute 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 WITH*out 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 <http://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// Kinda standard of internal CDR, complies to CDR interface also
|
|
type StoredCdr struct {
|
|
CgrId string
|
|
OrderId int64 // Stor order id used as export order id
|
|
TOR string
|
|
AccId string
|
|
CdrHost string
|
|
CdrSource string
|
|
ReqType string
|
|
Direction string
|
|
Tenant string
|
|
Category string
|
|
Account string
|
|
Subject string
|
|
Destination string
|
|
SetupTime time.Time
|
|
AnswerTime time.Time
|
|
Duration time.Duration
|
|
ExtraFields map[string]string
|
|
MediationRunId string
|
|
Cost float64
|
|
}
|
|
|
|
// Return cost as string, formated with number of decimals configured
|
|
func (storedCdr *StoredCdr) FormatCost(shiftDecimals, roundDecimals int) string {
|
|
cost := storedCdr.Cost
|
|
if shiftDecimals != 0 {
|
|
cost = cost * math.Pow10(shiftDecimals)
|
|
}
|
|
return strconv.FormatFloat(cost, 'f', roundDecimals, 64)
|
|
}
|
|
|
|
// Used to retrieve fields as string, primary fields are const labeled
|
|
func (storedCdr *StoredCdr) FieldAsString(rsrFld *RSRField) string {
|
|
switch rsrFld.Id {
|
|
case CGRID:
|
|
return rsrFld.ParseValue(storedCdr.CgrId)
|
|
case ORDERID:
|
|
return rsrFld.ParseValue(strconv.FormatInt(storedCdr.OrderId, 10))
|
|
case TOR:
|
|
return rsrFld.ParseValue(storedCdr.TOR)
|
|
case ACCID:
|
|
return rsrFld.ParseValue(storedCdr.AccId)
|
|
case CDRHOST:
|
|
return rsrFld.ParseValue(storedCdr.CdrHost)
|
|
case CDRSOURCE:
|
|
return rsrFld.ParseValue(storedCdr.CdrSource)
|
|
case REQTYPE:
|
|
return rsrFld.ParseValue(storedCdr.ReqType)
|
|
case DIRECTION:
|
|
return rsrFld.ParseValue(storedCdr.Direction)
|
|
case TENANT:
|
|
return rsrFld.ParseValue(storedCdr.Tenant)
|
|
case CATEGORY:
|
|
return rsrFld.ParseValue(storedCdr.Category)
|
|
case ACCOUNT:
|
|
return rsrFld.ParseValue(storedCdr.Account)
|
|
case SUBJECT:
|
|
return rsrFld.ParseValue(storedCdr.Subject)
|
|
case DESTINATION:
|
|
return rsrFld.ParseValue(storedCdr.Destination)
|
|
case SETUP_TIME:
|
|
return rsrFld.ParseValue(storedCdr.SetupTime.String())
|
|
case ANSWER_TIME:
|
|
return rsrFld.ParseValue(storedCdr.AnswerTime.String())
|
|
case DURATION:
|
|
return rsrFld.ParseValue(strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64))
|
|
case MEDI_RUNID:
|
|
return rsrFld.ParseValue(storedCdr.MediationRunId)
|
|
case COST:
|
|
return rsrFld.ParseValue(strconv.FormatFloat(storedCdr.Cost, 'f', -1, 64)) // Recommended to use FormatCost
|
|
default:
|
|
return rsrFld.ParseValue(storedCdr.ExtraFields[rsrFld.Id])
|
|
}
|
|
}
|
|
|
|
func (storedCdr *StoredCdr) AsStoredCdr() *StoredCdr {
|
|
return storedCdr
|
|
}
|
|
|
|
// Ability to send the CgrCdr remotely to another CDR server
|
|
func (storedCdr *StoredCdr) AsHttpForm() url.Values {
|
|
v := url.Values{}
|
|
for fld, val := range storedCdr.ExtraFields {
|
|
v.Set(fld, val)
|
|
}
|
|
v.Set(TOR, storedCdr.TOR)
|
|
v.Set(ACCID, storedCdr.AccId)
|
|
v.Set(CDRHOST, storedCdr.CdrHost)
|
|
v.Set(CDRSOURCE, storedCdr.CdrSource)
|
|
v.Set(REQTYPE, storedCdr.ReqType)
|
|
v.Set(DIRECTION, storedCdr.Direction)
|
|
v.Set(TENANT, storedCdr.Tenant)
|
|
v.Set(CATEGORY, storedCdr.Category)
|
|
v.Set(ACCOUNT, storedCdr.Account)
|
|
v.Set(SUBJECT, storedCdr.Subject)
|
|
v.Set(DESTINATION, storedCdr.Destination)
|
|
v.Set(SETUP_TIME, storedCdr.SetupTime.String())
|
|
v.Set(ANSWER_TIME, storedCdr.AnswerTime.String())
|
|
v.Set(DURATION, strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64))
|
|
return v
|
|
}
|
|
|
|
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored
|
|
func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, answerTimeFld, durationFld *RSRField,
|
|
extraFlds []*RSRField, primaryMandatory bool) (*StoredCdr, error) {
|
|
// MetaDefault will automatically be converted to their standard values
|
|
if reqTypeFld.Id == META_DEFAULT {
|
|
reqTypeFld.Id = REQTYPE
|
|
}
|
|
if directionFld.Id == META_DEFAULT {
|
|
directionFld.Id = DIRECTION
|
|
}
|
|
if tenantFld.Id == META_DEFAULT {
|
|
tenantFld.Id = TENANT
|
|
}
|
|
if categFld.Id == META_DEFAULT {
|
|
categFld.Id = CATEGORY
|
|
}
|
|
if accountFld.Id == META_DEFAULT {
|
|
accountFld.Id = ACCOUNT
|
|
}
|
|
if subjectFld.Id == META_DEFAULT {
|
|
subjectFld.Id = SUBJECT
|
|
}
|
|
if destFld.Id == META_DEFAULT {
|
|
destFld.Id = DESTINATION
|
|
}
|
|
if setupTimeFld.Id == META_DEFAULT {
|
|
setupTimeFld.Id = SETUP_TIME
|
|
}
|
|
if answerTimeFld.Id == META_DEFAULT {
|
|
answerTimeFld.Id = ANSWER_TIME
|
|
}
|
|
if durationFld.Id == META_DEFAULT {
|
|
durationFld.Id = DURATION
|
|
}
|
|
var err error
|
|
frkStorCdr := new(StoredCdr)
|
|
frkStorCdr.CgrId = storedCdr.CgrId
|
|
frkStorCdr.TOR = storedCdr.TOR
|
|
frkStorCdr.MediationRunId = runId
|
|
frkStorCdr.Cost = -1.0 // Default for non-rated CDR
|
|
frkStorCdr.AccId = storedCdr.AccId
|
|
frkStorCdr.CdrHost = storedCdr.CdrHost
|
|
frkStorCdr.CdrSource = storedCdr.CdrSource
|
|
frkStorCdr.ReqType = storedCdr.FieldAsString(reqTypeFld)
|
|
if primaryMandatory && len(frkStorCdr.ReqType) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, REQTYPE, reqTypeFld.Id))
|
|
}
|
|
frkStorCdr.Direction = storedCdr.FieldAsString(directionFld)
|
|
if primaryMandatory && len(frkStorCdr.Direction) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, DIRECTION, directionFld.Id))
|
|
}
|
|
frkStorCdr.Tenant = storedCdr.FieldAsString(tenantFld)
|
|
if primaryMandatory && len(frkStorCdr.Tenant) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, TENANT, tenantFld.Id))
|
|
}
|
|
frkStorCdr.Category = storedCdr.FieldAsString(categFld)
|
|
if primaryMandatory && len(frkStorCdr.Category) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, CATEGORY, categFld.Id))
|
|
}
|
|
frkStorCdr.Account = storedCdr.FieldAsString(accountFld)
|
|
if primaryMandatory && len(frkStorCdr.Account) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, ACCOUNT, accountFld.Id))
|
|
}
|
|
frkStorCdr.Subject = storedCdr.FieldAsString(subjectFld)
|
|
if primaryMandatory && len(frkStorCdr.Subject) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, SUBJECT, subjectFld.Id))
|
|
}
|
|
frkStorCdr.Destination = storedCdr.FieldAsString(destFld)
|
|
if primaryMandatory && len(frkStorCdr.Destination) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, DESTINATION, destFld.Id))
|
|
}
|
|
sTimeStr := storedCdr.FieldAsString(setupTimeFld)
|
|
if primaryMandatory && len(sTimeStr) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, SETUP_TIME, setupTimeFld.Id))
|
|
} else if frkStorCdr.SetupTime, err = ParseTimeDetectLayout(sTimeStr); err != nil {
|
|
return nil, err
|
|
}
|
|
aTimeStr := storedCdr.FieldAsString(answerTimeFld)
|
|
if primaryMandatory && len(aTimeStr) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, ANSWER_TIME, answerTimeFld.Id))
|
|
} else if frkStorCdr.AnswerTime, err = ParseTimeDetectLayout(aTimeStr); err != nil {
|
|
return nil, err
|
|
}
|
|
durStr := storedCdr.FieldAsString(durationFld)
|
|
if primaryMandatory && len(durStr) == 0 {
|
|
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, DURATION, durationFld.Id))
|
|
} else if frkStorCdr.Duration, err = ParseDurationWithSecs(durStr); err != nil {
|
|
return nil, err
|
|
}
|
|
frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds))
|
|
for _, fld := range extraFlds {
|
|
frkStorCdr.ExtraFields[fld.Id] = storedCdr.FieldAsString(fld)
|
|
}
|
|
return frkStorCdr, nil
|
|
}
|