Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion openmeter/billing/charges/service/featureid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func (s *ChargeFeatureIDTestSuite) TestUsageBasedActivationRecalculatesFeatureID
ChargeID: activatedCharge.GetChargeID(),
})
s.NoError(err)
s.True(alpacadecimal.NewFromInt(7).Equal(currentTotals.Quantity))
s.True(alpacadecimal.NewFromInt(21).Equal(currentTotals.DueTotals.Total))

clock.SetTime(servicePeriod.To.Add(2 * time.Hour))
s.UsageBasedTestHandler.onCreditsOnlyUsageAccrued = func(ctx context.Context, input usagebased.CreditsOnlyUsageAccruedInput) (creditrealization.CreateAllocationInputs, error) {
Expand Down
3 changes: 0 additions & 3 deletions openmeter/billing/charges/usagebased/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"errors"
"fmt"

"github.com/alpacahq/alpacadecimal"

"github.com/openmeterio/openmeter/openmeter/billing"
"github.com/openmeterio/openmeter/openmeter/billing/charges/meta"
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
Expand Down Expand Up @@ -176,6 +174,5 @@ func (i GetCurrentTotalsInput) Validate() error {

type GetCurrentTotalsResult struct {
Charge Charge
Quantity alpacadecimal.Decimal
DueTotals totals.Totals
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (s *CreditThenInvoiceStateMachine) SnapshotInvoiceUsage(ctx context.Context

storedAtOffset := meta.NormalizeTimestamp(currentRun.CollectionEnd)

ratingResult, err := s.Rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
ratingResult, err := s.Rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
Charge: s.Charge,
Customer: s.CustomerOverride,
FeatureMeter: s.FeatureMeter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (s *CreditsOnlyStateMachine) FinalizeRealizationRun(ctx context.Context) er

storedAtOffset := meta.NormalizeTimestamp(clock.Now().Add(-usagebased.InternalCollectionPeriod))

ratingResult, err := s.Rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
ratingResult, err := s.Rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
Charge: s.Charge,
Customer: s.CustomerOverride,
FeatureMeter: s.FeatureMeter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,18 @@ func (s *service) GetCurrentTotals(ctx context.Context, input usagebased.GetCurr
return usagebased.GetCurrentTotalsResult{}, err
}

ratingResult, err := s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
dueTotals, err := s.rater.GetTotalsForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
Charge: charge,
Customer: customerOverride,
FeatureMeter: featureMeter,
StoredAtOffset: clock.Now(),
})
if err != nil {
return usagebased.GetCurrentTotalsResult{}, fmt.Errorf("get rating for usage: %w", err)
return usagebased.GetCurrentTotalsResult{}, fmt.Errorf("get totals for usage: %w", err)
}

return usagebased.GetCurrentTotalsResult{
Charge: charge,
Quantity: ratingResult.Quantity,
DueTotals: ratingResult.Totals,
DueTotals: dueTotals,
}, nil
Comment thread
turip marked this conversation as resolved.
}
19 changes: 10 additions & 9 deletions openmeter/billing/charges/usagebased/service/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/openmeterio/openmeter/openmeter/billing/charges/meta"
"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
usagebasedrating "github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased/service/rating"
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
"github.com/openmeterio/openmeter/openmeter/customer"
"github.com/openmeterio/openmeter/pkg/clock"
"github.com/openmeterio/openmeter/pkg/framework/transaction"
Expand Down Expand Up @@ -141,19 +142,19 @@ func (s *service) expandChargesUsage(ctx context.Context, namespace string, char
}
}()

var ratingResult usagebasedrating.GetRatingForUsageResult
ratingResult, err = s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
var dueTotals totals.Totals
dueTotals, err = s.rater.GetTotalsForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
Charge: charge,
Customer: customerOverridesById[charge.GetCustomerID()],
FeatureMeter: featureMeter,
StoredAtOffset: storedAt,
})
if err != nil {
err = fmt.Errorf("rating charge %s: %w", charge.ID, err)
err = fmt.Errorf("get totals for charge %s: %w", charge.ID, err)
return
}

ratingResults.Store(charge.GetChargeID(), ratingResult)
ratingResults.Store(charge.GetChargeID(), dueTotals)
})
}

Expand All @@ -174,17 +175,17 @@ func (s *service) expandChargesUsage(ctx context.Context, namespace string, char
}

