towerops/lib/towerops/billing/billing_notifier.ex

101 lines
3 KiB
Elixir

defmodule Towerops.Billing.BillingNotifier do
@moduledoc """
Email notification service for billing events.
Sends emails for payment failures, subscription updates, and billing alerts.
"""
use Gettext, backend: ToweropsWeb.Gettext
import Swoosh.Email
import ToweropsWeb.GettextHelpers
alias Towerops.Mailer
alias Towerops.Organizations
require Logger
defp deliver(recipient, subject, body) do
from_address = Application.get_env(:towerops, :mailer_from, {"Towerops", "hi@towerops.net"})
email =
new()
|> to(recipient)
|> from(from_address)
|> subject(subject)
|> text_body(body)
case Mailer.deliver(email) do
{:ok, _metadata} ->
Logger.info("Billing email sent to #{recipient}: #{subject}")
{:ok, email}
{:error, reason} = error ->
Logger.error("Failed to send billing email to #{recipient}: #{inspect(reason)}")
error
end
end
@doc """
Deliver payment failure notification to organization owners and admins.
Sends an email to all organization owners and admins informing them of a payment
failure and providing a link to update their payment method.
"""
def deliver_payment_failed_notification(organization) do
# Get all owners and admins (people who can manage billing)
recipients =
organization.id
|> Organizations.list_organization_members()
|> Enum.filter(fn membership -> membership.role in [:owner, :admin] end)
|> Enum.map(fn membership -> membership.user end)
if Enum.empty?(recipients) do
Logger.warning("No owners or admins found for organization #{organization.slug} to notify about payment failure")
{:ok, []}
else
subject = t_email("Payment failed for %{org_name}", org_name: organization.name)
body =
t_email(
"""
Hi,
We were unable to process the payment for your %{org_name} subscription on Towerops.
Your subscription is still active, but we'll retry the payment in a few days. To avoid service interruption, please update your payment method as soon as possible.
You can update your payment method here:
%{billing_url}
If you have any questions or need assistance, please don't hesitate to reply to this email.
Thank you,
Towerops Team
""",
org_name: organization.name,
billing_url: billing_portal_url(organization)
)
results =
Enum.map(recipients, fn user ->
deliver(user.email, subject, body)
end)
# Return success if at least one email was sent
if Enum.any?(results, &match?({:ok, _}, &1)) do
{:ok, results}
else
{:error, :all_emails_failed}
end
end
end
defp billing_portal_url(organization) do
# Generate URL to billing settings page
# In production, this should use the configured app URL
base_url = Application.get_env(:towerops, :app_url, "https://towerops.net")
"#{base_url}/o/#{organization.slug}/settings#billing"
end
end