From aef3bdeb4776ab88888e8a14eb9c021e54416328 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Sun, 15 Nov 2015 21:33:21 +0200 Subject: [PATCH 1/4] connect fee gets debited first --- engine/account.go | 13 ++++++------- engine/account_test.go | 27 +++++++++++++++++++++++++++ engine/balances.go | 14 ++++++++++++-- engine/callcost.go | 1 + engine/calldesc.go | 4 ++++ engine/calldesc_test.go | 3 ++- engine/loader_csv_test.go | 4 +++- 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/engine/account.go b/engine/account.go index 5c5a414bc..49487ec63 100644 --- a/engine/account.go +++ b/engine/account.go @@ -287,15 +287,15 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //log.Printf("Unit balance: %+v", balance) // log.Printf("CD BEFORE UNIT: %+v", cd) - partCC, debitErr := balance.DebitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun) + partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } //log.Printf("CD AFTER UNIT: %+v", cd) if partCC != nil { //log.Printf("partCC: %+v", partCC.Timespans[0]) - initialLength = len(cc.Timespans) cc.Timespans = append(cc.Timespans, partCC.Timespans...) + cc.negativeConnectFee = partCC.negativeConnectFee if initialLength == 0 { // this is the first add, debit the connect fee ub.DebitConnectionFee(cc, usefulMoneyBalances, count) @@ -329,7 +329,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulMoneyBalances { //log.Printf("Money balance: %+v", balance) //log.Printf("CD BEFORE MONEY: %+v", cd) - partCC, debitErr := balance.DebitMoney(cd, balance.account, count, dryRun) + partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, initialLength == 0) if debitErr != nil { return nil, debitErr } @@ -338,10 +338,8 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo if partCC != nil { initialLength = len(cc.Timespans) cc.Timespans = append(cc.Timespans, partCC.Timespans...) - if initialLength == 0 { - // this is the first add, debit the connect fee - ub.DebitConnectionFee(cc, usefulMoneyBalances, count) - } + cc.negativeConnectFee = partCC.negativeConnectFee + //for i, ts := range cc.Timespans { //log.Printf("cc.times[an[%d]: %+v\n", i, ts) //} @@ -682,6 +680,7 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance } // debit connect fee if connectFee > 0 && !connectFeePaid { + cc.negativeConnectFee = true // there are no money for the connect fee; go negative b := acc.GetDefaultMoneyBalance() b.SubstractValue(connectFee) diff --git a/engine/account_test.go b/engine/account_test.go index ab6d7647a..d57aed98e 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -1193,6 +1193,33 @@ func TestMaxDurationShared(t *testing.T) { } +func TestMaxDurationConnectFeeOnly(t *testing.T) { + cd := &CallDescriptor{ + Tenant: "cgrates.org", + Category: "call", + TimeStart: time.Date(2015, 9, 24, 10, 48, 0, 0, time.UTC), + TimeEnd: time.Date(2015, 9, 24, 10, 58, 1, 0, time.UTC), + Direction: utils.OUT, + Destination: "4444", + Subject: "dy", + Account: "dy", + TOR: utils.VOICE, + DurationIndex: 600, + } + rif := &Account{Id: "rif", BalanceMap: map[string]BalanceChain{ + utils.MONETARY: BalanceChain{&Balance{Uuid: "moneya", Value: 0.2}}, + }} + + duration, err := cd.getMaxSessionDuration(rif) + if err != nil { + t.Error("Error getting max session duration: ", err) + } + if duration != 0 { + t.Error("Wrong max session: ", duration) + } + +} + func TestDebitSMS(t *testing.T) { cc := &CallCost{ Direction: utils.OUT, diff --git a/engine/balances.go b/engine/balances.go index 0971f2fde..d667eaf76 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -351,7 +351,7 @@ func (b *Balance) SetValue(amount float64) { b.dirty = true } -func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun bool) (cc *CallCost, err error) { +func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun, debitConnectFee bool) (cc *CallCost, err error) { if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 { return } @@ -431,6 +431,10 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala if err != nil { return nil, err } + if debitConnectFee { + // this is the first add, debit the connect fee + ub.DebitConnectionFee(cc, moneyBalances, count) + } cc.Timespans.Decompress() //log.Printf("CC: %+v", cc) @@ -522,7 +526,7 @@ func (b *Balance) DebitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala return } -func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun bool) (cc *CallCost, err error) { +func (b *Balance) debitMoney(cd *CallDescriptor, ub *Account, moneyBalances BalanceChain, count bool, dryRun, debitConnectFee bool) (cc *CallCost, err error) { if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 { return } @@ -531,6 +535,12 @@ func (b *Balance) DebitMoney(cd *CallDescriptor, ub *Account, count bool, dryRun if err != nil { return nil, err } + + if debitConnectFee { + // this is the first add, debit the connect fee + ub.DebitConnectionFee(cc, moneyBalances, count) + } + cc.Timespans.Decompress() //log.Printf("CallCost In Debit: %+v", cc) //for _, ts := range cc.Timespans { diff --git a/engine/callcost.go b/engine/callcost.go index 178bc2af5..5a9fbeba0 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -31,6 +31,7 @@ type CallCost struct { Cost float64 Timespans TimeSpans deductConnectFee bool + negativeConnectFee bool // the connect fee went negative on default balance maxCostDisconect bool } diff --git a/engine/calldesc.go b/engine/calldesc.go index 752f95445..4664f7ddb 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -564,6 +564,10 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura } //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 diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index c28eb0d69..75926480f 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -1069,8 +1069,9 @@ func TestMaxSesionTimeLongerThanMoney(t *testing.T) { } acc, _ := accountingStorage.GetAccount("cgrates.org:money") allowedTime, err := cd.getMaxSessionDuration(acc) - expected, err := time.ParseDuration("2h46m40s") + expected, err := time.ParseDuration("9999s") // 1 is the connect fee if err != nil || allowedTime != expected { + t.Log(utils.ToIJSON(acc)) t.Errorf("Expected: %v got %v", expected, allowedTime) } } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 9a86b538a..1e5694beb 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -71,6 +71,7 @@ RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s R_URG,0,0,1,1,0 MX,0,1,1s,1s,0 DY,0.15,0.05,60s,1s,0s +CF,1.12,0,1s,1s,0s ` destinationRates = ` RT_STANDARD,GERMANY,R1,*middle,4,0, @@ -93,6 +94,7 @@ RT_URG,URG,R_URG,*middle,4,0, MX_FREE,RET,MX,*middle,4,10,*free MX_DISC,RET,MX,*middle,4,10,*disconnect RT_DY,RET,DY,*up,2,0, +RT_DY,EU_LANDLINE,CF,*middle,4,0, ` ratingPlans = ` STANDARD,RT_STANDARD,WORKDAYS_00,10 @@ -396,7 +398,7 @@ func TestLoadTimimgs(t *testing.T) { } func TestLoadRates(t *testing.T) { - if len(csvr.rates) != 14 { + if len(csvr.rates) != 15 { t.Error("Failed to load rates: ", len(csvr.rates)) } rate := csvr.rates["R1"].RateSlots[0] From 13464460620a49cc89cf74c781265568ceecdf96 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Sun, 15 Nov 2015 21:51:30 +0200 Subject: [PATCH 2/4] migrator for derived chargers --- cmd/cgr-loader/cgr-loader.go | 4 ++++ cmd/cgr-loader/migrator_rc8.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 17c368cd8..740b0ecb3 100644 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -133,6 +133,10 @@ func main() { log.Print(err.Error()) return } + if err := migratorRC8rat.migrateDerivedChargers(); err != nil { + log.Print(err.Error()) + return + } log.Print("Done!") return } diff --git a/cmd/cgr-loader/migrator_rc8.go b/cmd/cgr-loader/migrator_rc8.go index 51a7ef182..d4b1a3678 100644 --- a/cmd/cgr-loader/migrator_rc8.go +++ b/cmd/cgr-loader/migrator_rc8.go @@ -366,3 +366,37 @@ func (mig MigratorRC8) migrateActions() error { } return nil } + +func (mig MigratorRC8) migrateDerivedChargers() error { + keys, err := mig.db.Keys(utils.DERIVEDCHARGERS_PREFIX + "*") + if err != nil { + return err + } + newDcsMap := make(map[string]*utils.DerivedChargers, len(keys)) + for _, key := range keys { + log.Printf("Migrating derived charger: %s...", key) + var oldDcs []*utils.DerivedCharger + var values []byte + if values, err = mig.db.Get(key); err == nil { + if err := mig.ms.Unmarshal(values, &oldDcs); err != nil { + return err + } + } + newDcs := &utils.DerivedChargers{ + DestinationIds: make(utils.StringMap), + Chargers: oldDcs, + } + newDcsMap[key] = newDcs + } + // write data back + for key, dcs := range newDcsMap { + result, err := mig.ms.Marshal(&dcs) + if err != nil { + return err + } + if err = mig.db.Set(key, result); err != nil { + return err + } + } + return nil +} From 9bc82ada018373afbdb9645362e00d0ebb3562c7 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Sun, 15 Nov 2015 22:02:19 +0200 Subject: [PATCH 3/4] fix general tests --- engine/account.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/engine/account.go b/engine/account.go index 49487ec63..65c4f5ad3 100644 --- a/engine/account.go +++ b/engine/account.go @@ -270,7 +270,6 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //log.Print(usefulMoneyBalances, usefulUnitBalances) //log.Print("STARTCD: ", cd) var leftCC *CallCost - var initialLength int cc = cd.CreateCallCost() generalBalanceChecker := true @@ -296,10 +295,6 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //log.Printf("partCC: %+v", partCC.Timespans[0]) cc.Timespans = append(cc.Timespans, partCC.Timespans...) cc.negativeConnectFee = partCC.negativeConnectFee - if initialLength == 0 { - // this is the first add, debit the connect fee - ub.DebitConnectionFee(cc, usefulMoneyBalances, count) - } // for i, ts := range cc.Timespans { // log.Printf("cc.times[an[%d]: %+v\n", i, ts) // } @@ -329,14 +324,13 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulMoneyBalances { //log.Printf("Money balance: %+v", balance) //log.Printf("CD BEFORE MONEY: %+v", cd) - partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, initialLength == 0) + partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } //log.Printf("CD AFTER MONEY: %+v", cd) //log.Printf("partCC: %+v", partCC) if partCC != nil { - initialLength = len(cc.Timespans) cc.Timespans = append(cc.Timespans, partCC.Timespans...) cc.negativeConnectFee = partCC.negativeConnectFee @@ -373,7 +367,7 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //log.Printf("HERE: %+v %d", leftCC) if leftCC.Cost > 0 && goNegative { - initialLength = len(cc.Timespans) + initialLength := len(cc.Timespans) cc.Timespans = append(cc.Timespans, leftCC.Timespans...) if initialLength == 0 { // this is the first add, debit the connect fee From 11cc543d0aa9606544fc870476c0959e29db4e5a Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 16 Nov 2015 09:45:34 +0200 Subject: [PATCH 4/4] migration_list for separate items migration --- cmd/cgr-loader/cgr-loader.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 740b0ecb3..5525d9460 100644 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -25,6 +25,7 @@ import ( "net/rpc" "path" "strconv" + "strings" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -35,7 +36,8 @@ import ( var ( //separator = flag.String("separator", ",", "Default field separator") cgrConfig, _ = config.NewDefaultCGRConfig() - migrateRC8 = flag.Bool("migrate_rc8", false, "Migrate Accounts, Actions and ActionTriggers to RC8 structures") + migrateRC8 = flag.Bool("migrate_rc8", false, "Migrate Accounts, Actions, ActionTriggers and DerivedChargers to RC8 structures") + migrateList = flag.String("migrate_list", "acc,atr,act,dcs", "Migration item list") tpdb_type = flag.String("tpdb_type", cgrConfig.TpDbType, "The type of the TariffPlan database ") tpdb_host = flag.String("tpdb_host", cgrConfig.TpDbHost, "The TariffPlan host to connect to.") tpdb_port = flag.String("tpdb_port", cgrConfig.TpDbPort, "The TariffPlan port to bind to.") @@ -106,9 +108,10 @@ func main() { log.Print(err.Error()) return } - if err := migratorRC8acc.migrateAccounts(); err != nil { - log.Print(err.Error()) - return + if strings.Contains(*migrateList, "acc") { + if err := migratorRC8acc.migrateAccounts(); err != nil { + log.Print(err.Error()) + } } db_nb, err = strconv.Atoi(*tpdb_name) @@ -125,17 +128,20 @@ func main() { log.Print(err.Error()) return } - if err := migratorRC8rat.migrateActionTriggers(); err != nil { - log.Print(err.Error()) - return + if strings.Contains(*migrateList, "atr") { + if err := migratorRC8rat.migrateActionTriggers(); err != nil { + log.Print(err.Error()) + } } - if err := migratorRC8rat.migrateActions(); err != nil { - log.Print(err.Error()) - return + if strings.Contains(*migrateList, "act") { + if err := migratorRC8rat.migrateActions(); err != nil { + log.Print(err.Error()) + } } - if err := migratorRC8rat.migrateDerivedChargers(); err != nil { - log.Print(err.Error()) - return + if strings.Contains(*migrateList, "dcs") { + if err := migratorRC8rat.migrateDerivedChargers(); err != nil { + log.Print(err.Error()) + } } log.Print("Done!") return