mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
debit from shared group empty balances
This commit is contained in:
@@ -197,7 +197,6 @@ func (ub *Account) getBalancesForPrefix(prefix string, balances BalanceChain, sh
|
||||
func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) {
|
||||
usefulMinuteBalances := ub.getBalancesForPrefix(cc.Destination, ub.BalanceMap[MINUTES+cc.Direction], "")
|
||||
usefulMoneyBalances := ub.getBalancesForPrefix(cc.Destination, ub.BalanceMap[CREDIT+cc.Direction], "")
|
||||
defaultMoneyBalance := ub.GetDefaultMoneyBalance(cc.Direction)
|
||||
// debit minutes
|
||||
for _, balance := range usefulMinuteBalances {
|
||||
if balance.SharedGroup != "" {
|
||||
@@ -221,7 +220,6 @@ func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// debit money
|
||||
for _, balance := range usefulMoneyBalances {
|
||||
if balance.SharedGroup != "" {
|
||||
@@ -233,7 +231,7 @@ func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) {
|
||||
goto CONNECT_FEE
|
||||
}
|
||||
}
|
||||
// get the highest priority money balanance
|
||||
// get the default money balanance
|
||||
// and go negative on it with the amount still unpaid
|
||||
for tsIndex := 0; tsIndex < len(cc.Timespans); tsIndex++ {
|
||||
ts := cc.Timespans[tsIndex]
|
||||
@@ -251,7 +249,7 @@ func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) {
|
||||
}
|
||||
for _, increment := range ts.Increments {
|
||||
cost := increment.Cost
|
||||
defaultMoneyBalance.Value -= cost
|
||||
ub.GetDefaultMoneyBalance(cc.Direction).Value -= cost
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: cost, DestinationId: cc.Destination}})
|
||||
}
|
||||
@@ -278,7 +276,7 @@ CONNECT_FEE:
|
||||
// debit connect fee
|
||||
if connectFee > 0 && !connectFeePaid {
|
||||
// there are no money for the connect fee; go negative
|
||||
defaultMoneyBalance.Value -= connectFee
|
||||
ub.GetDefaultMoneyBalance(cc.Direction).Value -= connectFee
|
||||
// the conect fee is not refundable!
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationId: cc.Destination}})
|
||||
@@ -336,9 +334,8 @@ func (ub *Account) GetDefaultMoneyBalance(direction string) *Balance {
|
||||
return balance
|
||||
}
|
||||
}
|
||||
|
||||
// create default balance
|
||||
defaultBalance := &Balance{Weight: 999}
|
||||
defaultBalance := &Balance{Weight: 0} // minimum weight
|
||||
ub.BalanceMap[CREDIT+direction] = append(ub.BalanceMap[CREDIT+direction], defaultBalance)
|
||||
return defaultBalance
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ func (cm *AccountLock) GuardMany(names []string, handler func() (float64, error)
|
||||
cm.Unlock()
|
||||
}
|
||||
lock <- true
|
||||
reply, err = handler()
|
||||
}
|
||||
reply, err = handler()
|
||||
for _, name := range names {
|
||||
|
||||
@@ -166,7 +166,7 @@ func resetCountersAction(ub *Account, a *Action) (err error) {
|
||||
}
|
||||
|
||||
func genericMakeNegative(a *Action) {
|
||||
if a.Balance != nil && a.Balance.Value > 0 { // only apply if not allready negative
|
||||
if a.Balance != nil && a.Balance.Value >= 0 { // only apply if not allready negative
|
||||
a.Balance.Value = -a.Balance.Value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,8 +393,9 @@ func (bc BalanceChain) Swap(i, j int) {
|
||||
}
|
||||
|
||||
func (bc BalanceChain) Less(j, i int) bool {
|
||||
return bc[i].Weight < bc[j].Weight ||
|
||||
bc[i].precision < bc[j].precision
|
||||
return bc[i].precision < bc[j].precision ||
|
||||
(bc[i].precision == bc[j].precision && bc[i].Weight < bc[j].Weight)
|
||||
|
||||
}
|
||||
|
||||
func (bc BalanceChain) Sort() {
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBalanceSortWeight(t *testing.T) {
|
||||
func TestBalanceSortPrecision(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 1, precision: 2}
|
||||
mb2 := &Balance{Weight: 2, precision: 1}
|
||||
var bs BalanceChain
|
||||
@@ -34,7 +34,7 @@ func TestBalanceSortWeight(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBalanceSortPrecision(t *testing.T) {
|
||||
func TestBalanceSortPrecisionWeightEqual(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 1, precision: 2}
|
||||
mb2 := &Balance{Weight: 1, precision: 1}
|
||||
var bs BalanceChain
|
||||
@@ -45,6 +45,39 @@ func TestBalanceSortPrecision(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBalanceSortPrecisionWeightGreater(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 2, precision: 2}
|
||||
mb2 := &Balance{Weight: 1, precision: 1}
|
||||
var bs BalanceChain
|
||||
bs = append(bs, mb2, mb1)
|
||||
bs.Sort()
|
||||
if bs[0] != mb1 || bs[1] != mb2 {
|
||||
t.Error("Buckets not sorted by precision!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBalanceSortWeight(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 2, precision: 1}
|
||||
mb2 := &Balance{Weight: 1, precision: 1}
|
||||
var bs BalanceChain
|
||||
bs = append(bs, mb2, mb1)
|
||||
bs.Sort()
|
||||
if bs[0] != mb1 || bs[1] != mb2 {
|
||||
t.Error("Buckets not sorted by precision!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBalanceSortWeightLess(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 1, precision: 1}
|
||||
mb2 := &Balance{Weight: 2, precision: 1}
|
||||
var bs BalanceChain
|
||||
bs = append(bs, mb2, mb1)
|
||||
bs.Sort()
|
||||
if bs[0] != mb2 || bs[1] != mb1 {
|
||||
t.Error("Buckets not sorted by precision!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBalanceEqual(t *testing.T) {
|
||||
mb1 := &Balance{Weight: 1, precision: 1, RateSubject: "1", DestinationId: ""}
|
||||
mb2 := &Balance{Weight: 1, precision: 1, RateSubject: "1", DestinationId: ""}
|
||||
|
||||
@@ -21,6 +21,7 @@ package engine
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/syslog"
|
||||
"time"
|
||||
//"encoding/json"
|
||||
@@ -581,9 +582,11 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) {
|
||||
cd.TimeEnd = cd.TimeStart.Add(remainingDuration)
|
||||
}
|
||||
cc, err = cd.debit(account)
|
||||
//log.Print(balanceMap[0].Value, balanceMap[1].Value)
|
||||
return 0, err
|
||||
})
|
||||
} else {
|
||||
log.Print("cxcxxc")
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,8 +374,8 @@ func TestMaxSessionTimeWithAccountShared(t *testing.T) {
|
||||
|
||||
result0, err := cd0.GetMaxSessionDuration()
|
||||
result1, err := cd1.GetMaxSessionDuration()
|
||||
if result0 != result1 || err != nil {
|
||||
t.Errorf("Expected %v was %v, %v", result1, result0, err)
|
||||
if result0 != result1/2 || err != nil {
|
||||
t.Errorf("Expected %v was %v, %v", result1/2, result0, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,6 +475,62 @@ func TestDebitAndMaxDebit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitFromShareAndNormal(t *testing.T) {
|
||||
ap, _ := accountingStorage.GetActionTimings("TOPUP_SHARED10_AT")
|
||||
for _, at := range ap {
|
||||
at.Execute()
|
||||
}
|
||||
|
||||
cd := &CallDescriptor{
|
||||
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",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "empty10",
|
||||
Destination: "0723",
|
||||
}
|
||||
acc, _ := cd.getAccount()
|
||||
balanceMap := acc.BalanceMap[CREDIT+OUTBOUND]
|
||||
cc, err := cd.MaxDebit()
|
||||
if err != nil || cc.Cost != 2.5 {
|
||||
t.Errorf("Debit from share and normal error: %+v, %v", cc, err)
|
||||
}
|
||||
|
||||
if balanceMap[0].Value != 10 || balanceMap[1].Value != 7.5 {
|
||||
t.Errorf("Error debiting from right balance: %v %v", balanceMap[0].Value, balanceMap[1].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitFromEmptyShare(t *testing.T) {
|
||||
ap, _ := accountingStorage.GetActionTimings("TOPUP_EMPTY_AT")
|
||||
for _, at := range ap {
|
||||
at.Execute()
|
||||
}
|
||||
|
||||
cd := &CallDescriptor{
|
||||
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",
|
||||
Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Account: "emptyX",
|
||||
Destination: "0723",
|
||||
}
|
||||
|
||||
cc, err := cd.MaxDebit()
|
||||
if err != nil || cc.Cost != 2.5 {
|
||||
t.Errorf("Debit from empty share error: %+v, %v", cc, err)
|
||||
}
|
||||
acc, _ := cd.getAccount()
|
||||
balanceMap := acc.BalanceMap[CREDIT+OUTBOUND]
|
||||
if len(balanceMap) != 2 || balanceMap[0].Value != 0 || balanceMap[1].Value != -2.5 {
|
||||
t.Errorf("Error debiting from empty share: %+v %+v", balanceMap[0], balanceMap[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxDebitZeroDefinedRate(t *testing.T) {
|
||||
ap, _ := accountingStorage.GetActionTimings("TOPUP10_AT")
|
||||
for _, at := range ap {
|
||||
|
||||
@@ -124,6 +124,7 @@ cgrates.directvoip.co.uk,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK
|
||||
sharedGroups = `
|
||||
SG1,*any,*lowest_first,
|
||||
SG2,*any,*lowest_first,EVENING
|
||||
SG3,*any,*lowest_first,
|
||||
`
|
||||
|
||||
actions = `
|
||||
@@ -133,7 +134,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
|
||||
SE0,*topup_reset,*monetary,*out,0,*unlimited,,,10,SG2,,10
|
||||
SE10,*topup_reset,*monetary,*out,10,*unlimited,,,10,SG2,,10
|
||||
SE10,*topup_reset,*monetary,*out,10,*unlimited,,,5,SG2,,10
|
||||
SE10,*topup,*monetary,*out,10,*unlimited,,,10,,,10
|
||||
EE0,*topup_reset,*monetary,*out,0,*unlimited,,,10,SG3,,10
|
||||
EE0,*allow_negative,*monetary,*out,0,*unlimited,,,10,,,10
|
||||
`
|
||||
actionTimings = `
|
||||
MORE_MINUTES,MINI,ONE_TIME_RUN,10
|
||||
@@ -142,6 +146,7 @@ TOPUP10_AT,TOPUP10_AC,ASAP,10
|
||||
TOPUP10_AT,TOPUP10_AC1,ASAP,10
|
||||
TOPUP_SHARED0_AT,SE0,ASAP,10
|
||||
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
|
||||
@@ -155,6 +160,8 @@ vdf,minitsboy;a1;a2,*out,MORE_MINUTES,STANDARD_TRIGGER
|
||||
cgrates.directvoip.co.uk,12345,*out,TOPUP10_AT,STANDARD_TRIGGERS
|
||||
vdf,empty0,*out,TOPUP_SHARED0_AT,
|
||||
vdf,empty10,*out,TOPUP_SHARED10_AT,
|
||||
vdf,emptyX,*out,TOPUP_EMPTY_AT,
|
||||
vdf,emptyY,*out,TOPUP_EMPTY_AT,
|
||||
`
|
||||
)
|
||||
|
||||
@@ -598,7 +605,7 @@ func TestLoadRatingProfiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActions(t *testing.T) {
|
||||
if len(csvr.actions) != 6 {
|
||||
if len(csvr.actions) != 7 {
|
||||
t.Error("Failed to load actions: ", csvr.actions)
|
||||
}
|
||||
as1 := csvr.actions["MINI"]
|
||||
@@ -660,7 +667,7 @@ func TestLoadActions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadSharedGroups(t *testing.T) {
|
||||
if len(csvr.sharedGroups) != 2 {
|
||||
if len(csvr.sharedGroups) != 3 {
|
||||
t.Error("Failed to load actions: ", csvr.sharedGroups)
|
||||
}
|
||||
|
||||
@@ -707,7 +714,7 @@ func TestLoadSharedGroups(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActionTimings(t *testing.T) {
|
||||
if len(csvr.actionsTimings) != 4 {
|
||||
if len(csvr.actionsTimings) != 5 {
|
||||
t.Error("Failed to load action timings: ", csvr.actionsTimings)
|
||||
}
|
||||
atm := csvr.actionsTimings["MORE_MINUTES"][0]
|
||||
@@ -769,7 +776,7 @@ func TestLoadActionTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadAccountActions(t *testing.T) {
|
||||
if len(csvr.accountActions) != 4 {
|
||||
if len(csvr.accountActions) != 6 {
|
||||
t.Error("Failed to load account actions: ", csvr.accountActions)
|
||||
}
|
||||
aa := csvr.accountActions["*out:vdf:minitsboy"]
|
||||
|
||||
Reference in New Issue
Block a user