# `PaperTiger.Proration`
[🔗](https://github.com/neilberkman/paper_tiger/blob/v1.5.1/lib/paper_tiger/proration.ex#L1)

Proration math shared by the immediate proration invoice (subscription
updates) and the proration lines in its preview
(`POST /v1/invoices/create_preview`).

One module on purpose: the previewed proration lines quote the immediate
adjustment, so both paths must use the same remaining-period ratio, item
diff, and currency.

Amounts follow Stripe's model: credit the unused remainder of what was
removed, charge the remainder of what was added, both scaled by how much of
the current billing period is left.

# `invoice_currency`

```elixir
@spec invoice_currency([map()]) :: String.t()
```

Invoice-level currency for a list of built lines.

# `lines`

```elixir
@spec lines([map()], [map()], float(), integer()) :: [map()]
```

Proration line items for a change from `old_items` to `new_items`, scaled
by `ratio`. Items are `%{price_id, product, quantity, unit_amount}` maps;
quantities are aggregated per price, and a price whose total amount did not
change produces no lines. Line currency comes from the price in the store,
falling back to "usd" for a price it does not hold.

# `price_currency`

```elixir
@spec price_currency(String.t() | nil) :: String.t()
```

The currency of a price in the store, falling back to "usd" for one it
does not hold. Also the invoice-level currency for a set of lines: the
first line's currency, on the Stripe invariant that one invoice carries
one currency.

# `remaining_ratio`

```elixir
@spec remaining_ratio(map(), integer()) :: float()
```

The share of the current billing period still ahead at `now`, clamped to
0..1. A subscription without a sane period (missing fields, zero-length
period) prorates at 1.0 — full charge, full credit — which is at least
predictable where the period math would be garbage.

---

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