fix(export): emit date custom-field values as ISO-8601 for re-import

This commit is contained in:
Moritz 2026-06-03 01:54:49 +02:00
parent d51dcb1ac3
commit 5c5fd56749
2 changed files with 35 additions and 4 deletions

View file

@ -4,13 +4,13 @@ defmodule Mv.Membership.CustomFieldValueFormatter do
Same logic as the member overview Formatter but without Gettext or web helpers, Same logic as the member overview Formatter but without Gettext or web helpers,
so it can be used from the Membership context. For boolean: "Yes"/"No"; so it can be used from the Membership context. For boolean: "Yes"/"No";
for date: European format (dd.mm.yyyy). for date: ISO-8601 (YYYY-MM-DD) so exported values can be re-imported.
""" """
@doc """ @doc """
Formats a custom field value for plain text (e.g. CSV). Formats a custom field value for plain text (e.g. CSV).
Handles nil, Ash.Union, JSONB map, and direct values. Uses custom_field.value_type Handles nil, Ash.Union, JSONB map, and direct values. Uses custom_field.value_type
for typing. Boolean -> "Yes"/"No", Date -> dd.mm.yyyy. for typing. Boolean -> "Yes"/"No", Date -> ISO-8601 (YYYY-MM-DD).
""" """
def format_custom_field_value(nil, _custom_field), do: "" def format_custom_field_value(nil, _custom_field), do: ""
@ -18,6 +18,10 @@ defmodule Mv.Membership.CustomFieldValueFormatter do
format_value_by_type(value, type, custom_field) format_value_by_type(value, type, custom_field)
end end
def format_custom_field_value(%Date{} = value, custom_field) do
format_value_by_type(value, :date, custom_field)
end
def format_custom_field_value(value, custom_field) when is_map(value) do def format_custom_field_value(value, custom_field) when is_map(value) do
type = Map.get(value, "type") || Map.get(value, "_union_type") type = Map.get(value, "type") || Map.get(value, "_union_type")
val = Map.get(value, "value") || Map.get(value, "_union_value") val = Map.get(value, "value") || Map.get(value, "_union_value")
@ -41,12 +45,12 @@ defmodule Mv.Membership.CustomFieldValueFormatter do
defp format_value_by_type(value, :boolean, _), do: to_string(value) defp format_value_by_type(value, :boolean, _), do: to_string(value)
defp format_value_by_type(%Date{} = date, :date, _) do defp format_value_by_type(%Date{} = date, :date, _) do
Calendar.strftime(date, "%d.%m.%Y") Date.to_iso8601(date)
end end
defp format_value_by_type(value, :date, _) when is_binary(value) do defp format_value_by_type(value, :date, _) when is_binary(value) do
case Date.from_iso8601(value) do case Date.from_iso8601(value) do
{:ok, date} -> Calendar.strftime(date, "%d.%m.%Y") {:ok, date} -> Date.to_iso8601(date)
_ -> value _ -> value
end end
end end

View file

@ -0,0 +1,27 @@
defmodule Mv.Membership.CustomFieldValueFormatterTest do
use ExUnit.Case, async: true
alias Mv.Membership.CustomFieldValueFormatter
describe "format_custom_field_value/2 for :date" do
test "formats an Ash.Union date value as ISO-8601" do
union = %Ash.Union{value: ~D[2024-03-15], type: :date}
assert CustomFieldValueFormatter.format_custom_field_value(union, %{value_type: :date}) ==
"2024-03-15"
end
test "formats a direct Date value as ISO-8601" do
assert CustomFieldValueFormatter.format_custom_field_value(~D[2024-03-15], %{
value_type: :date
}) == "2024-03-15"
end
test "formats an already-stored ISO-8601 string date as ISO-8601" do
union = %Ash.Union{value: "2024-03-15", type: :date}
assert CustomFieldValueFormatter.format_custom_field_value(union, %{value_type: :date}) ==
"2024-03-15"
end
end
end