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
@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
@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.
@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.
@spec statuses() :: [String.t()]
Canonical list of SubscriptionSchedule statuses.