Skip to content

Commit f58accf

Browse files
committed
feat(api): added planaddon handlers
1 parent 4f95a7d commit f58accf

10 files changed

Lines changed: 377 additions & 6 deletions

File tree

api/v3/handlers/plans/convert.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/openmeterio/openmeter/api/v3/labels"
1212
"github.com/openmeterio/openmeter/openmeter/productcatalog"
1313
"github.com/openmeterio/openmeter/openmeter/productcatalog/plan"
14+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
1415
"github.com/openmeterio/openmeter/openmeter/taxcode"
1516
"github.com/openmeterio/openmeter/pkg/datetime"
1617
"github.com/openmeterio/openmeter/pkg/models"
@@ -736,6 +737,22 @@ func toBillingTaxConfig(tc api.BillingRateCardTaxConfig) *productcatalog.TaxConf
736737
return result
737738
}
738739

740+
func fromPlanAddon(a planaddon.PlanAddon) (api.PlanAddon, error) {
741+
validationIssues, _ := a.AsProductCatalogPlanAddon().ValidationErrors()
742+
743+
return api.PlanAddon{
744+
Id: a.ID,
745+
Addon: api.AddonReferenceItem{Id: a.Addon.ID},
746+
FromPlanPhase: a.PlanAddonConfig.FromPlanPhase,
747+
MaxQuantity: a.PlanAddonConfig.MaxQuantity,
748+
CreatedAt: lo.ToPtr(a.CreatedAt),
749+
UpdatedAt: lo.ToPtr(a.UpdatedAt),
750+
DeletedAt: a.DeletedAt,
751+
Labels: labels.FromMetadata(a.Metadata),
752+
ValidationErrors: fromValidationErrors(validationIssues),
753+
}, nil
754+
}
755+
739756
func toBillingDiscounts(d api.BillingRateCardDiscounts) (productcatalog.Discounts, error) {
740757
result := productcatalog.Discounts{}
741758

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package plans
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
8+
api "github.com/openmeterio/openmeter/api/v3"
9+
"github.com/openmeterio/openmeter/api/v3/apierrors"
10+
"github.com/openmeterio/openmeter/api/v3/labels"
11+
"github.com/openmeterio/openmeter/api/v3/request"
12+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
13+
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
14+
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
15+
"github.com/openmeterio/openmeter/pkg/models"
16+
)
17+
18+
type (
19+
CreatePlanAddonRequest = planaddon.CreatePlanAddonInput
20+
CreatePlanAddonResponse = api.PlanAddon
21+
CreatePlanAddonParams = string
22+
CreatePlanAddonHandler httptransport.HandlerWithArgs[CreatePlanAddonRequest, CreatePlanAddonResponse, CreatePlanAddonParams]
23+
)
24+
25+
func (h *handler) CreatePlanAddon() CreatePlanAddonHandler {
26+
return httptransport.NewHandlerWithArgs(
27+
func(ctx context.Context, r *http.Request, planID CreatePlanAddonParams) (CreatePlanAddonRequest, error) {
28+
body := api.CreatePlanAddonRequest{}
29+
if err := request.ParseBody(r, &body); err != nil {
30+
return CreatePlanAddonRequest{}, err
31+
}
32+
33+
ns, err := h.resolveNamespace(ctx)
34+
if err != nil {
35+
return CreatePlanAddonRequest{}, err
36+
}
37+
38+
return CreatePlanAddonRequest{
39+
NamespacedModel: models.NamespacedModel{
40+
Namespace: ns,
41+
},
42+
PlanID: planID,
43+
AddonID: body.Addon.Id,
44+
FromPlanPhase: body.FromPlanPhase,
45+
MaxQuantity: body.MaxQuantity,
46+
Metadata: labels.ToMetadata(body.Labels),
47+
}, nil
48+
},
49+
func(ctx context.Context, request CreatePlanAddonRequest) (CreatePlanAddonResponse, error) {
50+
a, err := h.addonService.CreatePlanAddon(ctx, request)
51+
if err != nil {
52+
return CreatePlanAddonResponse{}, err
53+
}
54+
55+
if a == nil {
56+
return CreatePlanAddonResponse{}, fmt.Errorf("failed to create plan addon")
57+
}
58+
59+
return fromPlanAddon(*a)
60+
},
61+
commonhttp.JSONResponseEncoderWithStatus[CreatePlanAddonResponse](http.StatusCreated),
62+
httptransport.AppendOptions(
63+
h.options,
64+
httptransport.WithOperationName("create-plan-addon"),
65+
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
66+
)...,
67+
)
68+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package plans
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/go-chi/chi/v5"
8+
9+
"github.com/openmeterio/openmeter/api/v3/apierrors"
10+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
11+
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
12+
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
13+
"github.com/openmeterio/openmeter/pkg/models"
14+
)
15+
16+
type (
17+
DeletePlanAddonRequest = planaddon.DeletePlanAddonInput
18+
DeletePlanAddonResponse = any
19+
DeletePlanAddonParams = string
20+
DeletePlanAddonHandler httptransport.HandlerWithArgs[DeletePlanAddonRequest, DeletePlanAddonResponse, DeletePlanAddonParams]
21+
)
22+
23+
func (h *handler) DeletePlanAddon() DeletePlanAddonHandler {
24+
return httptransport.NewHandlerWithArgs(
25+
func(ctx context.Context, r *http.Request, planAddonID DeletePlanAddonParams) (DeletePlanAddonRequest, error) {
26+
ns, err := h.resolveNamespace(ctx)
27+
if err != nil {
28+
return DeletePlanAddonRequest{}, err
29+
}
30+
31+
planID := chi.URLParam(r, "planId")
32+
33+
return DeletePlanAddonRequest{
34+
NamespacedModel: models.NamespacedModel{
35+
Namespace: ns,
36+
},
37+
ID: planAddonID,
38+
PlanID: planID,
39+
}, nil
40+
},
41+
func(ctx context.Context, request DeletePlanAddonRequest) (DeletePlanAddonResponse, error) {
42+
if err := h.addonService.DeletePlanAddon(ctx, request); err != nil {
43+
return nil, err
44+
}
45+
46+
return nil, nil
47+
},
48+
commonhttp.EmptyResponseEncoder[DeletePlanAddonResponse](http.StatusNoContent),
49+
httptransport.AppendOptions(
50+
h.options,
51+
httptransport.WithOperationName("delete-plan-addon"),
52+
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
53+
)...,
54+
)
55+
}

