Accrue.Billing.PromotionCode (accrue v0.3.0)

Copy Markdown View Source

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

t()

@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

changeset(promo_or_changeset, attrs \\ %{})

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

force_status_changeset(promo_or_changeset, attrs \\ %{})

@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).