Skip to content

Commit 087e9c1

Browse files
authored
chore: split rating service (#4199)
1 parent fd573fa commit 087e9c1

10 files changed

Lines changed: 93 additions & 50 deletions

File tree

openmeter/billing/charges/service/featureid_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func (s *ChargeFeatureIDTestSuite) TestUsageBasedActivationRecalculatesFeatureID
196196
ChargeID: activatedCharge.GetChargeID(),
197197
})
198198
s.NoError(err)
199-
s.True(alpacadecimal.NewFromInt(7).Equal(currentTotals.Quantity))
199+
s.True(alpacadecimal.NewFromInt(21).Equal(currentTotals.DueTotals.Total))
200200

201201
clock.SetTime(servicePeriod.To.Add(2 * time.Hour))
202202
s.UsageBasedTestHandler.onCreditsOnlyUsageAccrued = func(ctx context.Context, input usagebased.CreditsOnlyUsageAccruedInput) (creditrealization.CreateAllocationInputs, error) {

openmeter/billing/charges/usagebased/service.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"errors"
66
"fmt"
77

8-
"github.com/alpacahq/alpacadecimal"
9-
108
"github.com/openmeterio/openmeter/openmeter/billing"
119
"github.com/openmeterio/openmeter/openmeter/billing/charges/meta"
1210
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
@@ -176,6 +174,5 @@ func (i GetCurrentTotalsInput) Validate() error {
176174

177175
type GetCurrentTotalsResult struct {
178176
Charge Charge
179-
Quantity alpacadecimal.Decimal
180177
DueTotals totals.Totals
181178
}

openmeter/billing/charges/usagebased/service/creditheninvoice.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func (s *CreditThenInvoiceStateMachine) SnapshotInvoiceUsage(ctx context.Context
183183

184184
storedAtOffset := meta.NormalizeTimestamp(currentRun.CollectionEnd)
185185

186-
ratingResult, err := s.Rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
186+
ratingResult, err := s.Rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
187187
Charge: s.Charge,
188188
Customer: s.CustomerOverride,
189189
FeatureMeter: s.FeatureMeter,

openmeter/billing/charges/usagebased/service/creditsonly.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func (s *CreditsOnlyStateMachine) FinalizeRealizationRun(ctx context.Context) er
181181

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

184-
ratingResult, err := s.Rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
184+
ratingResult, err := s.Rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
185185
Charge: s.Charge,
186186
Customer: s.CustomerOverride,
187187
FeatureMeter: s.FeatureMeter,

openmeter/billing/charges/usagebased/service/currenttotals.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,18 @@ func (s *service) GetCurrentTotals(ctx context.Context, input usagebased.GetCurr
4848
return usagebased.GetCurrentTotalsResult{}, err
4949
}
5050

51-
ratingResult, err := s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
51+
dueTotals, err := s.rater.GetTotalsForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
5252
Charge: charge,
5353
Customer: customerOverride,
5454
FeatureMeter: featureMeter,
5555
StoredAtOffset: clock.Now(),
5656
})
5757
if err != nil {
58-
return usagebased.GetCurrentTotalsResult{}, fmt.Errorf("get rating for usage: %w", err)
58+
return usagebased.GetCurrentTotalsResult{}, fmt.Errorf("get totals for usage: %w", err)
5959
}
6060

6161
return usagebased.GetCurrentTotalsResult{
6262
Charge: charge,
63-
Quantity: ratingResult.Quantity,
64-
DueTotals: ratingResult.Totals,
63+
DueTotals: dueTotals,
6564
}, nil
6665
}

openmeter/billing/charges/usagebased/service/get.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/openmeterio/openmeter/openmeter/billing/charges/meta"
1414
"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
1515
usagebasedrating "github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased/service/rating"
16+
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
1617
"github.com/openmeterio/openmeter/openmeter/customer"
1718
"github.com/openmeterio/openmeter/pkg/clock"
1819
"github.com/openmeterio/openmeter/pkg/framework/transaction"
@@ -141,19 +142,19 @@ func (s *service) expandChargesUsage(ctx context.Context, namespace string, char
141142
}
142143
}()
143144

144-
var ratingResult usagebasedrating.GetRatingForUsageResult
145-
ratingResult, err = s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
145+
var dueTotals totals.Totals
146+
dueTotals, err = s.rater.GetTotalsForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
146147
Charge: charge,
147148
Customer: customerOverridesById[charge.GetCustomerID()],
148149
FeatureMeter: featureMeter,
149150
StoredAtOffset: storedAt,
150151
})
151152
if err != nil {
152-
err = fmt.Errorf("rating charge %s: %w", charge.ID, err)
153+
err = fmt.Errorf("get totals for charge %s: %w", charge.ID, err)
153154
return
154155
}
155156

156-
ratingResults.Store(charge.GetChargeID(), ratingResult)
157+
ratingResults.Store(charge.GetChargeID(), dueTotals)
157158
})
158159
}
159160

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

