openmeter / subscription /errors.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 6)
d6f631f verified
Raw
History Blame Contribute Delete
9.35 kB
package subscription
import (
"errors"
"fmt"
"net/http"
"time"
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
"github.com/openmeterio/openmeter/pkg/models"
)
//
// Business Errors
// (TODO(galexi): probably should not use ValidationIssue for these)
//
const ErrCodeSubscriptionBillingPeriodQueriedBeforeSubscriptionStart models.ErrorCode = "subscription_billing_period_queried_before_subscription_start"
var ErrSubscriptionBillingPeriodQueriedBeforeSubscriptionStart = models.NewValidationIssue(
ErrCodeSubscriptionBillingPeriodQueriedBeforeSubscriptionStart,
"billing period queried before subscription start",
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
func NewErrSubscriptionBillingPeriodQueriedBeforeSubscriptionStart(queriedAt, subscriptionStart time.Time) error {
return ErrSubscriptionBillingPeriodQueriedBeforeSubscriptionStart.WithAttr("queried_at", queriedAt).WithAttr("subscription_start", subscriptionStart)
}
func IsErrSubscriptionBillingPeriodQueriedBeforeSubscriptionStart(err error) bool {
return IsValidationIssueWithCode(err, ErrCodeSubscriptionBillingPeriodQueriedBeforeSubscriptionStart)
}
const ErrCodeOnlySingleSubscriptionAllowed models.ErrorCode = "only_single_subscription_allowed_per_customer_at_a_time"
var ErrOnlySingleSubscriptionAllowed = models.NewValidationIssue(
ErrCodeOnlySingleSubscriptionAllowed,
"only single subscription is allowed per customer at a time",
commonhttp.WithHTTPStatusCodeAttribute(http.StatusConflict),
)
var ErrRestoreSubscriptionNotAllowedForMultiSubscription = models.NewGenericForbiddenError(errors.New("restore subscription is not allowed for multi-subscription"))
const ErrCodeOnlySingleSubscriptionItemAllowedAtATime models.ErrorCode = "only_single_subscription_item_allowed_at_a_time"
var ErrOnlySingleSubscriptionItemAllowedAtATime = models.NewValidationIssue(
ErrCodeOnlySingleSubscriptionItemAllowedAtATime,
"for any given feature, only one subscription item with entitlements or billable prices can exist at a time",
commonhttp.WithHTTPStatusCodeAttribute(http.StatusConflict),
)
// TODO(galexi): "ValidationIssue" is not the right concept here. We should have a different kind of error with all this capability. It's used here as a hack to localize things for the time being.
func IsValidationIssueWithCode(err error, code models.ErrorCode) bool {
issues, err := models.AsValidationIssues(err)
if err != nil {
return false
}
if len(issues) != 1 {
return false
}
return issues[0].Code() == code
}
func IsValidationIssueWithBoolAttr(err error, attrName string) bool {
issues, err := models.AsValidationIssues(err)
if err != nil {
return false
}
if len(issues) != 1 {
return false
}
return issues[0].Attributes()[attrName] == true
}
//
// Validation Issues
//
// Subscription
const ErrCodeSubscriptionBillingAnchorIsRequired models.ErrorCode = "subscription_billing_anchor_is_required"
var ErrSubscriptionBillingAnchorIsRequired = models.NewValidationIssue(
ErrCodeSubscriptionBillingAnchorIsRequired,
"billing anchor is required",
models.WithFieldString("billingAnchor"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
// Phase
const ErrCodeSubscriptionPhaseStartAfterIsNegative models.ErrorCode = "subscription_phase_start_after_is_negative"
var ErrSubscriptionPhaseStartAfterIsNegative = models.NewValidationIssue(
ErrCodeSubscriptionPhaseStartAfterIsNegative,
"subscription phase start after cannot be negative",
models.WithFieldString("startAfter"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionPhaseHasNoItems models.ErrorCode = "subscription_phase_has_no_items"
var ErrSubscriptionPhaseHasNoItems = models.NewValidationIssue(
ErrCodeSubscriptionPhaseHasNoItems,
"subscription phase must have at least one item",
models.WithFieldString("items"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionPhaseItemHistoryKeyMismatch models.ErrorCode = "subscription_phase_item_history_key_mismatch"
var ErrSubscriptionPhaseItemHistoryKeyMismatch = models.NewValidationIssue(
ErrCodeSubscriptionPhaseItemHistoryKeyMismatch,
"subscription phase item history key mismatch",
models.WithFieldString("itemsByKey"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionPhaseItemKeyMismatchWithPhaseKey models.ErrorCode = "subscription_phase_item_key_mismatch_with_phase_key"
var ErrSubscriptionPhaseItemKeyMismatchWithPhaseKey = models.NewValidationIssue(
ErrCodeSubscriptionPhaseItemKeyMismatchWithPhaseKey,
"subscription phase item key mismatch with phase key",
models.WithFieldString("itemKey"),
models.WithFieldString("phaseKey"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
// Item
const ErrCodeSubscriptionItemBillingOverrideIsOnlyAllowedForBillableItems models.ErrorCode = "subscription_item_billing_override_is_only_allowed_for_billable_items"
var ErrSubscriptionItemBillingOverrideIsOnlyAllowedForBillableItems = models.NewValidationIssue(
ErrCodeSubscriptionItemBillingOverrideIsOnlyAllowedForBillableItems,
"billing override is only allowed for billable items",
models.WithFieldString("billingBehaviorOverride"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionItemActiveFromOverrideRelativeToPhaseStartIsNegative models.ErrorCode = "subscription_item_active_from_override_relative_to_phase_start_is_negative"
var ErrSubscriptionItemActiveFromOverrideRelativeToPhaseStartIsNegative = models.NewValidationIssue(
ErrCodeSubscriptionItemActiveFromOverrideRelativeToPhaseStartIsNegative,
"active from override relative to phase start cannot be negative",
models.WithFieldString("activeFromOverrideRelativeToPhaseStart"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionItemActiveToOverrideRelativeToPhaseStartIsNegative models.ErrorCode = "subscription_item_active_to_override_relative_to_phase_start_is_negative"
var ErrSubscriptionItemActiveToOverrideRelativeToPhaseStartIsNegative = models.NewValidationIssue(
ErrCodeSubscriptionItemActiveToOverrideRelativeToPhaseStartIsNegative,
"active to override relative to phase start cannot be negative",
models.WithFieldString("activeToOverrideRelativeToPhaseStart"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
const ErrCodeSubscriptionItemHistoryOverlap models.ErrorCode = "subscription_item_history_overlap"
var ErrSubscriptionItemHistoryOverlap = models.NewValidationIssue(
ErrCodeSubscriptionItemHistoryOverlap,
"subscription item history overlap",
models.WithFieldString("itemsByKey"),
commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest),
)
//
// NotFound errors
//
// NewSubscriptionNotFoundError returns a new SubscriptionNotFoundError.
func NewSubscriptionNotFoundError(id string) error {
return &SubscriptionNotFoundError{
err: models.NewGenericNotFoundError(
fmt.Errorf("subscription %s not found", id),
),
}
}
var _ models.GenericError = &SubscriptionNotFoundError{}
// SubscriptionNotFoundError is returned when a meter is not found.
type SubscriptionNotFoundError struct {
err error
}
// Error returns the error message.
func (e *SubscriptionNotFoundError) Error() string {
return e.err.Error()
}
// Unwrap returns the wrapped error.
func (e *SubscriptionNotFoundError) Unwrap() error {
return e.err
}
// IsSubscriptionNotFoundError returns true if the error is a SubscriptionNotFoundError.
func IsSubscriptionNotFoundError(err error) bool {
if err == nil {
return false
}
var e *SubscriptionNotFoundError
return errors.As(err, &e)
}
// NewPhaseNotFoundError returns a new PhaseNotFoundError.
func NewPhaseNotFoundError(phaseId string) error {
return &PhaseNotFoundError{
err: models.NewGenericNotFoundError(
fmt.Errorf("subscription phase %s not found", phaseId),
),
}
}
var _ models.GenericError = &PhaseNotFoundError{}
// PhaseNotFoundError is returned when a meter is not found.
type PhaseNotFoundError struct {
err error
}
// Error returns the error message.
func (e *PhaseNotFoundError) Error() string {
return e.err.Error()
}
// Unwrap returns the wrapped error.
func (e *PhaseNotFoundError) Unwrap() error {
return e.err
}
// IsPhaseNotFoundError returns true if the error is a PhaseNotFoundError.
func IsPhaseNotFoundError(err error) bool {
if err == nil {
return false
}
var e *PhaseNotFoundError
return errors.As(err, &e)
}
// NewItemNotFoundError returns a new ItemNotFoundError.
func NewItemNotFoundError(itemId string) error {
return &ItemNotFoundError{
err: models.NewGenericNotFoundError(
fmt.Errorf("subscription item %s not found", itemId),
),
}
}
var _ models.GenericError = &ItemNotFoundError{}
// ItemNotFoundError is returned when a meter is not found.
type ItemNotFoundError struct {
err error
}
// Error returns the error message.
func (e *ItemNotFoundError) Error() string {
return e.err.Error()
}
// Unwrap returns the wrapped error.
func (e *ItemNotFoundError) Unwrap() error {
return e.err
}
// IsItemNotFoundError returns true if the error is a ItemNotFoundError.
func IsItemNotFoundError(err error) bool {
if err == nil {
return false
}
var e *ItemNotFoundError
return errors.As(err, &e)
}