subscription

package
v1.0.0-beta.201 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2025 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventSubsystem metadata.EventSubsystem = "subscription"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AlignmentError

type AlignmentError struct {
	Inner error
}

AlignmentError is an error that occurs when the spec is not aligned but we expect it to be.

func (AlignmentError) Error

func (e AlignmentError) Error() string

func (AlignmentError) Unwrap

func (e AlignmentError) Unwrap() error

type AllowedDuringApplyingPatchesError

type AllowedDuringApplyingPatchesError struct {
	Inner error
}

Some errors are allowed during applying individual patches, but still mean the Spec as a whole is invalid

func (*AllowedDuringApplyingPatchesError) Error

func (*AllowedDuringApplyingPatchesError) Unwrap

type AnyValuePatch

type AnyValuePatch interface {
	ValueAsAny() any
}

type Applies

type Applies interface {
	ApplyTo(spec *SubscriptionSpec, actx ApplyContext) error
}

Each Patch applies its changes to the SubscriptionSpec.

func ToApplies

func ToApplies(p Patch, _ int) Applies

type ApplyContext

type ApplyContext struct {
	CurrentTime time.Time
}

type BillingBehaviorOverride

type BillingBehaviorOverride struct {
	// If true, the billing cadence will be restarted
	// The anchor time will be the time the originating change takes effect,
	// which in practive translates to a SubscriptionItem's ActiveFrom property.
	RestartBillingPeriod *bool `json:"restartBillingPeriod,omitempty"`
}

type CancelledEvent

type CancelledEvent viewEvent

func (CancelledEvent) EventMetadata

func (s CancelledEvent) EventMetadata() metadata.EventMetadata

func (CancelledEvent) EventName

func (s CancelledEvent) EventName() string

func (CancelledEvent) Validate

func (s CancelledEvent) Validate() error

type ChangeSubscriptionWorkflowInput

type ChangeSubscriptionWorkflowInput struct {
	Timing
	models.AnnotatedModel
	Name        string
	Description *string
}

type ContinuedEvent

type ContinuedEvent viewEvent

func (ContinuedEvent) EventMetadata

func (s ContinuedEvent) EventMetadata() metadata.EventMetadata

func (ContinuedEvent) EventName

func (s ContinuedEvent) EventName() string

func (ContinuedEvent) Validate

func (s ContinuedEvent) Validate() error

type CreateSubscriptionCustomerInput

type CreateSubscriptionCustomerInput struct {
	models.AnnotatedModel `json:",inline"`
	Name                  string         `json:"name"`
	Description           *string        `json:"description,omitempty"`
	CustomerId            string         `json:"customerId"`
	Currency              currencyx.Code `json:"currency"`
	ActiveFrom            time.Time      `json:"activeFrom,omitempty"`
	ActiveTo              *time.Time     `json:"activeTo,omitempty"`
}

type CreateSubscriptionEntityInput

type CreateSubscriptionEntityInput struct {
	models.CadencedModel
	models.NamespacedModel
	models.AnnotatedModel

	productcatalog.Alignment

	Plan        *PlanRef
	Name        string  `json:"name,omitempty"`
	Description *string `json:"description,omitempty"`

	CustomerId string `json:"customerId,omitempty"`
	Currency   currencyx.Code
}

type CreateSubscriptionItemCustomerInput

type CreateSubscriptionItemCustomerInput struct {
	ActiveFromOverrideRelativeToPhaseStart *isodate.Period `json:"activeFromOverrideRelativeToPhaseStart"`
	ActiveToOverrideRelativeToPhaseStart   *isodate.Period `json:"activeToOverrideRelativeToPhaseStart,omitempty"`
	BillingBehaviorOverride
}

type CreateSubscriptionItemEntityInput

type CreateSubscriptionItemEntityInput struct {
	models.NamespacedModel
	models.AnnotatedModel

	ActiveFromOverrideRelativeToPhaseStart *isodate.Period
	ActiveToOverrideRelativeToPhaseStart   *isodate.Period

	models.CadencedModel

	BillingBehaviorOverride BillingBehaviorOverride

	// PhaseID is the ID of the phase this item belongs to.
	PhaseID string

	// Key is the unique key of the item in the phase.
	Key string

	RateCard RateCard

	EntitlementID *string
	Name          string  `json:"name,omitempty"`
	Description   *string `json:"description,omitempty"`
}

