mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Updated balance debit
This commit is contained in:
committed by
Dan Christian Bogos
parent
fb48016c51
commit
c182ca65f5
@@ -392,8 +392,8 @@ func (acc *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bo
|
||||
// try every balance multiple times in case one becomes active or ratig changes
|
||||
unitBalanceChecker = false
|
||||
for _, balance := range usefulUnitBalances {
|
||||
partCC, debitErr := balance.debitUnits(cd, balance.account,
|
||||
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0)
|
||||
partCC, debitErr := balance.debit(cd, balance.account,
|
||||
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0, true)
|
||||
if debitErr != nil {
|
||||
return nil, debitErr
|
||||
}
|
||||
@@ -429,8 +429,8 @@ func (acc *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bo
|
||||
// try every balance multiple times in case one becomes active or ratig changes
|
||||
moneyBalanceChecker = false
|
||||
for _, balance := range usefulMoneyBalances {
|
||||
partCC, debitErr := balance.debitMoney(cd, balance.account,
|
||||
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0)
|
||||
partCC, debitErr := balance.debit(cd, balance.account,
|
||||
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0,false)
|
||||
if debitErr != nil {
|
||||
return nil, debitErr
|
||||
}
|
||||
@@ -533,7 +533,6 @@ func (acc *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bo
|
||||
Value: defaultBalance.Value,
|
||||
}
|
||||
increment.BalanceInfo.AccountID = acc.ID
|
||||
increment.paid = true
|
||||
if count {
|
||||
acc.countUnits(
|
||||
cost,
|
||||
@@ -859,39 +858,39 @@ func (acc *Account) Clone() *Account {
|
||||
}
|
||||
|
||||
// DebitConnectionFee debits the connection fee
|
||||
func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balances, count bool, block bool) (bool, Balance) {
|
||||
func (acc *Account) DebitConnectionFee(cc *CallCost, ufMoneyBalances Balances, count bool, block bool) (bool, Balance) {
|
||||
var debitedBalance Balance
|
||||
|
||||
if cc.deductConnectFee {
|
||||
connectFee := cc.GetConnectFee()
|
||||
//log.Print("CONNECT FEE: %f", connectFee)
|
||||
connectFeePaid := false
|
||||
for _, b := range usefulMoneyBalances {
|
||||
if b.GetValue() >= connectFee {
|
||||
b.SubstractValue(connectFee)
|
||||
// the conect fee is not refundable!
|
||||
if count {
|
||||
acc.countUnits(connectFee, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
connectFeePaid = true
|
||||
debitedBalance = *b
|
||||
break
|
||||
}
|
||||
if b.Blocker && block { // stop here
|
||||
return false, debitedBalance
|
||||
}
|
||||
}
|
||||
// debit connect fee
|
||||
if connectFee > 0 && !connectFeePaid {
|
||||
cc.negativeConnectFee = true
|
||||
// there are no money for the connect fee; go negative
|
||||
b := acc.GetDefaultMoneyBalance()
|
||||
if !cc.deductConnectFee {
|
||||
return true, debitedBalance
|
||||
}
|
||||
connectFee := cc.GetConnectFee()
|
||||
//log.Print("CONNECT FEE: %f", connectFee)
|
||||
var connectFeePaid bool
|
||||
for _, b := range ufMoneyBalances {
|
||||
if b.GetValue() >= connectFee {
|
||||
b.SubstractValue(connectFee)
|
||||
debitedBalance = *b
|
||||
// the conect fee is not refundable!
|
||||
if count {
|
||||
acc.countUnits(connectFee, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
connectFeePaid = true
|
||||
debitedBalance = *b
|
||||
break
|
||||
}
|
||||
if b.Blocker && block { // stop here
|
||||
return false, debitedBalance
|
||||
}
|
||||
}
|
||||
// debit connect fee
|
||||
if connectFee > 0 && !connectFeePaid {
|
||||
cc.negativeConnectFee = true
|
||||
// there are no money for the connect fee; go negative
|
||||
b := acc.GetDefaultMoneyBalance()
|
||||
b.SubstractValue(connectFee)
|
||||
debitedBalance = *b
|
||||
// the conect fee is not refundable!
|
||||
if count {
|
||||
acc.countUnits(connectFee, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
}
|
||||
return true, debitedBalance
|
||||
|
||||
@@ -533,7 +533,7 @@ func TestDebitCreditHasCredit(t *testing.T) {
|
||||
}
|
||||
rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{
|
||||
utils.MetaVoice: {b1},
|
||||
utils.MetaMonetary: {&Balance{Uuid: "moneya", Value: 110}},
|
||||
utils.MetaMonetary: {{Uuid: "moneya", Value: 110}},
|
||||
}}
|
||||
var err error
|
||||
cc, err = rifsBalance.debitCreditBalance(cd, false, false, true)
|
||||
|
||||
@@ -267,11 +267,10 @@ func (b *Balance) GetCost(cd *CallDescriptor, getStandardIfEmpty bool) (*CallCos
|
||||
if getStandardIfEmpty {
|
||||
cd.RatingInfos = nil
|
||||
return cd.getCost()
|
||||
} else {
|
||||
cc := cd.CreateCallCost()
|
||||
cc.Cost = 0
|
||||
return cc, nil
|
||||
}
|
||||
cc := cd.CreateCallCost()
|
||||
cc.Cost = 0
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func (b *Balance) GetValue() float64 {
|
||||
@@ -302,7 +301,7 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 {
|
||||
return
|
||||
}
|
||||
if duration, err := utils.ParseZeroRatingSubject(cd.ToR, b.RatingSubject, config.CgrConfig().RalsCfg().BalanceRatingSubject); err == nil {
|
||||
if duration, err := utils.ParseZeroRatingSubject(cd.ToR, b.RatingSubject, config.CgrConfig().RalsCfg().BalanceRatingSubject, true); err == nil {
|
||||
// we have *zero based units
|
||||
cc = cd.CreateCallCost()
|
||||
cc.Timespans = append(cc.Timespans, &TimeSpan{
|
||||
@@ -359,12 +358,10 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
inc.Cost = 0
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(amount, cc.ToR, cc, b)
|
||||
}
|
||||
} else {
|
||||
inc.paid = false
|
||||
// delete the rest of the unpiad increments/timespans
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
@@ -438,7 +435,6 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
amount = utils.Round(amount/b.Factor.GetValue(cd.ToR), globalRoundingDecimals, utils.MetaRoundingUp)
|
||||
}
|
||||
cost := inc.Cost
|
||||
inc.paid = false
|
||||
if strategy == utils.MetaMaxCostDisconnect && cd.MaxCostSoFar >= maxCost {
|
||||
// cut the entire current timespan
|
||||
cc.maxCostDisconect = true
|
||||
@@ -462,7 +458,6 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
RateInterval: ts.RateInterval,
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(cost, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
@@ -501,7 +496,6 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
}
|
||||
cd.MaxCostSoFar += cost
|
||||
}
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(amount, cc.ToR, cc, b)
|
||||
if cost != 0 {
|
||||
@@ -509,7 +503,6 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inc.paid = false
|
||||
// delete the rest of the unpaid increments/timespans
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
@@ -544,7 +537,6 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
var ok bool
|
||||
//log.Print("cc: " + utils.ToJSON(cc))
|
||||
if debitConnectFee {
|
||||
|
||||
// this is the first add, debit the connect fee
|
||||
if ok, debitedConnectFeeBalance = ub.DebitConnectionFee(cc, moneyBalances, count, true); !ok {
|
||||
// balance is blocker
|
||||
@@ -567,7 +559,11 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
return nil, errors.New("timespan with no rate interval assigned")
|
||||
}
|
||||
|
||||
if tsIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && debitConnectFee && cc.deductConnectFee && ok {
|
||||
if tsIndex == 0 &&
|
||||
ts.RateInterval.Rating.ConnectFee > 0 &&
|
||||
debitConnectFee &&
|
||||
cc.deductConnectFee &&
|
||||
ok {
|
||||
|
||||
inc := &Increment{
|
||||
Duration: 0,
|
||||
@@ -593,13 +589,16 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
// check standard subject tags
|
||||
//log.Printf("INC: %+v", inc)
|
||||
|
||||
if tsIndex == 0 && incIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && cc.deductConnectFee && ok {
|
||||
if tsIndex == 0 &&
|
||||
incIndex == 0 &&
|
||||
ts.RateInterval.Rating.ConnectFee > 0 &&
|
||||
cc.deductConnectFee &&
|
||||
ok {
|
||||
// go to nextincrement
|
||||
continue
|
||||
}
|
||||
|
||||
amount := inc.Cost
|
||||
inc.paid = false
|
||||
if strategy == utils.MetaMaxCostDisconnect && cd.MaxCostSoFar >= maxCost {
|
||||
// cut the entire current timespan
|
||||
cc.maxCostDisconect = true
|
||||
@@ -625,7 +624,6 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
if b.RatingSubject != "" {
|
||||
inc.BalanceInfo.Monetary.RateInterval = ts.RateInterval
|
||||
}
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(amount, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
@@ -647,12 +645,10 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala
|
||||
if b.RatingSubject != "" {
|
||||
inc.BalanceInfo.Monetary.RateInterval = ts.RateInterval
|
||||
}
|
||||
inc.paid = true
|
||||
if count {
|
||||
ub.countUnits(amount, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
} else {
|
||||
inc.paid = false
|
||||
// delete the rest of the unpiad increments/timespans
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
@@ -826,3 +822,278 @@ func (bl *BalanceSummary) FieldAsInterface(fldPath []string) (val interface{}, e
|
||||
return bl.Initial, nil
|
||||
}
|
||||
}
|
||||
|
||||
// debitUnits will debit units for call descriptor.
|
||||
// returns the amount debited within cc
|
||||
func (b *Balance) debit(cd *CallDescriptor, ub *Account, moneyBalances Balances,
|
||||
count, dryRun, debitConnectFee, isUnitBal bool) (cc *CallCost, err error) {
|
||||
if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 {
|
||||
return
|
||||
}
|
||||
tor := cd.ToR
|
||||
if !isUnitBal {
|
||||
tor = utils.MetaMonetary
|
||||
}
|
||||
if duration, err_ := utils.ParseZeroRatingSubject(tor, b.RatingSubject,
|
||||
config.CgrConfig().RalsCfg().BalanceRatingSubject, isUnitBal); err_ == nil {
|
||||
// we have *zero based units
|
||||
cc = cd.CreateCallCost()
|
||||
ts := &TimeSpan{
|
||||
TimeStart: cd.TimeStart,
|
||||
TimeEnd: cd.TimeEnd,
|
||||
}
|
||||
cc.Timespans = TimeSpans{ts}
|
||||
ts.RoundToDuration(duration)
|
||||
ts.RateInterval = &RateInterval{
|
||||
Rating: &RIRate{
|
||||
Rates: RateGroups{
|
||||
&RGRate{
|
||||
GroupIntervalStart: 0,
|
||||
Value: 0,
|
||||
RateIncrement: duration,
|
||||
RateUnit: duration,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
prefix, destid := b.getMatchingPrefixAndDestID(cd.Destination)
|
||||
if prefix == utils.EmptyString {
|
||||
prefix = cd.Destination
|
||||
}
|
||||
if destid == utils.EmptyString {
|
||||
destid = utils.MetaAny
|
||||
}
|
||||
ts.setRatingInfo(&RatingInfo{
|
||||
MatchedSubject: b.Uuid,
|
||||
MatchedPrefix: prefix,
|
||||
MatchedDestId: destid,
|
||||
RatingPlanId: utils.MetaNone,
|
||||
})
|
||||
ts.createIncrementsSlice()
|
||||
//log.Printf("CC: %+v", ts)
|
||||
for incIndex, inc := range ts.Increments {
|
||||
//log.Printf("INCREMENET: %+v", inc)
|
||||
amount := float64(inc.Duration)
|
||||
if b.Factor != nil {
|
||||
amount = utils.Round(amount/b.Factor.GetValue(tor),
|
||||
globalRoundingDecimals, utils.MetaRoundingUp)
|
||||
}
|
||||
if b.GetValue() >= amount {
|
||||
b.SubstractValue(amount)
|
||||
inc.BalanceInfo.Unit = &UnitInfo{
|
||||
UUID: b.Uuid,
|
||||
ID: b.ID,
|
||||
Value: b.Value,
|
||||
DestinationID: cc.Destination,
|
||||
Consumed: amount,
|
||||
ToR: tor, //aici
|
||||
RateInterval: nil,
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
inc.Cost = 0
|
||||
if count {
|
||||
ub.countUnits(amount, tor, cc, b)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// delete the rest of the unpiad increments/timespans
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
return nil, nil
|
||||
}
|
||||
ts.SplitByIncrement(incIndex)
|
||||
if len(cc.Timespans) == 0 {
|
||||
cc = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
// no rating subject
|
||||
//log.Print("B: ", utils.ToJSON(b))
|
||||
//log.Printf("}}}}}}} %+v", cd.testCallcost)
|
||||
cc, err = b.GetCost(cd, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var debitedConnectFeeBalance Balance
|
||||
var connectFeeDebited bool
|
||||
//log.Print("cc: " + utils.ToJSON(cc))
|
||||
if debitConnectFee {
|
||||
// this is the first add, debit the connect fee
|
||||
if connectFeeDebited, debitedConnectFeeBalance = ub.DebitConnectionFee(cc, moneyBalances, count, true); !connectFeeDebited {
|
||||
// balance is blocker
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
cc.Timespans.Decompress()
|
||||
//log.Printf("CallCost In Debit: %+v", cc)
|
||||
//for _, ts := range cc.Timespans {
|
||||
// log.Printf("CC_TS: %+v", ts.RateInterval.Rating.Rates[0])
|
||||
//}
|
||||
for tsIndex, ts := range cc.Timespans {
|
||||
if ts.RateInterval == nil {
|
||||
utils.Logger.Err(fmt.Sprintf("Nil RateInterval ERROR on TS: %+v, CC: %+v, from CD: %+v", ts, cc, cd))
|
||||
return nil, errors.New("timespan with no rate interval assigned")
|
||||
}
|
||||
if ts.Increments == nil {
|
||||
ts.createIncrementsSlice()
|
||||
}
|
||||
//log.Printf("TS: %+v", ts)
|
||||
|
||||
if tsIndex == 0 &&
|
||||
ts.RateInterval.Rating.ConnectFee > 0 &&
|
||||
debitConnectFee &&
|
||||
cc.deductConnectFee &&
|
||||
connectFeeDebited {
|
||||
|
||||
ts.Increments = append([]*Increment{{
|
||||
Duration: 0,
|
||||
Cost: ts.RateInterval.Rating.ConnectFee,
|
||||
BalanceInfo: &DebitInfo{
|
||||
Monetary: &MonetaryInfo{
|
||||
UUID: debitedConnectFeeBalance.Uuid,
|
||||
ID: debitedConnectFeeBalance.ID,
|
||||
Value: debitedConnectFeeBalance.Value,
|
||||
},
|
||||
AccountID: ub.ID,
|
||||
},
|
||||
}}, ts.Increments...)
|
||||
}
|
||||
|
||||
maxCost, strategy := ts.RateInterval.GetMaxCost()
|
||||
//log.Printf("Timing: %+v", ts.RateInterval.Timing)
|
||||
//log.Printf("RGRate: %+v", ts.RateInterval.Rating)
|
||||
for incIndex, inc := range ts.Increments {
|
||||
// check standard subject tags
|
||||
//log.Printf("INC: %+v", inc)
|
||||
|
||||
if tsIndex == 0 &&
|
||||
incIndex == 0 &&
|
||||
ts.RateInterval.Rating.ConnectFee > 0 &&
|
||||
cc.deductConnectFee &&
|
||||
connectFeeDebited {
|
||||
// go to nextincrement
|
||||
continue
|
||||
}
|
||||
if cd.MaxCostSoFar >= maxCost {
|
||||
if strategy == utils.MetaMaxCostFree {
|
||||
inc.Cost = 0.0
|
||||
inc.BalanceInfo.Monetary = &MonetaryInfo{
|
||||
UUID: b.Uuid,
|
||||
ID: b.ID,
|
||||
Value: b.Value,
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
if b.RatingSubject != utils.EmptyString || isUnitBal {
|
||||
inc.BalanceInfo.Monetary.RateInterval = ts.RateInterval
|
||||
}
|
||||
if count {
|
||||
ub.countUnits(inc.Cost, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
|
||||
//log.Printf("TS: %+v", cc.Cost)
|
||||
// go to nextincrement
|
||||
continue
|
||||
} else if cc.maxCostDisconect = strategy == utils.MetaMaxCostDisconnect; cc.maxCostDisconect && dryRun {
|
||||
// cut the entire current timespan
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
cc.Timespans = cc.Timespans[:tsIndex]
|
||||
} else {
|
||||
ts.SplitByIncrement(incIndex)
|
||||
cc.Timespans = cc.Timespans[:tsIndex+1]
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// debit minutes and money
|
||||
amount := float64(inc.Duration)
|
||||
cost := inc.Cost
|
||||
|
||||
canDebitCost := b.GetValue() >= cost
|
||||
var moneyBal *Balance
|
||||
if isUnitBal {
|
||||
if b.Factor != nil {
|
||||
amount = utils.Round(amount/b.Factor.GetValue(cd.ToR), globalRoundingDecimals, utils.MetaRoundingUp)
|
||||
}
|
||||
for _, mb := range moneyBalances {
|
||||
if mb.GetValue() >= cost {
|
||||
moneyBal = mb
|
||||
break
|
||||
}
|
||||
}
|
||||
if cost != 0 && moneyBal == nil && (!dryRun || ub.AllowNegative) { // Fix for issue #685
|
||||
utils.Logger.Warning(fmt.Sprintf("<RALs> Going negative on account %s with AllowNegative: false", cd.GetAccountKey()))
|
||||
moneyBal = ub.GetDefaultMoneyBalance()
|
||||
}
|
||||
canDebitCost = b.GetValue() >= amount && (moneyBal != nil || cost == 0)
|
||||
}
|
||||
if !canDebitCost {
|
||||
// delete the rest of the unpaid increments/timespans
|
||||
if incIndex == 0 {
|
||||
// cut the entire current timespan
|
||||
cc.Timespans = cc.Timespans[:tsIndex]
|
||||
} else {
|
||||
ts.SplitByIncrement(incIndex)
|
||||
cc.Timespans = cc.Timespans[:tsIndex+1]
|
||||
}
|
||||
if len(cc.Timespans) == 0 {
|
||||
cc = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if isUnitBal { // unit balance
|
||||
b.SubstractValue(amount)
|
||||
inc.BalanceInfo.Unit = &UnitInfo{
|
||||
UUID: b.Uuid,
|
||||
ID: b.ID,
|
||||
Value: b.Value,
|
||||
DestinationID: cc.Destination,
|
||||
Consumed: amount,
|
||||
ToR: cc.ToR,
|
||||
RateInterval: ts.RateInterval,
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
if cost != 0 {
|
||||
moneyBal.SubstractValue(cost)
|
||||
inc.BalanceInfo.Monetary = &MonetaryInfo{
|
||||
UUID: moneyBal.Uuid,
|
||||
ID: moneyBal.ID,
|
||||
Value: moneyBal.Value,
|
||||
}
|
||||
cd.MaxCostSoFar += cost
|
||||
}
|
||||
if count {
|
||||
ub.countUnits(amount, cc.ToR, cc, b)
|
||||
if cost != 0 {
|
||||
ub.countUnits(cost, utils.MetaMonetary, cc, moneyBal)
|
||||
}
|
||||
}
|
||||
} else { // monetary balance
|
||||
b.SubstractValue(cost)
|
||||
cd.MaxCostSoFar += cost
|
||||
inc.BalanceInfo.Monetary = &MonetaryInfo{
|
||||
UUID: b.Uuid,
|
||||
ID: b.ID,
|
||||
Value: b.Value,
|
||||
}
|
||||
inc.BalanceInfo.AccountID = ub.ID
|
||||
if b.RatingSubject != "" {
|
||||
inc.BalanceInfo.Monetary.RateInterval = ts.RateInterval
|
||||
}
|
||||
if count {
|
||||
ub.countUnits(cost, utils.MetaMonetary, cc, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isUnitBal && len(cc.Timespans) == 0 {
|
||||
cc = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -99,15 +99,6 @@ func (cc *CallCost) CreateCallDescriptor() *CallDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
func (cc *CallCost) IsPaid() bool {
|
||||
for _, ts := range cc.Timespans {
|
||||
if paid, _ := ts.IsPaid(); !paid {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (cc *CallCost) ToDataCost() (*DataCost, error) {
|
||||
if cc.ToR == utils.MetaVoice {
|
||||
return nil, errors.New("Not a data call!")
|
||||
@@ -145,7 +136,6 @@ func (cc *CallCost) ToDataCost() (*DataCost, error) {
|
||||
Cost: incr.Cost,
|
||||
BalanceInfo: incr.BalanceInfo,
|
||||
CompressFactor: incr.CompressFactor,
|
||||
paid: incr.paid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,6 @@ func TestCallcostCallCostToDataCost(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: false,
|
||||
Duration: 12 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
@@ -324,7 +323,6 @@ func TestCallcostCallCostToDataCost(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: true,
|
||||
Duration: 24 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
@@ -429,55 +427,6 @@ func TestCallcostUpdateRatedUsage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallcostIsPaidFalse(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Timespans: TimeSpans{
|
||||
{
|
||||
Increments: Increments{
|
||||
&Increment{
|
||||
paid: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
rcv := cc.IsPaid()
|
||||
|
||||
if rcv != false {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", false, rcv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallcostIsPaidTrue(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
Timespans: TimeSpans{
|
||||
{
|
||||
MatchedSubject: "1001",
|
||||
Increments: Increments{
|
||||
&Increment{
|
||||
paid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchedSubject: "1002",
|
||||
Increments: Increments{
|
||||
&Increment{
|
||||
paid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
rcv := cc.IsPaid()
|
||||
|
||||
if rcv != true {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", true, rcv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallcostUpdateCost(t *testing.T) {
|
||||
cc := &CallCost{
|
||||
deductConnectFee: false,
|
||||
@@ -573,7 +522,6 @@ func TestCallcostUpdateCost(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: false,
|
||||
Duration: 12 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
@@ -595,7 +543,6 @@ func TestCallcostUpdateCost(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: true,
|
||||
Duration: 24 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
@@ -720,7 +667,6 @@ func TestCallcostGetStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: false,
|
||||
Duration: 12 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
@@ -742,7 +688,6 @@ func TestCallcostGetStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
paid: true,
|
||||
Duration: 24 * time.Second,
|
||||
CompressFactor: 2,
|
||||
},
|
||||
|
||||
@@ -1957,7 +1957,6 @@ func TestCalldescRefundIncrementsNoBalanceInfo(t *testing.T) {
|
||||
Increments: Increments{
|
||||
{
|
||||
Duration: time.Second,
|
||||
paid: true,
|
||||
Cost: 5,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -42,5 +42,4 @@ type DataIncrement struct {
|
||||
Cost float64
|
||||
BalanceInfo *DebitInfo // need more than one for units with cost
|
||||
CompressFactor int
|
||||
paid bool
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ type Increment struct {
|
||||
Cost float64
|
||||
BalanceInfo *DebitInfo // need more than one for units with cost
|
||||
CompressFactor int
|
||||
paid bool
|
||||
}
|
||||
|
||||
// Holds information about the balance that made a specific payment
|
||||
@@ -466,7 +465,6 @@ func (ts *TimeSpan) createIncrementsSlice() {
|
||||
if ts.RateInterval == nil {
|
||||
return
|
||||
}
|
||||
ts.Increments = make([]*Increment, 0)
|
||||
// create rated units series
|
||||
_, rateIncrement, _ := ts.RateInterval.GetRateParameters(ts.GetGroupStart())
|
||||
// we will use the calculated cost and devide by nb of increments
|
||||
@@ -475,36 +473,23 @@ func (ts *TimeSpan) createIncrementsSlice() {
|
||||
nbIncrements := int(ts.GetDuration() / rateIncrement)
|
||||
if nbIncrements > config.CgrConfig().RalsCfg().MaxIncrements {
|
||||
utils.Logger.Warning(fmt.Sprintf("error: <%s with %+v>, when creating increments slice, TimeSpan: %s", utils.ErrMaxIncrementsExceeded, nbIncrements, utils.ToJSON(ts)))
|
||||
ts.Increments = make([]*Increment, 0)
|
||||
return
|
||||
}
|
||||
incrementCost := ts.CalculateCost() / float64(nbIncrements)
|
||||
incrementCost = utils.Round(incrementCost, globalRoundingDecimals, utils.MetaRoundingMiddle)
|
||||
for s := 0; s < nbIncrements; s++ {
|
||||
inc := &Increment{
|
||||
ts.Increments = make([]*Increment, nbIncrements)
|
||||
for i := range ts.Increments {
|
||||
ts.Increments[i] = &Increment{
|
||||
Duration: rateIncrement,
|
||||
Cost: incrementCost,
|
||||
BalanceInfo: &DebitInfo{},
|
||||
}
|
||||
ts.Increments = append(ts.Increments, inc)
|
||||
}
|
||||
// put the rounded cost back in timespan
|
||||
ts.Cost = incrementCost * float64(nbIncrements)
|
||||
}
|
||||
|
||||
// returns whether the timespan has all increments marked as paid and if not
|
||||
// it also returns the first unpaied increment
|
||||
func (ts *TimeSpan) IsPaid() (bool, int) {
|
||||
if ts.Increments.Length() == 0 {
|
||||
return false, 0
|
||||
}
|
||||
for incrementIndex, increment := range ts.Increments {
|
||||
if !increment.paid {
|
||||
return false, incrementIndex
|
||||
}
|
||||
}
|
||||
return true, len(ts.Increments)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the given timespan according to how it relates to the interval.
|
||||
It will modify the endtime of the received timespan and it will return
|
||||
@@ -592,12 +577,12 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp
|
||||
}
|
||||
|
||||
// Split the timespan at the given increment start
|
||||
func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan {
|
||||
func (ts *TimeSpan) SplitByIncrement(index int) (newTs *TimeSpan) {
|
||||
if index <= 0 || index >= len(ts.Increments) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
timeStart := ts.GetTimeStartForIncrement(index)
|
||||
newTs := &TimeSpan{
|
||||
newTs = &TimeSpan{
|
||||
RateInterval: ts.RateInterval,
|
||||
TimeStart: timeStart,
|
||||
TimeEnd: ts.TimeEnd,
|
||||
@@ -608,7 +593,7 @@ func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan {
|
||||
newTs.Increments = ts.Increments[index:]
|
||||
ts.Increments = ts.Increments[:index]
|
||||
ts.SetNewDurationIndex(newTs)
|
||||
return newTs
|
||||
return
|
||||
}
|
||||
|
||||
// Split the timespan at the given second
|
||||
@@ -725,11 +710,12 @@ func (ts *TimeSpan) GetTimeStartForIncrement(index int) time.Time {
|
||||
}
|
||||
|
||||
func (ts *TimeSpan) RoundToDuration(duration time.Duration) {
|
||||
if duration < ts.GetDuration() {
|
||||
duration = utils.RoundDuration(duration, ts.GetDuration())
|
||||
tsDur := ts.GetDuration()
|
||||
if duration < tsDur {
|
||||
duration = utils.RoundDuration(duration, tsDur)
|
||||
}
|
||||
if duration > ts.GetDuration() {
|
||||
initialDuration := ts.GetDuration()
|
||||
if duration > tsDur {
|
||||
initialDuration := tsDur
|
||||
ts.TimeEnd = ts.TimeStart.Add(duration)
|
||||
ts.DurationIndex = ts.DurationIndex + (duration - initialDuration)
|
||||
}
|
||||
|
||||
@@ -391,9 +391,13 @@ func MinDuration(d1, d2 time.Duration) time.Duration {
|
||||
// ParseZeroRatingSubject will parse the subject in the balance
|
||||
// returns duration if able to extract it from subject
|
||||
// returns error if not able to parse duration (ie: if ratingSubject is standard one)
|
||||
func ParseZeroRatingSubject(tor, rateSubj string, defaultRateSubj map[string]string) (time.Duration, error) {
|
||||
func ParseZeroRatingSubject(tor, rateSubj string, defaultRateSubj map[string]string, isUnitBal bool) (time.Duration, error) {
|
||||
rateSubj = strings.TrimSpace(rateSubj)
|
||||
if rateSubj == "" || rateSubj == MetaAny {
|
||||
if !isUnitBal && rateSubj == EmptyString {
|
||||
return 0, errors.New("no rating subject for monetary")
|
||||
}
|
||||
if rateSubj == EmptyString ||
|
||||
rateSubj == MetaAny {
|
||||
var hasToR bool
|
||||
if rateSubj, hasToR = defaultRateSubj[tor]; !hasToR {
|
||||
rateSubj = defaultRateSubj[MetaAny]
|
||||
@@ -403,8 +407,8 @@ func ParseZeroRatingSubject(tor, rateSubj string, defaultRateSubj map[string]str
|
||||
return 0, errors.New("malformed rating subject: " + rateSubj)
|
||||
}
|
||||
durStr := rateSubj[len(MetaRatingSubjectPrefix):]
|
||||
if _, err := strconv.ParseFloat(durStr, 64); err == nil { // No time unit, postpend
|
||||
durStr += "ns"
|
||||
if val, err := strconv.ParseFloat(durStr, 64); err == nil { // No time unit, postpend
|
||||
return time.Duration(val), nil // just return the float value converted(this should be faster than reparsing the string)
|
||||
}
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
@@ -748,24 +748,24 @@ func TestParseZeroRatingSubject(t *testing.T) {
|
||||
MetaVoice: "*zero1s",
|
||||
}
|
||||
for i, s := range subj {
|
||||
if d, err := ParseZeroRatingSubject(MetaVoice, s, dfltRatingSubject); err != nil || d != dur[i] {
|
||||
if d, err := ParseZeroRatingSubject(MetaVoice, s, dfltRatingSubject, true); err != nil || d != dur[i] {
|
||||
t.Error("Error parsing rating subject: ", s, d, err)
|
||||
}
|
||||
}
|
||||
if d, err := ParseZeroRatingSubject(MetaData, EmptyString, dfltRatingSubject); err != nil || d != time.Nanosecond {
|
||||
if d, err := ParseZeroRatingSubject(MetaData, EmptyString, dfltRatingSubject, true); err != nil || d != time.Nanosecond {
|
||||
t.Error("Error parsing rating subject: ", EmptyString, d, err)
|
||||
}
|
||||
if d, err := ParseZeroRatingSubject(MetaSMS, EmptyString, dfltRatingSubject); err != nil || d != time.Nanosecond {
|
||||
if d, err := ParseZeroRatingSubject(MetaSMS, EmptyString, dfltRatingSubject, true); err != nil || d != time.Nanosecond {
|
||||
t.Error("Error parsing rating subject: ", EmptyString, d, err)
|
||||
}
|
||||
if d, err := ParseZeroRatingSubject(MetaMMS, EmptyString, dfltRatingSubject); err != nil || d != time.Nanosecond {
|
||||
if d, err := ParseZeroRatingSubject(MetaMMS, EmptyString, dfltRatingSubject, true); err != nil || d != time.Nanosecond {
|
||||
t.Error("Error parsing rating subject: ", EmptyString, d, err)
|
||||
}
|
||||
if d, err := ParseZeroRatingSubject(MetaMonetary, EmptyString, dfltRatingSubject); err != nil || d != time.Nanosecond {
|
||||
if d, err := ParseZeroRatingSubject(MetaMonetary, EmptyString, dfltRatingSubject, true); err != nil || d != time.Nanosecond {
|
||||
t.Error("Error parsing rating subject: ", EmptyString, d, err)
|
||||
}
|
||||
expecting := "malformed rating subject: test"
|
||||
if _, err := ParseZeroRatingSubject(MetaMonetary, "test", dfltRatingSubject); err == nil || err.Error() != expecting {
|
||||
if _, err := ParseZeroRatingSubject(MetaMonetary, "test", dfltRatingSubject, true); err == nil || err.Error() != expecting {
|
||||
t.Errorf("Expecting: %+v, received: %+v ", expecting, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user