# `LatticeStripe.SubscriptionSchedule.Phase`
[🔗](https://github.com/szTheory/lattice_stripe/blob/v2.2.2/lib/lattice_stripe/subscription_schedule/phase.ex#L1)

A single phase of a Stripe Subscription Schedule.

## Dual usage

This struct is used for BOTH `schedule.phases[]` entries AND
`schedule.default_settings`. When populated from `default_settings`, the
timeline fields (`start_date`, `end_date`, `iterations`, `trial_end`,
`trial_continuation`) will be `nil` — those fields only apply to concrete
phases on the timeline, not to the per-schedule defaults.

This asymmetry reflects Stripe's API shape, not a LatticeStripe modeling
defect. Reusing one struct for both positions is justified because every
other field on `default_settings` matches the Phase shape.

## Nested decoding

- `automatic_tax` decodes via `LatticeStripe.Invoice.AutomaticTax.from_map/1`
  (reused from Phase 14 — no duplication).
- `items` decodes into `[%LatticeStripe.SubscriptionSchedule.PhaseItem{}]`.
- `add_invoice_items` decodes into
  `[%LatticeStripe.SubscriptionSchedule.AddInvoiceItem{}]`.
- Other nested fields (`invoice_settings`, `transfer_data`,
  `billing_thresholds`, `discounts`, `metadata`, `pause_collection`,
  `prebilling`, `default_tax_rates`) stay as plain maps/values.

## PII

`Phase` uses Elixir's default derived Inspect — there is NO `defimpl Inspect`
on this struct. All PII masking for `default_payment_method` (and for any
payment-method id appearing inside `phases[]` or `default_settings`) is
handled by the single custom `Inspect` impl on the top-level
`%LatticeStripe.SubscriptionSchedule{}`, which never surfaces `phases[]`
or `default_settings` contents as full structs.

# `t`

```elixir
@type t() :: %LatticeStripe.SubscriptionSchedule.Phase{
  add_invoice_items:
    [LatticeStripe.SubscriptionSchedule.AddInvoiceItem.t()] | nil,
  application_fee_percent: number() | nil,
  automatic_tax: LatticeStripe.Invoice.AutomaticTax.t() | nil,
  billing_cycle_anchor: String.t() | nil,
  billing_thresholds: map() | nil,
  collection_method: String.t() | nil,
  currency: String.t() | nil,
  default_payment_method: String.t() | nil,
  default_tax_rates: list() | nil,
  description: String.t() | nil,
  discounts: list() | nil,
  end_date: integer() | nil,
  extra: map(),
  invoice_settings: map() | nil,
  items: [LatticeStripe.SubscriptionSchedule.PhaseItem.t()] | nil,
  iterations: integer() | nil,
  metadata: map() | nil,
  on_behalf_of: String.t() | nil,
  pause_collection: map() | nil,
  prebilling: map() | nil,
  proration_behavior: String.t() | nil,
  start_date: integer() | nil,
  transfer_data: map() | nil,
  trial_continuation: String.t() | nil,
  trial_end: integer() | nil
}
```

A Stripe Subscription Schedule Phase (also reused for default_settings).

# `from_map`

```elixir
@spec from_map(map() | nil) :: t() | nil
```

Converts a decoded Stripe API map to a `%Phase{}` struct.

Decodes nested typed structs:
- `automatic_tax` → `%LatticeStripe.Invoice.AutomaticTax{}`
- `items` → `[%LatticeStripe.SubscriptionSchedule.PhaseItem{}]`
- `add_invoice_items` → `[%LatticeStripe.SubscriptionSchedule.AddInvoiceItem{}]`

Unknown fields are collected into `:extra`.

Returns `nil` when given `nil`.

---

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