func (CreateSubscriptionItemEntityInput) Equal

type CreateSubscriptionItemInput

type CreateSubscriptionItemInput struct {
	CreateSubscriptionItemPlanInput     `json:",inline"`
	CreateSubscriptionItemCustomerInput `json:",inline"`
}

type CreateSubscriptionItemPlanInput

type CreateSubscriptionItemPlanInput struct {
	PhaseKey string   `json:"phaseKey"`
	ItemKey  string   `json:"itemKey"`
	RateCard RateCard `json:"rateCard"`
}

type CreateSubscriptionPhaseCustomerInput

type CreateSubscriptionPhaseCustomerInput struct {
	models.AnnotatedModel `json:",inline"`
}

type CreateSubscriptionPhaseEntityInput

type CreateSubscriptionPhaseEntityInput struct {
	models.NamespacedModel
	models.AnnotatedModel

	// ActiveFrom is the time the phase becomes active.
	ActiveFrom time.Time

	// SubscriptionID is the ID of the subscription this phase belongs to.
	SubscriptionID string `json:"subscriptionId"`

	// Key is the unique key for Phase.
	Key string `json:"key"`

	// Name
	Name string `json:"name"`

	// Description
	Description *string `json:"description,omitempty"`

	// StartAfter
	StartAfter isodate.Period `json:"interval"`
}

func (CreateSubscriptionPhaseEntityInput) Equal

type CreateSubscriptionPhaseInput

type CreateSubscriptionPhaseInput struct {
	// Duration is required exactly in cases where the phase wouldn't be the last phase.
	Duration *isodate.Period `json:"duration"`
	CreateSubscriptionPhasePlanInput
	CreateSubscriptionPhaseCustomerInput
}

func (CreateSubscriptionPhaseInput) Validate

func (i CreateSubscriptionPhaseInput) Validate() error

type CreateSubscriptionPhasePlanInput

type CreateSubscriptionPhasePlanInput struct {
	PhaseKey    string         `json:"key"`
	StartAfter  isodate.Period `json:"startAfter"`
	Name        string         `json:"name"`
	Description *string        `json:"description,omitempty"`
}

func (CreateSubscriptionPhasePlanInput) Validate

type CreateSubscriptionPlanInput

type CreateSubscriptionPlanInput struct {
	Plan *PlanRef `json:"plan"`
	productcatalog.Alignment
}

type CreateSubscriptionWorkflowInput

type CreateSubscriptionWorkflowInput struct {
	ChangeSubscriptionWorkflowInput
	Namespace  string
	CustomerID string
}

type CreatedEvent

type CreatedEvent viewEvent

func (CreatedEvent) EventMetadata

func (s CreatedEvent) EventMetadata() metadata.EventMetadata

func (CreatedEvent) EventName

func (s CreatedEvent) EventName() string

func (CreatedEvent) Validate

func (s CreatedEvent) Validate() error

type DeletedEvent

type DeletedEvent viewEvent

func (DeletedEvent) EventMetadata

func (s DeletedEvent) EventMetadata() metadata.EventMetadata

func (DeletedEvent) EventName

func (s DeletedEvent) EventName() string

func (DeletedEvent) Validate

func (s DeletedEvent) Validate() error

type EntitlementAdapter

type EntitlementAdapter interface {
	ScheduleEntitlement(ctx context.Context, input ScheduleSubscriptionEntitlementInput) (*SubscriptionEntitlement, error)
	// At refers to a point in time for which we're querying the system state, meaning:
	// if t1 < t2 < t3, and some entitlement was deleted effective at t2, then
	// with at = t1 the entitlement will be returned, while with at = t3 it won't.
	GetForSubscriptionAt(ctx context.Context, subscriptionID models.NamespacedID, at time.Time) ([]SubscriptionEntitlement, error)

	DeleteByItemID(ctx context.Context, itemId models.NamespacedID) error
}

