Vereinfacht accounting software API closes #431 #432
6 changed files with 98 additions and 11 deletions
|
|
@ -36,3 +36,4 @@ ASSOCIATION_NAME="Sportsclub XYZ"
|
||||||
# VEREINFACHT_API_URL=https://api.verein.visuel.dev/api/v1
|
# VEREINFACHT_API_URL=https://api.verein.visuel.dev/api/v1
|
||||||
# VEREINFACHT_API_KEY=your-api-key
|
# VEREINFACHT_API_KEY=your-api-key
|
||||||
# VEREINFACHT_CLUB_ID=2
|
# VEREINFACHT_CLUB_ID=2
|
||||||
|
# VEREINFACHT_APP_URL=https://app.verein.visuel.dev
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ defmodule Mv.Membership.Setting do
|
||||||
:default_membership_fee_type_id,
|
:default_membership_fee_type_id,
|
||||||
:vereinfacht_api_url,
|
:vereinfacht_api_url,
|
||||||
:vereinfacht_api_key,
|
:vereinfacht_api_key,
|
||||||
:vereinfacht_club_id
|
:vereinfacht_club_id,
|
||||||
|
:vereinfacht_app_url
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -87,7 +88,8 @@ defmodule Mv.Membership.Setting do
|
||||||
:default_membership_fee_type_id,
|
:default_membership_fee_type_id,
|
||||||
:vereinfacht_api_url,
|
:vereinfacht_api_url,
|
||||||
:vereinfacht_api_key,
|
:vereinfacht_api_key,
|
||||||
:vereinfacht_club_id
|
:vereinfacht_club_id,
|
||||||
|
:vereinfacht_app_url
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -251,6 +253,13 @@ defmodule Mv.Membership.Setting do
|
||||||
description "Vereinfacht club ID for multi-tenancy"
|
description "Vereinfacht club ID for multi-tenancy"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attribute :vereinfacht_app_url, :string do
|
||||||
|
allow_nil? true
|
||||||
|
public? true
|
||||||
|
|
||||||
|
description "Vereinfacht app base URL for contact view links (e.g. https://app.verein.visuel.dev)"
|
||||||
|
end
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,37 @@ defmodule Mv.Config do
|
||||||
env_or_setting("VEREINFACHT_CLUB_ID", :vereinfacht_club_id)
|
env_or_setting("VEREINFACHT_CLUB_ID", :vereinfacht_club_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the Vereinfacht app base URL for contact view links (frontend, not API).
|
||||||
|
|
||||||
|
Reads from `VEREINFACHT_APP_URL` env first, then from Settings.
|
||||||
|
Used to build links like https://app.verein.visuel.dev/en/admin/finances/contacts/{id}.
|
||||||
|
If not set, derived from API URL by replacing host \"api.\" with \"app.\" when possible.
|
||||||
|
"""
|
||||||
|
@spec vereinfacht_app_url() :: String.t() | nil
|
||||||
|
def vereinfacht_app_url do
|
||||||
|
env_or_setting("VEREINFACHT_APP_URL", :vereinfacht_app_url) ||
|
||||||
|
derive_app_url_from_api_url(vereinfacht_api_url())
|
||||||
|
end
|
||||||
|
|
||||||
|
defp derive_app_url_from_api_url(nil), do: nil
|
||||||
|
|
||||||
|
defp derive_app_url_from_api_url(api_url) when is_binary(api_url) do
|
||||||
|
api_url = String.trim(api_url)
|
||||||
|
uri = URI.parse(api_url)
|
||||||
|
host = uri.host || ""
|
||||||
|
|
||||||
|
if String.starts_with?(host, "api.") do
|
||||||
|
app_host = "app." <> String.slice(host, 4..-1//1)
|
||||||
|
scheme = uri.scheme || "https"
|
||||||
|
"#{scheme}://#{app_host}"
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp derive_app_url_from_api_url(_), do: nil
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns true if Vereinfacht is fully configured (URL, API key, and club ID all set).
|
Returns true if Vereinfacht is fully configured (URL, API key, and club ID all set).
|
||||||
"""
|
"""
|
||||||
|
|
@ -211,6 +242,11 @@ defmodule Mv.Config do
|
||||||
"""
|
"""
|
||||||
def vereinfacht_club_id_env_set?, do: env_set?("VEREINFACHT_CLUB_ID")
|
def vereinfacht_club_id_env_set?, do: env_set?("VEREINFACHT_CLUB_ID")
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns true if VEREINFACHT_APP_URL is set (field is read-only in Settings).
|
||||||
|
"""
|
||||||
|
def vereinfacht_app_url_env_set?, do: env_set?("VEREINFACHT_APP_URL")
|
||||||
|
|
||||||
defp env_set?(key) do
|
defp env_set?(key) do
|
||||||
case System.get_env(key) do
|
case System.get_env(key) do
|
||||||
nil -> false
|
nil -> false
|
||||||
|
|
@ -241,18 +277,22 @@ defmodule Mv.Config do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns the URL to view a finance contact (e.g. in Vereinfacht frontend or API).
|
Returns the URL to view a finance contact in the Vereinfacht app (frontend).
|
||||||
|
|
||||||
Uses the configured API base URL and appends /finance-contacts/{id}.
|
Uses the configured app base URL (or derived from API URL) and appends
|
||||||
Can be extended later with a dedicated frontend URL setting.
|
/en/admin/finances/contacts/{id}. Returns nil if no app URL can be determined.
|
||||||
"""
|
"""
|
||||||
@spec vereinfacht_contact_view_url(String.t()) :: String.t() | nil
|
@spec vereinfacht_contact_view_url(String.t()) :: String.t() | nil
|
||||||
def vereinfacht_contact_view_url(contact_id) when is_binary(contact_id) do
|
def vereinfacht_contact_view_url(contact_id) when is_binary(contact_id) do
|
||||||
base = vereinfacht_api_url()
|
base = vereinfacht_app_url()
|
||||||
|
|
||||||
if present?(base),
|
if present?(base) do
|
||||||
do: base |> String.trim_trailing("/") |> then(&"#{&1}/finance-contacts/#{contact_id}"),
|
base
|
||||||
else: nil
|
|> String.trim_trailing("/")
|
||||||
|
|> then(&"#{&1}/en/admin/finances/contacts/#{contact_id}")
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp present?(nil), do: false
|
defp present?(nil), do: false
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ defmodule MvWeb.GlobalSettingsLive do
|
||||||
|> assign(:vereinfacht_api_url_env_set, Mv.Config.vereinfacht_api_url_env_set?())
|
|> assign(:vereinfacht_api_url_env_set, Mv.Config.vereinfacht_api_url_env_set?())
|
||||||
|> assign(:vereinfacht_api_key_env_set, Mv.Config.vereinfacht_api_key_env_set?())
|
|> assign(:vereinfacht_api_key_env_set, Mv.Config.vereinfacht_api_key_env_set?())
|
||||||
|> assign(:vereinfacht_club_id_env_set, Mv.Config.vereinfacht_club_id_env_set?())
|
|> assign(:vereinfacht_club_id_env_set, Mv.Config.vereinfacht_club_id_env_set?())
|
||||||
|
|> assign(:vereinfacht_app_url_env_set, Mv.Config.vereinfacht_app_url_env_set?())
|
||||||
|> assign(:vereinfacht_api_key_set, present?(settings.vereinfacht_api_key))
|
|> assign(:vereinfacht_api_key_set, present?(settings.vereinfacht_api_key))
|
||||||
|> assign(:last_vereinfacht_sync_result, nil)
|
|> assign(:last_vereinfacht_sync_result, nil)
|
||||||
|> assign_form()
|
|> assign_form()
|
||||||
|
|
@ -142,6 +143,18 @@ defmodule MvWeb.GlobalSettingsLive do
|
||||||
if(@vereinfacht_club_id_env_set, do: gettext("From VEREINFACHT_CLUB_ID"), else: "2")
|
if(@vereinfacht_club_id_env_set, do: gettext("From VEREINFACHT_CLUB_ID"), else: "2")
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<.input
|
||||||
|
field={@form[:vereinfacht_app_url]}
|
||||||
|
type="text"
|
||||||
|
label={gettext("App URL (contact view link)")}
|
||||||
|
disabled={@vereinfacht_app_url_env_set}
|
||||||
|
placeholder={
|
||||||
|
if(@vereinfacht_app_url_env_set,
|
||||||
|
do: gettext("From VEREINFACHT_APP_URL"),
|
||||||
|
else: "https://app.verein.visuel.dev"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<.button
|
<.button
|
||||||
:if={
|
:if={
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
defmodule Mv.Repo.Migrations.AddVereinfachtAppUrl do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
alter table(:settings) do
|
||||||
|
add :vereinfacht_app_url, :text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
alter table(:settings) do
|
||||||
|
remove :vereinfacht_app_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -39,14 +39,23 @@ defmodule Mv.ConfigVereinfachtTest do
|
||||||
assert Mv.Config.vereinfacht_contact_view_url("123") == nil
|
assert Mv.Config.vereinfacht_contact_view_url("123") == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns URL when API URL is set" do
|
test "returns app contact view URL when API URL is set (derived app URL)" do
|
||||||
set_vereinfacht_env("VEREINFACHT_API_URL", "https://api.example.com/api/v1")
|
set_vereinfacht_env("VEREINFACHT_API_URL", "https://api.example.com/api/v1")
|
||||||
|
|
||||||
assert Mv.Config.vereinfacht_contact_view_url("42") ==
|
assert Mv.Config.vereinfacht_contact_view_url("42") ==
|
||||||
"https://api.example.com/api/v1/finance-contacts/42"
|
"https://app.example.com/en/admin/finances/contacts/42"
|
||||||
after
|
after
|
||||||
clear_vereinfacht_env()
|
clear_vereinfacht_env()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "returns app contact view URL when VEREINFACHT_APP_URL is set" do
|
||||||
|
set_vereinfacht_env("VEREINFACHT_APP_URL", "https://app.verein.visuel.dev")
|
||||||
|
|
||||||
|
assert Mv.Config.vereinfacht_contact_view_url("abc") ==
|
||||||
|
"https://app.verein.visuel.dev/en/admin/finances/contacts/abc"
|
||||||
|
after
|
||||||
|
System.delete_env("VEREINFACHT_APP_URL")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp set_vereinfacht_env(key, value) do
|
defp set_vereinfacht_env(key, value) do
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue