From aef3bdeb4776ab88888e8a14eb9c021e54416328 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Sun, 15 Nov 2015 21:33:21 +0200 Subject: [PATCH] connect fee gets debited first --- engine/account.go | 13 ++++++------- engine/account_test.go | 27 +++++++++++++++++++++++++++ engine/balances.go | 14 ++++++++++++-- engine/callcost.go | 1 + engine/calldesc.go | 4 ++++ engine/calldesc_test.go | 3 ++- engine/loader_csv_test.go | 4 +++- 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/engine/account.go b/engine/account.go index 5c5a414bc..49487ec63 100644 --- a/engine/account.go +++ b/engine/account.go @@ -287,15 +287,15 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //log.Printf("Unit balance: %+v", balance) // log.Printf("CD BEFORE UNIT: %+v", cd) - partCC, debitErr := balance.DebitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun) + partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } //log.Printf("CD AFTER UNIT: %+v", cd) if partCC != nil { //log.Printf("partCC: %+v", partCC.Timespans[0]) - initialLength = len(cc.Timespans) cc.Timespans = append(cc.Timespans, partCC.Timespans...) + cc.negativeConnectFee = partCC.negativeConnectFee if initialLength == 0 { // this is the first add, debit the connect fee ub.DebitConnectionFee(cc, usefulMoneyBalances, count) @@ -329,7 +329,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulMoneyBalances { //log.Printf("Money balance: %+v", balance) //log.Printf("CD BEFORE MONEY: %+v", cd) - partCC, debitErr := balance.DebitMoney(cd, balance.account, count, dryRun) + partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, initialLength == 0) if debitErr != nil { return nil, debitErr } @@ -338,10 +338,8 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo if partCC != nil { initialLength = len(cc.Timespans) cc.Timespans = append(cc.Timespans, partCC.Timespans...) - if initialLength == 0 { - // this is the first add, debit the connect fee - ub.DebitConnectionFee(cc, usefulMoneyBalances, count) - } + cc.negativeConnectFee = partCC.negativeConnectFee + //for i, ts := range cc.Timespans { //log.Printf("cc.times[an[%d]: %+v\n", i, ts) //} @@ -682,6 +680,7 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance } // 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) diff --git a/engine/account_test.go b/engine/account_test.go index ab6d7647a..d57aed98e 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -1193,6 +1193,33 @@ func TestMaxDurationShared(t *testing.T) { } +func TestMaxDurationConnectFeeOnly(t *testing.T) { + cd := &CallDescriptor{ + Tenant: "cgrates.org", + Category: "call", + TimeStart: time.Date(2015, 9, 24, 10, 48, 0, 0, time.UTC), + TimeEnd: time.Date(2015, 9, 24, 10, 58, 1, 0, time.UTC), + Direction: utils.OUT, + Destination: "4444", + Subject: "dy", + Account: "dy", + TOR: utils.VOICE, + DurationIndex: 600, + } + rif := &Account{Id: "rif", BalanceMap: map[string]BalanceChain{ + utils.MONETARY: BalanceChain{&Balance{Uuid: "moneya", Value: 0.2}}, + }} + + duration, err := cd.getMaxSessionDuration(rif) + if err != nil { + t.Error("Error getting max session duration: ", err) + } + if duration != 0 { + t.Error("Wrong max session: ", duration) + } + +} + func TestDebitSMS(t *testing.T) { cc := &CallCost{ Direction: utils.OUT, diff --git a/engine/balances.go b/engine/balances.go index 0971f2fde..d667eaf76 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -351,7 +351,7 @@ func (b *Balance) SetValue(amount float64) { b.dirty = true } -func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun bool) (cc *CallCost, err error) { +func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun, debitConnectFee bool) (cc *CallCost, err error) { if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 { return } @@ -431,6 +431,10 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala if err != nil { return nil, err } + if debitConnectFee { + // this is the first add, debit the connect fee + ub.DebitConnectionFee(cc, moneyBalances, count) + } cc.Timespans.Decompress() //log.Printf("CC: %+v", cc) @@ -522,7 +526,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala return } -func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun bool) (cc *CallCost, err error) { +func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun, debitConnectFee bool) (cc *CallCost, err error) { if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 { return } @@ -531,6 +535,12 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun if err != nil { return nil, err } + + if debitConnectFee { + // this is the first add, debit the connect fee + ub.DebitConnectionFee(cc, moneyBalances, count) + } + cc.Timespans.Decompress() //log.Printf("CallCost In Debit: %+v", cc) //for _, ts := range cc.Timespans { diff --git a/engine/callcost.go b/engine/callcost.go index 178bc2af5..5a9fbeba0 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -31,6 +31,7 @@ type CallCost struct { Cost float64 Timespans TimeSpans deductConnectFee bool + negativeConnectFee bool // the connect fee went negative on default balance maxCostDisconect bool } diff --git a/engine/calldesc.go b/engine/calldesc.go index 752f95445..4664f7ddb 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -564,6 +564,10 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura } //log.Printf("CC: %+v", cc) + // not enough credit for connect fee + if cc.negativeConnectFee == true { + return 0, nil + } var totalCost float64 var totalDuration time.Duration diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index c28eb0d69..75926480f 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -1069,8 +1069,9 @@ func TestMaxSesionTimeLongerThanMoney(t *testing.T) { } acc, _ := accountingStorage.GetAccount("cgrates.org:money") allowedTime, err := cd.getMaxSessionDuration(acc) - expected, err := time.ParseDuration("2h46m40s") + expected, err := time.ParseDuration("9999s") // 1 is the connect fee if err != nil || allowedTime != expected { + t.Log(utils.ToIJSON(acc)) t.Errorf("Expected: %v got %v", expected, allowedTime) } } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 9a86b538a..1e5694beb 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -71,6 +71,7 @@ RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s R_URG,0,0,1,1,0 MX,0,1,1s,1s,0 DY,0.15,0.05,60s,1s,0s +CF,1.12,0,1s,1s,0s ` destinationRates = ` RT_STANDARD,GERMANY,R1,*middle,4,0, @@ -93,6 +94,7 @@ RT_URG,URG,R_URG,*middle,4,0, MX_FREE,RET,MX,*middle,4,10,*free MX_DISC,RET,MX,*middle,4,10,*disconnect RT_DY,RET,DY,*up,2,0, +RT_DY,EU_LANDLINE,CF,*middle,4,0, ` ratingPlans = ` STANDARD,RT_STANDARD,WORKDAYS_00,10 @@ -396,7 +398,7 @@ func TestLoadTimimgs(t *testing.T) { } func TestLoadRates(t *testing.T) { - if len(csvr.rates) != 14 { + if len(csvr.rates) != 15 { t.Error("Failed to load rates: ", len(csvr.rates)) } rate := csvr.rates["R1"].RateSlots[0]