type ForbiddenError

type ForbiddenError struct {
	Msg string
}

func (*ForbiddenError) Error

func (e *ForbiddenError) Error() string

type ItemNotFoundError

type ItemNotFoundError struct {
	ID string
}

func (*ItemNotFoundError) Error

func (e *ItemNotFoundError) Error() string

type ListSubscriptionsInput

type ListSubscriptionsInput struct {
	pagination.Page

	Namespaces []string
	Customers  []string
	ActiveAt   *time.Time
}

func (ListSubscriptionsInput) Validate

func (i ListSubscriptionsInput) Validate() error

type NoBillingPeriodError

type NoBillingPeriodError struct {
	Inner error
}

NoBillingPeriodError is an error that occurs when a phase has no billing period.

func (NoBillingPeriodError) Error

func (e NoBillingPeriodError) Error() string

func (NoBillingPeriodError) Unwrap

func (e NoBillingPeriodError) Unwrap() error

type NoOpSubscriptionValidator

type NoOpSubscriptionValidator struct{}

func (NoOpSubscriptionValidator) ValidateCancel

func (NoOpSubscriptionValidator) ValidateContinue

func (NoOpSubscriptionValidator) ValidateCreate

func (NoOpSubscriptionValidator) ValidateDelete

func (NoOpSubscriptionValidator) ValidateUpdate

type NotFoundError

type NotFoundError struct {
	ID         string
	CustomerID string
}

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type Patch

type Patch interface {
	json.Marshaler
	Applies
	Validate() error
	Op() PatchOperation
	Path() PatchPath
}

type PatchConflictError

type PatchConflictError struct {
	Msg string
}

func (*PatchConflictError) Error

func (e *PatchConflictError) Error() string

type PatchForbiddenError

type PatchForbiddenError struct {
	Msg string
}

func (*PatchForbiddenError) Error

func (e *PatchForbiddenError) Error() string

type PatchOperation

type PatchOperation string
const (
	PatchOperationAdd        PatchOperation = "add"
	PatchOperationRemove     PatchOperation = "remove"
	PatchOperationUnschedule PatchOperation = "unschedule"
	PatchOperationStretch    PatchOperation = "stretch"
)

func (PatchOperation) Validate

func (o PatchOperation) Validate() error

type PatchPath

type PatchPath string

func NewItemPath

func NewItemPath(phaseKey, itemKey string) PatchPath

func NewPhasePath

func NewPhasePath(phaseKey string) PatchPath

func (PatchPath) IsParentOf

func (p PatchPath) IsParentOf(other PatchPath) bool

Checks whether p is a parent of other where parent means all segments of p are present and in order in other

func (PatchPath) ItemKey

func (p PatchPath) ItemKey() string

func (PatchPath) MarshalJSON

func (p PatchPath) MarshalJSON() ([]byte, error)

Lets implement JSON Marshaler for Path

func (PatchPath) PhaseKey

func (p PatchPath) PhaseKey() string

func (PatchPath) Type

func (p PatchPath) Type() PatchPathType

func (*PatchPath) UnmarshalJSON

func (p *PatchPath) UnmarshalJSON(data []byte) error

Lets implement JSON Unmarshaler for Path

func (PatchPath) Validate

func (p PatchPath) Validate() error

Lets implement validation for Path

type PatchPathType

type PatchPathType string
const (
	PatchPathTypePhase PatchPathType = "phase"
	PatchPathTypeItem  PatchPathType = "item"
)

type PatchValidationError

type PatchValidationError struct {
	Msg string
}

func (*PatchValidationError) Error

func (e *PatchValidationError) Error() string

type PhaseNotFoundError

type PhaseNotFoundError struct {
	ID string
}

func (*PhaseNotFoundError) Error

func (e *PhaseNotFoundError) Error() string

type Plan

type Plan interface {
	ToCreateSubscriptionPlanInput() CreateSubscriptionPlanInput

	GetName() string

	// Phases are expected to be returned in the order they activate.
	GetPhases() []PlanPhase

	// Will not make sense on the long term
	Currency() currencyx.Code
}

