diff --git a/engine/callcost.go b/engine/callcost.go index 3ac52e29a..973c4d900 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -47,7 +47,7 @@ func (cc *CallCost) Merge(other *CallCost) { } ts := cc.Timespans[len(cc.Timespans)-1] otherTs := other.Timespans[0] - if reflect.DeepEqual(ts.RatingPlan, otherTs.RatingPlan) && + if reflect.DeepEqual(ts.ratingPlan, otherTs.ratingPlan) && reflect.DeepEqual(ts.RateInterval, otherTs.RateInterval) { // extend the last timespan with ts.TimeEnd = ts.TimeEnd.Add(otherTs.GetDuration()) diff --git a/engine/calldesc.go b/engine/calldesc.go index 80b765f63..0ae284cb2 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -201,17 +201,16 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti if len(cd.RatingPlans) == 0 { return } - firstSpan.RatingPlan = cd.RatingPlans[0] - + firstSpan.ratingPlan = cd.RatingPlans[0] // split on activation periods afterStart, afterEnd := false, false //optimization for multiple activation periods - for _, ap := range cd.RatingPlans { - if !afterStart && !afterEnd && ap.ActivationTime.Before(cd.TimeStart) { - firstSpan.RatingPlan = ap + for _, rp := range cd.RatingPlans { + if !afterStart && !afterEnd && rp.ActivationTime.Before(cd.TimeStart) { + firstSpan.ratingPlan = rp } else { afterStart = true for i := 0; i < len(timespans); i++ { - newTs := timespans[i].SplitByRatingPlan(ap) + newTs := timespans[i].SplitByRatingPlan(rp) if newTs != nil { timespans = append(timespans, newTs) } else { @@ -223,16 +222,16 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti } // split on price intervals for i := 0; i < len(timespans); i++ { - ap := timespans[i].RatingPlan + rp := timespans[i].ratingPlan //timespans[i].RatingPlan = nil - ap.RateIntervals.Sort() - for _, interval := range ap.RateIntervals { + rp.RateIntervals.Sort() + for _, interval := range rp.RateIntervals { if timespans[i].RateInterval != nil && timespans[i].RateInterval.Weight < interval.Weight { continue // if the timespan has an interval than it already has a heigher weight } newTs := timespans[i].SplitByRateInterval(interval) if newTs != nil { - newTs.RatingPlan = ap + newTs.ratingPlan = rp timespans = append(timespans, newTs) } } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 5823f5e7e..0a4b700e5 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -76,6 +76,27 @@ func TestSplitSpans(t *testing.T) { } } +func TestSplitSpansRoundToIncrements(t *testing.T) { + t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC) + t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC) + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second} + + cd.LoadRatingPlans() + timespans := cd.splitInTimeSpans(nil) + if len(timespans) != 2 { + t.Log(cd.RatingPlans) + t.Error("Wrong number of timespans: ", len(timespans)) + } + var d time.Duration + for _, ts := range timespans { + d += ts.GetDuration() + t.Log(ts.GetDuration()) + } + if d != 132*time.Second { + t.Error("Wrong duration for timespans: ", d) + } +} + func TestGetCost(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) @@ -87,6 +108,20 @@ func TestGetCost(t *testing.T) { } } +func TestGetCostRateGroups(t *testing.T) { + t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC) + t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC) + cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second} + + result, err := cd.GetCost() + if err != nil { + t.Error("Error getting cost: ", err) + } + if result.Cost != 132 { + t.Error("Error calculating cost: ", result.Timespans[0]) + } +} + func TestGetCostNoConnectFee(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) diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index d12a57b85..44a58045a 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -52,6 +52,8 @@ R2,0,0.1,60s,1s,0,*middle,2,10 R3,0,0.05,60s,1s,0,*middle,2,10 R4,1,1,1s,1s,0,*up,2,10 R5,0,0.5,1s,1s,0,*down,2,10 +LANDLINE_OFFPEAK,0,1,1s,60s,0s,*up,4,10 +LANDLINE_OFFPEAK,0,1,1s,1s,60s,*up,4,10 ` destinationRates = ` RT_STANDARD,GERMANY,R1 @@ -62,6 +64,7 @@ RT_STD_WEEKEND,GERMANY,R2 RT_STD_WEEKEND,GERMANY_O2,R3 P1,NAT,R4 P2,NAT,R5 +T1,NAT,LANDLINE_OFFPEAK ` destinationRateTimings = ` STANDARD,RT_STANDARD,WORKDAYS_00,10 @@ -72,6 +75,7 @@ DEFAULT,RT_DEFAULT,WORKDAYS_00,10 EVENING,P1,WORKDAYS_00,10 EVENING,P2,WORKDAYS_18,10 EVENING,P2,WEEKENDS,10 +TDRT,T1,WORKDAYS_00,10 ` ratingProfiles = ` CUSTOMER_1,0,*out,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb @@ -85,6 +89,7 @@ vdf,0,*out,*any,2012-02-28T00:00:00Z,EVENING, vdf,0,*out,one,2012-02-28T00:00:00Z,STANDARD, vdf,0,*out,inf,2012-02-28T00:00:00Z,STANDARD,inf vdf,0,*out,fall,2012-02-28T00:00:00Z,PREMIUM,rif +test,0,*out,trp,2013-10-01T00:00:00Z,TDRT,rif ` actions = ` MINI,*topup_reset,*monetary,*out,10,*unlimited,,,10,,10 @@ -206,7 +211,7 @@ func TestLoadTimimgs(t *testing.T) { } func TestLoadRates(t *testing.T) { - if len(csvr.rates) != 5 { + if len(csvr.rates) != 6 { t.Error("Failed to load rates: ", csvr.rates) } rate := csvr.rates["R1"][0] @@ -280,10 +285,38 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", csvr.rates) } + rate = csvr.rates["LANDLINE_OFFPEAK"][0] + if !reflect.DeepEqual(rate, &LoadRate{ + Tag: "LANDLINE_OFFPEAK", + ConnectFee: 0, + Price: 1, + RateUnit: time.Second, + RateIncrement: time.Minute, + GroupIntervalStart: 0, + RoundingMethod: utils.ROUNDING_UP, + RoundingDecimals: 4, + Weight: 10, + }) { + t.Errorf("Error loading rate: %+v", rate) + } + rate = csvr.rates["LANDLINE_OFFPEAK"][1] + if !reflect.DeepEqual(rate, &LoadRate{ + Tag: "LANDLINE_OFFPEAK", + ConnectFee: 0, + Price: 1, + RateUnit: time.Second, + RateIncrement: time.Second, + GroupIntervalStart: 60 * time.Second, + RoundingMethod: utils.ROUNDING_UP, + RoundingDecimals: 4, + Weight: 10, + }) { + t.Errorf("Error loading rate: %+v", rate) + } } func TestLoadDestinationRates(t *testing.T) { - if len(csvr.destinationRates) != 5 { + if len(csvr.destinationRates) != 6 { t.Error("Failed to load destinationrates: ", csvr.destinationRates) } drs := csvr.destinationRates["RT_STANDARD"] @@ -351,10 +384,20 @@ func TestLoadDestinationRates(t *testing.T) { }) { t.Error("Error loading destination rate: ", drs) } + drs = csvr.destinationRates["T1"] + if !reflect.DeepEqual(drs, []*DestinationRate{ + &DestinationRate{ + Tag: "T1", + DestinationsTag: "NAT", + rates: csvr.rates["LANDLINE_OFFPEAK"], + }, + }) { + t.Error("Error loading destination rate: ", drs) + } } func TestLoadDestinationRateTimings(t *testing.T) { - if len(csvr.destinationRateTimings) != 4 { + if len(csvr.destinationRateTimings) != 5 { t.Error("Failed to load rate timings: ", csvr.destinationRateTimings) } rplan := csvr.destinationRateTimings["STANDARD"] @@ -518,18 +561,67 @@ func TestLoadDestinationRateTimings(t *testing.T) { }, } if !reflect.DeepEqual(rplan, expected) { - t.Errorf("Error loading destination rate timing: %#v", rplan) + t.Errorf("Error loading destination rate timing: %+v", rplan) + } + rplan = csvr.destinationRateTimings["TDRT"] + expected = []*DestinationRateTiming{ + &DestinationRateTiming{ + destinationRates: csvr.destinationRates["T1"], + Weight: 10, + timing: csvr.timings["WORKDAYS_00"], + }, + } + if !reflect.DeepEqual(rplan, expected) { + t.Errorf("Error loading destination rate timing: %+v", rplan[0]) } } func TestLoadRatingProfiles(t *testing.T) { - if len(csvr.ratingProfiles) != 9 { + if len(csvr.ratingProfiles) != 10 { t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles) } - rp := csvr.ratingProfiles["*out:CUSTOMER_1:0:rif:from:tm"] - expected := &RatingProfile{} - if reflect.DeepEqual(rp, expected) { - t.Errorf("Error loading rating profile: %+v", rp.DestinationMap["GERMANY"][1].RateIntervals[2].Rates[0]) + rp := csvr.ratingProfiles["*out:test:0:trp"] + expected := &RatingProfile{ + Id: "*out:test:0:trp", + FallbackKey: "*out:test:0:rif", + DestinationMap: map[string][]*RatingPlan{ + "NAT": []*RatingPlan{ + &RatingPlan{ + ActivationTime: time.Date(2013, time.October, 1, 0, 0, 0, 0, time.UTC), + RateIntervals: []*RateInterval{ + &RateInterval{ + Years: Years{}, + Months: Months{}, + MonthDays: MonthDays{}, + WeekDays: WeekDays{1, 2, 3, 4, 5}, + StartTime: "00:00:00", + EndTime: "", + Weight: 10, + ConnectFee: 0, + Rates: RateGroups{ + &Rate{ + GroupIntervalStart: 0, + Value: 1, + RateIncrement: time.Minute, + RateUnit: time.Second, + }, + &Rate{ + GroupIntervalStart: time.Minute, + Value: 1, + RateIncrement: time.Second, + RateUnit: time.Second, + }, + }, + RoundingMethod: utils.ROUNDING_UP, + RoundingDecimals: 4, + }, + }, + }, + }, + }, + } + if !reflect.DeepEqual(rp, expected) { + t.Errorf("Error loading rating profile: %+v") } } diff --git a/engine/timespans.go b/engine/timespans.go index a10986944..9c7029f98 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -29,7 +29,7 @@ A unit in which a call will be split that has a specific price related interval type TimeSpan struct { TimeStart, TimeEnd time.Time Cost float64 - RatingPlan *RatingPlan + ratingPlan *RatingPlan RateInterval *RateInterval CallDuration time.Duration // the call duration so far till TimeEnd overlapped bool // mark a timespan as overlapped by an expanded one @@ -39,7 +39,7 @@ type TimeSpan struct { type Increment struct { Duration time.Duration Cost float64 - BalanceUuid string + BalanceUuids []string // need more than one for minutes with cost BalanceType string BalanceRateInterval *RateInterval MinuteInfo *MinuteInfo @@ -53,14 +53,16 @@ type MinuteInfo struct { } func (incr *Increment) Clone() *Increment { - return &Increment{ + nIncr := &Increment{ Duration: incr.Duration, Cost: incr.Cost, - BalanceUuid: incr.BalanceUuid, BalanceType: incr.BalanceType, BalanceRateInterval: incr.BalanceRateInterval, MinuteInfo: incr.MinuteInfo, } + nIncr.BalanceUuids = make([]string, len(incr.BalanceUuids)) + copy(nIncr.BalanceUuids, incr.BalanceUuids) + return nIncr } type Increments []*Increment @@ -132,7 +134,6 @@ a new timespan starting from the end of the received one. The interval will attach itself to the timespan that overlaps the interval. */ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) { - //Logger.Debug("here: ", ts, " +++ ", i) // if the span is not in interval return nil if !(i.Contains(ts.TimeStart) || i.Contains(ts.TimeEnd)) { @@ -141,10 +142,10 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) { } // split by GroupStart i.Rates.Sort() - for _, price := range i.Rates { - if ts.GetGroupStart() < price.GroupIntervalStart && ts.GetGroupEnd() >= price.GroupIntervalStart { + for _, rate := range i.Rates { + if ts.GetGroupStart() < rate.GroupIntervalStart && ts.GetGroupEnd() >= rate.GroupIntervalStart { ts.SetRateInterval(i) - splitTime := ts.TimeStart.Add(price.GroupIntervalStart - ts.GetGroupStart()) + splitTime := ts.TimeStart.Add(rate.GroupIntervalStart - ts.GetGroupStart()) nts = &TimeSpan{TimeStart: splitTime, TimeEnd: ts.TimeEnd} ts.TimeEnd = splitTime nts.SetRateInterval(i) @@ -241,13 +242,13 @@ func (ts *TimeSpan) SplitByDuration(duration time.Duration) *TimeSpan { } // Splits the given timespan on activation period's activation time. -func (ts *TimeSpan) SplitByRatingPlan(ap *RatingPlan) (newTs *TimeSpan) { - if !ts.Contains(ap.ActivationTime) { +func (ts *TimeSpan) SplitByRatingPlan(rp *RatingPlan) (newTs *TimeSpan) { + if !ts.Contains(rp.ActivationTime) { return nil } - newTs = &TimeSpan{TimeStart: ap.ActivationTime, TimeEnd: ts.TimeEnd, RatingPlan: ap} + newTs = &TimeSpan{TimeStart: rp.ActivationTime, TimeEnd: ts.TimeEnd, ratingPlan: rp} newTs.CallDuration = ts.CallDuration - ts.TimeEnd = ap.ActivationTime + ts.TimeEnd = rp.ActivationTime ts.SetNewCallDuration(newTs) return } diff --git a/engine/userbalance.go b/engine/userbalance.go index 8288ddf67..44d24fbea 100644 --- a/engine/userbalance.go +++ b/engine/userbalance.go @@ -193,8 +193,8 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { amount := increment.Duration.Seconds() if b.Value >= amount { b.Value -= amount - increment.BalanceUuid = b.Uuid - increment.MinuteInfo = &MinuteInfo{b.DestinationId, amount, 0} + increment.BalanceUuids = append(increment.BalanceUuids, b.Uuid) + increment.MinuteInfo = &MinuteInfo{cc.Destination, amount, 0} paid = true if count { ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) @@ -248,8 +248,8 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { } cc.Timespans = newTimespans b.Value -= amount - newTs.Increments[0].BalanceUuid = b.Uuid - newTs.Increments[0].MinuteInfo = &MinuteInfo{b.DestinationId, amount, 0} + newTs.Increments[0].BalanceUuids = append(newTs.Increments[0].BalanceUuids, b.Uuid) + newTs.Increments[0].MinuteInfo = &MinuteInfo{cc.Destination, amount, 0} paid = true if count { ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) @@ -274,18 +274,20 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { for nIdx, nInc := range nts.Increments { // debit minutes and money seconds := nInc.Duration.Seconds() - amount := nInc.Cost + //cost := nInc.Cost if b.Value >= seconds { b.Value -= seconds - nInc.BalanceUuid = b.Uuid + nInc.BalanceUuids = append(nInc.BalanceUuids, b.Uuid) + nInc.MinuteInfo = &MinuteInfo{newCC.Destination, seconds, 0} if count { - ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: amount, DestinationId: newCC.Destination}}) + ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: seconds, DestinationId: newCC.Destination}}) } } else { nts.SplitByIncrement(nIdx) } } } + // calculate overlaped timespans var paidDuration time.Duration for _, pts := range paidTs { @@ -349,7 +351,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { amount := increment.Cost if b.Value >= amount { b.Value -= amount - increment.BalanceUuid = b.Uuid + increment.BalanceUuids = append(increment.BalanceUuids, b.Uuid) paid = true if count { ub.countUnits(&Action{BalanceId: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}}) @@ -376,7 +378,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { amount := nInc.Cost if b.Value >= amount { b.Value -= amount - nInc.BalanceUuid = b.Uuid + nInc.BalanceUuids = append(nInc.BalanceUuids, b.Uuid) if count { ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: amount, DestinationId: newCC.Destination}}) } @@ -446,7 +448,7 @@ func (ub *UserBalance) refoundIncrements(increments Increments, count bool) { for _, increment := range increments { var balance *Balance for _, balanceChain := range ub.BalanceMap { - if balance = balanceChain.GetBalance(increment.BalanceUuid); balance != nil { + if balance = balanceChain.GetBalance(increment.BalanceUuids[0]); balance != nil { break } } diff --git a/engine/userbalance_test.go b/engine/userbalance_test.go index b41816160..e3fde4a66 100644 --- a/engine/userbalance_test.go +++ b/engine/userbalance_test.go @@ -228,7 +228,7 @@ func TestDebitCreditZeroSecond(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" { + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } if rifsBalance.BalanceMap[MINUTES+OUTBOUND][0].Value != 0 || @@ -259,7 +259,7 @@ func TestDebitCreditZeroMinute(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -292,8 +292,8 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "tests" || - cc.Timespans[1].Increments[0].BalanceUuid != "testm" { + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "tests" || + cc.Timespans[1].Increments[0].BalanceUuids[0] != "testm" { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0], cc.Timespans[1].Increments[0]) } if rifsBalance.BalanceMap[MINUTES+OUTBOUND][1].Value != 0 || @@ -330,7 +330,7 @@ func TestDebitCreditNoCredit(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -371,7 +371,7 @@ func TestDebitCreditHasCredit(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -407,7 +407,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != 10*time.Second { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -448,7 +448,7 @@ func TestDebitCreditMoreTimespans(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -486,7 +486,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) { if err != nil { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "testb" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } @@ -558,7 +558,7 @@ func TestDebitCreditMoneyOnly(t *testing.T) { t.Error("Error debiting balance: ", err) } - if cc.Timespans[0].Increments[0].BalanceUuid != "money" || + if cc.Timespans[0].Increments[0].BalanceUuids[0] != "money" || cc.Timespans[0].Increments[0].Duration != 10*time.Second { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index 0492967d5..a09ae6d76 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -297,7 +297,7 @@ func (sm *FSSessionManager) LoopAction(s *Session, cd *engine.CallDescriptor, in cc = &engine.CallCost{} cd.LoopIndex = index cd.Amount = sm.debitPeriod.Seconds() - cd.CallDuration += time.Duration(cd.Amount) * time.Second + cd.CallDuration += sm.debitPeriod err := sm.connector.MaxDebit(*cd, cc) if err != nil { engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err))