Accrue.Billing.SubscriptionSchedule (accrue v1.0.0)

Copy Markdown View Source

Ecto schema for accrue_subscription_schedules.

A subscription schedule lets you pre-program future plan changes: start a customer on a discounted trial phase, then automatically migrate them to full pricing at a specific date — without manual intervention. Use a schedule instead of a plain subscription when you need time-boxed phases or future price changes locked in advance.

This schema stores a thin local projection of Stripe's SubscriptionSchedule resource. Stripe is canonical for phase state; Accrue persists only the typed columns the admin UI needs to filter and sort on, plus a data jsonb with the full Stripe payload for callers that need the raw shape.

Two changeset functions reflect the two sources of writes: changeset/2 validates status on the user path, while force_status_changeset/2 bypasses that check on the webhook path because Stripe is the source of truth for schedule state.

Summary

Functions

User-path changeset with status validation.

Webhook-path changeset. Stripe is canonical for schedule state; this path skips the status allowlist so out-of-order events can settle arbitrary state without validation failing.

Canonical list of SubscriptionSchedule statuses.

Types

t()

@type t() :: %Accrue.Billing.SubscriptionSchedule{
  __meta__: term(),
  canceled_at: term(),
  current_phase_index: term(),
  customer: term(),
  customer_id: term(),
  data: term(),
  id: term(),
  inserted_at: term(),
  last_stripe_event_id: term(),
  last_stripe_event_ts: term(),
  lock_version: term(),
  metadata: term(),
  next_phase_at: term(),
  phases_count: term(),
  processor: term(),
  processor_id: term(),
  released_at: term(),
  status: term(),
  subscription: term(),
  subscription_id: term(),
  updated_at: term()
}

Functions

changeset(schedule_or_changeset, attrs \\ %{})

@spec changeset(
  %Accrue.Billing.SubscriptionSchedule{
    __meta__: term(),
    canceled_at: term(),
    current_phase_index: term(),
    customer: term(),
    customer_id: term(),
    data: term(),
    id: term(),
    inserted_at: term(),
    last_stripe_event_id: term(),
    last_stripe_event_ts: term(),
    lock_version: term(),
    metadata: term(),
    next_phase_at: term(),
    phases_count: term(),
    processor: term(),
    processor_id: term(),
    released_at: term(),
    status: term(),
    subscription: term(),
    subscription_id: term(),
    updated_at: term()
  }
  | Ecto.Changeset.t(),
  map()
) :: Ecto.Changeset.t()

User-path changeset with status validation.

force_status_changeset(schedule_or_changeset, attrs \\ %{})

@spec force_status_changeset(
  %Accrue.Billing.SubscriptionSchedule{
    __meta__: term(),
    canceled_at: term(),
    current_phase_index: term(),
    customer: term(),
    customer_id: term(),
    data: term(),
    id: term(),
    inserted_at: term(),
    last_stripe_event_id: term(),
    last_stripe_event_ts: term(),
    lock_version: term(),
    metadata: term(),
    next_phase_at: term(),
    phases_count: term(),
    processor: term(),
    processor_id: term(),
    released_at: term(),
    status: term(),
    subscription: term(),
    subscription_id: term(),
    updated_at: term()
  }
  | Ecto.Changeset.t(),
  map()
) :: Ecto.Changeset.t()

Webhook-path changeset. Stripe is canonical for schedule state; this path skips the status allowlist so out-of-order events can settle arbitrary state without validation failing.

statuses()

@spec statuses() :: [String.t()]

Canonical list of SubscriptionSchedule statuses.