All methods are expected to return stable values.

type PlanNotFoundError

type PlanNotFoundError struct {
	Key     string
	Version int
}

func (PlanNotFoundError) Error

func (e PlanNotFoundError) Error() string

type PlanPhase

type PlanPhase interface {
	ToCreateSubscriptionPhasePlanInput() CreateSubscriptionPhasePlanInput
	GetRateCards() []PlanRateCard
	GetKey() string
}

All methods are expected to return stable values.

type PlanRateCard

type PlanRateCard interface {
	ToCreateSubscriptionItemPlanInput() CreateSubscriptionItemPlanInput
	GetKey() string
}

All methods are expected to return stable values.

type PlanRef

type PlanRef struct {
	Id      string `json:"id"`
	Key     string `json:"key"`
	Version int    `json:"version"`
}

func (PlanRef) Equal

func (p PlanRef) Equal(p2 PlanRef) bool

func (*PlanRef) NilEqual

func (p *PlanRef) NilEqual(p2 *PlanRef) bool

type RateCard

type RateCard struct {
	// Name of the RateCard
	Name string `json:"name"`

	// Description for the RateCard
	Description *string `json:"description,omitempty"`

	// Feature defines optional Feature assigned to RateCard
	FeatureKey *string `json:"featureKey,omitempty"`

	// EntitlementTemplate defines the template used for instantiating entitlement.Entitlement.
	// If Feature is set then template must be provided as well.
	EntitlementTemplate *productcatalog.EntitlementTemplate `json:"entitlementTemplate,omitempty"`

	// TaxConfig defines provider specific tax information.
	TaxConfig *productcatalog.TaxConfig `json:"taxConfig,omitempty"`

	// Price defines the price for the RateCard
	Price *productcatalog.Price `json:"price,omitempty"`

	// BillingCadence defines the billing cadence of the RateCard in ISO8601 format.
	// Example: "P1D12H"
	BillingCadence *isodate.Period `json:"billingCadence,omitempty"`
}

RateCard is a local implementation of plan.RateCard until productcatalog models are available TODO: extract ProductCatalog models and use them, doing it like this is a mess....

func (RateCard) Equal

func (r RateCard) Equal(other RateCard) bool

func (RateCard) Validate

func (r RateCard) Validate() error

TODO: these should live on actual RateCard model once it exists

type RemoveSubscriptionPhaseInput

type RemoveSubscriptionPhaseInput struct {
	Shift RemoveSubscriptionPhaseShifting `json:"shift"`
}

type RemoveSubscriptionPhaseShifting

type RemoveSubscriptionPhaseShifting int
const (
	RemoveSubscriptionPhaseShiftNext RemoveSubscriptionPhaseShifting = iota
	RemoveSubscriptionPhaseShiftPrev
)

func (RemoveSubscriptionPhaseShifting) Validate

type ScheduleSubscriptionEntitlementInput

type ScheduleSubscriptionEntitlementInput struct {
	entitlement.CreateEntitlementInputs
}

func (ScheduleSubscriptionEntitlementInput) Equal

func (ScheduleSubscriptionEntitlementInput) Validate

type Service

type Service interface {
	// Create a new subscription accotding to the given spec
	Create(ctx context.Context, namespace string, spec SubscriptionSpec) (Subscription, error)
	// Update the subscription with the given ID to the target spec
	Update(ctx context.Context, subscriptionID models.NamespacedID, target SubscriptionSpec) (Subscription, error)
	// Delete a scheduled subscription with the given ID
	Delete(ctx context.Context, subscriptionID models.NamespacedID) error
	// Cancel a running subscription at the provided time
	Cancel(ctx context.Context, subscriptionID models.NamespacedID, timing Timing) (Subscription, error)
	// Continue a canceled subscription (effectively undoing the cancellation)
	Continue(ctx context.Context, subscriptionID models.NamespacedID) (Subscription, error)
	// Get the subscription with the given ID
	Get(ctx context.Context, subscriptionID models.NamespacedID) (Subscription, error)
	// GetView returns a full view of the subscription with the given ID
	GetView(ctx context.Context, subscriptionID models.NamespacedID) (SubscriptionView, error)
	// List lists the subscriptions matching the set criteria
	List(ctx context.Context, params ListSubscriptionsInput) (SubscriptionList, error)
}

