subscription

package
v1.0.0-beta.210 Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2025 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// AnnotationSubscriptionID is the ID of the subscription that created this entitlement
	AnnotationSubscriptionID = "subscription.id"
)
View Source
const (
	EventSubsystem metadata.EventSubsystem = "subscription"
)

Variables

View Source
var AnnotationParser = annotationParser{}

Functions

func IsItemNotFoundError

func IsItemNotFoundError(err error) bool

IsItemNotFoundError returns true if the error is a ItemNotFoundError.

func IsPhaseNotFoundError

func IsPhaseNotFoundError(err error) bool

IsPhaseNotFoundError returns true if the error is a PhaseNotFoundError.

func IsPlanNotFoundError

func IsPlanNotFoundError(err error) bool

IsPlanNotFoundError returns true if the error is a PlanNotFoundError.

func IsSubscriptionNotFoundError

func IsSubscriptionNotFoundError(err error) bool

IsSubscriptionNotFoundError returns true if the error is a SubscriptionNotFoundError.

func NewItemNotFoundError

func NewItemNotFoundError(itemId string) error

NewItemNotFoundError returns a new ItemNotFoundError.

func NewPhaseNotFoundError

func NewPhaseNotFoundError(phaseId string) error

NewPhaseNotFoundError returns a new PhaseNotFoundError.

func NewPlanNotFoundError

func NewPlanNotFoundError(key string, version int) error

NewPlanNotFoundError returns a new PlanNotFoundError.

func NewSubscriptionNotFoundError

func NewSubscriptionNotFoundError(id string) error

NewSubscriptionNotFoundError returns a new SubscriptionNotFoundError.

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 AllowedDuringApplyingToSpecError

type AllowedDuringApplyingToSpecError struct {
	Inner error
}

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

func (*AllowedDuringApplyingToSpecError) Error

func (*AllowedDuringApplyingToSpecError) Unwrap

type AnyValuePatch

type AnyValuePatch interface {
	ValueAsAny() any
}

type AppliesToSpec

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

Things can apply themselves to the spec

func NewAggregateAppliesToSpec

func NewAggregateAppliesToSpec(applieses []AppliesToSpec) AppliesToSpec

NewAggregateAppliesToSpec aggregates multiple applies to spec into a single applies to spec, and also validates the spec after applying all the patches

func NewAppliesToSpec

func NewAppliesToSpec(fn func(spec *SubscriptionSpec, actx ApplyContext) error) AppliesToSpec

func ToApplies

func ToApplies(p Patch, _ int) AppliesToSpec

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 NewCancelledEvent

func NewCancelledEvent(ctx context.Context, view SubscriptionView) CancelledEvent

NewCancelledEvent creates a new deleted event

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 ContinuedEvent

type ContinuedEvent viewEvent

func NewContinuedEvent

func NewContinuedEvent(ctx context.Context, view SubscriptionView) ContinuedEvent

NewContinuedEvent creates a new continued event

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.MetadataModel `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.MetadataModel

	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.MetadataModel

	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 productcatalog.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 productcatalog.RateCard `json:"rateCard"`
}

func (*CreateSubscriptionItemPlanInput) UnmarshalJSON

func (i *CreateSubscriptionItemPlanInput) UnmarshalJSON(b []byte) error

type CreateSubscriptionPhaseCustomerInput

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

type CreateSubscriptionPhaseEntityInput

type CreateSubscriptionPhaseEntityInput struct {
	models.NamespacedModel
	models.MetadataModel

	// 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 CreatedEvent

type CreatedEvent viewEvent

func NewCreatedEvent

func NewCreatedEvent(ctx context.Context, view SubscriptionView) CreatedEvent

NewCreatedEvent creates a new created event

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 NewDeletedEvent

func NewDeletedEvent(ctx context.Context, view SubscriptionView) DeletedEvent

NewDeletedEvent creates a new deleted event

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, annotations models.Annotations) (*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 ItemNotFoundError

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

ItemNotFoundError is returned when a meter is not found.

func (*ItemNotFoundError) Error

func (e *ItemNotFoundError) Error() string

Error returns the error message.

func (*ItemNotFoundError) Unwrap

func (e *ItemNotFoundError) Unwrap() error

Unwrap returns the wrapped error.

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 Patch

type Patch interface {
	AppliesToSpec
	Validate() error
	Op() PatchOperation
	Path() SpecPath
}

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 PatchValidationError

type PatchValidationError struct {
	Msg string
}

func (*PatchValidationError) Error

func (e *PatchValidationError) Error() string

type PhaseNotFoundError

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

PhaseNotFoundError is returned when a meter is not found.

func (*PhaseNotFoundError) Error

func (e *PhaseNotFoundError) Error() string

Error returns the error message.

func (*PhaseNotFoundError) Unwrap

func (e *PhaseNotFoundError) Unwrap() error

Unwrap returns the wrapped error.

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 {
	// contains filtered or unexported fields
}

PlanNotFoundError is returned when a meter is not found.

func (*PlanNotFoundError) Error

func (e *PlanNotFoundError) Error() string

Error returns the error message.

func (*PlanNotFoundError) Unwrap

func (e *PlanNotFoundError) Unwrap() error

Unwrap returns the wrapped error.

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 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)
	// GetAllForCustomerSince returns all subscriptions for the given customer that are active or scheduled to start after the given timestamp
	GetAllForCustomerSince(ctx context.Context, customerID models.NamespacedID, at time.Time) ([]Subscription, error)

	ValidatorService
}

type SpecPath

type SpecPath string

func NewItemPath

func NewItemPath(phaseKey, itemKey string) SpecPath

func NewItemVersionPath

func NewItemVersionPath(phaseKey, itemKey string, idx int) SpecPath

func NewPhasePath

func NewPhasePath(phaseKey string) SpecPath

func (SpecPath) IsParentOf

func (p SpecPath) IsParentOf(other SpecPath) bool

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

func (SpecPath) ItemKey

func (p SpecPath) ItemKey() string

func (SpecPath) ItemVersion

func (p SpecPath) ItemVersion() int

func (SpecPath) MarshalJSON

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

Lets implement JSON Marshaler for Path

func (SpecPath) PhaseKey

func (p SpecPath) PhaseKey() string

func (SpecPath) Type

func (p SpecPath) Type() SpecPathType

func (*SpecPath) UnmarshalJSON

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

Lets implement JSON Unmarshaler for Path

func (SpecPath) Validate

func (p SpecPath) Validate() error

Lets implement validation for Path

type SpecPathType

type SpecPathType string
const (
	SpecPathTypePhase       SpecPathType = "phase"
	SpecPathTypeItem        SpecPathType = "item"
	SpecPathTypeItemVersion SpecPathType = "item_version"
)

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.MetadataModel

	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.MetadataModel `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 productcatalog.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

