| package subscriptions |
|
|
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "net/http" |
|
|
| "github.com/samber/lo" |
|
|
| api "github.com/openmeterio/openmeter/api/v3" |
| "github.com/openmeterio/openmeter/api/v3/apierrors" |
| "github.com/openmeterio/openmeter/api/v3/request" |
| "github.com/openmeterio/openmeter/openmeter/customer" |
| "github.com/openmeterio/openmeter/openmeter/productcatalog" |
| "github.com/openmeterio/openmeter/openmeter/productcatalog/plan" |
| plansubscription "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription" |
| "github.com/openmeterio/openmeter/pkg/framework/commonhttp" |
| "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" |
| models "github.com/openmeterio/openmeter/pkg/models" |
| ) |
|
|
| type ( |
| CreateSubscriptionRequest = plansubscription.CreateSubscriptionRequest |
| CreateSubscriptionResponse = api.BillingSubscription |
| CreateSubscriptionHandler = httptransport.Handler[CreateSubscriptionRequest, CreateSubscriptionResponse] |
| ) |
|
|
| |
| func (h *handler) CreateSubscription() CreateSubscriptionHandler { |
| return httptransport.NewHandler( |
| func(ctx context.Context, r *http.Request) (plansubscription.CreateSubscriptionRequest, error) { |
| |
| body := api.BillingSubscriptionCreate{} |
| if err := request.ParseBody(r, &body); err != nil { |
| return CreateSubscriptionRequest{}, err |
| } |
|
|
| |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return CreateSubscriptionRequest{}, err |
| } |
|
|
| var settlementMode *productcatalog.SettlementMode |
| if body.SettlementMode != nil { |
| settlementMode = lo.ToPtr(productcatalog.SettlementMode(*body.SettlementMode)) |
| } |
|
|
| |
| if body.Customer.Id == nil && body.Customer.Key == nil { |
| reason := "one of customer.id or customer.key is required" |
| return CreateSubscriptionRequest{}, apierrors.NewBadRequestError( |
| ctx, |
| errors.New(reason), |
| []apierrors.InvalidParameter{ |
| { |
| Field: "customer.id", |
| Reason: reason, |
| Source: apierrors.InvalidParamSourceBody, |
| Rule: "required", |
| }, |
| { |
| Field: "customer.key", |
| Reason: reason, |
| Source: apierrors.InvalidParamSourceBody, |
| Rule: "required", |
| }, |
| }, |
| ) |
| } |
|
|
| |
| customerEntity, err := h.getCustomerByIDOrKey(ctx, ns, body.Customer.Id, body.Customer.Key) |
| if err != nil { |
| return CreateSubscriptionRequest{}, fmt.Errorf("failed to get customer: %w", err) |
| } |
|
|
| |
| if body.Plan.Id == nil && body.Plan.Key == nil { |
| reason := "one of plan.id or plan.key is required" |
| |
| return CreateSubscriptionRequest{}, apierrors.NewBadRequestError( |
| ctx, |
| errors.New(reason), |
| []apierrors.InvalidParameter{ |
| { |
| Field: "plan.id", |
| Reason: reason, |
| Source: apierrors.InvalidParamSourceBody, |
| Rule: "required", |
| }, |
| { |
| Field: "plan.key", |
| Reason: reason, |
| Source: apierrors.InvalidParamSourceBody, |
| Rule: "required", |
| }, |
| }, |
| ) |
| } |
|
|
| |
| planEntity, err := h.getPlanByIDOrKey(ctx, ns, body.Plan.Id, body.Plan.Key, body.Plan.Version) |
| if err != nil { |
| return CreateSubscriptionRequest{}, fmt.Errorf("failed to get plan: %w", err) |
| } |
|
|
| |
| planInput := plansubscription.PlanInput{} |
| planInput.FromRef(&plansubscription.PlanRefInput{ |
| Key: planEntity.Key, |
| Version: &planEntity.Version, |
| }) |
|
|
| |
| subscriptionName := fmt.Sprintf("%s v%d", planEntity.Key, planEntity.Version) |
| workflowInput, err := FromAPIBillingSubscriptionCreate( |
| ns, |
| customerEntity.GetID(), |
| subscriptionName, |
| body, |
| ) |
| if err != nil { |
| return CreateSubscriptionRequest{}, err |
| } |
|
|
| return plansubscription.CreateSubscriptionRequest{ |
| WorkflowInput: workflowInput, |
| PlanInput: planInput, |
| SettlementMode: settlementMode, |
| }, nil |
| }, |
| func(ctx context.Context, request plansubscription.CreateSubscriptionRequest) (CreateSubscriptionResponse, error) { |
| |
| m, err := h.planSubscriptionService.Create(ctx, request) |
| if err != nil { |
| return CreateSubscriptionResponse{}, err |
| } |
|
|
| |
| return ToAPIBillingSubscription(m), nil |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[CreateSubscriptionResponse](http.StatusCreated), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("create-subscription"), |
| httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()), |
| )..., |
| ) |
| } |
|
|
| |
| |
| func (h *handler) getCustomerByIDOrKey(ctx context.Context, namespace string, customerID *string, customerKey *string) (*customer.Customer, error) { |
| var getCustomerInput customer.GetCustomerInput |
|
|
| if customerID != nil { |
| getCustomerInput = customer.GetCustomerInput{ |
| CustomerID: &customer.CustomerID{ |
| Namespace: namespace, |
| ID: *customerID, |
| }, |
| } |
| } else if customerKey != nil { |
| getCustomerInput = customer.GetCustomerInput{ |
| CustomerKey: &customer.CustomerKey{ |
| Namespace: namespace, |
| Key: *customerKey, |
| }, |
| } |
| } else { |
| return nil, fmt.Errorf("customer id or customer key is required") |
| } |
|
|
| return h.customerService.GetCustomer(ctx, getCustomerInput) |
| } |
|
|
| |
| |
| func (h *handler) getPlanByIDOrKey(ctx context.Context, namespace string, planID *string, planKey *string, planVersion *int) (*plan.Plan, error) { |
| |
| var getPlanInput plan.GetPlanInput |
|
|
| if planID != nil { |
| getPlanInput = plan.GetPlanInput{ |
| NamespacedID: models.NamespacedID{ |
| Namespace: namespace, |
| ID: *planID, |
| }, |
| } |
| } else if planKey != nil { |
| getPlanInput = plan.GetPlanInput{} |
| |
| |
| getPlanInput.Namespace = namespace |
| getPlanInput.Key = *planKey |
|
|
| if planVersion != nil { |
| getPlanInput.Version = *planVersion |
| } else { |
| getPlanInput.IncludeLatest = true |
| } |
| } else { |
| return nil, errors.New("plan id or plan key must be set") |
| } |
|
|
| |
| return h.planService.GetPlan(ctx, getPlanInput) |
| } |
|
|