type SpecValidationError

type SpecValidationError struct {
	AffectedKeys [][]string
	Msg          string
}

func (*SpecValidationError) Error

func (e *SpecValidationError) Error() string

type Subscription

type Subscription struct {
	models.NamespacedID
	models.ManagedModel
	models.CadencedModel
	models.AnnotatedModel

	productcatalog.Alignment

	Name        string  `json:"name,omitempty"`
	Description *string `json:"description,omitempty"`

	// References the plan (if the Subscription was created form one)
	PlanRef *PlanRef `json:"planRef"`

	CustomerId string         `json:"customerId,omitempty"`
	Currency   currencyx.Code `json:"currency,omitempty"`
}

func (Subscription) AsEntityInput

func (s Subscription) AsEntityInput() CreateSubscriptionEntityInput

func (Subscription) GetStatusAt

func (s Subscription) GetStatusAt(at time.Time) SubscriptionStatus

type SubscriptionAction

type SubscriptionAction string
const (
	SubscriptionActionCreate   SubscriptionAction = "create"
	SubscriptionActionUpdate   SubscriptionAction = "update"
	SubscriptionActionCancel   SubscriptionAction = "cancel"
	SubscriptionActionContinue SubscriptionAction = "continue"
	SubscriptionActionDelete   SubscriptionAction = "delete"
)

type SubscriptionEntitlement

type SubscriptionEntitlement struct {
	Entitlement entitlement.Entitlement
	Cadence     models.CadencedModel
}

func (SubscriptionEntitlement) ToScheduleSubscriptionEntitlementInput

func (s SubscriptionEntitlement) ToScheduleSubscriptionEntitlementInput() ScheduleSubscriptionEntitlementInput

func (SubscriptionEntitlement) Validate

func (s SubscriptionEntitlement) Validate() error

type SubscriptionItem

type SubscriptionItem struct {
	models.NamespacedID   `json:",inline"`
	models.ManagedModel   `json:",inline"`
	models.AnnotatedModel `json:",inline"`

	// SubscriptionItem doesn't have a separate Cadence, only one relative to the phase, denoting if it's intentionally different from the phase's cadence.
	// The durations are relative to phase start.
	ActiveFromOverrideRelativeToPhaseStart *isodate.Period `json:"activeFromOverrideRelativeToPhaseStart,omitempty"`
	ActiveToOverrideRelativeToPhaseStart   *isodate.Period `json:"activeToOverrideRelativeToPhaseStart,omitempty"`

	// The defacto cadence of the item is calculated and persisted after each change.
	models.CadencedModel `json:",inline"`

	BillingBehaviorOverride BillingBehaviorOverride `json:"billingBehaviorOverride"`

	// SubscriptionID is the ID of the subscription this item belongs to.
	SubscriptionId string `json:"subscriptionId"`
	// PhaseID is the ID of the phase this item belongs to.
	PhaseId string `json:"phaseId"`
	// Key is the unique key of the item in the phase.
	Key string `json:"itemKey"`

	RateCard RateCard `json:"rateCard"`

	EntitlementID *string `json:"entitlementId,omitempty"`
	// Name
	Name string `json:"name"`

	// Description
	Description *string `json:"description,omitempty"`
}

func (SubscriptionItem) AsEntityInput

func (SubscriptionItem) GetCadence

func (i SubscriptionItem) GetCadence(phaseCadence models.CadencedModel) models.CadencedModel

type SubscriptionItemRef

type SubscriptionItemRef struct {
	SubscriptionId string `json:"subscriptionId"`
	PhaseKey       string `json:"phaseKey"`
	ItemKey        string `json:"itemKey"`
}

SubscriptionItemRef is an unstable reference to a SubscriptionItem

func (SubscriptionItemRef) Equals

type SubscriptionItemRepository

