From 79a264b974f56a9598a038d2a37e56722da3e374 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 27 Feb 2012 14:51:04 +0200 Subject: [PATCH] volume discount integrated in turbo system :) --- timespans/calldesc.go | 50 +++++++++++++++-------- timespans/calldesc_test.go | 74 +++++++++++++++++++++-------------- timespans/tariff_plans.go | 15 ++++--- timespans/test.kch | Bin 6298936 -> 6298936 bytes timespans/timespans.go | 9 ++++- timespans/timespans_test.go | 13 +++--- timespans/userbudget.go | 5 ++- timespans/userbudget_test.go | 2 +- 8 files changed, 109 insertions(+), 59 deletions(-) diff --git a/timespans/calldesc.go b/timespans/calldesc.go index b615e2ba9..a06bf6edb 100644 --- a/timespans/calldesc.go +++ b/timespans/calldesc.go @@ -55,7 +55,8 @@ type CallDescriptor struct { TimeStart, TimeEnd time.Time Amount float64 ActivationPeriods []*ActivationPeriod - StorageGetter StorageGetter + storageGetter StorageGetter + userBudget *UserBudget } /* @@ -67,6 +68,23 @@ func (cd *CallDescriptor) AddActivationPeriod(aps ...*ActivationPeriod) { } } +/* +Gets and caches the user budget information. +*/ +func (cd *CallDescriptor) getUserBudget() (ub *UserBudget, err error) { + if cd.userBudget == nil { + cd.userBudget, err = cd.storageGetter.GetUserBudget(cd.Subject) + } + return cd.userBudget, err +} + +/* +Exported method to set the storage getter. +*/ +func (cd *CallDescriptor) SetStorageGetter(sg StorageGetter) { + cd.storageGetter = sg +} + /* Restores the activation periods from storage. */ @@ -75,10 +93,10 @@ func (cd *CallDescriptor) RestoreFromStorage() (destPrefix string, err error) { base := fmt.Sprintf("%s:%s:", cd.CstmId, cd.Subject) destPrefix = cd.DestinationPrefix key := base + destPrefix - values, err := cd.StorageGetter.GetActivationPeriods(key) + values, err := cd.storageGetter.GetActivationPeriods(key) //get for a smaller prefix if the orignal one was not found - for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = cd.StorageGetter.GetActivationPeriods(key) { + for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = cd.storageGetter.GetActivationPeriods(key) { i-- destPrefix = cd.DestinationPrefix[:i] key = base + destPrefix @@ -111,9 +129,9 @@ Splits the received timespan into sub time spans according to the activation per func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeSpan) { timespans = append(timespans, firstSpan) // split on (free) minute buckets - if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil { + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { userBudget.mux.RLock() - _, bucketList := userBudget.getSecondsForPrefix(cd.StorageGetter, cd.DestinationPrefix) + _, bucketList := userBudget.getSecondsForPrefix(cd.storageGetter, cd.DestinationPrefix) for _, mb := range bucketList { for i := 0; i < len(timespans); i++ { if timespans[i].MinuteInfo != nil { @@ -192,7 +210,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) { if ts.MinuteInfo == nil && i == 0 { connectionFee = ts.Interval.ConnectFee } - cost += ts.GetCost() + cost += ts.GetCost(cd) } cc := &CallCost{TOR: cd.TOR, CstmId: cd.CstmId, @@ -216,7 +234,7 @@ func (cd *CallDescriptor) getPresentSecondCost() (cost float64, err error) { timespans := cd.splitTimeSpan(ts) if len(timespans) > 0 { - cost = round(timespans[0].GetCost(), 3) + cost = round(timespans[0].GetCost(cd), 3) } return } @@ -230,10 +248,10 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { _, err = cd.RestoreFromStorage() now := time.Now() availableCredit, availableSeconds := 0.0, 0.0 - if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil { + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { userBudget.mux.RLock() availableCredit = userBudget.Credit - availableSeconds, _ = userBudget.getSecondsForPrefix(cd.StorageGetter, cd.DestinationPrefix) + availableSeconds, _ = userBudget.getSecondsForPrefix(cd.storageGetter, cd.DestinationPrefix) userBudget.mux.RUnlock() } else { return cd.Amount, err @@ -254,7 +272,7 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { if ts.MinuteInfo == nil && i == 0 { cost += ts.Interval.ConnectFee } - cost += ts.GetCost() + cost += ts.GetCost(cd) } if cost < availableCredit { return maxSessionSeconds, nil @@ -266,22 +284,22 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { } func (cd *CallDescriptor) DebitCents() (left float64, err error) { - if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil { - return userBudget.debitMoneyBudget(cd.StorageGetter, cd.Amount), nil + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { + return userBudget.debitMoneyBudget(cd.storageGetter, cd.Amount), nil } return 0.0, err } func (cd *CallDescriptor) DebitSMS() (left float64, err error) { - if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil { - return userBudget.debitSMSBuget(cd.StorageGetter, cd.Amount) + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { + return userBudget.debitSMSBuget(cd.storageGetter, cd.Amount) } return 0, err } func (cd *CallDescriptor) DebitSeconds() (err error) { - if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil { - return userBudget.debitMinutesBudget(cd.StorageGetter, cd.Amount, cd.DestinationPrefix) + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { + return userBudget.debitMinutesBudget(cd.storageGetter, cd.Amount, cd.DestinationPrefix) } return err } diff --git a/timespans/calldesc_test.go b/timespans/calldesc_test.go index 72df3eb0e..f63c10bcc 100644 --- a/timespans/calldesc_test.go +++ b/timespans/calldesc_test.go @@ -29,7 +29,7 @@ func TestKyotoSplitSpans(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} cd.RestoreFromStorage() timespans := cd.splitInTimeSpans() @@ -44,7 +44,7 @@ func TestRedisSplitSpans(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter} cd.RestoreFromStorage() timespans := cd.splitInTimeSpans() @@ -60,13 +60,13 @@ func TestKyotoGetCost(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { t.Errorf("Expected %v was %v", expected, result) } - cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ = cd.GetCost() expected = &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 540, ConnectFee: 0} } @@ -77,7 +77,7 @@ func TestRedisGetCost(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -94,7 +94,7 @@ func TestMongoGetCost(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -108,7 +108,7 @@ func TestFullDestNotFound(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -122,7 +122,7 @@ func TestMultipleActivationPeriods(t *testing.T) { t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 330, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -138,7 +138,7 @@ func TestSpansMultipleActivationPeriods(t *testing.T) { t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 360, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -152,7 +152,7 @@ func TestLessThanAMinute(t *testing.T) { t1 := time.Date(2012, time.February, 8, 23, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 23, 50, 30, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 0.5, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -166,7 +166,7 @@ func TestUniquePrice(t *testing.T) { t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", Cost: 60.35, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -180,7 +180,7 @@ func TestPresentSecodCost(t *testing.T) { t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.getPresentSecondCost() expected := 0.016 if result != expected { @@ -194,7 +194,7 @@ func TestMinutesCost(t *testing.T) { t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 8, 22, 51, 50, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter} result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", Cost: 0.1, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { @@ -206,7 +206,7 @@ func TestMinutesCost(t *testing.T) { func TestMaxSessionTimeNoUserBudget(t *testing.T) { getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10) defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", StorageGetter: getter, Amount: 1000} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", storageGetter: getter, Amount: 1000} result, err := cd.GetMaxSessionTime() if result != 1000 || err != nil { t.Errorf("Expected %v was %v", 1000, result) @@ -216,7 +216,7 @@ func TestMaxSessionTimeNoUserBudget(t *testing.T) { func TestMaxSessionTimeWithUserBudget(t *testing.T) { getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10) defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 5400} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 5400} result, err := cd.GetMaxSessionTime() if result != 1080 || err != nil { t.Errorf("Expected %v was %v", 1080, result) @@ -226,13 +226,29 @@ func TestMaxSessionTimeWithUserBudget(t *testing.T) { func TestMaxSessionTimeNoCredit(t *testing.T) { getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10) defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "broker", DestinationPrefix: "0723", StorageGetter: getter, Amount: 5400} + cd := &CallDescriptor{CstmId: "vdf", Subject: "broker", DestinationPrefix: "0723", storageGetter: getter, Amount: 5400} result, err := cd.GetMaxSessionTime() if result != 100 || err != nil { t.Errorf("Expected %v was %v", 100, result) } } +func TestGetCostWithVolumeDiscount(t *testing.T) { + getter, _ := NewKyotoStorage("test.kch") + defer getter.Close() + vd1 := &VolumeDiscount{100, 10} + vd2 := &VolumeDiscount{500, 20} + seara := &TariffPlan{Id: "seara", SmsCredit: 100, VolumeDiscountThresholds: []*VolumeDiscount{vd1, vd2}} + rifsBudget := &UserBudget{Id: "other", Credit: 21, tariffPlan: seara, ResetDayOfTheMonth: 10, VolumeDiscountSeconds: 105} + t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter, userBudget: rifsBudget} + callCost, err := cd.GetCost() + if callCost.Cost != 54.0 || err != nil { + t.Errorf("Expected %v was %v", 54.0, callCost) + } +} + /*********************************** BENCHMARKS ***************************************/ func BenchmarkRedisGetting(b *testing.B) { b.StopTimer() @@ -255,7 +271,7 @@ func BenchmarkRedisRestoring(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { cd.RestoreFromStorage() @@ -269,7 +285,7 @@ func BenchmarkRedisGetCost(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetCost() @@ -283,7 +299,7 @@ func BenchmarkKyotoGetting(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { key := cd.GetKey() @@ -298,7 +314,7 @@ func BenchmarkKyotoRestoring(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { cd.RestoreFromStorage() @@ -312,7 +328,7 @@ func BenchmarkSplitting(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} cd.RestoreFromStorage() b.StartTimer() for i := 0; i < b.N; i++ { @@ -327,7 +343,7 @@ func BenchmarkKyotoGetCost(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetCost() @@ -355,7 +371,7 @@ func BenchmarkMongoGetCost(b *testing.B) { t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetCost() @@ -366,7 +382,7 @@ func BenchmarkKyotoSingleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewKyotoStorage("test.kch") defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 100} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 100} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() @@ -377,7 +393,7 @@ func BenchmarkKyotoMultipleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewKyotoStorage("test.kch") defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 5400} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 5400} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() @@ -388,7 +404,7 @@ func BenchmarkRedisSingleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewRedisStorage("", 10) defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 100} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 100} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() @@ -399,7 +415,7 @@ func BenchmarkRedisMultipleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewRedisStorage("", 10) defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 5400} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 5400} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() @@ -410,7 +426,7 @@ func BenchmarkMongoSingleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewMongoStorage("127.0.0.1", "test") defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 100} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 100} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() @@ -421,7 +437,7 @@ func BenchmarkMongoMultipleGetSessionTime(b *testing.B) { b.StopTimer() getter, _ := NewMongoStorage("127.0.0.1", "test") defer getter.Close() - cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", StorageGetter: getter, Amount: 5400} + cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", storageGetter: getter, Amount: 5400} b.StartTimer() for i := 0; i < b.N; i++ { cd.GetMaxSessionTime() diff --git a/timespans/tariff_plans.go b/timespans/tariff_plans.go index 6bb821bf8..4f2002ec4 100644 --- a/timespans/tariff_plans.go +++ b/timespans/tariff_plans.go @@ -18,6 +18,7 @@ along with this program. If not, see package timespans import ( + // "log" "strconv" "strings" ) @@ -82,11 +83,13 @@ func (tp *TariffPlan) restore(input string) { mb.restore(mbs) tp.MinuteBuckets = append(tp.MinuteBuckets, mb) } - for _, vdss := range strings.Split(elements[4], ",") { - vd := &VolumeDiscount{} - vds := strings.Split(vdss, "|") - vd.Volume, _ = strconv.ParseFloat(vds[0], 64) - vd.Discount, _ = strconv.ParseFloat(vds[1], 64) - tp.VolumeDiscountThresholds = append(tp.VolumeDiscountThresholds, vd) + if len(elements) > 4 { + for _, vdss := range strings.Split(elements[4], ",") { + vd := &VolumeDiscount{} + vds := strings.Split(vdss, "|") + vd.Volume, _ = strconv.ParseFloat(vds[0], 64) + vd.Discount, _ = strconv.ParseFloat(vds[1], 64) + tp.VolumeDiscountThresholds = append(tp.VolumeDiscountThresholds, vd) + } } } diff --git a/timespans/test.kch b/timespans/test.kch index 24fde4769eebf668dd6e44fff83af2449d2654f9..99f1e2ebf2990f1e480089ba23b5fdff6dfcc905 100644 GIT binary patch delta 245 zcmYkrM=}Ed06%>Df) zAYV{{LPd&|C{?Chg-TVb)u>gcUW1TEO~RVBh=^*{rd@}aPF=e7=oQze-++WcLxzn= zN*Og~+=NL}rp=g@HfP>~MN5{gShZ%|hD}?x?bx+v-+@C%j-5Dl=G=u#SFYW-b?4rL l$InbG5((%1t1$8Mlzq;olF9U+k3cjNe;*5dy+$%WfnTlgP}~3j delta 249 zcmYksHBtis06 diff --git a/timespans/timespans.go b/timespans/timespans.go index 501c70857..8600a563c 100644 --- a/timespans/timespans.go +++ b/timespans/timespans.go @@ -49,7 +49,7 @@ func (ts *TimeSpan) GetDuration() time.Duration { /* Returns the cost of the timespan according to the relevant cost interval. */ -func (ts *TimeSpan) GetCost() (cost float64) { +func (ts *TimeSpan) GetCost(cd *CallDescriptor) (cost float64) { if ts.MinuteInfo != nil { return ts.GetDuration().Seconds() * ts.MinuteInfo.Price } @@ -61,6 +61,13 @@ func (ts *TimeSpan) GetCost() (cost float64) { } else { cost = ts.GetDuration().Seconds() * ts.Interval.Price } + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { + userBudget.mux.RLock() + if percentageDiscount, err := userBudget.getVolumeDiscount(cd.storageGetter); err == nil && percentageDiscount > 0 { + cost *= (100 - percentageDiscount) / 100 + } + userBudget.mux.RUnlock() + } return } diff --git a/timespans/timespans_test.go b/timespans/timespans_test.go index 0a138acd9..c0ee69160 100644 --- a/timespans/timespans_test.go +++ b/timespans/timespans_test.go @@ -184,19 +184,22 @@ func TestSplitByActivationTime(t *testing.T) { } func TestTimespanGetCost(t *testing.T) { + getter, _ := NewKyotoStorage("test.kch") + defer getter.Close() t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC) ts1 := TimeSpan{TimeStart: t1, TimeEnd: t2} - if ts1.GetCost() != 0 { + cd := &CallDescriptor{Subject: "other", storageGetter: getter} + if ts1.GetCost(cd) != 0 { t.Error("No interval and still kicking") } ts1.Interval = &Interval{Price: 1} - if ts1.GetCost() != 600 { - t.Error("Expected 10 got ", ts1.GetCost()) + if ts1.GetCost(cd) != 600 { + t.Error("Expected 10 got ", ts1.GetCost(cd)) } ts1.Interval.BillingUnit = .1 - if ts1.GetCost() != 6000 { - t.Error("Expected 6000 got ", ts1.GetCost()) + if ts1.GetCost(cd) != 6000 { + t.Error("Expected 6000 got ", ts1.GetCost(cd)) } } diff --git a/timespans/userbudget.go b/timespans/userbudget.go index e403752bf..0f2b58625 100644 --- a/timespans/userbudget.go +++ b/timespans/userbudget.go @@ -116,9 +116,12 @@ func (ub *UserBudget) getTariffPlan(storage StorageGetter) (tp *TariffPlan, err return ub.tariffPlan, err } +/* +Returns thevolume discount procentage according to the nuber of acumulated volume discount seconds. +*/ func (ub *UserBudget) getVolumeDiscount(storage StorageGetter) (float64, error) { tariffPlan, err := ub.getTariffPlan(storage) - if err != nil { + if err != nil || tariffPlan == nil { return 0.0, err } thresholds := len(tariffPlan.VolumeDiscountThresholds) diff --git a/timespans/userbudget_test.go b/timespans/userbudget_test.go index d4e311cd5..1569d7ee7 100644 --- a/timespans/userbudget_test.go +++ b/timespans/userbudget_test.go @@ -315,7 +315,7 @@ func TestGetVolumeDiscountNotHaving(t *testing.T) { } } -func TestGetVolumeDiscountNotSteps(t *testing.T) { +func TestGetVolumeDiscountSteps(t *testing.T) { vd1 := &VolumeDiscount{100, 11} vd2 := &VolumeDiscount{500, 20} seara := &TariffPlan{Id: "seara", SmsCredit: 100, VolumeDiscountThresholds: []*VolumeDiscount{vd1, vd2}}