| package httpdriver |
|
|
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "net/http" |
| "slices" |
|
|
| "github.com/samber/lo" |
|
|
| "github.com/openmeterio/openmeter/api" |
| "github.com/openmeterio/openmeter/openmeter/app" |
| apphttpdriver "github.com/openmeterio/openmeter/openmeter/app/httpdriver" |
| "github.com/openmeterio/openmeter/openmeter/billing" |
| "github.com/openmeterio/openmeter/pkg/convert" |
| "github.com/openmeterio/openmeter/pkg/datetime" |
| "github.com/openmeterio/openmeter/pkg/defaultx" |
| "github.com/openmeterio/openmeter/pkg/framework/commonhttp" |
| "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" |
| "github.com/openmeterio/openmeter/pkg/models" |
| "github.com/openmeterio/openmeter/pkg/pagination" |
| "github.com/openmeterio/openmeter/pkg/sortx" |
| ) |
|
|
| var _ ProfileHandler = (*handler)(nil) |
|
|
| type ( |
| CreateProfileRequest = billing.CreateProfileInput |
| CreateProfileResponse = api.BillingProfile |
| CreateProfileHandler httptransport.Handler[CreateProfileRequest, CreateProfileResponse] |
| ) |
|
|
| func (h *handler) CreateProfile() CreateProfileHandler { |
| return httptransport.NewHandler( |
| func(ctx context.Context, r *http.Request) (CreateProfileRequest, error) { |
| body := api.BillingProfileCreate{} |
| if err := commonhttp.JSONRequestBodyDecoder(r, &body); err != nil { |
| return CreateProfileRequest{}, fmt.Errorf("failed to decode request body: %w", err) |
| } |
|
|
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return CreateProfileRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| workflow, err := fromAPIBillingWorkflowCreate(body.Workflow) |
| if err != nil { |
| return CreateProfileRequest{}, fmt.Errorf("failed to parse workflow: %w", err) |
| } |
|
|
| return CreateProfileRequest{ |
| Namespace: ns, |
|
|
| Name: body.Name, |
| Description: body.Description, |
|
|
| Metadata: lo.FromPtrOr(body.Metadata, map[string]string{}), |
|
|
| Supplier: apiBillingPartyCreateToSupplierContact(body.Supplier), |
|
|
| Default: body.Default, |
|
|
| WorkflowConfig: workflow, |
| Apps: billing.CreateProfileAppsInput{ |
| Tax: app.AppID{ |
| Namespace: ns, |
| ID: body.Apps.Tax, |
| }, |
| Invoicing: app.AppID{ |
| Namespace: ns, |
| ID: body.Apps.Invoicing, |
| }, |
| Payment: app.AppID{ |
| Namespace: ns, |
| ID: body.Apps.Payment, |
| }, |
| }, |
| }, nil |
| }, |
| func(ctx context.Context, request CreateProfileRequest) (CreateProfileResponse, error) { |
| profile, err := h.service.CreateProfile(ctx, request) |
| if err != nil { |
| return CreateProfileResponse{}, fmt.Errorf("failed to create profile: %w", err) |
| } |
|
|
| return h.MapProfileToApi(ctx, profile) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[CreateProfileResponse](http.StatusCreated), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("CreateBillingProfile"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| GetProfileParams struct { |
| ID string |
| Expand []api.BillingProfileExpand |
| } |
| GetProfileRequest = billing.GetProfileInput |
| GetProfileResponse = api.BillingProfile |
| GetProfileHandler httptransport.HandlerWithArgs[GetProfileRequest, GetProfileResponse, GetProfileParams] |
| ) |
|
|
| func (h *handler) GetProfile() GetProfileHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, params GetProfileParams) (GetProfileRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return GetProfileRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| return GetProfileRequest{ |
| Profile: billing.ProfileID{ |
| Namespace: ns, |
| ID: params.ID, |
| }, |
| Expand: mapProfileExpandToEntity(params.Expand), |
| }, nil |
| }, |
| func(ctx context.Context, request GetProfileRequest) (GetProfileResponse, error) { |
| profile, err := h.service.GetProfile(ctx, request) |
| if err != nil { |
| return GetProfileResponse{}, fmt.Errorf("failed to get profile: %w", err) |
| } |
|
|
| return h.MapProfileToApi(ctx, profile) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[CreateProfileResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("GetBillingProfile"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| DeleteProfileRequest = billing.DeleteProfileInput |
| DeleteProfileResponse = struct{} |
| DeleteProfileHandler httptransport.HandlerWithArgs[DeleteProfileRequest, DeleteProfileResponse, string] |
| ) |
|
|
| func (h *handler) DeleteProfile() DeleteProfileHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, id string) (DeleteProfileRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return DeleteProfileRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| return DeleteProfileRequest{ |
| Namespace: ns, |
| ID: id, |
| }, nil |
| }, |
| func(ctx context.Context, request DeleteProfileRequest) (DeleteProfileResponse, error) { |
| if err := h.service.DeleteProfile(ctx, request); err != nil { |
| return DeleteProfileResponse{}, fmt.Errorf("failed to archive profile: %w", err) |
| } |
|
|
| return DeleteProfileResponse{}, nil |
| }, |
| commonhttp.EmptyResponseEncoder[DeleteProfileResponse](http.StatusNoContent), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("DeleteBillingProfile"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| UpdateProfileRequest = billing.UpdateProfileInput |
| UpdateProfileResponse = api.BillingProfile |
| UpdateProfileHandler httptransport.HandlerWithArgs[UpdateProfileRequest, UpdateProfileResponse, string] |
| ) |
|
|
| func (h *handler) UpdateProfile() UpdateProfileHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, id string) (UpdateProfileRequest, error) { |
| body := api.BillingProfileReplaceUpdateWithWorkflow{} |
| if err := commonhttp.JSONRequestBodyDecoder(r, &body); err != nil { |
| return UpdateProfileRequest{}, fmt.Errorf("failed to decode request body: %w", err) |
| } |
|
|
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return UpdateProfileRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| workflow, err := fromAPIBillingWorkflow(body.Workflow) |
| if err != nil { |
| return UpdateProfileRequest{}, fmt.Errorf("failed to parse workflow: %w", err) |
| } |
|
|
| return UpdateProfileRequest{ |
| Namespace: ns, |
| ID: id, |
|
|
| Name: body.Name, |
| Description: body.Description, |
|
|
| Metadata: lo.FromPtrOr(body.Metadata, map[string]string{}), |
|
|
| Supplier: apiBillingPartyToSupplierContact(body.Supplier), |
|
|
| Default: body.Default, |
|
|
| WorkflowConfig: workflow, |
| }, nil |
| }, |
| func(ctx context.Context, request UpdateProfileRequest) (UpdateProfileResponse, error) { |
| profile, err := h.service.UpdateProfile(ctx, request) |
| if err != nil { |
| return UpdateProfileResponse{}, fmt.Errorf("failed to update profile: %w", err) |
| } |
|
|
| return h.MapProfileToApi(ctx, profile) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[UpdateProfileResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("UpdateBillingProfiles"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| ListProfilesRequest = billing.ListProfilesInput |
| ListProfilesResponse = api.BillingProfilePaginatedResponse |
| ListProfilesParams = api.ListBillingProfilesParams |
| ListProfilesHandler httptransport.HandlerWithArgs[ListProfilesRequest, ListProfilesResponse, ListProfilesParams] |
| ) |
|
|
| func (h *handler) ListProfiles() ListProfilesHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, params ListProfilesParams) (ListProfilesRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return ListProfilesRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| return ListProfilesRequest{ |
| Namespace: ns, |
| IncludeArchived: lo.FromPtrOr(params.IncludeArchived, DefaultIncludeArchived), |
| OrderBy: lo.FromPtrOr(params.OrderBy, api.BillingProfileOrderByCreatedAt), |
| Order: sortx.Order(lo.FromPtrOr(params.Order, api.SortOrderDESC)), |
|
|
| Page: pagination.Page{ |
| PageSize: defaultx.WithDefault(params.PageSize, DefaultPageSize), |
| PageNumber: defaultx.WithDefault(params.Page, DefaultPageNumber), |
| }, |
| }, nil |
| }, |
| func(ctx context.Context, request ListProfilesRequest) (ListProfilesResponse, error) { |
| profiles, err := h.service.ListProfiles(ctx, request) |
| if err != nil { |
| return ListProfilesResponse{}, fmt.Errorf("failed to list profiles: %w", err) |
| } |
|
|
| out := ListProfilesResponse{ |
| Items: make([]api.BillingProfile, 0, len(profiles.Items)), |
| Page: profiles.Page.PageNumber, |
| PageSize: profiles.Page.PageSize, |
| TotalCount: profiles.TotalCount, |
| } |
|
|
| for _, profile := range profiles.Items { |
| apiProfile, err := h.MapProfileToApi(ctx, &profile) |
| if err != nil { |
| return ListProfilesResponse{}, fmt.Errorf("failed to convert profile to API: %w", err) |
| } |
|
|
| out.Items = append(out.Items, apiProfile) |
| } |
|
|
| return out, nil |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[ListProfilesResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("ListBillingProfiles"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| func apiBillingPartyCreateToSupplierContact(c api.BillingParty) billing.SupplierContact { |
| out := billing.SupplierContact{ |
| Name: lo.FromPtr(c.Name), |
| } |
|
|
| if c.Addresses == nil || len(*c.Addresses) == 0 { |
| return out |
| } |
|
|
| if c.TaxId != nil { |
| out.TaxCode = c.TaxId.Code |
| } |
|
|
| addr := (*c.Addresses)[0] |
|
|
| out.Address = models.Address{ |
| Country: (*models.CountryCode)(addr.Country), |
| City: addr.City, |
| State: addr.State, |
| PostalCode: addr.PostalCode, |
| Line1: addr.Line1, |
| Line2: addr.Line2, |
| PhoneNumber: addr.PhoneNumber, |
| } |
|
|
| return out |
| } |
|
|
| func apiBillingPartyToSupplierContact(c api.BillingParty) billing.SupplierContact { |
| out := billing.SupplierContact{ |
| Name: lo.FromPtr(c.Name), |
| } |
|
|
| if c.Addresses == nil || len(*c.Addresses) == 0 { |
| return out |
| } |
|
|
| if c.TaxId != nil { |
| out.TaxCode = c.TaxId.Code |
| } |
|
|
| addr := (*c.Addresses)[0] |
|
|
| out.Address = models.Address{ |
| Country: (*models.CountryCode)(addr.Country), |
| City: addr.City, |
| State: addr.State, |
| PostalCode: addr.PostalCode, |
| Line1: addr.Line1, |
| Line2: addr.Line2, |
| PhoneNumber: addr.PhoneNumber, |
| } |
|
|
| return out |
| } |
|
|
| func fromAPIBillingWorkflow(i api.BillingWorkflow) (billing.WorkflowConfig, error) { |
| return fromAPIBillingWorkflowWithSubscriptionEndProrationModeDefault(i, "") |
| } |
|
|
| func fromAPIBillingWorkflowWithSubscriptionEndProrationModeDefault(i api.BillingWorkflow, defaultSubscriptionEndProrationMode billing.SubscriptionEndProrationMode) (billing.WorkflowConfig, error) { |
| def := billing.DefaultWorkflowConfig |
|
|
| if i.Collection == nil { |
| i.Collection = &api.BillingWorkflowCollectionSettings{} |
| } |
|
|
| if i.Invoicing == nil { |
| i.Invoicing = &api.BillingWorkflowInvoicingSettings{} |
| } |
|
|
| if i.Payment == nil { |
| i.Payment = &api.BillingWorkflowPaymentSettings{} |
| } |
|
|
| if i.Tax == nil { |
| i.Tax = &api.BillingWorkflowTaxSettings{} |
| } |
|
|
| collInterval, err := parseDurationPtr(i.Collection.Interval, def.Collection.Interval) |
| if err != nil { |
| return billing.WorkflowConfig{}, fmt.Errorf("failed to parse collection interval: %w", err) |
| } |
|
|
| draftPeriod, err := parseDurationPtr(i.Invoicing.DraftPeriod, def.Invoicing.DraftPeriod) |
| if err != nil { |
| return billing.WorkflowConfig{}, fmt.Errorf("failed to parse draft period: %w", err) |
| } |
|
|
| dueAfter, err := parseDurationPtr(i.Invoicing.DueAfter, def.Invoicing.DueAfter) |
| if err != nil { |
| return billing.WorkflowConfig{}, fmt.Errorf("failed to parse due after: %w", err) |
| } |
|
|
| subscriptionEndProrationMode := defaultSubscriptionEndProrationMode |
| if i.Invoicing.SubscriptionEndProrationMode != nil { |
| subscriptionEndProrationMode = billing.SubscriptionEndProrationMode(*i.Invoicing.SubscriptionEndProrationMode) |
| } |
|
|
| return billing.WorkflowConfig{ |
| Collection: billing.CollectionConfig{ |
| Alignment: def.Collection.Alignment, |
| Interval: collInterval, |
| }, |
|
|
| Invoicing: billing.InvoicingConfig{ |
| AutoAdvance: lo.FromPtrOr(i.Invoicing.AutoAdvance, def.Invoicing.AutoAdvance), |
| DraftPeriod: draftPeriod, |
| DueAfter: dueAfter, |
| ProgressiveBilling: lo.FromPtrOr(i.Invoicing.ProgressiveBilling, def.Invoicing.ProgressiveBilling), |
| SubscriptionEndProrationMode: subscriptionEndProrationMode, |
| DefaultTaxConfig: mapTaxConfigToEntity(i.Invoicing.DefaultTaxConfig), |
| }, |
|
|
| Payment: billing.PaymentConfig{ |
| CollectionMethod: lo.FromPtrOr((*billing.CollectionMethod)(i.Payment.CollectionMethod), def.Payment.CollectionMethod), |
| }, |
|
|
| Tax: billing.WorkflowTaxConfig{ |
| Enabled: lo.FromPtrOr(i.Tax.Enabled, def.Tax.Enabled), |
| Enforced: lo.FromPtrOr(i.Tax.Enforced, def.Tax.Enforced), |
| }, |
| }, nil |
| } |
|
|
| func fromAPIBillingWorkflowCreate(i api.BillingWorkflowCreate) (billing.WorkflowConfig, error) { |
| return fromAPIBillingWorkflowWithSubscriptionEndProrationModeDefault( |
| api.BillingWorkflow(i), |
| billing.DefaultWorkflowConfig.Invoicing.SubscriptionEndProrationMode, |
| ) |
| } |
|
|
| func parseDurationPtr(d *string, defaultDuration datetime.ISODuration) (datetime.ISODuration, error) { |
| if d == nil { |
| return defaultDuration, nil |
| } |
|
|
| return datetime.ISODurationString(*d).Parse() |
| } |
|
|
| func (h *handler) MapProfileToApi(ctx context.Context, p *billing.Profile) (api.BillingProfile, error) { |
| if p == nil { |
| return api.BillingProfile{}, errors.New("profile is nil") |
| } |
|
|
| workflowConfig, err := mapWorkflowConfigToAPI(p.WorkflowConfig) |
| if err != nil { |
| return api.BillingProfile{}, fmt.Errorf("failed to map workflow config to API: %w", err) |
| } |
|
|
| out := api.BillingProfile{ |
| Id: p.ID, |
| CreatedAt: p.CreatedAt, |
| UpdatedAt: p.UpdatedAt, |
| DeletedAt: p.DeletedAt, |
|
|
| Description: p.Description, |
| Metadata: convert.MapToPointer(p.Metadata), |
| Default: p.Default, |
|
|
| Name: p.Name, |
| Supplier: mapSupplierContactToAPI(p.Supplier), |
| Workflow: workflowConfig, |
| } |
|
|
| if p.Apps != nil { |
| apps, err := mapProfileAppsToAPI(p.Apps) |
| if err != nil { |
| return api.BillingProfile{}, fmt.Errorf("failed to map profile apps: %w", err) |
| } |
|
|
| if apps != nil { |
| out.Apps = *apps |
| } |
| } else { |
| apps, err := mapProfileAppReferencesToAPI(p.AppReferences) |
| if err != nil { |
| return api.BillingProfile{}, fmt.Errorf("failed to map profile app references: %w", err) |
| } |
|
|
| if apps != nil { |
| out.Apps = *apps |
| } |
| } |
|
|
| return out, nil |
| } |
|
|
| func mapProfileAppsToAPI(a *billing.ProfileApps) (*api.BillingProfileAppsOrReference, error) { |
| if a == nil { |
| return nil, nil |
| } |
|
|
| tax, err := apphttpdriver.MapAppToAPI(a.Tax) |
| if err != nil { |
| return nil, fmt.Errorf("cannot map tax app: %w", err) |
| } |
|
|
| invoicing, err := apphttpdriver.MapAppToAPI(a.Invoicing) |
| if err != nil { |
| return nil, fmt.Errorf("cannot map invoicing app: %w", err) |
| } |
|
|
| payment, err := apphttpdriver.MapAppToAPI(a.Payment) |
| if err != nil { |
| return nil, fmt.Errorf("cannot map payment app: %w", err) |
| } |
|
|
| apps := api.BillingProfileApps{ |
| Tax: tax, |
| Invoicing: invoicing, |
| Payment: payment, |
| } |
|
|
| out := api.BillingProfileAppsOrReference{} |
|
|
| if err := out.FromBillingProfileApps(apps); err != nil { |
| return nil, fmt.Errorf("failed to convert apps to API: %w", err) |
| } |
|
|
| return &out, nil |
| } |
|
|
| func mapProfileAppReferencesToAPI(a *billing.ProfileAppReferences) (*api.BillingProfileAppsOrReference, error) { |
| if a == nil { |
| return nil, nil |
| } |
|
|
| apps := api.BillingProfileAppReferences{ |
| Tax: api.AppReference{ |
| Id: a.Tax.ID, |
| }, |
| Invoicing: api.AppReference{ |
| Id: a.Invoicing.ID, |
| }, |
| Payment: api.AppReference{ |
| Id: a.Payment.ID, |
| }, |
| } |
|
|
| out := api.BillingProfileAppsOrReference{} |
|
|
| if err := out.FromBillingProfileAppReferences(apps); err != nil { |
| return nil, fmt.Errorf("failed to convert apps to API: %w", err) |
| } |
|
|
| return &out, nil |
| } |
|
|
| func mapProfileExpandToEntity(expand []api.BillingProfileExpand) billing.ProfileExpand { |
| if len(expand) == 0 { |
| return billing.ProfileExpand{} |
| } |
|
|
| return billing.ProfileExpand{ |
| Apps: slices.Contains(expand, api.BillingProfileExpandApps), |
| } |
| } |
|
|
| func mapSupplierContactToAPI(c billing.SupplierContact) api.BillingParty { |
| a := c.Address |
|
|
| out := api.BillingParty{ |
| Id: lo.EmptyableToPtr(c.ID), |
| Name: lo.EmptyableToPtr(c.Name), |
| Addresses: lo.ToPtr([]api.Address{ |
| { |
| Country: (*string)(a.Country), |
| PostalCode: a.PostalCode, |
| State: a.State, |
| City: a.City, |
| Line1: a.Line1, |
| Line2: a.Line2, |
| PhoneNumber: a.PhoneNumber, |
| }, |
| }), |
| } |
|
|
| if c.TaxCode != nil { |
| out.TaxId = &api.BillingPartyTaxIdentity{ |
| Code: c.TaxCode, |
| } |
| } |
|
|
| return out |
| } |
|
|
| func mapAlignmentToAPI(c billing.CollectionConfig) (*api.BillingWorkflowCollectionAlignment, error) { |
| apiAlignment := &api.BillingWorkflowCollectionAlignment{} |
|
|
| switch c.Alignment { |
| case billing.AlignmentKindSubscription: |
| if err := apiAlignment.FromBillingWorkflowCollectionAlignmentSubscription( |
| api.BillingWorkflowCollectionAlignmentSubscription{ |
| Type: api.BillingWorkflowCollectionAlignmentSubscriptionType(c.Alignment), |
| }, |
| ); err != nil { |
| return &api.BillingWorkflowCollectionAlignment{}, fmt.Errorf("failed to map alignment to API: %w", err) |
| } |
| case billing.AlignmentKindAnchored: |
| if c.AnchoredAlignmentDetail == nil { |
| return &api.BillingWorkflowCollectionAlignment{}, fmt.Errorf("anchored alignment detail is not set") |
| } |
|
|
| interval := api.RecurringPeriodInterval{} |
| if err := interval.FromRecurringPeriodInterval0(c.AnchoredAlignmentDetail.Interval.ISOString().String()); err != nil { |
| return &api.BillingWorkflowCollectionAlignment{}, fmt.Errorf("failed to map interval to API: %w", err) |
| } |
|
|
| if err := apiAlignment.FromBillingWorkflowCollectionAlignmentAnchored( |
| api.BillingWorkflowCollectionAlignmentAnchored{ |
| Type: api.BillingWorkflowCollectionAlignmentAnchoredType(c.Alignment), |
| RecurringPeriod: api.RecurringPeriodV2{ |
| Anchor: c.AnchoredAlignmentDetail.Anchor, |
| Interval: interval, |
| }, |
| }, |
| ); err != nil { |
| return &api.BillingWorkflowCollectionAlignment{}, fmt.Errorf("failed to map alignment to API: %w", err) |
| } |
| default: |
| return &api.BillingWorkflowCollectionAlignment{}, fmt.Errorf("invalid alignment: %s", c.Alignment) |
| } |
|
|
| return apiAlignment, nil |
| } |
|
|
| func mapWorkflowConfigToAPI(c billing.WorkflowConfig) (api.BillingWorkflow, error) { |
| apiAlignment, err := mapAlignmentToAPI(c.Collection) |
| if err != nil { |
| return api.BillingWorkflow{}, fmt.Errorf("failed to map alignment to API: %w", err) |
| } |
|
|
| return api.BillingWorkflow{ |
| Collection: &api.BillingWorkflowCollectionSettings{ |
| Alignment: apiAlignment, |
| Interval: lo.EmptyableToPtr(c.Collection.Interval.String()), |
| }, |
|
|
| Invoicing: &api.BillingWorkflowInvoicingSettings{ |
| AutoAdvance: lo.ToPtr(c.Invoicing.AutoAdvance), |
| DraftPeriod: lo.EmptyableToPtr(c.Invoicing.DraftPeriod.String()), |
| DueAfter: lo.EmptyableToPtr(c.Invoicing.DueAfter.String()), |
| ProgressiveBilling: lo.ToPtr(c.Invoicing.ProgressiveBilling), |
| SubscriptionEndProrationMode: lo.ToPtr(api.BillingWorkflowInvoicingSubscriptionEndProrationMode(c.Invoicing.SubscriptionEndProrationMode)), |
| DefaultTaxConfig: mapTaxConfigToAPI(c.Invoicing.DefaultTaxConfig), |
| }, |
|
|
| Payment: &api.BillingWorkflowPaymentSettings{ |
| CollectionMethod: (*api.CollectionMethod)(lo.EmptyableToPtr(string(c.Payment.CollectionMethod))), |
| }, |
|
|
| Tax: &api.BillingWorkflowTaxSettings{ |
| Enabled: lo.ToPtr(c.Tax.Enabled), |
| Enforced: lo.ToPtr(c.Tax.Enforced), |
| }, |
| }, nil |
| } |
|
|
| func mapWorkflowConfigSettingsToAPI(c billing.WorkflowConfig) (api.BillingWorkflow, error) { |
| apiAlignment, err := mapAlignmentToAPI(c.Collection) |
| if err != nil { |
| return api.BillingWorkflow{}, fmt.Errorf("failed to map alignment to API: %w", err) |
| } |
|
|
| return api.BillingWorkflow{ |
| Collection: &api.BillingWorkflowCollectionSettings{ |
| Alignment: apiAlignment, |
| Interval: lo.EmptyableToPtr(c.Collection.Interval.String()), |
| }, |
|
|
| Invoicing: &api.BillingWorkflowInvoicingSettings{ |
| AutoAdvance: lo.ToPtr(c.Invoicing.AutoAdvance), |
| DraftPeriod: lo.EmptyableToPtr(c.Invoicing.DraftPeriod.String()), |
| DueAfter: lo.EmptyableToPtr(c.Invoicing.DueAfter.String()), |
| ProgressiveBilling: lo.ToPtr(c.Invoicing.ProgressiveBilling), |
| SubscriptionEndProrationMode: lo.ToPtr(api.BillingWorkflowInvoicingSubscriptionEndProrationMode(c.Invoicing.SubscriptionEndProrationMode)), |
| DefaultTaxConfig: mapTaxConfigToAPI(c.Invoicing.DefaultTaxConfig), |
| }, |
|
|
| Payment: &api.BillingWorkflowPaymentSettings{ |
| CollectionMethod: (*api.CollectionMethod)(lo.EmptyableToPtr(string(c.Payment.CollectionMethod))), |
| }, |
|
|
| Tax: &api.BillingWorkflowTaxSettings{ |
| Enabled: lo.ToPtr(c.Tax.Enabled), |
| Enforced: lo.ToPtr(c.Tax.Enforced), |
| }, |
| }, nil |
| } |
|
|