46 lines
1.2 KiB
Elixir
46 lines
1.2 KiB
Elixir
defmodule Towerops.Workers.BillingSyncWorker do
|
|
@moduledoc """
|
|
Daily Oban job to sync device usage to Stripe for metered billing.
|
|
|
|
Runs at 3 AM UTC daily via Oban cron.
|
|
"""
|
|
|
|
use Oban.Worker, queue: :maintenance, max_attempts: 3
|
|
|
|
alias Towerops.Billing
|
|
alias Towerops.Organizations
|
|
|
|
require Logger
|
|
|
|
@impl Oban.Worker
|
|
def perform(_job) do
|
|
Logger.info("Starting daily billing sync")
|
|
|
|
# Get all organizations with active paid subscriptions
|
|
organizations = Organizations.list_organizations_with_active_subscriptions()
|
|
|
|
results =
|
|
Enum.map(organizations, fn org ->
|
|
case Billing.sync_usage_to_stripe(org) do
|
|
:ok -> {:ok, org.slug}
|
|
{:error, reason} -> {:error, org.slug, reason}
|
|
end
|
|
end)
|
|
|
|
successes = Enum.count(results, &match?({:ok, _}, &1))
|
|
failures = Enum.count(results, &match?({:error, _, _}, &1))
|
|
|
|
Logger.info("Billing sync complete: #{successes} success, #{failures} failures")
|
|
|
|
if failures > 0 do
|
|
failed_orgs =
|
|
results
|
|
|> Enum.filter(&match?({:error, _, _}, &1))
|
|
|> Enum.map_join(", ", fn {:error, slug, reason} -> "#{slug}: #{inspect(reason)}" end)
|
|
|
|
Logger.error("Failed to sync: #{failed_orgs}")
|
|
end
|
|
|
|
:ok
|
|
end
|
|
end
|