type SubscriptionItemRepository interface {
	entutils.TxCreator

	GetForSubscriptionAt(ctx context.Context, subscriptionID models.NamespacedID, at time.Time) ([]SubscriptionItem, error)

	Create(ctx context.Context, input CreateSubscriptionItemEntityInput) (SubscriptionItem, error)
	Delete(ctx context.Context, id models.NamespacedID) error
	GetByID(ctx context.Context, id models.NamespacedID) (SubscriptionItem, error)
}

type SubscriptionItemSpec

type SubscriptionItemSpec struct {
	CreateSubscriptionItemInput `json:",inline"`
}

func (SubscriptionItemSpec) GetCadence

func (s SubscriptionItemSpec) GetCadence(phaseCadence models.CadencedModel) models.CadencedModel

func (SubscriptionItemSpec) GetRef

func (SubscriptionItemSpec) ToCreateSubscriptionItemEntityInput

func (s SubscriptionItemSpec) ToCreateSubscriptionItemEntityInput(
	phaseID models.NamespacedID,
	phaseCadence models.CadencedModel,
	entitlement *entitlement.Entitlement,
) (CreateSubscriptionItemEntityInput, error)

func (SubscriptionItemSpec) ToScheduleSubscriptionEntitlementInput

func (s SubscriptionItemSpec) ToScheduleSubscriptionEntitlementInput(
	cust customer.Customer,
	cadence models.CadencedModel,
) (ScheduleSubscriptionEntitlementInput, bool, error)

func (*SubscriptionItemSpec) Validate

func (s *SubscriptionItemSpec) Validate() error

type SubscriptionItemView

type SubscriptionItemView struct {
	SubscriptionItem SubscriptionItem     `json:"subscriptionItem"`
	Spec             SubscriptionItemSpec `json:"spec"`

	Entitlement *SubscriptionEntitlement `json:"entitlement,omitempty"`
}

func (*SubscriptionItemView) AsSpec

func (*SubscriptionItemView) Validate

func (s *SubscriptionItemView) Validate() error

type SubscriptionList

type SubscriptionList = pagination.PagedResponse[Subscription]

type SubscriptionPhase

type SubscriptionPhase struct {
	models.NamespacedID   `json:",inline"`
	models.ManagedModel   `json:",inline"`
	models.AnnotatedModel `json:",inline"`

	ActiveFrom time.Time `json:"activeFrom"`

	// SubscriptionID is the ID of the subscription this phase belongs to.
	SubscriptionID string `json:"subscriptionId"`

	// Key is the unique key for Phase.
	Key string `json:"key"`

	// Name
	Name string `json:"name"`

	// Description
	Description *string `json:"description,omitempty"`
}

type SubscriptionPhaseRepository

type SubscriptionPhaseRepository interface {
	entutils.TxCreator

	// Returns the phases for a subscription
	GetForSubscriptionAt(ctx context.Context, subscriptionID models.NamespacedID, at time.Time) ([]SubscriptionPhase, error)

	// Create a new subscription phase
	Create(ctx context.Context, input CreateSubscriptionPhaseEntityInput) (SubscriptionPhase, error)
	Delete(ctx context.Context, id models.NamespacedID) error
}

type SubscriptionPhaseSpec

type SubscriptionPhaseSpec struct {
	// Duration is not part of the Spec by design
	CreateSubscriptionPhasePlanInput     `json:",inline"`
	CreateSubscriptionPhaseCustomerInput `json:",inline"`

	// In each key, for each phase, we have a list of item specs to account for mid-phase changes
	ItemsByKey map[string][]*SubscriptionItemSpec `json:"itemsByKey"`
}

func (SubscriptionPhaseSpec) GetBillableItemsByKey

func (s SubscriptionPhaseSpec) GetBillableItemsByKey() map[string][]*SubscriptionItemSpec

GetBillableItemsByKey returns a map of billable items by key

func (SubscriptionPhaseSpec) GetBillingCadence

func (s SubscriptionPhaseSpec) GetBillingCadence() (isodate.Period, error)

func (SubscriptionPhaseSpec) HasBillables

func (s SubscriptionPhaseSpec) HasBillables() bool

func (SubscriptionPhaseSpec) ToCreateSubscriptionPhaseEntityInput