func (*SubscriptionItem) UnmarshalJSON

func (i *SubscriptionItem) UnmarshalJSON(b []byte) error

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) Validate

func (s *SubscriptionItemSpec) Validate() error

type SubscriptionItemView

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

	Entitlement *SubscriptionEntitlement `json:"entitlement,omitempty"`
	Feature     *feature.Feature         `json:"feature,omitempty"`
}

func (*SubscriptionItemView) AsSpec

func (*SubscriptionItemView) Validate

func (s *SubscriptionItemView) Validate() error

type SubscriptionList

type SubscriptionList = pagination.PagedResponse[Subscription]

type SubscriptionNotFoundError

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

SubscriptionNotFoundError is returned when a meter is not found.

func (*SubscriptionNotFoundError) Error

func (e *SubscriptionNotFoundError) Error() string

Error returns the error message.

func (*SubscriptionNotFoundError) Unwrap

func (e *SubscriptionNotFoundError) Unwrap() error

Unwrap returns the wrapped error.

type SubscriptionPhase

type SubscriptionPhase struct {
	models.NamespacedID  `json:",inline"`
	models.ManagedModel  `json:",inline"`
	models.MetadataModel `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) HasEntitlements

func (s SubscriptionPhaseSpec) HasEntitlements() bool

func (SubscriptionPhaseSpec) HasMeteredBillables

func (s SubscriptionPhaseSpec) HasMeteredBillables() 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) Apply

func (s *SubscriptionSpec) Apply(applies AppliesToSpec, context ApplyContext) error

func (*SubscriptionSpec) ApplyMany

func (s *SubscriptionSpec) ApplyMany(applieses []AppliesToSpec, aCtx ApplyContext) error

func (*SubscriptionSpec) GetAlignedBillingPeriodAt

func (s *SubscriptionSpec) GetAlignedBillingPeriodAt(phaseKey string, at time.Time) (timeutil.ClosedPeriod, 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) HasBillables

func (s *SubscriptionSpec) HasBillables() bool

func (*SubscriptionSpec) HasEntitlements

func (s *SubscriptionSpec) HasEntitlements() bool

func (*SubscriptionSpec) HasMeteredBillables

func (s *SubscriptionSpec) HasMeteredBillables() bool

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,
	entFeats []feature.Feature,
	itemFeats []feature.Feature,
) (*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 ToScheduleSubscriptionEntitlementInputOptions

type ToScheduleSubscriptionEntitlementInputOptions struct {
	Customer     customer.Customer
	Cadence      models.CadencedModel
	PhaseCadence models.CadencedModel
	IsAligned    bool
}

type UpdatedEvent

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

func NewUpdatedEvent

func NewUpdatedEvent(ctx context.Context, view SubscriptionView) UpdatedEvent

NewUpdatedEvent creates a new updated event

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 ValidatorService

type ValidatorService interface {
	RegisterValidator(SubscriptionValidator) error
}

type ValuePatch

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

Directories

Path Synopsis
validators

Jump to

Keyboard shortcuts

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