PhoenixKit.Modules.Shop.Options.MetadataValidator (phoenix_kit v1.7.39)

Copy Markdown View Source

Validates and normalizes product metadata for options and pricing.

This module handles:

  • Format normalization (object -> string for price modifiers)
  • Consistency validation between _option_values and _price_modifiers
  • Cleanup of orphaned modifiers for removed values

Price Modifier Formats

The canonical format is a simple string representing the price delta:

%{"_price_modifiers" => %{
  "size" => %{"M" => "5.00", "L" => "10.00"},
  "color" => %{"Gold" => "8.00"}
}}

Legacy object format is also supported for backward compatibility:

%{"_price_modifiers" => %{
  "size" => %{"M" => %{"type" => "fixed", "value" => "5.00"}}
}}

Both formats are normalized to string format when saving.

Summary

Functions

Removes orphaned modifiers for values not in _option_values.

Normalizes all price modifiers to string format.

Normalizes a complete set of product attributes before saving.

Validates metadata structure against option schema.

Validates consistency between _option_values and _price_modifiers.

Functions

clean_orphaned_modifiers(metadata)

Removes orphaned modifiers for values not in _option_values.

This cleans up price modifiers when option values are removed.

Examples

metadata = %{
  "_option_values" => %{"size" => ["M", "L"]},
  "_price_modifiers" => %{"size" => %{"S" => "0", "M" => "5.00", "L" => "10.00"}}
}

MetadataValidator.clean_orphaned_modifiers(metadata)
# => %{
#   "_option_values" => %{"size" => ["M", "L"]},
#   "_price_modifiers" => %{"size" => %{"M" => "5.00", "L" => "10.00"}}
# }

normalize_price_modifiers(metadata, base_price \\ nil)

Normalizes all price modifiers to string format.

Converts object format to string format:

  • %{"type" => "fixed", "value" => "10.00"} -> "10.00"
  • %{"value" => "10.00"} -> "10.00"
  • %{"final_price" => "30.00"} with base_price 20 -> "10.00"

Already-string values are passed through unchanged.

Examples

metadata = %{
  "_price_modifiers" => %{
    "size" => %{
      "M" => %{"type" => "fixed", "value" => "5.00"},
      "L" => "10.00"
    }
  }
}

MetadataValidator.normalize_price_modifiers(metadata)
# => %{
#   "_price_modifiers" => %{
#     "size" => %{"M" => "5.00", "L" => "10.00"}
#   }
# }

normalize_product_attrs(attrs)

Normalizes a complete set of product attributes before saving.

This function:

  1. Normalizes price modifiers to string format
  2. Cleans orphaned modifiers
  3. Removes empty _option_values and _price_modifiers maps

Examples

attrs = %{
  "title" => "My Product",
  "metadata" => %{
    "_option_values" => %{"size" => ["M", "L"]},
    "_price_modifiers" => %{
      "size" => %{
        "M" => %{"type" => "fixed", "value" => "5.00"},
        "S" => "orphaned"
      }
    }
  }
}

MetadataValidator.normalize_product_attrs(attrs)
# Normalizes modifiers and removes orphaned "S" entry

validate(metadata, option_schema)

Validates metadata structure against option schema.

Returns :ok or {:error, errors} where errors is a list of error tuples.

Examples

schema = [%{"key" => "size", "type" => "select", "options" => ["S", "M", "L"]}]

MetadataValidator.validate(%{"size" => "M"}, schema)
# => :ok

MetadataValidator.validate(%{"size" => "XL"}, schema)
# => {:error, [{"size", "must be one of: S, M, L"}]}

validate_consistency(metadata)

Validates consistency between _option_values and _price_modifiers.

Ensures that:

  • All keys in _price_modifiers have corresponding entries in _option_values (or are schema options)
  • All values in _price_modifiers exist in their respective option values

Returns a list of error tuples (empty if valid).