# `Accrue.Jobs.ReconcileRefundFees`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v1.0.0/lib/accrue/jobs/reconcile_refund_fees.ex#L1)

Daily backstop Oban worker for refund fees that weren't populated at
create time (D3-46).

## Sweep window

Selects `accrue_refunds` where `fees_settled_at IS NULL AND inserted_at
< now() - 24h`. The 24h buffer gives Stripe's balance_transaction
settlement time to populate before the reconciler tries to pull fees
forward — earlier attempts would just re-fail with nil `fee_refunded`.

## Flow per row

  1. Refetch canonical via `Processor.retrieve_refund/2` with
     `expand: ["balance_transaction", "charge.balance_transaction"]`
  2. Extract `fee` / `fee_refunded` from `charge.balance_transaction`
  3. If both populated: update row with `stripe_fee_refunded_amount_minor`,
     `merchant_loss_amount_minor`, and `fees_settled_at = Clock.utc_now()`
  4. Emit `[:accrue, :billing, :refund, :fees_settled]` telemetry
  5. Record `refund.fees_settled` event

Rows without populated fees are skipped silently — the next sweep
will pick them up again.

Schedule via Oban cron in the host app:

    config :my_app, Oban,
      plugins: [
        {Oban.Plugins.Cron,
         crontab: [
           {"@daily", Accrue.Jobs.ReconcileRefundFees}
         ]}
      ]

---

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