return slicesx.MapWithErr(charges, func(charge usagebased.Charge) (usagebased.Charge, error) {
ratingResultAny, ok := ratingResults.Load(charge.GetChargeID())
dueTotalsAny, ok := ratingResults.Load(charge.GetChargeID())
if !ok {
return charge, fmt.Errorf("rating result not found for charge %s", charge.ID)
return charge, fmt.Errorf("totals result not found for charge %s", charge.ID)
}

ratingResult, ok := ratingResultAny.(usagebasedrating.GetRatingForUsageResult)
dueTotals, ok := dueTotalsAny.(totals.Totals)
if !ok {
return charge, fmt.Errorf("rating result not found for charge %s", charge.ID)
return charge, fmt.Errorf("invalid totals type for charge %s", charge.ID)
}

charge.Expands.RealtimeUsage = &ratingResult.Totals
charge.Expands.RealtimeUsage = &dueTotals
return charge, nil
})
Comment thread
turip marked this conversation as resolved.
}
39 changes: 39 additions & 0 deletions openmeter/billing/charges/usagebased/service/rating/details.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package rating

import (
"context"
"fmt"

"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
)

// GetDetailedLinesForUsage returns the rated detailed lines together with the metered quantity snapshot
// used to compute them. Prefer GetTotalsForUsage when only totals are needed because it is faster.
func (s *Service) GetDetailedLinesForUsage(ctx context.Context, in GetRatingForUsageInput) (GetRatingForUsageResult, error) {
Comment thread
turip marked this conversation as resolved.
if err := in.Validate(); err != nil {
return GetRatingForUsageResult{}, err
}

snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
Customer: in.Customer.Customer,
FeatureMeter: in.FeatureMeter,
ServicePeriod: in.Charge.Intent.ServicePeriod,
StoredAtOffset: in.StoredAtOffset,
})
if err != nil {
return GetRatingForUsageResult{}, fmt.Errorf("get snapshot quantity: %w", err)
}

ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
Intent: in.Charge.Intent,
MeterValue: snapshotQuantity,
})
if err != nil {
return GetRatingForUsageResult{}, fmt.Errorf("rating: %w", err)
}

return GetRatingForUsageResult{
GenerateDetailedLinesResult: ratingResult,
Quantity: snapshotQuantity,
}, nil
}
30 changes: 0 additions & 30 deletions openmeter/billing/charges/usagebased/service/rating/service.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package rating

import (
"context"
"errors"
"fmt"
"time"
Expand Down Expand Up @@ -81,32 +80,3 @@ func (i GetRatingForUsageInput) Validate() error {

return nil
}

func (s *Service) GetRatingForUsage(ctx context.Context, in GetRatingForUsageInput) (GetRatingForUsageResult, error) {
if err := in.Validate(); err != nil {
return GetRatingForUsageResult{}, err
}

snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
Customer: in.Customer.Customer,
FeatureMeter: in.FeatureMeter,
ServicePeriod: in.Charge.Intent.ServicePeriod,
StoredAtOffset: in.StoredAtOffset,
})
if err != nil {
return GetRatingForUsageResult{}, fmt.Errorf("get snapshot quantity: %w", err)
}

ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
Intent: in.Charge.Intent,
MeterValue: snapshotQuantity,
})
if err != nil {
return GetRatingForUsageResult{}, fmt.Errorf("rating: %w", err)
}

return GetRatingForUsageResult{
GenerateDetailedLinesResult: ratingResult,
Quantity: snapshotQuantity,
}, nil
}
37 changes: 37 additions & 0 deletions openmeter/billing/charges/usagebased/service/rating/totals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package rating

import (
"context"
"fmt"

"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
)

// GetTotalsForUsage returns the rated totals for the charge at the requested stored-at offset.
// It avoids generating detailed lines, so prefer it over GetDetailedLinesForUsage when only totals are needed.
func (s *Service) GetTotalsForUsage(ctx context.Context, in GetRatingForUsageInput) (totals.Totals, error) {
if err := in.Validate(); err != nil {
return totals.Totals{}, err
}

snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
Customer: in.Customer.Customer,
FeatureMeter: in.FeatureMeter,
ServicePeriod: in.Charge.Intent.ServicePeriod,
StoredAtOffset: in.StoredAtOffset,
})
if err != nil {
return totals.Totals{}, fmt.Errorf("get snapshot quantity: %w", err)
}

ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
Intent: in.Charge.Intent,
MeterValue: snapshotQuantity,
})
if err != nil {
return totals.Totals{}, fmt.Errorf("rating totals: %w", err)
}

return ratingResult.Totals, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (s *Service) CreateRatedRun(ctx context.Context, in CreateRatedRunInput) (C
return CreateRatedRunResult{}, err
}

ratingResult, err := s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
ratingResult, err := s.rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
Charge: in.Charge,
Customer: in.CustomerOverride,
FeatureMeter: in.FeatureMeter,
Expand Down
Loading