Ecto schema for the accrue_promotion_codes table.
Stores the thin local projection of a processor promotion code — the
customer-facing string (e.g. "SUMMER25") that resolves to a
Coupon. Phase 4 (BILL-27) mirrors only the fields the admin
LiveView needs to filter/sort: code, active, max_redemptions,
times_redeemed, expires_at, plus the FK to accrue_coupons.
Per D4-01 / Claude's Discretion: full processor mirror is NOT a goal. The canonical source of truth is the processor; Accrue denormalizes only what the admin UI touches.
Summary
Functions
User-path changeset. Validates required fields plus metadata shape,
enforces uniqueness on processor_id and code, and optimistic
locking on lock_version.
Webhook-path changeset (D3-17). Skips required-field validation so out-of-order webhook events can settle partial state. Processor is canonical (D2-29).
Types
@type t() :: %Accrue.Billing.PromotionCode{ __meta__: term(), active: term(), code: term(), coupon: term(), coupon_id: term(), data: term(), expires_at: term(), id: term(), inserted_at: term(), last_stripe_event_id: term(), last_stripe_event_ts: term(), lock_version: term(), max_redemptions: term(), metadata: term(), processor: term(), processor_id: term(), times_redeemed: term(), updated_at: term() }
Functions
@spec changeset( %Accrue.Billing.PromotionCode{ __meta__: term(), active: term(), code: term(), coupon: term(), coupon_id: term(), data: term(), expires_at: term(), id: term(), inserted_at: term(), last_stripe_event_id: term(), last_stripe_event_ts: term(), lock_version: term(), max_redemptions: term(), metadata: term(), processor: term(), processor_id: term(), times_redeemed: term(), updated_at: term() } | Ecto.Changeset.t(), map() ) :: Ecto.Changeset.t()
User-path changeset. Validates required fields plus metadata shape,
enforces uniqueness on processor_id and code, and optimistic
locking on lock_version.
@spec force_status_changeset( %Accrue.Billing.PromotionCode{ __meta__: term(), active: term(), code: term(), coupon: term(), coupon_id: term(), data: term(), expires_at: term(), id: term(), inserted_at: term(), last_stripe_event_id: term(), last_stripe_event_ts: term(), lock_version: term(), max_redemptions: term(), metadata: term(), processor: term(), processor_id: term(), times_redeemed: term(), updated_at: term() } | Ecto.Changeset.t(), map() ) :: Ecto.Changeset.t()
Webhook-path changeset (D3-17). Skips required-field validation so out-of-order webhook events can settle partial state. Processor is canonical (D2-29).