func (s SubscriptionPhaseSpec) ToCreateSubscriptionPhaseEntityInput(
	subscription Subscription,
	activeFrom time.Time,
) CreateSubscriptionPhaseEntityInput

func (SubscriptionPhaseSpec) Validate

func (s SubscriptionPhaseSpec) Validate(
	phaseCadence models.CadencedModel,
	alignment productcatalog.Alignment,
) error

type SubscriptionPhaseView

type SubscriptionPhaseView struct {
	SubscriptionPhase SubscriptionPhase                 `json:"subscriptionPhase"`
	Spec              SubscriptionPhaseSpec             `json:"spec"`
	ItemsByKey        map[string][]SubscriptionItemView `json:"itemsByKey"`
}

func (*SubscriptionPhaseView) ActiveFrom

func (s *SubscriptionPhaseView) ActiveFrom(subscriptionCadence models.CadencedModel) time.Time

func (*SubscriptionPhaseView) AsSpec

func (*SubscriptionPhaseView) Validate

func (s *SubscriptionPhaseView) Validate(includeItems bool) error

type SubscriptionRepository

type SubscriptionRepository interface {
	entutils.TxCreator

	models.CadencedResourceRepo[Subscription]

	// Returns all subscriptions active or scheduled after the given timestamp
	GetAllForCustomerSince(ctx context.Context, customerID models.NamespacedID, at time.Time) ([]Subscription, error)

	// Returns the subscription by ID
	GetByID(ctx context.Context, subscriptionID models.NamespacedID) (Subscription, error)

	// Create a new subscription
	Create(ctx context.Context, input CreateSubscriptionEntityInput) (Subscription, error)

	// Delete a subscription
	Delete(ctx context.Context, id models.NamespacedID) error

	// List subscriptions
	List(ctx context.Context, params ListSubscriptionsInput) (SubscriptionList, error)
}

type SubscriptionSpec

type SubscriptionSpec struct {
	CreateSubscriptionPlanInput     `json:",inline"`
	CreateSubscriptionCustomerInput `json:",inline"`

	// We use pointers so Patches can manipulate the spec
	Phases map[string]*SubscriptionPhaseSpec `json:"phases"`
}

func NewSpecFromPlan

NewSpecFromPlan creates a SubscriptionSpec from a Plan and a CreateSubscriptionCustomerInput.

func (*SubscriptionSpec) ApplyPatches

func (s *SubscriptionSpec) ApplyPatches(patches []Applies, context ApplyContext) error

func (*SubscriptionSpec) GetAlignedBillingPeriodAt

func (s *SubscriptionSpec) GetAlignedBillingPeriodAt(phaseKey string, at time.Time) (timeutil.Period, error)

For a phase in an Aligned subscription, there's a single aligned BillingPeriod for all items in that phase. The period starts with the phase and iterates every BillingCadence duration, but can be reanchored to the time of an edit.

func (*SubscriptionSpec) GetCurrentPhaseAt

func (s *SubscriptionSpec) GetCurrentPhaseAt(t time.Time) (*SubscriptionPhaseSpec, bool)

func (*SubscriptionSpec) GetPhaseCadence

func (s *SubscriptionSpec) GetPhaseCadence(phaseKey string) (models.CadencedModel, error)

func (*SubscriptionSpec) GetSortedPhases

func (s *SubscriptionSpec) GetSortedPhases() []*SubscriptionPhaseSpec

GetSortedPhases returns the subscription phase references time sorted order ASC.

func (*SubscriptionSpec) ToCreateSubscriptionEntityInput

func (s *SubscriptionSpec) ToCreateSubscriptionEntityInput(ns string) CreateSubscriptionEntityInput

func (*SubscriptionSpec) Validate

func (s *SubscriptionSpec) Validate() error

type SubscriptionStateMachine

type SubscriptionStateMachine struct {
	// contains filtered or unexported fields
}

SubscriptionStateMachine is a very simple state machine that determines what actions can be taken on a Subscription

func (SubscriptionStateMachine) CanTransitionOrErr

func (sm SubscriptionStateMachine) CanTransitionOrErr(ctx context.Context, action SubscriptionAction) error

