| package service |
|
|
| import ( |
| "context" |
| "fmt" |
| "log/slog" |
| "time" |
|
|
| "go.opentelemetry.io/otel/trace" |
|
|
| "github.com/openmeterio/openmeter/openmeter/billing" |
| "github.com/openmeterio/openmeter/openmeter/billing/charges" |
| "github.com/openmeterio/openmeter/openmeter/billing/worker/subscriptionsync" |
| "github.com/openmeterio/openmeter/openmeter/billing/worker/subscriptionsync/service/reconciler" |
| "github.com/openmeterio/openmeter/openmeter/subscription" |
| "github.com/openmeterio/openmeter/pkg/featuregate" |
| "github.com/openmeterio/openmeter/pkg/framework/transaction" |
| "github.com/openmeterio/openmeter/pkg/models" |
| ) |
|
|
| type FeatureFlags struct { |
| EnableFlatFeeInAdvanceProrating bool |
| EnableFlatFeeInArrearsProrating bool |
| EnableCreditThenInvoice bool |
| MaxLinesPerCollectedInvoice int |
| } |
|
|
| type Config struct { |
| BillingService billing.Service |
| |
| ChargesService charges.Service |
| SubscriptionService subscription.Service |
| SubscriptionSyncAdapter subscriptionsync.Adapter |
| FeatureFlags FeatureFlags |
| ForceAsyncInvoicePendingLines bool |
| Logger *slog.Logger |
| Tracer trace.Tracer |
| FeatureGate *featuregate.FeatureGateChecker |
| } |
|
|
| func (c Config) Validate() error { |
| if c.BillingService == nil { |
| return fmt.Errorf("billing service is required") |
| } |
|
|
| if c.SubscriptionService == nil { |
| return fmt.Errorf("subscription service is required") |
| } |
|
|
| if c.SubscriptionSyncAdapter == nil { |
| return fmt.Errorf("subscription sync adapter is required") |
| } |
|
|
| if c.Logger == nil { |
| return fmt.Errorf("logger is required") |
| } |
|
|
| if c.Tracer == nil { |
| return fmt.Errorf("tracer is required") |
| } |
|
|
| if err := c.FeatureGate.Validate(); err != nil { |
| return err |
| } |
|
|
| return nil |
| } |
|
|
| var _ subscriptionsync.Service = (*Service)(nil) |
|
|
| type Service struct { |
| billingService billing.Service |
| chargesService charges.Service |
| reconciler reconciler.Reconciler |
| subscriptionService subscription.Service |
| subscriptionSyncAdapter subscriptionsync.Adapter |
| featureFlags FeatureFlags |
| forceAsyncInvoicePendingLines bool |
| logger *slog.Logger |
| tracer trace.Tracer |
| } |
|
|
| func New(config Config) (*Service, error) { |
| if err := config.Validate(); err != nil { |
| return nil, err |
| } |
| reconcilerSvc, err := reconciler.New(reconciler.Config{ |
| BillingService: config.BillingService, |
| ChargesService: config.ChargesService, |
| EnableCreditThenInvoice: config.FeatureFlags.EnableCreditThenInvoice, |
| Logger: config.Logger, |
| FeatureGate: config.FeatureGate, |
| }) |
| if err != nil { |
| return nil, err |
| } |
| return &Service{ |
| billingService: config.BillingService, |
| chargesService: config.ChargesService, |
| reconciler: reconcilerSvc, |
| subscriptionSyncAdapter: config.SubscriptionSyncAdapter, |
| featureFlags: config.FeatureFlags, |
| forceAsyncInvoicePendingLines: config.ForceAsyncInvoicePendingLines, |
| subscriptionService: config.SubscriptionService, |
| logger: config.Logger, |
| tracer: config.Tracer, |
| }, nil |
| } |
|
|
| func (s *Service) GetSyncStates(ctx context.Context, input subscriptionsync.GetSyncStatesInput) ([]subscriptionsync.SyncState, error) { |
| return transaction.Run(ctx, s.subscriptionSyncAdapter, func(ctx context.Context) ([]subscriptionsync.SyncState, error) { |
| return s.subscriptionSyncAdapter.GetSyncStates(ctx, input) |
| }) |
| } |
|
|
| func (s *Service) SyncByViewAndInvoiceCustomer(ctx context.Context, view subscription.SubscriptionView, asOf time.Time) error { |
| return s.synchronizeSubscriptionAndInvoiceCustomer(ctx, newSubscriptionReferenceOrView(view), asOf) |
| } |
|
|
| func (s *Service) SyncByIDAndInvoiceCustomer(ctx context.Context, subscriptionID models.NamespacedID, asOf time.Time) error { |
| return s.synchronizeSubscriptionAndInvoiceCustomer(ctx, newSubscriptionReferenceOrView(subscriptionID), asOf) |
| } |
|
|
| func (s *Service) SyncByView(ctx context.Context, view subscription.SubscriptionView, asOf time.Time, opts ...subscriptionsync.SynchronizeSubscriptionOption) error { |
| _, err := s.synchronizeSubscription(ctx, newSubscriptionReferenceOrView(view), asOf, opts...) |
| return err |
| } |
|
|
| func (s *Service) SyncByID(ctx context.Context, subscriptionID models.NamespacedID, asOf time.Time, opts ...subscriptionsync.SynchronizeSubscriptionOption) error { |
| _, err := s.synchronizeSubscription(ctx, newSubscriptionReferenceOrView(subscriptionID), asOf, opts...) |
| return err |
| } |
|
|