From 02430bef24a741b02d5456877eff683f5e805483 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 29 Feb 2012 16:22:06 +0200 Subject: [PATCH] implemented received call bonus --- timespans/minute_buckets.go | 11 +++--- timespans/tariff_plans.go | 61 ++++++++++++++++++++++++++------ timespans/tariff_plans_test.go | 14 +++++--- timespans/test.kch | Bin 6299032 -> 6299136 bytes timespans/test_tariffplans.json | 3 ++ timespans/userbudget.go | 28 +++++++++++---- timespans/userbudget_test.go | 12 +++++++ 7 files changed, 103 insertions(+), 26 deletions(-) diff --git a/timespans/minute_buckets.go b/timespans/minute_buckets.go index fd2cd0aae..908c7fcc1 100644 --- a/timespans/minute_buckets.go +++ b/timespans/minute_buckets.go @@ -18,6 +18,7 @@ along with this program. If not, see package timespans import ( + // "log" "math" "strconv" "strings" @@ -47,11 +48,11 @@ func (mb *MinuteBucket) store() (result string) { De-serializes the minute bucket for the storage. Used for key-value storages. */ func (mb *MinuteBucket) restore(input string) { - mbse := strings.Split(input, "|") - mb.Seconds, _ = strconv.ParseFloat(mbse[0], 64) - mb.Priority, _ = strconv.Atoi(mbse[1]) - mb.Price, _ = strconv.ParseFloat(mbse[2], 64) - mb.DestinationId = mbse[3] + elements := strings.Split(input, "|") + mb.Seconds, _ = strconv.ParseFloat(elements[0], 64) + mb.Priority, _ = strconv.Atoi(elements[1]) + mb.Price, _ = strconv.ParseFloat(elements[2], 64) + mb.DestinationId = elements[3] } /* diff --git a/timespans/tariff_plans.go b/timespans/tariff_plans.go index 4d9a9c6fe..b69a287da 100644 --- a/timespans/tariff_plans.go +++ b/timespans/tariff_plans.go @@ -45,13 +45,6 @@ type VolumeDiscount struct { Discount float64 // procentage } -type RecivedCallBonus struct { - Credit float64 - SmsCredit float64 - Traffic float64 - MinuteBuckets *MinuteBucket -} - /* Serializes the tariff plan for the storage. Used for key-value storages. */ @@ -59,13 +52,19 @@ func (tp *TariffPlan) store() (result string) { result += strconv.FormatFloat(tp.SmsCredit, 'f', -1, 64) + ";" result += strconv.FormatFloat(tp.Traffic, 'f', -1, 64) + ";" result += strconv.FormatFloat(tp.ReceivedCallSecondsLimit, 'f', -1, 64) + ";" + if tp.RecivedCallBonus == nil { + tp.RecivedCallBonus = &RecivedCallBonus{} + } + result += tp.RecivedCallBonus.store() + ";" for i, mb := range tp.MinuteBuckets { if i > 0 { result += "," } result += mb.store() } - result += ";" + if tp.VolumeDiscountThresholds != nil { + result += ";" + } for i, vd := range tp.VolumeDiscountThresholds { if i > 0 { result += "," @@ -84,13 +83,15 @@ func (tp *TariffPlan) restore(input string) { tp.SmsCredit, _ = strconv.ParseFloat(elements[0], 64) tp.Traffic, _ = strconv.ParseFloat(elements[1], 64) tp.ReceivedCallSecondsLimit, _ = strconv.ParseFloat(elements[2], 64) - for _, mbs := range strings.Split(elements[3], ",") { + tp.RecivedCallBonus = &RecivedCallBonus{} + tp.RecivedCallBonus.restore(elements[3]) + for _, mbs := range strings.Split(elements[4], ",") { mb := &MinuteBucket{} mb.restore(mbs) tp.MinuteBuckets = append(tp.MinuteBuckets, mb) } - if len(elements) > 4 { - for _, vdss := range strings.Split(elements[4], ",") { + if len(elements) > 5 { + for _, vdss := range strings.Split(elements[5], ",") { vd := &VolumeDiscount{} vds := strings.Split(vdss, "|") vd.Volume, _ = strconv.ParseFloat(vds[0], 64) @@ -99,3 +100,41 @@ func (tp *TariffPlan) restore(input string) { } } } + +/* +Structure to be filled for each tariff plan with the bonus value for received calls minutes. +*/ +type RecivedCallBonus struct { + Credit float64 + SmsCredit float64 + Traffic float64 + MinuteBucket *MinuteBucket +} + +/* +Serializes the tariff plan for the storage. Used for key-value storages. +*/ +func (rcb *RecivedCallBonus) store() (result string) { + result += strconv.FormatFloat(rcb.Credit, 'f', -1, 64) + "," + result += strconv.FormatFloat(rcb.SmsCredit, 'f', -1, 64) + "," + result += strconv.FormatFloat(rcb.Traffic, 'f', -1, 64) + if rcb.MinuteBucket != nil { + result += "," + result += rcb.MinuteBucket.store() + } + return +} + +/* +De-serializes the tariff plan for the storage. Used for key-value storages. +*/ +func (rcb *RecivedCallBonus) restore(input string) { + elements := strings.Split(input, ",") + rcb.Credit, _ = strconv.ParseFloat(elements[0], 64) + rcb.SmsCredit, _ = strconv.ParseFloat(elements[1], 64) + rcb.Traffic, _ = strconv.ParseFloat(elements[2], 64) + if len(elements) > 3 { + rcb.MinuteBucket = &MinuteBucket{} + rcb.MinuteBucket.restore(elements[3]) + } +} diff --git a/timespans/tariff_plans_test.go b/timespans/tariff_plans_test.go index c80d41207..bb2ad3dcb 100644 --- a/timespans/tariff_plans_test.go +++ b/timespans/tariff_plans_test.go @@ -24,8 +24,14 @@ 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"} + rcb := &RecivedCallBonus{Credit: 100} vd := &VolumeDiscount{100, 10} - seara := &TariffPlan{Id: "seara_voo", SmsCredit: 100, ReceivedCallSecondsLimit: 0, MinuteBuckets: []*MinuteBucket{b1, b2}, VolumeDiscountThresholds: []*VolumeDiscount{vd}} + seara := &TariffPlan{Id: "seara_voo", + SmsCredit: 100, + ReceivedCallSecondsLimit: 0, + RecivedCallBonus: rcb, + MinuteBuckets: []*MinuteBucket{b1, b2}, + VolumeDiscountThresholds: []*VolumeDiscount{vd}} s := seara.store() tp1 := &TariffPlan{Id: "seara_voo"} tp1.restore(s) @@ -82,7 +88,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_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}} for i := 0; i < b.N; i++ { getter.SetTariffPlan(seara) getter.GetTariffPlan(seara.Id) @@ -94,7 +100,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_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}} for i := 0; i < b.N; i++ { getter.SetTariffPlan(seara) getter.GetTariffPlan(seara.Id) @@ -106,7 +112,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_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}} for i := 0; i < b.N; i++ { getter.SetTariffPlan(seara) getter.GetTariffPlan(seara.Id) diff --git a/timespans/test.kch b/timespans/test.kch index 3edb68d9bb492ae54d65c00391fb483259129c97..10bc6a0864d35b613fd7fb0bf65f27157eb4a651 100644 GIT binary patch delta 642 zcmbQSyMei3PXqG=bq+xW5J-?~G;B3w+-k^_G_if+L?$3+-ac_6%YtskMF^Qjhpi5b zvGdzM`f_gn=*xAdm$4QhxzVA2L;HSNzU}*E`QOJLk z8e;*O79MqJcU^4*#I`_e2gLT@3HVBG4!6g-i9)@w;- z9_HB_4edSJ^>-=*u?i5Y0_LFJg$tH+xKO~*t&nVA|B5wpXB)%*^AITt<>F1;q*csnVPmxXV0RRu< B$X@^e diff --git a/timespans/test_tariffplans.json b/timespans/test_tariffplans.json index b4484102f..3fc95b306 100644 --- a/timespans/test_tariffplans.json +++ b/timespans/test_tariffplans.json @@ -1,14 +1,17 @@ [ {"Id":"seara","SmsCredit":100,"ReceivedCallsSecondsLimit": 100, + "RecivedCallBonus" : {"Credit": 100}, "MinuteBuckets": [{"Seconds":10,"Priority":10,"Price":0.01,"DestinationId":"nationale"}, {"Seconds":100,"Priority":20,"Price":0,"DestinationId":"retea"}], "VolumeDiscountThresholds": [{"Volume": 100, "Discount": 10},{"Volume": 500, "Discount": 15},{"Volume": 1000, "Discount": 20}] }, {"Id":"dimineata","SmsCredit":100,"ReceivedCallsSecondsLimit": 100, + "RecivedCallBonus" : {"Credit": 100}, "MinuteBuckets": [{"Seconds":100,"Priority":10,"Price":0.01,"DestinationId":"nationale"}, {"Seconds":1000,"Priority":20,"Price":0,"DestinationId":"retea"}], "VolumeDiscountThresholds": [{"Volume": 100, "Discount": 10},{"Volume": 500, "Discount": 15},{"Volume": 1000, "Discount": 20}] } ] + diff --git a/timespans/userbudget.go b/timespans/userbudget.go index 2e0c2eb15..4de2a75e6 100644 --- a/timespans/userbudget.go +++ b/timespans/userbudget.go @@ -80,7 +80,10 @@ func (ub *UserBudget) store() (result string) { result += strconv.FormatFloat(ub.VolumeDiscountSeconds, 'f', -1, 64) + ";" result += strconv.FormatFloat(ub.ReceivedCallSeconds, 'f', -1, 64) + ";" result += strconv.Itoa(ub.ResetDayOfTheMonth) + ";" - result += ub.TariffPlanId + ";" + result += ub.TariffPlanId + if ub.MinuteBuckets != nil { + result += ";" + } for i, mb := range ub.MinuteBuckets { if i > 0 { result += "," @@ -102,10 +105,12 @@ func (ub *UserBudget) restore(input string) { ub.ReceivedCallSeconds, _ = strconv.ParseFloat(elements[4], 64) ub.ResetDayOfTheMonth, _ = strconv.Atoi(elements[5]) ub.TariffPlanId = elements[6] - for _, mbs := range strings.Split(elements[7], ",") { - mb := &MinuteBucket{} - mb.restore(mbs) - ub.MinuteBuckets = append(ub.MinuteBuckets, mb) + if len(elements) > 7 { + for _, mbs := range strings.Split(elements[7], ",") { + mb := &MinuteBucket{} + mb.restore(mbs) + ub.MinuteBuckets = append(ub.MinuteBuckets, mb) + } } } @@ -249,7 +254,18 @@ func (ub *UserBudget) addReceivedCallSeconds(sg StorageGetter, amount float64) e if tariffPlan, err := ub.getTariffPlan(sg); tariffPlan != nil && err == nil { if ub.ReceivedCallSeconds >= tariffPlan.ReceivedCallSecondsLimit { ub.ReceivedCallSeconds -= tariffPlan.ReceivedCallSecondsLimit - // do the dew + if tariffPlan.RecivedCallBonus != nil { // apply the bonus + ub.Credit += tariffPlan.RecivedCallBonus.Credit + ub.SmsCredit += tariffPlan.RecivedCallBonus.SmsCredit + ub.Traffic += tariffPlan.RecivedCallBonus.Traffic + if tariffPlan.RecivedCallBonus.MinuteBucket != nil { + for _, mb := range ub.MinuteBuckets { + if mb.DestinationId == tariffPlan.RecivedCallBonus.MinuteBucket.DestinationId { + mb.Seconds += tariffPlan.RecivedCallBonus.MinuteBucket.Seconds + } + } + } + } } } return sg.SetUserBudget(ub) diff --git a/timespans/userbudget_test.go b/timespans/userbudget_test.go index 754b1d3e2..11eef1b73 100644 --- a/timespans/userbudget_test.go +++ b/timespans/userbudget_test.go @@ -376,6 +376,18 @@ func TestGetVolumeDiscountSteps(t *testing.T) { } } +func TestRecivedCallsBonus(t *testing.T) { + getter, _ := NewKyotoStorage("test.kch") + defer getter.Close() + rcb := &RecivedCallBonus{Credit: 100} + seara := &TariffPlan{Id: "seara_voo", SmsCredit: 100, ReceivedCallSecondsLimit: 10, RecivedCallBonus: rcb} + rifsBudget := &UserBudget{Id: "other", Credit: 21, tariffPlan: seara, ResetDayOfTheMonth: 10, ReceivedCallSeconds: 1} + err := rifsBudget.addReceivedCallSeconds(getter, 12) + if err != nil || rifsBudget.Credit != 121 || rifsBudget.ReceivedCallSeconds != 3 { + t.Error("Wrong Received call bonus procedure: ", rifsBudget) + } +} + /*********************************** Benchmarks *******************************/ func BenchmarkGetSecondForPrefix(b *testing.B) {