You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
855 lines
21 KiB
855 lines
21 KiB
3 years ago
|
package dbManager
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"math"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/go-openapi/strfmt"
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
cdrModels "github.com/Cyclops-Labs/cyclops-4-hpc.git/services/cdr/models"
|
||
|
"github.com/Cyclops-Labs/cyclops-4-hpc.git/services/credit-system/models"
|
||
|
"github.com/Cyclops-Labs/cyclops-4-hpc.git/services/credit-system/server/cacheManager"
|
||
|
cusModels "github.com/Cyclops-Labs/cyclops-4-hpc.git/services/customerdb/models"
|
||
|
pmModels "github.com/Cyclops-Labs/cyclops-4-hpc.git/services/plan-manager/models"
|
||
|
l "gitlab.com/cyclops-utilities/logging"
|
||
|
"gorm.io/driver/postgres"
|
||
|
"gorm.io/gorm"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
scaler = 1e7
|
||
|
statusDuplicated = iota
|
||
|
statusFail
|
||
|
statusMissing
|
||
|
statusOK
|
||
|
AC_CREDIT = "CREDIT"
|
||
|
AC_CASH = "CASH"
|
||
|
AC_BOTH = "BOTH"
|
||
|
AC_NONE = "NONE"
|
||
|
MED_CASH = "CASH"
|
||
|
MED_CREDIT = "CREDIT"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
//states = []string{"active", "error", "inactive", "suspended", "terminated"}
|
||
|
states = []string{"active", "error", "inactive", "used"}
|
||
|
totalTime float64
|
||
|
totalCount int64
|
||
|
)
|
||
|
|
||
|
// DbParameter is the struct defined to group and contain all the methods
|
||
|
// that interact with the database.
|
||
|
// On it there is the following parameters:
|
||
|
// - Cache: CacheManager pointer for the cache mechanism.
|
||
|
// - connStr: strings with the connection information to the database
|
||
|
// - Db: a gorm.DB pointer to the db to invoke all the db methods
|
||
|
type DbParameter struct {
|
||
|
Cache *cacheManager.CacheManager
|
||
|
connStr string
|
||
|
Db *gorm.DB
|
||
|
Metrics map[string]*prometheus.GaugeVec
|
||
|
}
|
||
|
|
||
|
// New is the function to create the struct DbParameter.
|
||
|
// Parameters:
|
||
|
// - dbConn: strings with the connection information to the database
|
||
|
// - tables: array of interfaces that will contains the models to migrate
|
||
|
// to the database on initialization
|
||
|
// Returns:
|
||
|
// - DbParameter: struct to interact with dbManager functionalities¬
|
||
|
func New(dbConn string, tables ...interface{}) *DbParameter {
|
||
|
|
||
|
l.Trace.Printf("[DB] Gerenating new DBParameter.\n")
|
||
|
|
||
|
var (
|
||
|
dp DbParameter
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
dp.connStr = dbConn
|
||
|
|
||
|
dp.Db, err = gorm.Open(postgres.Open(dbConn), &gorm.Config{})
|
||
|
|
||
|
if err != nil {
|
||
|
|
||
|
l.Error.Printf("[DB] Error opening connection. Error: %v\n", err)
|
||
|
|
||
|
}
|
||
|
|
||
|
l.Trace.Printf("[DB] Migrating tables.\n")
|
||
|
|
||
|
//Database migration, it handles everything
|
||
|
dp.Db.AutoMigrate(tables...)
|
||
|
|
||
|
//l.Trace.Printf("[DB] Generating hypertables.\n")
|
||
|
|
||
|
// Hypertables creation for timescaledb in case of needed
|
||
|
//dp.Db.Exec("SELECT create_hypertable('" + dp.Db.NewScope(&models.TABLE).TableName() + "', 'TIMESCALE-ROW-INDEX');")
|
||
|
|
||
|
return &dp
|
||
|
|
||
|
}
|
||
|
|
||
|
// AddConsumption job is to decrease the credit in the system linked to the
|
||
|
// provided account by a certain amount of credit.
|
||
|
// This function is the one that produces a "cosumed" decrease of credit without
|
||
|
// human intervention.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account requested.
|
||
|
// - amount: float containing the amount to be -- in the system
|
||
|
// Returns:
|
||
|
// - reference to creditStatus containing the credit balance after the operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) AddConsumption(id string, amount float64, medium string) (*models.CreditStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to add a comsuption of %v credit, in the account with id: %v", amount, id)
|
||
|
|
||
|
var c, c0, cs models.CreditStatus
|
||
|
var ce models.CreditEvents
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.CreditStatus{AccountID: id}).First(&c).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
} else {
|
||
|
|
||
|
med := strings.ToUpper(medium)
|
||
|
|
||
|
if med == models.CreditEventsMediumCREDIT {
|
||
|
|
||
|
c0.AvailableCredit = c.AvailableCredit - amount
|
||
|
|
||
|
}
|
||
|
|
||
|
if med == models.CreditEventsMediumCASH {
|
||
|
|
||
|
c0.AvailableCash = c.AvailableCash - amount
|
||
|
|
||
|
}
|
||
|
|
||
|
c0.LastUpdate = strfmt.DateTime(time.Now())
|
||
|
|
||
|
ce.AccountID = id
|
||
|
ce.Delta = -amount
|
||
|
ce.EventType = func(s string) *string { return &s }(models.EventEventTypeConsumption)
|
||
|
ce.Timestamp = strfmt.DateTime(time.Now())
|
||
|
ce.Medium = &med
|
||
|
|
||
|
if e = d.Db.Model(&c).Updates(c0).Error; e == nil {
|
||
|
|
||
|
if e = d.Db.Create(&ce).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.CreditStatus{AccountID: id}).First(&cs)
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to add the comsuption of credit event for account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to update the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return &cs, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// CreateAccount job is to register a new account in the system with the provided
|
||
|
// ID.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account to be created.
|
||
|
// Returns:
|
||
|
// - reference to AccountStatus containing the state of the account after the
|
||
|
// operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) CreateAccount(id string) (*models.AccountStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to create a new account with id: %v", id)
|
||
|
|
||
|
var a, a0, as models.AccountStatus
|
||
|
var c models.CreditStatus
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.AccountStatus{AccountID: id}).First(&a).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
a0.AccountID = id
|
||
|
a0.CreatedAt = strfmt.DateTime(time.Now())
|
||
|
|
||
|
c.AccountID = id
|
||
|
c.LastUpdate = strfmt.DateTime(time.Now())
|
||
|
|
||
|
if e = d.Db.Create(&a0).Error; e == nil {
|
||
|
|
||
|
if e = d.Db.Create(&c).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.AccountStatus{AccountID: id}).First(&as)
|
||
|
|
||
|
d.Metrics["count"].With(prometheus.Labels{"type": "Accounts created"}).Inc()
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to create the credit account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to create the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v already in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account already exist in the system")
|
||
|
|
||
|
}
|
||
|
|
||
|
return &as, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// DecreaseCredit job is to decrease the credit in the system linked to the
|
||
|
// provided account by a certain amount of credit.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account requested.
|
||
|
// - amount: float containing the amount to be decreased in the system.
|
||
|
// Returns:
|
||
|
// - reference to CreditStatus containing the credit balance after the operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) DecreaseCredit(id string, amount float64, medium string) (*models.CreditStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to decrease credit by: %v, in the account with id: %v", amount, id)
|
||
|
|
||
|
var c, c0, cs models.CreditStatus
|
||
|
var ce models.CreditEvents
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.CreditStatus{AccountID: id}).First(&c).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
} else {
|
||
|
|
||
|
med := strings.ToUpper(medium)
|
||
|
|
||
|
if med == models.CreditEventsMediumCREDIT {
|
||
|
|
||
|
c0.AvailableCredit = c.AvailableCredit - amount
|
||
|
|
||
|
}
|
||
|
|
||
|
if med == models.CreditEventsMediumCASH {
|
||
|
|
||
|
c0.AvailableCash = c.AvailableCash - amount
|
||
|
|
||
|
}
|
||
|
|
||
|
c0.LastUpdate = strfmt.DateTime(time.Now())
|
||
|
|
||
|
ce.AccountID = id
|
||
|
ce.Delta = -amount
|
||
|
ce.EventType = func(s string) *string { return &s }(models.EventEventTypeAuthorizedDecrease)
|
||
|
ce.Timestamp = strfmt.DateTime(time.Now())
|
||
|
ce.Medium = &med
|
||
|
|
||
|
if e = d.Db.Model(&c).Updates(c0).Error; e == nil {
|
||
|
|
||
|
if e = d.Db.Create(&ce).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.CreditStatus{AccountID: id}).First(&cs)
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to add the decrease of credit event for account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to update the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return &cs, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// DisableAccount job is to mark as disabled in the system the account provided.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account to be disabled.
|
||
|
// Returns:
|
||
|
// - reference to AccountStatus containing the state of the account after the
|
||
|
// operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) DisableAccount(id string) (*models.AccountStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to disable account with id: %v", id)
|
||
|
|
||
|
var a, as models.AccountStatus
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.AccountStatus{AccountID: id}).First(&a).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
} else {
|
||
|
|
||
|
enabled := false
|
||
|
|
||
|
if e = d.Db.Model(&a).Updates(&models.AccountStatus{Enabled: enabled}).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.AccountStatus{AccountID: id}).First(&as)
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to update the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return &as, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// EnableAccount job is to mark as enabled in the system the account provided.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account to be enabled.
|
||
|
// Returns:
|
||
|
// - reference to AccountStatus containing the state of the account after the
|
||
|
// operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) EnableAccount(id string) (*models.AccountStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to enable account with id: %v", id)
|
||
|
|
||
|
var a, as models.AccountStatus
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.AccountStatus{AccountID: id}).First(&a).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if e = d.Db.Model(&a).Update("Enabled", true).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.AccountStatus{AccountID: id}).First(&as)
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to update the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return &as, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// GetAccountStatus job is to retrieve the actual state of the provided account.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account to be retrieved.
|
||
|
// Returns:
|
||
|
// - reference to AccountStatus containing the state of the account.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) GetAccountStatus(id string) (*models.AccountStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to get the status of the account with id: %v", id)
|
||
|
|
||
|
var as models.AccountStatus
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.AccountStatus{AccountID: id}).First(&as).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
}
|
||
|
|
||
|
return &as, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// GetCredit job is to retrieve the actual state of the credit balance of the
|
||
|
// provided account.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account requested.
|
||
|
// Returns:
|
||
|
// - reference to CreditStatus containing the credit balance.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) GetCredit(id string) (*models.CreditStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to get the credit balance in the account with id: %v", id)
|
||
|
|
||
|
var cs models.CreditStatus
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.CreditStatus{AccountID: id}).First(&cs).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
}
|
||
|
|
||
|
return &cs, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// GetHistory job is to retrieve the history of the credit balance of the account
|
||
|
// provided with the posibility of filter the actions.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account requested.
|
||
|
// - filtered: string specifying the criteria for filtering.
|
||
|
// Returns:
|
||
|
// - reference to CreditHistory containing the credit balance history contained
|
||
|
// in the system.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) GetHistory(id string, filtered bool, medium string) (*models.CreditHistory, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to get the credit history in the account with id: %v", id)
|
||
|
|
||
|
var ch models.CreditHistory
|
||
|
var ce []*models.CreditEvents
|
||
|
var e0 []*models.Event
|
||
|
var e error
|
||
|
|
||
|
ch.AccountID = id
|
||
|
|
||
|
med := strings.ToUpper(medium)
|
||
|
|
||
|
if filtered {
|
||
|
|
||
|
evType := models.EventEventTypeConsumption
|
||
|
|
||
|
e = d.Db.Where(&models.CreditEvents{AccountID: id, Medium: &med}).Not(&models.CreditEvents{EventType: &evType}).Find(&ce).Error
|
||
|
|
||
|
} else {
|
||
|
|
||
|
e = d.Db.Where(&models.CreditEvents{AccountID: id, Medium: &med}).Find(&ce).Error
|
||
|
|
||
|
}
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't have events in the system, check with administrator.", id)
|
||
|
|
||
|
}
|
||
|
|
||
|
for _, event := range ce {
|
||
|
|
||
|
var ev models.Event
|
||
|
ev.Delta = event.Delta
|
||
|
ev.EventType = event.EventType
|
||
|
ev.Timestamp = event.Timestamp
|
||
|
ev.AuthorizedBy = event.AuthorizedBy
|
||
|
e0 = append(e0, &ev)
|
||
|
|
||
|
}
|
||
|
|
||
|
l.Trace.Printf("[DB] Amount of events for the account with id: %v, is: %v.", id, len(e0))
|
||
|
|
||
|
ch.Events = e0
|
||
|
|
||
|
return &ch, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// IncreaseCredit job is to increase the credit in the system linked to the
|
||
|
// provided account by a certain amount of credit.
|
||
|
// Parameters:
|
||
|
// - id: string containing the id of the account requested.
|
||
|
// - amount: float containing the amount to be -- in the system
|
||
|
// Returns:
|
||
|
// - reference to CreditStatus containing the credit balance after the operation.
|
||
|
// - error raised in case of problems.
|
||
|
func (d *DbParameter) IncreaseCredit(id string, amount float64, medium string) (*models.CreditStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to increase credit by: %v, in the account with id: %v", amount, id)
|
||
|
|
||
|
var c, c0, cs models.CreditStatus
|
||
|
var ce models.CreditEvents
|
||
|
var e error
|
||
|
|
||
|
if r := d.Db.Where(&models.CreditStatus{AccountID: id}).First(&c).Error; errors.Is(r, gorm.ErrRecordNotFound) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account with id: %v doesn't exist in the system, check with administrator.", id)
|
||
|
|
||
|
e = errors.New("account doesn't exist in the system")
|
||
|
|
||
|
} else {
|
||
|
|
||
|
med := strings.ToUpper(medium)
|
||
|
|
||
|
if med == models.CreditEventsMediumCREDIT {
|
||
|
|
||
|
c0.AvailableCredit = c.AvailableCredit + amount
|
||
|
|
||
|
}
|
||
|
|
||
|
if med == models.CreditEventsMediumCASH {
|
||
|
|
||
|
c0.AvailableCash = c.AvailableCash + amount
|
||
|
|
||
|
}
|
||
|
|
||
|
c0.LastUpdate = strfmt.DateTime(time.Now())
|
||
|
|
||
|
ce.AccountID = id
|
||
|
ce.Delta = amount
|
||
|
ce.EventType = func(s string) *string { return &s }(models.EventEventTypeAuthorizedIncrease)
|
||
|
ce.Timestamp = strfmt.DateTime(time.Now())
|
||
|
ce.Medium = &med
|
||
|
|
||
|
if e = d.Db.Model(&c).Updates(c0).Error; e == nil {
|
||
|
|
||
|
if e = d.Db.Create(&ce).Error; e == nil {
|
||
|
|
||
|
d.Db.Where(&models.CreditStatus{AccountID: id}).First(&cs)
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to add the increase of credit event for account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to update the account in the system failed.")
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return &cs, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// ListAccounts job is to retrieve the list of all the accounts safe in the system.
|
||
|
// Returns:
|
||
|
// - slice of references to AccountStatus containing the status of every account
|
||
|
// in the system
|
||
|
func (d *DbParameter) ListAccounts() ([]*models.AccountStatus, error) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Attempting to list accounts in the system.")
|
||
|
|
||
|
var as []*models.AccountStatus
|
||
|
var e error
|
||
|
|
||
|
if e = d.Db.Find(&as).Error; e != nil {
|
||
|
|
||
|
l.Trace.Printf("[DB] There is not accounts in the system")
|
||
|
|
||
|
}
|
||
|
|
||
|
return as, e
|
||
|
|
||
|
}
|
||
|
|
||
|
// ProcessCDR job is to check every CDR report arriving to the system to add the
|
||
|
// consumptions of each account to the corresponding
|
||
|
// Parameters:
|
||
|
// - report: CDR Report model reference to be processed.
|
||
|
// - usage: a boolean discriminant to set the accounting to usage instead of cost
|
||
|
// Returns:
|
||
|
// - e: error in case of problem while doing a conversion, a cache.get, or adding the comsumption.
|
||
|
func (d *DbParameter) ProcessCDR(report cdrModels.CReport, token string) error {
|
||
|
|
||
|
l.Trace.Printf("[DB] Starting the processing of the a CDR.\n")
|
||
|
|
||
|
var planID string
|
||
|
|
||
|
now := time.Now().UnixNano()
|
||
|
|
||
|
listAccounts, e := d.ListAccounts()
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] There's was an error retrieving the accounts in the system. Error: %v\n", e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
if len(listAccounts) < 1 {
|
||
|
|
||
|
l.Trace.Printf("[DB] There's no accounts in the system right now, skipping the processing...\n")
|
||
|
|
||
|
return nil
|
||
|
|
||
|
}
|
||
|
|
||
|
p, e := d.Cache.Get(report.AccountID, "product", token)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] Something went wrong while retrieving the product info for id [ %v ]. Error: %v\n", report.AccountID, e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
product := p.(cusModels.Product)
|
||
|
|
||
|
c, e := d.Cache.Get(product.CustomerID, "customer", token)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] Something went wrong while retrieving the customer info for id [ %v ]. Error: %v\n", product.CustomerID, e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
customer := c.(cusModels.Customer)
|
||
|
|
||
|
account, e := d.GetAccountStatus(customer.CustomerID)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Trace.Printf("[DB] There's no account associated in the customer level ID: [ %v ], moving to the next level...\n", customer.CustomerID)
|
||
|
|
||
|
acc, e := d.GetAccountStatus(customer.ResellerID)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Trace.Printf("[DB] There's no account associated in the reseller level. ID: [ %v ], skipping this product [ %v ].\n", customer.ResellerID, product.ProductID)
|
||
|
|
||
|
return nil
|
||
|
|
||
|
}
|
||
|
|
||
|
account = acc
|
||
|
|
||
|
}
|
||
|
|
||
|
if !(account.Enabled) {
|
||
|
|
||
|
l.Trace.Printf("[DB] Account associated [ %v ] is disabled! Skipping...\n", account.AccountID)
|
||
|
|
||
|
return nil
|
||
|
|
||
|
}
|
||
|
|
||
|
if product.PlanID != "" {
|
||
|
|
||
|
planID = product.PlanID
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if customer.PlanID != "" {
|
||
|
|
||
|
planID = customer.PlanID
|
||
|
|
||
|
} else {
|
||
|
|
||
|
r, e := d.Cache.Get(customer.ResellerID, "reseller", token)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] Something went wrong while retrieving the reseller info for id [ %v ]. Error: %v\n", customer.ResellerID, e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
reseller := r.(cusModels.Reseller)
|
||
|
|
||
|
planID = reseller.PlanID
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
PlanDefault:
|
||
|
p, e = d.Cache.Get(planID, "plan", token)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
if planID == "DEFAULT" {
|
||
|
|
||
|
l.Warning.Printf("[DB] Something went wrong while retrieving the default plan id [ %v ]. Error: %v\n", planID, e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
l.Warning.Printf("[DB] Something went wrong while retrieving the plan id [ %v ]. Re-trying with default plan. Error: %v\n", planID, e)
|
||
|
|
||
|
planID = "DEFAULT"
|
||
|
|
||
|
goto PlanDefault
|
||
|
|
||
|
}
|
||
|
|
||
|
plan := p.(pmModels.Plan)
|
||
|
|
||
|
// In case the plan is not valid we return to the deault plan (id 0) which is valid ad vitam
|
||
|
if (time.Now()).After((time.Time)(*plan.OfferedEndDate)) || (time.Now()).Before((time.Time)(*plan.OfferedStartDate)) {
|
||
|
|
||
|
l.Warning.Printf("[DB] The plan [ %v ] is only valid between [ %v ] and [ %v ]. Falling back to default plan.\n", plan.ID, *plan.OfferedStartDate, *plan.OfferedEndDate)
|
||
|
|
||
|
planID = "DEFAULT"
|
||
|
|
||
|
goto PlanDefault
|
||
|
|
||
|
}
|
||
|
|
||
|
skus := make(map[string]*pmModels.SkuPrice)
|
||
|
|
||
|
for _, k := range plan.SkuPrices {
|
||
|
|
||
|
skus[k.SkuName] = k
|
||
|
|
||
|
}
|
||
|
|
||
|
var cashDelta, creditDelta float64
|
||
|
|
||
|
for i := range report.Usage {
|
||
|
|
||
|
var value interface{}
|
||
|
|
||
|
mode := *skus[report.Usage[i].ResourceType].AccountingMode
|
||
|
|
||
|
if mode == AC_CREDIT || mode == AC_BOTH {
|
||
|
|
||
|
for _, j := range states {
|
||
|
|
||
|
value = report.Usage[i].UsageBreakup[j]
|
||
|
|
||
|
if value == nil {
|
||
|
|
||
|
l.Debug.Printf("[DB] The state [ %v ] seem to not be part of the usage UsageBreakup [ %+v ], skipping...", j, report.Usage[i].UsageBreakup)
|
||
|
|
||
|
continue
|
||
|
|
||
|
}
|
||
|
|
||
|
if k := reflect.ValueOf(value); k.Kind() == reflect.Float64 {
|
||
|
|
||
|
creditDelta += value.(float64) * skus[report.Usage[i].ResourceType].UnitCreditPrice
|
||
|
|
||
|
continue
|
||
|
|
||
|
}
|
||
|
|
||
|
v, e := value.(json.Number).Float64()
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] There was a problem retrieving the float value from the usagebreakup interface. Error: %v.\n", e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
creditDelta += v * skus[report.Usage[i].ResourceType].UnitCreditPrice
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if mode == AC_CASH || mode == AC_BOTH {
|
||
|
|
||
|
value = report.Usage[i].Cost["totalFromSku"]
|
||
|
|
||
|
if k := reflect.ValueOf(value); k.Kind() == reflect.Float64 {
|
||
|
|
||
|
cashDelta += value.(float64)
|
||
|
|
||
|
continue
|
||
|
|
||
|
}
|
||
|
|
||
|
v, e := value.(json.Number).Float64()
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] There was a problem retrieving the float value from the cost interface. Error: %v.\n", e)
|
||
|
|
||
|
return e
|
||
|
|
||
|
}
|
||
|
|
||
|
cashDelta += v
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
state, e := d.AddConsumption(account.AccountID, d.getNiceFloat(creditDelta), MED_CREDIT)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] There was a problem while adding the consumption to the account [ %v ]. Error: %v.\n", account.AccountID, e)
|
||
|
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
if state.AvailableCredit < float64(0) {
|
||
|
|
||
|
l.Warning.Printf("[DB] Account [ %v ] credit is not positive. Credit: [ %v ].\n", account.AccountID, state.AvailableCredit)
|
||
|
|
||
|
}
|
||
|
|
||
|
l.Trace.Printf("[DB] Account [ %v ] has been updated with a [ %v ] consumption.\n", account.AccountID, creditDelta)
|
||
|
|
||
|
state, e = d.AddConsumption(account.AccountID, d.getNiceFloat(cashDelta), MED_CASH)
|
||
|
|
||
|
if e != nil {
|
||
|
|
||
|
l.Warning.Printf("[DB] There was a problem while adding the consumption to the account [ %v ]. Error: %v.\n", account.AccountID, e)
|
||
|
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
if state.AvailableCash < float64(0) {
|
||
|
|
||
|
l.Warning.Printf("[DB] Account [ %v ] cash is not positive. Cash: [ %v ].\n", account.AccountID, state.AvailableCash)
|
||
|
|
||
|
}
|
||
|
|
||
|
l.Trace.Printf("[DB] Account [ %v ] has been updated with a [ %v ] consumption.\n", account.AccountID, cashDelta)
|
||
|
|
||
|
totalTime += float64(time.Now().UnixNano()-now) / float64(time.Millisecond)
|
||
|
totalCount++
|
||
|
|
||
|
d.Metrics["count"].With(prometheus.Labels{"type": "CDRs procesed"}).Inc()
|
||
|
|
||
|
d.Metrics["time"].With(prometheus.Labels{"type": "CDRs average processing time"}).Set(totalTime / float64(totalCount))
|
||
|
|
||
|
return nil
|
||
|
|
||
|
}
|
||
|
|
||
|
func (d *DbParameter) getNiceFloat(i float64) (o float64) {
|
||
|
|
||
|
return float64(math.Round(i*scaler) / scaler)
|
||
|
|
||
|
}
|