type SubscriptionStatus

type SubscriptionStatus string
const (
	// Active means the subscription is active and the customer is being billed
	SubscriptionStatusActive SubscriptionStatus = "active"
	// Canceled means the subscription has already been canceled but is still active
	SubscriptionStatusCanceled SubscriptionStatus = "canceled"
	// Inactive means the subscription is inactive (might have been previously active) and the customer is not being billed
	SubscriptionStatusInactive SubscriptionStatus = "inactive"
	// Scheduled means the subscription is scheduled to be active in the future
	SubscriptionStatusScheduled SubscriptionStatus = "scheduled"
)

func (SubscriptionStatus) Validate

func (s SubscriptionStatus) Validate() error

type SubscriptionValidator

type SubscriptionValidator interface {
	ValidateCreate(context.Context, SubscriptionView) error
	ValidateUpdate(context.Context, SubscriptionView) error
	ValidateCancel(context.Context, SubscriptionView) error
	ValidateContinue(context.Context, SubscriptionView) error
	ValidateDelete(context.Context, SubscriptionView) error
}

type SubscriptionView

type SubscriptionView struct {
	Subscription Subscription            `json:"subscription"`
	Customer     customer.Customer       `json:"customer"`
	Spec         SubscriptionSpec        `json:"spec"`
	Phases       []SubscriptionPhaseView `json:"phases"`
}

func NewSubscriptionView

func NewSubscriptionView(
	sub Subscription,
	cust customer.Customer,
	phases []SubscriptionPhase,
	items []SubscriptionItem,
	ents []SubscriptionEntitlement,
) (*SubscriptionView, error)

func (SubscriptionView) AsSpec

func (SubscriptionView) GetPhaseByKey

func (s SubscriptionView) GetPhaseByKey(key string) (*SubscriptionPhaseView, bool)

func (*SubscriptionView) Validate

func (s *SubscriptionView) Validate(includePhases bool) error

type Timing

type Timing struct {
	Custom *time.Time
	Enum   *TimingEnum
}

Timing represents the timing of a change in a subscription, such as a plan change or a cancellation.

func (Timing) Resolve

func (c Timing) Resolve() (time.Time, error)

func (Timing) ResolveForSpec

func (c Timing) ResolveForSpec(spec SubscriptionSpec) (time.Time, error)

func (Timing) Validate

func (c Timing) Validate() error

func (Timing) ValidateForAction

func (c Timing) ValidateForAction(action SubscriptionAction, subView *SubscriptionView) error

type TimingEnum

type TimingEnum string
const (
	// Immediate means the change will take effect immediately.
	TimingImmediate TimingEnum = "immediate"
	// NextBillingCycle means the change will take effect at the start of the next billing cycle.
	// This value is only supported for aligned subscriptions.
	TimingNextBillingCycle TimingEnum = "next_billing_cycle"
)

func (TimingEnum) Validate

func (c TimingEnum) Validate() error

type UpdatedEvent

type UpdatedEvent struct {
	// We can consider adding the old version or diff here if needed
	UpdatedView SubscriptionView `json:"updatedView"`
}

func (UpdatedEvent) EventMetadata

func (s UpdatedEvent) EventMetadata() metadata.EventMetadata

func (UpdatedEvent) EventName

func (s UpdatedEvent) EventName() string

func (UpdatedEvent) Validate

func (s UpdatedEvent) Validate() error

type ValuePatch

type ValuePatch[T any] interface {
	Patch
	Value() T
	AnyValuePatch
}

type WorkflowService

type WorkflowService interface {
	CreateFromPlan(ctx context.Context, inp CreateSubscriptionWorkflowInput, plan Plan) (SubscriptionView, error)
	EditRunning(ctx context.Context, subscriptionID models.NamespacedID, customizations []Patch, timing Timing) (SubscriptionView, error)
	ChangeToPlan(ctx context.Context, subscriptionID models.NamespacedID, inp ChangeSubscriptionWorkflowInput, plan Plan) (current Subscription, new SubscriptionView, err error)
}

Directories

Path Synopsis
adapters
validators

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL