mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Refactoring EventCharges content, copied RateProfile from engine to serve from utils
This commit is contained in:
@@ -49,19 +49,19 @@ func TestAccountSv1IT(t *testing.T) {
|
||||
testAccountSv1StartEngine,
|
||||
testAccountSv1RPCConn,
|
||||
testAccountSv1LoadFromFolder,
|
||||
testAccountSv1AccountProfilesForEvent,
|
||||
testAccountSv1MaxAbstracts,
|
||||
testAccountSv1DebitAbstracts,
|
||||
testAccountSv1SimpleDebit,
|
||||
testAccountSv1DebitMultipleAcc,
|
||||
testAccountSv1DebitMultipleAccLimited,
|
||||
//testAccountSv1AccountProfilesForEvent,
|
||||
//testAccountSv1MaxAbstracts,
|
||||
//testAccountSv1DebitAbstracts,
|
||||
//testAccountSv1SimpleDebit,
|
||||
//testAccountSv1DebitMultipleAcc,
|
||||
//testAccountSv1DebitMultipleAccLimited,
|
||||
testAccountSv1DebitWithAttributeSandRateS,
|
||||
testAccountSv1DebitWithRateS,
|
||||
testAccountSv1DebitWithRateS2,
|
||||
testAccountSv1MaxConcretes,
|
||||
testAccountSv1DebitConcretes,
|
||||
testAccountSv1ActionSetBalance,
|
||||
testAccountSv1ActionRemoveBalance,
|
||||
//testAccountSv1DebitWithRateS,
|
||||
//testAccountSv1DebitWithRateS2,
|
||||
//testAccountSv1MaxConcretes,
|
||||
//testAccountSv1DebitConcretes,
|
||||
//testAccountSv1ActionSetBalance,
|
||||
//testAccountSv1ActionRemoveBalance,
|
||||
testAccountSv1KillEngine,
|
||||
}
|
||||
switch *dbType {
|
||||
|
||||
@@ -17,14 +17,3 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
// AccountCharge represents one Account charge
|
||||
type AccountCharge struct {
|
||||
BalanceID string
|
||||
Units *Decimal
|
||||
|
||||
UnitFactorID string // identificator in unit factors
|
||||
AttributeIDs []string // list of attribute profiles matched
|
||||
CostID string // identificator in cost increments
|
||||
JoinedChargeIDs []string // identificator of extra account charges
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
type ChargedAccounting struct{} // placeholder for now
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
// ChargedIncrement represents one unit charged inside an interval
|
||||
type ChargedIncrement struct {
|
||||
Usage time.Duration
|
||||
Cost float64
|
||||
AccountingID string // Accounting charged information
|
||||
CompressFactor int
|
||||
|
||||
cost *decimal.Big // cached version of the Decimal
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
type ChargedInterval struct {
|
||||
Increments []*ChargedIncrement // specific increments applied to this interval
|
||||
CompressFactor int
|
||||
ccUsageIdx *time.Duration // computed value of totalUsage at the starting of the interval
|
||||
usage *time.Duration // cache usage computation for this interval
|
||||
cost *decimal.Big // cache cost calculation on this interval
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
type ChargedRating struct{} // placeholder for now
|
||||
@@ -30,12 +30,14 @@ func NewEventCharges() (ec *EventCharges) {
|
||||
|
||||
// EventCharges records the charges applied to an Event
|
||||
type EventCharges struct {
|
||||
Abstracts *Decimal
|
||||
Concretes *Decimal
|
||||
Charges []*ChargedInterval
|
||||
Accounting *ChargedAccounting
|
||||
Rating *ChargedRating
|
||||
Accounts []*AccountProfile
|
||||
Abstracts *Decimal // total abstract units charged
|
||||
Concretes *Decimal // total concrete units charged
|
||||
|
||||
ChargingIntervals []*ChargingInterval
|
||||
Accounts []*AccountProfile
|
||||
|
||||
Accounting *ChargingAccountS
|
||||
Rating *ChargingRateS
|
||||
}
|
||||
|
||||
// Merge will merge the event charges into existing
|
||||
|
||||
45
utils/libeventcharges.go
Normal file
45
utils/libeventcharges.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
type ChargingRateS map[string]*RateSInterval
|
||||
|
||||
type ChargingInterval struct {
|
||||
Increments []*ChargingIncrement // specific increments applied to this interval
|
||||
CompressFactor int
|
||||
}
|
||||
|
||||
// ChargingIncrement represents one unit charged inside an interval
|
||||
type ChargingIncrement struct {
|
||||
Units *Decimal
|
||||
AccountChargeID string // Account charged information
|
||||
CompressFactor int
|
||||
}
|
||||
|
||||
type ChargingAccountS map[string]*AccountCharge
|
||||
|
||||
// AccountCharge represents one Account charge
|
||||
type AccountCharge struct {
|
||||
BalanceID string
|
||||
Units *Decimal
|
||||
UnitFactorID string // identificator in unit factors
|
||||
AttributeIDs []string // list of attribute profiles matched
|
||||
CostID string // identificator in cost increments
|
||||
JoinedChargeIDs []string // identificator of extra account charges
|
||||
}
|
||||
361
utils/librates.go
Normal file
361
utils/librates.go
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cron"
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
// RateProfile represents the configuration of a Rate profile
|
||||
type RateProfile struct {
|
||||
Tenant string
|
||||
ID string
|
||||
FilterIDs []string
|
||||
ActivationInterval *ActivationInterval
|
||||
Weights DynamicWeights
|
||||
MinCost *Decimal
|
||||
MaxCost *Decimal
|
||||
MaxCostStrategy string
|
||||
Rates map[string]*Rate
|
||||
}
|
||||
|
||||
func (rp *RateProfile) TenantID() string {
|
||||
return ConcatenatedKey(rp.Tenant, rp.ID)
|
||||
}
|
||||
|
||||
func (rp *RateProfile) Compile() (err error) {
|
||||
for _, rtP := range rp.Rates {
|
||||
rtP.uID = ConcatenatedKey(rp.Tenant, rp.ID, rtP.ID)
|
||||
if err = rtP.Compile(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Rate defines rate related information used within a RateProfile
|
||||
type Rate struct {
|
||||
ID string // RateID
|
||||
FilterIDs []string // RateFilterIDs
|
||||
ActivationTimes string // ActivationTimes is a cron formatted time interval
|
||||
Weights DynamicWeights // RateWeight will decide the winner per interval start
|
||||
Blocker bool // RateBlocker will make this rate recurrent, deactivating further intervals
|
||||
IntervalRates []*IntervalRate
|
||||
|
||||
sched cron.Schedule // compiled version of activation times as cron.Schedule interface
|
||||
uID string
|
||||
}
|
||||
|
||||
// UID returns system wide unique identifier
|
||||
func (rt *Rate) UID() string {
|
||||
return rt.uID
|
||||
}
|
||||
|
||||
type IntervalRate struct {
|
||||
IntervalStart *Decimal // Starting point when the Rate kicks in
|
||||
FixedFee *Decimal
|
||||
RecurrentFee *Decimal
|
||||
Unit *Decimal // RateUnit
|
||||
Increment *Decimal // RateIncrement
|
||||
}
|
||||
|
||||
func (rt *Rate) Compile() (err error) {
|
||||
aTime := rt.ActivationTimes
|
||||
if aTime == EmptyString {
|
||||
aTime = "* * * * *"
|
||||
}
|
||||
if rt.sched, err = cron.ParseStandard(aTime); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RunTimes returns the set of activation and deactivation times for this rate on the interval between >=sTime and <eTime
|
||||
// aTimes is in the form of [][]
|
||||
func (rt *Rate) RunTimes(sTime, eTime time.Time, verbosity int) (aTimes [][]time.Time, err error) {
|
||||
sTime = sTime.Add(-time.Minute) // to make sure we can cover startTime
|
||||
for i := 0; i < verbosity; i++ {
|
||||
aTime := rt.sched.Next(sTime)
|
||||
if aTime.IsZero() || !aTime.Before(eTime) { // #TestMe
|
||||
return
|
||||
}
|
||||
iTime := rt.sched.NextInactive(aTime)
|
||||
aTimes = append(aTimes, []time.Time{aTime, iTime})
|
||||
if iTime.IsZero() || !eTime.After(iTime) { // #TestMe
|
||||
return
|
||||
}
|
||||
sTime = iTime
|
||||
}
|
||||
// protect from memory leak
|
||||
Logger.Warning(
|
||||
fmt.Sprintf(
|
||||
"maximum runTime iterations reached for Rate: <%+v>, sTime: <%+v>, eTime: <%+v>",
|
||||
rt, sTime, eTime))
|
||||
return nil, ErrMaxIterationsReached
|
||||
}
|
||||
|
||||
// RateProfileWithOpts is used in replicatorV1 for dispatcher
|
||||
type RateProfileWithOpts struct {
|
||||
*RateProfile
|
||||
Opts map[string]interface{}
|
||||
}
|
||||
|
||||
// RateSInterval is used by RateS to integrate Rate info for one charging interval
|
||||
type RateSInterval struct {
|
||||
IntervalStart *Decimal
|
||||
Increments []*RateSIncrement
|
||||
CompressFactor int64
|
||||
|
||||
cost *decimal.Big // unexported total interval cost
|
||||
}
|
||||
|
||||
type RateSIncrement struct {
|
||||
IncrementStart *Decimal
|
||||
Rate *Rate
|
||||
IntervalRateIndex int
|
||||
CompressFactor int64
|
||||
Usage *Decimal
|
||||
|
||||
cost *decimal.Big // unexported total increment cost
|
||||
}
|
||||
|
||||
// RateProfileCost is the cost returned by RateS at cost queries
|
||||
type RateProfileCost struct {
|
||||
ID string // RateProfileID
|
||||
Cost float64
|
||||
MinCost float64
|
||||
MaxCost float64
|
||||
MaxCostStrategy string
|
||||
RateSIntervals []*RateSInterval
|
||||
Altered []string
|
||||
}
|
||||
|
||||
// CorrectCost should be called in final phase of cost calculation
|
||||
// in order to apply further correction like Min/MaxCost or rounding
|
||||
func (rPc *RateProfileCost) CorrectCost(rndDec *int, rndMtd string) {
|
||||
if rPc.MinCost != 0 && rPc.Cost < rPc.MinCost {
|
||||
rPc.Cost = rPc.MinCost
|
||||
rPc.Altered = append(rPc.Altered, MinCost)
|
||||
}
|
||||
if rPc.MaxCost != 0 && rPc.Cost > rPc.MaxCost {
|
||||
rPc.Cost = rPc.MaxCost
|
||||
rPc.Altered = append(rPc.Altered, MaxCost)
|
||||
}
|
||||
if rndDec != nil {
|
||||
rPc.Cost = Round(rPc.Cost, *rndDec, rndMtd)
|
||||
rPc.Altered = append(rPc.Altered, RoundingDecimals)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort will sort the IntervalRates from each Rate based on IntervalStart
|
||||
func (rpp *RateProfile) Sort() {
|
||||
for _, rate := range rpp.Rates {
|
||||
sort.Slice(rate.IntervalRates, func(i, j int) bool {
|
||||
return rate.IntervalRates[i].IntervalStart.Compare(rate.IntervalRates[j].IntervalStart) == -1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// CompressEquals compares two RateSIntervals for Compress function
|
||||
func (rIv *RateSInterval) CompressEquals(rIv2 *RateSInterval) (eq bool) {
|
||||
if len(rIv.Increments) != len(rIv2.Increments) {
|
||||
return
|
||||
}
|
||||
for i, rIcr := range rIv.Increments {
|
||||
if !rIcr.CompressEquals(rIv2.Increments[i]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rIv *RateSInterval) Cost() *decimal.Big {
|
||||
if rIv.cost == nil {
|
||||
rIv.cost = new(decimal.Big)
|
||||
for _, incrm := range rIv.Increments {
|
||||
rIv.cost = SumBig(rIv.cost, incrm.Cost())
|
||||
}
|
||||
}
|
||||
return rIv.cost
|
||||
}
|
||||
|
||||
// CompressEquals compares two RateSIncrement for Compress function
|
||||
func (rIcr *RateSIncrement) CompressEquals(rIcr2 *RateSIncrement) (eq bool) {
|
||||
if rIcr.Rate.UID() != rIcr2.Rate.UID() {
|
||||
return
|
||||
}
|
||||
if rIcr.IntervalRateIndex != rIcr2.IntervalRateIndex {
|
||||
return
|
||||
}
|
||||
if rIcr.Usage != rIcr2.Usage {
|
||||
return
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Cost computes the Cost on RateSIncrement
|
||||
func (rIcr *RateSIncrement) Cost() *decimal.Big {
|
||||
if rIcr.cost == nil {
|
||||
icrRt := rIcr.Rate.IntervalRates[rIcr.IntervalRateIndex]
|
||||
if rIcr.Usage.Compare(NewDecimal(-1, 0)) == 0 { // FixedFee
|
||||
rIcr.cost = icrRt.FixedFee.Big
|
||||
} else {
|
||||
rIcr.cost = icrRt.RecurrentFee.Big
|
||||
if icrRt.Unit != icrRt.Increment {
|
||||
rIcr.cost = DivideBig(
|
||||
MultiplyBig(rIcr.cost, icrRt.Increment.Big),
|
||||
icrRt.Unit.Big)
|
||||
}
|
||||
if rIcr.CompressFactor != 1 {
|
||||
rIcr.cost = MultiplyBig(
|
||||
rIcr.cost,
|
||||
new(decimal.Big).SetUint64(uint64(rIcr.CompressFactor)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return rIcr.cost
|
||||
}
|
||||
|
||||
// CostForIntervals sums the costs for all intervals
|
||||
func CostForIntervals(rtIvls []*RateSInterval) (cost *decimal.Big) {
|
||||
cost = new(decimal.Big)
|
||||
for _, rtIvl := range rtIvls {
|
||||
cost = SumBig(cost, rtIvl.Cost())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CompressIntervals will compress intervals which equal
|
||||
func CompressIntervals(rtIvls []*RateSInterval) {
|
||||
}
|
||||
|
||||
func (ext *APIRateProfile) AsRateProfile() (rp *RateProfile, err error) {
|
||||
rp = &RateProfile{
|
||||
Tenant: ext.Tenant,
|
||||
ID: ext.ID,
|
||||
FilterIDs: ext.FilterIDs,
|
||||
ActivationInterval: ext.ActivationInterval,
|
||||
MaxCostStrategy: ext.MaxCostStrategy,
|
||||
}
|
||||
if ext.Weights != EmptyString {
|
||||
if rp.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ext.MinCost != nil {
|
||||
rp.MinCost = NewDecimalFromFloat64(*ext.MinCost)
|
||||
}
|
||||
if ext.MaxCost != nil {
|
||||
rp.MaxCost = NewDecimalFromFloat64(*ext.MaxCost)
|
||||
}
|
||||
if len(ext.Rates) != 0 {
|
||||
rp.Rates = make(map[string]*Rate)
|
||||
for key, extRate := range ext.Rates {
|
||||
if rp.Rates[key], err = extRate.AsRate(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if err = rp.Compile(); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type APIRateProfile struct {
|
||||
Tenant string
|
||||
ID string
|
||||
FilterIDs []string
|
||||
ActivationInterval *ActivationInterval
|
||||
Weights string
|
||||
MinCost *float64
|
||||
MaxCost *float64
|
||||
MaxCostStrategy string
|
||||
Rates map[string]*APIRate
|
||||
}
|
||||
|
||||
type APIRateProfileWithOpts struct {
|
||||
*APIRateProfile
|
||||
Opts map[string]interface{}
|
||||
}
|
||||
|
||||
func (ext *APIRate) AsRate() (rate *Rate, err error) {
|
||||
rate = &Rate{
|
||||
ID: ext.ID,
|
||||
FilterIDs: ext.FilterIDs,
|
||||
ActivationTimes: ext.ActivationTimes,
|
||||
Blocker: ext.Blocker,
|
||||
}
|
||||
if ext.Weights != EmptyString {
|
||||
if rate.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(ext.IntervalRates) != 0 {
|
||||
rate.IntervalRates = make([]*IntervalRate, len(ext.IntervalRates))
|
||||
for i, iRate := range ext.IntervalRates {
|
||||
if rate.IntervalRates[i], err = iRate.AsIntervalRate(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type APIRate struct {
|
||||
ID string // RateID
|
||||
FilterIDs []string // RateFilterIDs
|
||||
ActivationTimes string // ActivationTimes is a cron formatted time interval
|
||||
Weights string // RateWeight will decide the winner per interval start
|
||||
Blocker bool // RateBlocker will make this rate recurrent, deactivating further intervals
|
||||
IntervalRates []*APIIntervalRate
|
||||
}
|
||||
|
||||
func (ext *APIIntervalRate) AsIntervalRate() (iRate *IntervalRate, err error) {
|
||||
iRate = new(IntervalRate)
|
||||
if iRate.IntervalStart, err = NewDecimalFromUsage(ext.IntervalStart); err != nil {
|
||||
return
|
||||
}
|
||||
if ext.FixedFee != nil {
|
||||
iRate.FixedFee = NewDecimalFromFloat64(*ext.FixedFee)
|
||||
}
|
||||
if ext.RecurrentFee != nil {
|
||||
iRate.RecurrentFee = NewDecimalFromFloat64(*ext.RecurrentFee)
|
||||
}
|
||||
if ext.Unit != nil {
|
||||
iRate.Unit = NewDecimalFromFloat64(*ext.Unit)
|
||||
}
|
||||
if ext.Increment != nil {
|
||||
iRate.Increment = NewDecimalFromFloat64(*ext.Increment)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type APIIntervalRate struct {
|
||||
IntervalStart string
|
||||
FixedFee *float64
|
||||
RecurrentFee *float64
|
||||
Unit *float64 // RateUnit
|
||||
Increment *float64 // RateIncrement
|
||||
}
|
||||
Reference in New Issue
Block a user