mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
fix for MaxDebit bug
max duration was calculated badly
This commit is contained in:
@@ -83,7 +83,8 @@ func (b *Balance) Clone() *Balance {
|
||||
}
|
||||
|
||||
// Returns the available number of seconds for a specified credit
|
||||
func (b *Balance) GetMinutesForCredit(cd *CallDescriptor, initialCredit float64) (duration time.Duration, credit float64) {
|
||||
func (b *Balance) GetMinutesForCredit(origCD *CallDescriptor, initialCredit float64) (duration time.Duration, credit float64) {
|
||||
cd := origCD.Clone()
|
||||
duration = time.Duration(b.Value) * time.Second
|
||||
credit = initialCredit
|
||||
cc, err := b.GetCost(cd)
|
||||
@@ -112,6 +113,7 @@ func (b *Balance) GetCost(cd *CallDescriptor) (*CallCost, error) {
|
||||
if b.RateSubject != "" {
|
||||
cd.Subject = b.RateSubject
|
||||
cd.Account = cd.Subject
|
||||
cd.RatingInfos = nil
|
||||
return cd.GetCost()
|
||||
}
|
||||
cc := cd.CreateCallCost()
|
||||
@@ -221,15 +223,21 @@ func (b *Balance) DebitMinutes(cc *CallCost, count bool, ub *Account, moneyBalan
|
||||
if moneyBal != nil && b.Value >= seconds {
|
||||
b.Value -= seconds
|
||||
b.Value = utils.Round(b.Value, roundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
moneyBal.Value -= cost
|
||||
|
||||
nInc.BalanceInfo.MinuteBalanceUuid = b.Uuid
|
||||
nInc.BalanceInfo.MoneyBalanceUuid = moneyBal.Uuid
|
||||
nInc.BalanceInfo.AccountId = ub.Id
|
||||
nInc.MinuteInfo = &MinuteInfo{newCC.Destination, seconds}
|
||||
if cost != 0 {
|
||||
nInc.BalanceInfo.MoneyBalanceUuid = moneyBal.Uuid
|
||||
moneyBal.Value -= cost
|
||||
moneyBal.Value = utils.Round(moneyBal.Value, roundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
}
|
||||
nInc.paid = true
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: MINUTES, Direction: newCC.Direction, Balance: &Balance{Value: seconds, DestinationId: newCC.Destination}})
|
||||
ub.countUnits(&Action{BalanceType: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: cost, DestinationId: newCC.Destination}})
|
||||
if cost != 0 {
|
||||
ub.countUnits(&Action{BalanceType: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: cost, DestinationId: newCC.Destination}})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
increment.paid = false
|
||||
|
||||
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
@@ -32,7 +31,7 @@ type CallCost struct {
|
||||
}
|
||||
|
||||
// Pretty printing for call cost
|
||||
func (cc *CallCost) String() (r string) {
|
||||
/*func (cc *CallCost) String() (r string) {
|
||||
connectFee := 0.0
|
||||
if cc.deductConnectFee {
|
||||
connectFee = cc.GetConnectFee()
|
||||
@@ -43,7 +42,7 @@ func (cc *CallCost) String() (r string) {
|
||||
}
|
||||
r += " )"
|
||||
return
|
||||
}
|
||||
}*/
|
||||
|
||||
// Merges the received timespan if they are similar (same activation period, same interval, same minute info.
|
||||
func (cc *CallCost) Merge(other *CallCost) {
|
||||
|
||||
@@ -397,7 +397,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
}
|
||||
err := cd.LoadRatingPlans()
|
||||
if err != nil {
|
||||
Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetAccountKey(), err))
|
||||
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)
|
||||
@@ -659,7 +659,7 @@ func (cd *CallDescriptor) Clone() *CallDescriptor {
|
||||
CallDuration: cd.CallDuration,
|
||||
Amount: cd.Amount,
|
||||
FallbackSubject: cd.FallbackSubject,
|
||||
RatingInfos: cd.RatingInfos,
|
||||
Increments: cd.Increments,
|
||||
//RatingInfos: cd.RatingInfos,
|
||||
//Increments: cd.Increments,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ func TestDebitAndMaxDebit(t *testing.T) {
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 5400}
|
||||
}
|
||||
cd2 := cd1.Clone()
|
||||
cc1, err1 := cd1.Debit()
|
||||
cc2, err2 := cd2.MaxDebit()
|
||||
@@ -434,6 +434,38 @@ func TestDebitAndMaxDebit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxDebitZeroDefinedRate(t *testing.T) {
|
||||
ap, _ := accountingStorage.GetActionTimings("TOPUP1000UKMOB_AT")
|
||||
for _, at := range ap {
|
||||
at.Execute()
|
||||
}
|
||||
ap, _ = accountingStorage.GetActionTimings("TOPUP10_AT")
|
||||
for _, at := range ap {
|
||||
at.Execute()
|
||||
}
|
||||
cd1 := &CallDescriptor{
|
||||
Direction: "*out",
|
||||
TOR: "call",
|
||||
Tenant: "cgrates.directvoip.co.uk",
|
||||
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}
|
||||
cc, err := cd1.MaxDebit()
|
||||
if err != nil {
|
||||
t.Error("Error maxdebiting: ", err)
|
||||
}
|
||||
if cc.GetDuration() != 49*time.Second {
|
||||
t.Error("Error obtaining max debit duration: ", cc.GetDuration())
|
||||
}
|
||||
if cc.Cost != 0.9 {
|
||||
t.Error("Error in max debit cost: ", cc.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************** BENCHMARKS ***************************************/
|
||||
func BenchmarkStorageGetting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestHistoryDestinations(t *testing.T) {
|
||||
scribe := historyScribe.(*history.MockScribe)
|
||||
buf := scribe.BufMap[history.DESTINATIONS_FN]
|
||||
expected := `[{"Id":"ALL","Prefixes":["49","41","43"]},
|
||||
{"Id":"DST_UK_Mobile_BIG5","Prefixes":["447956"]},
|
||||
{"Id":"GERMANY","Prefixes":["49"]},
|
||||
{"Id":"GERMANY_O2","Prefixes":["41"]},
|
||||
{"Id":"GERMANY_PREMIUM","Prefixes":["43"]},
|
||||
|
||||
@@ -43,12 +43,15 @@ RET,0724
|
||||
PSTN_71,+4971
|
||||
PSTN_72,+4972
|
||||
PSTN_70,+4970
|
||||
DST_UK_Mobile_BIG5,447956
|
||||
`
|
||||
timings = `
|
||||
WORKDAYS_00,*any,*any,*any,1;2;3;4;5,00:00:00
|
||||
WORKDAYS_18,*any,*any,*any,1;2;3;4;5,18:00:00
|
||||
WEEKENDS,*any,*any,*any,6;7,00:00:00
|
||||
ONE_TIME_RUN,2012,,,,*asap
|
||||
ALWAYS,*any,*any,*any,*any,00:00:00
|
||||
ASAP,*any,*any,*any,*any,*asap
|
||||
`
|
||||
rates = `
|
||||
R1,0,0.2,60s,1s,0,*middle,2
|
||||
@@ -61,6 +64,8 @@ LANDLINE_OFFPEAK,0,1,1s,1s,60s,*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,1s,1s,0s,*up,4
|
||||
RT_UK_Mobile_BIG5_PKG,0,0,20s,20s,0s,*up,8
|
||||
RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s,*up,8
|
||||
`
|
||||
destinationRates = `
|
||||
RT_STANDARD,GERMANY,R1
|
||||
@@ -75,8 +80,10 @@ T1,NAT,LANDLINE_OFFPEAK
|
||||
T2,GERMANY,GBP_72
|
||||
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
|
||||
`
|
||||
destinationRateTimings = `
|
||||
ratingPlans = `
|
||||
STANDARD,RT_STANDARD,WORKDAYS_00,10
|
||||
STANDARD,RT_STD_WEEKEND,WORKDAYS_18,10
|
||||
STANDARD,RT_STD_WEEKEND,WEEKENDS,10
|
||||
@@ -91,6 +98,8 @@ 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
|
||||
`
|
||||
ratingProfiles = `
|
||||
CUSTOMER_1,0,*out,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb
|
||||
@@ -109,6 +118,8 @@ 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.directvoip.co.uk,call,*out,*any,2013-01-06T00:00:00Z,RP_UK,
|
||||
cgrates.directvoip.co.uk,call,*out,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,
|
||||
`
|
||||
sharedGroups = `
|
||||
SG1,*any,*lowest_first,,
|
||||
@@ -119,24 +130,33 @@ SG2,*any,*lowest_first,EVENING,
|
||||
MINI,*topup_reset,*monetary,*out,10,*unlimited,,,10,,,10
|
||||
MINI,*topup,*minutes,*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
|
||||
TOPUP1000UKMOB_AC,*topup_reset,*minutes,*out,40,*unlimited,DST_UK_Mobile_BIG5,discounted_minutes,10,,,10
|
||||
`
|
||||
actionTimings = `
|
||||
MORE_MINUTES,MINI,ONE_TIME_RUN,10
|
||||
MORE_MINUTES,SHARED,ONE_TIME_RUN,10
|
||||
TOPUP10_AT,TOPUP10_AC,ASAP,10
|
||||
TOPUP1000UKMOB_AT,TOPUP1000UKMOB_AC,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
|
||||
`
|
||||
accountActions = `
|
||||
vdf,minitsboy;a1;a2,*out,MORE_MINUTES,STANDARD_TRIGGER
|
||||
cgrates.directvoip.co.uk,12345,*out,TOPUP10_AT,STANDARD_TRIGGERS
|
||||
cgrates.directvoip.co.uk,12345,*out,TOPUP1000UKMOB_AT,STANDARD_TRIGGERS
|
||||
`
|
||||
)
|
||||
|
||||
var csvr *CSVReader
|
||||
|
||||
func init() {
|
||||
csvr = NewStringCSVReader(dataStorage, accountingStorage, ',', destinations, timings, rates, destinationRates, destinationRateTimings, ratingProfiles, sharedGroups, actions, actionTimings, actionTriggers, accountActions)
|
||||
csvr = NewStringCSVReader(dataStorage, accountingStorage, ',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, sharedGroups, actions, actionTimings, actionTriggers, accountActions)
|
||||
csvr.LoadDestinations()
|
||||
csvr.LoadTimings()
|
||||
csvr.LoadRates()
|
||||
@@ -154,7 +174,7 @@ func init() {
|
||||
}
|
||||
|
||||
func TestLoadDestinations(t *testing.T) {
|
||||
if len(csvr.destinations) != 9 {
|
||||
if len(csvr.destinations) != 10 {
|
||||
t.Error("Failed to load destinations: ", len(csvr.destinations))
|
||||
}
|
||||
for _, d := range csvr.destinations {
|
||||
@@ -195,14 +215,12 @@ func TestLoadDestinations(t *testing.T) {
|
||||
if !reflect.DeepEqual(d.Prefixes, []string{`+4970`}) {
|
||||
t.Error("Faild to load destinations", d)
|
||||
}
|
||||
default:
|
||||
t.Error("Unknown destination tag!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTimimgs(t *testing.T) {
|
||||
if len(csvr.timings) != 4 {
|
||||
if len(csvr.timings) != 6 {
|
||||
t.Error("Failed to load timings: ", csvr.timings)
|
||||
}
|
||||
timing := csvr.timings["WORKDAYS_00"]
|
||||
@@ -252,7 +270,7 @@ func TestLoadTimimgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadRates(t *testing.T) {
|
||||
if len(csvr.rates) != 9 {
|
||||
if len(csvr.rates) != 11 {
|
||||
t.Error("Failed to load rates: ", csvr.rates)
|
||||
}
|
||||
rate := csvr.rates["R1"].RateSlots[0]
|
||||
@@ -322,7 +340,7 @@ func TestLoadRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadDestinationRates(t *testing.T) {
|
||||
if len(csvr.destinationRates) != 7 {
|
||||
if len(csvr.destinationRates) != 9 {
|
||||
t.Error("Failed to load destinationrates: ", csvr.destinationRates)
|
||||
}
|
||||
drs := csvr.destinationRates["RT_STANDARD"]
|
||||
@@ -434,7 +452,7 @@ func TestLoadDestinationRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadDestinationRateTimings(t *testing.T) {
|
||||
if len(csvr.ratingPlans) != 7 {
|
||||
if len(csvr.ratingPlans) != 9 {
|
||||
t.Error("Failed to load rate timings: ", csvr.ratingPlans)
|
||||
}
|
||||
rplan := csvr.ratingPlans["STANDARD"]
|
||||
@@ -554,7 +572,7 @@ func TestLoadDestinationRateTimings(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadRatingProfiles(t *testing.T) {
|
||||
if len(csvr.ratingProfiles) != 12 {
|
||||
if len(csvr.ratingProfiles) != 14 {
|
||||
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
|
||||
}
|
||||
rp := csvr.ratingProfiles["*out:test:0:trp"]
|
||||
@@ -572,7 +590,7 @@ func TestLoadRatingProfiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActions(t *testing.T) {
|
||||
if len(csvr.actions) != 2 {
|
||||
if len(csvr.actions) != 4 {
|
||||
t.Error("Failed to load actions: ", csvr.actions)
|
||||
}
|
||||
as1 := csvr.actions["MINI"]
|
||||
@@ -681,7 +699,7 @@ func TestLoadSharedGroups(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActionTimings(t *testing.T) {
|
||||
if len(csvr.actionsTimings) != 1 {
|
||||
if len(csvr.actionsTimings) != 3 {
|
||||
t.Error("Failed to load action timings: ", csvr.actionsTimings)
|
||||
}
|
||||
atm := csvr.actionsTimings["MORE_MINUTES"][0]
|
||||
@@ -707,7 +725,7 @@ func TestLoadActionTimings(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadActionTriggers(t *testing.T) {
|
||||
if len(csvr.actionsTriggers) != 1 {
|
||||
if len(csvr.actionsTriggers) != 2 {
|
||||
t.Error("Failed to load action triggers: ", csvr.actionsTriggers)
|
||||
}
|
||||
atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0]
|
||||
@@ -743,8 +761,8 @@ func TestLoadActionTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadAccountActions(t *testing.T) {
|
||||
if len(csvr.accountActions) != 1 {
|
||||
t.Error("Failed to load account actions: ", csvr.accountActions)
|
||||
if len(csvr.accountActions) != 3 {
|
||||
t.Error("Failed to load account actions: ", csvr.accountActions[2])
|
||||
}
|
||||
aa := csvr.accountActions[0]
|
||||
expected := &Account{
|
||||
|
||||
Reference in New Issue
Block a user