PhoenixKitEcommerce.PriceDisplay (PhoenixKitEcommerce v0.1.14)

Copy Markdown View Source

How a price is written on the storefront: From €40.00 /hour.

Two independent decorations, both optional and both off by default:

  • a unit — free text per language ("per hour", "/m²", "в час"), so a service shop can state its pricing model. Free text rather than a vocabulary: nothing here needs to know what an hour is, and every shop invents units the next one has never heard of.

  • a "From" prefix — set explicitly by the admin, or implied when the product's options genuinely produce a price range.

Storage

Both live under one reserved key in Product.metadata:

%{"_price_display" => %{
    "unit" => %{"en" => "per hour", "ru" => "в час"},
    "from" => true
  }}

A single versioned namespace rather than two loose top-level keys: the metadata map is an advertised extension point, so this module's data stays in one place that can grow (and be recognised) without colliding with whatever a host already stores there. _-prefixed matches the existing _option_values / _price_modifiers convention, and option keys may not begin with _, so no user-defined option can shadow it.

Context is load-bearing

render/4 takes a context because the same product means different things on different pages:

  • :catalog — the product's asking price. May show "From", and the amount comes from the product's option-aware range.
  • :selected — the price for the options the shopper picked. Exact, so never "From"; keeps the unit.
  • :cart / :order — a SNAPSHOT of what was (or will be) charged. Exact, never "From", and the unit comes from the snapshot rather than the live product, so an edit or deletion cannot rewrite a line the customer already agreed to.

Absent data renders exactly what the module rendered before this existed.

Summary

Functions

Builds the storable namespace map from admin form input.

The reserved metadata key. Consumers that copy metadata around (the CSV upsert, the product form) use this to preserve the namespace.

Renders a price for display.

Reads the display settings out of a product (or a raw metadata map).

The unit text for a language, with default-language fallback.

Functions

build(unit_map, from?)

Builds the storable namespace map from admin form input.

Blank units are dropped so an untouched form does not persist empty strings, and values are length-bounded — this text renders next to a price on a public page, it is not a description field.

metadata_key()

The reserved metadata key. Consumers that copy metadata around (the CSV upsert, the product form) use this to preserve the namespace.

render(product, currency, ctx, opts \\ [])

Renders a price for display.

Options

  • :amount — the exact amount to render (required for :selected, :cart and :order; ignored for :catalog, which derives the product's range).
  • :unit — an explicit unit string, used by snapshot contexts so a cart line can render the unit it stored rather than the live one.
  • :language — the viewer's language, for unit resolution.
  • :range_style:from (default) or :range, catalog only.

settings(metadata)

Reads the display settings out of a product (or a raw metadata map).

Returns %{unit: %{lang => text}, from: boolean} with safe defaults.

unit_for(product_or_metadata, language)

The unit text for a language, with default-language fallback.

Returns nil when the product has no unit — callers render the plain price.