Phase 3 Plan 06 refund write surface (BILL-26, D3-45..47).
Ships create_refund/2 with sync best-effort fee math: when the
processor response carries an expanded
charge.balance_transaction.fee_refunded, the refund row is persisted
with stripe_fee_refunded_amount_minor, merchant_loss_amount_minor,
and fees_settled_at. When the balance_transaction is not yet
populated, those columns stay nil — the webhook backstop in Plan 07
(charge.refund.updated) fills them asynchronously.
Return shape is uniform {:ok, %Refund{}} — no tagged variant
like {:ok, :pending_fees, _} — because fee settlement state is a
property of the row (fees_settled?/1 predicate), not a branch in the
caller's control flow (D3-47).
Summary
Functions
Creates a refund for the given %Charge{}. Always returns
{:ok, %Refund{}} on success — fee settlement state is tracked via
Refund.fees_settled?/1.
Raising variant of create_refund/2.
Functions
@spec create_refund( Accrue.Billing.Charge.t(), keyword() ) :: {:ok, Accrue.Billing.Refund.t()} | {:error, term()}
Creates a refund for the given %Charge{}. Always returns
{:ok, %Refund{}} on success — fee settlement state is tracked via
Refund.fees_settled?/1.
Options
:amount—%Accrue.Money{}, defaults to the full charge amount (charge.amount_cents).:reason— refund reason string passed to the processor.:operation_id— deterministic idempotency seed.
@spec create_refund!( Accrue.Billing.Charge.t(), keyword() ) :: Accrue.Billing.Refund.t()
Raising variant of create_refund/2.