towerops/lib/towerops/integrations.ex
Graham McIntire de075ea8d9
Store billing subscriber/MRR data on integrations for dashboard
Each billing sync (Gaiia, Splynx, VISP, Sonar) already computes
subscriber counts and MRR but only stored them in sync messages.
Now persists them on the integrations table so the dashboard can
aggregate across all billing providers instead of only querying
Gaiia network sites (which were never populated).

Also fixes SnmpKit Config environment detection to use Mix.env()
as fallback when MIX_ENV env var is not set.
2026-02-15 16:51:33 -06:00

96 lines
2.6 KiB
Elixir

defmodule Towerops.Integrations do
@moduledoc """
Context for managing third-party integrations per organization.
"""
import Ecto.Query
alias Towerops.Integrations.Integration
alias Towerops.Repo
def list_integrations(organization_id) do
Integration
|> where(organization_id: ^organization_id)
|> order_by(:provider)
|> Repo.all()
end
def get_integration(organization_id, provider) do
case Repo.get_by(Integration, organization_id: organization_id, provider: provider) do
nil -> {:error, :not_found}
integration -> {:ok, integration}
end
end
def get_integration!(organization_id, provider) do
Repo.get_by!(Integration, organization_id: organization_id, provider: provider)
end
def create_integration(organization_id, attrs) do
%Integration{}
|> Integration.changeset(Map.put(attrs, :organization_id, organization_id))
|> Repo.insert()
end
def update_integration(%Integration{} = integration, attrs) do
integration
|> Integration.changeset(attrs)
|> Repo.update()
end
def update_sync_status(%Integration{} = integration, status, message \\ nil) do
integration
|> Integration.changeset(%{
last_sync_status: status,
last_synced_at: DateTime.truncate(DateTime.utc_now(), :second),
last_sync_message: message
})
|> Repo.update()
end
def delete_integration(%Integration{} = integration) do
Repo.delete(integration)
end
def change_integration(%Integration{} = integration, attrs \\ %{}) do
Integration.changeset(integration, attrs)
end
def get_integration_by_id(id) do
case Repo.get(Integration, id) do
nil -> {:error, :not_found}
integration -> {:ok, integration}
end
end
@billing_providers ~w(gaiia splynx visp sonar)
def update_billing_totals(%Integration{} = integration, subscriber_count, total_mrr) do
integration
|> Integration.changeset(%{subscriber_count: subscriber_count, total_mrr: total_mrr})
|> Repo.update()
end
def get_billing_summary(organization_id) do
result =
Integration
|> where(organization_id: ^organization_id)
|> where([i], i.provider in @billing_providers)
|> where(enabled: true)
|> select([i], %{
total_subscribers: coalesce(sum(i.subscriber_count), 0),
total_mrr: coalesce(sum(i.total_mrr), 0)
})
|> Repo.one()
%{
total_subscribers: result.total_subscribers,
total_mrr: result.total_mrr || Decimal.new(0)
}
end
def list_enabled_integrations(provider) do
Integration
|> where(provider: ^provider, enabled: true)
|> Repo.all()
end
end