api/v3/handlers/plans/get_addon.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package plans
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
api "github.com/openmeterio/openmeter/api/v3"
8+
"github.com/openmeterio/openmeter/api/v3/apierrors"
9+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
10+
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
11+
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
12+
"github.com/openmeterio/openmeter/pkg/models"
13+
)
14+
15+
type (
16+
GetPlanAddonRequest = planaddon.GetPlanAddonInput
17+
GetPlanAddonResponse = api.PlanAddon
18+
GetPlanAddonParams = string
19+
GetPlanAddonHandler httptransport.HandlerWithArgs[GetPlanAddonRequest, GetPlanAddonResponse, GetPlanAddonParams]
20+
)
21+
22+
func (h *handler) GetPlanAddon() GetPlanAddonHandler {
23+
return httptransport.NewHandlerWithArgs(
24+
func(ctx context.Context, r *http.Request, planAddonID GetPlanAddonParams) (GetPlanAddonRequest, error) {
25+
ns, err := h.resolveNamespace(ctx)
26+
if err != nil {
27+
return GetPlanAddonRequest{}, err
28+
}
29+
30+
return GetPlanAddonRequest{
31+
NamespacedModel: models.NamespacedModel{
32+
Namespace: ns,
33+
},
34+
ID: planAddonID,
35+
}, nil
36+
},
37+
func(ctx context.Context, request GetPlanAddonRequest) (GetPlanAddonResponse, error) {
38+
a, err := h.addonService.GetPlanAddon(ctx, request)
39+
if err != nil {
40+
return GetPlanAddonResponse{}, err
41+
}
42+
43+
return fromPlanAddon(*a)
44+
},
45+
commonhttp.JSONResponseEncoderWithStatus[GetPlanAddonResponse](http.StatusOK),
46+
httptransport.AppendOptions(
47+
h.options,
48+
httptransport.WithOperationName("get-plan-addon"),
49+
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
50+
)...,
51+
)
52+
}

api/v3/handlers/plans/handler.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55

66
"github.com/openmeterio/openmeter/openmeter/productcatalog/plan"
7+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
78
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
89
)
910

