mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
working on user budget
This commit is contained in:
@@ -28,7 +28,7 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) {
|
||||
Serializes the activation periods for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ap *ActivationPeriod) store() (result string) {
|
||||
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
|
||||
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
|
||||
for _, i := range ap.Intervals {
|
||||
var is string
|
||||
is = strconv.Itoa(int(i.Month)) + "|"
|
||||
|
||||
@@ -4,15 +4,17 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure that gathers multiple destination prefixes under a common id.
|
||||
*/
|
||||
type Destination struct {
|
||||
Id string
|
||||
Prefixes []string
|
||||
}
|
||||
|
||||
func (d *Destination) GetKey() (result string) {
|
||||
return d.Id
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (d *Destination) store() (result string) {
|
||||
for _, p := range d.Prefixes {
|
||||
result += p + ","
|
||||
@@ -26,7 +28,7 @@ func (d *Destination) restore(input string) {
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if the bucket contains specified prefix.
|
||||
De-serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (d *Destination) containsPrefix(prefix string) bool {
|
||||
for _, p := range d.Prefixes {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package timespans
|
||||
|
||||
type MinuteBucket struct {
|
||||
Seconds int
|
||||
Priority int
|
||||
Price float64
|
||||
Seconds int
|
||||
Priority int
|
||||
Price float64
|
||||
DestinationId string
|
||||
destination *Destination
|
||||
destination *Destination
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the destination loading it from the storage if necessary.
|
||||
*/
|
||||
func (mb *MinuteBucket) getDestination(storage StorageGetter) (dest *Destination) {
|
||||
if mb.destination == nil {
|
||||
mb.destination,_ = storage.GetDestination(mb.DestinationId)
|
||||
mb.destination, _ = storage.GetDestination(mb.DestinationId)
|
||||
}
|
||||
return mb.destination
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ these numbers to the user budget every month.
|
||||
*/
|
||||
type TariffPlan struct {
|
||||
Id string
|
||||
SmsCredit int
|
||||
SmsCredit int
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the activation periods for the storage. Used for key-value storages.
|
||||
Serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) store() (result string) {
|
||||
result += strconv.Itoa(tp.SmsCredit) + ";"
|
||||
@@ -32,17 +32,17 @@ func (tp *TariffPlan) store() (result string) {
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the activation periods for the storage. Used for key-value storages.
|
||||
De-serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
tp.SmsCredit,_ = strconv.Atoi(elements[0])
|
||||
tp.SmsCredit, _ = strconv.Atoi(elements[0])
|
||||
for _, mbs := range elements[1 : len(elements)-1] {
|
||||
mb := &MinuteBucket{}
|
||||
mbse := strings.Split(mbs, "|")
|
||||
mb.Seconds,_ = strconv.Atoi(mbse[0])
|
||||
mb.Priority,_ = strconv.Atoi(mbse[1])
|
||||
mb.Price,_ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.Seconds, _ = strconv.Atoi(mbse[0])
|
||||
mb.Priority, _ = strconv.Atoi(mbse[1])
|
||||
mb.Price, _ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.DestinationId = mbse[3]
|
||||
|
||||
tp.MinuteBuckets = append(tp.MinuteBuckets, mb)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
func TestTariffPlanStoreRestore(t *testing.T) {
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
s := seara.store()
|
||||
tp1 := &TariffPlan{Id: "seara"}
|
||||
tp1.restore(s)
|
||||
@@ -21,7 +21,7 @@ func TestTariffPlanKyotoStore(t *testing.T) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
@@ -34,7 +34,7 @@ func TestTariffPlanRedisStore(t *testing.T) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
@@ -47,7 +47,7 @@ func TestTariffPlanMongoStore(t *testing.T) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
@@ -62,7 +62,7 @@ func BenchmarkTariffPlanKyotoStoreRestore(b *testing.B) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
@@ -74,7 +74,7 @@ func BenchmarkTariffPlanRedisStoreRestore(b *testing.B) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
@@ -86,7 +86,7 @@ func BenchmarkTariffPlanMongoStoreRestore(b *testing.B) {
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
|
||||
@@ -3,31 +3,85 @@ package timespans
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure conatining information about user's credit (minutes, cents, sms...).'
|
||||
*/
|
||||
type UserBudget struct {
|
||||
id string
|
||||
minuteBuckets []*MinuteBucket
|
||||
credit float64
|
||||
smsCredit int
|
||||
Id string
|
||||
Credit float64
|
||||
SmsCredit int
|
||||
ResetDayOfTheMonth int
|
||||
TariffPlanId string
|
||||
tariffPlan *TariffPlan
|
||||
resetDayOfTheMonth int
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the user budget for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ub *UserBudget) store() (result string) {
|
||||
result += strconv.FormatFloat(ub.Credit, 'f', -1, 64) + ";"
|
||||
result += strconv.Itoa(ub.SmsCredit) + ";"
|
||||
result += strconv.Itoa(ub.ResetDayOfTheMonth) + ";"
|
||||
result += ub.TariffPlanId + ";"
|
||||
for _, mb := range ub.MinuteBuckets {
|
||||
var mbs string
|
||||
mbs += strconv.Itoa(int(mb.Seconds)) + "|"
|
||||
mbs += strconv.Itoa(int(mb.Priority)) + "|"
|
||||
mbs += strconv.FormatFloat(mb.Price, 'f', -1, 64) + "|"
|
||||
mbs += mb.DestinationId
|
||||
result += mbs + ";"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the user budget for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ub *UserBudget) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
ub.Credit, _ = strconv.ParseFloat(elements[0], 64)
|
||||
ub.SmsCredit, _ = strconv.Atoi(elements[1])
|
||||
ub.ResetDayOfTheMonth, _ = strconv.Atoi(elements[2])
|
||||
ub.TariffPlanId = elements[3]
|
||||
for _, mbs := range elements[4 : len(elements)-1] {
|
||||
mb := &MinuteBucket{}
|
||||
mbse := strings.Split(mbs, "|")
|
||||
mb.Seconds, _ = strconv.Atoi(mbse[0])
|
||||
mb.Priority, _ = strconv.Atoi(mbse[1])
|
||||
mb.Price, _ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.DestinationId = mbse[3]
|
||||
|
||||
ub.MinuteBuckets = append(ub.MinuteBuckets, mb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Returns the tariff plan loading it from the storage if necessary.
|
||||
*/
|
||||
func (ub *UserBudget) getTariffPlan(storage StorageGetter) (tp *TariffPlan) {
|
||||
if ub.tariffPlan == nil {
|
||||
ub.tariffPlan, _ = storage.GetTariffPlan(ub.TariffPlanId)
|
||||
}
|
||||
return ub.tariffPlan
|
||||
}
|
||||
|
||||
/*
|
||||
Returns user's avaliable minutes for the specified destination
|
||||
*/
|
||||
func (ub *UserBudget) GetSecondsForPrefix(storage StorageGetter, prefix string) (seconds int) {
|
||||
if len(ub.minuteBuckets) == 0 {
|
||||
log.Print("There are no minute buckets to check for user", ub.id)
|
||||
if len(ub.MinuteBuckets) == 0 {
|
||||
log.Print("There are no minute buckets to check for user", ub.Id)
|
||||
return
|
||||
}
|
||||
bestBucket := ub.minuteBuckets[0]
|
||||
bestBucket := ub.MinuteBuckets[0]
|
||||
|
||||
for _, mb := range ub.minuteBuckets {
|
||||
for _, mb := range ub.MinuteBuckets {
|
||||
d := mb.getDestination(storage)
|
||||
if d.containsPrefix(prefix) && mb.Priority > bestBucket.Priority {
|
||||
bestBucket = mb
|
||||
@@ -35,7 +89,7 @@ func (ub *UserBudget) GetSecondsForPrefix(storage StorageGetter, prefix string)
|
||||
}
|
||||
seconds = bestBucket.Seconds
|
||||
if bestBucket.Price > 0 {
|
||||
seconds = int(math.Min(ub.credit/bestBucket.Price, float64(seconds)))
|
||||
seconds = int(math.Min(ub.Credit/bestBucket.Price, float64(seconds)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package timespans
|
||||
|
||||
import (
|
||||
"testing"
|
||||
//"log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -14,7 +15,7 @@ func TestGetSeconds(t *testing.T) {
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, destination: retea}
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 200, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
ub1 := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 200, tariffPlan: tf1, ResetDayOfTheMonth: 10}
|
||||
seconds := ub1.GetSecondsForPrefix(nil, "0723")
|
||||
expected := 100
|
||||
if seconds != expected {
|
||||
@@ -27,7 +28,7 @@ func TestGetPricedSeconds(t *testing.T) {
|
||||
b2 := &MinuteBucket{Seconds: 100, Price: 1, Priority: 20, destination: retea}
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 21, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
ub1 := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, tariffPlan: tf1, ResetDayOfTheMonth: 10}
|
||||
seconds := ub1.GetSecondsForPrefix(nil, "0723")
|
||||
expected := 21
|
||||
if seconds != expected {
|
||||
@@ -35,6 +36,20 @@ func TestGetPricedSeconds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserBudgetStoreRestore(t *testing.T) {
|
||||
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
rifsBudget := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, tariffPlan: seara, ResetDayOfTheMonth: 10}
|
||||
s := rifsBudget.store()
|
||||
ub1 := &UserBudget{Id: "rif"}
|
||||
ub1.restore(s)
|
||||
if ub1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, ub1.store())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************** Benchmarks *******************************/
|
||||
|
||||
func BenchmarkGetSecondForPrefix(b *testing.B) {
|
||||
@@ -43,9 +58,9 @@ func BenchmarkGetSecondForPrefix(b *testing.B) {
|
||||
b2 := &MinuteBucket{Seconds: 100, Price: 1, Priority: 20, destination: retea}
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 21, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
ub1 := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, tariffPlan: tf1, ResetDayOfTheMonth: 10}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ub1.GetSecondsForPrefix(nil,"0723")
|
||||
ub1.GetSecondsForPrefix(nil, "0723")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user