diff --git a/engine/account.go b/engine/account.go index 1e34d2e3c..386bfd32d 100644 --- a/engine/account.go +++ b/engine/account.go @@ -416,6 +416,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo if debitErr != nil { return nil, debitErr } + //utils.Logger.Info(fmt.Sprintf("CD AFTER UNIT: %+v", cd)) if partCC != nil { //log.Printf("partCC: %+v", partCC.Timespans[0]) @@ -511,9 +512,13 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo if leftCC.Cost > 0 && goNegative { initialLength := len(cc.Timespans) cc.Timespans = append(cc.Timespans, leftCC.Timespans...) + + var debitedConnectFeeBalance Balance + var ok bool + if initialLength == 0 { // this is the first add, debit the connect fee - ub.DebitConnectionFee(cc, usefulMoneyBalances, count, true) + ok, debitedConnectFeeBalance = ub.DebitConnectionFee(cc, usefulMoneyBalances, count, true) } //log.Printf("Left CC: %+v ", leftCC) // get the default money balanance @@ -522,11 +527,37 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo utils.Logger.Err(fmt.Sprintf(" Going negative on account %s with AllowNegative: false", cd.GetAccountKey())) } leftCC.Timespans.Decompress() - for _, ts := range leftCC.Timespans { + for tsIndex, ts := range leftCC.Timespans { if ts.Increments == nil { ts.createIncrementsSlice() } - for _, increment := range ts.Increments { + + if tsIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && cc.deductConnectFee && ok { + + inc := &Increment{ + Duration: 0, + Cost: ts.RateInterval.Rating.ConnectFee, + BalanceInfo: &DebitInfo{ + Monetary: &MonetaryInfo{ + UUID: debitedConnectFeeBalance.Uuid, + ID: debitedConnectFeeBalance.ID, + Value: debitedConnectFeeBalance.Value, + }, + AccountID: ub.ID, + }, + } + + incs := []*Increment{inc} + ts.Increments = append(incs, ts.Increments...) + } + + for incIndex, increment := range ts.Increments { + + if tsIndex == 0 && incIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && cc.deductConnectFee && ok { + // go to nextincrement + continue + } + cost := increment.Cost defaultBalance := ub.GetDefaultMoneyBalance() defaultBalance.SubstractValue(cost) @@ -823,7 +854,9 @@ func (acc *Account) Clone() *Account { return newAcc } -func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balances, count bool, block bool) bool { +func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balances, count bool, block bool) (bool, Balance) { + var debitedBalance Balance + if cc.deductConnectFee { connectFee := cc.GetConnectFee() //log.Print("CONNECT FEE: %f", connectFee) @@ -836,10 +869,11 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance acc.countUnits(connectFee, utils.MONETARY, cc, b) } connectFeePaid = true + debitedBalance = *b break } if b.Blocker && block { // stop here - return false + return false, debitedBalance } } // debit connect fee @@ -848,13 +882,14 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance // there are no money for the connect fee; go negative b := acc.GetDefaultMoneyBalance() b.SubstractValue(connectFee) + debitedBalance = *b // the conect fee is not refundable! if count { acc.countUnits(connectFee, utils.MONETARY, cc, b) } } } - return true + return true, debitedBalance } func (acc *Account) matchActionFilter(condition string) (bool, error) { diff --git a/engine/balances.go b/engine/balances.go index b96be9b56..7db4de777 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -385,13 +385,15 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala } else { // get the cost from balance //log.Printf("::::::: %+v", cd) + var debitedConnectFeeBalance Balance + var ok bool cc, err = b.GetCost(cd, true) if err != nil { return nil, err } if debitConnectFee { // this is the first add, debit the connect fee - if ub.DebitConnectionFee(cc, moneyBalances, count, true) == false { + if ok, debitedConnectFeeBalance = ub.DebitConnectionFee(cc, moneyBalances, count, true); !ok { // found blocker balance return nil, nil } @@ -408,8 +410,34 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala utils.Logger.Err(fmt.Sprintf("Nil RateInterval ERROR on TS: %+v, CC: %+v, from CD: %+v", ts, cc, cd)) return nil, errors.New("timespan with no rate interval assigned") } + + if tsIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && debitConnectFee && cc.deductConnectFee && ok { + + inc := &Increment{ + Duration: 0, + Cost: ts.RateInterval.Rating.ConnectFee, + BalanceInfo: &DebitInfo{ + Monetary: &MonetaryInfo{ + UUID: debitedConnectFeeBalance.Uuid, + ID: debitedConnectFeeBalance.ID, + Value: debitedConnectFeeBalance.Value, + }, + AccountID: ub.ID, + }, + } + + incs := []*Increment{inc} + ts.Increments = append(incs, ts.Increments...) + } + maxCost, strategy := ts.RateInterval.GetMaxCost() for incIndex, inc := range ts.Increments { + + if tsIndex == 0 && incIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && debitConnectFee && cc.deductConnectFee && ok { + // go to nextincrement + continue + } + // debit minutes and money amount := inc.Duration.Seconds() if b.Factor != nil { @@ -513,10 +541,14 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala if err != nil { return nil, err } + + var debitedConnectFeeBalance Balance + var ok bool //log.Print("cc: " + utils.ToJSON(cc)) if debitConnectFee { + // this is the first add, debit the connect fee - if ub.DebitConnectionFee(cc, moneyBalances, count, true) == false { + if ok, debitedConnectFeeBalance = ub.DebitConnectionFee(cc, moneyBalances, count, true); !ok { // balance is blocker return nil, nil } @@ -536,12 +568,38 @@ func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances Bala utils.Logger.Err(fmt.Sprintf("Nil RateInterval ERROR on TS: %+v, CC: %+v, from CD: %+v", ts, cc, cd)) return nil, errors.New("timespan with no rate interval assigned") } + + if tsIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && debitConnectFee && cc.deductConnectFee && ok { + + inc := &Increment{ + Duration: 0, + Cost: ts.RateInterval.Rating.ConnectFee, + BalanceInfo: &DebitInfo{ + Monetary: &MonetaryInfo{ + UUID: debitedConnectFeeBalance.Uuid, + ID: debitedConnectFeeBalance.ID, + Value: debitedConnectFeeBalance.Value, + }, + AccountID: ub.ID, + }, + } + + incs := []*Increment{inc} + ts.Increments = append(incs, ts.Increments...) + } + maxCost, strategy := ts.RateInterval.GetMaxCost() //log.Printf("Timing: %+v", ts.RateInterval.Timing) //log.Printf("Rate: %+v", ts.RateInterval.Rating) for incIndex, inc := range ts.Increments { // check standard subject tags //log.Printf("INC: %+v", inc) + + if tsIndex == 0 && incIndex == 0 && ts.RateInterval.Rating.ConnectFee > 0 && cc.deductConnectFee && ok { + // go to nextincrement + continue + } + amount := inc.Cost inc.paid = false if strategy == utils.MAX_COST_DISCONNECT && cd.MaxCostSoFar >= maxCost { diff --git a/engine/callcost.go b/engine/callcost.go index 5e4ee8c75..b0899d32b 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -169,9 +169,9 @@ func (cc *CallCost) UpdateCost() { func (cc *CallCost) updateCost() { cost := 0.0 - if cc.deductConnectFee { // add back the connectFee - cost += cc.GetConnectFee() - } + //if cc.deductConnectFee { // add back the connectFee + // cost += cc.GetConnectFee() + //} for _, ts := range cc.Timespans { ts.Cost = ts.CalculateCost() cost += ts.Cost diff --git a/engine/calldesc.go b/engine/calldesc.go index 9df42331d..66ea9d1f0 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -370,6 +370,7 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { } //log.Printf("After SplitByRatingPlan: %+v", utils.ToJSON(timespans)) // split on days + for i := 0; i < len(timespans); i++ { rp := timespans[i].ratingInfo newTs := timespans[i].SplitByDay() @@ -386,6 +387,7 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) { } //log.Printf("After SplitByDay: %+v", utils.ToJSON(timespans)) // split on rate intervals + for i := 0; i < len(timespans); i++ { //log.Printf("==============%v==================", i) //log.Printf("TS: %+v", timespans[i]) @@ -501,6 +503,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) { } func (cd *CallDescriptor) getCost() (*CallCost, error) { + // check for 0 duration if cd.GetDuration() == 0 { cc := cd.CreateCallCost() diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 777134d9d..9326306d9 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -1425,6 +1425,7 @@ func TestMaxDebitZeroDefinedRate(t *testing.T) { if cc.GetDuration() != 49*time.Second { t.Error("Error obtaining max debit duration: ", cc.GetDuration()) } + if cc.Cost != 0.91 { t.Error("Error in max debit cost: ", cc.Cost) } diff --git a/engine/timespans.go b/engine/timespans.go index 4d18af209..6e65ca21a 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -696,7 +696,15 @@ func (nts *TimeSpan) copyRatingInfo(ts *TimeSpan) { // returns a time for the specified second in the time span func (ts *TimeSpan) GetTimeStartForIncrement(index int) time.Time { - return ts.TimeStart.Add(time.Duration(int64(index) * ts.Increments[0].Duration.Nanoseconds())) + + start := ts.TimeStart + for incIndex, inc := range ts.Increments { + if incIndex < index { + start = start.Add(time.Duration(inc.Duration.Nanoseconds())) + } + } + return start + //return ts.TimeStart.Add(time.Duration(int64(index) * ts.Increments[0].Duration.Nanoseconds())) } func (ts *TimeSpan) RoundToDuration(duration time.Duration) { diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index 0b1619f2c..5eb69a971 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -141,6 +141,7 @@ func (self *SMGSession) debit(dur time.Duration, lastUsed *time.Duration) (time. // Attempts to refund a duration, error on failure func (self *SMGSession) refund(refundDuration time.Duration) error { + if refundDuration == 0 { // Nothing to refund return nil } @@ -154,12 +155,16 @@ func (self *SMGSession) refund(refundDuration time.Duration) error { if refundDuration <= tsDuration { lastRefundedIncrementIndex := -1 + for j := len(ts.Increments) - 1; j >= 0; j-- { increment := ts.Increments[j] + if increment.Duration <= refundDuration { + refundIncrements = append(refundIncrements, increment) refundDuration -= increment.Duration lastRefundedIncrementIndex = j + } else { break //increment duration is larger, cannot refund increment }