diff --git a/engine/account.go b/engine/account.go index 961cd471c..53eac07fc 100644 --- a/engine/account.go +++ b/engine/account.go @@ -236,27 +236,27 @@ func (ub *Account) debitCreditBalance(cc *CallCost, count bool) (err error) { } CONNECT_FEE: if cc.deductConnectFee { - amount := cc.GetConnectFee() + connectFee := cc.GetConnectFee() connectFeePaid := false for _, b := range usefulMoneyBalances { - if b.Value >= amount { - b.Value -= amount + if b.Value >= connectFee { + b.Value -= connectFee b.Value = utils.Round(b.Value, roundingDecimals, utils.ROUNDING_MIDDLE) // the conect fee is not refundable! if count { - ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationId: cc.Destination}}) } connectFeePaid = true break } } // debit connect fee - if cc.GetConnectFee() > 0 && !connectFeePaid { + if connectFee > 0 && !connectFeePaid { // there are no money for the connect fee; go negative - defaultMoneyBalance.Value -= amount + defaultMoneyBalance.Value -= connectFee // the conect fee is not refundable! if count { - ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) + ub.countUnits(&Action{BalanceType: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: connectFee, DestinationId: cc.Destination}}) } } } diff --git a/engine/account_test.go b/engine/account_test.go index 9894129ff..fe98fb1b8 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -217,8 +217,8 @@ func TestDebitCreditZeroSecond(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - t.Logf("%+v", cc.Timespans[0]) if cc.Timespans[0].Increments[0].BalanceInfo.MinuteBalanceUuid != "testb" { + t.Logf("%+v", cc.Timespans[0]) t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } if rifsBalance.BalanceMap[MINUTES+OUTBOUND][0].Value != 0 || @@ -550,9 +550,9 @@ func TestDebitCreditMoneyOnly(t *testing.T) { if err == nil { t.Error("Missing noy enough credit error ") } - t.Logf("%+v", cc.Timespans[0].Increments) if cc.Timespans[0].Increments[0].BalanceInfo.MoneyBalanceUuid != "money" || cc.Timespans[0].Increments[0].Duration != 10*time.Second { + t.Logf("%+v", cc.Timespans[0].Increments) t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0].BalanceInfo) } if rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != -30 { diff --git a/engine/actions_test.go b/engine/actions_test.go index 573854031..73c1eeced 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -124,11 +124,11 @@ func TestActionTimingOnlyMonths(t *testing.T) { y, m, _ := now.Date() nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - t.Log("NextMonth: ", nextMonth) at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(nextMonth.Year(), nextMonth.Month(), 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { + t.Log("NextMonth: ", nextMonth) t.Errorf("Expected %v was %v", expected, st) } } @@ -978,6 +978,29 @@ func TestTopupAction(t *testing.T) { } } +func TestTopupActionLoaded(t *testing.T) { + initialUb, _ := accountingStorage.GetAccount("*out:vdf:minitsboy") + a := &Action{ + ActionType: "*topup", + BalanceType: CREDIT, + Direction: OUTBOUND, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + } + + at := &ActionTiming{ + AccountIds: []string{"*out:vdf:minitsboy"}, + actions: Actions{a}, + } + + at.Execute() + afterUb, _ := accountingStorage.GetAccount("*out:vdf:minitsboy") + initialValue := initialUb.BalanceMap[CREDIT+OUTBOUND].GetTotalValue() + afterValue := afterUb.BalanceMap[CREDIT+OUTBOUND].GetTotalValue() + if initialValue != 100 || afterValue != 125 { + t.Error("Bad topup before and after: ", initialValue, afterValue) + } +} + /********************************** Benchmarks ********************************/ func BenchmarkUUID(b *testing.B) { diff --git a/engine/callcost.go b/engine/callcost.go index f5b4f0ede..41cdd5ba6 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -33,7 +33,11 @@ type CallCost struct { // Pretty printing for call cost func (cc *CallCost) String() (r string) { - r = fmt.Sprintf("%v[%v] : %s(%s) -> %s (", cc.Cost, cc.GetConnectFee(), cc.Subject, cc.Account, cc.Destination) + connectFee := 0.0 + if cc.deductConnectFee { + connectFee = cc.GetConnectFee() + } + r = fmt.Sprintf("%v[%v] : %s(%s) - > %s (", cc.Cost, connectFee, cc.Subject, cc.Account, cc.Destination) for _, ts := range cc.Timespans { r += fmt.Sprintf(" %v,", ts.GetDuration()) } diff --git a/engine/calldesc.go b/engine/calldesc.go index fbb70a735..cf56d7aec 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -473,7 +473,9 @@ func (origCD *CallDescriptor) GetMaxSessionDuration() (time.Duration, error) { cd.TimeStart = cd.TimeStart.Add(availableDuration) // substract the connect fee cc, err := cd.GetCost() - availableCredit -= cc.GetConnectFee() + if cc.deductConnectFee { + availableCredit -= cc.GetConnectFee() + } if err != nil { Logger.Err(fmt.Sprintf("Could not get cost for %s: %s.", cd.GetKey(cd.Subject), err.Error())) return 0, err @@ -516,11 +518,14 @@ func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { //Logger.Debug(fmt.Sprintf("Account: %s", ub)) //cCost, _ := json.Marshal(cc) //Logger.Debug(fmt.Sprintf("CallCost: %s", cCost)) - if cc.Cost != 0 || cc.GetConnectFee() != 0 { + if cc.Cost != 0 || (cc.deductConnectFee && cc.GetConnectFee() != 0) { userBalance.debitCreditBalance(cc, true) } cost := 0.0 // re-calculate call cost after balances + if cc.deductConnectFee { // add back the connectFee + cost += cc.GetConnectFee() + } for _, ts := range cc.Timespans { cost += ts.getCost() cost = utils.Round(cost, roundingDecimals, utils.ROUNDING_MIDDLE) // just get rid of the extra decimals diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 63160064b..bfd330919 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -62,11 +62,25 @@ func populateDB() { &Balance{Value: 100, DestinationId: "RET", Weight: 20}, }}, } + // this is added to test if csv load tests account will not overwrite balances + minitsboy := &Account{ + Id: "*out:vdf:minitsboy", + BalanceMap: map[string]BalanceChain{ + MINUTES + OUTBOUND: BalanceChain{ + &Balance{Value: 20, DestinationId: "NAT", Weight: 10, RateSubject: "rif"}, + &Balance{Value: 100, DestinationId: "RET", Weight: 20}, + }, + CREDIT + OUTBOUND: BalanceChain{ + &Balance{Value: 100, Weight: 10}, + }, + }, + } if accountingStorage != nil { accountingStorage.SetActions("TEST_ACTIONS", ats) accountingStorage.SetActions("TEST_ACTIONS_ORDER", ats1) accountingStorage.SetAccount(broker) accountingStorage.SetAccount(minu) + accountingStorage.SetAccount(minitsboy) } else { log.Fatal("Could not connect to db!") } @@ -91,16 +105,15 @@ func TestSplitSpansRoundToIncrements(t *testing.T) { cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second} cd.LoadRatingPlans() - t.Logf("%+v", cd) timespans := cd.splitInTimeSpans(nil) if len(timespans) != 2 { + t.Logf("%+v", cd) t.Log(cd.RatingInfos) t.Error("Wrong number of timespans: ", len(timespans)) } var d time.Duration for _, ts := range timespans { d += ts.GetDuration() - t.Log(ts.GetDuration()) } if d != 132*time.Second { t.Error("Wrong duration for timespans: ", d) diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 7802d7a25..8cee2496e 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -754,6 +754,16 @@ func TestLoadAccountActions(t *testing.T) { if !reflect.DeepEqual(aa, expected) { t.Error("Error loading account action: ", aa) } + // test that it does not overwrite balances + existing, err := accountingStorage.GetAccount(aa.Id) + if err != nil || len(existing.BalanceMap) != 2 { + t.Errorf("The account was not set before load: %+v", existing) + } + accountingStorage.SetAccount(aa) + existing, err = accountingStorage.GetAccount(aa.Id) + if err != nil || len(existing.BalanceMap) != 2 { + t.Errorf("The set account altered the balances: %+v", existing) + } } func TestLoadAliases(t *testing.T) { diff --git a/engine/ratingplan_test.go b/engine/ratingplan_test.go index 3b7fa2747..46876af3b 100644 --- a/engine/ratingplan_test.go +++ b/engine/ratingplan_test.go @@ -174,7 +174,6 @@ func TestApAddIntervalIfNotPresent(t *testing.T) { if len(rp.DestinationRates["NAT"]) != 1 { t.Error("Wronfullyrppended interval ;)") } - t.Log() rp.AddRateInterval("NAT", i3) if len(rp.DestinationRates["NAT"]) != 2 { t.Error("Wronfully not appended interval ;)", rp.DestinationRates)