satellite: use segment count for billing
Change-Id: Iafaf41cb6cde4cb2abdac3f75ce0fead838cb758
This commit is contained in:
parent
52f8c8175e
commit
d441c8da15
@ -64,7 +64,7 @@ func setupPayments(log *zap.Logger, db satellite.DB) (*stripecoinpayments.Servic
|
||||
db.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ func TestBilling_InlineFiles(t *testing.T) {
|
||||
usage := getProjectTotal(ctx, t, planet, 0, projectID, since)
|
||||
|
||||
// Usage should be > 0
|
||||
require.NotZero(t, usage.ObjectCount)
|
||||
require.NotZero(t, usage.SegmentCount)
|
||||
require.NotZero(t, usage.Storage)
|
||||
require.NotZero(t, usage.Egress)
|
||||
})
|
||||
@ -131,8 +131,8 @@ func TestBilling_FilesAfterDeletion(t *testing.T) {
|
||||
// Get usage for uploaded file before we delete it
|
||||
usageBefore := getProjectTotal(ctx, t, planet, 0, projectID, since)
|
||||
|
||||
// ObjectCount and Storage should be > 0
|
||||
require.NotZero(t, usageBefore.ObjectCount)
|
||||
// SegmentCount and Storage should be > 0
|
||||
require.NotZero(t, usageBefore.SegmentCount)
|
||||
require.NotZero(t, usageBefore.Storage)
|
||||
require.Zero(t, usageBefore.Egress)
|
||||
|
||||
@ -146,7 +146,7 @@ func TestBilling_FilesAfterDeletion(t *testing.T) {
|
||||
usageAfter := getProjectTotal(ctx, t, planet, 0, projectID, since)
|
||||
|
||||
// Verify data is correct. We don’t bill for the data after deleting objects, usage should be equal
|
||||
require.Equal(t, usageBefore.ObjectCount, usageAfter.ObjectCount, "Object count should be equal")
|
||||
require.Equal(t, usageBefore.SegmentCount, usageAfter.SegmentCount, "Segment count should be equal")
|
||||
require.Equal(t, usageBefore.Storage, usageAfter.Storage, "Storage should be equal")
|
||||
require.Zero(t, usageAfter.Egress, "Egress should be 0")
|
||||
})
|
||||
|
@ -69,9 +69,9 @@ type StorageNodeUsage struct {
|
||||
// ProjectUsage consist of period total storage, egress
|
||||
// and objects count per hour for certain Project in bytes.
|
||||
type ProjectUsage struct {
|
||||
Storage float64 `json:"storage"`
|
||||
Egress int64 `json:"egress"`
|
||||
ObjectCount float64 `json:"objectCount"`
|
||||
Storage float64 `json:"storage"`
|
||||
Egress int64 `json:"egress"`
|
||||
SegmentCount float64 `json:"segmentCount"`
|
||||
|
||||
Since time.Time `json:"since"`
|
||||
Before time.Time `json:"before"`
|
||||
@ -88,9 +88,9 @@ type BucketUsage struct {
|
||||
ProjectID uuid.UUID
|
||||
BucketName string
|
||||
|
||||
Storage float64
|
||||
Egress float64
|
||||
ObjectCount int64
|
||||
Storage float64
|
||||
Egress float64
|
||||
SegmentCount int64
|
||||
|
||||
Since time.Time
|
||||
Before time.Time
|
||||
|
@ -132,7 +132,7 @@ func NewAdmin(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
peer.DB.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
|
||||
if err != nil {
|
||||
|
@ -492,7 +492,7 @@ func (server *Server) checkUsage(ctx context.Context, w http.ResponseWriter, pro
|
||||
sendJSONError(w, "unable to list project usage", err.Error(), http.StatusInternalServerError)
|
||||
return true
|
||||
}
|
||||
if currentUsage.Storage > 0 || currentUsage.Egress > 0 || currentUsage.ObjectCount > 0 {
|
||||
if currentUsage.Storage > 0 || currentUsage.Egress > 0 || currentUsage.SegmentCount > 0 {
|
||||
sendJSONError(w, "usage for current month exists", "", http.StatusConflict)
|
||||
return true
|
||||
}
|
||||
@ -505,7 +505,7 @@ func (server *Server) checkUsage(ctx context.Context, w http.ResponseWriter, pro
|
||||
return true
|
||||
}
|
||||
|
||||
if lastMonthUsage.Storage > 0 || lastMonthUsage.Egress > 0 || lastMonthUsage.ObjectCount > 0 {
|
||||
if lastMonthUsage.Storage > 0 || lastMonthUsage.Egress > 0 || lastMonthUsage.SegmentCount > 0 {
|
||||
// time passed into the check function need to be the UTC midnight dates
|
||||
// of the first day of the current month and the first day of the last
|
||||
// month
|
||||
|
@ -530,7 +530,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
peer.DB.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
|
||||
if err != nil {
|
||||
@ -580,7 +580,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
pricing := paymentsconfig.PricingValues{
|
||||
StorageTBPrice: config.Payments.StorageTBPrice,
|
||||
EgressTBPrice: config.Payments.EgressTBPrice,
|
||||
ObjectPrice: config.Payments.ObjectPrice,
|
||||
SegmentPrice: config.Payments.SegmentPrice,
|
||||
}
|
||||
|
||||
peer.Console.Endpoint = consoleweb.NewServer(
|
||||
|
@ -72,7 +72,7 @@ func TestGraphqlMutation(t *testing.T) {
|
||||
pc := paymentsconfig.Config{
|
||||
StorageTBPrice: "10",
|
||||
EgressTBPrice: "45",
|
||||
ObjectPrice: "0.0000022",
|
||||
SegmentPrice: "0.0000022",
|
||||
}
|
||||
|
||||
paymentsService, err := stripecoinpayments.NewService(
|
||||
@ -88,7 +88,7 @@ func TestGraphqlMutation(t *testing.T) {
|
||||
db.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -66,8 +66,8 @@ const (
|
||||
FieldStorage = "storage"
|
||||
// FieldEgress is a field name for egress total.
|
||||
FieldEgress = "egress"
|
||||
// FieldObjectCount is a field name for objects count.
|
||||
FieldObjectCount = "objectCount"
|
||||
// FieldSegmentCount is a field name for segments count.
|
||||
FieldSegmentCount = "segmentCount"
|
||||
// FieldPageCount is a field name for total page count.
|
||||
FieldPageCount = "pageCount"
|
||||
// FieldCurrentPage is a field name for current page number.
|
||||
@ -336,7 +336,7 @@ func graphqlBucketUsage() *graphql.Object {
|
||||
FieldEgress: &graphql.Field{
|
||||
Type: graphql.Float,
|
||||
},
|
||||
FieldObjectCount: &graphql.Field{
|
||||
FieldSegmentCount: &graphql.Field{
|
||||
Type: graphql.Float,
|
||||
},
|
||||
SinceArg: &graphql.Field{
|
||||
@ -417,7 +417,7 @@ func graphqlProjectUsage() *graphql.Object {
|
||||
FieldEgress: &graphql.Field{
|
||||
Type: graphql.Float,
|
||||
},
|
||||
FieldObjectCount: &graphql.Field{
|
||||
FieldSegmentCount: &graphql.Field{
|
||||
Type: graphql.Float,
|
||||
},
|
||||
SinceArg: &graphql.Field{
|
||||
|
@ -56,7 +56,7 @@ func TestGraphqlQuery(t *testing.T) {
|
||||
pc := paymentsconfig.Config{
|
||||
StorageTBPrice: "10",
|
||||
EgressTBPrice: "45",
|
||||
ObjectPrice: "0.0000022",
|
||||
SegmentPrice: "0.0000022",
|
||||
}
|
||||
|
||||
paymentsService, err := stripecoinpayments.NewService(
|
||||
@ -72,7 +72,7 @@ func TestGraphqlQuery(t *testing.T) {
|
||||
db.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -205,7 +205,7 @@ func TestBuckets(t *testing.T) {
|
||||
bucketName
|
||||
storage
|
||||
egress
|
||||
objectCount
|
||||
segmentCount
|
||||
since
|
||||
before
|
||||
__typename
|
||||
@ -342,7 +342,7 @@ func TestProjects(t *testing.T) {
|
||||
bucketName
|
||||
storage
|
||||
egress
|
||||
objectCount
|
||||
segmentCount
|
||||
since
|
||||
before
|
||||
__typename
|
||||
@ -582,7 +582,7 @@ func TestWrongUser(t *testing.T) {
|
||||
bucketName
|
||||
storage
|
||||
egress
|
||||
objectCount
|
||||
segmentCount
|
||||
since
|
||||
before
|
||||
__typename
|
||||
@ -728,7 +728,7 @@ func TestWrongUser(t *testing.T) {
|
||||
bucketName
|
||||
storage
|
||||
egress
|
||||
objectCount
|
||||
segmentCount
|
||||
since
|
||||
before
|
||||
__typename
|
||||
|
@ -369,7 +369,7 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
|
||||
PathwayOverviewEnabled bool
|
||||
StorageTBPrice string
|
||||
EgressTBPrice string
|
||||
ObjectPrice string
|
||||
SegmentPrice string
|
||||
RecaptchaEnabled bool
|
||||
RecaptchaSiteKey string
|
||||
NewOnboarding bool
|
||||
@ -401,7 +401,7 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data.DefaultPaidBandwidthLimit = server.config.UsageLimits.Bandwidth.Paid
|
||||
data.StorageTBPrice = server.pricing.StorageTBPrice
|
||||
data.EgressTBPrice = server.pricing.EgressTBPrice
|
||||
data.ObjectPrice = server.pricing.ObjectPrice
|
||||
data.SegmentPrice = server.pricing.SegmentPrice
|
||||
data.RecaptchaEnabled = server.config.Recaptcha.Enabled
|
||||
data.RecaptchaSiteKey = server.config.Recaptcha.SiteKey
|
||||
data.NewOnboarding = server.config.NewOnboarding
|
||||
|
@ -455,7 +455,7 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB,
|
||||
peer.DB.ProjectAccounting(),
|
||||
pc.StorageTBPrice,
|
||||
pc.EgressTBPrice,
|
||||
pc.ObjectPrice,
|
||||
pc.SegmentPrice,
|
||||
pc.BonusRate)
|
||||
if err != nil {
|
||||
return nil, errs.Combine(err, peer.Close())
|
||||
|
@ -13,7 +13,7 @@ type Config struct {
|
||||
StripeCoinPayments stripecoinpayments.Config
|
||||
StorageTBPrice string `help:"price user should pay for storing TB per month" default:"4" testDefault:"10"`
|
||||
EgressTBPrice string `help:"price user should pay for each TB of egress" default:"7" testDefault:"45"`
|
||||
ObjectPrice string `help:"price user should pay for each object stored in network per month" default:"0" testDefault:"0.0000022"`
|
||||
SegmentPrice string `help:"price user should pay for each segment stored in network per month" default:"0" testDefault:"0.0000022"`
|
||||
BonusRate int64 `help:"amount of percents that user will earn as bonus credits by depositing in STORJ tokens" default:"10"`
|
||||
NodeEgressBandwidthPrice int64 `help:"price node receive for storing TB of egress in cents" default:"2000"`
|
||||
NodeRepairBandwidthPrice int64 `help:"price node receive for storing TB of repair in cents" default:"1000"`
|
||||
@ -25,5 +25,5 @@ type Config struct {
|
||||
type PricingValues struct {
|
||||
StorageTBPrice string
|
||||
EgressTBPrice string
|
||||
ObjectPrice string
|
||||
SegmentPrice string
|
||||
}
|
||||
|
@ -17,6 +17,6 @@ type ProjectCharge struct {
|
||||
StorageGbHrs int64 `json:"storagePrice"`
|
||||
// Egress shows how many cents we should pay for Egress.
|
||||
Egress int64 `json:"egressPrice"`
|
||||
// ObjectCount shows how many cents we should pay for objects count.
|
||||
ObjectCount int64 `json:"objectPrice"`
|
||||
// SegmentCount shows how many cents we should pay for objects count.
|
||||
SegmentCount int64 `json:"segmentPrice"`
|
||||
}
|
||||
|
@ -100,14 +100,14 @@ func (accounts *accounts) ProjectCharges(ctx context.Context, userID uuid.UUID,
|
||||
return charges, Error.Wrap(err)
|
||||
}
|
||||
|
||||
projectPrice := accounts.service.calculateProjectUsagePrice(usage.Egress, usage.Storage, usage.ObjectCount)
|
||||
projectPrice := accounts.service.calculateProjectUsagePrice(usage.Egress, usage.Storage, usage.SegmentCount)
|
||||
|
||||
charges = append(charges, payments.ProjectCharge{
|
||||
ProjectUsage: *usage,
|
||||
|
||||
ProjectID: project.ID,
|
||||
Egress: projectPrice.Egress.IntPart(),
|
||||
ObjectCount: projectPrice.Objects.IntPart(),
|
||||
SegmentCount: projectPrice.Segments.IntPart(),
|
||||
StorageGbHrs: projectPrice.Storage.IntPart(),
|
||||
})
|
||||
}
|
||||
@ -128,7 +128,7 @@ func (accounts *accounts) CheckProjectInvoicingStatus(ctx context.Context, proje
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if currentUsage.Storage > 0 || currentUsage.Egress > 0 || currentUsage.ObjectCount > 0 {
|
||||
if currentUsage.Storage > 0 || currentUsage.Egress > 0 || currentUsage.SegmentCount > 0 {
|
||||
return true, errors.New("usage for current month exists")
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ func (accounts *accounts) CheckProjectInvoicingStatus(ctx context.Context, proje
|
||||
return false, err
|
||||
}
|
||||
|
||||
if lastMonthUsage.Storage > 0 || lastMonthUsage.Egress > 0 || lastMonthUsage.ObjectCount > 0 {
|
||||
if lastMonthUsage.Storage > 0 || lastMonthUsage.Egress > 0 || lastMonthUsage.SegmentCount > 0 {
|
||||
// time passed into the check function need to be the UTC midnight dates of the first and last day of the month
|
||||
err = accounts.service.db.ProjectRecords().Check(ctx, projectID, firstOfMonth.AddDate(0, -1, 0), firstOfMonth.Add(-time.Hour*24))
|
||||
if errors.Is(err, ErrProjectRecordExists) {
|
||||
|
@ -35,7 +35,7 @@ type CreateProjectRecord struct {
|
||||
ProjectID uuid.UUID
|
||||
Storage float64
|
||||
Egress int64
|
||||
Objects float64
|
||||
Segments float64
|
||||
}
|
||||
|
||||
// ProjectRecord holds project usage particular for billing period.
|
||||
@ -44,7 +44,7 @@ type ProjectRecord struct {
|
||||
ProjectID uuid.UUID
|
||||
Storage float64
|
||||
Egress int64
|
||||
Objects float64
|
||||
Segments float64
|
||||
PeriodStart time.Time
|
||||
PeriodEnd time.Time
|
||||
State int
|
||||
|
@ -36,7 +36,7 @@ func TestProjectRecords(t *testing.T) {
|
||||
ProjectID: prjID,
|
||||
Storage: 1,
|
||||
Egress: 2,
|
||||
Objects: 3,
|
||||
Segments: 3,
|
||||
},
|
||||
},
|
||||
start, end,
|
||||
@ -87,7 +87,7 @@ func TestProjectRecordsList(t *testing.T) {
|
||||
ProjectID: projID,
|
||||
Storage: float64(i) + 1,
|
||||
Egress: int64(i) + 2,
|
||||
Objects: float64(i) + 3,
|
||||
Segments: float64(i) + 3,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -122,7 +122,7 @@ func TestProjectRecordsList(t *testing.T) {
|
||||
assert.Equal(t, createRecord.ProjectID, record.ProjectID)
|
||||
assert.Equal(t, createRecord.Storage, record.Storage)
|
||||
assert.Equal(t, createRecord.Egress, record.Egress)
|
||||
assert.Equal(t, createRecord.Objects, record.Objects)
|
||||
assert.Equal(t, createRecord.Segments, record.Segments)
|
||||
assert.True(t, start.Equal(record.PeriodStart))
|
||||
assert.True(t, end.Equal(record.PeriodEnd))
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ type Service struct {
|
||||
|
||||
StorageMBMonthPriceCents decimal.Decimal
|
||||
EgressMBPriceCents decimal.Decimal
|
||||
ObjectMonthPriceCents decimal.Decimal
|
||||
SegmentMonthPriceCents decimal.Decimal
|
||||
// BonusRate amount of percents
|
||||
BonusRate int64
|
||||
// Coupon Values
|
||||
@ -80,7 +80,7 @@ type Service struct {
|
||||
}
|
||||
|
||||
// NewService creates a Service instance.
|
||||
func NewService(log *zap.Logger, stripeClient StripeClient, config Config, db DB, projectsDB console.Projects, usageDB accounting.ProjectAccounting, storageTBPrice, egressTBPrice, objectPrice string, bonusRate int64) (*Service, error) {
|
||||
func NewService(log *zap.Logger, stripeClient StripeClient, config Config, db DB, projectsDB console.Projects, usageDB accounting.ProjectAccounting, storageTBPrice, egressTBPrice, segmentPrice string, bonusRate int64) (*Service, error) {
|
||||
|
||||
coinPaymentsClient := coinpayments.NewClient(
|
||||
coinpayments.Credentials{
|
||||
@ -97,7 +97,7 @@ func NewService(log *zap.Logger, stripeClient StripeClient, config Config, db DB
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objectMonthDollars, err := decimal.NewFromString(objectPrice)
|
||||
segmentMonthDollars, err := decimal.NewFromString(segmentPrice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -105,7 +105,7 @@ func NewService(log *zap.Logger, stripeClient StripeClient, config Config, db DB
|
||||
// change the precision from TB dollars to MB cents
|
||||
storageMBMonthPriceCents := storageTBMonthDollars.Shift(-6).Shift(2)
|
||||
egressMBPriceCents := egressTBDollars.Shift(-6).Shift(2)
|
||||
objectMonthPriceCents := objectMonthDollars.Shift(2)
|
||||
segmentMonthPriceCents := segmentMonthDollars.Shift(2)
|
||||
|
||||
return &Service{
|
||||
log: log,
|
||||
@ -116,7 +116,7 @@ func NewService(log *zap.Logger, stripeClient StripeClient, config Config, db DB
|
||||
coinPayments: coinPaymentsClient,
|
||||
StorageMBMonthPriceCents: storageMBMonthPriceCents,
|
||||
EgressMBPriceCents: egressMBPriceCents,
|
||||
ObjectMonthPriceCents: objectMonthPriceCents,
|
||||
SegmentMonthPriceCents: segmentMonthPriceCents,
|
||||
BonusRate: bonusRate,
|
||||
StripeFreeTierCouponID: config.StripeFreeTierCouponID,
|
||||
AutoAdvance: config.AutoAdvance,
|
||||
@ -476,7 +476,7 @@ func (service *Service) createProjectRecords(ctx context.Context, customerID str
|
||||
ProjectID: project.ID,
|
||||
Storage: usage.Storage,
|
||||
Egress: usage.Egress,
|
||||
Objects: usage.ObjectCount,
|
||||
Segments: usage.SegmentCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -591,7 +591,7 @@ func (service *Service) createInvoiceItems(ctx context.Context, cusID, projName
|
||||
// InvoiceItemsFromProjectRecord calculates Stripe invoice item from project record.
|
||||
func (service *Service) InvoiceItemsFromProjectRecord(projName string, record ProjectRecord) (result []*stripe.InvoiceItemParams) {
|
||||
projectItem := &stripe.InvoiceItemParams{}
|
||||
projectItem.Description = stripe.String(fmt.Sprintf("Project %s - Object Storage (MB-Month)", projName))
|
||||
projectItem.Description = stripe.String(fmt.Sprintf("Project %s - Segment Storage (MB-Month)", projName))
|
||||
projectItem.Quantity = stripe.Int64(storageMBMonthDecimal(record.Storage).IntPart())
|
||||
storagePrice, _ := service.StorageMBMonthPriceCents.Float64()
|
||||
projectItem.UnitAmountDecimal = stripe.Float64(storagePrice)
|
||||
@ -605,11 +605,12 @@ func (service *Service) InvoiceItemsFromProjectRecord(projName string, record Pr
|
||||
result = append(result, projectItem)
|
||||
|
||||
projectItem = &stripe.InvoiceItemParams{}
|
||||
projectItem.Description = stripe.String(fmt.Sprintf("Project %s - Object Fee (Object-Month)", projName))
|
||||
projectItem.Quantity = stripe.Int64(objectMonthDecimal(record.Objects).IntPart())
|
||||
objectPrice, _ := service.ObjectMonthPriceCents.Float64()
|
||||
projectItem.UnitAmountDecimal = stripe.Float64(objectPrice)
|
||||
projectItem.Description = stripe.String(fmt.Sprintf("Project %s - Segment Fee (Segment-Month)", projName))
|
||||
projectItem.Quantity = stripe.Int64(segmentMonthDecimal(record.Segments).IntPart())
|
||||
segmentPrice, _ := service.SegmentMonthPriceCents.Float64()
|
||||
projectItem.UnitAmountDecimal = stripe.Float64(segmentPrice)
|
||||
result = append(result, projectItem)
|
||||
service.log.Info("invoice items", zap.Any("result", result))
|
||||
|
||||
return result
|
||||
}
|
||||
@ -785,27 +786,27 @@ func (service *Service) finalizeInvoice(ctx context.Context, invoiceID string) (
|
||||
|
||||
// projectUsagePrice represents pricing for project usage.
|
||||
type projectUsagePrice struct {
|
||||
Storage decimal.Decimal
|
||||
Egress decimal.Decimal
|
||||
Objects decimal.Decimal
|
||||
Storage decimal.Decimal
|
||||
Egress decimal.Decimal
|
||||
Segments decimal.Decimal
|
||||
}
|
||||
|
||||
// Total returns project usage price total.
|
||||
func (price projectUsagePrice) Total() decimal.Decimal {
|
||||
return price.Storage.Add(price.Egress).Add(price.Objects)
|
||||
return price.Storage.Add(price.Egress).Add(price.Segments)
|
||||
}
|
||||
|
||||
// Total returns project usage price total.
|
||||
func (price projectUsagePrice) TotalInt64() int64 {
|
||||
return price.Storage.Add(price.Egress).Add(price.Objects).IntPart()
|
||||
return price.Storage.Add(price.Egress).Add(price.Segments).IntPart()
|
||||
}
|
||||
|
||||
// calculateProjectUsagePrice calculate project usage price.
|
||||
func (service *Service) calculateProjectUsagePrice(egress int64, storage, objects float64) projectUsagePrice {
|
||||
func (service *Service) calculateProjectUsagePrice(egress int64, storage, segments float64) projectUsagePrice {
|
||||
return projectUsagePrice{
|
||||
Storage: service.StorageMBMonthPriceCents.Mul(storageMBMonthDecimal(storage)).Round(0),
|
||||
Egress: service.EgressMBPriceCents.Mul(egressMBDecimal(egress)).Round(0),
|
||||
Objects: service.ObjectMonthPriceCents.Mul(objectMonthDecimal(objects)).Round(0),
|
||||
Storage: service.StorageMBMonthPriceCents.Mul(storageMBMonthDecimal(storage)).Round(0),
|
||||
Egress: service.EgressMBPriceCents.Mul(egressMBDecimal(egress)).Round(0),
|
||||
Segments: service.SegmentMonthPriceCents.Mul(segmentMonthDecimal(segments)).Round(0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,8 +828,8 @@ func egressMBDecimal(egress int64) decimal.Decimal {
|
||||
return decimal.NewFromInt(egress).Shift(-6).Round(0)
|
||||
}
|
||||
|
||||
// objectMonthDecimal converts objects usage from Object-Hours to Object-Months.
|
||||
// segmentMonthDecimal converts segments usage from Segment-Hours to Segment-Months.
|
||||
// The result is rounded to the nearest whole number, but returned as Decimal for convenience.
|
||||
func objectMonthDecimal(objects float64) decimal.Decimal {
|
||||
return decimal.NewFromFloat(objects).Div(decimal.NewFromInt(hoursPerMonth)).Round(0)
|
||||
func segmentMonthDecimal(segments float64) decimal.Decimal {
|
||||
return decimal.NewFromFloat(segments).Div(decimal.NewFromInt(hoursPerMonth)).Round(0)
|
||||
}
|
||||
|
@ -130,8 +130,8 @@ func TestService_InvoiceUserWithManyProjects(t *testing.T) {
|
||||
ProjectID: projects[i].ID,
|
||||
BucketName: "testbucket",
|
||||
},
|
||||
TotalBytes: projectsStorage[i],
|
||||
ObjectCount: int64(i + 1),
|
||||
TotalBytes: projectsStorage[i],
|
||||
TotalSegments: int64(i + 1),
|
||||
}
|
||||
tallies := map[metabase.BucketLocation]*accounting.BucketTally{
|
||||
{}: tally,
|
||||
@ -161,8 +161,8 @@ func TestService_InvoiceUserWithManyProjects(t *testing.T) {
|
||||
expectedStorage := float64(projectsStorage[i] * int64(storageHours))
|
||||
require.Equal(t, expectedStorage, projectRecord.Storage)
|
||||
|
||||
expectedObjectsCount := float64((i + 1) * storageHours)
|
||||
require.Equal(t, expectedObjectsCount, projectRecord.Objects)
|
||||
expectedSegmentsCount := float64((i + 1) * storageHours)
|
||||
require.Equal(t, expectedSegmentsCount, projectRecord.Segments)
|
||||
}
|
||||
|
||||
// run all parts of invoice generation to see if there are no unexpected errors
|
||||
@ -239,16 +239,16 @@ func TestService_InvoiceItemsFromProjectRecord(t *testing.T) {
|
||||
// these numbers are fraction of cents, not of dollars.
|
||||
expectedStoragePrice := 0.001
|
||||
expectedEgressPrice := 0.0045
|
||||
expectedObjectPrice := 0.00022
|
||||
expectedSegmentPrice := 0.00022
|
||||
|
||||
type TestCase struct {
|
||||
Storage float64
|
||||
Egress int64
|
||||
Objects float64
|
||||
Storage float64
|
||||
Egress int64
|
||||
Segments float64
|
||||
|
||||
StorageQuantity int64
|
||||
EgressQuantity int64
|
||||
ObjectsQuantity int64
|
||||
StorageQuantity int64
|
||||
EgressQuantity int64
|
||||
SegmentsQuantity int64
|
||||
}
|
||||
|
||||
var testCases = []TestCase{
|
||||
@ -267,18 +267,18 @@ func TestService_InvoiceItemsFromProjectRecord(t *testing.T) {
|
||||
EgressQuantity: 134000, // Megabytes
|
||||
},
|
||||
{
|
||||
Objects: 400000, // Object-Hours
|
||||
// object quantity is calculated to Object-Months
|
||||
// round(400000 / 720) Object-Hours to Object-Months, 720 - hours in month
|
||||
ObjectsQuantity: 556, // Object-Months
|
||||
Segments: 400000, // Segment-Hours
|
||||
// object quantity is calculated to Segment-Months
|
||||
// round(400000 / 720) Segment-Hours to Segment-Months, 720 - hours in month
|
||||
SegmentsQuantity: 556, // Segment-Months
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
record := stripecoinpayments.ProjectRecord{
|
||||
Storage: tc.Storage,
|
||||
Egress: tc.Egress,
|
||||
Objects: tc.Objects,
|
||||
Storage: tc.Storage,
|
||||
Egress: tc.Egress,
|
||||
Segments: tc.Segments,
|
||||
}
|
||||
|
||||
items := satellite.API.Payments.Service.InvoiceItemsFromProjectRecord("project name", record)
|
||||
@ -289,8 +289,8 @@ func TestService_InvoiceItemsFromProjectRecord(t *testing.T) {
|
||||
require.Equal(t, tc.EgressQuantity, *items[1].Quantity)
|
||||
require.Equal(t, expectedEgressPrice, *items[1].UnitAmountDecimal)
|
||||
|
||||
require.Equal(t, tc.ObjectsQuantity, *items[2].Quantity)
|
||||
require.Equal(t, expectedObjectPrice, *items[2].UnitAmountDecimal)
|
||||
require.Equal(t, tc.SegmentsQuantity, *items[2].Quantity)
|
||||
require.Equal(t, expectedSegmentPrice, *items[2].UnitAmountDecimal)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func (db *invoiceProjectRecords) Create(ctx context.Context, records []stripecoi
|
||||
dbx.StripecoinpaymentsInvoiceProjectRecord_PeriodEnd(end),
|
||||
dbx.StripecoinpaymentsInvoiceProjectRecord_State(invoiceProjectRecordStateUnapplied.Int()),
|
||||
dbx.StripecoinpaymentsInvoiceProjectRecord_Create_Fields{
|
||||
Objects: dbx.StripecoinpaymentsInvoiceProjectRecord_Objects(int64(record.Objects)),
|
||||
Segments: dbx.StripecoinpaymentsInvoiceProjectRecord_Segments(int64(record.Segments)),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@ -175,9 +175,9 @@ func fromDBXInvoiceProjectRecord(dbxRecord *dbx.StripecoinpaymentsInvoiceProject
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
var objects float64
|
||||
if dbxRecord.Objects != nil {
|
||||
objects = float64(*dbxRecord.Objects)
|
||||
var segments float64
|
||||
if dbxRecord.Segments != nil {
|
||||
segments = float64(*dbxRecord.Segments)
|
||||
}
|
||||
|
||||
return &stripecoinpayments.ProjectRecord{
|
||||
@ -185,7 +185,7 @@ func fromDBXInvoiceProjectRecord(dbxRecord *dbx.StripecoinpaymentsInvoiceProject
|
||||
ProjectID: projectID,
|
||||
Storage: dbxRecord.Storage,
|
||||
Egress: dbxRecord.Egress,
|
||||
Objects: objects,
|
||||
Segments: segments,
|
||||
PeriodStart: dbxRecord.PeriodStart,
|
||||
PeriodEnd: dbxRecord.PeriodEnd,
|
||||
State: dbxRecord.State,
|
||||
|
@ -279,7 +279,7 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
|
||||
bucket_storage_tallies.total_bytes,
|
||||
bucket_storage_tallies.inline,
|
||||
bucket_storage_tallies.remote,
|
||||
bucket_storage_tallies.object_count
|
||||
bucket_storage_tallies.total_segments_count
|
||||
FROM
|
||||
bucket_storage_tallies
|
||||
WHERE
|
||||
@ -304,7 +304,7 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
|
||||
tally := accounting.BucketStorageTally{}
|
||||
|
||||
var inline, remote int64
|
||||
err = storageTalliesRows.Scan(&tally.IntervalStart, &tally.TotalBytes, &inline, &remote, &tally.ObjectCount)
|
||||
err = storageTalliesRows.Scan(&tally.IntervalStart, &tally.TotalBytes, &inline, &remote, &tally.TotalSegmentCount)
|
||||
if err != nil {
|
||||
return nil, errs.Combine(err, storageTalliesRows.Close())
|
||||
}
|
||||
@ -337,7 +337,7 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
|
||||
current := (tallies)[i]
|
||||
hours := (tallies)[i-1].IntervalStart.Sub(current.IntervalStart).Hours()
|
||||
usage.Storage += memory.Size(current.Bytes()).Float64() * hours
|
||||
usage.ObjectCount += float64(current.ObjectCount) * hours
|
||||
usage.SegmentCount += float64(current.TotalSegmentCount) * hours
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,7 +614,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
|
||||
FROM bucket_bandwidth_rollups
|
||||
WHERE project_id = ? AND bucket_name = ? AND interval_start >= ? AND interval_start <= ? AND action = ?`)
|
||||
|
||||
storageQuery := db.db.Rebind(`SELECT total_bytes, inline, remote, object_count
|
||||
storageQuery := db.db.Rebind(`SELECT total_bytes, inline, remote, total_segments_count
|
||||
FROM bucket_storage_tallies
|
||||
WHERE project_id = ? AND bucket_name = ? AND interval_start >= ? AND interval_start <= ?
|
||||
ORDER BY interval_start DESC
|
||||
@ -646,7 +646,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
|
||||
|
||||
var tally accounting.BucketStorageTally
|
||||
var inline, remote int64
|
||||
err = storageRow.Scan(&tally.TotalBytes, &inline, &remote, &tally.ObjectCount)
|
||||
err = storageRow.Scan(&tally.TotalBytes, &inline, &remote, &tally.TotalSegmentCount)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, err
|
||||
@ -659,7 +659,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
|
||||
|
||||
// fill storage and object count
|
||||
bucketUsage.Storage = memory.Size(tally.Bytes()).GB()
|
||||
bucketUsage.ObjectCount = tally.ObjectCount
|
||||
bucketUsage.SegmentCount = tally.TotalSegmentCount
|
||||
|
||||
bucketUsages = append(bucketUsages, bucketUsage)
|
||||
}
|
||||
|
6
scripts/testdata/satellite-config.yaml.lock
vendored
6
scripts/testdata/satellite-config.yaml.lock
vendored
@ -541,12 +541,12 @@ identity.key-path: /root/.local/share/storj/identity/satellite/identity.key
|
||||
# price node receive for storing TB of repair in cents
|
||||
# payments.node-repair-bandwidth-price: 1000
|
||||
|
||||
# price user should pay for each object stored in network per month
|
||||
# payments.object-price: "0"
|
||||
|
||||
# payments provider to use
|
||||
# payments.provider: ""
|
||||
|
||||
# price user should pay for each segment stored in network per month
|
||||
# payments.segment-price: "0"
|
||||
|
||||
# price user should pay for storing TB per month
|
||||
# payments.storage-tb-price: "4"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user