@@ -15,22 +16,30 @@ type Handler interface {
1516
DeletePlan() DeletePlanHandler
1617
PublishPlan() PublishPlanHandler
1718
ArchivePlan() ArchivePlanHandler
19+
ListPlanAddons() ListPlanAddonsHandler
20+
GetPlanAddon() GetPlanAddonHandler
21+
CreatePlanAddon() CreatePlanAddonHandler
22+
UpdatePlanAddon() UpdatePlanAddonHandler
23+
DeletePlanAddon() DeletePlanAddonHandler
1824
}
1925

2026
type handler struct {
2127
resolveNamespace func(ctx context.Context) (string, error)
2228
service plan.Service
29+
addonService planaddon.Service
2330
options []httptransport.HandlerOption
2431
}
2532

2633
func New(
2734
resolveNamespace func(ctx context.Context) (string, error),
2835
service plan.Service,
36+
addonService planaddon.Service,
2937
options ...httptransport.HandlerOption,
3038
) Handler {
3139
return &handler{
3240
resolveNamespace: resolveNamespace,
3341
service: service,
42+
addonService: addonService,
3443
options: options,
3544
}
3645
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package plans
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/go-chi/chi/v5"
8+
"github.com/samber/lo"
9+
10+
api "github.com/openmeterio/openmeter/api/v3"
11+
"github.com/openmeterio/openmeter/api/v3/apierrors"
12+
"github.com/openmeterio/openmeter/api/v3/response"
13+
"github.com/openmeterio/openmeter/openmeter/productcatalog/planaddon"
14+
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
15+
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
16+
"github.com/openmeterio/openmeter/pkg/pagination"
17+
)
18+
19+
type (
20+
ListPlanAddonsRequest = planaddon.ListPlanAddonsInput
21+
ListPlanAddonsResponse = response.PagePaginationResponse[api.PlanAddon]
22+
ListPlanAddonsParams = api.ListPlanAddonsParams
23+
ListPlanAddonsHandler httptransport.HandlerWithArgs[ListPlanAddonsRequest, ListPlanAddonsResponse, ListPlanAddonsParams]
24+
)
25+
26+
func (h *handler) ListPlanAddons() ListPlanAddonsHandler {
27+
return httptransport.NewHandlerWithArgs(
28+
func(ctx context.Context, r *http.Request, params ListPlanAddonsParams) (ListPlanAddonsRequest, error) {
29+
ns, err := h.resolveNamespace(ctx)
30+
if err != nil {
31+
return ListPlanAddonsRequest{}, err
32+
}
33+
34+
planID := chi.URLParam(r, "planId")
35+
36+
page := pagination.NewPage(1, 20)
37+
if params.Page != nil {
38+
page = pagination.NewPage(
39+
lo.FromPtrOr(params.Page.Number, 1),
40+
lo.FromPtrOr(params.Page.Size, 20),
41+
)
42+
}
43+
44+
if err := page.Validate(); err != nil {
45+
return ListPlanAddonsRequest{}, apierrors.NewBadRequestError(ctx, err, apierrors.InvalidParameters{
46+
apierrors.InvalidParameter{
47+
Field: "page",
48+
Reason: err.Error(),
49+
Source: apierrors.InvalidParamSourceQuery,
50+
},
51+
})
52+
}
53+
54+
return ListPlanAddonsRequest{
55+
Namespaces: []string{ns},
56+
PlanIDs: []string{planID},
57+
Page: page,
58+
}, nil
59+
},
60+
func(ctx context.Context, req ListPlanAddonsRequest) (ListPlanAddonsResponse, error) {
61+
result, err := h.addonService.ListPlanAddons(ctx, req)
62+
if err != nil {
63+
return ListPlanAddonsResponse{}, err
64+
}
65+
66+
items := make([]api.PlanAddon, 0, len(result.Items))
67+
for _, a := range result.Items {
68+
planAddon, err := fromPlanAddon(a)
69+
if err != nil {
70+
return ListPlanAddonsResponse{}, err
71+
}
72+
73+
items = append(items, planAddon)
74+
}
75+
76+
return response.NewPagePaginationResponse(items, response.PageMetaPage{
77+
Size: req.Page.PageSize,
78+
Number: req.Page.PageNumber,
79+
Total: lo.ToPtr(result.TotalCount),
80+
}), nil
81+
},
82+
commonhttp.JSONResponseEncoderWithStatus[ListPlanAddonsResponse](http.StatusOK),
83+
httptransport.AppendOptions(
84+
h.options,
85+
httptransport.WithOperationName("list-plan-addons"),
86+
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
87+
)...,
88+
)
89+
}

0 commit comments

Comments
 (0)