Skip to content

Commit 36abde9

Browse files
refactor(subs): subscription validations (#3442)
Signed-off-by: Alex Goth <64845621+GAlexIHU@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 4b6727e commit 36abde9

File tree

29 files changed

+820
-325
lines changed

29 files changed

+820
-325
lines changed

app/common/subscription.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func NewSubscriptionServices(
6464
subscriptionItemRepo,
6565
)
6666

67-
subscriptionService := subscriptionservice.New(subscriptionservice.ServiceConfig{
67+
subscriptionService, err := subscriptionservice.New(subscriptionservice.ServiceConfig{
6868
SubscriptionRepo: subscriptionRepo,
6969
SubscriptionPhaseRepo: subscriptionPhaseRepo,
7070
SubscriptionItemRepo: subscriptionItemRepo,
@@ -76,6 +76,9 @@ func NewSubscriptionServices(
7676
FeatureFlags: featureFlags,
7777
Lockr: lockr,
7878
})
79+
if err != nil {
80+
return SubscriptionServiceWithWorkflow{}, err
81+
}
7982

8083
subAddRepo := subscriptionaddonrepo.NewSubscriptionAddonRepo(db)
8184
subAddQtyRepo := subscriptionaddonrepo.NewSubscriptionAddonQuantityRepo(db)

openmeter/billing/validators/customer/customer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func (v *Validator) ValidateDeleteCustomer(ctx context.Context, input customer.D
4646

4747
// Let's sync any subscriptions pending for this customer
4848
subs, err := v.subscriptionService.List(ctx, subscription.ListSubscriptionsInput{
49-
Namespaces: []string{input.Namespace},
50-
Customers: []string{input.ID},
49+
Namespaces: []string{input.Namespace},
50+
CustomerIDs: []string{input.ID},
5151
})
5252
if err != nil {
5353
return err

openmeter/billing/validators/subscription/validator.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import (
1313
)
1414

1515
type Validator struct {
16-
subscription.NoOpSubscriptionValidator
16+
subscription.NoOpSubscriptionCommandValidator
1717
billingService billing.Service
1818
}
1919

20-
func NewValidator(billingService billing.Service) (*Validator, error) {
20+
func NewValidator(billingService billing.Service) (subscription.SubscriptionCommandValidator, error) {
2121
if billingService == nil {
2222
return nil, fmt.Errorf("billing service is required")
2323
}
@@ -27,7 +27,7 @@ func NewValidator(billingService billing.Service) (*Validator, error) {
2727
}, nil
2828
}
2929

30-
func (v Validator) ValidateCreate(ctx context.Context, view subscription.SubscriptionView) error {
30+
func (v Validator) ValidateCreated(ctx context.Context, view subscription.SubscriptionView) error {
3131
err := v.validateBillingSetup(ctx, view)
3232
if err != nil {
3333
return models.NewGenericConflictError(fmt.Errorf("invalid billing setup: %w", err))
@@ -36,7 +36,7 @@ func (v Validator) ValidateCreate(ctx context.Context, view subscription.Subscri
3636
return nil
3737
}
3838

39-
func (v Validator) ValidateUpdate(ctx context.Context, view subscription.SubscriptionView) error {
39+
func (v Validator) ValidateUpdated(ctx context.Context, view subscription.SubscriptionView) error {
4040
err := v.validateBillingSetup(ctx, view)
4141
if err != nil {
4242
return models.NewGenericConflictError(fmt.Errorf("invalid billing setup: %w", err))

openmeter/billing/worker/subscription/reconciler.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import (
77
"log/slog"
88
"time"
99

10+
"github.com/samber/lo"
11+
1012
"github.com/openmeterio/openmeter/openmeter/customer"
1113
"github.com/openmeterio/openmeter/openmeter/subscription"
14+
"github.com/openmeterio/openmeter/pkg/clock"
1215
"github.com/openmeterio/openmeter/pkg/models"
1316
"github.com/openmeterio/openmeter/pkg/timeutil"
1417
)
@@ -83,11 +86,11 @@ func (r *Reconciler) ListSubscriptions(ctx context.Context, in ReconcilerListSub
8386
}
8487

8588
subscriptions, err := r.subscriptionService.List(ctx, subscription.ListSubscriptionsInput{
86-
Namespaces: in.Namespaces,
87-
Customers: in.Customers,
88-
ActiveInPeriod: &timeutil.ClosedPeriod{
89-
From: time.Now().Add(-in.Lookback),
90-
To: time.Now(),
89+
Namespaces: in.Namespaces,
90+
CustomerIDs: in.Customers,
91+
ActiveInPeriod: &timeutil.StartBoundedPeriod{
92+
From: clock.Now().Add(-in.Lookback),
93+
To: lo.ToPtr(clock.Now()),
9194
},
9295
})
9396
if err != nil {

openmeter/customer/httpdriver/customer.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ func (h *handler) ListCustomers() ListCustomersHandler {
9292
})
9393

9494
subscriptions, err := h.subscriptionService.List(ctx, subscription.ListSubscriptionsInput{
95-
Namespaces: []string{request.Namespace},
96-
Customers: customerIDs,
97-
ActiveAt: lo.ToPtr(time.Now()),
95+
Namespaces: []string{request.Namespace},
96+
CustomerIDs: customerIDs,
97+
ActiveAt: lo.ToPtr(time.Now()),
9898
})
9999
if err != nil {
100100
return ListCustomersResponse{}, err
@@ -475,9 +475,9 @@ func (h *handler) GetCustomerAccess() GetCustomerAccessHandler {
475475
func (h *handler) mapCustomerWithSubscriptionsToAPI(ctx context.Context, customer customer.Customer, expand []api.CustomerExpand) (api.Customer, error) {
476476
// Get the customer's subscriptions
477477
subscriptions, err := h.subscriptionService.List(ctx, subscription.ListSubscriptionsInput{
478-
Namespaces: []string{customer.Namespace},
479-
Customers: []string{customer.ID},
480-
ActiveAt: lo.ToPtr(time.Now()),
478+
Namespaces: []string{customer.Namespace},
479+
CustomerIDs: []string{customer.ID},
480+
ActiveAt: lo.ToPtr(time.Now()),
481481
})
482482
if err != nil {
483483
return GetCustomerResponse{}, err

openmeter/productcatalog/subscription/http/get.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ func (h *handler) ListCustomerSubscriptions() ListCustomerSubscriptionsHandler {
113113
var def ListCustomerSubscriptionsResponse
114114

115115
subs, err := h.SubscriptionService.List(ctx, subscription.ListSubscriptionsInput{
116-
Page: req.Page,
117-
Namespaces: []string{req.CustomerID.Namespace},
118-
Customers: []string{req.CustomerID.ID},
116+
Page: req.Page,
117+
Namespaces: []string{req.CustomerID.Namespace},
118+
CustomerIDs: []string{req.CustomerID.ID},
119119
})
120120
if err != nil {
121121
return def, err

openmeter/server/server_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import (
6262
"github.com/openmeterio/openmeter/pkg/models"
6363
"github.com/openmeterio/openmeter/pkg/pagination"
6464
"github.com/openmeterio/openmeter/pkg/ref"
65+
"github.com/openmeterio/openmeter/pkg/timeutil"
6566
)
6667

6768
var DefaultNamespace = "test"
@@ -1209,7 +1210,7 @@ var _ subscription.Service = (*NoopSubscriptionService)(nil)
12091210
// for use in testing
12101211
type NoopSubscriptionService struct{}
12111212

1212-
func (n NoopSubscriptionService) RegisterValidator(validator subscription.SubscriptionValidator) error {
1213+
func (n NoopSubscriptionService) RegisterValidator(validator subscription.SubscriptionCommandValidator) error {
12131214
return nil
12141215
}
12151216

@@ -1245,10 +1246,14 @@ func (n NoopSubscriptionService) List(ctx context.Context, params subscription.L
12451246
return pagination.Result[subscription.Subscription]{}, nil
12461247
}
12471248

1248-
func (n NoopSubscriptionService) GetAllForCustomerSince(ctx context.Context, customerID models.NamespacedID, at time.Time) ([]subscription.Subscription, error) {
1249+
func (n NoopSubscriptionService) GetAllForCustomer(ctx context.Context, customerID models.NamespacedID, period timeutil.StartBoundedPeriod) ([]subscription.Subscription, error) {
12491250
return []subscription.Subscription{}, nil
12501251
}
12511252

1253+
func (n NoopSubscriptionService) ExpandViews(ctx context.Context, subs []subscription.Subscription) ([]subscription.SubscriptionView, error) {
1254+
return []subscription.SubscriptionView{}, nil
1255+
}
1256+
12521257
var _ subscriptionworkflow.Service = (*NoopSubscriptionWorkflowService)(nil)
12531258

12541259
// NoopSubscriptionWorkflowService implements subscriptionworkflow.Service with no-op operations

openmeter/subscription/entitlement.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package subscription
33
import (
44
"context"
55
"fmt"
6-
"time"
76

87
"github.com/openmeterio/openmeter/openmeter/entitlement"
98
"github.com/openmeterio/openmeter/pkg/models"
@@ -62,7 +61,9 @@ type EntitlementAdapter interface {
6261
// At refers to a point in time for which we're querying the system state, meaning:
6362
// if t1 < t2 < t3, and some entitlement was deleted effective at t2, then
6463
// with at = t1 the entitlement will be returned, while with at = t3 it won't.
65-
GetForSubscriptionAt(ctx context.Context, subscriptionID models.NamespacedID, at time.Time) ([]SubscriptionEntitlement, error)
64+
GetForSubscriptionAt(ctx context.Context, input GetForSubscriptionAtInput) ([]SubscriptionEntitlement, error)
65+
66+
GetForSubscriptionsAt(ctx context.Context, input []GetForSubscriptionAtInput) ([]SubscriptionEntitlement, error)
6667

6768
DeleteByItemID(ctx context.Context, itemId models.NamespacedID) error
6869
}

openmeter/subscription/entitlement/adapter.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package subscriptionentitlement
33
import (
44
"context"
55
"fmt"
6-
"time"
76

87
"github.com/samber/lo"
98

@@ -13,6 +12,7 @@ import (
1312
"github.com/openmeterio/openmeter/pkg/framework/transaction"
1413
"github.com/openmeterio/openmeter/pkg/models"
1514
"github.com/openmeterio/openmeter/pkg/pagination"
15+
"github.com/openmeterio/openmeter/pkg/slicesx"
1616
)
1717

1818
type EntitlementSubscriptionAdapter struct {
@@ -105,8 +105,8 @@ func (a *EntitlementSubscriptionAdapter) GetByItemID(ctx context.Context, id mod
105105
}, nil
106106
}
107107

108-
func (a *EntitlementSubscriptionAdapter) GetForSubscriptionAt(ctx context.Context, subscriptionID models.NamespacedID, at time.Time) ([]subscription.SubscriptionEntitlement, error) {
109-
items, err := a.itemRepo.GetForSubscriptionAt(ctx, subscriptionID, at)
108+
func (a *EntitlementSubscriptionAdapter) GetForSubscriptionAt(ctx context.Context, input subscription.GetForSubscriptionAtInput) ([]subscription.SubscriptionEntitlement, error) {
109+
items, err := a.itemRepo.GetForSubscriptionAt(ctx, input)
110110
if err != nil {
111111
return nil, err
112112
}
@@ -118,7 +118,7 @@ func (a *EntitlementSubscriptionAdapter) GetForSubscriptionAt(ctx context.Contex
118118
if len(items) > 0 {
119119
ents, err = a.entitlementConnector.ListEntitlements(ctx, entitlement.ListEntitlementsParams{
120120
IDs: lo.Map(items, func(s subscription.SubscriptionItem, _ int) string { return *s.EntitlementID }),
121-
Namespaces: []string{subscriptionID.Namespace},
121+
Namespaces: []string{input.Namespace},
122122
Page: pagination.Page{}, // zero value so all entitlements are fetched
123123
})
124124
if err != nil {
@@ -148,6 +148,42 @@ func (a *EntitlementSubscriptionAdapter) GetForSubscriptionAt(ctx context.Contex
148148
return subEnts, nil
149149
}
150150

151+
func (a *EntitlementSubscriptionAdapter) GetForSubscriptionsAt(ctx context.Context, input []subscription.GetForSubscriptionAtInput) ([]subscription.SubscriptionEntitlement, error) {
152+
items, err := a.itemRepo.GetForSubscriptionsAt(ctx, input)
153+
if err != nil {
154+
return nil, err
155+
}
156+
157+
items = lo.Filter(items, func(s subscription.SubscriptionItem, _ int) bool { return s.EntitlementID != nil })
158+
159+
if len(items) == 0 {
160+
return nil, nil
161+
}
162+
163+
ents, err := a.entitlementConnector.ListEntitlements(ctx, entitlement.ListEntitlementsParams{
164+
IDs: lo.Map(items, func(s subscription.SubscriptionItem, _ int) string { return *s.EntitlementID }),
165+
Namespaces: lo.Uniq(lo.Map(input, func(s subscription.GetForSubscriptionAtInput, _ int) string { return s.Namespace })),
166+
Page: pagination.Page{}, // zero value so all entitlements are fetched
167+
})
168+
if err != nil {
169+
return nil, err
170+
}
171+
172+
return slicesx.MapWithErr(ents.Items, func(ent entitlement.Entitlement) (subscription.SubscriptionEntitlement, error) {
173+
if ent.ActiveFrom == nil {
174+
return subscription.SubscriptionEntitlement{}, fmt.Errorf("entitlement active from is nil, entitlement doesn't have cadence")
175+
}
176+
177+
return subscription.SubscriptionEntitlement{
178+
Entitlement: ent,
179+
Cadence: models.CadencedModel{
180+
ActiveFrom: *ent.ActiveFrom,
181+
ActiveTo: ent.ActiveTo,
182+
},
183+
}, nil
184+
})
185+
}
186+
151187
func (a *EntitlementSubscriptionAdapter) DeleteByItemID(ctx context.Context, id models.NamespacedID) error {
152188
item, err := a.itemRepo.GetByID(ctx, id)
153189
if err != nil {

openmeter/subscription/list.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ type ListSubscriptionsInput struct {
1313
pagination.Page
1414

1515
Namespaces []string
16-
Customers []string
16+
CustomerIDs []string
1717
ActiveAt *time.Time
18-
ActiveInPeriod *timeutil.ClosedPeriod
18+
ActiveInPeriod *timeutil.StartBoundedPeriod
1919
}
2020

2121
func (i ListSubscriptionsInput) Validate() error {

0 commit comments

Comments
 (0)