mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
816 lines
23 KiB
Go
816 lines
23 KiB
Go
/*
|
|
Rating system designed to be used in VoIP Carriers World
|
|
Copyright (C) 2013 ITsysCOM
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/cgrates/cgrates/utils"
|
|
)
|
|
|
|
type DbReader struct {
|
|
tpid string
|
|
storDb LoadStorage
|
|
dataDb RatingStorage
|
|
accountDb AccountingStorage
|
|
actions map[string][]*Action
|
|
actionsTimings map[string][]*ActionTiming
|
|
actionsTriggers map[string][]*ActionTrigger
|
|
accountActions map[string]*Account
|
|
dirtyRpAliases []string // used to clean aliases that might have changed
|
|
dirtyAccAliases []string // used to clean aliases that might have changed
|
|
destinations []*Destination
|
|
rpAliases map[string]string
|
|
accAliases map[string]string
|
|
timings map[string]*utils.TPTiming
|
|
rates map[string]*utils.TPRate
|
|
destinationRates map[string]*utils.TPDestinationRate
|
|
ratingPlans map[string]*RatingPlan
|
|
ratingProfiles map[string]*RatingProfile
|
|
sharedGroups map[string]*SharedGroup
|
|
}
|
|
|
|
func NewDbReader(storDB LoadStorage, ratingDb RatingStorage, accountDb AccountingStorage, tpid string) *DbReader {
|
|
c := new(DbReader)
|
|
c.storDb = storDB
|
|
c.dataDb = ratingDb
|
|
c.accountDb = accountDb
|
|
c.tpid = tpid
|
|
c.actions = make(map[string][]*Action)
|
|
c.actionsTimings = make(map[string][]*ActionTiming)
|
|
c.actionsTriggers = make(map[string][]*ActionTrigger)
|
|
c.ratingPlans = make(map[string]*RatingPlan)
|
|
c.ratingProfiles = make(map[string]*RatingProfile)
|
|
c.sharedGroups = make(map[string]*SharedGroup)
|
|
c.rpAliases = make(map[string]string)
|
|
c.accAliases = make(map[string]string)
|
|
c.accountActions = make(map[string]*Account)
|
|
return c
|
|
}
|
|
|
|
// FIXME: this method is code duplication from csv loader
|
|
func (dbr *DbReader) ShowStatistics() {
|
|
// destinations
|
|
destCount := len(dbr.destinations)
|
|
log.Print("Destinations: ", destCount)
|
|
prefixDist := make(map[int]int, 50)
|
|
prefixCount := 0
|
|
for _, d := range dbr.destinations {
|
|
prefixDist[len(d.Prefixes)] += 1
|
|
prefixCount += len(d.Prefixes)
|
|
}
|
|
log.Print("Avg Prefixes: ", prefixCount/destCount)
|
|
log.Print("Prefixes distribution:")
|
|
for k, v := range prefixDist {
|
|
log.Printf("%d: %d", k, v)
|
|
}
|
|
// rating plans
|
|
rplCount := len(dbr.ratingPlans)
|
|
log.Print("Rating plans: ", rplCount)
|
|
destRatesDist := make(map[int]int, 50)
|
|
destRatesCount := 0
|
|
for _, rpl := range dbr.ratingPlans {
|
|
destRatesDist[len(rpl.DestinationRates)] += 1
|
|
destRatesCount += len(rpl.DestinationRates)
|
|
}
|
|
log.Print("Avg Destination Rates: ", destRatesCount/rplCount)
|
|
log.Print("Destination Rates distribution:")
|
|
for k, v := range destRatesDist {
|
|
log.Printf("%d: %d", k, v)
|
|
}
|
|
// rating profiles
|
|
rpfCount := len(dbr.ratingProfiles)
|
|
log.Print("Rating profiles: ", rpfCount)
|
|
activDist := make(map[int]int, 50)
|
|
activCount := 0
|
|
for _, rpf := range dbr.ratingProfiles {
|
|
activDist[len(rpf.RatingPlanActivations)] += 1
|
|
activCount += len(rpf.RatingPlanActivations)
|
|
}
|
|
log.Print("Avg Activations: ", activCount/rpfCount)
|
|
log.Print("Activation distribution:")
|
|
for k, v := range activDist {
|
|
log.Printf("%d: %d", k, v)
|
|
}
|
|
// actions
|
|
log.Print("Actions: ", len(dbr.actions))
|
|
// action timings
|
|
log.Print("Action plans: ", len(dbr.actionsTimings))
|
|
// account actions
|
|
log.Print("Account actions: ", len(dbr.accountActions))
|
|
}
|
|
|
|
func (dbr *DbReader) WriteToDatabase(flush, verbose bool) (err error) {
|
|
storage := dbr.dataDb
|
|
if flush {
|
|
storage.(Storage).Flush()
|
|
}
|
|
if verbose {
|
|
log.Print("Destinations")
|
|
}
|
|
for _, d := range dbr.destinations {
|
|
err = storage.SetDestination(d)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Print(d.Id, " : ", d.Prefixes)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Rating plans")
|
|
}
|
|
for _, rp := range dbr.ratingPlans {
|
|
err = storage.SetRatingPlan(rp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Print(rp.Id)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Rating profiles")
|
|
}
|
|
for _, rp := range dbr.ratingProfiles {
|
|
err = storage.SetRatingProfile(rp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Print(rp.Id)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Action plans")
|
|
}
|
|
for k, ats := range dbr.actionsTimings {
|
|
err = accountingStorage.SetActionTimings(k, ats)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Println(k)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Actions")
|
|
}
|
|
for k, as := range dbr.actions {
|
|
err = accountingStorage.SetActions(k, as)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Println(k)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Account actions")
|
|
}
|
|
for _, ub := range dbr.accountActions {
|
|
err = accountingStorage.SetAccount(ub)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Println(ub.Id)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Rating profile aliases")
|
|
}
|
|
if err := storage.RemoveRpAliases(dbr.dirtyRpAliases); err != nil {
|
|
return err
|
|
}
|
|
for key, alias := range dbr.rpAliases {
|
|
err = storage.SetRpAlias(key, alias)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Println(key)
|
|
}
|
|
}
|
|
if verbose {
|
|
log.Print("Account aliases")
|
|
}
|
|
if err := accountingStorage.RemoveAccAliases(dbr.dirtyAccAliases); err != nil {
|
|
return err
|
|
}
|
|
for key, alias := range dbr.accAliases {
|
|
err = accountingStorage.SetAccAlias(key, alias)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if verbose {
|
|
log.Println(key)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (dbr *DbReader) LoadDestinations() (err error) {
|
|
dbr.destinations, err = dbr.storDb.GetTpDestinations(dbr.tpid, "")
|
|
return
|
|
}
|
|
|
|
func (dbr *DbReader) LoadTimings() (err error) {
|
|
dbr.timings, err = dbr.storDb.GetTpTimings(dbr.tpid, "")
|
|
return err
|
|
}
|
|
|
|
func (dbr *DbReader) LoadRates() (err error) {
|
|
dbr.rates, err = dbr.storDb.GetTpRates(dbr.tpid, "")
|
|
return err
|
|
}
|
|
|
|
func (dbr *DbReader) LoadDestinationRates() (err error) {
|
|
dbr.destinationRates, err = dbr.storDb.GetTpDestinationRates(dbr.tpid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, drs := range dbr.destinationRates {
|
|
for _, dr := range drs.DestinationRates {
|
|
rate, exists := dbr.rates[dr.RateId]
|
|
if !exists {
|
|
return fmt.Errorf("Could not find rate for tag %v", dr.RateId)
|
|
}
|
|
dr.Rate = rate
|
|
destinationExists := false
|
|
for _, d := range dbr.destinations {
|
|
if d.Id == dr.DestinationId {
|
|
destinationExists = true
|
|
break
|
|
}
|
|
}
|
|
if !destinationExists {
|
|
if dbExists, err := dbr.dataDb.HasData(DESTINATION_PREFIX, dr.DestinationId); err != nil {
|
|
return err
|
|
} else if !dbExists {
|
|
return fmt.Errorf("Could not get destination for tag %v", dr.DestinationId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadRatingPlans() error {
|
|
mpRpls, err := dbr.storDb.GetTpRatingPlans(dbr.tpid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for tag, rplBnds := range mpRpls {
|
|
for _, rplBnd := range rplBnds {
|
|
t, exists := dbr.timings[rplBnd.TimingId]
|
|
if !exists {
|
|
return fmt.Errorf("Could not get timing for tag %v", rplBnd.TimingId)
|
|
}
|
|
rplBnd.SetTiming(t)
|
|
drs, exists := dbr.destinationRates[rplBnd.DestinationRatesId]
|
|
if !exists {
|
|
return fmt.Errorf("Could not find destination rate for tag %v", rplBnd.DestinationRatesId)
|
|
}
|
|
plan, exists := dbr.ratingPlans[tag]
|
|
if !exists {
|
|
plan = &RatingPlan{Id: tag}
|
|
dbr.ratingPlans[plan.Id] = plan
|
|
}
|
|
for _, dr := range drs.DestinationRates {
|
|
plan.AddRateInterval(dr.DestinationId, GetRateInterval(rplBnd, dr))
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadRatingProfiles() error {
|
|
mpTpRpfs, err := dbr.storDb.GetTpRatingProfiles(&utils.TPRatingProfile{TPid: dbr.tpid}) //map[string]*utils.TPRatingProfile
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, tpRpf := range mpTpRpfs {
|
|
dbr.dirtyRpAliases = append(dbr.dirtyRpAliases, tpRpf.Subject)
|
|
// extract aliases from subject
|
|
aliases := strings.Split(tpRpf.Subject, ";")
|
|
if len(aliases) > 1 {
|
|
tpRpf.Subject = aliases[0]
|
|
for _, alias := range aliases[1:] {
|
|
dbr.rpAliases[alias] = tpRpf.Subject
|
|
}
|
|
}
|
|
rpf := &RatingProfile{Id: tpRpf.KeyId()}
|
|
for _, tpRa := range tpRpf.RatingPlanActivations {
|
|
at, err := utils.ParseDate(tpRa.ActivationTime)
|
|
if err != nil {
|
|
return fmt.Errorf("Cannot parse activation time from %v", tpRa.ActivationTime)
|
|
}
|
|
_, exists := dbr.ratingPlans[tpRa.RatingPlanId]
|
|
if !exists {
|
|
if dbExists, err := dbr.dataDb.HasData(RATING_PLAN_PREFIX, tpRa.RatingPlanId); err != nil {
|
|
return err
|
|
} else if !dbExists {
|
|
return fmt.Errorf("Could not load rating plans for tag: %v", tpRa.RatingPlanId)
|
|
}
|
|
}
|
|
rpf.RatingPlanActivations = append(rpf.RatingPlanActivations,
|
|
&RatingPlanActivation{
|
|
ActivationTime: at,
|
|
RatingPlanId: tpRa.RatingPlanId,
|
|
FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.TOR, tpRa.FallbackSubjects),
|
|
})
|
|
}
|
|
dbr.ratingProfiles[tpRpf.KeyId()] = rpf
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Returns true, nil in case of load success, false, nil in case of RatingPlan not found in storDb
|
|
func (dbr *DbReader) LoadRatingPlanByTag(tag string) (bool, error) {
|
|
mpRpls, err := dbr.storDb.GetTpRatingPlans(dbr.tpid, tag)
|
|
if err != nil {
|
|
return false, err
|
|
} else if len(mpRpls) == 0 {
|
|
return false, nil
|
|
}
|
|
for tag, rplBnds := range mpRpls {
|
|
ratingPlan := &RatingPlan{Id: tag}
|
|
for _, rp := range rplBnds {
|
|
// Logger.Debug(fmt.Sprintf("Rating Plan binding: %v", rp))
|
|
tm, err := dbr.storDb.GetTpTimings(dbr.tpid, rp.TimingId)
|
|
// Logger.Debug(fmt.Sprintf("Timing: %v", tm))
|
|
if err != nil || len(tm) == 0 {
|
|
return false, fmt.Errorf("No Timings profile with id %s: %v", rp.TimingId, err)
|
|
}
|
|
rp.SetTiming(tm[rp.TimingId])
|
|
drm, err := dbr.storDb.GetTpDestinationRates(dbr.tpid, rp.DestinationRatesId)
|
|
if err != nil || len(drm) == 0 {
|
|
return false, fmt.Errorf("No DestinationRates profile with id %s: %v", rp.DestinationRatesId, err)
|
|
}
|
|
for _, drate := range drm[rp.DestinationRatesId].DestinationRates {
|
|
// Logger.Debug(fmt.Sprintf("Destination rate: %v", drate))
|
|
rt, err := dbr.storDb.GetTpRates(dbr.tpid, drate.RateId)
|
|
if err != nil || len(rt) == 0 {
|
|
return false, fmt.Errorf("No Rates profile with id %s: %v", drate.RateId, err)
|
|
}
|
|
// Logger.Debug(fmt.Sprintf("Rate: %v", rt))
|
|
drate.Rate = rt[drate.RateId]
|
|
ratingPlan.AddRateInterval(drate.DestinationId, GetRateInterval(rp, drate))
|
|
|
|
dms, err := dbr.storDb.GetTpDestinations(dbr.tpid, drate.DestinationId)
|
|
if err != nil {
|
|
return false, err
|
|
} else if len(dms) == 0 {
|
|
if dbExists, err := dbr.dataDb.HasData(DESTINATION_PREFIX, drate.DestinationId); err != nil {
|
|
return false, err
|
|
} else if !dbExists {
|
|
return false, fmt.Errorf("Could not get destination for tag %v", drate.DestinationId)
|
|
}
|
|
continue
|
|
}
|
|
// Logger.Debug(fmt.Sprintf("Tag: %s Destinations: %v", drate.DestinationId, dms))
|
|
for _, destination := range dms {
|
|
// Logger.Debug(fmt.Sprintf("Destination: %v", destination))
|
|
dbr.dataDb.SetDestination(destination)
|
|
}
|
|
}
|
|
}
|
|
if err := dbr.dataDb.SetRatingPlan(ratingPlan); err != nil {
|
|
return false, err
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadRatingProfileFiltered(qriedRpf *utils.TPRatingProfile) error {
|
|
var resultRatingProfile *RatingProfile
|
|
mpTpRpfs, err := dbr.storDb.GetTpRatingProfiles(qriedRpf) //map[string]*utils.TPRatingProfile
|
|
if err != nil {
|
|
return fmt.Errorf("No RateProfile for filter %v, error: %v", qriedRpf, err)
|
|
}
|
|
for _, tpRpf := range mpTpRpfs {
|
|
// Logger.Debug(fmt.Sprintf("Rating profile: %v", tpRpf))
|
|
resultRatingProfile = &RatingProfile{Id: tpRpf.KeyId()}
|
|
for _, tpRa := range tpRpf.RatingPlanActivations {
|
|
at, err := utils.ParseDate(tpRa.ActivationTime)
|
|
if err != nil {
|
|
return fmt.Errorf("Cannot parse activation time from %v", tpRa.ActivationTime)
|
|
}
|
|
_, exists := dbr.ratingPlans[tpRa.RatingPlanId]
|
|
if !exists {
|
|
if dbExists, err := dbr.dataDb.HasData(RATING_PLAN_PREFIX, tpRa.RatingPlanId); err != nil {
|
|
return err
|
|
} else if !dbExists {
|
|
return fmt.Errorf("Could not load rating plans for tag: %v", tpRa.RatingPlanId)
|
|
}
|
|
}
|
|
resultRatingProfile.RatingPlanActivations = append(resultRatingProfile.RatingPlanActivations,
|
|
&RatingPlanActivation{at, tpRa.RatingPlanId,
|
|
utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.TOR, tpRa.FallbackSubjects)})
|
|
}
|
|
if err := dbr.dataDb.SetRatingProfile(resultRatingProfile); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadSharedGroups() (err error) {
|
|
dbr.sharedGroups, err = dbr.storDb.GetTpSharedGroups(dbr.tpid, "")
|
|
return err
|
|
}
|
|
|
|
func (dbr *DbReader) LoadActions() (err error) {
|
|
storActs, err := dbr.storDb.GetTpActions(dbr.tpid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// map[string][]*Action
|
|
for tag, tpacts := range storActs {
|
|
acts := make([]*Action, len(tpacts))
|
|
for idx, tpact := range tpacts {
|
|
acts[idx] = &Action{
|
|
Id: utils.GenUUID(),
|
|
ActionType: tpact.Identifier,
|
|
BalanceType: tpact.BalanceType,
|
|
Direction: tpact.Direction,
|
|
Weight: tpact.Weight,
|
|
ExtraParameters: tpact.ExtraParameters,
|
|
ExpirationString: tpact.ExpiryTime,
|
|
Balance: &Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: tpact.Units,
|
|
Weight: tpact.BalanceWeight,
|
|
RatingSubject: tpact.RatingSubject,
|
|
DestinationId: tpact.DestinationId,
|
|
},
|
|
}
|
|
}
|
|
dbr.actions[tag] = acts
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadActionTimings() (err error) {
|
|
atsMap, err := dbr.storDb.GetTPActionTimings(dbr.tpid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for atId, ats := range atsMap {
|
|
for _, at := range ats {
|
|
|
|
_, exists := dbr.actions[at.ActionsId]
|
|
if !exists {
|
|
return fmt.Errorf("ActionTiming: Could not load the action for tag: %v", at.ActionsId)
|
|
}
|
|
t, exists := dbr.timings[at.TimingId]
|
|
if !exists {
|
|
return fmt.Errorf("ActionTiming: Could not load the timing for tag: %v", at.TimingId)
|
|
}
|
|
actTmg := &ActionTiming{
|
|
Uuid: utils.GenUUID(),
|
|
Id: atId,
|
|
Weight: at.Weight,
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: t.Years,
|
|
Months: t.Months,
|
|
MonthDays: t.MonthDays,
|
|
WeekDays: t.WeekDays,
|
|
StartTime: t.StartTime,
|
|
},
|
|
},
|
|
ActionsId: at.ActionsId,
|
|
}
|
|
dbr.actionsTimings[atId] = append(dbr.actionsTimings[atId], actTmg)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (dbr *DbReader) LoadActionTriggers() (err error) {
|
|
atrsMap, err := dbr.storDb.GetTpActionTriggers(dbr.tpid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for key, atrsLst := range atrsMap {
|
|
atrs := make([]*ActionTrigger, len(atrsLst))
|
|
for idx, apiAtr := range atrsLst {
|
|
atrs[idx] = &ActionTrigger{Id: utils.GenUUID(),
|
|
BalanceType: apiAtr.BalanceType,
|
|
Direction: apiAtr.Direction,
|
|
ThresholdType: apiAtr.ThresholdType,
|
|
ThresholdValue: apiAtr.ThresholdValue,
|
|
DestinationId: apiAtr.DestinationId,
|
|
Weight: apiAtr.Weight,
|
|
ActionsId: apiAtr.ActionsId,
|
|
}
|
|
}
|
|
dbr.actionsTriggers[key] = atrs
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (dbr *DbReader) LoadAccountActions() (err error) {
|
|
acs, err := dbr.storDb.GetTpAccountActions(&utils.TPAccountActions{TPid: dbr.tpid})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, aa := range acs {
|
|
if _, alreadyDefined := dbr.accountActions[aa.KeyId()]; alreadyDefined {
|
|
return fmt.Errorf("Duplicate account action found: %s", aa.KeyId())
|
|
}
|
|
dbr.dirtyAccAliases = append(dbr.dirtyAccAliases, aa.Account)
|
|
// extract aliases from subject
|
|
aliases := strings.Split(aa.Account, ";")
|
|
if len(aliases) > 1 {
|
|
aa.Account = aliases[0]
|
|
for _, alias := range aliases[1:] {
|
|
dbr.accAliases[alias] = aa.Account
|
|
}
|
|
}
|
|
aTriggers, exists := dbr.actionsTriggers[aa.ActionTriggersId]
|
|
if !exists {
|
|
return fmt.Errorf("Could not get action triggers for tag %v", aa.ActionTriggersId)
|
|
}
|
|
ub := &Account{
|
|
Id: aa.KeyId(),
|
|
ActionTriggers: aTriggers,
|
|
}
|
|
dbr.accountActions[aa.KeyId()] = ub
|
|
aTimings, exists := dbr.actionsTimings[aa.ActionPlanId]
|
|
if !exists {
|
|
log.Printf("Could not get action timing for tag %v", aa.ActionPlanId)
|
|
// must not continue here
|
|
}
|
|
for _, at := range aTimings {
|
|
at.AccountIds = append(at.AccountIds, aa.KeyId())
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dbr *DbReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) error {
|
|
accountActions, err := dbr.storDb.GetTpAccountActions(qriedAA)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, accountAction := range accountActions {
|
|
id := accountAction.KeyId()
|
|
var actionsIds []string // collects action ids
|
|
// action timings
|
|
if accountAction.ActionPlanId != "" {
|
|
// get old userBalanceIds
|
|
var exitingAccountIds []string
|
|
existingActionTimings, err := dbr.accountDb.GetActionTimings(accountAction.ActionPlanId)
|
|
if err == nil && len(existingActionTimings) > 0 {
|
|
// all action timings from a specific tag shuld have the same list of user balances from the first one
|
|
exitingAccountIds = existingActionTimings[0].AccountIds
|
|
}
|
|
|
|
actionTimingsMap, err := dbr.storDb.GetTPActionTimings(dbr.tpid, accountAction.ActionPlanId)
|
|
if err != nil {
|
|
return err
|
|
} else if len(actionTimingsMap) == 0 {
|
|
return fmt.Errorf("No ActionTimings with id <%s>", accountAction.ActionPlanId)
|
|
}
|
|
var actionTimings []*ActionTiming
|
|
ats := actionTimingsMap[accountAction.ActionPlanId]
|
|
for _, at := range ats {
|
|
// Check action exists before saving it inside actionTiming key
|
|
// ToDo: try saving the key after the actions was retrieved in order to save one query here.
|
|
if actions, err := dbr.storDb.GetTpActions(dbr.tpid, at.ActionsId); err != nil {
|
|
return err
|
|
} else if len(actions) == 0 {
|
|
return fmt.Errorf("No Action with id <%s>", at.ActionsId)
|
|
}
|
|
timingsMap, err := dbr.storDb.GetTpTimings(dbr.tpid, at.TimingId)
|
|
if err != nil {
|
|
return err
|
|
} else if len(timingsMap) == 0 {
|
|
return fmt.Errorf("No Timing with id <%s>", at.TimingId)
|
|
}
|
|
t := timingsMap[at.TimingId]
|
|
actTmg := &ActionTiming{
|
|
Uuid: utils.GenUUID(),
|
|
Id: accountAction.ActionPlanId,
|
|
Weight: at.Weight,
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: t.Months,
|
|
MonthDays: t.MonthDays,
|
|
WeekDays: t.WeekDays,
|
|
StartTime: t.StartTime,
|
|
},
|
|
},
|
|
ActionsId: at.ActionsId,
|
|
}
|
|
// collect action ids from timings
|
|
actionsIds = append(actionsIds, actTmg.ActionsId)
|
|
//add user balance id if no already in
|
|
found := false
|
|
for _, ubId := range exitingAccountIds {
|
|
if ubId == id {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
actTmg.AccountIds = append(exitingAccountIds, id)
|
|
}
|
|
actionTimings = append(actionTimings, actTmg)
|
|
}
|
|
|
|
// write action timings
|
|
err = dbr.accountDb.SetActionTimings(accountAction.ActionPlanId, actionTimings)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// action triggers
|
|
var actionTriggers ActionTriggerPriotityList
|
|
//ActionTriggerPriotityList []*ActionTrigger
|
|
if accountAction.ActionTriggersId != "" {
|
|
apiAtrsMap, err := dbr.storDb.GetTpActionTriggers(dbr.tpid, accountAction.ActionTriggersId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
atrsMap := make(map[string][]*ActionTrigger)
|
|
for key, atrsLst := range apiAtrsMap {
|
|
atrs := make([]*ActionTrigger, len(atrsLst))
|
|
for idx, apiAtr := range atrsLst {
|
|
atrs[idx] = &ActionTrigger{Id: utils.GenUUID(),
|
|
BalanceType: apiAtr.BalanceType,
|
|
Direction: apiAtr.Direction,
|
|
ThresholdType: apiAtr.ThresholdType,
|
|
ThresholdValue: apiAtr.ThresholdValue,
|
|
DestinationId: apiAtr.DestinationId,
|
|
Weight: apiAtr.Weight,
|
|
ActionsId: apiAtr.ActionsId,
|
|
}
|
|
}
|
|
atrsMap[key] = atrs
|
|
}
|
|
actionTriggers = atrsMap[accountAction.ActionTriggersId]
|
|
// collect action ids from triggers
|
|
for _, atr := range actionTriggers {
|
|
actionsIds = append(actionsIds, atr.ActionsId)
|
|
}
|
|
}
|
|
|
|
// actions
|
|
acts := make(map[string][]*Action)
|
|
for _, actId := range actionsIds {
|
|
storActs, err := dbr.storDb.GetTpActions(dbr.tpid, actId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for tag, tpacts := range storActs {
|
|
enacts := make([]*Action, len(tpacts))
|
|
for idx, tpact := range tpacts {
|
|
enacts[idx] = &Action{
|
|
Id: utils.GenUUID(),
|
|
ActionType: tpact.Identifier,
|
|
BalanceType: tpact.BalanceType,
|
|
Direction: tpact.Direction,
|
|
Weight: tpact.Weight,
|
|
ExtraParameters: tpact.ExtraParameters,
|
|
ExpirationString: tpact.ExpiryTime,
|
|
Balance: &Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: tpact.Units,
|
|
Weight: tpact.BalanceWeight,
|
|
RatingSubject: tpact.RatingSubject,
|
|
DestinationId: tpact.DestinationId,
|
|
},
|
|
}
|
|
}
|
|
acts[tag] = enacts
|
|
}
|
|
}
|
|
// writee actions
|
|
for k, as := range acts {
|
|
err = dbr.accountDb.SetActions(k, as)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
ub, err := dbr.accountDb.GetAccount(id)
|
|
if err != nil {
|
|
ub = &Account{
|
|
Id: id,
|
|
}
|
|
}
|
|
ub.ActionTriggers = actionTriggers
|
|
|
|
if err := dbr.accountDb.SetAccount(ub); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Automated loading
|
|
func (dbr *DbReader) LoadAll() error {
|
|
var err error
|
|
if err = dbr.LoadDestinations(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadTimings(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadRates(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadDestinationRates(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadRatingPlans(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadRatingProfiles(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadSharedGroups(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadActions(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadActionTimings(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadActionTriggers(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbr.LoadAccountActions(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Returns the identities loaded for a specific entity category
|
|
func (dbr *DbReader) GetLoadedIds(categ string) ([]string, error) {
|
|
switch categ {
|
|
case DESTINATION_PREFIX:
|
|
ids := make([]string, len(dbr.destinations))
|
|
for idx, dst := range dbr.destinations {
|
|
ids[idx] = dst.Id
|
|
}
|
|
return ids, nil
|
|
case RATING_PLAN_PREFIX:
|
|
keys := make([]string, len(dbr.ratingPlans))
|
|
i := 0
|
|
for k := range dbr.ratingPlans {
|
|
keys[i] = k
|
|
i++
|
|
}
|
|
return keys, nil
|
|
case RATING_PROFILE_PREFIX:
|
|
keys := make([]string, len(dbr.ratingProfiles))
|
|
i := 0
|
|
for k := range dbr.ratingProfiles {
|
|
keys[i] = k
|
|
i++
|
|
}
|
|
return keys, nil
|
|
case ACTION_PREFIX: // actions
|
|
keys := make([]string, len(dbr.actions))
|
|
i := 0
|
|
for k := range dbr.actions {
|
|
keys[i] = k
|
|
i++
|
|
}
|
|
return keys, nil
|
|
case ACTION_TIMING_PREFIX: // actionsTimings
|
|
keys := make([]string, len(dbr.actionsTimings))
|
|
i := 0
|
|
for k := range dbr.actionsTimings {
|
|
keys[i] = k
|
|
i++
|
|
}
|
|
return keys, nil
|
|
}
|
|
return nil, errors.New("Unsupported category")
|
|
}
|