# `Accrue.Billing.Customer`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/billing/customer.ex#L1)

Ecto schema for the `accrue_customers` table.

The Customer is the fully-realized polymorphic schema linking a host
app's billable record (User, Organization, Team, etc.) to a processor
customer (e.g. Stripe `cus_xxx`).

## Polymorphic ownership

`owner_type` and `owner_id` are explicit string columns (D2-01, D2-02),
lossless across UUID, bigint, ULID, or any future PK format. The composite
unique index `(owner_type, owner_id, processor)` enforces one customer per
billable per processor.

## Metadata

The `metadata` field follows the exact Stripe metadata contract (D2-07):
flat `%{String.t() => String.t()}`, max 50 keys, keys max 40 chars,
values max 500 chars, no nested maps. See `Accrue.Billing.Metadata`.

## Optimistic locking

All writes use `Ecto.Changeset.optimistic_lock/2` on `lock_version`
to prevent torn writes when a user update and webhook reconcile race
on the same customer (D2-09).

## Phase 3 additions

  * `default_payment_method_id` — FK to accrue_payment_methods with
    `ON DELETE SET NULL`. Set via `set_default_payment_method/2`
    (Plan 06), which asserts attachment before updating.
  * `last_stripe_event_ts` / `last_stripe_event_id` — webhook watermark

# `t`

```elixir
@type t() :: %Accrue.Billing.Customer{
  __meta__: term(),
  charges: term(),
  data: term(),
  default_payment_method: term(),
  default_payment_method_id: term(),
  email: term(),
  id: term(),
  inserted_at: term(),
  invoices: term(),
  last_stripe_event_id: term(),
  last_stripe_event_ts: term(),
  lock_version: term(),
  metadata: term(),
  name: term(),
  owner_id: term(),
  owner_type: term(),
  payment_methods: term(),
  preferred_locale: term(),
  preferred_timezone: term(),
  processor: term(),
  processor_id: term(),
  subscriptions: term(),
  updated_at: term()
}
```

# `changeset`

```elixir
@spec changeset(
  %Accrue.Billing.Customer{
    __meta__: term(),
    charges: term(),
    data: term(),
    default_payment_method: term(),
    default_payment_method_id: term(),
    email: term(),
    id: term(),
    inserted_at: term(),
    invoices: term(),
    last_stripe_event_id: term(),
    last_stripe_event_ts: term(),
    lock_version: term(),
    metadata: term(),
    name: term(),
    owner_id: term(),
    owner_type: term(),
    payment_methods: term(),
    preferred_locale: term(),
    preferred_timezone: term(),
    processor: term(),
    processor_id: term(),
    subscriptions: term(),
    updated_at: term()
  }
  | Ecto.Changeset.t(),
  map()
) :: Ecto.Changeset.t()
```

Builds a changeset for creating or updating a Customer.

Validates required fields, enforces Stripe-compatible metadata
constraints, and applies optimistic locking.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
