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
- Refetch canonical via
Processor.retrieve_refund/2withexpand: ["balance_transaction", "charge.balance_transaction"] - Extract
fee/fee_refundedfromcharge.balance_transaction - If both populated: update row with
stripe_fee_refunded_amount_minor,merchant_loss_amount_minor, andfees_settled_at = Clock.utc_now() - Emit
[:accrue, :billing, :refund, :fees_settled]telemetry - Record
refund.fees_settledevent
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}
]}
]