mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
Merge branch 'master' into shared_balances
Conflicts: engine/balances.go utils/consts.go
This commit is contained in:
@@ -138,56 +138,50 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *UserBalance, moneyB
|
||||
if increment.paid {
|
||||
continue
|
||||
}
|
||||
if b.RateSubject == ZEROSECOND || b.RateSubject == "" {
|
||||
amount := increment.Duration.Seconds()
|
||||
if b.Value >= amount {
|
||||
b.Value -= amount
|
||||
increment.BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
increment.MinuteInfo = &MinuteInfo{cc.Destination, amount}
|
||||
increment.Cost = 0
|
||||
increment.paid = true
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
|
||||
}
|
||||
if duration, err := utils.ParseZeroRatingSubject(b.RateSubject); err == nil {
|
||||
seconds := duration.Seconds()
|
||||
amount := seconds
|
||||
if seconds == 1 {
|
||||
amount = increment.Duration.Seconds()
|
||||
}
|
||||
continue
|
||||
}
|
||||
if b.RateSubject == ZEROMINUTE {
|
||||
amount := time.Minute.Seconds()
|
||||
if b.Value >= amount { // balance has at least 60 seconds
|
||||
newTs := ts
|
||||
if incrementIndex != 0 {
|
||||
// if increment it's not at the begining we must split the timespan
|
||||
newTs = ts.SplitByIncrement(incrementIndex)
|
||||
}
|
||||
newTs.RoundToDuration(time.Minute)
|
||||
newTs.RateInterval = &RateInterval{
|
||||
Rating: &RIRate{
|
||||
Rates: RateGroups{
|
||||
&Rate{
|
||||
GroupIntervalStart: 0,
|
||||
Value: 0,
|
||||
RateIncrement: time.Minute,
|
||||
RateUnit: time.Minute,
|
||||
inc := increment
|
||||
if seconds > 1 { // we need to recreate increments
|
||||
if incrementIndex != 0 {
|
||||
// if increment it's not at the begining we must split the timespan
|
||||
newTs = ts.SplitByIncrement(incrementIndex)
|
||||
}
|
||||
newTs.RoundToDuration(time.Minute)
|
||||
newTs.RateInterval = &RateInterval{
|
||||
Rating: &RIRate{
|
||||
Rates: RateGroups{
|
||||
&Rate{
|
||||
GroupIntervalStart: 0,
|
||||
Value: 0,
|
||||
RateIncrement: time.Minute,
|
||||
RateUnit: time.Minute,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
newTs.createIncrementsSlice()
|
||||
// insert the new timespan
|
||||
if newTs != ts {
|
||||
tsIndex++
|
||||
cc.Timespans = append(cc.Timespans, nil)
|
||||
copy(cc.Timespans[tsIndex+1:], cc.Timespans[tsIndex:])
|
||||
cc.Timespans[tsIndex] = newTs
|
||||
tsWasSplit = true
|
||||
}
|
||||
cc.Timespans.RemoveOverlapedFromIndex(tsIndex)
|
||||
inc = newTs.Increments[0]
|
||||
}
|
||||
newTs.createIncrementsSlice()
|
||||
// insert the new timespan
|
||||
if newTs != ts {
|
||||
tsIndex++
|
||||
cc.Timespans = append(cc.Timespans, nil)
|
||||
copy(cc.Timespans[tsIndex+1:], cc.Timespans[tsIndex:])
|
||||
cc.Timespans[tsIndex] = newTs
|
||||
tsWasSplit = true
|
||||
}
|
||||
cc.Timespans.RemoveOverlapedFromIndex(tsIndex)
|
||||
b.Value -= amount
|
||||
newTs.Increments[0].BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
newTs.Increments[0].MinuteInfo = &MinuteInfo{cc.Destination, amount}
|
||||
newTs.Increments[0].Cost = 0
|
||||
newTs.Increments[0].paid = true
|
||||
inc.BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
inc.MinuteInfo = &MinuteInfo{cc.Destination, amount}
|
||||
inc.Cost = 0
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package engine
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/syslog"
|
||||
"time"
|
||||
//"encoding/json"
|
||||
@@ -420,7 +421,6 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
|
||||
/*
|
||||
Returns the approximate max allowed session for user balance. It will try the max amount received in the call descriptor
|
||||
and will decrease it by 10% for nine times. So if the user has little credit it will still allow 10% of the initial amount.
|
||||
If the user has no credit then it will return 0.
|
||||
If the user has postpayed plan it returns -1.
|
||||
*/
|
||||
@@ -449,15 +449,15 @@ func (origCd *CallDescriptor) GetMaxSessionDuration() (time.Duration, error) {
|
||||
return 0, err
|
||||
}
|
||||
//Logger.Debug(fmt.Sprintf("availableDuration: %v, availableCredit: %v", availableDuration, availableCredit))
|
||||
// check for zero balance
|
||||
if availableCredit == 0 {
|
||||
return availableDuration, nil
|
||||
}
|
||||
initialDuration := cd.TimeEnd.Sub(cd.TimeStart)
|
||||
if initialDuration <= availableDuration {
|
||||
// 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
|
||||
@@ -482,7 +482,11 @@ func (origCd *CallDescriptor) GetMaxSessionDuration() (time.Duration, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableDuration, nil
|
||||
log.Print(initialDuration, availableDuration, initialDuration < availableDuration)
|
||||
if initialDuration < availableDuration {
|
||||
return initialDuration, nil
|
||||
}
|
||||
return utils.MinDuration(initialDuration, availableDuration), nil
|
||||
}
|
||||
|
||||
// Interface method used to add/substract an amount of cents or bonus seconds (as returned by GetCost method)
|
||||
|
||||
@@ -296,7 +296,7 @@ func TestMaxSessionTimeWithUserBalance(t *testing.T) {
|
||||
Destination: "0723",
|
||||
Amount: 1000}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
expected := 300 * time.Second
|
||||
expected := time.Minute
|
||||
if result != expected || err != nil {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
}
|
||||
@@ -314,7 +314,7 @@ func TestMaxSessionTimeWithUserBalanceAccount(t *testing.T) {
|
||||
Destination: "0723",
|
||||
Amount: 1000}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
expected := 300 * time.Second
|
||||
expected := time.Minute
|
||||
if result != expected || err != nil {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
}
|
||||
@@ -331,8 +331,8 @@ func TestMaxSessionTimeNoCredit(t *testing.T) {
|
||||
Destination: "0723",
|
||||
Amount: 5400}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
if result != 100*time.Second || err != nil {
|
||||
t.Errorf("Expected %v was %v", 100, result)
|
||||
if result != time.Minute || err != nil {
|
||||
t.Errorf("Expected %v was %v", time.Minute, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +343,8 @@ func TestMaxSessionModifiesCallDesc(t *testing.T) {
|
||||
Direction: "*out",
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "broker",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 5400}
|
||||
initial := cd.Clone()
|
||||
@@ -353,6 +354,46 @@ func TestMaxSessionModifiesCallDesc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxDebitDurationNoGreatherThanInitialDuration(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",
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 1000}
|
||||
initialDuration := cd.TimeEnd.Sub(cd.TimeStart)
|
||||
result, _ := cd.GetMaxSessionDuration()
|
||||
if result > initialDuration {
|
||||
t.Error("max session duration greather than initial duration", initialDuration, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitAndMaxDebit(t *testing.T) {
|
||||
cd1 := &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",
|
||||
TOR: "0",
|
||||
Tenant: "vdf",
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 5400}
|
||||
cd2 := cd1.Clone()
|
||||
cc1, err1 := cd1.Debit()
|
||||
cc2, err2 := cd2.MaxDebit()
|
||||
if err1 != nil || err2 != nil {
|
||||
t.Error("Error debiting and/or maxdebiting: ", err1, err2)
|
||||
}
|
||||
if !reflect.DeepEqual(cc1, cc2) {
|
||||
t.Errorf("Debit and MaxDebit differ: %+v != %+v", cc1, cc2)
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************** BENCHMARKS ***************************************/
|
||||
func BenchmarkStorageGetting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
@@ -49,9 +49,6 @@ const (
|
||||
TRIGGER_MAX_COUNTER = "*max_counter"
|
||||
TRIGGER_MIN_BALANCE = "*min_balance"
|
||||
TRIGGER_MAX_BALANCE = "*max_balance"
|
||||
// minute subjects
|
||||
ZEROSECOND = "*zerosecond"
|
||||
ZEROMINUTE = "*zerominute"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestDebitNegativeMoneyBalance(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditZeroSecond(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: ZEROSECOND}
|
||||
b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1s"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -243,7 +243,7 @@ func TestDebitCreditZeroSecond(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditZeroMinute(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -276,8 +276,8 @@ func TestDebitCreditZeroMinute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
func TestDebitCreditZeroMixedMinute(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testm", Value: 70, Weight: 5, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b2 := &Balance{Uuid: "tests", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: ZEROSECOND}
|
||||
b1 := &Balance{Uuid: "testm", Value: 70, Weight: 5, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
b2 := &Balance{Uuid: "tests", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1s"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -311,7 +311,7 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditNoCredit(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -351,7 +351,7 @@ func TestDebitCreditNoCredit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditHasCredit(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -393,7 +393,7 @@ func TestDebitCreditHasCredit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditSplitMinutesMoney(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: ZEROSECOND}
|
||||
b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1s"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -430,7 +430,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditMoreTimespans(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 150, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b1 := &Balance{Uuid: "testb", Value: 150, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -467,8 +467,8 @@ func TestDebitCreditMoreTimespans(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditMoreTimespansMixed(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b2 := &Balance{Uuid: "testa", Value: 150, Weight: 5, DestinationId: "NAT", RateSubject: ZEROSECOND}
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
b2 := &Balance{Uuid: "testa", Value: 150, Weight: 5, DestinationId: "NAT", RateSubject: "*zero1s"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
@@ -506,7 +506,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDebitCreditNoConectFeeCredit(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: ZEROMINUTE}
|
||||
b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1m"}
|
||||
cc := &CallCost{
|
||||
Direction: OUTBOUND,
|
||||
Destination: "0723045326",
|
||||
|
||||
167
utils/consts.go
167
utils/consts.go
@@ -1,89 +1,90 @@
|
||||
package utils
|
||||
|
||||
const (
|
||||
VERSION = "0.9.1c4"
|
||||
POSTGRES = "postgres"
|
||||
MYSQL = "mysql"
|
||||
MONGO = "mongo"
|
||||
REDIS = "redis"
|
||||
LOCALHOST = "127.0.0.1"
|
||||
FSCDR_FILE_CSV = "freeswitch_file_csv"
|
||||
FSCDR_HTTP_JSON = "freeswitch_http_json"
|
||||
NOT_IMPLEMENTED = "not implemented"
|
||||
PREPAID = "prepaid"
|
||||
POSTPAID = "postpaid"
|
||||
PSEUDOPREPAID = "pseudoprepaid"
|
||||
RATED = "rated"
|
||||
ERR_NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
|
||||
ERR_SERVER_ERROR = "SERVER_ERROR"
|
||||
ERR_NOT_FOUND = "NOT_FOUND"
|
||||
ERR_MANDATORY_IE_MISSING = "MANDATORY_IE_MISSING"
|
||||
ERR_EXISTS = "EXISTS"
|
||||
ERR_BROKEN_REFERENCE = "BROKEN_REFERENCE"
|
||||
TBL_TP_TIMINGS = "tp_timings"
|
||||
TBL_TP_DESTINATIONS = "tp_destinations"
|
||||
TBL_TP_RATES = "tp_rates"
|
||||
TBL_TP_DESTINATION_RATES = "tp_destination_rates"
|
||||
TBL_TP_RATING_PLANS = "tp_rating_plans"
|
||||
TBL_TP_RATE_PROFILES = "tp_rating_profiles"
|
||||
TBL_TP_ACTIONS = "tp_actions"
|
||||
TBL_TP_ACTION_PLANS = "tp_action_plans"
|
||||
TBL_TP_ACTION_TRIGGERS = "tp_action_triggers"
|
||||
TBL_TP_ACCOUNT_ACTIONS = "tp_account_actions"
|
||||
TBL_CDRS_PRIMARY = "cdrs_primary"
|
||||
TBL_CDRS_EXTRA = "cdrs_extra"
|
||||
TBL_COST_DETAILS = "cost_details"
|
||||
TBL_RATED_CDRS = "rated_cdrs"
|
||||
TIMINGS_CSV = "Timings.csv"
|
||||
DESTINATIONS_CSV = "Destinations.csv"
|
||||
RATES_CSV = "Rates.csv"
|
||||
DESTINATION_RATES_CSV = "DestinationRates.csv"
|
||||
RATING_PLANS_CSV = "RatingPlans.csv"
|
||||
RATING_PROFILES_CSV = "RatingProfiles.csv"
|
||||
SHARED_GROUPS_CSV = "SharedGroups.csv"
|
||||
ACTIONS_CSV = "Actions.csv"
|
||||
ACTION_PLANS_CSV = "ActionPlans.csv"
|
||||
ACTION_TRIGGERS_CSV = "ActionTriggers.csv"
|
||||
ACCOUNT_ACTIONS_CSV = "AccountActions.csv"
|
||||
TIMINGS_NRCOLS = 6
|
||||
DESTINATIONS_NRCOLS = 2
|
||||
RATES_NRCOLS = 8
|
||||
DESTINATION_RATES_NRCOLS = 3
|
||||
DESTRATE_TIMINGS_NRCOLS = 4
|
||||
RATE_PROFILES_NRCOLS = 7
|
||||
SHARED_GROUPS_NRCOLS = 5
|
||||
ACTIONS_NRCOLS = 12
|
||||
ACTION_PLANS_NRCOLS = 4
|
||||
ACTION_TRIGGERS_NRCOLS = 8
|
||||
ACCOUNT_ACTIONS_NRCOLS = 5
|
||||
ROUNDING_UP = "*up"
|
||||
ROUNDING_MIDDLE = "*middle"
|
||||
ROUNDING_DOWN = "*down"
|
||||
ANY = "*any"
|
||||
COMMENT_CHAR = '#'
|
||||
CSV_SEP = ','
|
||||
FALLBACK_SEP = ';'
|
||||
JSON = "json"
|
||||
MSGPACK = "msgpack"
|
||||
CSV_LOAD = "CSVLOAD"
|
||||
CGRID = "cgrid"
|
||||
ACCID = "accid"
|
||||
CDRHOST = "cdrhost"
|
||||
CDRSOURCE = "cdrsource"
|
||||
REQTYPE = "reqtype"
|
||||
DIRECTION = "direction"
|
||||
TENANT = "tenant"
|
||||
TOR = "tor"
|
||||
ACCOUNT = "account"
|
||||
SUBJECT = "subject"
|
||||
DESTINATION = "destination"
|
||||
ANSWER_TIME = "answer_time"
|
||||
DURATION = "duration"
|
||||
DEFAULT_RUNID = "default"
|
||||
STATIC_VALUE_PREFIX = "^"
|
||||
CDRE_CSV = "csv"
|
||||
CDRE_DRYRUN = "dry_run"
|
||||
INTERNAL = "internal"
|
||||
VERSION = "0.9.1c4"
|
||||
POSTGRES = "postgres"
|
||||
MYSQL = "mysql"
|
||||
MONGO = "mongo"
|
||||
REDIS = "redis"
|
||||
LOCALHOST = "127.0.0.1"
|
||||
FSCDR_FILE_CSV = "freeswitch_file_csv"
|
||||
FSCDR_HTTP_JSON = "freeswitch_http_json"
|
||||
NOT_IMPLEMENTED = "not implemented"
|
||||
PREPAID = "prepaid"
|
||||
POSTPAID = "postpaid"
|
||||
PSEUDOPREPAID = "pseudoprepaid"
|
||||
RATED = "rated"
|
||||
ERR_NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
|
||||
ERR_SERVER_ERROR = "SERVER_ERROR"
|
||||
ERR_NOT_FOUND = "NOT_FOUND"
|
||||
ERR_MANDATORY_IE_MISSING = "MANDATORY_IE_MISSING"
|
||||
ERR_EXISTS = "EXISTS"
|
||||
ERR_BROKEN_REFERENCE = "BROKEN_REFERENCE"
|
||||
TBL_TP_TIMINGS = "tp_timings"
|
||||
TBL_TP_DESTINATIONS = "tp_destinations"
|
||||
TBL_TP_RATES = "tp_rates"
|
||||
TBL_TP_DESTINATION_RATES = "tp_destination_rates"
|
||||
TBL_TP_RATING_PLANS = "tp_rating_plans"
|
||||
TBL_TP_RATE_PROFILES = "tp_rating_profiles"
|
||||
TBL_TP_ACTIONS = "tp_actions"
|
||||
TBL_TP_ACTION_PLANS = "tp_action_plans"
|
||||
TBL_TP_ACTION_TRIGGERS = "tp_action_triggers"
|
||||
TBL_TP_ACCOUNT_ACTIONS = "tp_account_actions"
|
||||
TBL_CDRS_PRIMARY = "cdrs_primary"
|
||||
TBL_CDRS_EXTRA = "cdrs_extra"
|
||||
TBL_COST_DETAILS = "cost_details"
|
||||
TBL_RATED_CDRS = "rated_cdrs"
|
||||
TIMINGS_CSV = "Timings.csv"
|
||||
DESTINATIONS_CSV = "Destinations.csv"
|
||||
RATES_CSV = "Rates.csv"
|
||||
DESTINATION_RATES_CSV = "DestinationRates.csv"
|
||||
RATING_PLANS_CSV = "RatingPlans.csv"
|
||||
RATING_PROFILES_CSV = "RatingProfiles.csv"
|
||||
SHARED_GROUPS_CSV = "SharedGroups.csv"
|
||||
ACTIONS_CSV = "Actions.csv"
|
||||
ACTION_PLANS_CSV = "ActionPlans.csv"
|
||||
ACTION_TRIGGERS_CSV = "ActionTriggers.csv"
|
||||
ACCOUNT_ACTIONS_CSV = "AccountActions.csv"
|
||||
TIMINGS_NRCOLS = 6
|
||||
DESTINATIONS_NRCOLS = 2
|
||||
RATES_NRCOLS = 8
|
||||
DESTINATION_RATES_NRCOLS = 3
|
||||
DESTRATE_TIMINGS_NRCOLS = 4
|
||||
RATE_PROFILES_NRCOLS = 7
|
||||
SHARED_GROUPS_NRCOLS = 5
|
||||
ACTIONS_NRCOLS = 12
|
||||
ACTION_PLANS_NRCOLS = 4
|
||||
ACTION_TRIGGERS_NRCOLS = 8
|
||||
ACCOUNT_ACTIONS_NRCOLS = 5
|
||||
ROUNDING_UP = "*up"
|
||||
ROUNDING_MIDDLE = "*middle"
|
||||
ROUNDING_DOWN = "*down"
|
||||
ANY = "*any"
|
||||
COMMENT_CHAR = '#'
|
||||
CSV_SEP = ','
|
||||
FALLBACK_SEP = ';'
|
||||
JSON = "json"
|
||||
MSGPACK = "msgpack"
|
||||
CSV_LOAD = "CSVLOAD"
|
||||
CGRID = "cgrid"
|
||||
ACCID = "accid"
|
||||
CDRHOST = "cdrhost"
|
||||
CDRSOURCE = "cdrsource"
|
||||
REQTYPE = "reqtype"
|
||||
DIRECTION = "direction"
|
||||
TENANT = "tenant"
|
||||
TOR = "tor"
|
||||
ACCOUNT = "account"
|
||||
SUBJECT = "subject"
|
||||
DESTINATION = "destination"
|
||||
ANSWER_TIME = "answer_time"
|
||||
DURATION = "duration"
|
||||
DEFAULT_RUNID = "default"
|
||||
STATIC_VALUE_PREFIX = "^"
|
||||
CDRE_CSV = "csv"
|
||||
CDRE_DRYRUN = "dry_run"
|
||||
INTERNAL = "internal"
|
||||
ZERO_RATING_SUBJECT_PREFIX = "*zero"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -187,3 +187,22 @@ func ParseDurationWithSecs(durStr string) (time.Duration, error) {
|
||||
func BalanceKey(tenant, account, direction string) string {
|
||||
return fmt.Sprintf("%s:%s:%s", direction, tenant, account)
|
||||
}
|
||||
|
||||
// returns the minimum duration between the two
|
||||
func MinDuration(d1, d2 time.Duration) time.Duration {
|
||||
if d1 < d2 {
|
||||
return d1
|
||||
}
|
||||
return d2
|
||||
}
|
||||
|
||||
func ParseZeroRatingSubject(rateSubj string) (time.Duration, error) {
|
||||
if rateSubj == "" {
|
||||
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s"
|
||||
}
|
||||
if !strings.HasPrefix(rateSubj, ZERO_RATING_SUBJECT_PREFIX) {
|
||||
return 0, errors.New("malformed rating subject: " + rateSubj)
|
||||
}
|
||||
durStr := rateSubj[len(ZERO_RATING_SUBJECT_PREFIX):]
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
@@ -336,3 +336,23 @@ func TestParseDurationWithSecs(t *testing.T) {
|
||||
t.Error("Parsed different than expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinDuration(t *testing.T) {
|
||||
d1, _ := time.ParseDuration("1m")
|
||||
d2, _ := time.ParseDuration("59s")
|
||||
minD1 := MinDuration(d1, d2)
|
||||
minD2 := MinDuration(d2, d1)
|
||||
if minD1 != d2 || minD2 != d2 {
|
||||
t.Error("Error getting min duration: ", minD1, minD2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseZeroRatingSubject(t *testing.T) {
|
||||
subj := []string{"", "*zero1s", "*zero5m", "*zero10h"}
|
||||
dur := []time.Duration{time.Second, time.Second, 5 * time.Minute, 10 * time.Hour}
|
||||
for i, s := range subj {
|
||||
if d, err := ParseZeroRatingSubject(s); err != nil || d != dur[i] {
|
||||
t.Error("Error parsing rating subject: ", s, d, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user