PhoenixKitEcommerce. ProductSource. Catalogue. View
(PhoenixKitEcommerce v0.5.0)
Copy Markdown
View Source
Builds hand-built %PhoenixKitEcommerce.Product{} / %PhoenixKitEcommerce.Category{}
view-structs from a phoenix_kit_catalogue item/category, so the facade,
Options, PriceDisplay, CartItem and the storefront templates read
exactly the field names they read today from phoenix_kit_shop_products/
phoenix_kit_shop_categories — no behavior change on their side.
Every function here is pure: no Repo call, no write. product_view/2
and category_view/2 build the struct with struct(Product|Category, fields) — __meta__ stays :built, which is exactly what
PhoenixKitEcommerce.update_product/2/delete_product/2 refuse.
Accepts duck-typed records (a real %PhoenixKitCatalogue.Schemas.Item{}/
%PhoenixKitCatalogue.Schemas.Category{}, or a plain map with the same
keys) — nothing here pattern-matches on the catalogue structs, so tests
can feed plain maps without the optional phoenix_kit_catalogue
dependency loaded.
Summary
Functions
Builds a %Category{} view-struct from a catalogue category.
Synthesizes the legacy metadata sub-map every option/price-display
reader (Options, variant picker, CartItem.from_product/3) expects:
_option_values (labels in the item's stored selection order),
_price_modifiers (slug-keyed ecommerce.price_modifiers swapped to
the label keys those readers match on), _option_labels (%{set_slug => set display name}, read straight off sets — see the moduledoc
note on product_view/2's :language, since a set's OWN translated
name has to already be sitting on it by the time it gets here) and
_value_slugs (%{set_slug => %{label => value slug}}, every value in
the set, not only the ones selected — Block 6/7's future slug-based
selected_specs reads this; nothing in THIS block writes it back).
All four computed fresh from sets on every call, merged over whatever
else data["ecommerce"]["legacy_metadata"] snapshotted (_option_slots,
_image_mappings, _price_display, …) — minus those same four keys,
so a stale snapshot never shadows the live attachment state.
Builds a %Product{} view-struct from a catalogue item.
Functions
@spec category_view(map(), keyword()) :: PhoenixKitEcommerce.Category.t()
Builds a %Category{} view-struct from a catalogue category.
opts[:parent] sets the :parent association field (a %Category{}
view-struct, or nil for a root category / when the caller didn't ask
for it) — a view-struct can never be Repo.preload/2'd, so leaving the
default Ecto.Association.NotLoaded in place (as every OTHER unset
belongs_to/has_many field on this struct still does) would crash
the first template that does a plain if category.parent do truthy
check, same as PhoenixKitEcommerce.ProductSource.Catalogue's
single_category/2 already resolves :category for products.
:storefront_filters is read straight off
data["ecommerce"]["storefront_filters"] (%{} when absent) — see
PhoenixKitEcommerce.merge_storefront_filters/2 for how it overrides
the global filter config.
Synthesizes the legacy metadata sub-map every option/price-display
reader (Options, variant picker, CartItem.from_product/3) expects:
_option_values (labels in the item's stored selection order),
_price_modifiers (slug-keyed ecommerce.price_modifiers swapped to
the label keys those readers match on), _option_labels (%{set_slug => set display name}, read straight off sets — see the moduledoc
note on product_view/2's :language, since a set's OWN translated
name has to already be sitting on it by the time it gets here) and
_value_slugs (%{set_slug => %{label => value slug}}, every value in
the set, not only the ones selected — Block 6/7's future slug-based
selected_specs reads this; nothing in THIS block writes it back).
All four computed fresh from sets on every call, merged over whatever
else data["ecommerce"]["legacy_metadata"] snapshotted (_option_slots,
_image_mappings, _price_display, …) — minus those same four keys,
so a stale snapshot never shadows the live attachment state.
sets accepts the same shapes product_view/2's :sets option does.
language (default nil) picks which translation of each VALUE's
label _option_values/_price_modifiers/_value_slugs key on —
nil keeps every one of them exactly as product_view/2 built it
before this option existed. _option_labels doesn't take language
at all: it reads whatever :name already sits on each set in sets.
@spec product_view(map(), keyword()) :: PhoenixKitEcommerce.Product.t()
Builds a %Product{} view-struct from a catalogue item.
opts[:sets] is a PhoenixKitCatalogue.Catalogue.AttributeSets.resolve_for_item/2
result (%{schema_version: _, sets: [...]}) — or, for tests and other
callers that already have the per-item list, the bare sets list
itself. opts[:category] is a category_view/2 result, attached as
:category when the caller preloaded one.
opts[:language] (a language code, or nil for the untranslated
labels sets already carries) picks the language metadata's
_option_values/_price_modifiers/_value_slugs use for each
attribute-set VALUE's label — see legacy_metadata/3. It does NOT
translate a set's own :name (_option_labels, below) — a value's
translation lives right on it (values[].extras, whatever
resolve_set/2 read off the value's EntityData.data), so this
pure module can pick it with a plain map lookup, but a set's
settings["translations"] isn't part of the resolved shape at all;
translating :name needs an actual read
(ProductSource.Catalogue.Query.set_display_names/2) that only the
caller building sets (ProductSource.Catalogue) can do before
handing them to this pure function.
opts[:base_currency] overrides the shop's configured base currency
code used as the fallback when the item's own data["ecommerce"]["currency"]
is absent — every real caller omits it (falling through to
base_currency_code/0, which reads PhoenixKitEcommerce.get_base_currency/0),
so this stays a pure function for callers (tests included) that want to
avoid that DB read entirely.
opts[:languages] overrides which language codes language_keys/2 treats
as enabled (see its doc) — every real caller omits it (falling through to
Translations.enabled_languages/0, itself backed by the Languages
module's settings), so tests can pin a fixed set of languages without
that dependency either.