diff --git a/engine/calldesc.go b/engine/calldesc.go index 2d55812bb..9d6e81c1d 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -150,13 +150,14 @@ type CallDescriptor struct { TOR string // used unit balances selector ExtraFields map[string]string // Extra fields, mostly used for user profile matching // session limits - MaxRate float64 - MaxRateUnit time.Duration - MaxCostSoFar float64 - CgrID string - RunID string - account *Account - testCallcost *CallCost // testing purpose only! + MaxRate float64 + MaxRateUnit time.Duration + MaxCostSoFar float64 + CgrID string + RunID string + ForceDuration bool // for Max debit if less than duration return err + account *Account + testCallcost *CallCost // testing purpose only! } func (cd *CallDescriptor) ValidateCallData() error { @@ -728,9 +729,16 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) { return nil, utils.ErrAccountNotFound } else { //log.Printf("ACC: %+v", account) - if memberIds, err := account.GetUniqueSharedGroupMembers(cd); err == nil { + if memberIDs, err := account.GetUniqueSharedGroupMembers(cd); err == nil { _, err = Guardian.Guard(func() (interface{}, error) { remainingDuration, err := cd.getMaxSessionDuration(account) + if err != nil && cd.GetDuration() > 0 { + return 0, err + } + // check ForceDuartion + if cd.ForceDuration && !account.AllowNegative && remainingDuration < cd.GetDuration() { + return 0, utils.ErrInsufficientCredit + } //log.Print("AFTER MAX SESSION: ", cd) if err != nil || remainingDuration == 0 { cc = cd.CreateCallCost() @@ -758,7 +766,7 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) { cc, err = cd.debit(account, false, true) //log.Print(balanceMap[0].Value, balanceMap[1].Value) return 0, err - }, 0, memberIds.Slice()...) + }, 0, memberIDs.Slice()...) if err != nil { return cc, err } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 9f174dc4f..8e1fe8ac0 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -1271,6 +1271,31 @@ func TestMaxDebitZeroDefinedRate(t *testing.T) { } } +func TestMaxDebitForceDuration(t *testing.T) { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs + at.Execute() + } + cd1 := &CallDescriptor{ + Direction: "*out", + Category: "call", + Tenant: "cgrates.org", + 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, 40, 0, time.UTC), + LoopIndex: 0, + DurationIndex: 0, + ForceDuration: true, + } + _, err := cd1.MaxDebit() + if err != utils.ErrInsufficientCredit { + t.Fatal("Error forcing duration: ", err) + } +} + func TestMaxDebitZeroDefinedRateOnlyMinutes(t *testing.T) { ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) for _, at := range ap.ActionTimings { diff --git a/utils/consts.go b/utils/consts.go index 42ce00d04..904c177a4 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -29,7 +29,7 @@ var ( ErrRatingPlanNotFound = errors.New("RATING_PLAN_NOT_FOUND") ErrAccountNotFound = errors.New("ACCOUNT_NOT_FOUND") ErrUserNotFound = errors.New("USER_NOT_FOUND") - ErrCreditInsufficient = errors.New("CREDIT_INSUFFICIENT") + ErrInsufficientCredit = errors.New("INSUFFICENT_CREDIT") ) const (