/* Returns the approximate max allowed session for user balance. It will try the max amount received in the call descriptor If the user has no credit then it will return 0. If the user has postpayed plan it returns -1. */ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Duration, error) { // clone the account for discarding chenges on debit dry run //log.Printf("ORIG CD: %+v", origCD) account := origAcc.Clone() if account.AllowNegative { return -1, nil } // for zero duration index if origCD.DurationIndex < origCD.TimeEnd.Sub(origCD.TimeStart) { origCD.DurationIndex = origCD.TimeEnd.Sub(origCD.TimeStart) } if origCD.TOR == "" { origCD.TOR = utils.VOICE } cd := origCD.Clone() initialDuration := cd.TimeEnd.Sub(cd.TimeStart) defaultBalance := account.GetDefaultMoneyBalance() //use this to check what increment was payed with debt initialDefaultBalanceValue := defaultBalance.GetValue() cc, err := cd.debit(account, true, false) if err != nil { return 0, err } // not enough credit for connect fee if cc.negativeConnectFee == true { return 0, nil } var totalCost float64 var totalDuration time.Duration cc.Timespans.Decompress() for _, ts := range cc.Timespans { if cd.MaxRate > 0 && cd.MaxRateUnit > 0 { rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() { return utils.MinDuration(initialDuration, totalDuration), nil } } if ts.Increments == nil { ts.createIncrementsSlice() } for _, incr := range ts.Increments { totalCost += incr.Cost if incr.BalanceInfo.Monetary != nil && incr.BalanceInfo.Monetary.UUID == defaultBalance.Uuid { initialDefaultBalanceValue -= incr.Cost if initialDefaultBalanceValue < 0 { // this increment was payed with debt // TODO: improve this check return utils.MinDuration(initialDuration, totalDuration), nil } } totalDuration += incr.Duration //log.Print("INC: ", utils.ToJSON(incr)) if totalDuration >= initialDuration { // we have enough, return return initialDuration, nil } } } return utils.MinDuration(initialDuration, totalDuration), nil }
/* Returns the approximate max allowed session for user balance. It will try the max amount received in the call descriptor If the user has no credit then it will return 0. If the user has postpayed plan it returns -1. */ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Duration, error) { // clone the account for discarding chenges on debit dry run //log.Printf("ORIG CD: %+v", origCD) account := origAcc.Clone() if account.AllowNegative { return -1, nil } if origCD.DurationIndex < origCD.TimeEnd.Sub(origCD.TimeStart) { origCD.DurationIndex = origCD.TimeEnd.Sub(origCD.TimeStart) } if origCD.TOR == "" { origCD.TOR = utils.VOICE } //utils.Logger.Debug("ORIG: " + utils.ToJSON(origCD)) cd := origCD.Clone() initialDuration := cd.TimeEnd.Sub(cd.TimeStart) //utils.Logger.Debug(fmt.Sprintf("INITIAL_DURATION: %v", initialDuration)) defaultBalance := account.GetDefaultMoneyBalance() //use this to check what increment was payed with debt initialDefaultBalanceValue := defaultBalance.GetValue() //utils.Logger.Debug("ACCOUNT: " + utils.ToJSON(account)) //utils.Logger.Debug("DEFAULT_BALANCE: " + utils.ToJSON(defaultBalance)) // cc, err := cd.debit(account, true, false) //utils.Logger.Debug("CC: " + utils.ToJSON(cc)) //log.Print("CC: ", utils.ToIJSON(cc)) //utils.Logger.Debug(fmt.Sprintf("ERR: %v", err)) if err != nil { return 0, err } //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 cc.Timespans.Decompress() //log.Printf("ACC: %+v", account) for _, ts := range cc.Timespans { //if ts.RateInterval != nil { //log.Printf("TS: %+v", ts) //utils.Logger.Debug("TS: " + utils.ToJSON(ts)) //} if cd.MaxRate > 0 && cd.MaxRateUnit > 0 { rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() { //utils.Logger.Debug(fmt.Sprintf("0_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration)) return utils.MinDuration(initialDuration, totalDuration), nil } } if ts.Increments == nil { ts.createIncrementsSlice() } for _, incr := range ts.Increments { //utils.Logger.Debug("INCR: " + utils.ToJSON(incr)) totalCost += incr.Cost if incr.BalanceInfo.MoneyBalanceUuid == defaultBalance.Uuid { initialDefaultBalanceValue -= incr.Cost if initialDefaultBalanceValue < 0 { // this increment was payed with debt // TODO: improve this check //utils.Logger.Debug(fmt.Sprintf("1_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration)) return utils.MinDuration(initialDuration, totalDuration), nil } } totalDuration += incr.Duration if totalDuration >= initialDuration { // we have enough, return //utils.Logger.Debug(fmt.Sprintf("2_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration)) return initialDuration, nil } } } //utils.Logger.Debug(fmt.Sprintf("3_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration)) return utils.MinDuration(initialDuration, totalDuration), nil }
/* Returns the approximate max allowed session for user balance. It will try the max amount received in the call descriptor If the user has no credit then it will return 0. If the user has postpayed plan it returns -1. */ func (origCD *CallDescriptor) getMaxSessionDuration(account *Account) (time.Duration, error) { if origCD.DurationIndex < origCD.TimeEnd.Sub(origCD.TimeStart) { origCD.DurationIndex = origCD.TimeEnd.Sub(origCD.TimeStart) } if origCD.TOR == "" { origCD.TOR = MINUTES } cd := origCD.Clone() //Logger.Debug(fmt.Sprintf("MAX SESSION cd: %+v", cd)) err := cd.LoadRatingPlans() if err != nil { Logger.Err(fmt.Sprintf("error getting cost for key %v: %v", cd.GetAccountKey(), err)) return 0, err } var availableDuration time.Duration availableCredit := 0.0 if account.AllowNegative { return -1, nil } else { availableDuration, availableCredit, _ = account.getCreditForPrefix(cd) // Logger.Debug(fmt.Sprintf("available sec: %v credit: %v", availableSeconds, availableCredit)) } if cd.MaxCost > 0 { // limit availableCredit if cd.MaxCostSoFar+availableCredit > cd.MaxCost { availableCredit = cd.MaxCost - cd.MaxCostSoFar } } //Logger.Debug(fmt.Sprintf("availableDuration: %v, availableCredit: %v", availableDuration, availableCredit)) initialDuration := cd.TimeEnd.Sub(cd.TimeStart) if initialDuration <= availableDuration { // there are enough minutes for requested interval return initialDuration, nil } //Logger.Debug(fmt.Sprintf("initial Duration: %v", initialDuration)) // we must move the timestart for the interval with the available duration because // that was already checked cd.TimeStart = cd.TimeStart.Add(availableDuration) // substract the connect fee cc, err := cd.GetCost() if availableDuration == 0 && cc.deductConnectFee { // only if we did not already used minutes availableCredit -= cc.GetConnectFee() } // check for zero balance if (availableCredit < 0) || (availableCredit == 0 && cc.Cost > 0) { return utils.MinDuration(initialDuration, availableDuration), nil } if err != nil { Logger.Err(fmt.Sprintf("Could not get cost for %s: %s.", cd.GetKey(cd.Subject), err.Error())) return 0, err } // now let's check how many increments are covered with the avilableCredit // also check for max rate/max rate unit for _, ts := range cc.Timespans { ts.createIncrementsSlice() //Logger.Debug(fmt.Sprintf("TS: %+v", ts)) if cd.MaxRate > 0 && cd.MaxRateUnit > 0 { rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() { return availableDuration, nil } } for _, incr := range ts.Increments { if incr.Cost <= availableCredit { availableCredit -= incr.Cost availableDuration += incr.Duration } else { return availableDuration, nil } } } if initialDuration < availableDuration { return initialDuration, nil } return utils.MinDuration(initialDuration, availableDuration), nil }