Packages

phoenix_kit

1.7.26
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules billing web settings.ex
Raw

lib/modules/billing/web/settings.ex

defmodule PhoenixKit.Modules.Billing.Web.Settings do
@moduledoc """
Billing settings LiveView for the billing module.
Provides configuration interface for billing module settings.
Company and bank information is now managed in Organization Settings.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Billing
alias PhoenixKit.Modules.Billing.CountryData
alias PhoenixKit.Modules.Shop
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
project_title = Settings.get_setting("project_title", "PhoenixKit")
billing_enabled = Billing.enabled?()
socket =
socket
|> assign(:page_title, "Billing Settings")
|> assign(:project_title, project_title)
|> assign(:url_path, Routes.path("/admin/billing/settings"))
|> assign(:billing_enabled, billing_enabled)
|> load_settings()
{:ok, socket}
end
@impl true
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
defp load_settings(socket) do
# Get company info from consolidated Settings (with fallback to legacy keys)
company_info = CountryData.get_company_info()
bank_details = CountryData.get_bank_details()
company_country = company_info["country"] || ""
socket
# General settings
|> assign(:default_currency, Settings.get_setting("billing_default_currency", "EUR"))
|> assign(:invoice_prefix, Settings.get_setting("billing_invoice_prefix", "INV"))
|> assign(:order_prefix, Settings.get_setting("billing_order_prefix", "ORD"))
|> assign(:receipt_prefix, Settings.get_setting("billing_receipt_prefix", "RCP"))
|> assign(:invoice_due_days, Settings.get_setting("billing_invoice_due_days", "14"))
|> assign(:tax_enabled, Settings.get_setting("billing_tax_enabled", "false") == "true")
|> assign(:tax_rate, Settings.get_setting("billing_default_tax_rate", "0"))
# Company info (from consolidated source)
|> assign(:company_info, company_info)
|> assign(:company_address_formatted, CountryData.format_company_address())
|> assign(:company_country_name, get_country_name(company_country))
|> assign(:company_country, company_country)
# For suggested tax rate
|> assign_suggested_tax_rate()
# Bank details (from consolidated source)
|> assign(:bank_details, bank_details)
end
# Helper to get country name from code
defp get_country_name(""), do: ""
defp get_country_name(nil), do: ""
defp get_country_name(country_code) do
case BeamLabCountries.get(country_code) do
nil -> country_code
country -> country.name
end
end
@impl true
def handle_event("toggle_billing", _params, socket) do
new_enabled = !socket.assigns.billing_enabled
# If disabling Billing and Shop is enabled, disable Shop first
if not new_enabled and shop_enabled?(), do: Shop.disable_system()
result =
if new_enabled do
Billing.enable_system()
else
Billing.disable_system()
end
case result do
:ok ->
{:noreply,
socket
|> assign(:billing_enabled, new_enabled)
|> put_flash(:info, if(new_enabled, do: "Billing enabled", else: "Billing disabled"))}
_ ->
{:noreply, put_flash(socket, :error, "Failed to update billing status")}
end
end
@impl true
def handle_event("save_general", params, socket) do
# Convert checkbox value to "true"/"false" string
tax_enabled = if params["tax_enabled"] == "true", do: "true", else: "false"
settings = [
{"billing_default_currency", params["default_currency"]},
{"billing_invoice_prefix", params["invoice_prefix"]},
{"billing_order_prefix", params["order_prefix"]},
{"billing_receipt_prefix", params["receipt_prefix"]},
{"billing_invoice_due_days", params["invoice_due_days"]},
{"billing_tax_enabled", tax_enabled},
{"billing_default_tax_rate", params["tax_rate"]}
]
Enum.each(settings, fn {key, value} ->
Settings.update_setting(key, value)
end)
{:noreply,
socket
|> load_settings()
|> put_flash(:info, "General settings saved")}
end
@impl true
def handle_event("tax_rate_changed", %{"tax_rate" => tax_rate}, socket) do
current_rate = parse_tax_rate(tax_rate)
country_code = socket.assigns.company_country
suggested_rate =
if country_code != "" do
rate = CountryData.get_standard_vat_percent(country_code)
if rate == current_rate, do: nil, else: rate
else
nil
end
{:noreply,
socket
|> assign(:tax_rate, tax_rate)
|> assign(:suggested_tax_rate, suggested_rate)}
end
@impl true
def handle_event("apply_suggested_tax", _params, socket) do
case socket.assigns.suggested_tax_rate do
nil ->
{:noreply, socket}
rate ->
{:noreply,
socket
|> assign(:tax_rate, to_string(rate))
|> assign(:suggested_tax_rate, nil)}
end
end
# Suggested tax rate helper
defp assign_suggested_tax_rate(socket) do
country_code = socket.assigns.company_country
current_rate = parse_tax_rate(socket.assigns.tax_rate)
suggested_rate =
if country_code != "" do
rate = CountryData.get_standard_vat_percent(country_code)
# Hide suggestion if it matches current rate
if rate == current_rate, do: nil, else: rate
else
nil
end
assign(socket, :suggested_tax_rate, suggested_rate)
end
defp parse_tax_rate(rate) when is_binary(rate) do
case Float.parse(rate) do
{value, _} -> if value == trunc(value), do: trunc(value), else: value
:error -> 0
end
end
defp parse_tax_rate(rate) when is_number(rate), do: rate
defp parse_tax_rate(_), do: 0
defp shop_enabled? do
Code.ensure_loaded?(Shop) and
function_exported?(Shop, :enabled?, 0) and
Shop.enabled?()
rescue
_ -> false
end
end