feat(vereinfacht): add client, sync flash and SyncContact change
- Application: create SyncFlash ETS table on start - Vereinfacht: Client, SyncFlash, sync_member, format_error, sync_members_without_contact - SyncContact change on Member create_member and update_member - Member: attribute vereinfacht_contact_id, internal action set_vereinfacht_contact_id
This commit is contained in:
parent
b775f5f5c4
commit
3a61699dd2
7 changed files with 551 additions and 1 deletions
54
lib/mv/vereinfacht/changes/sync_contact.ex
Normal file
54
lib/mv/vereinfacht/changes/sync_contact.ex
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
defmodule Mv.Vereinfacht.Changes.SyncContact do
|
||||
@moduledoc """
|
||||
Syncs a member to Vereinfacht as a finance contact after create/update.
|
||||
|
||||
- If the member has no `vereinfacht_contact_id`, creates a contact via API and saves the ID.
|
||||
- If the member already has an ID, updates the contact via API.
|
||||
Runs in `after_transaction` so the member is persisted first. API failures are logged
|
||||
but do not block the member operation. Requires Vereinfacht to be configured
|
||||
(Mv.Config.vereinfacht_configured?/0).
|
||||
"""
|
||||
use Ash.Resource.Change
|
||||
|
||||
require Logger
|
||||
|
||||
@impl true
|
||||
def change(changeset, _opts, _context) do
|
||||
if Mv.Config.vereinfacht_configured?() do
|
||||
Ash.Changeset.after_transaction(changeset, &sync_after_transaction/2)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
# Ash calls after_transaction with (changeset, result) only - 2 args.
|
||||
defp sync_after_transaction(_changeset, {:ok, member}) do
|
||||
case Mv.Vereinfacht.sync_member(member) do
|
||||
:ok ->
|
||||
Mv.Vereinfacht.SyncFlash.store(to_string(member.id), :ok, "Synced to Vereinfacht.")
|
||||
{:ok, member}
|
||||
|
||||
{:ok, member_updated} ->
|
||||
Mv.Vereinfacht.SyncFlash.store(
|
||||
to_string(member_updated.id),
|
||||
:ok,
|
||||
"Synced to Vereinfacht."
|
||||
)
|
||||
|
||||
{:ok, member_updated}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Vereinfacht sync failed for member #{member.id}: #{inspect(reason)}")
|
||||
|
||||
Mv.Vereinfacht.SyncFlash.store(
|
||||
to_string(member.id),
|
||||
:warning,
|
||||
Mv.Vereinfacht.format_error(reason)
|
||||
)
|
||||
|
||||
{:ok, member}
|
||||
end
|
||||
end
|
||||
|
||||
defp sync_after_transaction(_changeset, error), do: error
|
||||
end
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
defmodule Mv.Vereinfacht.Changes.SyncLinkedMemberAfterUserChange do
|
||||
@moduledoc """
|
||||
Syncs the linked Member to Vereinfacht after a User action that may have updated
|
||||
the member's email via Ecto (e.g. User email change → SyncUserEmailToMember).
|
||||
|
||||
Attach to any User action that uses SyncUserEmailToMember. After the transaction
|
||||
commits, if the user has a linked member and Vereinfacht is configured, syncs
|
||||
that member to the API. Failures are logged but do not affect the User result.
|
||||
"""
|
||||
use Ash.Resource.Change
|
||||
|
||||
require Logger
|
||||
alias Mv.Membership.Member
|
||||
alias Mv.Membership
|
||||
alias Mv.Helpers.SystemActor
|
||||
alias Mv.Helpers
|
||||
|
||||
@impl true
|
||||
def change(changeset, _opts, _context) do
|
||||
if Mv.Config.vereinfacht_configured?() do
|
||||
Ash.Changeset.after_transaction(changeset, &sync_linked_member_after_transaction/2)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
defp sync_linked_member_after_transaction(_changeset, {:ok, user}) do
|
||||
case load_linked_member(user) do
|
||||
nil ->
|
||||
{:ok, user}
|
||||
|
||||
member ->
|
||||
case Mv.Vereinfacht.sync_member(member) do
|
||||
:ok ->
|
||||
{:ok, user}
|
||||
|
||||
{:ok, _} ->
|
||||
{:ok, user}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning(
|
||||
"Vereinfacht sync failed for member #{member.id} (linked to user #{user.id}): #{inspect(reason)}"
|
||||
)
|
||||
|
||||
{:ok, user}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp sync_linked_member_after_transaction(_changeset, result), do: result
|
||||
|
||||
defp load_linked_member(%{member_id: nil}), do: nil
|
||||
defp load_linked_member(%{member_id: ""}), do: nil
|
||||
|
||||
defp load_linked_member(user) do
|
||||
actor = SystemActor.get_system_actor()
|
||||
opts = Helpers.ash_actor_opts(actor)
|
||||
|
||||
case Ash.get(Member, user.member_id, [domain: Membership] ++ opts) do
|
||||
{:ok, %Member{} = member} -> member
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue