From 34b2a369f7ed604849ef56e0f0b6b4d9cced1cd1 Mon Sep 17 00:00:00 2001 From: Jeremy Wharton Date: Tue, 4 Apr 2023 04:10:25 -0500 Subject: [PATCH] satellite/payments/stripe: apply egress discount to project charges The project charge information used by the satellite frontend to compute project cost estimates has been updated to account for configured egress discounts. Resolves storj/storj-private#215 Change-Id: Ic90b015d65f5bea104ac96fb0cea545b3f9f1f8f --- satellite/payments/projectcharges.go | 12 ++++++------ satellite/payments/stripe/accounts.go | 9 +++++---- satellite/payments/stripe/service.go | 23 +++++++++++++++-------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/satellite/payments/projectcharges.go b/satellite/payments/projectcharges.go index 50e5daaea..8e501ce6f 100644 --- a/satellite/payments/projectcharges.go +++ b/satellite/payments/projectcharges.go @@ -14,12 +14,12 @@ import ( type ProjectCharge struct { accounting.ProjectUsage - // StorageGbHrs shows how much cents we should pay for storing GB*Hrs. - StorageGbHrs int64 `json:"storagePrice"` - // Egress shows how many cents we should pay for Egress. - Egress int64 `json:"egressPrice"` - // SegmentCount shows how many cents we should pay for objects count. - SegmentCount int64 `json:"segmentPrice"` + // StorageMBMonthCents is how many cents we should pay for storing MB*months. + StorageMBMonthCents int64 `json:"storagePrice"` + // EgressMBCents is how many cents we should pay for megabytes of egress. + EgressMBCents int64 `json:"egressPrice"` + // SegmentMonthCents is how many cents we should pay for objects count. + SegmentMonthCents int64 `json:"segmentPrice"` } // ProjectChargesResponse represents a collection of project usage charges grouped by project ID and partner name. diff --git a/satellite/payments/stripe/accounts.go b/satellite/payments/stripe/accounts.go index a924ebc1a..e2f431317 100644 --- a/satellite/payments/stripe/accounts.go +++ b/satellite/payments/stripe/accounts.go @@ -146,14 +146,15 @@ func (accounts *accounts) ProjectCharges(ctx context.Context, userID uuid.UUID, for partner, usage := range usages { priceModel := accounts.GetProjectUsagePriceModel(partner) - price := accounts.service.calculateProjectUsagePrice(usage.Egress, usage.Storage, usage.SegmentCount, priceModel) + usage.Egress = applyEgressDiscount(usage, priceModel) + price := accounts.service.calculateProjectUsagePrice(usage, priceModel) partnerCharges[partner] = payments.ProjectCharge{ ProjectUsage: usage, - Egress: price.Egress.IntPart(), - SegmentCount: price.Segments.IntPart(), - StorageGbHrs: price.Storage.IntPart(), + EgressMBCents: price.Egress.IntPart(), + SegmentMonthCents: price.Segments.IntPart(), + StorageMBMonthCents: price.Storage.IntPart(), } } diff --git a/satellite/payments/stripe/service.go b/satellite/payments/stripe/service.go index 1afcfa729..f0db054f0 100644 --- a/satellite/payments/stripe/service.go +++ b/satellite/payments/stripe/service.go @@ -539,10 +539,7 @@ func (service *Service) InvoiceItemsFromProjectUsage(projName string, partnerUsa priceModel := service.Accounts().GetProjectUsagePriceModel(partner) usage := partnerUsages[partner] - usage.Egress -= int64(math.Round(usage.Storage / hoursPerMonth * priceModel.EgressDiscountRatio)) - if usage.Egress < 0 { - usage.Egress = 0 - } + usage.Egress = applyEgressDiscount(usage, priceModel) prefix := "Project " + projName if partner != "" { @@ -891,11 +888,11 @@ func (price projectUsagePrice) TotalInt64() int64 { } // calculateProjectUsagePrice calculate project usage price. -func (service *Service) calculateProjectUsagePrice(egress int64, storage, segments float64, pricing payments.ProjectUsagePriceModel) projectUsagePrice { +func (service *Service) calculateProjectUsagePrice(usage accounting.ProjectUsage, pricing payments.ProjectUsagePriceModel) projectUsagePrice { return projectUsagePrice{ - Storage: pricing.StorageMBMonthCents.Mul(storageMBMonthDecimal(storage)).Round(0), - Egress: pricing.EgressMBCents.Mul(egressMBDecimal(egress)).Round(0), - Segments: pricing.SegmentMonthCents.Mul(segmentMonthDecimal(segments)).Round(0), + Storage: pricing.StorageMBMonthCents.Mul(storageMBMonthDecimal(usage.Storage)).Round(0), + Egress: pricing.EgressMBCents.Mul(egressMBDecimal(usage.Egress)).Round(0), + Segments: pricing.SegmentMonthCents.Mul(segmentMonthDecimal(usage.SegmentCount)).Round(0), } } @@ -928,3 +925,13 @@ func segmentMonthDecimal(segments float64) decimal.Decimal { func doesProjectRecordHaveNoUsage(record ProjectRecord) bool { return record.Storage == 0 && record.Egress == 0 && record.Segments == 0 } + +// applyEgressDiscount returns the amount of egress that we should charge for by subtracting +// the discounted amount. +func applyEgressDiscount(usage accounting.ProjectUsage, model payments.ProjectUsagePriceModel) int64 { + egress := usage.Egress - int64(math.Round(usage.Storage/hoursPerMonth*model.EgressDiscountRatio)) + if egress < 0 { + egress = 0 + } + return egress +}