Skip to content

Commit

Permalink
feat: store payment status
Browse files Browse the repository at this point in the history
  • Loading branch information
turip committed Jan 31, 2025
1 parent 2957794 commit 12d8d32
Show file tree
Hide file tree
Showing 43 changed files with 1,192 additions and 73 deletions.
9 changes: 5 additions & 4 deletions app/common/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func NewAppService(logger *slog.Logger, db *entdb.Client, appsConfig config.Apps
})
}

func NewAppStripeService(logger *slog.Logger, db *entdb.Client, appsConfig config.AppsConfiguration, appService app.Service, customerService customer.Service, secretService secret.Service) (appstripe.Service, error) {
func NewAppStripeService(logger *slog.Logger, db *entdb.Client, appsConfig config.AppsConfiguration, appService app.Service, customerService customer.Service, secretService secret.Service, billingService billing.Service) (appstripe.Service, error) {
// TODO: remove this check after enabled by default
if !appsConfig.Enabled || db == nil {
return nil, nil
Expand All @@ -66,9 +66,10 @@ func NewAppStripeService(logger *slog.Logger, db *entdb.Client, appsConfig confi
}

return appstripeservice.New(appstripeservice.Config{
Adapter: appStripeAdapter,
AppService: appService,
SecretService: secretService,
Adapter: appStripeAdapter,
AppService: appService,
SecretService: secretService,
BillingService: billingService,
})
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/billing-worker/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions cmd/jobs/internal/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions cmd/server/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions openmeter/app/stripe/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package appstripe
import (
"context"

"github.com/stripe/stripe-go/v80"

"github.com/openmeterio/openmeter/openmeter/app/stripe/client"
appstripeentity "github.com/openmeterio/openmeter/openmeter/app/stripe/entity"
"github.com/openmeterio/openmeter/openmeter/billing"
Expand Down Expand Up @@ -30,6 +32,7 @@ type AppStripeAdapter interface {
DeleteStripeAppData(ctx context.Context, input appstripeentity.DeleteStripeAppDataInput) error
// Billing
GetSupplierContact(ctx context.Context, input appstripeentity.GetSupplierContactInput) (billing.SupplierContact, error)
GetStripeInvoice(ctx context.Context, input appstripeentity.GetStripeInvoiceInput) (*stripe.Invoice, error)
// Customer
GetStripeCustomerData(ctx context.Context, input appstripeentity.GetStripeCustomerDataInput) (appstripeentity.CustomerData, error)
UpsertStripeCustomerData(ctx context.Context, input appstripeentity.UpsertStripeCustomerDataInput) error
Expand Down
21 changes: 21 additions & 0 deletions openmeter/app/stripe/adapter/stripe.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"

"github.com/samber/lo"
"github.com/stripe/stripe-go/v80"

"github.com/openmeterio/openmeter/openmeter/app"
appentity "github.com/openmeterio/openmeter/openmeter/app/entity"
Expand Down Expand Up @@ -589,6 +590,26 @@ func (a adapter) GetSupplierContact(ctx context.Context, input appstripeentity.G
return supplierContact, nil
}

func (a adapter) GetStripeInvoice(ctx context.Context, input appstripeentity.GetStripeInvoiceInput) (*stripe.Invoice, error) {
// Validate input
if err := input.Validate(); err != nil {
return nil, app.ValidationError{
Err: fmt.Errorf("error validate input: %w", err),
}
}

// Get Stripe App client
_, stripeAppClient, err := a.getStripeAppClient(ctx, input.AppID)
if err != nil {
return nil, fmt.Errorf("failed to get stripe app client: %w", err)
}

// Get the invoice
return stripeAppClient.GetInvoice(ctx, stripeclient.GetInvoiceInput{
StripeInvoiceID: input.StripeInvoiceID,
})
}

// GetMaskedSecretAPIKey returns a masked secret API key
func (a adapter) GetMaskedSecretAPIKey(secretAPIKeyID secretentity.SecretID) (string, error) {
// Validate input
Expand Down
1 change: 1 addition & 0 deletions openmeter/app/stripe/client/appclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type StripeAppClient interface {
CreateCheckoutSession(ctx context.Context, input CreateCheckoutSessionInput) (StripeCheckoutSession, error)
GetPaymentMethod(ctx context.Context, stripePaymentMethodID string) (StripePaymentMethod, error)
// Invoice
GetInvoice(ctx context.Context, input GetInvoiceInput) (*stripe.Invoice, error)
CreateInvoice(ctx context.Context, input CreateInvoiceInput) (*stripe.Invoice, error)
UpdateInvoice(ctx context.Context, input UpdateInvoiceInput) (*stripe.Invoice, error)
DeleteInvoice(ctx context.Context, input DeleteInvoiceInput) error
Expand Down
22 changes: 22 additions & 0 deletions openmeter/app/stripe/client/invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ func (c *stripeAppClient) FinalizeInvoice(ctx context.Context, input FinalizeInv
})
}

// GetInvoice gets an invoice from Stripe.
func (c *stripeAppClient) GetInvoice(ctx context.Context, input GetInvoiceInput) (*stripe.Invoice, error) {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("stripe get invoice: invalid input: %w", err)
}

return c.client.Invoices.Get(input.StripeInvoiceID, nil)
}

// CreateInvoiceInput is the input for creating a new invoice in Stripe.
type CreateInvoiceInput struct {
StripeCustomerID string
Expand Down Expand Up @@ -161,3 +170,16 @@ func (i FinalizeInvoiceInput) Validate() error {

return nil
}

// GetInvoice gets an invoice from Stripe.
type GetInvoiceInput struct {
StripeInvoiceID string
}

func (i GetInvoiceInput) Validate() error {
if i.StripeInvoiceID == "" {
return errors.New("stripe invoice id is required")
}

return nil
}
92 changes: 92 additions & 0 deletions openmeter/app/stripe/entity/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/openmeterio/openmeter/api"
appentity "github.com/openmeterio/openmeter/openmeter/app/entity"
appentitybase "github.com/openmeterio/openmeter/openmeter/app/entity/base"
"github.com/openmeterio/openmeter/openmeter/billing"
customerentity "github.com/openmeterio/openmeter/openmeter/customer/entity"
secretentity "github.com/openmeterio/openmeter/openmeter/secret/entity"
)
Expand Down Expand Up @@ -448,3 +449,94 @@ func (i GetSupplierContactInput) Validate() error {

return nil
}

type ValidationErrorsInput struct {
Op billing.InvoiceOperation
Errors []*stripe.Error
}

type HandleInvoiceStateTransitionInput struct {
AppID appentitybase.AppID
Invoice stripe.Invoice
Event *stripe.Event

// Trigger setup

// Trigger is the state machine trigger that will be used to transition the invoice
Trigger billing.InvoiceTrigger // TODO: Type?
// TargetStatus specifies the expected status of the invoice after the transition, needed to filter
// for duplicate events as the state machine doesn't allow transition into the same state
TargetStatus billing.InvoiceStatus

// Event filtering

// IgnoreInvoiceInStatus is a list of invoice statuses. If the invoice is in this status we ignore the event
// this allows to filter for out of order events.
IgnoreInvoiceInStatus []billing.InvoiceStatusMatcher
// ShouldTriggerOnEvent gets the *current* stripe invoice and returns true if the state machine should be triggered
// useful for filtering late events based on the current state (optional)
ShouldTriggerOnEvent func(*stripe.Invoice) (bool, error)

// Validation errors
// GetValidationErrors is invoked with the current stripe invoice and returns the validation errors if any
GetValidationErrors func(*stripe.Invoice) (*ValidationErrorsInput, error)
}

func (i HandleInvoiceStateTransitionInput) Validate() error {
if err := i.AppID.Validate(); err != nil {
return fmt.Errorf("error validating app id: %w", err)
}

if i.Event == nil {
return errors.New("event is required")
}

if i.Invoice.ID == "" {
return errors.New("invoice id is required")
}

if i.Trigger == nil {
return errors.New("trigger is required")
}

return nil
}

type HandleInvoiceSentEventInput struct {
AppID appentitybase.AppID
Invoice stripe.Invoice
SentAt int64
}

func (i HandleInvoiceSentEventInput) Validate() error {
if err := i.AppID.Validate(); err != nil {
return fmt.Errorf("error validating app id: %w", err)
}

if i.Invoice.ID == "" {
return errors.New("invoice id is required")
}

if i.SentAt == 0 {
return errors.New("sent at is required")
}

return nil
}

type GetStripeInvoiceInput struct {
AppID appentitybase.AppID
StripeInvoiceID string
}

func (i GetStripeInvoiceInput) Validate() error {
if err := i.AppID.Validate(); err != nil {
return fmt.Errorf("error validating app id: %w", err)
}

if i.StripeInvoiceID == "" {
return errors.New("stripe invoice id is required")
}

return nil
}
9 changes: 9 additions & 0 deletions openmeter/app/stripe/httpdriver/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package httpdriver

type StripeLogAttributeName string

const (
StripeEventIDAttributeName StripeLogAttributeName = "stripe_event_id"
StripeEventTypeAttributeName StripeLogAttributeName = "stripe_event_type"
AppIDAttributeName StripeLogAttributeName = "app_id"
)
Loading

0 comments on commit 12d8d32

Please sign in to comment.