mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Merge branch 'data'
Conflicts: engine/calldesc.go mediator/mediator.go sessionmanager/fssessionmanager.go utils/storedcdr.go
This commit is contained in:
@@ -211,7 +211,7 @@ func (self *ApierV1) LoadRatingProfile(attrs utils.TPRatingProfile, reply *strin
|
||||
|
||||
type AttrSetRatingProfile struct {
|
||||
Tenant string // Tenant's Id
|
||||
TOR string // TypeOfRecord
|
||||
Category string // TypeOfRecord
|
||||
Direction string // Traffic direction, OUT is the only one supported for now
|
||||
Subject string // Rating subject, usually the same as account
|
||||
Overwrite bool // Overwrite if exists
|
||||
@@ -228,7 +228,7 @@ func (self *ApierV1) SetRatingProfile(attrs AttrSetRatingProfile, reply *string)
|
||||
return fmt.Errorf("%s:RatingPlanActivation:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
}
|
||||
tpRpf := utils.TPRatingProfile{Tenant: attrs.Tenant, TOR: attrs.TOR, Direction: attrs.Direction, Subject: attrs.Subject}
|
||||
tpRpf := utils.TPRatingProfile{Tenant: attrs.Tenant, Category: attrs.Category, Direction: attrs.Direction, Subject: attrs.Subject}
|
||||
keyId := tpRpf.KeyId()
|
||||
if !attrs.Overwrite {
|
||||
if exists, err := self.RatingDb.HasData(engine.RATING_PROFILE_PREFIX, keyId); err != nil {
|
||||
@@ -249,7 +249,7 @@ func (self *ApierV1) SetRatingProfile(attrs AttrSetRatingProfile, reply *string)
|
||||
return fmt.Errorf(fmt.Sprintf("%s:RatingPlanId:%s", utils.ERR_NOT_FOUND, ra.RatingPlanId))
|
||||
}
|
||||
rpfl.RatingPlanActivations[idx] = &engine.RatingPlanActivation{ActivationTime: at, RatingPlanId: ra.RatingPlanId,
|
||||
FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.TOR, ra.FallbackSubjects)}
|
||||
FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.Category, ra.FallbackSubjects)}
|
||||
}
|
||||
if err := self.RatingDb.SetRatingProfile(rpfl); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
|
||||
@@ -450,7 +450,7 @@ func TestApierTPRatingProfile(t *testing.T) {
|
||||
return
|
||||
}
|
||||
reply := ""
|
||||
rpf := &utils.TPRatingProfile{TPid: engine.TEST_SQL, LoadId: engine.TEST_SQL, Tenant: "cgrates.org", TOR: "call", Direction: "*out", Subject: "*any",
|
||||
rpf := &utils.TPRatingProfile{TPid: engine.TEST_SQL, LoadId: engine.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any",
|
||||
RatingPlanActivations: []*utils.TPRatingActivation{
|
||||
&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1", FallbackSubjects: ""},
|
||||
}}
|
||||
@@ -743,7 +743,7 @@ func TestApierSetRatingProfile(t *testing.T) {
|
||||
}
|
||||
reply := ""
|
||||
rpa := &utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1", FallbackSubjects: "dan2"}
|
||||
rpf := &AttrSetRatingProfile{Tenant: "cgrates.org", TOR: "call", Direction: "*out", Subject: "dan", RatingPlanActivations: []*utils.TPRatingActivation{rpa}}
|
||||
rpf := &AttrSetRatingProfile{Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "dan", RatingPlanActivations: []*utils.TPRatingActivation{rpa}}
|
||||
if err := rater.Call("ApierV1.SetRatingProfile", rpf, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.SetRatingProfile: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
@@ -759,15 +759,15 @@ func TestApierSetRatingProfile(t *testing.T) {
|
||||
tStart, _ := utils.ParseDate("2013-08-07T17:30:00Z")
|
||||
tEnd, _ := utils.ParseDate("2013-08-07T17:31:30Z")
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "dan",
|
||||
Account: "dan",
|
||||
Destination: "+4917621621391",
|
||||
CallDuration: 90,
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "dan",
|
||||
Account: "dan",
|
||||
Destination: "+4917621621391",
|
||||
DurationIndex: 90,
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
}
|
||||
var cc engine.CallCost
|
||||
// Simple test that command is executed without errors
|
||||
@@ -784,7 +784,7 @@ func TestApierLoadRatingProfile(t *testing.T) {
|
||||
return
|
||||
}
|
||||
reply := ""
|
||||
rpf := &utils.TPRatingProfile{TPid: engine.TEST_SQL, LoadId: engine.TEST_SQL, Tenant: "cgrates.org", TOR: "call", Direction: "*out", Subject: "*any"}
|
||||
rpf := &utils.TPRatingProfile{TPid: engine.TEST_SQL, LoadId: engine.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any"}
|
||||
if err := rater.Call("ApierV1.LoadRatingProfile", rpf, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.LoadRatingProfile: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
@@ -1300,15 +1300,15 @@ func TestResponderGetCost(t *testing.T) {
|
||||
tStart, _ := utils.ParseDate("2013-08-07T17:30:00Z")
|
||||
tEnd, _ := utils.ParseDate("2013-08-07T17:31:30Z")
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "+4917621621391",
|
||||
CallDuration: 90,
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "+4917621621391",
|
||||
DurationIndex: 90,
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
}
|
||||
var cc engine.CallCost
|
||||
// Simple test that command is executed without errors
|
||||
@@ -1345,7 +1345,7 @@ func TestMaxDebitInexistentAcnt(t *testing.T) {
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "INVALID",
|
||||
Account: "INVALID",
|
||||
Destination: "1002",
|
||||
|
||||
@@ -78,7 +78,7 @@ func (self *ApierV1) GetTPRatingProfileLoadIds(attrs utils.AttrTPRatingProfileId
|
||||
}
|
||||
if ids, err := self.StorDb.GetTPTableIds(attrs.TPid, utils.TBL_TP_RATE_PROFILES, "loadid", map[string]string{
|
||||
"tenant": attrs.Tenant,
|
||||
"tor": attrs.TOR,
|
||||
"tor": attrs.Category,
|
||||
"direction": attrs.Direction,
|
||||
"subject": attrs.Subject,
|
||||
}); err != nil {
|
||||
@@ -96,7 +96,7 @@ func (self *ApierV1) RemTPRatingProfile(attrs utils.TPRatingProfile, reply *stri
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid", "LoadId", "Tenant", "TOR", "Direction", "Subject"}); len(missing) != 0 { //Params missing
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
if err := self.StorDb.RemTPData(utils.TBL_TP_RATE_PROFILES, attrs.TPid, attrs.LoadId, attrs.Tenant, attrs.TOR, attrs.Direction, attrs.Subject); err != nil {
|
||||
if err := self.StorDb.RemTPData(utils.TBL_TP_RATE_PROFILES, attrs.TPid, attrs.LoadId, attrs.Tenant, attrs.Category, attrs.Direction, attrs.Subject); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
} else {
|
||||
*reply = "OK"
|
||||
|
||||
@@ -197,15 +197,15 @@ func TestFsCsvCall1(t *testing.T) {
|
||||
tStart := time.Date(2014, 01, 15, 6, 0, 0, 0, time.UTC)
|
||||
tEnd := time.Date(2014, 01, 15, 6, 0, 35, 0, time.UTC)
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
CallDuration: 35,
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
DurationIndex: 35,
|
||||
}
|
||||
var cc engine.CallCost
|
||||
// Make sure the cost is what we expect it is
|
||||
@@ -232,16 +232,16 @@ func TestFsCsvCall1(t *testing.T) {
|
||||
t.Errorf("Received unexpected UnitCounters: %v", reply.UnitCounters)
|
||||
}
|
||||
cd = engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
CallDuration: 35,
|
||||
LoopIndex: 1, // Should not charge ConnectFee
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
TimeStart: tStart,
|
||||
TimeEnd: tEnd,
|
||||
DurationIndex: 35,
|
||||
LoopIndex: 1, // Should not charge ConnectFee
|
||||
}
|
||||
// Make sure debit charges what cost returned
|
||||
if err := rater.Call("Responder.MaxDebit", cd, &cc); err != nil {
|
||||
|
||||
@@ -311,7 +311,7 @@ func TestMaxCallDuration(t *testing.T) {
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
@@ -330,7 +330,7 @@ func TestMaxCallDuration(t *testing.T) {
|
||||
cd = engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1002",
|
||||
Account: "1002",
|
||||
Destination: "1001",
|
||||
@@ -348,7 +348,7 @@ func TestMaxCallDuration(t *testing.T) {
|
||||
cd = engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1006",
|
||||
Account: "1006",
|
||||
Destination: "1001",
|
||||
@@ -367,7 +367,7 @@ func TestMaxCallDuration(t *testing.T) {
|
||||
cd = engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1007",
|
||||
Account: "1007",
|
||||
Destination: "1001",
|
||||
@@ -393,7 +393,7 @@ func TestMaxDebit1001(t *testing.T) {
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1001",
|
||||
Account: "1001",
|
||||
Destination: "1002",
|
||||
@@ -432,7 +432,7 @@ func TestMaxDebit1007(t *testing.T) {
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
Tenant: "cgrates.org",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Subject: "1007",
|
||||
Account: "1007",
|
||||
Destination: "1002",
|
||||
|
||||
@@ -86,7 +86,7 @@ func (self *Cdrc) parseFieldsConfig() error {
|
||||
utils.REQTYPE: self.cgrCfg.CdrcReqTypeField,
|
||||
utils.DIRECTION: self.cgrCfg.CdrcDirectionField,
|
||||
utils.TENANT: self.cgrCfg.CdrcTenantField,
|
||||
utils.TOR: self.cgrCfg.CdrcTorField,
|
||||
utils.Category: self.cgrCfg.CdrcTorField,
|
||||
utils.ACCOUNT: self.cgrCfg.CdrcAccountField,
|
||||
utils.SUBJECT: self.cgrCfg.CdrcSubjectField,
|
||||
utils.DESTINATION: self.cgrCfg.CdrcDestinationField,
|
||||
@@ -145,8 +145,8 @@ func (self *Cdrc) recordForkCdr(record []string) (*utils.StoredCdr, error) {
|
||||
ratedCdr.Direction = fieldVal
|
||||
case utils.TENANT:
|
||||
ratedCdr.Tenant = fieldVal
|
||||
case utils.TOR:
|
||||
ratedCdr.TOR = fieldVal
|
||||
case utils.Category:
|
||||
ratedCdr.Category = fieldVal
|
||||
case utils.ACCOUNT:
|
||||
ratedCdr.Account = fieldVal
|
||||
case utils.SUBJECT:
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestRecordForkCdr(t *testing.T) {
|
||||
ReqType: cdrRow[1],
|
||||
Direction: cdrRow[2],
|
||||
Tenant: cdrRow[3],
|
||||
TOR: cdrRow[4],
|
||||
Category: cdrRow[4],
|
||||
Account: cdrRow[5],
|
||||
Subject: cdrRow[6],
|
||||
Destination: cdrRow[7],
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestCsvCdrWriter(t *testing.T) {
|
||||
csvCdrWriter := NewCsvCdrWriter(writer, 0, 4, "", -1, exportedFields)
|
||||
ratedCdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1",
|
||||
ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Duration: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID,
|
||||
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func TestWriteCdr(t *testing.T) {
|
||||
}
|
||||
fwWriter := FixedWidthCdrWriter{writer: wrBuf, exportTemplate: exportTpl, roundDecimals: 4, header: &bytes.Buffer{}, content: &bytes.Buffer{}, trailer: &bytes.Buffer{}}
|
||||
cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 1, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 2.34567,
|
||||
@@ -143,14 +143,14 @@ func TestWriteCdrs(t *testing.T) {
|
||||
}
|
||||
fwWriter := FixedWidthCdrWriter{writer: wrBuf, exportTemplate: exportTpl, roundDecimals: 4, header: &bytes.Buffer{}, content: &bytes.Buffer{}, trailer: &bytes.Buffer{}}
|
||||
cdr1 := &utils.StoredCdr{CgrId: utils.Sha1("aaa1", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 2, AccId: "aaa1", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1010",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1010",
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 2.25,
|
||||
ExtraFields: map[string]string{"productnumber": "12341", "fieldextr2": "valextr2"},
|
||||
}
|
||||
cdr2 := &utils.StoredCdr{CgrId: utils.Sha1("aaa2", time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC).String()), OrderId: 4, AccId: "aaa2", CdrHost: "192.168.1.2", ReqType: "prepaid", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1002", Subject: "1002", Destination: "1011",
|
||||
Category: "call", Account: "1002", Subject: "1002", Destination: "1011",
|
||||
SetupTime: time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 7, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(5) * time.Minute, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.40001,
|
||||
@@ -158,7 +158,7 @@ func TestWriteCdrs(t *testing.T) {
|
||||
}
|
||||
cdr3 := &utils.StoredCdr{}
|
||||
cdr4 := &utils.StoredCdr{CgrId: utils.Sha1("aaa3", time.Date(2013, 11, 7, 9, 42, 18, 0, time.UTC).String()), OrderId: 3, AccId: "aaa4", CdrHost: "192.168.1.4", ReqType: "postpaid", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1004", Subject: "1004", Destination: "1013",
|
||||
Category: "call", Account: "1004", Subject: "1004", Destination: "1013",
|
||||
SetupTime: time.Date(2013, 11, 7, 9, 42, 18, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 9, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(20) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 2.34567,
|
||||
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
FS_ACCOUNT = "cgr_account"
|
||||
FS_DESTINATION = "cgr_destination"
|
||||
FS_REQTYPE = "cgr_reqtype" //prepaid or postpaid
|
||||
FS_TOR = "cgr_tor"
|
||||
FS_CATEGORY = "cgr_category"
|
||||
FS_UUID = "uuid" // -Unique ID for this call leg
|
||||
FS_CSTMID = "cgr_tenant"
|
||||
FS_CALL_DEST_NR = "dialed_extension"
|
||||
@@ -104,8 +104,8 @@ func (fsCdr FSCdr) GetDestination() string {
|
||||
return utils.FirstNonEmpty(fsCdr.vars[FS_DESTINATION], fsCdr.vars[FS_CALL_DEST_NR], fsCdr.vars[FS_SIP_REQUSER])
|
||||
}
|
||||
|
||||
func (fsCdr FSCdr) GetTOR() string {
|
||||
return utils.FirstNonEmpty(fsCdr.vars[FS_TOR], cfg.DefaultTOR)
|
||||
func (fsCdr FSCdr) GetCategory() string {
|
||||
return utils.FirstNonEmpty(fsCdr.vars[FS_CATEGORY], cfg.DefaultCategory)
|
||||
}
|
||||
|
||||
func (fsCdr FSCdr) GetTenant() string {
|
||||
@@ -177,7 +177,7 @@ func (fsCdr FSCdr) Store() (result string, err error) {
|
||||
result += fsCdr.GetSubject() + "|"
|
||||
result += fsCdr.GetAccount() + "|"
|
||||
result += fsCdr.GetDestination() + "|"
|
||||
result += fsCdr.GetTOR() + "|"
|
||||
result += fsCdr.GetCategory() + "|"
|
||||
result += fsCdr.GetAccId() + "|"
|
||||
result += fsCdr.GetTenant() + "|"
|
||||
result += fsCdr.GetReqType() + "|"
|
||||
@@ -240,8 +240,8 @@ func (fsCdr FSCdr) ForkCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, a
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, tenantFld))
|
||||
}
|
||||
if strings.HasPrefix(torFld, utils.STATIC_VALUE_PREFIX) {
|
||||
rtCdr.TOR = torFld[1:]
|
||||
} else if rtCdr.TOR, hasKey = fsCdr.vars[torFld]; !hasKey && fieldsMandatory {
|
||||
rtCdr.Category = torFld[1:]
|
||||
} else if rtCdr.Category, hasKey = fsCdr.vars[torFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, torFld))
|
||||
}
|
||||
if strings.HasPrefix(accountFld, utils.STATIC_VALUE_PREFIX) {
|
||||
|
||||
@@ -69,7 +69,7 @@ func TestCDRFields(t *testing.T) {
|
||||
if fsCdr.GetDestination() != "+4986517174963" {
|
||||
t.Error("Error parsing cdr: ", fsCdr)
|
||||
}
|
||||
if fsCdr.GetTOR() != "call" {
|
||||
if fsCdr.GetCategory() != "call" {
|
||||
t.Error("Error parsing cdr: ", fsCdr)
|
||||
}
|
||||
if fsCdr.GetTenant() != "ipbx.itsyscom.com" {
|
||||
@@ -115,7 +115,7 @@ func TestFsCdrForkCdr(t *testing.T) {
|
||||
}
|
||||
expctRatedCdr := &utils.StoredCdr{CgrId: utils.Sha1("01df56f4-d99a-4ef6-b7fe-b924b2415b7f", time.Date(2013, 8, 4, 9, 50, 54, 0, time.UTC).Local().String()), AccId: "01df56f4-d99a-4ef6-b7fe-b924b2415b7f",
|
||||
CdrHost: "127.0.0.1", CdrSource: FS_CDR_SOURCE, ReqType: utils.RATED,
|
||||
Direction: "*out", Tenant: "ipbx.itsyscom.com", TOR: "call", Account: "dan", Subject: "dan", Destination: "+4986517174963",
|
||||
Direction: "*out", Tenant: "ipbx.itsyscom.com", Category: "call", Account: "dan", Subject: "dan", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 8, 4, 9, 50, 54, 0, time.UTC).Local(),
|
||||
AnswerTime: time.Date(2013, 8, 4, 9, 50, 56, 0, time.UTC).Local(), Duration: time.Duration(4) * time.Second,
|
||||
ExtraFields: map[string]string{"effective_caller_id_number": "+4986517174960"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
@@ -129,7 +129,7 @@ func TestFsCdrForkCdr(t *testing.T) {
|
||||
}
|
||||
expctRatedCdr2 := &utils.StoredCdr{CgrId: utils.Sha1("01df56f4-d99a-4ef6-b7fe-b924b2415b7f", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), AccId: "01df56f4-d99a-4ef6-b7fe-b924b2415b7f", CdrHost: "127.0.0.1",
|
||||
CdrSource: FS_CDR_SOURCE, ReqType: "postpaid",
|
||||
Direction: "*in", Tenant: "cgrates.com", TOR: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "+4986517174963",
|
||||
Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(12) * time.Second,
|
||||
ExtraFields: map[string]string{"effective_caller_id_number": "+4986517174960"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
|
||||
@@ -77,7 +77,7 @@ type CGRConfig struct {
|
||||
RPCGOBListen string // RPC GOB listening address
|
||||
HTTPListen string // HTTP listening address
|
||||
DefaultReqType string // Use this request type if not defined on top
|
||||
DefaultTOR string // set default type of record
|
||||
DefaultCategory string // set default type of record
|
||||
DefaultTenant string // set default tenant
|
||||
DefaultSubject string // set default rating subject, useful in case of fallback
|
||||
RoundingMethod string // Rounding method for the end price: <*up|*middle|*down>
|
||||
@@ -166,7 +166,7 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.RPCGOBListen = "127.0.0.1:2013"
|
||||
self.HTTPListen = "127.0.0.1:2080"
|
||||
self.DefaultReqType = utils.RATED
|
||||
self.DefaultTOR = "call"
|
||||
self.DefaultCategory = "call"
|
||||
self.DefaultTenant = "cgrates.org"
|
||||
self.DefaultSubject = "cgrates"
|
||||
self.RoundingMethod = utils.ROUNDING_MIDDLE
|
||||
@@ -235,7 +235,7 @@ func (self *CGRConfig) setDefaults() error {
|
||||
&utils.RSRField{Id: utils.REQTYPE},
|
||||
&utils.RSRField{Id: utils.DIRECTION},
|
||||
&utils.RSRField{Id: utils.TENANT},
|
||||
&utils.RSRField{Id: utils.TOR},
|
||||
&utils.RSRField{Id: utils.Category},
|
||||
&utils.RSRField{Id: utils.ACCOUNT},
|
||||
&utils.RSRField{Id: utils.SUBJECT},
|
||||
&utils.RSRField{Id: utils.DESTINATION},
|
||||
@@ -371,8 +371,8 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
if hasOpt = c.HasOption("global", "default_reqtype"); hasOpt {
|
||||
cfg.DefaultReqType, _ = c.GetString("global", "default_reqtype")
|
||||
}
|
||||
if hasOpt = c.HasOption("global", "default_tor"); hasOpt {
|
||||
cfg.DefaultTOR, _ = c.GetString("global", "default_tor")
|
||||
if hasOpt = c.HasOption("global", "default_category"); hasOpt {
|
||||
cfg.DefaultCategory, _ = c.GetString("global", "default_category")
|
||||
}
|
||||
if hasOpt = c.HasOption("global", "default_tenant"); hasOpt {
|
||||
cfg.DefaultTenant, _ = c.GetString("global", "default_tenant")
|
||||
|
||||
@@ -69,7 +69,7 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.RPCGOBListen = "127.0.0.1:2013"
|
||||
eCfg.HTTPListen = "127.0.0.1:2080"
|
||||
eCfg.DefaultReqType = utils.RATED
|
||||
eCfg.DefaultTOR = "call"
|
||||
eCfg.DefaultCategory = "call"
|
||||
eCfg.DefaultTenant = "cgrates.org"
|
||||
eCfg.DefaultSubject = "cgrates"
|
||||
eCfg.RoundingMethod = utils.ROUNDING_MIDDLE
|
||||
@@ -138,7 +138,7 @@ func TestDefaults(t *testing.T) {
|
||||
&utils.RSRField{Id: utils.REQTYPE},
|
||||
&utils.RSRField{Id: utils.DIRECTION},
|
||||
&utils.RSRField{Id: utils.TENANT},
|
||||
&utils.RSRField{Id: utils.TOR},
|
||||
&utils.RSRField{Id: utils.Category},
|
||||
&utils.RSRField{Id: utils.ACCOUNT},
|
||||
&utils.RSRField{Id: utils.SUBJECT},
|
||||
&utils.RSRField{Id: utils.DESTINATION},
|
||||
@@ -203,7 +203,7 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.RPCGOBListen = "test"
|
||||
eCfg.HTTPListen = "test"
|
||||
eCfg.DefaultReqType = "test"
|
||||
eCfg.DefaultTOR = "test"
|
||||
eCfg.DefaultCategory = "test"
|
||||
eCfg.DefaultTenant = "test"
|
||||
eCfg.DefaultSubject = "test"
|
||||
eCfg.RoundingMethod = "test"
|
||||
|
||||
@@ -25,7 +25,7 @@ rpc_json_listen = test # RPC JSON listening address
|
||||
rpc_gob_listen = test # RPC GOB listening address
|
||||
http_listen = test # HTTP listening address
|
||||
default_reqtype = test # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
|
||||
default_tor = test # Default Type of Record to consider when missing from requests.
|
||||
default_category = test # Default Type of Record to consider when missing from requests.
|
||||
default_tenant = test # Default Tenant to consider when missing from requests.
|
||||
default_subject = test # Default rating Subject to consider when missing from requests.
|
||||
rounding_method = test # Rounding method for floats/costs: <up|middle|down>
|
||||
|
||||
@@ -50,7 +50,7 @@ func (self *CmdGetCallCost) RpcMethod() string {
|
||||
}
|
||||
|
||||
func (self *CmdGetCallCost) RpcParams() interface{} {
|
||||
if self.rpcParams == nil {
|
||||
if self.rpcParams == nil {
|
||||
self.rpcParams = &apier.AttrGetCallCost{RunId: utils.DEFAULT_RUNID}
|
||||
}
|
||||
return self.rpcParams
|
||||
|
||||
@@ -183,6 +183,7 @@ CREATE TABLE `tp_action_triggers` (
|
||||
`direction` varchar(8) NOT NULL,
|
||||
`threshold_type` char(12) NOT NULL,
|
||||
`threshold_value` double(20,4) NOT NULL,
|
||||
`recurrent` bool NOT NULL,
|
||||
`destination_id` varchar(64) NOT NULL,
|
||||
`actions_id` varchar(64) NOT NULL,
|
||||
`weight` double(8,2) NOT NULL,
|
||||
@@ -219,9 +220,9 @@ CREATE TABLE tp_derived_chargers (
|
||||
tbid int(11) NOT NULL AUTO_INCREMENT,
|
||||
tpid varchar(64) NOT NULL,
|
||||
loadid varchar(64) NOT NULL,
|
||||
direction varchar(8) NOT NULL,
|
||||
tenant varchar(64) NOT NULL,
|
||||
tor varchar(16) NOT NULL,
|
||||
direction varchar(8) NOT NULL,
|
||||
account varchar(24) NOT NULL,
|
||||
subject varchar(64) NOT NULL,
|
||||
runid_field varchar(24) NOT NULL,
|
||||
@@ -237,4 +238,4 @@ CREATE TABLE tp_derived_chargers (
|
||||
duration_field varchar(24) NOT NULL,
|
||||
PRIMARY KEY (`tbid`),
|
||||
KEY `tpid` (`tpid`)
|
||||
);
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Tag,BalanceType,Direction,ThresholdType,ThresholdValue,DestinationTag,ActionsTag,Weight
|
||||
STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,,LOG_BALANCE,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,,LOG_BALANCE,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_counter,15,FS_USERS,LOG_BALANCE,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,false,,LOG_BALANCE,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,false,,LOG_BALANCE,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_counter,15,false,FS_USERS,LOG_BALANCE,10
|
||||
|
||||
|
@@ -34,14 +34,10 @@ const (
|
||||
INBOUND = "*in"
|
||||
OUTBOUND = "*out"
|
||||
// Balance types
|
||||
CREDIT = "*monetary"
|
||||
SMS = "*sms"
|
||||
DATA = "*data"
|
||||
DATA_TIME = "*data_time"
|
||||
MINUTES = "*minutes"
|
||||
// action price type
|
||||
PRICE_PERCENT = "*percent"
|
||||
PRICE_ABSOLUTE = "*absolute"
|
||||
CREDIT = "*monetary"
|
||||
SMS = "*sms"
|
||||
DATA = "*data"
|
||||
MINUTES = "*call_duration"
|
||||
// action trigger threshold types
|
||||
TRIGGER_MIN_COUNTER = "*min_counter"
|
||||
TRIGGER_MAX_COUNTER = "*max_counter"
|
||||
@@ -49,10 +45,6 @@ const (
|
||||
TRIGGER_MAX_BALANCE = "*max_balance"
|
||||
)
|
||||
|
||||
var (
|
||||
AMOUNT_TOO_BIG = errors.New("Amount excedes balance!")
|
||||
)
|
||||
|
||||
/*
|
||||
Structure containing information about user's credit (minutes, cents, sms...).'
|
||||
This can represent a user or a shared group.
|
||||
@@ -70,7 +62,7 @@ type Account struct {
|
||||
|
||||
func (ub *Account) getCreditForPrefix(cd *CallDescriptor) (duration time.Duration, credit float64, balances BalanceChain) {
|
||||
creditBalances := ub.getBalancesForPrefix(cd.Destination, ub.BalanceMap[CREDIT+cd.Direction], "")
|
||||
minuteBalances := ub.getBalancesForPrefix(cd.Destination, ub.BalanceMap[MINUTES+cd.Direction], "")
|
||||
unitBalances := ub.getBalancesForPrefix(cd.Destination, ub.BalanceMap[cd.Tor+cd.Direction], "")
|
||||
// gather all balances from shared groups
|
||||
var extendedCreditBalances BalanceChain
|
||||
for _, cb := range creditBalances {
|
||||
@@ -85,10 +77,10 @@ func (ub *Account) getCreditForPrefix(cd *CallDescriptor) (duration time.Duratio
|
||||
}
|
||||
}
|
||||
var extendedMinuteBalances BalanceChain
|
||||
for _, mb := range minuteBalances {
|
||||
for _, mb := range unitBalances {
|
||||
if mb.SharedGroup != "" {
|
||||
if sharedGroup, _ := accountingStorage.GetSharedGroup(mb.SharedGroup, false); sharedGroup != nil {
|
||||
sgb := sharedGroup.GetBalances(cd.Destination, MINUTES+cd.Direction, ub)
|
||||
sgb := sharedGroup.GetBalances(cd.Destination, cd.Tor+cd.Direction, ub)
|
||||
sgb = sharedGroup.SortBalancesByStrategy(mb, sgb)
|
||||
extendedMinuteBalances = append(extendedMinuteBalances, sgb...)
|
||||
}
|
||||
@@ -211,11 +203,11 @@ func (account *Account) getAlldBalancesForPrefix(destination, balanceType string
|
||||
}
|
||||
|
||||
func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) {
|
||||
usefulMinuteBalances := ub.getAlldBalancesForPrefix(cc.Destination, MINUTES+cc.Direction)
|
||||
usefulUnitBalances := ub.getAlldBalancesForPrefix(cc.Destination, cc.Tor+cc.Direction)
|
||||
usefulMoneyBalances := ub.getAlldBalancesForPrefix(cc.Destination, CREDIT+cc.Direction)
|
||||
// debit minutes
|
||||
for _, balance := range usefulMinuteBalances {
|
||||
balance.DebitMinutes(cc, count, balance.account, usefulMoneyBalances)
|
||||
for _, balance := range usefulUnitBalances {
|
||||
balance.DebitUnits(cc, count, balance.account, usefulMoneyBalances)
|
||||
if cc.IsPaid() {
|
||||
goto CONNECT_FEE
|
||||
}
|
||||
@@ -292,7 +284,7 @@ CONNECT_FEE:
|
||||
}
|
||||
// save darty shared balances
|
||||
usefulMoneyBalances.SaveDirtyBalances(ub)
|
||||
usefulMinuteBalances.SaveDirtyBalances(ub)
|
||||
usefulUnitBalances.SaveDirtyBalances(ub)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -308,15 +300,15 @@ func (ub *Account) GetDefaultMoneyBalance(direction string) *Balance {
|
||||
return defaultBalance
|
||||
}
|
||||
|
||||
func (ub *Account) refundIncrement(increment *Increment, direction string, count bool) {
|
||||
func (ub *Account) refundIncrement(increment *Increment, direction, unitType string, count bool) {
|
||||
var balance *Balance
|
||||
if increment.BalanceInfo.MinuteBalanceUuid != "" {
|
||||
if balance = ub.BalanceMap[MINUTES+direction].GetBalance(increment.BalanceInfo.MinuteBalanceUuid); balance == nil {
|
||||
if increment.BalanceInfo.UnitBalanceUuid != "" {
|
||||
if balance = ub.BalanceMap[unitType+direction].GetBalance(increment.BalanceInfo.UnitBalanceUuid); balance == nil {
|
||||
return
|
||||
}
|
||||
balance.Value += increment.Duration.Seconds()
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: MINUTES, Direction: direction, Balance: &Balance{Value: -increment.Duration.Seconds()}})
|
||||
ub.countUnits(&Action{BalanceType: unitType, Direction: direction, Balance: &Balance{Value: -increment.Duration.Seconds()}})
|
||||
}
|
||||
}
|
||||
// check money too
|
||||
@@ -391,6 +383,16 @@ func (ub *Account) ResetActionTriggers(a *Action) {
|
||||
ub.executeActionTriggers(a)
|
||||
}
|
||||
|
||||
// Sets/Unsets recurrent flag for action triggers
|
||||
func (ub *Account) SetRecurrent(a *Action, recurrent bool) {
|
||||
for _, at := range ub.ActionTriggers {
|
||||
if !at.Match(a) {
|
||||
continue
|
||||
}
|
||||
at.Recurrent = recurrent
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the unit counter that matches the specified action type
|
||||
func (ub *Account) getUnitCounter(a *Action) *UnitsCounter {
|
||||
for _, uc := range ub.UnitCounters {
|
||||
@@ -477,9 +479,9 @@ func (ub *Account) GetSharedGroups() (groups []string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (account *Account) GetUniqueSharedGroupMembers(destination, direction string) ([]string, error) {
|
||||
func (account *Account) GetUniqueSharedGroupMembers(destination, direction, unitType string) ([]string, error) {
|
||||
creditBalances := account.getBalancesForPrefix(destination, account.BalanceMap[CREDIT+direction], "")
|
||||
minuteBalances := account.getBalancesForPrefix(destination, account.BalanceMap[MINUTES+direction], "")
|
||||
unitBalances := account.getBalancesForPrefix(destination, account.BalanceMap[unitType+direction], "")
|
||||
// gather all shared group ids
|
||||
var sharedGroupIds []string
|
||||
for _, cb := range creditBalances {
|
||||
@@ -487,7 +489,7 @@ func (account *Account) GetUniqueSharedGroupMembers(destination, direction strin
|
||||
sharedGroupIds = append(sharedGroupIds, cb.SharedGroup)
|
||||
}
|
||||
}
|
||||
for _, mb := range minuteBalances {
|
||||
for _, mb := range unitBalances {
|
||||
if mb.SharedGroup != "" {
|
||||
sharedGroupIds = append(sharedGroupIds, mb.SharedGroup)
|
||||
}
|
||||
|
||||
@@ -97,14 +97,15 @@ func TestGetSecondsForPrefix(t *testing.T) {
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
ub1 := &Account{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 200}}}}
|
||||
cd := &CallDescriptor{
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
TimeStart: time.Date(2013, 10, 4, 15, 46, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 4, 15, 46, 10, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
CallDuration: 10 * time.Second,
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
TimeStart: time.Date(2013, 10, 4, 15, 46, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 4, 15, 46, 10, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: 10 * time.Second,
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723",
|
||||
Tor: MINUTES,
|
||||
}
|
||||
seconds, credit, bucketList := ub1.getCreditForPrefix(cd)
|
||||
expected := 110 * time.Second
|
||||
@@ -126,13 +127,14 @@ func TestGetSpecialPricedSeconds(t *testing.T) {
|
||||
},
|
||||
}
|
||||
cd := &CallDescriptor{
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
TimeStart: time.Date(2013, 10, 4, 15, 46, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 4, 15, 46, 60, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723",
|
||||
Tor: MINUTES,
|
||||
}
|
||||
seconds, credit, bucketList := ub1.getCreditForPrefix(cd)
|
||||
expected := 20 * time.Second
|
||||
@@ -164,19 +166,20 @@ func TestDebitCreditZeroSecond(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}}
|
||||
err := rifsBalance.debitCreditBalance(cc, false)
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" {
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" {
|
||||
t.Logf("%+v", cc.Timespans[0])
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -193,12 +196,13 @@ func TestDebitCreditZeroMinute(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -209,7 +213,7 @@ func TestDebitCreditZeroMinute(t *testing.T) {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
t.Logf("%+v", cc.Timespans)
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Minute {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -227,13 +231,14 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 20, 0, time.UTC),
|
||||
ratingInfo: &RatingInfo{},
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 20, 0, time.UTC),
|
||||
ratingInfo: &RatingInfo{},
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1, b2},
|
||||
@@ -243,8 +248,8 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "tests" ||
|
||||
cc.Timespans[1].Increments[0].BalanceInfo.MinuteBalanceUuid != "testm" {
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "tests" ||
|
||||
cc.Timespans[1].Increments[0].BalanceInfo.UnitBalanceUuid != "testm" {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0], cc.Timespans[1].Increments[0])
|
||||
}
|
||||
if rifsBalance.BalanceMap[MINUTES+OUTBOUND][1].Value != 0 ||
|
||||
@@ -261,18 +266,19 @@ func TestDebitCreditNoCredit(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -281,7 +287,7 @@ func TestDebitCreditNoCredit(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Error("Showing no enough credit error ")
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Minute {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -301,18 +307,19 @@ func TestDebitCreditHasCredit(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -322,7 +329,7 @@ func TestDebitCreditHasCredit(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Minute {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -343,13 +350,14 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 20, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 20, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -359,7 +367,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != 10*time.Second {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -380,18 +388,19 @@ func TestDebitCreditMoreTimespans(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -400,7 +409,7 @@ func TestDebitCreditMoreTimespans(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Minute {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -418,18 +427,19 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1, b2},
|
||||
@@ -438,7 +448,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Minute {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -456,18 +466,19 @@ func TestDebitCreditNoConectFeeCredit(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{ConnectFee: 10.0, Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{ConnectFee: 10.0, Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
MINUTES + OUTBOUND: BalanceChain{b1},
|
||||
@@ -488,19 +499,20 @@ func TestDebitCreditMoneyOnly(t *testing.T) {
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "money", Value: 50}},
|
||||
@@ -530,17 +542,18 @@ func TestDebitCreditSubjectMinutes(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 250, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"}
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
deductConnectFee: true,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
@@ -551,7 +564,7 @@ func TestDebitCreditSubjectMinutes(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].BalanceInfo.MoneyBalanceUuid != "moneya" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Second {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
@@ -572,17 +585,18 @@ func TestDebitCreditSubjectMinutes(t *testing.T) {
|
||||
func TestDebitCreditSubjectMoney(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
deductConnectFee: true,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
@@ -609,17 +623,18 @@ func TestDebitCreditSubjectMixed(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 40, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"}
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 55, 0, time.UTC),
|
||||
CallDuration: 55 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 55, 0, time.UTC),
|
||||
DurationIndex: 55 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
deductConnectFee: true,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
@@ -630,7 +645,7 @@ func TestDebitCreditSubjectMixed(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].BalanceInfo.MoneyBalanceUuid != "moneya" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Second {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
@@ -652,23 +667,24 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"}
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
deductConnectFee: true,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
@@ -680,7 +696,7 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) {
|
||||
t.Error("Error showing debiting balance error: ", err)
|
||||
}
|
||||
//t.Logf("%+v %+v", cc.Timespans[0], cc.Timespans[1])
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Second {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -703,23 +719,24 @@ func TestDebitCreditSubjectMixedPartPay(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RatingSubject: "minu"}
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
CallDuration: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
CallDuration: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
DurationIndex: 10 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: MINUTES,
|
||||
deductConnectFee: true,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
@@ -731,7 +748,7 @@ func TestDebitCreditSubjectMixedPartPay(t *testing.T) {
|
||||
t.Error("Error showing debiting balance error: ", err)
|
||||
}
|
||||
//t.Logf("%+v %+v", cc.Timespans[0], cc.Timespans[1])
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" ||
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testb" ||
|
||||
cc.Timespans[0].Increments[0].Duration != time.Second {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
@@ -940,12 +957,12 @@ func TestAccountRefund(t *testing.T) {
|
||||
},
|
||||
}
|
||||
increments := Increments{
|
||||
&Increment{Cost: 2, BalanceInfo: &BalanceInfo{MinuteBalanceUuid: "", MoneyBalanceUuid: "moneya"}},
|
||||
&Increment{Cost: 2, Duration: 3 * time.Second, BalanceInfo: &BalanceInfo{MinuteBalanceUuid: "minutea", MoneyBalanceUuid: "moneya"}},
|
||||
&Increment{Duration: 4 * time.Second, BalanceInfo: &BalanceInfo{MinuteBalanceUuid: "minuteb", MoneyBalanceUuid: ""}},
|
||||
&Increment{Cost: 2, BalanceInfo: &BalanceInfo{UnitBalanceUuid: "", MoneyBalanceUuid: "moneya"}},
|
||||
&Increment{Cost: 2, Duration: 3 * time.Second, BalanceInfo: &BalanceInfo{UnitBalanceUuid: "minutea", MoneyBalanceUuid: "moneya"}},
|
||||
&Increment{Duration: 4 * time.Second, BalanceInfo: &BalanceInfo{UnitBalanceUuid: "minuteb", MoneyBalanceUuid: ""}},
|
||||
}
|
||||
for _, increment := range increments {
|
||||
ub.refundIncrement(increment, OUTBOUND, false)
|
||||
ub.refundIncrement(increment, OUTBOUND, MINUTES, false)
|
||||
}
|
||||
if ub.BalanceMap[CREDIT+OUTBOUND][0].Value != 104 ||
|
||||
ub.BalanceMap[MINUTES+OUTBOUND][0].Value != 13 ||
|
||||
@@ -957,15 +974,15 @@ func TestAccountRefund(t *testing.T) {
|
||||
func TestDebitShared(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 0, 0, time.UTC),
|
||||
CallDuration: 55 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 2, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 0, 0, time.UTC),
|
||||
DurationIndex: 55 * time.Second,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 2, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
deductConnectFee: true,
|
||||
@@ -1013,6 +1030,114 @@ func TestDebitShared(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitSMS(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 48, 1, 0, time.UTC),
|
||||
ratingInfo: &RatingInfo{},
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1 * time.Second, RateUnit: time.Second}}}},
|
||||
},
|
||||
},
|
||||
Tor: SMS,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
SMS + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationId: "NAT"}},
|
||||
CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}},
|
||||
}}
|
||||
err := rifsBalance.debitCreditBalance(cc, false)
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testm" {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
if rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value != 99 ||
|
||||
rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 21 {
|
||||
t.Log(cc.Timespans[0].Increments)
|
||||
t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitDataUnits(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
ratingInfo: &RatingInfo{},
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
Rates: RateGroups{
|
||||
&Rate{GroupIntervalStart: 0, Value: 2, RateIncrement: 1 * time.Second, RateUnit: time.Minute},
|
||||
&Rate{GroupIntervalStart: 60, Value: 1, RateIncrement: 1 * time.Second, RateUnit: time.Second},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tor: DATA,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationId: "NAT"}},
|
||||
CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}},
|
||||
}}
|
||||
err := rifsBalance.debitCreditBalance(cc, false)
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if cc.Timespans[0].Increments[0].BalanceInfo.UnitBalanceUuid != "testm" {
|
||||
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
|
||||
}
|
||||
if rifsBalance.BalanceMap[DATA+OUTBOUND][0].Value != 20 ||
|
||||
rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 21 {
|
||||
t.Log(cc.Timespans[0].Increments)
|
||||
t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[DATA+OUTBOUND][0].Value, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitDataMoney(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
Timespans: []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC),
|
||||
ratingInfo: &RatingInfo{},
|
||||
DurationIndex: 0,
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
Rates: RateGroups{
|
||||
&Rate{GroupIntervalStart: 0, Value: 2, RateIncrement: time.Minute, RateUnit: time.Second},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tor: DATA,
|
||||
}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{
|
||||
DATA + OUTBOUND: BalanceChain{&Balance{Uuid: "testm", Value: 0, Weight: 5, DestinationId: "NAT"}},
|
||||
CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 160}},
|
||||
}}
|
||||
err := rifsBalance.debitCreditBalance(cc, false)
|
||||
if err != nil {
|
||||
t.Error("Error debiting balance: ", err)
|
||||
}
|
||||
if rifsBalance.BalanceMap[DATA+OUTBOUND][0].Value != 0 ||
|
||||
rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 0 {
|
||||
t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[DATA+OUTBOUND][0].Value, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************** Benchmarks *******************************/
|
||||
|
||||
func BenchmarkGetSecondForPrefix(b *testing.B) {
|
||||
|
||||
@@ -50,6 +50,8 @@ type Action struct {
|
||||
const (
|
||||
LOG = "*log"
|
||||
RESET_TRIGGERS = "*reset_triggers"
|
||||
SET_RECURRENT = "*set_recurrent"
|
||||
UNSET_RECURRENT = "*unset_recurrent"
|
||||
ALLOW_NEGATIVE = "*allow_negative"
|
||||
DENY_NEGATIVE = "*deny_negative"
|
||||
RESET_ACCOUNT = "*reset_account"
|
||||
@@ -74,6 +76,10 @@ func getActionFunc(typ string) (actionTypeFunc, bool) {
|
||||
return logAction, true
|
||||
case RESET_TRIGGERS:
|
||||
return resetTriggersAction, true
|
||||
case SET_RECURRENT:
|
||||
return setRecurrentAction, true
|
||||
case UNSET_RECURRENT:
|
||||
return unsetRecurrentAction, true
|
||||
case ALLOW_NEGATIVE:
|
||||
return allowNegativeAction, true
|
||||
case DENY_NEGATIVE:
|
||||
@@ -115,6 +121,16 @@ func resetTriggersAction(ub *Account, a *Action) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func setRecurrentAction(ub *Account, a *Action) (err error) {
|
||||
ub.SetRecurrent(a, true)
|
||||
return
|
||||
}
|
||||
|
||||
func unsetRecurrentAction(ub *Account, a *Action) (err error) {
|
||||
ub.SetRecurrent(a, false)
|
||||
return
|
||||
}
|
||||
|
||||
func allowNegativeAction(ub *Account, a *Action) (err error) {
|
||||
ub.AllowNegative = true
|
||||
return
|
||||
|
||||
@@ -32,6 +32,7 @@ type ActionTrigger struct {
|
||||
Direction string
|
||||
ThresholdType string //*min_counter, *max_counter, *min_balance, *max_balance
|
||||
ThresholdValue float64
|
||||
Recurrent bool // reset eexcuted flag each run
|
||||
DestinationId string
|
||||
Weight float64
|
||||
ActionsId string
|
||||
@@ -68,7 +69,7 @@ func (at *ActionTrigger) Execute(ub *Account) (err error) {
|
||||
atLeastOneActionExecuted = true
|
||||
}
|
||||
}
|
||||
if !atLeastOneActionExecuted {
|
||||
if !atLeastOneActionExecuted || at.Recurrent {
|
||||
at.Executed = false
|
||||
}
|
||||
storageLogger.LogActionTrigger(ub.Id, RATER_SOURCE, at, aac)
|
||||
|
||||
@@ -142,7 +142,7 @@ func (b *Balance) SubstractAmount(amount float64) {
|
||||
b.dirty = true
|
||||
}
|
||||
|
||||
func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalances BalanceChain) error {
|
||||
func (b *Balance) DebitUnits(cc *CallCost, count bool, ub *Account, moneyBalances BalanceChain) error {
|
||||
for tsIndex := 0; tsIndex < len(cc.Timespans); tsIndex++ {
|
||||
if b.Value <= 0 {
|
||||
return nil
|
||||
@@ -202,13 +202,13 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalan
|
||||
inc = newTs.Increments[0]
|
||||
}
|
||||
b.SubstractAmount(amount)
|
||||
inc.BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
inc.BalanceInfo.UnitBalanceUuid = b.Uuid
|
||||
inc.BalanceInfo.AccountId = ub.Id
|
||||
inc.MinuteInfo = &MinuteInfo{cc.Destination, amount}
|
||||
inc.UnitInfo = &UnitInfo{cc.Destination, amount, cc.Tor}
|
||||
inc.Cost = 0
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
|
||||
ub.countUnits(&Action{BalanceType: cc.Tor, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
|
||||
}
|
||||
}
|
||||
continue
|
||||
@@ -218,7 +218,7 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalan
|
||||
cd.Subject = b.RatingSubject
|
||||
cd.TimeStart = ts.GetTimeStartForIncrement(incrementIndex)
|
||||
cd.TimeEnd = cc.Timespans[len(cc.Timespans)-1].TimeEnd
|
||||
cd.CallDuration = cc.Timespans[len(cc.Timespans)-1].CallDuration
|
||||
cd.DurationIndex = cc.Timespans[len(cc.Timespans)-1].DurationIndex
|
||||
newCC, err := b.GetCost(cd)
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("Error getting new cost for balance subject: %v", err))
|
||||
@@ -242,9 +242,9 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalan
|
||||
}
|
||||
if (cost == 0 || moneyBal != nil) && b.Value >= seconds {
|
||||
b.SubstractAmount(seconds)
|
||||
nInc.BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
nInc.BalanceInfo.UnitBalanceUuid = b.Uuid
|
||||
nInc.BalanceInfo.AccountId = ub.Id
|
||||
nInc.MinuteInfo = &MinuteInfo{newCC.Destination, seconds}
|
||||
nInc.UnitInfo = &UnitInfo{newCC.Destination, seconds, cc.Tor}
|
||||
if cost != 0 {
|
||||
nInc.BalanceInfo.MoneyBalanceUuid = moneyBal.Uuid
|
||||
moneyBal.Value -= cost
|
||||
@@ -252,7 +252,7 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalan
|
||||
}
|
||||
nInc.paid = true
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: MINUTES, Direction: newCC.Direction, Balance: &Balance{Value: seconds, DestinationId: newCC.Destination}})
|
||||
ub.countUnits(&Action{BalanceType: newCC.Tor, Direction: newCC.Direction, Balance: &Balance{Value: seconds, DestinationId: newCC.Destination}})
|
||||
if cost != 0 {
|
||||
ub.countUnits(&Action{BalanceType: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: cost, DestinationId: newCC.Destination}})
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func (b *Balance) DebitMoney(cc *CallCost, count bool, ub *Account) error {
|
||||
cd.Subject = b.RatingSubject
|
||||
cd.TimeStart = ts.GetTimeStartForIncrement(incrementIndex)
|
||||
cd.TimeEnd = cc.Timespans[len(cc.Timespans)-1].TimeEnd
|
||||
cd.CallDuration = cc.Timespans[len(cc.Timespans)-1].CallDuration
|
||||
cd.DurationIndex = cc.Timespans[len(cc.Timespans)-1].DurationIndex
|
||||
newCC, err := b.GetCost(cd)
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("Error getting new cost for balance subject: %v", err))
|
||||
|
||||
@@ -18,16 +18,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The output structure that will be returned with the call cost information.
|
||||
type CallCost struct {
|
||||
Direction, TOR, Tenant, Subject, Account, Destination string
|
||||
Cost float64
|
||||
Timespans TimeSpans
|
||||
deductConnectFee bool
|
||||
Direction, Category, Tenant, Subject, Account, Destination, Tor string
|
||||
Cost float64
|
||||
Timespans TimeSpans
|
||||
deductConnectFee bool
|
||||
}
|
||||
|
||||
// Pretty printing for call cost
|
||||
@@ -98,7 +99,7 @@ func (cc *CallCost) GetConnectFee() float64 {
|
||||
func (cc *CallCost) CreateCallDescriptor() *CallDescriptor {
|
||||
return &CallDescriptor{
|
||||
Direction: cc.Direction,
|
||||
TOR: cc.TOR,
|
||||
Category: cc.Category,
|
||||
Tenant: cc.Tenant,
|
||||
Subject: cc.Subject,
|
||||
Account: cc.Account,
|
||||
@@ -114,3 +115,49 @@ func (cc *CallCost) IsPaid() bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (cc *CallCost) ToDataCost() (*DataCost, error) {
|
||||
if cc.Tor == MINUTES {
|
||||
return nil, errors.New("Not a data call!")
|
||||
}
|
||||
dc := &DataCost{
|
||||
Direction: cc.Direction,
|
||||
Category: cc.Category,
|
||||
Tenant: cc.Tenant,
|
||||
Subject: cc.Subject,
|
||||
Account: cc.Account,
|
||||
Destination: cc.Destination,
|
||||
Tor: cc.Tor,
|
||||
Cost: cc.Cost,
|
||||
deductConnectFee: cc.deductConnectFee,
|
||||
}
|
||||
dc.DataSpans = make([]*DataSpan, len(cc.Timespans))
|
||||
for i, ts := range cc.Timespans {
|
||||
length := ts.TimeEnd.Sub(ts.TimeStart).Seconds()
|
||||
callDuration := ts.DurationIndex.Seconds()
|
||||
dc.DataSpans[i] = &DataSpan{
|
||||
DataStart: callDuration - length,
|
||||
DataEnd: callDuration,
|
||||
Cost: ts.Cost,
|
||||
ratingInfo: ts.ratingInfo,
|
||||
RateInterval: ts.RateInterval,
|
||||
DataIndex: callDuration,
|
||||
MatchedSubject: ts.MatchedSubject,
|
||||
MatchedPrefix: ts.MatchedPrefix,
|
||||
MatchedDestId: ts.MatchedDestId,
|
||||
}
|
||||
dc.DataSpans[i].Increments = make([]*DataIncrement, len(ts.Increments))
|
||||
for j, incr := range ts.Increments {
|
||||
dc.DataSpans[i].Increments[j] = &DataIncrement{
|
||||
Amount: incr.Duration.Seconds(),
|
||||
Cost: incr.Cost,
|
||||
BalanceInfo: incr.BalanceInfo,
|
||||
BalanceRateInterval: incr.BalanceRateInterval,
|
||||
UnitInfo: incr.UnitInfo,
|
||||
CompressFactor: incr.CompressFactor,
|
||||
paid: incr.paid,
|
||||
}
|
||||
}
|
||||
}
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
@@ -19,14 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestSingleResultMerge(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 0, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 17, 1, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc1, _ := cd.GetCost()
|
||||
if cc1.Cost != 61 {
|
||||
t.Errorf("expected 61 was %v", cc1.Cost)
|
||||
@@ -50,7 +53,7 @@ func TestSingleResultMerge(t *testing.T) {
|
||||
func TestMultipleResultMerge(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 0, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc1, _ := cd.GetCost()
|
||||
if cc1.Cost != 61 {
|
||||
t.Errorf("expected 61 was %v", cc1.Cost)
|
||||
@@ -60,7 +63,7 @@ func TestMultipleResultMerge(t *testing.T) {
|
||||
}
|
||||
t1 = time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC)
|
||||
t2 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
|
||||
cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd = &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc2, _ := cd.GetCost()
|
||||
if cc2.Cost != 30 {
|
||||
t.Errorf("expected 30 was %v", cc2.Cost)
|
||||
@@ -80,7 +83,7 @@ func TestMultipleResultMerge(t *testing.T) {
|
||||
func TestMultipleInputLeftMerge(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc1, _ := cd.GetCost()
|
||||
if cc1.Cost != 91 {
|
||||
t.Errorf("expected 91 was %v", cc1.Cost)
|
||||
@@ -104,14 +107,14 @@ func TestMultipleInputLeftMerge(t *testing.T) {
|
||||
func TestMultipleInputRightMerge(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 58, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc1, _ := cd.GetCost()
|
||||
if cc1.Cost != 61 {
|
||||
t.Errorf("expected 61 was %v", cc1.Cost)
|
||||
}
|
||||
t1 = time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
|
||||
t2 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
|
||||
cd = &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd = &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc2, _ := cd.GetCost()
|
||||
if cc2.Cost != 91 {
|
||||
t.Errorf("expected 91 was %v", cc2.Cost)
|
||||
@@ -128,7 +131,7 @@ func TestMultipleInputRightMerge(t *testing.T) {
|
||||
func TestCallCostMergeEmpty(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 58, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: OUTBOUND, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cc1, _ := cd.GetCost()
|
||||
cc2 := &CallCost{}
|
||||
cc1.Merge(cc2)
|
||||
@@ -161,3 +164,44 @@ func TestCallCostGetDuration(t *testing.T) {
|
||||
t.Error("Wrong call cost duration: ", cc.GetDuration())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallCostToDataCostError(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
Category: "data",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 5, 0, time.UTC),
|
||||
Tor: MINUTES,
|
||||
}
|
||||
cc, _ := cd.GetCost()
|
||||
_, err := cc.ToDataCost()
|
||||
if err == nil {
|
||||
t.Error("Failed to throw error on call to datacost!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallCostToDataCost(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
Category: "data",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 5, 0, time.UTC),
|
||||
Tor: DATA,
|
||||
}
|
||||
cc, _ := cd.GetCost()
|
||||
dc, err := cc.ToDataCost()
|
||||
if err != nil {
|
||||
t.Error("Error convertiong to data cost: ", err)
|
||||
}
|
||||
js, _ := json.Marshal(dc)
|
||||
expected := `{"Direction":"*out","Category":"data","Tenant":"cgrates.org","Subject":"rif","Account":"","Destination":"*any","Tor":"*data","Cost":65,"DataSpans":[{"DataStart":0,"DataEnd":60,"Cost":60,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":0,"Rates":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":60000000000,"RateUnit":1000000000},{"GroupIntervalStart":60000000000,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"*up","RoundingDecimals":4},"Weight":10},"DataIndex":60,"Increments":[],"MatchedSubject":"","MatchedPrefix":"","MatchedDestId":""},{"DataStart":60,"DataEnd":65,"Cost":5,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":0,"Rates":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":60000000000,"RateUnit":1000000000},{"GroupIntervalStart":60000000000,"Value":1,"RateIncrement":1000000000,"RateUnit":1000000000}],"RoundingMethod":"*up","RoundingDecimals":4},"Weight":10},"DataIndex":65,"Increments":[],"MatchedSubject":"*out:cgrates.org:data:rif","MatchedPrefix":"*any","MatchedDestId":"*any"}]}`
|
||||
if string(js) != expected {
|
||||
t.Error("Error coverting to data cost: ", string(js))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,11 +107,11 @@ The input stucture that contains call information.
|
||||
*/
|
||||
type CallDescriptor struct {
|
||||
Direction string
|
||||
TOR string
|
||||
Category string
|
||||
Tenant, Subject, Account, Destination string
|
||||
TimeStart, TimeEnd time.Time
|
||||
LoopIndex float64 // indicates the position of this segment in a cost request loop
|
||||
CallDuration time.Duration // the call duration so far (till TimeEnd)
|
||||
DurationIndex time.Duration // the call duration so far (till TimeEnd)
|
||||
//Amount float64
|
||||
FallbackSubject string // the subject to check for destination if not found on primary subject
|
||||
RatingInfos RatingInfos
|
||||
@@ -120,14 +120,15 @@ type CallDescriptor struct {
|
||||
MaxRate float64
|
||||
MaxRateUnit time.Duration
|
||||
account *Account
|
||||
Tor string
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) ValidateCallData() error {
|
||||
if cd.TimeStart.After(cd.TimeEnd) || cd.TimeStart.Equal(cd.TimeEnd) {
|
||||
return errors.New("TimeStart must be strctly before TimeEnd")
|
||||
}
|
||||
if cd.TimeEnd.Sub(cd.TimeStart) < cd.CallDuration {
|
||||
return errors.New("CallDuration must be equal or grater than TimeEnd - TimeStart")
|
||||
if cd.TimeEnd.Sub(cd.TimeStart) < cd.DurationIndex {
|
||||
return errors.New("DurationIndex must be equal or grater than TimeEnd - TimeStart")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -200,7 +201,7 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
|
||||
}
|
||||
if len(ri.FallbackKeys) > 0 {
|
||||
tempCD := &CallDescriptor{
|
||||
TOR: cd.TOR,
|
||||
Category: cd.Category,
|
||||
Direction: cd.Direction,
|
||||
Tenant: cd.Tenant,
|
||||
Destination: cd.Destination,
|
||||
@@ -295,41 +296,43 @@ func (cd *CallDescriptor) GetKey(subject string) string {
|
||||
subject = realSubject
|
||||
cd.Subject = realSubject
|
||||
}
|
||||
return fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, subject)
|
||||
return fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.Category, subject)
|
||||
}
|
||||
|
||||
// Splits the received timespan into sub time spans according to the activation periods intervals.
|
||||
func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*TimeSpan) {
|
||||
if firstSpan == nil {
|
||||
firstSpan = &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd, CallDuration: cd.CallDuration}
|
||||
}
|
||||
func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
|
||||
firstSpan := &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd, DurationIndex: cd.DurationIndex}
|
||||
|
||||
timespans = append(timespans, firstSpan)
|
||||
if len(cd.RatingInfos) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
firstSpan.ratingInfo = cd.RatingInfos[0]
|
||||
// split on rating plans
|
||||
afterStart, afterEnd := false, false //optimization for multiple activation periods
|
||||
for _, rp := range cd.RatingInfos {
|
||||
if !afterStart && !afterEnd && rp.ActivationTime.Before(cd.TimeStart) {
|
||||
firstSpan.ratingInfo = rp
|
||||
firstSpan.MatchedSubject = rp.MatchedSubject
|
||||
firstSpan.MatchedPrefix = rp.MatchedPrefix
|
||||
firstSpan.MatchedDestId = rp.MatchedDestId
|
||||
} else {
|
||||
afterStart = true
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
newTs := timespans[i].SplitByRatingPlan(rp)
|
||||
if newTs != nil {
|
||||
timespans = append(timespans, newTs)
|
||||
} else {
|
||||
afterEnd = true
|
||||
break
|
||||
if cd.Tor == MINUTES {
|
||||
// split on rating plans
|
||||
afterStart, afterEnd := false, false //optimization for multiple activation periods
|
||||
for _, rp := range cd.RatingInfos {
|
||||
if !afterStart && !afterEnd && rp.ActivationTime.Before(cd.TimeStart) {
|
||||
firstSpan.ratingInfo = rp
|
||||
firstSpan.MatchedSubject = rp.MatchedSubject
|
||||
firstSpan.MatchedPrefix = rp.MatchedPrefix
|
||||
firstSpan.MatchedDestId = rp.MatchedDestId
|
||||
} else {
|
||||
afterStart = true
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
newTs := timespans[i].SplitByRatingPlan(rp)
|
||||
if newTs != nil {
|
||||
timespans = append(timespans, newTs)
|
||||
} else {
|
||||
afterEnd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger.Debug(fmt.Sprintf("After SplitByRatingPlan: %+v", timespans))
|
||||
// split on price intervals
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
@@ -379,7 +382,7 @@ func (cd *CallDescriptor) roundTimeSpansToIncrement(timespans TimeSpans) []*Time
|
||||
if rateIncrement > ts.GetDuration() {
|
||||
initialDuration := ts.GetDuration()
|
||||
ts.TimeEnd = ts.TimeStart.Add(rateIncrement)
|
||||
ts.CallDuration = ts.CallDuration + (rateIncrement - initialDuration)
|
||||
ts.DurationIndex = ts.DurationIndex + (rateIncrement - initialDuration)
|
||||
timespans.RemoveOverlapedFromIndex(i)
|
||||
}
|
||||
}
|
||||
@@ -397,15 +400,19 @@ func (cd *CallDescriptor) GetDuration() time.Duration {
|
||||
Creates a CallCost structure with the cost information calculated for the received CallDescriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
if cd.CallDuration < cd.TimeEnd.Sub(cd.TimeStart) {
|
||||
cd.CallDuration = cd.TimeEnd.Sub(cd.TimeStart)
|
||||
if cd.DurationIndex < cd.TimeEnd.Sub(cd.TimeStart) {
|
||||
cd.DurationIndex = cd.TimeEnd.Sub(cd.TimeStart)
|
||||
}
|
||||
if cd.Tor == "" {
|
||||
cd.Tor = MINUTES
|
||||
}
|
||||
err := cd.LoadRatingPlans()
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("error getting cost for key %s: %v", cd.GetKey(cd.Subject), err))
|
||||
return &CallCost{Cost: -1}, err
|
||||
}
|
||||
timespans := cd.splitInTimeSpans(nil)
|
||||
|
||||
timespans := cd.splitInTimeSpans()
|
||||
cost := 0.0
|
||||
|
||||
for i, ts := range timespans {
|
||||
@@ -420,7 +427,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
//startIndex := len(fmt.Sprintf("%s:%s:%s:", cd.Direction, cd.Tenant, cd.TOR))
|
||||
cc := &CallCost{
|
||||
Direction: cd.Direction,
|
||||
TOR: cd.TOR,
|
||||
Category: cd.Category,
|
||||
Tenant: cd.Tenant,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
@@ -428,6 +435,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
Cost: cost,
|
||||
Timespans: timespans,
|
||||
deductConnectFee: cd.LoopIndex == 0,
|
||||
Tor: cd.Tor,
|
||||
}
|
||||
//Logger.Info(fmt.Sprintf("<Rater> Get Cost: %s => %v", cd.GetKey(), cc))
|
||||
cc.Timespans.Compress()
|
||||
@@ -440,8 +448,11 @@ If the user has no credit then it will return 0.
|
||||
If the user has postpayed plan it returns -1.
|
||||
*/
|
||||
func (origCD *CallDescriptor) getMaxSessionDuration(account *Account) (time.Duration, error) {
|
||||
if origCD.CallDuration < origCD.TimeEnd.Sub(origCD.TimeStart) {
|
||||
origCD.CallDuration = origCD.TimeEnd.Sub(origCD.TimeStart)
|
||||
if origCD.DurationIndex < origCD.TimeEnd.Sub(origCD.TimeStart) {
|
||||
origCD.DurationIndex = origCD.TimeEnd.Sub(origCD.TimeStart)
|
||||
}
|
||||
if origCD.Tor == "" {
|
||||
origCD.Tor = MINUTES
|
||||
}
|
||||
cd := origCD.Clone()
|
||||
//Logger.Debug(fmt.Sprintf("MAX SESSION cd: %+v", cd))
|
||||
@@ -464,10 +475,6 @@ func (origCD *CallDescriptor) getMaxSessionDuration(account *Account) (time.Dura
|
||||
// there are enough minutes for requested interval
|
||||
return initialDuration, nil
|
||||
}
|
||||
// check for zero balance
|
||||
if availableCredit == 0 {
|
||||
return utils.MinDuration(initialDuration, availableDuration), nil
|
||||
}
|
||||
//Logger.Debug(fmt.Sprintf("initial Duration: %v", initialDuration))
|
||||
// we must move the timestart for the interval with the available duration because
|
||||
// that was already checked
|
||||
@@ -478,6 +485,10 @@ func (origCD *CallDescriptor) getMaxSessionDuration(account *Account) (time.Dura
|
||||
if availableDuration == 0 && cc.deductConnectFee { // only if we did not already used minutes
|
||||
availableCredit -= cc.GetConnectFee()
|
||||
}
|
||||
// check for zero balance
|
||||
if (availableCredit < 0) || (availableCredit == 0 && cc.Cost > 0) {
|
||||
return utils.MinDuration(initialDuration, availableDuration), nil
|
||||
}
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("Could not get cost for %s: %s.", cd.GetKey(cd.Subject), err.Error()))
|
||||
return 0, err
|
||||
@@ -513,7 +524,7 @@ func (cd *CallDescriptor) GetMaxSessionDuration() (duration time.Duration, err e
|
||||
Logger.Err(fmt.Sprintf("Could not get user balance for %s: %s.", cd.GetAccountKey(), err.Error()))
|
||||
return 0, err
|
||||
} else {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction); err == nil {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction, cd.Tor); err == nil {
|
||||
AccLock.GuardMany(memberIds, func() (float64, error) {
|
||||
duration, err = cd.getMaxSessionDuration(account)
|
||||
return 0, err
|
||||
@@ -563,7 +574,7 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) {
|
||||
Logger.Err(fmt.Sprintf("Could not get user balance for %s: %s.", cd.GetAccountKey(), err.Error()))
|
||||
return nil, err
|
||||
} else {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction); err == nil {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction, cd.Tor); err == nil {
|
||||
AccLock.GuardMany(memberIds, func() (float64, error) {
|
||||
cc, err = cd.debit(account)
|
||||
return 0, err
|
||||
@@ -584,7 +595,7 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) {
|
||||
Logger.Err(fmt.Sprintf("Could not get user balance for %s: %s.", cd.GetAccountKey(), err.Error()))
|
||||
return nil, err
|
||||
} else {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction); err == nil {
|
||||
if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction, cd.Tor); err == nil {
|
||||
AccLock.GuardMany(memberIds, func() (float64, error) {
|
||||
remainingDuration, err := cd.getMaxSessionDuration(account)
|
||||
if err != nil || remainingDuration == 0 {
|
||||
@@ -617,7 +628,7 @@ func (cd *CallDescriptor) RefundIncrements() (left float64, err error) {
|
||||
defer accountingStorage.SetAccount(account)
|
||||
}
|
||||
}
|
||||
account.refundIncrement(increment, cd.Direction, true)
|
||||
account.refundIncrement(increment, cd.Direction, cd.Tor, true)
|
||||
}
|
||||
return 0.0, err
|
||||
}
|
||||
@@ -634,31 +645,33 @@ func (cd *CallDescriptor) FlushCache() (err error) {
|
||||
func (cd *CallDescriptor) CreateCallCost() *CallCost {
|
||||
return &CallCost{
|
||||
Direction: cd.Direction,
|
||||
TOR: cd.TOR,
|
||||
Category: cd.Category,
|
||||
Tenant: cd.Tenant,
|
||||
Subject: cd.Subject,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
Tor: cd.Tor,
|
||||
}
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) Clone() *CallDescriptor {
|
||||
return &CallDescriptor{
|
||||
Direction: cd.Direction,
|
||||
TOR: cd.TOR,
|
||||
Tenant: cd.Tenant,
|
||||
Subject: cd.Subject,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
TimeStart: cd.TimeStart,
|
||||
TimeEnd: cd.TimeEnd,
|
||||
LoopIndex: cd.LoopIndex,
|
||||
CallDuration: cd.CallDuration,
|
||||
MaxRate: cd.MaxRate,
|
||||
MaxRateUnit: cd.MaxRateUnit,
|
||||
Direction: cd.Direction,
|
||||
Category: cd.Category,
|
||||
Tenant: cd.Tenant,
|
||||
Subject: cd.Subject,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
TimeStart: cd.TimeStart,
|
||||
TimeEnd: cd.TimeEnd,
|
||||
LoopIndex: cd.LoopIndex,
|
||||
DurationIndex: cd.DurationIndex,
|
||||
MaxRate: cd.MaxRate,
|
||||
MaxRateUnit: cd.MaxRateUnit,
|
||||
// Amount: cd.Amount,
|
||||
FallbackSubject: cd.FallbackSubject,
|
||||
//RatingInfos: cd.RatingInfos,
|
||||
//Increments: cd.Increments,
|
||||
Tor: cd.Tor,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,13 @@ func populateDB() {
|
||||
&Balance{Value: 100, DestinationId: "RET", Weight: 20},
|
||||
}},
|
||||
}
|
||||
luna := &Account{
|
||||
Id: "*out:vdf:luna",
|
||||
BalanceMap: map[string]BalanceChain{
|
||||
CREDIT + OUTBOUND: BalanceChain{
|
||||
&Balance{Value: 0, Weight: 20},
|
||||
}},
|
||||
}
|
||||
// this is added to test if csv load tests account will not overwrite balances
|
||||
minitsboy := &Account{
|
||||
Id: "*out:vdf:minitsboy",
|
||||
@@ -82,6 +89,7 @@ func populateDB() {
|
||||
accountingStorage.SetAccount(broker)
|
||||
accountingStorage.SetAccount(minu)
|
||||
accountingStorage.SetAccount(minitsboy)
|
||||
accountingStorage.SetAccount(luna)
|
||||
} else {
|
||||
log.Fatal("Could not connect to db!")
|
||||
}
|
||||
@@ -90,10 +98,10 @@ func populateDB() {
|
||||
func TestSplitSpans(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
|
||||
cd.LoadRatingPlans()
|
||||
timespans := cd.splitInTimeSpans(nil)
|
||||
timespans := cd.splitInTimeSpans()
|
||||
if len(timespans) != 2 {
|
||||
t.Log(cd.RatingInfos)
|
||||
t.Error("Wrong number of timespans: ", len(timespans))
|
||||
@@ -103,10 +111,10 @@ func TestSplitSpans(t *testing.T) {
|
||||
func TestSplitSpansRoundToIncrements(t *testing.T) {
|
||||
t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, DurationIndex: 132 * time.Second}
|
||||
|
||||
cd.LoadRatingPlans()
|
||||
timespans := cd.splitInTimeSpans(nil)
|
||||
timespans := cd.splitInTimeSpans()
|
||||
if len(timespans) != 2 {
|
||||
t.Logf("%+v", cd)
|
||||
t.Log(cd.RatingInfos)
|
||||
@@ -124,7 +132,7 @@ func TestSplitSpansRoundToIncrements(t *testing.T) {
|
||||
func TestGetCost(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2701}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 1 {
|
||||
@@ -135,7 +143,7 @@ func TestGetCost(t *testing.T) {
|
||||
func TestGetCostTimespans(t *testing.T) {
|
||||
t1 := time.Date(2013, time.October, 8, 9, 23, 2, 0, time.UTC)
|
||||
t2 := time.Date(2013, time.October, 8, 9, 24, 27, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, CallDuration: 85 * time.Second}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, DurationIndex: 85 * time.Second}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "test", Subject: "trp", Destination: "0256", Cost: 85}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 0 || len(result.Timespans) != 2 {
|
||||
@@ -147,7 +155,7 @@ func TestGetCostTimespans(t *testing.T) {
|
||||
func TestGetCostRatingPlansAndRatingIntervals(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 27, 23, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 28, 18, 10, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, CallDuration: t2.Sub(t1)}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, DurationIndex: t2.Sub(t1)}
|
||||
result, _ := cd.GetCost()
|
||||
if len(result.Timespans) != 3 ||
|
||||
!result.Timespans[0].TimeEnd.Equal(result.Timespans[1].TimeStart) ||
|
||||
@@ -162,7 +170,7 @@ func TestGetCostRatingPlansAndRatingIntervals(t *testing.T) {
|
||||
func TestGetCostRatingPlansAndRatingIntervalsMore(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 27, 9, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 28, 18, 10, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, CallDuration: t2.Sub(t1)}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "CUSTOMER_1", Subject: "rif:from:tm", Destination: "49178", TimeStart: t1, TimeEnd: t2, LoopIndex: 0, DurationIndex: t2.Sub(t1)}
|
||||
result, _ := cd.GetCost()
|
||||
if len(result.Timespans) != 4 ||
|
||||
!result.Timespans[0].TimeEnd.Equal(result.Timespans[1].TimeStart) ||
|
||||
@@ -178,7 +186,7 @@ func TestGetCostRatingPlansAndRatingIntervalsMore(t *testing.T) {
|
||||
func TestGetCostRateGroups(t *testing.T) {
|
||||
t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, DurationIndex: 132 * time.Second}
|
||||
|
||||
result, err := cd.GetCost()
|
||||
if err != nil {
|
||||
@@ -192,7 +200,7 @@ func TestGetCostRateGroups(t *testing.T) {
|
||||
func TestGetCostNoConnectFee(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 1}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2, LoopIndex: 1}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2700}
|
||||
// connect fee is not added because LoopIndex is 1
|
||||
@@ -204,7 +212,7 @@ func TestGetCostNoConnectFee(t *testing.T) {
|
||||
func TestGetCostAccount(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Account: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Account: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2701}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 1 {
|
||||
@@ -215,7 +223,7 @@ func TestGetCostAccount(t *testing.T) {
|
||||
func TestFullDestNotFound(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256308200", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 2701}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 1 {
|
||||
@@ -227,7 +235,7 @@ func TestFullDestNotFound(t *testing.T) {
|
||||
func TestSubjectNotFound(t *testing.T) {
|
||||
t1 := time.Date(2013, time.February, 1, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2013, time.February, 1, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "not_exiting", Destination: "025740532", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "not_exiting", Destination: "025740532", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 2701}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 1 {
|
||||
@@ -239,7 +247,7 @@ func TestSubjectNotFound(t *testing.T) {
|
||||
func TestMultipleRatingPlans(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 2701}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 1 {
|
||||
@@ -251,7 +259,7 @@ func TestMultipleRatingPlans(t *testing.T) {
|
||||
func TestSpansMultipleRatingPlans(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
if result.Cost != 1200 || result.GetConnectFee() != 0 {
|
||||
t.Errorf("Expected %v was %v", 1200, result)
|
||||
@@ -261,7 +269,7 @@ func TestSpansMultipleRatingPlans(t *testing.T) {
|
||||
func TestLessThanAMinute(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 8, 23, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 30, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0257", Cost: 15}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 0 {
|
||||
@@ -272,7 +280,7 @@ func TestLessThanAMinute(t *testing.T) {
|
||||
func TestUniquePrice(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723045326", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0723045326", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0723", Cost: 1810.5}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 0 {
|
||||
@@ -283,7 +291,7 @@ func TestUniquePrice(t *testing.T) {
|
||||
func TestMinutesCost(t *testing.T) {
|
||||
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 22, 51, 50, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0723", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Cost: 55}
|
||||
if result.Cost != expected.Cost || result.GetConnectFee() != 0 {
|
||||
@@ -296,7 +304,7 @@ func TestMaxSessionTimeNoAccount(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "ttttttt",
|
||||
Destination: "0723"}
|
||||
@@ -311,7 +319,7 @@ func TestMaxSessionTimeWithAccount(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu",
|
||||
Destination: "0723",
|
||||
@@ -330,7 +338,7 @@ func TestMaxSessionTimeWithMaxRate(t *testing.T) {
|
||||
}
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
@@ -352,7 +360,7 @@ func TestMaxSessionTimeWithAccountAlias(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "a1",
|
||||
Account: "a1",
|
||||
@@ -379,7 +387,7 @@ func TestMaxSessionTimeWithAccountShared(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "empty0",
|
||||
@@ -390,7 +398,7 @@ func TestMaxSessionTimeWithAccountShared(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "empty10",
|
||||
@@ -418,7 +426,7 @@ func TestMaxDebitWithAccountShared(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 34, 5, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu",
|
||||
Account: "empty0",
|
||||
@@ -445,7 +453,7 @@ func TestMaxSessionTimeWithAccountAccount(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
@@ -463,10 +471,11 @@ func TestMaxSessionTimeNoCredit(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "broker",
|
||||
Destination: "0723",
|
||||
Tor: MINUTES,
|
||||
}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
if result != time.Minute || err != nil {
|
||||
@@ -478,15 +487,16 @@ func TestMaxSessionModifiesCallDesc(t *testing.T) {
|
||||
t1 := time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC)
|
||||
t2 := time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: t1,
|
||||
TimeEnd: t2,
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
CallDuration: t2.Sub(t1),
|
||||
TimeStart: t1,
|
||||
TimeEnd: t2,
|
||||
Direction: "*out",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
DurationIndex: t2.Sub(t1),
|
||||
Tor: MINUTES,
|
||||
}
|
||||
initial := cd.Clone()
|
||||
cd.GetMaxSessionDuration()
|
||||
@@ -501,7 +511,7 @@ func TestMaxDebitDurationNoGreatherThanInitialDuration(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
@@ -519,7 +529,7 @@ func TestDebitAndMaxDebit(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
@@ -536,6 +546,42 @@ func TestDebitAndMaxDebit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxSesionTimeEmptyBalance(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "luna",
|
||||
Destination: "0723",
|
||||
}
|
||||
acc, _ := accountingStorage.GetAccount("*out:vdf:luna")
|
||||
allowedTime, err := cd.getMaxSessionDuration(acc)
|
||||
if err != nil || allowedTime != 0 {
|
||||
t.Error("Error get max session for 0 acount")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxSesionTimeEmptyBalanceAndNoCost(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "one",
|
||||
Account: "luna",
|
||||
Destination: "112",
|
||||
}
|
||||
acc, _ := accountingStorage.GetAccount("*out:vdf:luna")
|
||||
allowedTime, err := cd.getMaxSessionDuration(acc)
|
||||
if err != nil || allowedTime == 0 {
|
||||
t.Error("Error get max session for 0 acount")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitFromShareAndNormal(t *testing.T) {
|
||||
ap, _ := accountingStorage.GetActionTimings("TOPUP_SHARED10_AT")
|
||||
for _, at := range ap {
|
||||
@@ -546,7 +592,7 @@ func TestDebitFromShareAndNormal(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 34, 5, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "empty10",
|
||||
@@ -574,7 +620,7 @@ func TestDebitFromEmptyShare(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 34, 5, 0, time.UTC),
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "emptyX",
|
||||
@@ -598,16 +644,16 @@ func TestMaxDebitZeroDefinedRate(t *testing.T) {
|
||||
at.Execute()
|
||||
}
|
||||
cd1 := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 0, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
CallDuration: 0}
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 0, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: 0}
|
||||
cc, err := cd1.MaxDebit()
|
||||
if err != nil {
|
||||
t.Error("Error maxdebiting: ", err)
|
||||
@@ -626,16 +672,16 @@ func TestMaxDebitZeroDefinedRateOnlyMinutes(t *testing.T) {
|
||||
at.Execute()
|
||||
}
|
||||
cd1 := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 40, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
CallDuration: 0}
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 40, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: 0}
|
||||
cc, err := cd1.MaxDebit()
|
||||
if err != nil {
|
||||
t.Fatal("Error maxdebiting: ", err)
|
||||
@@ -654,16 +700,16 @@ func TestMaxDebitConsumesMinutes(t *testing.T) {
|
||||
at.Execute()
|
||||
}
|
||||
cd1 := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 5, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
CallDuration: 0}
|
||||
Direction: "*out",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
Destination: "447956",
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 5, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: 0}
|
||||
cd1.MaxDebit()
|
||||
if cd1.account.BalanceMap[MINUTES+OUTBOUND][0].Value != 20 {
|
||||
t.Error("Error using minutes: ", cd1.account.BalanceMap[MINUTES+OUTBOUND][0].Value)
|
||||
@@ -672,17 +718,54 @@ func TestMaxDebitConsumesMinutes(t *testing.T) {
|
||||
|
||||
func TestCDGetCostANY(t *testing.T) {
|
||||
cd1 := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 5, 0, time.UTC),
|
||||
LoopIndex: 0,
|
||||
CallDuration: 0}
|
||||
Direction: "*out",
|
||||
Category: "data",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 0, 1, 0, time.UTC),
|
||||
Tor: DATA,
|
||||
}
|
||||
cc, err := cd1.GetCost()
|
||||
if err != nil || cc.Cost != 6 {
|
||||
if err != nil || cc.Cost != 60 {
|
||||
t.Errorf("Error getting *any dest: %+v %v", cc, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDSplitInDataSlots(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
Category: "data",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 5, 0, time.UTC),
|
||||
Tor: DATA,
|
||||
DurationIndex: 65 * time.Second,
|
||||
}
|
||||
cd.LoadRatingPlans()
|
||||
timespans := cd.splitInTimeSpans()
|
||||
if len(timespans) != 2 {
|
||||
t.Log(cd.RatingInfos[0])
|
||||
t.Error("Wrong number of timespans: ", len(timespans))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDDataGetCost(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
Category: "data",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "rif",
|
||||
Destination: utils.ANY,
|
||||
TimeStart: time.Date(2014, 3, 4, 6, 0, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2014, 3, 4, 6, 1, 5, 0, time.UTC),
|
||||
Tor: DATA,
|
||||
}
|
||||
cc, err := cd.GetCost()
|
||||
if err != nil || cc.Cost != 65 {
|
||||
t.Errorf("Error getting *any dest: %+v %v", cc, err)
|
||||
}
|
||||
}
|
||||
@@ -692,7 +775,7 @@ func BenchmarkStorageGetting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
dataStorage.GetRatingProfile(cd.GetKey(cd.Subject), false)
|
||||
@@ -703,7 +786,7 @@ func BenchmarkStorageRestoring(b *testing.B) {
|
||||
b.StopTimer()
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.LoadRatingPlans()
|
||||
@@ -714,7 +797,7 @@ func BenchmarkStorageGetCost(b *testing.B) {
|
||||
b.StopTimer()
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost()
|
||||
@@ -725,11 +808,11 @@ func BenchmarkSplitting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
cd.LoadRatingPlans()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.splitInTimeSpans(nil)
|
||||
cd.splitInTimeSpans()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,7 +827,7 @@ func BenchmarkStorageSingleGetSessionTime(b *testing.B) {
|
||||
|
||||
func BenchmarkStorageMultipleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723"}
|
||||
cd := &CallDescriptor{Direction: "*out", Category: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723"}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionDuration()
|
||||
|
||||
45
engine/datacost.go
Normal file
45
engine/datacost.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package engine
|
||||
|
||||
// type used for showing sane data cost
|
||||
type DataCost struct {
|
||||
Direction, Category, Tenant, Subject, Account, Destination, Tor string
|
||||
Cost float64
|
||||
DataSpans []*DataSpan
|
||||
deductConnectFee bool
|
||||
}
|
||||
type DataSpan struct {
|
||||
DataStart, DataEnd float64
|
||||
Cost float64
|
||||
ratingInfo *RatingInfo
|
||||
RateInterval *RateInterval
|
||||
DataIndex float64 // the data transfer so far till DataEnd
|
||||
Increments []*DataIncrement
|
||||
MatchedSubject, MatchedPrefix, MatchedDestId string
|
||||
}
|
||||
|
||||
type DataIncrement struct {
|
||||
Amount float64
|
||||
Cost float64
|
||||
BalanceInfo *BalanceInfo // need more than one for units with cost
|
||||
BalanceRateInterval *RateInterval
|
||||
UnitInfo *UnitInfo
|
||||
CompressFactor int
|
||||
paid bool
|
||||
}
|
||||
@@ -47,6 +47,7 @@ func TestHistoryDestinations(t *testing.T) {
|
||||
{"Id":"PSTN_71","Prefixes":["+4971"]},
|
||||
{"Id":"PSTN_72","Prefixes":["+4972"]},
|
||||
{"Id":"RET","Prefixes":["0723","0724"]},
|
||||
{"Id":"URG","Prefixes":["112"]},
|
||||
{"Id":"nat","Prefixes":["0257","0256","0723"]}]`
|
||||
if buf.String() != expected {
|
||||
t.Error("Error in destination history content:", buf.String())
|
||||
|
||||
@@ -482,7 +482,7 @@ func (csvr *CSVReader) LoadRatingProfiles() (err error) {
|
||||
defer fp.Close()
|
||||
}
|
||||
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
|
||||
tenant, tor, direction, subject, fallbacksubject := record[0], record[1], record[2], record[3], record[6]
|
||||
direction, tenant, tor, subject, fallbacksubject := record[0], record[1], record[2], record[3], record[6]
|
||||
at, err := utils.ParseDate(record[4])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot parse activation time from %v", record[4])
|
||||
@@ -675,7 +675,11 @@ func (csvr *CSVReader) LoadActionTriggers() (err error) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not parse action trigger value: %v", err)
|
||||
}
|
||||
weight, err := strconv.ParseFloat(record[7], 64)
|
||||
recurrent, err := strconv.ParseBool(record[5])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not parse action trigger recurrent flag: %v", err)
|
||||
}
|
||||
weight, err := strconv.ParseFloat(record[8], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not parse action trigger weight: %v", err)
|
||||
}
|
||||
@@ -685,8 +689,9 @@ func (csvr *CSVReader) LoadActionTriggers() (err error) {
|
||||
Direction: record[2],
|
||||
ThresholdType: record[3],
|
||||
ThresholdValue: value,
|
||||
DestinationId: record[5],
|
||||
ActionsId: record[6],
|
||||
Recurrent: recurrent,
|
||||
DestinationId: record[6],
|
||||
ActionsId: record[7],
|
||||
Weight: weight,
|
||||
}
|
||||
csvr.actionsTriggers[tag] = append(csvr.actionsTriggers[tag], at)
|
||||
|
||||
@@ -44,6 +44,7 @@ PSTN_71,+4971
|
||||
PSTN_72,+4972
|
||||
PSTN_70,+4970
|
||||
DST_UK_Mobile_BIG5,447956
|
||||
URG,112
|
||||
*any,
|
||||
`
|
||||
timings = `
|
||||
@@ -60,13 +61,14 @@ R2,0,0.1,60s,1s,0,*middle,2
|
||||
R3,0,0.05,60s,1s,0,*middle,2
|
||||
R4,1,1,1s,1s,0,*up,2
|
||||
R5,0,0.5,1s,1s,0,*down,2
|
||||
LANDLINE_OFFPEAK,0,1,1s,60s,0s,*up,4
|
||||
LANDLINE_OFFPEAK,0,1,1s,1s,60s,*up,4
|
||||
LANDLINE_OFFPEAK,0,1,1,60,0,*up,4
|
||||
LANDLINE_OFFPEAK,0,1,1,1,60,*up,4
|
||||
GBP_71,0.000000,5.55555,1s,1s,0s,*up,4
|
||||
GBP_72,0.000000,7.77777,1s,1s,0s,*up,4
|
||||
GBP_70,0.000000,1,1,1,0,*up,4
|
||||
RT_UK_Mobile_BIG5_PKG,0.01,0,20s,20s,0s,*up,8
|
||||
RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s,*up,8
|
||||
R_URG,0,0,1,1,0,*down,2
|
||||
`
|
||||
destinationRates = `
|
||||
RT_STANDARD,GERMANY,R1
|
||||
@@ -83,12 +85,14 @@ T2,GERMANY_O2,GBP_70
|
||||
T2,GERMANY_PREMIUM,GBP_71
|
||||
DR_UK_Mobile_BIG5_PKG,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5_PKG
|
||||
DR_UK_Mobile_BIG5,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5
|
||||
DATA_RATE,*any,R4
|
||||
DATA_RATE,*any,LANDLINE_OFFPEAK
|
||||
RT_URG,URG,R_URG
|
||||
`
|
||||
ratingPlans = `
|
||||
STANDARD,RT_STANDARD,WORKDAYS_00,10
|
||||
STANDARD,RT_STD_WEEKEND,WORKDAYS_18,10
|
||||
STANDARD,RT_STD_WEEKEND,WEEKENDS,10
|
||||
STANDARD,RT_URG,ALWAYS,20
|
||||
PREMIUM,RT_STANDARD,WORKDAYS_00,10
|
||||
PREMIUM,RT_STD_WEEKEND,WORKDAYS_18,10
|
||||
PREMIUM,RT_STD_WEEKEND,WEEKENDS,10
|
||||
@@ -96,33 +100,34 @@ DEFAULT,RT_DEFAULT,WORKDAYS_00,10
|
||||
EVENING,P1,WORKDAYS_00,10
|
||||
EVENING,P2,WORKDAYS_18,10
|
||||
EVENING,P2,WEEKENDS,10
|
||||
EVENING,DATA_RATE,ALWAYS,10
|
||||
TDRT,T1,WORKDAYS_00,10
|
||||
TDRT,T2,WORKDAYS_00,10
|
||||
G,RT_STANDARD,WORKDAYS_00,10
|
||||
R,P1,WORKDAYS_00,10
|
||||
RP_UK_Mobile_BIG5_PKG,DR_UK_Mobile_BIG5_PKG,ALWAYS,10
|
||||
RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10
|
||||
RP_DATA,DATA_RATE,ALWAYS,10
|
||||
`
|
||||
ratingProfiles = `
|
||||
CUSTOMER_1,0,*out,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb
|
||||
CUSTOMER_1,0,*out,rif:from:tm,2012-02-28T00:00:00Z,STANDARD,danb
|
||||
CUSTOMER_2,0,*out,danb:87.139.12.167,2012-01-01T00:00:00Z,STANDARD,danb
|
||||
CUSTOMER_1,0,*out,danb,2012-01-01T00:00:00Z,PREMIUM,
|
||||
vdf,0,*out,rif,2012-01-01T00:00:00Z,EVENING,
|
||||
vdf,0,*out,rif,2012-02-28T00:00:00Z,EVENING,
|
||||
vdf,0,*out,minu;a1;a2;a3,2012-01-01T00:00:00Z,EVENING,
|
||||
vdf,0,*out,*any,2012-02-28T00:00:00Z,EVENING,
|
||||
vdf,0,*out,one,2012-02-28T00:00:00Z,STANDARD,
|
||||
vdf,0,*out,inf,2012-02-28T00:00:00Z,STANDARD,inf
|
||||
vdf,0,*out,fall,2012-02-28T00:00:00Z,PREMIUM,rif
|
||||
test,0,*out,trp,2013-10-01T00:00:00Z,TDRT,rif;danb
|
||||
vdf,0,*out,fallback1,2013-11-18T13:45:00Z,G,fallback2
|
||||
vdf,0,*out,fallback1,2013-11-18T13:46:00Z,G,fallback2
|
||||
vdf,0,*out,fallback1,2013-11-18T13:47:00Z,G,fallback2
|
||||
vdf,0,*out,fallback2,2013-11-18T13:45:00Z,R,rif
|
||||
cgrates.org,call,*out,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
cgrates.org,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,
|
||||
*out,CUSTOMER_1,0,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb
|
||||
*out,CUSTOMER_1,0,rif:from:tm,2012-02-28T00:00:00Z,STANDARD,danb
|
||||
*out,CUSTOMER_2,0,danb:87.139.12.167,2012-01-01T00:00:00Z,STANDARD,danb
|
||||
*out,CUSTOMER_1,0,danb,2012-01-01T00:00:00Z,PREMIUM,
|
||||
*out,vdf,0,rif,2012-01-01T00:00:00Z,EVENING,
|
||||
*out,vdf,0,rif,2012-02-28T00:00:00Z,EVENING,
|
||||
*out,vdf,0,minu;a1;a2;a3,2012-01-01T00:00:00Z,EVENING,
|
||||
*out,vdf,0,*any,2012-02-28T00:00:00Z,EVENING,
|
||||
*out,vdf,0,one,2012-02-28T00:00:00Z,STANDARD,
|
||||
*out,vdf,0,inf,2012-02-28T00:00:00Z,STANDARD,inf
|
||||
*out,vdf,0,fall,2012-02-28T00:00:00Z,PREMIUM,rif
|
||||
*out,test,0,trp,2013-10-01T00:00:00Z,TDRT,rif;danb
|
||||
*out,vdf,0,fallback1,2013-11-18T13:45:00Z,G,fallback2
|
||||
*out,vdf,0,fallback1,2013-11-18T13:46:00Z,G,fallback2
|
||||
*out,vdf,0,fallback1,2013-11-18T13:47:00Z,G,fallback2
|
||||
*out,vdf,0,fallback2,2013-11-18T13:45:00Z,R,rif
|
||||
*out,cgrates.org,call,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
*out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,
|
||||
*out,cgrates.org,data,rif,2013-01-06T00:00:00Z,RP_DATA,
|
||||
`
|
||||
sharedGroups = `
|
||||
SG1,*any,*lowest,
|
||||
@@ -132,10 +137,10 @@ SG3,*any,*lowest,
|
||||
|
||||
actions = `
|
||||
MINI,*topup_reset,*monetary,*out,10,*unlimited,,,10,,,10
|
||||
MINI,*topup,*minutes,*out,100,*unlimited,NAT,test,10,,,10
|
||||
MINI,*topup,*call_duration,*out,100,*unlimited,NAT,test,10,,,10
|
||||
SHARED,*topup,*monetary,*out,100,*unlimited,,,10,SG1,,10
|
||||
TOPUP10_AC,*topup_reset,*monetary,*out,1,*unlimited,*any,,10,,,10
|
||||
TOPUP10_AC1,*topup_reset,*minutes,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10
|
||||
TOPUP10_AC1,*topup_reset,*call_duration,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10
|
||||
SE0,*topup_reset,*monetary,*out,0,*unlimited,,,10,SG2,,10
|
||||
SE10,*topup_reset,*monetary,*out,10,*unlimited,,,5,SG2,,10
|
||||
SE10,*topup,*monetary,*out,10,*unlimited,,,10,,,10
|
||||
@@ -152,11 +157,11 @@ TOPUP_SHARED10_AT,SE10,ASAP,10
|
||||
TOPUP_EMPTY_AT,EE0,ASAP,10
|
||||
`
|
||||
actionTriggers = `
|
||||
STANDARD_TRIGGER,*minutes,*out,*min_counter,10,GERMANY_O2,SOME_1,10
|
||||
STANDARD_TRIGGER,*minutes,*out,*max_balance,200,GERMANY,SOME_2,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,,LOG_WARNING,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,,LOG_WARNING,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_counter,5,FS_USERS,LOG_WARNING,10
|
||||
STANDARD_TRIGGER,*call_duration,*out,*min_counter,10,false,GERMANY_O2,SOME_1,10
|
||||
STANDARD_TRIGGER,*call_duration,*out,*max_balance,200,false,GERMANY,SOME_2,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,false,,LOG_WARNING,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,false,,LOG_WARNING,10
|
||||
STANDARD_TRIGGERS,*monetary,*out,*max_counter,5,false,FS_USERS,LOG_WARNING,10
|
||||
`
|
||||
accountActions = `
|
||||
vdf,minitsboy;a1;a2,*out,MORE_MINUTES,STANDARD_TRIGGER
|
||||
@@ -198,7 +203,7 @@ func init() {
|
||||
}
|
||||
|
||||
func TestLoadDestinations(t *testing.T) {
|
||||
if len(csvr.destinations) != 11 {
|
||||
if len(csvr.destinations) != 12 {
|
||||
t.Error("Failed to load destinations: ", len(csvr.destinations))
|
||||
}
|
||||
for _, d := range csvr.destinations {
|
||||
@@ -294,7 +299,7 @@ func TestLoadTimimgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadRates(t *testing.T) {
|
||||
if len(csvr.rates) != 11 {
|
||||
if len(csvr.rates) != 12 {
|
||||
t.Error("Failed to load rates: ", csvr.rates)
|
||||
}
|
||||
rate := csvr.rates["R1"].RateSlots[0]
|
||||
@@ -344,7 +349,7 @@ func TestLoadRates(t *testing.T) {
|
||||
t.Error("Error loading rate: ", rate)
|
||||
}
|
||||
rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[0]
|
||||
if expctRs, err = utils.NewRateSlot(0, 1, "1s", "60s", "0s", utils.ROUNDING_UP, 4); err != nil {
|
||||
if expctRs, err = utils.NewRateSlot(0, 1, "1", "60", "0", utils.ROUNDING_UP, 4); err != nil {
|
||||
t.Error("Error loading rate: ", rate, err.Error())
|
||||
} else if !reflect.DeepEqual(rate, expctRs) ||
|
||||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
|
||||
@@ -353,7 +358,7 @@ func TestLoadRates(t *testing.T) {
|
||||
t.Error("Error loading rate: ", rate)
|
||||
}
|
||||
rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[1]
|
||||
if expctRs, err = utils.NewRateSlot(0, 1, "1s", "1s", "60s", utils.ROUNDING_UP, 4); err != nil {
|
||||
if expctRs, err = utils.NewRateSlot(0, 1, "1", "1", "60", utils.ROUNDING_UP, 4); err != nil {
|
||||
t.Error("Error loading rate: ", rate, err.Error())
|
||||
} else if !reflect.DeepEqual(rate, expctRs) ||
|
||||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
|
||||
@@ -364,7 +369,7 @@ func TestLoadRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadDestinationRates(t *testing.T) {
|
||||
if len(csvr.destinationRates) != 10 {
|
||||
if len(csvr.destinationRates) != 11 {
|
||||
t.Error("Failed to load destinationrates: ", csvr.destinationRates)
|
||||
}
|
||||
drs := csvr.destinationRates["RT_STANDARD"]
|
||||
@@ -476,7 +481,7 @@ func TestLoadDestinationRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadRatingPlans(t *testing.T) {
|
||||
if len(csvr.ratingPlans) != 9 {
|
||||
if len(csvr.ratingPlans) != 10 {
|
||||
t.Error("Failed to load rating plans: ", len(csvr.ratingPlans))
|
||||
}
|
||||
rplan := csvr.ratingPlans["STANDARD"]
|
||||
@@ -504,6 +509,13 @@ func TestLoadRatingPlans(t *testing.T) {
|
||||
WeekDays: utils.WeekDays{time.Saturday, time.Sunday},
|
||||
StartTime: "00:00:00",
|
||||
},
|
||||
"96c78ff5": &RITiming{
|
||||
Years: utils.Years{},
|
||||
Months: utils.Months{},
|
||||
MonthDays: utils.MonthDays{},
|
||||
WeekDays: utils.WeekDays{},
|
||||
StartTime: "00:00:00",
|
||||
},
|
||||
},
|
||||
Ratings: map[string]*RIRate{
|
||||
"d54545c1": &RIRate{
|
||||
@@ -545,6 +557,19 @@ func TestLoadRatingPlans(t *testing.T) {
|
||||
RoundingMethod: utils.ROUNDING_MIDDLE,
|
||||
RoundingDecimals: 2,
|
||||
},
|
||||
"2efe78aa": &RIRate{
|
||||
ConnectFee: 0,
|
||||
Rates: []*Rate{
|
||||
&Rate{
|
||||
GroupIntervalStart: 0,
|
||||
Value: 0,
|
||||
RateIncrement: time.Second,
|
||||
RateUnit: time.Second,
|
||||
},
|
||||
},
|
||||
RoundingMethod: utils.ROUNDING_DOWN,
|
||||
RoundingDecimals: 2,
|
||||
},
|
||||
},
|
||||
DestinationRates: map[string]RPRateList{
|
||||
"GERMANY": []*RPRate{
|
||||
@@ -588,15 +613,22 @@ func TestLoadRatingPlans(t *testing.T) {
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
"URG": []*RPRate{
|
||||
&RPRate{
|
||||
Timing: "96c78ff5",
|
||||
Rating: "2efe78aa",
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(rplan, expected) {
|
||||
t.Errorf("Error loading destination rate timing: %+v", rplan.Ratings["e06c337f"])
|
||||
t.Errorf("Error loading destination rate timing: %+v", rplan.DestinationRates["URG"][0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRatingProfiles(t *testing.T) {
|
||||
if len(csvr.ratingProfiles) != 14 {
|
||||
if len(csvr.ratingProfiles) != 15 {
|
||||
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
|
||||
}
|
||||
rp := csvr.ratingProfiles["*out:test:0:trp"]
|
||||
|
||||
@@ -341,7 +341,7 @@ func (dbr *DbReader) LoadRatingProfiles() error {
|
||||
&RatingPlanActivation{
|
||||
ActivationTime: at,
|
||||
RatingPlanId: tpRa.RatingPlanId,
|
||||
FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.TOR, tpRa.FallbackSubjects),
|
||||
FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.Category, tpRa.FallbackSubjects),
|
||||
})
|
||||
}
|
||||
dbr.ratingProfiles[tpRpf.KeyId()] = rpf
|
||||
@@ -430,7 +430,7 @@ func (dbr *DbReader) LoadRatingProfileFiltered(qriedRpf *utils.TPRatingProfile)
|
||||
}
|
||||
resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations,
|
||||
&RatingPlanActivation{at, tpRa.RatingPlanId,
|
||||
utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.TOR, tpRa.FallbackSubjects)})
|
||||
utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.Category, tpRa.FallbackSubjects)})
|
||||
}
|
||||
if err := dbr.dataDb.SetRatingProfile(resultRatingProfile); err != nil {
|
||||
return err
|
||||
@@ -528,6 +528,7 @@ func (dbr *DbReader) LoadActionTriggers() (err error) {
|
||||
DestinationId: apiAtr.DestinationId,
|
||||
Weight: apiAtr.Weight,
|
||||
ActionsId: apiAtr.ActionsId,
|
||||
Recurrent: apiAtr.Recurrent,
|
||||
}
|
||||
}
|
||||
dbr.actionsTriggers[key] = atrs
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestApRestoreFromStorage(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
Direction: OUTBOUND,
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Tenant: "CUSTOMER_1",
|
||||
Subject: "rif:from:tm",
|
||||
Destination: "49"}
|
||||
@@ -76,7 +76,7 @@ func TestFallbackDirect(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Tenant: "CUSTOMER_2",
|
||||
Subject: "danb:87.139.12.167",
|
||||
@@ -91,7 +91,7 @@ func TestFallbackMultiple(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Tenant: "vdf",
|
||||
Subject: "fall",
|
||||
@@ -106,7 +106,7 @@ func TestFallbackWithBackTrace(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Tenant: "CUSTOMER_2",
|
||||
Subject: "danb:87.139.12.167",
|
||||
@@ -121,7 +121,7 @@ func TestFallbackDefault(t *testing.T) {
|
||||
cd := &CallDescriptor{
|
||||
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Tenant: "vdf",
|
||||
Subject: "one",
|
||||
@@ -133,7 +133,7 @@ func TestFallbackDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackNoInfiniteLoop(t *testing.T) {
|
||||
cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "rif", Destination: "0721"}
|
||||
cd := &CallDescriptor{Category: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "rif", Destination: "0721"}
|
||||
cd.LoadRatingPlans()
|
||||
if len(cd.RatingInfos) != 0 {
|
||||
t.Error("Error restoring activation periods: ", len(cd.RatingInfos))
|
||||
@@ -141,7 +141,7 @@ func TestFallbackNoInfiniteLoop(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackNoInfiniteLoopSelf(t *testing.T) {
|
||||
cd := &CallDescriptor{TOR: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "inf", Destination: "0721"}
|
||||
cd := &CallDescriptor{Category: "0", Direction: OUTBOUND, Tenant: "vdf", Subject: "inf", Destination: "0721"}
|
||||
cd.LoadRatingPlans()
|
||||
if len(cd.RatingInfos) != 0 {
|
||||
t.Error("Error restoring activation periods: ", len(cd.RatingInfos))
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestGetRatingProfileForPrefix(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 11, 18, 13, 45, 1, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 11, 18, 13, 47, 30, 0, time.UTC),
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Subject: "fallback1",
|
||||
Destination: "0256098",
|
||||
@@ -47,7 +47,7 @@ func TestGetRatingProfileForPrefixFirstEmpty(t *testing.T) {
|
||||
TimeStart: time.Date(2013, 11, 18, 13, 44, 1, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 11, 18, 13, 47, 30, 0, time.UTC),
|
||||
Tenant: "vdf",
|
||||
TOR: "0",
|
||||
Category: "0",
|
||||
Direction: OUTBOUND,
|
||||
Subject: "fallback1",
|
||||
Destination: "0256098",
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
var balance1 string = `{"Id":"*out:192.168.56.66:dan","Type":"*prepaid","BalanceMap":{"*monetary*out":[{"Uuid":"7fe5d6e740b6edd180b96274b8bd4123","Value":10,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":10,"GroupIds":null,"DestinationId":"*any","RateSubject":""}]},"UnitCounters":null,"ActionTriggers":[{"Id":"120ea04d40af91c580adb0da11554c88","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*min_balance","ThresholdValue":2,"DestinationId":"","Weight":10,"ActionsId":"LOG_BALANCE","Executed":false},{"Id":"fa217a904059cfd3806239f5ad229f4a","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*max_balance","ThresholdValue":20,"DestinationId":"","Weight":10,"ActionsId":"LOG_BALANCE","Executed":false},{"Id":"f05174b740ab987c802a0a29aa5a2764","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*max_counter","ThresholdValue":15,"DestinationId":"FS_USERS","Weight":10,"ActionsId":"LOG_BALANCE","Executed":false},{"Id":"4d6ebf454048371280100094246163a7","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*min_balance","ThresholdValue":0.1,"DestinationId":"","Weight":10,"ActionsId":"WARN_HTTP","Executed":false}],"Groups":null,"UserIds":null}`
|
||||
|
||||
var callCost1 string = `{"Direction":"*out","TOR":"call","Tenant":"192.168.56.66","Subject":"dan","Account":"dan","Destination":"+4986517174963","Cost":0.6,"ConnectFee":0,"Timespans":[{"TimeStart":"2013-12-03T14:36:48+01:00","TimeEnd":"2013-12-03T14:37:48+01:00","Cost":0.6,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":0,"Rates":[{"GroupIntervalStart":0,"Value":0.6,"RateIncrement":60000000000,"RateUnit":60000000000}],"RoundingMethod":"*up","RoundingDecimals":2},"Weight":10},"CallDuration":60000000000,"Increments":null,"MatchedSubject":"*out:192.168.56.66:call:*any","MatchedPrefix":"+49"}]}`
|
||||
var callCost1 string = `{"Direction":"*out","TOR":"call","Tenant":"192.168.56.66","Subject":"dan","Account":"dan","Destination":"+4986517174963","Cost":0.6,"ConnectFee":0,"Timespans":[{"TimeStart":"2013-12-03T14:36:48+01:00","TimeEnd":"2013-12-03T14:37:48+01:00","Cost":0.6,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":0,"Rates":[{"GroupIntervalStart":0,"Value":0.6,"RateIncrement":60000000000,"RateUnit":60000000000}],"RoundingMethod":"*up","RoundingDecimals":2},"Weight":10},"DurationIndex":60000000000,"Increments":null,"MatchedSubject":"*out:192.168.56.66:call:*any","MatchedPrefix":"+49"}]}`
|
||||
|
||||
func TestDebitBalanceForCall1(t *testing.T) {
|
||||
b1 := new(Account)
|
||||
@@ -47,7 +47,7 @@ func TestDebitBalanceForCall1(t *testing.T) {
|
||||
|
||||
var balanceInsufficient = `{"Id":"*out:192.168.56.66:dan","Type":"*prepaid","BalanceMap":{"*monetary*out":[{"Uuid":"de49cb1a40b2740a8087a1d28112e11c","Value":1,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":10,"GroupIds":null,"DestinationId":"*any","RateSubject":""}]},"UnitCounters":[{"Direction":"*out","BalanceId":"*monetary","Balances":[{"Uuid":"","Value":4,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":0,"GroupIds":null,"DestinationId":"","RateSubject":""}]}],"ActionTriggers":[{"Id":"a33f036e402c2b47801f1380c5c82564","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*min_balance","ThresholdValue":2,"DestinationId":"","Weight":10,"ActionsId":"LOG_BALANCE","Executed":true},{"Id":"91776f2d40496c03806cdbc73ae6b5f9","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*max_balance","ThresholdValue":20,"DestinationId":"","Weight":10,"ActionsId":"LOG_BALANCE","Executed":false},{"Id":"e85e933a4045f77c80ef647295ae209b","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*max_counter","ThresholdValue":15,"DestinationId":"FS_USERS","Weight":10,"ActionsId":"LOG_BALANCE","Executed":false},{"Id":"89c178b440a640b6802334b17b63cd4e","BalanceId":"*monetary","Direction":"*out","ThresholdType":"*min_balance","ThresholdValue":2.1,"DestinationId":"","Weight":10,"ActionsId":"WARN_HTTP","Executed":true}],"Groups":null,"UserIds":null}`
|
||||
|
||||
var costInsufficient = `{"Direction":"*out","TOR":"call","Tenant":"192.168.56.66","Subject":"dan","Account":"dan","Destination":"+4986517174963","Cost":1,"ConnectFee":3,"Timespans":[{"TimeStart":"2013-12-05T09:52:17+01:00","TimeEnd":"2013-12-05T09:53:17+01:00","Cost":1,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":3,"Rates":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":60000000000,"RateUnit":60000000000}],"RoundingMethod":"*up","RoundingDecimals":2},"Weight":10},"CallDuration":60000000000,"Increments":null,"MatchedSubject":"*out:192.168.56.66:call:*any","MatchedPrefix":"+49"}]}`
|
||||
var costInsufficient = `{"Direction":"*out","TOR":"call","Tenant":"192.168.56.66","Subject":"dan","Account":"dan","Destination":"+4986517174963","Cost":1,"ConnectFee":3,"Timespans":[{"TimeStart":"2013-12-05T09:52:17+01:00","TimeEnd":"2013-12-05T09:53:17+01:00","Cost":1,"RateInterval":{"Timing":{"Years":[],"Months":[],"MonthDays":[],"WeekDays":[],"StartTime":"00:00:00","EndTime":""},"Rating":{"ConnectFee":3,"Rates":[{"GroupIntervalStart":0,"Value":1,"RateIncrement":60000000000,"RateUnit":60000000000}],"RoundingMethod":"*up","RoundingDecimals":2},"Weight":10},"DurationIndex":60000000000,"Increments":null,"MatchedSubject":"*out:192.168.56.66:call:*any","MatchedPrefix":"+49"}]}`
|
||||
|
||||
func TestDebitInsufficientBalance(t *testing.T) {
|
||||
b1 := new(Account)
|
||||
|
||||
@@ -165,53 +165,6 @@ func (rs *Responder) Shutdown(arg string, reply *string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) GetMonetary(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, CREDIT, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rs *Responder) GetSMS(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, SMS, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rs *Responder) GetInternet(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, DATA, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rs *Responder) GetInternetTime(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, DATA_TIME, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rs *Responder) GetMinutes(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, MINUTES, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get balance
|
||||
func (rs *Responder) getBalance(arg *CallDescriptor, balanceId string, reply *CallCost) (err error) {
|
||||
if rs.Bal != nil {
|
||||
return errors.New("No balancer supported for this command right now")
|
||||
}
|
||||
ubKey := arg.Direction + ":" + arg.Tenant + ":" + arg.Account
|
||||
userBalance, err := accountingStorage.GetAccount(ubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if balance, balExists := userBalance.BalanceMap[balanceId+arg.Direction]; !balExists {
|
||||
// No match, balanceId not found
|
||||
return errors.New("-BALANCE_NOT_FOUND")
|
||||
} else {
|
||||
reply.Tenant = arg.Tenant
|
||||
reply.Account = arg.Account
|
||||
reply.Direction = arg.Direction
|
||||
reply.Cost = balance.GetTotalValue()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
The function that gets the information from the raters using balancer.
|
||||
*/
|
||||
|
||||
@@ -269,7 +269,7 @@ func (self *SQLStorage) SetTPRatingProfiles(tpid string, rps map[string]*utils.T
|
||||
if i != 0 { //Consecutive values after the first will be prefixed with "," as separator
|
||||
buffer.WriteRune(',')
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf("('%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s')", tpid, rp.LoadId, rp.Tenant, rp.TOR, rp.Direction,
|
||||
buffer.WriteString(fmt.Sprintf("('%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s')", tpid, rp.LoadId, rp.Tenant, rp.Category, rp.Direction,
|
||||
rp.Subject, rpa.ActivationTime, rpa.RatingPlanId, rpa.FallbackSubjects))
|
||||
i++
|
||||
}
|
||||
@@ -476,7 +476,7 @@ func (self *SQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (
|
||||
cgrid,
|
||||
cc.Direction,
|
||||
cc.Tenant,
|
||||
cc.TOR,
|
||||
cc.Category,
|
||||
cc.Account,
|
||||
cc.Subject,
|
||||
cc.Destination,
|
||||
@@ -500,7 +500,7 @@ func (self *SQLStorage) GetCallCostLog(cgrid, source, runid string) (cc *CallCos
|
||||
var src string
|
||||
var timespansJson string
|
||||
cc = &CallCost{Cost: -1}
|
||||
err = row.Scan(&cgrid, &cc.Direction, &cc.Tenant, &cc.TOR, &cc.Account, &cc.Subject,
|
||||
err = row.Scan(&cgrid, &cc.Direction, &cc.Tenant, &cc.Category, &cc.Account, &cc.Subject,
|
||||
&cc.Destination, &cc.Cost, ×pansJson, &src)
|
||||
if len(timespansJson) == 0 { // No costs returned
|
||||
return nil, nil
|
||||
@@ -533,7 +533,7 @@ func (self *SQLStorage) SetCdr(cdr utils.RawCDR) (err error) {
|
||||
cdr.GetReqType(),
|
||||
cdr.GetDirection(),
|
||||
cdr.GetTenant(),
|
||||
cdr.GetTOR(),
|
||||
cdr.GetCategory(),
|
||||
cdr.GetAccount(),
|
||||
cdr.GetSubject(),
|
||||
cdr.GetDestination(),
|
||||
@@ -796,11 +796,11 @@ func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, cdrHosts, cdrSources, reqT
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(extraFields, &extraFieldsMp); err != nil {
|
||||
return nil, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %s, error: %s", cgrid, runid, err.Error())
|
||||
return nil, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %v, error: %s", cgrid, runid, err.Error())
|
||||
}
|
||||
storCdr := &utils.StoredCdr{
|
||||
CgrId: cgrid, OrderId: orderid, AccId: accid, CdrHost: cdrhost, CdrSource: cdrsrc, ReqType: reqtype, Direction: direction, Tenant: tenant,
|
||||
TOR: tor, Account: account, Subject: subject, Destination: destination, SetupTime: setupTime, AnswerTime: answerTime, Duration: time.Duration(duration),
|
||||
Category: tor, Account: account, Subject: subject, Destination: destination, SetupTime: setupTime, AnswerTime: answerTime, Duration: time.Duration(duration),
|
||||
ExtraFields: extraFieldsMp, MediationRunId: runid.String, Cost: cost.Float64,
|
||||
}
|
||||
cdrs = append(cdrs, storCdr)
|
||||
@@ -1005,7 +1005,7 @@ func (self *SQLStorage) GetTpRatingPlans(tpid, tag string) (map[string][]*utils.
|
||||
}
|
||||
|
||||
func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) (map[string]*utils.TPRatingProfile, error) {
|
||||
q := fmt.Sprintf("SELECT loadid,tenant,tor,direction,subject,activation_time,rating_plan_id,fallback_subjects FROM %s WHERE tpid='%s'",
|
||||
q := fmt.Sprintf("SELECT loadid,direction,tenant,tor,subject,activation_time,rating_plan_id,fallback_subjects FROM %s WHERE tpid='%s'",
|
||||
utils.TBL_TP_RATE_PROFILES, qryRpf.TPid)
|
||||
if len(qryRpf.LoadId) != 0 {
|
||||
q += fmt.Sprintf(" AND loadid='%s'", qryRpf.LoadId)
|
||||
@@ -1013,8 +1013,8 @@ func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) (map[
|
||||
if len(qryRpf.Tenant) != 0 {
|
||||
q += fmt.Sprintf(" AND tenant='%s'", qryRpf.Tenant)
|
||||
}
|
||||
if len(qryRpf.TOR) != 0 {
|
||||
q += fmt.Sprintf(" AND tor='%s'", qryRpf.TOR)
|
||||
if len(qryRpf.Category) != 0 {
|
||||
q += fmt.Sprintf(" AND tor='%s'", qryRpf.Category)
|
||||
}
|
||||
if len(qryRpf.Direction) != 0 {
|
||||
q += fmt.Sprintf(" AND direction='%s'", qryRpf.Direction)
|
||||
@@ -1033,7 +1033,7 @@ func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) (map[
|
||||
if err := rows.Scan(&rcvLoadId, &tenant, &tor, &direction, &subject, &activation_time, &rating_plan_tag, &fallback_subjects); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rp := &utils.TPRatingProfile{TPid: qryRpf.TPid, LoadId: rcvLoadId, Tenant: tenant, TOR: tor, Direction: direction, Subject: subject}
|
||||
rp := &utils.TPRatingProfile{TPid: qryRpf.TPid, LoadId: rcvLoadId, Tenant: tenant, Category: tor, Direction: direction, Subject: subject}
|
||||
if existingRp, has := rpfs[rp.KeyId()]; !has {
|
||||
rp.RatingPlanActivations = []*utils.TPRatingActivation{
|
||||
&utils.TPRatingActivation{ActivationTime: activation_time, RatingPlanId: rating_plan_tag, FallbackSubjects: fallback_subjects}}
|
||||
@@ -1138,7 +1138,8 @@ func (self *SQLStorage) GetTpActionTriggers(tpid, tag string) (map[string][]*uti
|
||||
for rows.Next() {
|
||||
var threshold, weight float64
|
||||
var tpid, tag, balances_type, direction, destinations_tag, actions_tag, thresholdType string
|
||||
if err := rows.Scan(&tpid, &tag, &balances_type, &direction, &thresholdType, &threshold, &destinations_tag, &actions_tag, &weight); err != nil {
|
||||
var recurrent bool
|
||||
if err := rows.Scan(&tpid, &tag, &balances_type, &direction, &thresholdType, &threshold, &recurrent, &destinations_tag, &actions_tag, &weight); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestRemoveData(t *testing.T) {
|
||||
}
|
||||
// Create RatingProfile
|
||||
ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1"}}
|
||||
rp := &utils.TPRatingProfile{TPid: TEST_SQL, LoadId: TEST_SQL, Tenant: "cgrates.org", TOR: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras}
|
||||
rp := &utils.TPRatingProfile{TPid: TEST_SQL, LoadId: TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras}
|
||||
if err := mysql.SetTPRatingProfiles(TEST_SQL, map[string]*utils.TPRatingProfile{rp.KeyId(): rp}); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func TestRemoveData(t *testing.T) {
|
||||
t.Error("Could not store TPRatingProfile")
|
||||
}
|
||||
// Remove RatingProfile
|
||||
if err := mysql.RemTPData(utils.TBL_TP_RATE_PROFILES, rp.TPid, rp.LoadId, rp.Tenant, rp.TOR, rp.Direction, rp.Subject); err != nil {
|
||||
if err := mysql.RemTPData(utils.TBL_TP_RATE_PROFILES, rp.TPid, rp.LoadId, rp.Tenant, rp.Category, rp.Direction, rp.Subject); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
if rps, err := mysql.GetTpRatingProfiles(rp); err != nil {
|
||||
@@ -158,19 +158,19 @@ func TestSetCdr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
strCdr1 := &utils.StoredCdr{AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &utils.StoredCdr{AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: "prepaid",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &utils.StoredCdr{AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: "rated",
|
||||
Direction: "*out", Tenant: "itsyscom.com", TOR: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
@@ -188,19 +188,19 @@ func TestSetRatedCdr(t *testing.T) {
|
||||
return
|
||||
}
|
||||
strCdr1 := &utils.StoredCdr{AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
|
||||
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
|
||||
strCdr2 := &utils.StoredCdr{AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: "prepaid",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
|
||||
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
|
||||
strCdr3 := &utils.StoredCdr{AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: "rated",
|
||||
Direction: "*out", Tenant: "itsyscom.com", TOR: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
|
||||
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
MediationRunId: "wholesale_run", Cost: 1.201}
|
||||
|
||||
@@ -35,7 +35,7 @@ type TimeSpan struct {
|
||||
Cost float64
|
||||
ratingInfo *RatingInfo
|
||||
RateInterval *RateInterval
|
||||
CallDuration time.Duration // the call duration so far till TimeEnd
|
||||
DurationIndex time.Duration // the call duration so far till TimeEnd
|
||||
Increments Increments
|
||||
MatchedSubject, MatchedPrefix, MatchedDestId string
|
||||
}
|
||||
@@ -43,34 +43,35 @@ type TimeSpan struct {
|
||||
type Increment struct {
|
||||
Duration time.Duration
|
||||
Cost float64
|
||||
BalanceInfo *BalanceInfo // need more than one for minutes with cost
|
||||
BalanceInfo *BalanceInfo // need more than one for units with cost
|
||||
BalanceRateInterval *RateInterval
|
||||
MinuteInfo *MinuteInfo
|
||||
UnitInfo *UnitInfo
|
||||
CompressFactor int
|
||||
paid bool
|
||||
}
|
||||
|
||||
// Holds the minute information related to a specified timespan
|
||||
type MinuteInfo struct {
|
||||
type UnitInfo struct {
|
||||
DestinationId string
|
||||
Quantity float64
|
||||
Tor string
|
||||
//Price float64
|
||||
}
|
||||
|
||||
func (mi *MinuteInfo) Equal(other *MinuteInfo) bool {
|
||||
func (mi *UnitInfo) Equal(other *UnitInfo) bool {
|
||||
return mi.DestinationId == other.DestinationId &&
|
||||
mi.Quantity == other.Quantity
|
||||
}
|
||||
|
||||
// Holds information about the balance that made a specific payment
|
||||
type BalanceInfo struct {
|
||||
MinuteBalanceUuid string
|
||||
MoneyBalanceUuid string
|
||||
AccountId string // used when debited from shared balance
|
||||
UnitBalanceUuid string
|
||||
MoneyBalanceUuid string
|
||||
AccountId string // used when debited from shared balance
|
||||
}
|
||||
|
||||
func (bi *BalanceInfo) Equal(other *BalanceInfo) bool {
|
||||
return bi.MinuteBalanceUuid == other.MinuteBalanceUuid &&
|
||||
return bi.UnitBalanceUuid == other.UnitBalanceUuid &&
|
||||
bi.MoneyBalanceUuid == other.MoneyBalanceUuid &&
|
||||
bi.AccountId == other.AccountId
|
||||
}
|
||||
@@ -191,7 +192,7 @@ func (incr *Increment) Clone() *Increment {
|
||||
Duration: incr.Duration,
|
||||
Cost: incr.Cost,
|
||||
BalanceRateInterval: incr.BalanceRateInterval,
|
||||
MinuteInfo: incr.MinuteInfo,
|
||||
UnitInfo: incr.UnitInfo,
|
||||
BalanceInfo: incr.BalanceInfo,
|
||||
}
|
||||
return nIncr
|
||||
@@ -202,7 +203,7 @@ func (incr *Increment) Equal(other *Increment) bool {
|
||||
incr.Cost == other.Cost &&
|
||||
((incr.BalanceInfo == nil && other.BalanceInfo == nil) || incr.BalanceInfo.Equal(other.BalanceInfo)) &&
|
||||
((incr.BalanceRateInterval == nil && other.BalanceRateInterval == nil) || reflect.DeepEqual(incr.BalanceRateInterval, other.BalanceRateInterval)) &&
|
||||
((incr.MinuteInfo == nil && other.MinuteInfo == nil) || incr.MinuteInfo.Equal(other.MinuteInfo))
|
||||
((incr.UnitInfo == nil && other.UnitInfo == nil) || incr.UnitInfo.Equal(other.UnitInfo))
|
||||
}
|
||||
|
||||
func (incr *Increment) GetCompressFactor() int {
|
||||
@@ -317,7 +318,6 @@ a new timespan starting from the end of the received one.
|
||||
The interval will attach itself to the timespan that overlaps the interval.
|
||||
*/
|
||||
func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
|
||||
//Logger.Debug("here: ", ts, " +++ ", i)
|
||||
// if the span is not in interval return nil
|
||||
if !(i.Contains(ts.TimeStart, false) || i.Contains(ts.TimeEnd, true)) {
|
||||
//Logger.Debug("Not in interval")
|
||||
@@ -328,7 +328,7 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
|
||||
if i.Rating != nil {
|
||||
i.Rating.Rates.Sort()
|
||||
for _, rate := range i.Rating.Rates {
|
||||
// Logger.Debug(fmt.Sprintf("Rate: %+v", rate))
|
||||
//Logger.Debug(fmt.Sprintf("Rate: %+v", rate))
|
||||
if ts.GetGroupStart() < rate.GroupIntervalStart && ts.GetGroupEnd() > rate.GroupIntervalStart {
|
||||
// Logger.Debug(fmt.Sprintf("Splitting"))
|
||||
ts.SetRateInterval(i)
|
||||
@@ -340,8 +340,8 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
|
||||
nts.copyRatingInfo(ts)
|
||||
ts.TimeEnd = splitTime
|
||||
nts.SetRateInterval(i)
|
||||
nts.CallDuration = ts.CallDuration
|
||||
ts.SetNewCallDuration(nts)
|
||||
nts.DurationIndex = ts.DurationIndex
|
||||
ts.SetNewDurationIndex(nts)
|
||||
// Logger.Debug(fmt.Sprintf("Group splitting: %+v %+v", ts, nts))
|
||||
return
|
||||
}
|
||||
@@ -368,8 +368,8 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
|
||||
}
|
||||
nts.copyRatingInfo(ts)
|
||||
ts.TimeEnd = splitTime
|
||||
nts.CallDuration = ts.CallDuration
|
||||
ts.SetNewCallDuration(nts)
|
||||
nts.DurationIndex = ts.DurationIndex
|
||||
ts.SetNewDurationIndex(nts)
|
||||
// Logger.Debug(fmt.Sprintf("right: %+v %+v", ts, nts))
|
||||
return
|
||||
}
|
||||
@@ -390,8 +390,8 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
|
||||
ts.TimeEnd = splitTime
|
||||
|
||||
nts.SetRateInterval(i)
|
||||
nts.CallDuration = ts.CallDuration
|
||||
ts.SetNewCallDuration(nts)
|
||||
nts.DurationIndex = ts.DurationIndex
|
||||
ts.SetNewDurationIndex(nts)
|
||||
// Logger.Debug(fmt.Sprintf("left: %+v %+v", ts, nts))
|
||||
return
|
||||
}
|
||||
@@ -410,11 +410,11 @@ func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan {
|
||||
TimeEnd: ts.TimeEnd,
|
||||
}
|
||||
newTs.copyRatingInfo(ts)
|
||||
newTs.CallDuration = ts.CallDuration
|
||||
newTs.DurationIndex = ts.DurationIndex
|
||||
ts.TimeEnd = timeStart
|
||||
newTs.Increments = ts.Increments[index:]
|
||||
ts.Increments = ts.Increments[:index]
|
||||
ts.SetNewCallDuration(newTs)
|
||||
ts.SetNewDurationIndex(newTs)
|
||||
return newTs
|
||||
}
|
||||
|
||||
@@ -430,7 +430,7 @@ func (ts *TimeSpan) SplitByDuration(duration time.Duration) *TimeSpan {
|
||||
TimeEnd: ts.TimeEnd,
|
||||
}
|
||||
newTs.copyRatingInfo(ts)
|
||||
newTs.CallDuration = ts.CallDuration
|
||||
newTs.DurationIndex = ts.DurationIndex
|
||||
ts.TimeEnd = timeStart
|
||||
// split the increment
|
||||
for incrIndex, incr := range ts.Increments {
|
||||
@@ -449,7 +449,7 @@ func (ts *TimeSpan) SplitByDuration(duration time.Duration) *TimeSpan {
|
||||
break
|
||||
}
|
||||
}
|
||||
ts.SetNewCallDuration(newTs)
|
||||
ts.SetNewDurationIndex(newTs)
|
||||
return newTs
|
||||
}
|
||||
|
||||
@@ -463,16 +463,16 @@ func (ts *TimeSpan) SplitByRatingPlan(rp *RatingInfo) (newTs *TimeSpan) {
|
||||
TimeEnd: ts.TimeEnd,
|
||||
}
|
||||
newTs.copyRatingInfo(ts)
|
||||
newTs.CallDuration = ts.CallDuration
|
||||
newTs.DurationIndex = ts.DurationIndex
|
||||
ts.TimeEnd = rp.ActivationTime
|
||||
ts.SetNewCallDuration(newTs)
|
||||
ts.SetNewDurationIndex(newTs)
|
||||
// Logger.Debug(fmt.Sprintf("RP SPLITTING: %+v %+v", ts, newTs))
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the starting time of this timespan
|
||||
func (ts *TimeSpan) GetGroupStart() time.Duration {
|
||||
s := ts.CallDuration - ts.GetDuration()
|
||||
s := ts.DurationIndex - ts.GetDuration()
|
||||
if s < 0 {
|
||||
s = 0
|
||||
}
|
||||
@@ -480,16 +480,16 @@ func (ts *TimeSpan) GetGroupStart() time.Duration {
|
||||
}
|
||||
|
||||
func (ts *TimeSpan) GetGroupEnd() time.Duration {
|
||||
return ts.CallDuration
|
||||
return ts.DurationIndex
|
||||
}
|
||||
|
||||
// sets the CallDuration attribute to reflect new timespan
|
||||
func (ts *TimeSpan) SetNewCallDuration(nts *TimeSpan) {
|
||||
d := ts.CallDuration - nts.GetDuration()
|
||||
// sets the DurationIndex attribute to reflect new timespan
|
||||
func (ts *TimeSpan) SetNewDurationIndex(nts *TimeSpan) {
|
||||
d := ts.DurationIndex - nts.GetDuration()
|
||||
if d < 0 {
|
||||
d = 0
|
||||
}
|
||||
ts.CallDuration = d
|
||||
ts.DurationIndex = d
|
||||
}
|
||||
|
||||
func (nts *TimeSpan) copyRatingInfo(ts *TimeSpan) {
|
||||
@@ -514,6 +514,6 @@ func (ts *TimeSpan) RoundToDuration(duration time.Duration) {
|
||||
if duration > ts.GetDuration() {
|
||||
initialDuration := ts.GetDuration()
|
||||
ts.TimeEnd = ts.TimeStart.Add(duration)
|
||||
ts.CallDuration = ts.CallDuration + (duration - initialDuration)
|
||||
ts.DurationIndex = ts.DurationIndex + (duration - initialDuration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ func TestTimespanSplitGroupedRates(t *testing.T) {
|
||||
}
|
||||
t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 3, 18, 00, 0, 0, time.UTC)
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 1800 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, DurationIndex: 1800 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
oldDuration := ts.GetDuration()
|
||||
nts := ts.SplitByRateInterval(i)
|
||||
splitTime := time.Date(2012, time.February, 3, 17, 45, 00, 0, time.UTC)
|
||||
@@ -313,7 +313,7 @@ func TestTimespanSplitGroupedRatesIncrements(t *testing.T) {
|
||||
}
|
||||
t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 3, 17, 31, 0, 0, time.UTC)
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 60 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, DurationIndex: 60 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
oldDuration := ts.GetDuration()
|
||||
nts := ts.SplitByRateInterval(i)
|
||||
cd := &CallDescriptor{}
|
||||
@@ -395,7 +395,7 @@ func TestTimespanSplitGroupSecondSplit(t *testing.T) {
|
||||
}
|
||||
t1 := time.Date(2012, time.February, 3, 17, 00, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 3, 17, 04, 0, 0, time.UTC)
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 240 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, DurationIndex: 240 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
oldDuration := ts.GetDuration()
|
||||
nts := ts.SplitByRateInterval(i)
|
||||
splitTime := time.Date(2012, time.February, 3, 17, 01, 00, 0, time.UTC)
|
||||
@@ -440,7 +440,7 @@ func TestTimespanSplitLong(t *testing.T) {
|
||||
}
|
||||
t1 := time.Date(2013, time.October, 9, 9, 0, 0, 0, time.UTC)
|
||||
t2 := time.Date(2013, time.October, 10, 20, 0, 0, 0, time.UTC)
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: t2.Sub(t1), ratingInfo: &RatingInfo{}}
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, DurationIndex: t2.Sub(t1), ratingInfo: &RatingInfo{}}
|
||||
oldDuration := ts.GetDuration()
|
||||
nts := ts.SplitByRateInterval(i)
|
||||
splitTime := time.Date(2013, time.October, 9, 18, 0, 0, 0, time.UTC)
|
||||
@@ -472,7 +472,7 @@ func TestTimespanSplitMultipleGroup(t *testing.T) {
|
||||
}
|
||||
t1 := time.Date(2012, time.February, 3, 17, 00, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 3, 17, 04, 0, 0, time.UTC)
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, CallDuration: 240 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
ts := &TimeSpan{TimeStart: t1, TimeEnd: t2, DurationIndex: 240 * time.Second, ratingInfo: &RatingInfo{}}
|
||||
oldDuration := ts.GetDuration()
|
||||
nts := ts.SplitByRateInterval(i)
|
||||
splitTime := time.Date(2012, time.February, 3, 17, 01, 00, 0, time.UTC)
|
||||
@@ -533,7 +533,7 @@ func TestTimespanExpandingPastEnd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimespanExpandingCallDuration(t *testing.T) {
|
||||
func TestTimespanExpandingDurationIndex(t *testing.T) {
|
||||
timespans := []*TimeSpan{
|
||||
&TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 10, 14, 30, 0, 0, time.UTC),
|
||||
@@ -736,10 +736,10 @@ func TestTimespanCreateIncrements(t *testing.T) {
|
||||
|
||||
func TestTimespanSplitByIncrement(t *testing.T) {
|
||||
ts := &TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
CallDuration: 60 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
DurationIndex: 60 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
RoundingMethod: utils.ROUNDING_MIDDLE,
|
||||
@@ -761,8 +761,8 @@ func TestTimespanSplitByIncrement(t *testing.T) {
|
||||
if ts.GetDuration() != 50*time.Second || newTs.GetDuration() != 10*time.Second {
|
||||
t.Error("Error spliting by increment: ", ts.GetDuration(), newTs.GetDuration())
|
||||
}
|
||||
if ts.CallDuration != 50*time.Second || newTs.CallDuration != 60*time.Second {
|
||||
t.Error("Error spliting by increment at setting call duration: ", ts.CallDuration, newTs.CallDuration)
|
||||
if ts.DurationIndex != 50*time.Second || newTs.DurationIndex != 60*time.Second {
|
||||
t.Error("Error spliting by increment at setting call duration: ", ts.DurationIndex, newTs.DurationIndex)
|
||||
}
|
||||
if len(ts.Increments) != 5 || len(newTs.Increments) != 1 {
|
||||
t.Error("Error spliting increments: ", ts.Increments, newTs.Increments)
|
||||
@@ -771,9 +771,9 @@ func TestTimespanSplitByIncrement(t *testing.T) {
|
||||
|
||||
func TestTimespanSplitByIncrementStart(t *testing.T) {
|
||||
ts := &TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
CallDuration: 60 * time.Second,
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
DurationIndex: 60 * time.Second,
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
RoundingMethod: utils.ROUNDING_MIDDLE,
|
||||
@@ -795,8 +795,8 @@ func TestTimespanSplitByIncrementStart(t *testing.T) {
|
||||
if ts.GetDuration() != 60*time.Second || newTs != nil {
|
||||
t.Error("Error spliting by increment: ", ts.GetDuration())
|
||||
}
|
||||
if ts.CallDuration != 60*time.Second {
|
||||
t.Error("Error spliting by incrementat setting call duration: ", ts.CallDuration)
|
||||
if ts.DurationIndex != 60*time.Second {
|
||||
t.Error("Error spliting by incrementat setting call duration: ", ts.DurationIndex)
|
||||
}
|
||||
if len(ts.Increments) != 6 {
|
||||
t.Error("Error spliting increments: ", ts.Increments)
|
||||
@@ -805,9 +805,9 @@ func TestTimespanSplitByIncrementStart(t *testing.T) {
|
||||
|
||||
func TestTimespanSplitByIncrementEnd(t *testing.T) {
|
||||
ts := &TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
CallDuration: 60 * time.Second,
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
DurationIndex: 60 * time.Second,
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
RoundingMethod: utils.ROUNDING_MIDDLE,
|
||||
@@ -829,8 +829,8 @@ func TestTimespanSplitByIncrementEnd(t *testing.T) {
|
||||
if ts.GetDuration() != 60*time.Second || newTs != nil {
|
||||
t.Error("Error spliting by increment: ", ts.GetDuration())
|
||||
}
|
||||
if ts.CallDuration != 60*time.Second {
|
||||
t.Error("Error spliting by increment at setting call duration: ", ts.CallDuration)
|
||||
if ts.DurationIndex != 60*time.Second {
|
||||
t.Error("Error spliting by increment at setting call duration: ", ts.DurationIndex)
|
||||
}
|
||||
if len(ts.Increments) != 6 {
|
||||
t.Error("Error spliting increments: ", ts.Increments)
|
||||
@@ -839,10 +839,10 @@ func TestTimespanSplitByIncrementEnd(t *testing.T) {
|
||||
|
||||
func TestTimespanSplitByDuration(t *testing.T) {
|
||||
ts := &TimeSpan{
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
CallDuration: 60 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
TimeStart: time.Date(2013, 9, 19, 18, 30, 0, 0, time.UTC),
|
||||
TimeEnd: time.Date(2013, 9, 19, 18, 31, 00, 0, time.UTC),
|
||||
DurationIndex: 60 * time.Second,
|
||||
ratingInfo: &RatingInfo{},
|
||||
RateInterval: &RateInterval{
|
||||
Rating: &RIRate{
|
||||
RoundingMethod: utils.ROUNDING_MIDDLE,
|
||||
@@ -864,8 +864,8 @@ func TestTimespanSplitByDuration(t *testing.T) {
|
||||
if ts.GetDuration() != 46*time.Second || newTs.GetDuration() != 14*time.Second {
|
||||
t.Error("Error spliting by duration: ", ts.GetDuration(), newTs.GetDuration())
|
||||
}
|
||||
if ts.CallDuration != 46*time.Second || newTs.CallDuration != 60*time.Second {
|
||||
t.Error("Error spliting by duration at setting call duration: ", ts.CallDuration, newTs.CallDuration)
|
||||
if ts.DurationIndex != 46*time.Second || newTs.DurationIndex != 60*time.Second {
|
||||
t.Error("Error spliting by duration at setting call duration: ", ts.DurationIndex, newTs.DurationIndex)
|
||||
}
|
||||
if len(ts.Increments) != 5 || len(newTs.Increments) != 2 {
|
||||
t.Error("Error spliting increments: ", ts.Increments, newTs.Increments)
|
||||
@@ -1501,35 +1501,35 @@ func TestTSCompressDecompress(t *testing.T) {
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1111 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1553,35 +1553,35 @@ func TestTSMultipleCompressDecompress(t *testing.T) {
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1111 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
&Increment{
|
||||
Duration: time.Minute,
|
||||
Cost: 10.4,
|
||||
BalanceInfo: &BalanceInfo{"1", "2", "3"},
|
||||
BalanceRateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}},
|
||||
MinuteInfo: &MinuteInfo{"1", 2.3},
|
||||
UnitInfo: &UnitInfo{"1", 2.3, MINUTES},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -273,7 +273,7 @@ func (self *TPCSVImporter) importRatingProfiles(fn string) error {
|
||||
rp := &utils.TPRatingProfile{
|
||||
LoadId: loadId,
|
||||
Tenant: tenant,
|
||||
TOR: tor,
|
||||
Category: tor,
|
||||
Direction: direction,
|
||||
Subject: subject,
|
||||
RatingPlanActivations: []*utils.TPRatingActivation{
|
||||
|
||||
@@ -48,11 +48,11 @@ RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s,*up,8`
|
||||
DR_UK_Mobile_BIG5,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5`
|
||||
ratingPlans := `RP_UK_Mobile_BIG5_PKG,DR_UK_Mobile_BIG5_PKG,ALWAYS,10
|
||||
RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10`
|
||||
ratingProfiles := `cgrates.org,call,*out,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
cgrates.org,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
ratingProfiles := `*out,cgrates.org,call,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
*out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
sharedGroups := ``
|
||||
actions := `TOPUP10_AC,*topup_reset,*monetary,*out,10,*unlimited,*any,,10,,,10
|
||||
TOPUP10_AC1,*topup_reset,*minutes,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
TOPUP10_AC1,*topup_reset,*call_duration,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10
|
||||
TOPUP10_AT,TOPUP10_AC1,ASAP,10`
|
||||
actionTriggers := ``
|
||||
@@ -135,7 +135,7 @@ func TestExecuteActions(t *testing.T) {
|
||||
func TestDebit(t *testing.T) {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
|
||||
@@ -48,11 +48,11 @@ RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s,*up,8`
|
||||
DR_UK_Mobile_BIG5,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5`
|
||||
ratingPlans := `RP_UK_Mobile_BIG5_PKG,DR_UK_Mobile_BIG5_PKG,ALWAYS,10
|
||||
RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10`
|
||||
ratingProfiles := `cgrates.org,call,*out,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
cgrates.org,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
ratingProfiles := `*out,cgrates.org,call,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
*out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
sharedGroups := ``
|
||||
actions := `TOPUP10_AC,*topup_reset,*monetary,*out,0,*unlimited,*any,,10,,,10
|
||||
TOPUP10_AC1,*topup_reset,*minutes,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
TOPUP10_AC1,*topup_reset,*call_duration,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10
|
||||
TOPUP10_AT,TOPUP10_AC1,ASAP,10`
|
||||
actionTriggers := ``
|
||||
@@ -135,7 +135,7 @@ func TestExecuteActions2(t *testing.T) {
|
||||
func TestDebit2(t *testing.T) {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
|
||||
@@ -48,10 +48,10 @@ RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s,*up,8`
|
||||
DR_UK_Mobile_BIG5,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5`
|
||||
ratingPlans := `RP_UK_Mobile_BIG5_PKG,DR_UK_Mobile_BIG5_PKG,ALWAYS,10
|
||||
RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10`
|
||||
ratingProfiles := `cgrates.org,call,*out,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
cgrates.org,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
ratingProfiles := `*out,cgrates.org,call,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
*out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,`
|
||||
sharedGroups := ``
|
||||
actions := `TOPUP10_AC1,*topup_reset,*minutes,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
actions := `TOPUP10_AC1,*topup_reset,*call_duration,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10`
|
||||
actionPlans := `TOPUP10_AT,TOPUP10_AC1,ASAP,10`
|
||||
actionTriggers := ``
|
||||
accountActions := `cgrates.org,12345,*out,TOPUP10_AT,`
|
||||
@@ -131,7 +131,7 @@ func TestExecuteActions3(t *testing.T) {
|
||||
func TestDebit3(t *testing.T) {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Category: "call",
|
||||
Tenant: "cgrates.org",
|
||||
Subject: "12345",
|
||||
Account: "12345",
|
||||
|
||||
@@ -65,16 +65,16 @@ func (self *Mediator) getCostsFromRater(cdr *utils.StoredCdr) (*engine.CallCost,
|
||||
return cc, nil
|
||||
}
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: "*out", //record[m.directionFields[runIdx]] TODO: fix me
|
||||
Tenant: cdr.Tenant,
|
||||
TOR: cdr.TOR,
|
||||
Subject: cdr.Subject,
|
||||
Account: cdr.Account,
|
||||
Destination: cdr.Destination,
|
||||
TimeStart: cdr.AnswerTime,
|
||||
TimeEnd: cdr.AnswerTime.Add(cdr.Duration),
|
||||
LoopIndex: 0,
|
||||
CallDuration: cdr.Duration,
|
||||
Direction: "*out", //record[m.directionFields[runIdx]] TODO: fix me
|
||||
Tenant: cdr.Tenant,
|
||||
Category: cdr.Category,
|
||||
Subject: cdr.Subject,
|
||||
Account: cdr.Account,
|
||||
Destination: cdr.Destination,
|
||||
TimeStart: cdr.AnswerTime,
|
||||
TimeEnd: cdr.AnswerTime.Add(cdr.Duration),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: cdr.Duration,
|
||||
}
|
||||
if cdr.ReqType == utils.PSEUDOPREPAID {
|
||||
err = self.connector.Debit(cd, cc)
|
||||
@@ -114,8 +114,8 @@ func (self *Mediator) RateCdr(dbcdr utils.RawCDR) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cdrs := []*utils.StoredCdr{rtCdr} // Start with initial dbcdr, will add here all to be mediated
|
||||
attrsDC := utils.AttrDerivedChargers{Direction: rtCdr.Direction, Tenant: rtCdr.Tenant, Category: rtCdr.TOR,
|
||||
cdrs := []*utils.StoredCdr{rtCdr} // Start with initial dbcdr, will add here all to be mediated
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: rtCdr.Tenant, Category: rtCdr.Category, Direction: rtCdr.Direction,
|
||||
Account: rtCdr.Account, Subject: rtCdr.Subject}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := self.connector.GetDerivedChargers(attrsDC, &dcs); err != nil {
|
||||
|
||||
@@ -32,7 +32,7 @@ type Event interface {
|
||||
GetAccount(string) string
|
||||
GetDestination(string) string
|
||||
GetCallDestNr(string) string
|
||||
GetTOR(string) string
|
||||
GetCategory(string) string
|
||||
GetTenant(string) string
|
||||
GetReqType(string) string
|
||||
GetSetupTime(string) (time.Time, error)
|
||||
|
||||
@@ -20,12 +20,13 @@ package sessionmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/fsock"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ToDo: Introduce support for RSRFields
|
||||
@@ -40,7 +41,7 @@ const (
|
||||
ACCOUNT = "variable_cgr_account"
|
||||
DESTINATION = "variable_cgr_destination"
|
||||
REQTYPE = "variable_cgr_reqtype" //prepaid or postpaid
|
||||
TOR = "variable_cgr_tor"
|
||||
Category = "variable_cgr_tor"
|
||||
UUID = "Unique-ID" // -Unique ID for this call leg
|
||||
CSTMID = "variable_cgr_tenant"
|
||||
CALL_DEST_NR = "Caller-Destination-Number"
|
||||
@@ -126,13 +127,13 @@ func (fsev FSEvent) GetCallDestNr(fieldName string) string {
|
||||
}
|
||||
return utils.FirstNonEmpty(fsev[fieldName], fsev[CALL_DEST_NR])
|
||||
}
|
||||
func (fsev FSEvent) GetTOR(fieldName string) string {
|
||||
func (fsev FSEvent) GetCategory(fieldName string) string {
|
||||
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
|
||||
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
|
||||
} else if fieldName == utils.META_DEFAULT {
|
||||
return utils.FirstNonEmpty(fsev[TOR], config.CgrConfig().DefaultTOR)
|
||||
return utils.FirstNonEmpty(fsev[Category], config.CgrConfig().DefaultCategory)
|
||||
}
|
||||
return utils.FirstNonEmpty(fsev[fieldName], fsev[TOR], config.CgrConfig().DefaultTOR)
|
||||
return utils.FirstNonEmpty(fsev[fieldName], fsev[Category], config.CgrConfig().DefaultCategory)
|
||||
}
|
||||
func (fsev FSEvent) GetCgrId() string {
|
||||
setupTime, _ := fsev.GetSetupTime(utils.META_DEFAULT)
|
||||
@@ -162,7 +163,7 @@ func (fsev FSEvent) MissingParameter() bool {
|
||||
strings.TrimSpace(fsev.GetSubject(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetAccount(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetDestination(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetTOR(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetCategory(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetUUID()) == "" ||
|
||||
strings.TrimSpace(fsev.GetTenant(utils.META_DEFAULT)) == "" ||
|
||||
strings.TrimSpace(fsev.GetCallDestNr(utils.META_DEFAULT)) == ""
|
||||
|
||||
@@ -19,10 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package sessionmanager
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestEventCreation(t *testing.T) {
|
||||
@@ -62,7 +63,7 @@ func TestEventParseStatic(t *testing.T) {
|
||||
if ev.GetReqType("^test") != "test" ||
|
||||
ev.GetDirection("^test") != "test" ||
|
||||
ev.GetTenant("^test") != "test" ||
|
||||
ev.GetTOR("^test") != "test" ||
|
||||
ev.GetCategory("^test") != "test" ||
|
||||
ev.GetAccount("^test") != "test" ||
|
||||
ev.GetSubject("^test") != "test" ||
|
||||
ev.GetDestination("^test") != "test" ||
|
||||
@@ -73,7 +74,7 @@ func TestEventParseStatic(t *testing.T) {
|
||||
ev.GetReqType("^test") != "test",
|
||||
ev.GetDirection("^test") != "test",
|
||||
ev.GetTenant("^test") != "test",
|
||||
ev.GetTOR("^test") != "test",
|
||||
ev.GetCategory("^test") != "test",
|
||||
ev.GetAccount("^test") != "test",
|
||||
ev.GetSubject("^test") != "test",
|
||||
ev.GetDestination("^test") != "test",
|
||||
@@ -111,7 +112,7 @@ Task-Runtime: 1349437318`
|
||||
if ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out" ||
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetTOR("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
@@ -122,7 +123,7 @@ Task-Runtime: 1349437318`
|
||||
ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out",
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetTOR("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
@@ -477,7 +478,7 @@ variable_rtp_audio_rtcp_octet_count: 0
|
||||
if ev.GetReqType(utils.META_DEFAULT) != utils.PSEUDOPREPAID ||
|
||||
ev.GetDirection(utils.META_DEFAULT) != "*out" ||
|
||||
ev.GetTenant(utils.META_DEFAULT) != "cgrates.org" ||
|
||||
ev.GetTOR(utils.META_DEFAULT) != "call" ||
|
||||
ev.GetCategory(utils.META_DEFAULT) != "call" ||
|
||||
ev.GetAccount(utils.META_DEFAULT) != "1003" ||
|
||||
ev.GetSubject(utils.META_DEFAULT) != "1003" ||
|
||||
ev.GetDestination(utils.META_DEFAULT) != "1002" ||
|
||||
@@ -488,7 +489,7 @@ variable_rtp_audio_rtcp_octet_count: 0
|
||||
ev.GetReqType(utils.META_DEFAULT) != utils.PSEUDOPREPAID,
|
||||
ev.GetDirection(utils.META_DEFAULT) != "*out",
|
||||
ev.GetTenant(utils.META_DEFAULT) != "cgrates.org",
|
||||
ev.GetTOR(utils.META_DEFAULT) != "call",
|
||||
ev.GetCategory(utils.META_DEFAULT) != "call",
|
||||
ev.GetAccount(utils.META_DEFAULT) != "1003",
|
||||
ev.GetSubject(utils.META_DEFAULT) != "1003",
|
||||
ev.GetDestination(utils.META_DEFAULT) != "1002",
|
||||
|
||||
@@ -151,7 +151,7 @@ func (sm *FSSessionManager) OnHeartBeat(ev Event) {
|
||||
func (sm *FSSessionManager) OnChannelPark(ev Event) {
|
||||
var maxCallDuration time.Duration // This will be the maximum duration this channel will be allowed to last
|
||||
var durInitialized bool
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetTOR(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := sm.connector.GetDerivedChargers(attrsDC, &dcs); err != nil {
|
||||
@@ -178,7 +178,7 @@ func (sm *FSSessionManager) OnChannelPark(ev Event) {
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: ev.GetDirection(dc.DirectionField),
|
||||
Tenant: ev.GetTenant(dc.TenantField),
|
||||
TOR: ev.GetTOR(dc.TorField),
|
||||
Category: ev.GetCategory(dc.TorField),
|
||||
Subject: ev.GetSubject(dc.SubjectField),
|
||||
Account: ev.GetAccount(dc.AccountField),
|
||||
Destination: ev.GetDestination(dc.DestinationField),
|
||||
@@ -219,7 +219,7 @@ func (sm *FSSessionManager) OnChannelAnswer(ev Event) {
|
||||
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_setvar %s cgr_reqtype %s\n\n", ev.GetUUID(), ev.GetReqType(""))); err != nil {
|
||||
engine.Logger.Err(fmt.Sprintf("Error on attempting to overwrite cgr_type in chan variables: %v", err))
|
||||
}
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetTOR(utils.META_DEFAULT),
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT),
|
||||
Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := sm.connector.GetDerivedChargers(attrsDC, &dcs); err != nil {
|
||||
@@ -242,7 +242,7 @@ func (sm *FSSessionManager) OnChannelHangupComplete(ev Event) {
|
||||
sm.RemoveSession(s.uuid) // Unreference it early so we avoid concurrency
|
||||
}
|
||||
defer s.Close(ev) // Stop loop and save the costs deducted so far to database
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetTOR(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := sm.connector.GetDerivedChargers(attrsDC, &dcs); err != nil {
|
||||
@@ -264,16 +264,16 @@ func (sm *FSSessionManager) OnChannelHangupComplete(ev Event) {
|
||||
return
|
||||
}
|
||||
cd := engine.CallDescriptor{
|
||||
Direction: ev.GetDirection(dc.DirectionField),
|
||||
Tenant: ev.GetTenant(dc.TenantField),
|
||||
TOR: ev.GetTOR(dc.TorField),
|
||||
Subject: ev.GetSubject(dc.SubjectField),
|
||||
Account: ev.GetAccount(dc.AccountField),
|
||||
LoopIndex: 0,
|
||||
CallDuration: duration,
|
||||
Destination: ev.GetDestination(dc.DestinationField),
|
||||
TimeStart: startTime,
|
||||
TimeEnd: startTime.Add(duration),
|
||||
Direction: ev.GetDirection(dc.DirectionField),
|
||||
Tenant: ev.GetTenant(dc.TenantField),
|
||||
Category: ev.GetCategory(dc.TorField),
|
||||
Subject: ev.GetSubject(dc.SubjectField),
|
||||
Account: ev.GetAccount(dc.AccountField),
|
||||
LoopIndex: 0,
|
||||
DurationIndex: duration,
|
||||
Destination: ev.GetDestination(dc.DestinationField),
|
||||
TimeStart: startTime,
|
||||
TimeEnd: startTime.Add(duration),
|
||||
}
|
||||
cc := &engine.CallCost{}
|
||||
err = sm.connector.Debit(cd, cc)
|
||||
@@ -333,7 +333,7 @@ func (sm *FSSessionManager) OnChannelHangupComplete(ev Event) {
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: lastCC.Direction,
|
||||
Tenant: lastCC.Tenant,
|
||||
TOR: lastCC.TOR,
|
||||
Category: lastCC.Category,
|
||||
Subject: lastCC.Subject,
|
||||
Account: lastCC.Account,
|
||||
Destination: lastCC.Destination,
|
||||
|
||||
@@ -61,7 +61,7 @@ func NewSession(ev Event, sm SessionManager, dcs utils.DerivedChargers) *Session
|
||||
cd := &engine.CallDescriptor{
|
||||
Direction: ev.GetDirection(dc.DirectionField),
|
||||
Tenant: ev.GetTenant(dc.TenantField),
|
||||
TOR: ev.GetTOR(dc.TorField),
|
||||
Category: ev.GetCategory(dc.TorField),
|
||||
Subject: ev.GetSubject(dc.SubjectField),
|
||||
Account: ev.GetAccount(dc.AccountField),
|
||||
Destination: ev.GetDestination(dc.DestinationField),
|
||||
@@ -97,7 +97,7 @@ func (s *Session) debitLoop(runIdx int) {
|
||||
}
|
||||
nextCd.TimeEnd = nextCd.TimeStart.Add(debitPeriod)
|
||||
nextCd.LoopIndex = index
|
||||
nextCd.CallDuration += debitPeriod // first presumed duration
|
||||
nextCd.DurationIndex += debitPeriod // first presumed duration
|
||||
cc := &engine.CallCost{}
|
||||
if err := s.sessionManager.MaxDebit(&nextCd, cc); err != nil {
|
||||
engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err))
|
||||
@@ -112,8 +112,8 @@ func (s *Session) debitLoop(runIdx int) {
|
||||
s.sessionRuns[runIdx].callCosts = append(s.sessionRuns[runIdx].callCosts, cc)
|
||||
nextCd.TimeEnd = cc.GetEndTime() // set debited timeEnd
|
||||
// update call duration with real debited duration
|
||||
nextCd.CallDuration -= debitPeriod
|
||||
nextCd.CallDuration += nextCd.GetDuration()
|
||||
nextCd.DurationIndex -= debitPeriod
|
||||
nextCd.DurationIndex += nextCd.GetDuration()
|
||||
time.Sleep(cc.GetDuration())
|
||||
index++
|
||||
}
|
||||
@@ -129,7 +129,7 @@ func (s *Session) Close(ev Event) {
|
||||
if _, err := ev.GetEndTime(); err != nil {
|
||||
engine.Logger.Err("Error parsing answer event stop time.")
|
||||
for idx := range s.sessionRuns {
|
||||
s.sessionRuns[idx].callDescriptor.TimeEnd = s.sessionRuns[idx].callDescriptor.TimeStart.Add(s.sessionRuns[idx].callDescriptor.CallDuration)
|
||||
s.sessionRuns[idx].callDescriptor.TimeEnd = s.sessionRuns[idx].callDescriptor.TimeStart.Add(s.sessionRuns[idx].callDescriptor.DurationIndex)
|
||||
}
|
||||
}
|
||||
s.SaveOperations()
|
||||
|
||||
@@ -146,14 +146,14 @@ func NewTPRatingProfileFromKeyId(tpid, loadId, keyId string) (*TPRatingProfile,
|
||||
if len(s) != 4 {
|
||||
return nil, fmt.Errorf("Cannot parse key %s into RatingProfile", keyId)
|
||||
}
|
||||
return &TPRatingProfile{TPid: tpid, LoadId: loadId, Tenant: s[1], TOR: s[2], Direction: s[0], Subject: s[3]}, nil
|
||||
return &TPRatingProfile{TPid: tpid, LoadId: loadId, Tenant: s[1], Category: s[2], Direction: s[0], Subject: s[3]}, nil
|
||||
}
|
||||
|
||||
type TPRatingProfile struct {
|
||||
TPid string // Tariff plan id
|
||||
LoadId string // Gives ability to load specific RatingProfile based on load identifier, hence being able to keep history also in stordb
|
||||
Tenant string // Tenant's Id
|
||||
TOR string // TypeOfRecord
|
||||
Category string // TypeOfRecord
|
||||
Direction string // Traffic direction, OUT is the only one supported for now
|
||||
Subject string // Rating subject, usually the same as account
|
||||
RatingPlanActivations []*TPRatingActivation // Activate rate profiles at specific time
|
||||
@@ -161,7 +161,7 @@ type TPRatingProfile struct {
|
||||
|
||||
// Used as key in nosql db (eg: redis)
|
||||
func (self *TPRatingProfile) KeyId() string {
|
||||
return fmt.Sprintf("%s:%s:%s:%s", self.Direction, self.Tenant, self.TOR, self.Subject)
|
||||
return fmt.Sprintf("%s:%s:%s:%s", self.Direction, self.Tenant, self.Category, self.Subject)
|
||||
}
|
||||
|
||||
type TPRatingActivation struct {
|
||||
@@ -196,7 +196,7 @@ func FallbackSubjKeys(direction, tenant, tor, fallbackSubjects string) []string
|
||||
type AttrTPRatingProfileIds struct {
|
||||
TPid string // Tariff plan id
|
||||
Tenant string // Tenant's Id
|
||||
TOR string // TypeOfRecord
|
||||
Category string // TypeOfRecord
|
||||
Direction string // Traffic direction
|
||||
Subject string // Rating subject, usually the same as account
|
||||
}
|
||||
@@ -245,6 +245,7 @@ type TPActionTrigger struct {
|
||||
Direction string // Traffic direction
|
||||
ThresholdType string // This threshold type
|
||||
ThresholdValue float64 // Threshold
|
||||
Recurrent bool // reset executed flag each run
|
||||
DestinationId string // Id of the destination profile
|
||||
ActionsId string // Actions which will execute on threshold reached
|
||||
Weight float64 // weight
|
||||
|
||||
@@ -77,8 +77,8 @@ func (cgrCdr CgrCdr) GetDestination() string {
|
||||
return cgrCdr[DESTINATION]
|
||||
}
|
||||
|
||||
func (cgrCdr CgrCdr) GetTOR() string {
|
||||
return cgrCdr[TOR]
|
||||
func (cgrCdr CgrCdr) GetCategory() string {
|
||||
return cgrCdr[Category]
|
||||
}
|
||||
|
||||
func (cgrCdr CgrCdr) GetTenant() string {
|
||||
@@ -136,7 +136,7 @@ func (cgrCdr CgrCdr) ForkCdr(runId, reqTypeFld, directionFld, tenantFld, torFld,
|
||||
tenantFld = TENANT
|
||||
}
|
||||
if torFld == META_DEFAULT {
|
||||
torFld = TOR
|
||||
torFld = Category
|
||||
}
|
||||
if accountFld == META_DEFAULT {
|
||||
accountFld = ACCOUNT
|
||||
@@ -178,8 +178,8 @@ func (cgrCdr CgrCdr) ForkCdr(runId, reqTypeFld, directionFld, tenantFld, torFld,
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, tenantFld))
|
||||
}
|
||||
if strings.HasPrefix(torFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.TOR = torFld[1:]
|
||||
} else if rtCdr.TOR, hasKey = cgrCdr[torFld]; !hasKey && fieldsMandatory {
|
||||
rtCdr.Category = torFld[1:]
|
||||
} else if rtCdr.Category, hasKey = cgrCdr[torFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, torFld))
|
||||
}
|
||||
if strings.HasPrefix(accountFld, STATIC_VALUE_PREFIX) {
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestCgrCdrFields(t *testing.T) {
|
||||
if cgrCdr.GetDestination() != "1002" {
|
||||
t.Error("Error parsing cdr: ", cgrCdr)
|
||||
}
|
||||
if cgrCdr.GetTOR() != "call" {
|
||||
if cgrCdr.GetCategory() != "call" {
|
||||
t.Error("Error parsing cdr: ", cgrCdr)
|
||||
}
|
||||
if cgrCdr.GetTenant() != "cgrates.org" {
|
||||
@@ -96,7 +96,7 @@ func TestCgrCdrForkCdr(t *testing.T) {
|
||||
}
|
||||
setupTime1 := time.Date(2013, 11, 7, 8, 42, 24, 0, time.UTC)
|
||||
expctSplRatedCdr := &StoredCdr{CgrId: Sha1("dsafdsaf", setupTime1.String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: setupTime1, AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Duration: 10000000000, ExtraFields: map[string]string{}, MediationRunId: "sample_run1", Cost: -1}
|
||||
if !reflect.DeepEqual(expctSplRatedCdr, rtSampleCdrOut) {
|
||||
@@ -112,7 +112,7 @@ func TestCgrCdrForkCdr(t *testing.T) {
|
||||
}
|
||||
setupTime, _ := ParseTimeDetectLayout("2013-11-07T08:42:24Z")
|
||||
expctRatedCdr := &StoredCdr{CgrId: Sha1("dsafdsaf", setupTime.String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Unix(1383813744, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Duration: 10000000000, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut, expctRatedCdr) {
|
||||
@@ -124,7 +124,7 @@ func TestCgrCdrForkCdr(t *testing.T) {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr2 := &StoredCdr{CgrId: Sha1("dsafdsaf", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "postpaid",
|
||||
Direction: "*in", Tenant: "cgrates.com", TOR: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002",
|
||||
Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(12) * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
@@ -144,7 +144,7 @@ func TestCgrCdrForkCdrFromMetaDefaults(t *testing.T) {
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
setupTime := time.Date(2013, 11, 7, 8, 42, 24, 0, time.UTC)
|
||||
expctCdr := &StoredCdr{CgrId: Sha1("dsafdsaf", setupTime.String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: setupTime, AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
|
||||
@@ -56,7 +56,7 @@ const (
|
||||
SHARED_GROUPS_NRCOLS = 4
|
||||
ACTIONS_NRCOLS = 12
|
||||
ACTION_PLANS_NRCOLS = 4
|
||||
ACTION_TRIGGERS_NRCOLS = 8
|
||||
ACTION_TRIGGERS_NRCOLS = 9
|
||||
ACCOUNT_ACTIONS_NRCOLS = 5
|
||||
DERIVED_CHARGERS_NRCOLS = 16
|
||||
ROUNDING_UP = "*up"
|
||||
@@ -78,7 +78,7 @@ const (
|
||||
REQTYPE = "reqtype"
|
||||
DIRECTION = "direction"
|
||||
TENANT = "tenant"
|
||||
TOR = "tor"
|
||||
Category = "tor"
|
||||
ACCOUNT = "account"
|
||||
SUBJECT = "subject"
|
||||
DESTINATION = "destination"
|
||||
|
||||
@@ -40,9 +40,7 @@ func MirrorMap(mapIn map[string]string) (map[string]string, error) {
|
||||
func MissingMapKeys(inMap map[string]string, requiredKeys []string) []string {
|
||||
missingKeys := []string{}
|
||||
for _, reqKey := range requiredKeys {
|
||||
if val, hasKey := inMap[reqKey]; !hasKey {
|
||||
missingKeys = append(missingKeys, reqKey)
|
||||
} else if val == "" {
|
||||
if val, hasKey := inMap[reqKey]; !hasKey || val == "" {
|
||||
missingKeys = append(missingKeys, reqKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var PrimaryCdrFields []string = []string{ACCID, CDRHOST, CDRSOURCE, REQTYPE, DIRECTION, TENANT, TOR, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, ANSWER_TIME, DURATION}
|
||||
var PrimaryCdrFields []string = []string{ACCID, CDRHOST, CDRSOURCE, REQTYPE, DIRECTION, TENANT, Category, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, ANSWER_TIME, DURATION}
|
||||
|
||||
// RawCDR is the type containing all the original CDR fields, needs it as it is for later usage
|
||||
type RawCDR interface {
|
||||
@@ -34,7 +34,7 @@ type RawCDR interface {
|
||||
GetSubject() string
|
||||
GetAccount() string
|
||||
GetDestination() string
|
||||
GetTOR() string
|
||||
GetCategory() string
|
||||
GetTenant() string
|
||||
GetReqType() string
|
||||
GetSetupTime() (time.Time, error) // Time when the call was set-up
|
||||
|
||||
@@ -35,7 +35,7 @@ func NewStoredCdrFromRawCDR(rawcdr RawCDR) (*StoredCdr, error) {
|
||||
strCdr.ReqType = rawcdr.GetReqType()
|
||||
strCdr.Direction = rawcdr.GetDirection()
|
||||
strCdr.Tenant = rawcdr.GetTenant()
|
||||
strCdr.TOR = rawcdr.GetTOR()
|
||||
strCdr.Category = rawcdr.GetCategory()
|
||||
strCdr.Account = rawcdr.GetAccount()
|
||||
strCdr.Subject = rawcdr.GetSubject()
|
||||
strCdr.Destination = rawcdr.GetDestination()
|
||||
@@ -62,7 +62,7 @@ type StoredCdr struct {
|
||||
ReqType string
|
||||
Direction string
|
||||
Tenant string
|
||||
TOR string
|
||||
Category string
|
||||
Account string
|
||||
Subject string
|
||||
Destination string
|
||||
@@ -108,8 +108,8 @@ func (storedCdr *StoredCdr) GetDestination() string {
|
||||
return storedCdr.Destination
|
||||
}
|
||||
|
||||
func (storedCdr *StoredCdr) GetTOR() string {
|
||||
return storedCdr.TOR
|
||||
func (storedCdr *StoredCdr) GetCategory() string {
|
||||
return storedCdr.Category
|
||||
}
|
||||
|
||||
func (storedCdr *StoredCdr) GetTenant() string {
|
||||
@@ -154,7 +154,7 @@ func (storedCdr *StoredCdr) AsRawCdrHttpForm() url.Values {
|
||||
v.Set(REQTYPE, storedCdr.ReqType)
|
||||
v.Set(DIRECTION, storedCdr.Direction)
|
||||
v.Set(TENANT, storedCdr.Tenant)
|
||||
v.Set(TOR, storedCdr.TOR)
|
||||
v.Set(Category, storedCdr.Category)
|
||||
v.Set(ACCOUNT, storedCdr.Account)
|
||||
v.Set(SUBJECT, storedCdr.Subject)
|
||||
v.Set(DESTINATION, storedCdr.Destination)
|
||||
@@ -186,8 +186,8 @@ func (storedCdr *StoredCdr) ExportFieldValue(fldName string) string {
|
||||
return storedCdr.Direction
|
||||
case TENANT:
|
||||
return storedCdr.Tenant
|
||||
case TOR:
|
||||
return storedCdr.TOR
|
||||
case Category:
|
||||
return storedCdr.Category
|
||||
case ACCOUNT:
|
||||
return storedCdr.Account
|
||||
case SUBJECT:
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestNewStoredCdrFromRawCDR(t *testing.T) {
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
setupTime, _ := ParseTimeDetectLayout(cgrCdr["setup_time"])
|
||||
expctRtCdr := &StoredCdr{CgrId: Sha1(cgrCdr["accid"], setupTime.String()), AccId: cgrCdr["accid"], CdrHost: cgrCdr["cdrhost"], CdrSource: cgrCdr["cdrsource"], ReqType: cgrCdr["reqtype"],
|
||||
Direction: cgrCdr["direction"], Tenant: cgrCdr["tenant"], TOR: cgrCdr["tor"], Account: cgrCdr["account"], Subject: cgrCdr["subject"],
|
||||
Direction: cgrCdr["direction"], Tenant: cgrCdr["tenant"], Category: cgrCdr["tor"], Account: cgrCdr["account"], Subject: cgrCdr["subject"],
|
||||
Destination: cgrCdr["destination"], SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(10) * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: DEFAULT_RUNID, Cost: -1}
|
||||
if rt, err := NewStoredCdrFromRawCDR(cgrCdr); err != nil {
|
||||
@@ -47,7 +47,7 @@ func TestNewStoredCdrFromRawCDR(t *testing.T) {
|
||||
|
||||
func TestStoredCdrFields(t *testing.T) {
|
||||
ratedCdr := StoredCdr{CgrId: Sha1("dsafdsaf", time.Unix(1383813746, 0).String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813746, 0), AnswerTime: time.Unix(1383813746, 0), Duration: 10,
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813746, 0), AnswerTime: time.Unix(1383813746, 0), Duration: 10,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
}
|
||||
if ratedCdr.GetCgrId() != Sha1("dsafdsaf", time.Unix(1383813746, 0).String()) {
|
||||
@@ -71,7 +71,7 @@ func TestStoredCdrFields(t *testing.T) {
|
||||
if ratedCdr.GetDestination() != "1002" {
|
||||
t.Error("Error parsing cdr: ", ratedCdr)
|
||||
}
|
||||
if ratedCdr.GetTOR() != "call" {
|
||||
if ratedCdr.GetCategory() != "call" {
|
||||
t.Error("Error parsing cdr: ", ratedCdr)
|
||||
}
|
||||
if ratedCdr.GetTenant() != "cgrates.org" {
|
||||
@@ -108,7 +108,7 @@ func TestStoredCdrFields(t *testing.T) {
|
||||
|
||||
func TestAsRawCdrHttpForm(t *testing.T) {
|
||||
ratedCdr := StoredCdr{CgrId: Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
}
|
||||
cdrForm := ratedCdr.AsRawCdrHttpForm()
|
||||
@@ -130,8 +130,8 @@ func TestAsRawCdrHttpForm(t *testing.T) {
|
||||
if cdrForm.Get(TENANT) != ratedCdr.Tenant {
|
||||
t.Errorf("Expected: %s, received: %s", ratedCdr.Tenant, cdrForm.Get(TENANT))
|
||||
}
|
||||
if cdrForm.Get(TOR) != ratedCdr.TOR {
|
||||
t.Errorf("Expected: %s, received: %s", ratedCdr.TOR, cdrForm.Get(TOR))
|
||||
if cdrForm.Get(Category) != ratedCdr.Category {
|
||||
t.Errorf("Expected: %s, received: %s", ratedCdr.Category, cdrForm.Get(Category))
|
||||
}
|
||||
if cdrForm.Get(ACCOUNT) != ratedCdr.Account {
|
||||
t.Errorf("Expected: %s, received: %s", ratedCdr.Account, cdrForm.Get(ACCOUNT))
|
||||
@@ -161,7 +161,7 @@ func TestAsRawCdrHttpForm(t *testing.T) {
|
||||
|
||||
func TestExportFieldValue(t *testing.T) {
|
||||
cdr := StoredCdr{CgrId: Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: DEFAULT_RUNID,
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: DEFAULT_RUNID,
|
||||
Duration: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
}
|
||||
if cdr.ExportFieldValue(CGRID) != cdr.CgrId ||
|
||||
@@ -172,7 +172,7 @@ func TestExportFieldValue(t *testing.T) {
|
||||
cdr.ExportFieldValue(REQTYPE) != cdr.ReqType ||
|
||||
cdr.ExportFieldValue(DIRECTION) != cdr.Direction ||
|
||||
cdr.ExportFieldValue(TENANT) != cdr.Tenant ||
|
||||
cdr.ExportFieldValue(TOR) != cdr.TOR ||
|
||||
cdr.ExportFieldValue(Category) != cdr.Category ||
|
||||
cdr.ExportFieldValue(ACCOUNT) != cdr.Account ||
|
||||
cdr.ExportFieldValue(SUBJECT) != cdr.Subject ||
|
||||
cdr.ExportFieldValue(DESTINATION) != cdr.Destination ||
|
||||
|
||||
Reference in New Issue
Block a user