feat(vereinfacht): add DB schema, config and setting attributes

- Migrations: vereinfacht_contact_id on members, vereinfacht_* on settings
- Mv.Config: Vereinfacht ENV/Settings helpers, vereinfacht_configured?, contact_view_url
- Setting: vereinfacht_api_url, api_key, club_id
This commit is contained in:
Moritz 2026-02-18 22:28:32 +01:00
parent 47284fee98
commit a5a4d66655
Signed by: moritz
GPG key ID: 1020A035E5DD0824
6 changed files with 542 additions and 2 deletions

View file

@ -142,4 +142,98 @@ defmodule Mv.Config do
|> Keyword.get(key, default)
|> parse_and_validate_integer(default)
end
# ---------------------------------------------------------------------------
# Vereinfacht accounting software integration
# ENV variables take priority; fallback to Settings from database.
# ---------------------------------------------------------------------------
@doc """
Returns the Vereinfacht API base URL.
Reads from `VEREINFACHT_API_URL` env first, then from Settings.
"""
@spec vereinfacht_api_url() :: String.t() | nil
def vereinfacht_api_url do
env_or_setting("VEREINFACHT_API_URL", :vereinfacht_api_url)
end
@doc """
Returns the Vereinfacht API key (Bearer token).
Reads from `VEREINFACHT_API_KEY` env first, then from Settings.
"""
@spec vereinfacht_api_key() :: String.t() | nil
def vereinfacht_api_key do
env_or_setting("VEREINFACHT_API_KEY", :vereinfacht_api_key)
end
@doc """
Returns the Vereinfacht club ID for multi-tenancy.
Reads from `VEREINFACHT_CLUB_ID` env first, then from Settings.
"""
@spec vereinfacht_club_id() :: String.t() | nil
def vereinfacht_club_id do
env_or_setting("VEREINFACHT_CLUB_ID", :vereinfacht_club_id)
end
@doc """
Returns true if Vereinfacht is fully configured (URL, API key, and club ID all set).
"""
@spec vereinfacht_configured?() :: boolean()
def vereinfacht_configured? do
present?(vereinfacht_api_url()) and present?(vereinfacht_api_key()) and
present?(vereinfacht_club_id())
end
@doc """
Returns true if any Vereinfacht ENV variable is set (used to gray out Settings UI).
"""
@spec vereinfacht_env_configured?() :: boolean()
def vereinfacht_env_configured? do
System.get_env("VEREINFACHT_API_URL") != nil or
System.get_env("VEREINFACHT_API_KEY") != nil or
System.get_env("VEREINFACHT_CLUB_ID") != nil
end
defp env_or_setting(env_key, setting_key) do
case System.get_env(env_key) do
nil -> get_vereinfacht_from_settings(setting_key)
value -> trim_nil(value)
end
end
defp get_vereinfacht_from_settings(key) do
case Mv.Membership.get_settings() do
{:ok, settings} -> settings |> Map.get(key) |> trim_nil()
{:error, _} -> nil
end
end
defp trim_nil(nil), do: nil
defp trim_nil(s) when is_binary(s) do
t = String.trim(s)
if t == "", do: nil, else: t
end
@doc """
Returns the URL to view a finance contact (e.g. in Vereinfacht frontend or API).
Uses the configured API base URL and appends /finance-contacts/{id}.
Can be extended later with a dedicated frontend URL setting.
"""
@spec vereinfacht_contact_view_url(String.t()) :: String.t() | nil
def vereinfacht_contact_view_url(contact_id) when is_binary(contact_id) do
base = vereinfacht_api_url()
if present?(base),
do: base |> String.trim_trailing("/") |> then(&"#{&1}/finance-contacts/#{contact_id}"),
else: nil
end
defp present?(nil), do: false
defp present?(s) when is_binary(s), do: String.trim(s) != ""
defp present?(_), do: false
end