176177
return slicesx.MapWithErr(charges, func(charge usagebased.Charge) (usagebased.Charge, error) {
177-
ratingResultAny, ok := ratingResults.Load(charge.GetChargeID())
178+
dueTotalsAny, ok := ratingResults.Load(charge.GetChargeID())
178179
if !ok {
179-
return charge, fmt.Errorf("rating result not found for charge %s", charge.ID)
180+
return charge, fmt.Errorf("totals result not found for charge %s", charge.ID)
180181
}
181182

182-
ratingResult, ok := ratingResultAny.(usagebasedrating.GetRatingForUsageResult)
183+
dueTotals, ok := dueTotalsAny.(totals.Totals)
183184
if !ok {
184-
return charge, fmt.Errorf("rating result not found for charge %s", charge.ID)
185+
return charge, fmt.Errorf("invalid totals type for charge %s", charge.ID)
185186
}
186187

187-
charge.Expands.RealtimeUsage = &ratingResult.Totals
188+
charge.Expands.RealtimeUsage = &dueTotals
188189
return charge, nil
189190
})
190191
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package rating
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
8+
)
9+
10+
// GetDetailedLinesForUsage returns the rated detailed lines together with the metered quantity snapshot
11+
// used to compute them. Prefer GetTotalsForUsage when only totals are needed because it is faster.
12+
func (s *Service) GetDetailedLinesForUsage(ctx context.Context, in GetRatingForUsageInput) (GetRatingForUsageResult, error) {
13+
if err := in.Validate(); err != nil {
14+
return GetRatingForUsageResult{}, err
15+
}
16+
17+
snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
18+
Customer: in.Customer.Customer,
19+
FeatureMeter: in.FeatureMeter,
20+
ServicePeriod: in.Charge.Intent.ServicePeriod,
21+
StoredAtOffset: in.StoredAtOffset,
22+
})
23+
if err != nil {
24+
return GetRatingForUsageResult{}, fmt.Errorf("get snapshot quantity: %w", err)
25+
}
26+
27+
ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
28+
Intent: in.Charge.Intent,
29+
MeterValue: snapshotQuantity,
30+
})
31+
if err != nil {
32+
return GetRatingForUsageResult{}, fmt.Errorf("rating: %w", err)
33+
}
34+
35+
return GetRatingForUsageResult{
36+
GenerateDetailedLinesResult: ratingResult,
37+
Quantity: snapshotQuantity,
38+
}, nil
39+
}

openmeter/billing/charges/usagebased/service/rating/service.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package rating
22

33
import (
4-
"context"
54
"errors"
65
"fmt"
76
"time"
@@ -81,32 +80,3 @@ func (i GetRatingForUsageInput) Validate() error {
8180

8281
return nil
8382
}
84-
85-
func (s *Service) GetRatingForUsage(ctx context.Context, in GetRatingForUsageInput) (GetRatingForUsageResult, error) {
86-
if err := in.Validate(); err != nil {
87-
return GetRatingForUsageResult{}, err
88-
}
89-
90-
snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
91-
Customer: in.Customer.Customer,
92-
FeatureMeter: in.FeatureMeter,
93-
ServicePeriod: in.Charge.Intent.ServicePeriod,
94-
StoredAtOffset: in.StoredAtOffset,
95-
})
96-
if err != nil {
97-
return GetRatingForUsageResult{}, fmt.Errorf("get snapshot quantity: %w", err)
98-
}
99-
100-
ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
101-
Intent: in.Charge.Intent,
102-
MeterValue: snapshotQuantity,
103-
})
104-
if err != nil {
105-
return GetRatingForUsageResult{}, fmt.Errorf("rating: %w", err)
106-
}
107-
108-
return GetRatingForUsageResult{
109-
GenerateDetailedLinesResult: ratingResult,
110-
Quantity: snapshotQuantity,
111-
}, nil
112-
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package rating
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/openmeterio/openmeter/openmeter/billing/charges/usagebased"
8+
"github.com/openmeterio/openmeter/openmeter/billing/models/totals"
9+
)
10+
11+
// GetTotalsForUsage returns the rated totals for the charge at the requested stored-at offset.
12+
// It avoids generating detailed lines, so prefer it over GetDetailedLinesForUsage when only totals are needed.
13+
func (s *Service) GetTotalsForUsage(ctx context.Context, in GetRatingForUsageInput) (totals.Totals, error) {
14+
if err := in.Validate(); err != nil {
15+
return totals.Totals{}, err
16+
}
17+
18+
snapshotQuantity, err := s.snapshotQuantity(ctx, snapshotQuantityInput{
19+
Customer: in.Customer.Customer,
20+
FeatureMeter: in.FeatureMeter,
21+
ServicePeriod: in.Charge.Intent.ServicePeriod,
22+
StoredAtOffset: in.StoredAtOffset,
23+
})
24+
if err != nil {
25+
return totals.Totals{}, fmt.Errorf("get snapshot quantity: %w", err)
26+
}
27+
28+
ratingResult, err := s.ratingService.GenerateDetailedLines(usagebased.RateableIntent{
29+
Intent: in.Charge.Intent,
30+
MeterValue: snapshotQuantity,
31+
})
32+
if err != nil {
33+
return totals.Totals{}, fmt.Errorf("rating totals: %w", err)
34+
}
35+
36+
return ratingResult.Totals, nil
37+
}

openmeter/billing/charges/usagebased/service/run/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (s *Service) CreateRatedRun(ctx context.Context, in CreateRatedRunInput) (C
109109
return CreateRatedRunResult{}, err
110110
}
111111

112-
ratingResult, err := s.rater.GetRatingForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
112+
ratingResult, err := s.rater.GetDetailedLinesForUsage(ctx, usagebasedrating.GetRatingForUsageInput{
113113
Charge: in.Charge,
114114
Customer: in.CustomerOverride,
115115
FeatureMeter: in.FeatureMeter,

0 commit comments

Comments
 (0)