fix(member-export): split composite Name and Address into component columns on export
This commit is contained in:
parent
a64835fe6d
commit
0a23d03d9d
3 changed files with 96 additions and 1 deletions
|
|
@ -29,10 +29,17 @@ defmodule MvWeb.MemberLive.Index.ExportPayload do
|
|||
member_fields_computed = assigns[:member_fields_visible_computed] || []
|
||||
member_fields_visible = assigns[:member_fields_visible] || []
|
||||
|
||||
# The composite Name/Address cells have no DB column of their own, so they are
|
||||
# not in `member_fields_visible_db` — and their constituents are hidden from
|
||||
# it precisely because the composite replaces them in the table. When a
|
||||
# composite is the visible variant, export its constituent DB columns instead
|
||||
# so the CSV/PDF still carries name and address, split into components.
|
||||
composite_constituents = composite_export_constituents(member_fields_visible, assigns)
|
||||
|
||||
# Order DB member fields exactly like the table/constants.
|
||||
ordered_member_fields_db =
|
||||
Mv.Constants.member_fields()
|
||||
|> Enum.filter(&(&1 in member_fields_db))
|
||||
|> Enum.filter(&(&1 in member_fields_db or &1 in composite_constituents))
|
||||
|
||||
# Order computed fields in canonical order.
|
||||
ordered_computed_fields =
|
||||
|
|
@ -92,6 +99,26 @@ defmodule MvWeb.MemberLive.Index.ExportPayload do
|
|||
defp cycle_status_filter(:unpaid), do: "unpaid"
|
||||
defp cycle_status_filter(_), do: nil
|
||||
|
||||
# DB constituent columns to add for whichever composite cells are currently
|
||||
# visible. Email is a name constituent only while folded into the compact
|
||||
# Member cell (`member_include_email`); otherwise it is exported as its own
|
||||
# visible column and needs no expansion here.
|
||||
defp composite_export_constituents(member_fields_visible, assigns) do
|
||||
name =
|
||||
if :name in member_fields_visible do
|
||||
FieldVisibility.name_constituents(assigns[:member_include_email] || false)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
address =
|
||||
if :address in member_fields_visible,
|
||||
do: FieldVisibility.address_constituents(),
|
||||
else: []
|
||||
|
||||
name ++ address
|
||||
end
|
||||
|
||||
defp build_member_fields_list(ordered_db, member_fields_visible) do
|
||||
member_fields_visible = member_fields_visible || []
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,20 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
leading ++ rest
|
||||
end
|
||||
|
||||
@doc """
|
||||
The DB constituent columns the composite `:name` cell stands in for, in
|
||||
canonical order. `:email` is a constituent only while it is folded into the
|
||||
compact Member cell (`include_email?` true); otherwise it is its own column.
|
||||
"""
|
||||
@spec name_constituents(boolean()) :: [atom()]
|
||||
def name_constituents(include_email?) do
|
||||
if include_email?, do: @name_constituents, else: @name_constituents -- [:email]
|
||||
end
|
||||
|
||||
@doc "The DB constituent columns the composite `:address` cell stands in for, in canonical order."
|
||||
@spec address_constituents() :: [:street | :house_number | :postal_code | :city, ...]
|
||||
def address_constituents, do: @address_constituents
|
||||
|
||||
# The email is a separate offered column except when it is folded into the
|
||||
# compact Member cell (compact + include_email).
|
||||
defp email_offered?(compact_member, include_email), do: not (compact_member and include_email)
|
||||
|
|
|
|||
|
|
@ -83,5 +83,59 @@ defmodule MvWeb.MemberLive.Index.ExportPayloadTest do
|
|||
assert payload.cycle_status_filter == nil
|
||||
assert payload.boolean_filters == %{}
|
||||
end
|
||||
|
||||
test "expands visible composite Name/Address cells into their constituent db columns" do
|
||||
# Compact mode: the composite :name / :address cells are visible and their
|
||||
# constituent columns are hidden from member_fields_visible_db. The export
|
||||
# must still carry name and address, split into their db components.
|
||||
assigns = %{
|
||||
selected_members: MapSet.new(),
|
||||
member_fields_visible_db: [:join_date],
|
||||
member_fields_visible_computed: [],
|
||||
member_fields_visible: [:name, :address, :join_date],
|
||||
member_include_email: true,
|
||||
visible_custom_field_ids: [],
|
||||
all_custom_fields: []
|
||||
}
|
||||
|
||||
payload = ExportPayload.build(assigns)
|
||||
|
||||
# Constituents are emitted in Mv.Constants.member_fields/0 order, interleaved
|
||||
# with the ordinary visible db field (join_date sits between the name and
|
||||
# address groups per constants order).
|
||||
assert payload.column_order == [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"join_date",
|
||||
"city",
|
||||
"street",
|
||||
"house_number",
|
||||
"postal_code"
|
||||
]
|
||||
|
||||
# The composite pseudo-columns themselves are never exported.
|
||||
refute "name" in payload.member_fields
|
||||
refute "address" in payload.member_fields
|
||||
end
|
||||
|
||||
test "omits email from the Name composite expansion when it is not folded into the cell" do
|
||||
# include_email off: email is its own column (exported only if separately
|
||||
# visible), so the Name composite expands to first/last name only.
|
||||
assigns = %{
|
||||
selected_members: MapSet.new(),
|
||||
member_fields_visible_db: [:join_date],
|
||||
member_fields_visible_computed: [],
|
||||
member_fields_visible: [:name, :join_date],
|
||||
member_include_email: false,
|
||||
visible_custom_field_ids: [],
|
||||
all_custom_fields: []
|
||||
}
|
||||
|
||||
payload = ExportPayload.build(assigns)
|
||||
|
||||
assert payload.column_order == ["first_name", "last_name", "join_date"]
|
||||
refute "email" in payload.column_order
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue