diff --git a/engine/account.go b/engine/account.go index 4b01a213e..5d2e6dac9 100644 --- a/engine/account.go +++ b/engine/account.go @@ -208,7 +208,7 @@ func (account *Account) getAlldBalancesForPrefix(destination, category, balanceT return } -func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bool) (cc *CallCost, err error) { +func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bool, goNegative bool) (cc *CallCost, err error) { usefulUnitBalances := ub.getAlldBalancesForPrefix(cd.Destination, cd.Category, cd.TOR+cd.Direction) usefulMoneyBalances := ub.getAlldBalancesForPrefix(cd.Destination, cd.Category, CREDIT+cd.Direction) //log.Print(usefulMoneyBalances, usefulUnitBalances) @@ -240,7 +240,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo ub.DebitConnectionFee(cc, usefulMoneyBalances, count) } // for i, ts := range cc.Timespans { - // log.Printf("cc.times[an[%d]: %+v\n", i, ts) + // log.Printf("cc.times[an[%d]: %+v\n", i, ts) // } cd.TimeStart = cc.GetEndTime() //log.Printf("CD: %+v", cd) @@ -302,25 +302,27 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo // this is the first add, debit the connect fee ub.DebitConnectionFee(cc, usefulMoneyBalances, count) } - //log.Printf("Left CC: %+v", leftCC) - // get the default money balanance - // and go negative on it with the amount still unpaid - for _, ts := range leftCC.Timespans { - if ts.Increments == nil { - ts.createIncrementsSlice() + if leftCC.Cost == 0 || goNegative { + //log.Printf("Left CC: %+v", leftCC) + // get the default money balanance + // and go negative on it with the amount still unpaid + if len(leftCC.Timespans) > 0 && leftCC.Cost > 0 && !ub.AllowNegative { + err = errors.New("not enough credit") } - for _, increment := range ts.Increments { - cost := increment.Cost - defaultBalance := ub.GetDefaultMoneyBalance(leftCC.Direction) - defaultBalance.SubstractAmount(cost) - increment.BalanceInfo.MoneyBalanceUuid = defaultBalance.Uuid - increment.BalanceInfo.AccountId = ub.Id - increment.paid = true - if count { - ub.countUnits(&Action{BalanceType: CREDIT, Direction: leftCC.Direction, Balance: &Balance{Value: cost, DestinationId: leftCC.Destination}}) + for _, ts := range leftCC.Timespans { + if ts.Increments == nil { + ts.createIncrementsSlice() } - if !ub.AllowNegative { - err = errors.New("not enough credit") + for _, increment := range ts.Increments { + cost := increment.Cost + defaultBalance := ub.GetDefaultMoneyBalance(leftCC.Direction) + defaultBalance.SubstractAmount(cost) + increment.BalanceInfo.MoneyBalanceUuid = defaultBalance.Uuid + increment.BalanceInfo.AccountId = ub.Id + increment.paid = true + if count { + ub.countUnits(&Action{BalanceType: CREDIT, Direction: leftCC.Direction, Balance: &Balance{Value: cost, DestinationId: leftCC.Destination}}) + } } } } diff --git a/engine/account_test.go b/engine/account_test.go index a8809d8bb..c5f392239 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -185,7 +185,7 @@ func TestDebitCreditZeroSecond(t *testing.T) { } rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1}, CREDIT + OUTBOUND: BalanceChain{&Balance{Category: "0", Value: 21}}}} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -228,7 +228,7 @@ func TestDebitCreditZeroMinute(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -275,7 +275,7 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -326,7 +326,7 @@ func TestDebitCreditNoCredit(t *testing.T) { MINUTES + OUTBOUND: BalanceChain{b1}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { t.Error("Showing no enough credit error ") } @@ -378,7 +378,7 @@ func TestDebitCreditHasCredit(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 110}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -426,7 +426,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 50}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -478,7 +478,7 @@ func TestDebitCreditMoreTimespans(t *testing.T) { MINUTES + OUTBOUND: BalanceChain{b1}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -527,7 +527,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) { MINUTES + OUTBOUND: BalanceChain{b1, b2}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -577,7 +577,7 @@ func TestDebitCreditNoConectFeeCredit(t *testing.T) { MINUTES + OUTBOUND: BalanceChain{b1}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { t.Error("Error showing debiting balance error: ", err) } @@ -621,7 +621,7 @@ func TestDebitCreditMoneyOnly(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "money", Value: 50}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { t.Error("Missing noy enough credit error ") } @@ -675,7 +675,7 @@ func TestDebitCreditSubjectMinutes(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 350}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -729,7 +729,7 @@ func TestDebitCreditSubjectMoney(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 75, DestinationId: "NAT", RatingSubject: "minu"}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -780,7 +780,7 @@ func TestDebitCreditSubjectMoney(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 19500, RatingSubject: "minu"}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -842,7 +842,7 @@ func TestDebitCreditSubjectMixedMoreTS(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 50, RatingSubject: "minu"}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { t.Error("Error showing debiting balance error: ", err) } @@ -906,7 +906,7 @@ func TestDebitCreditSubjectMixedPartPay(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Uuid: "moneya", Value: 75, RatingSubject: "minu"}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { t.Error("Error showing debiting balance error: ", err) } @@ -1173,7 +1173,7 @@ func TestDebitShared(t *testing.T) { accountingStorage.SetAccount(groupie) accountingStorage.SetSharedGroup(sg) cache2go.Cache(SHARED_GROUP_PREFIX+"SG_TEST", sg) - cc, err := rif.debitCreditBalance(cd, false, false) + cc, err := rif.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -1233,7 +1233,7 @@ func TestDebitSMS(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -1283,7 +1283,7 @@ func TestDebitDataUnits(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } @@ -1332,7 +1332,7 @@ func TestDebitDataMoney(t *testing.T) { CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 160}}, }} var err error - cc, err = rifsBalance.debitCreditBalance(cd, false, false) + cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { t.Error("Error debiting balance: ", err) } diff --git a/engine/calldesc.go b/engine/calldesc.go index f0db7f388..2c2e8fd2c 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -464,7 +464,7 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura } cd := origCD.Clone() initialDuration := cd.TimeEnd.Sub(cd.TimeStart) - cc, _ := cd.debit(account, true) + cc, _ := cd.debit(account, true, false) //log.Printf("CC: %+v", cc) @@ -526,7 +526,7 @@ func (cd *CallDescriptor) GetMaxSessionDuration() (duration time.Duration, err e // Interface method used to add/substract an amount of cents or bonus seconds (as returned by GetCost method) // from user's money balance. -func (cd *CallDescriptor) debit(account *Account, dryRun bool) (cc *CallCost, err error) { +func (cd *CallDescriptor) debit(account *Account, dryRun bool, goNegative bool) (cc *CallCost, err error) { if !dryRun { defer accountingStorage.SetAccount(account) } @@ -534,7 +534,7 @@ func (cd *CallDescriptor) debit(account *Account, dryRun bool) (cc *CallCost, er cd.TOR = MINUTES } //log.Printf("Debit CD: %+v", cd) - cc, err = account.debitCreditBalance(cd, !dryRun, dryRun) + cc, err = account.debitCreditBalance(cd, !dryRun, dryRun, goNegative) //log.Print("HERE: ", cc, err) if err != nil { Logger.Err(fmt.Sprintf(" Error getting cost for account key %v: %v", cd.GetAccountKey(), err)) @@ -563,7 +563,7 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { } else { if memberIds, err := account.GetUniqueSharedGroupMembers(cd.Destination, cd.Direction, cd.Category, cd.TOR); err == nil { AccLock.GuardMany(memberIds, func() (float64, error) { - cc, err = cd.debit(account, false) + cc, err = cd.debit(account, false, true) return 0, err }) } else { @@ -597,7 +597,7 @@ func (cd *CallDescriptor) MaxDebit() (cc *CallCost, err error) { cd.TimeEnd = cd.TimeStart.Add(remainingDuration) cd.DurationIndex -= initialDuration - remainingDuration } - cc, err = cd.debit(account, false) + cc, err = cd.debit(account, false, true) //log.Print(balanceMap[0].Value, balanceMap[1].Value) return 0, err }) diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 1210e3cc5..ffcf050ab 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -523,7 +523,10 @@ func TestMaxSessionModifiesCallDesc(t *testing.T) { TOR: MINUTES, } initial := cd.Clone() - cd.GetMaxSessionDuration() + _, err := cd.GetMaxSessionDuration() + if err != nil { + t.Error("Got error from max duration: ", err) + } cd.account = nil // it's OK to cache the account if !reflect.DeepEqual(cd, initial) { t.Errorf("GetMaxSessionDuration is changing the call descriptor %+v != %+v", cd, initial) @@ -542,7 +545,10 @@ func TestMaxDebitDurationNoGreatherThanInitialDuration(t *testing.T) { Destination: "0723", } initialDuration := cd.TimeEnd.Sub(cd.TimeStart) - result, _ := cd.GetMaxSessionDuration() + result, err := cd.GetMaxSessionDuration() + if err != nil { + t.Error("Got error from max duration: ", err) + } if result > initialDuration { t.Error("max session duration greather than initial duration", initialDuration, result) }