PhoenixKitCatalogue.Import.Matcher (PhoenixKitCatalogue v0.19.0)

Copy Markdown View Source

Matches PRO100 rows to existing catalogue items.

The file identifies a row by a numeric code, which is our SKU reduced to digits (Pro100.Id.digits_only/1). That reduction is lossy — it drops the decor letter and the finish, so 73.U767.18 and 73.U767.PM.18 both become 7376718. Matching on it alone leaves every such row permanently ambiguous: on a real export, 28 codes were shared by 62 rows, none of which could ever be updated.

Resolution therefore tries {digits, name} first and falls back to digits alone only when that is unique. The name decides when the code cannot; the code still decides when the name has drifted.

Both indexes skip items whose SKU carries no digits. That is what stops a code-less file row from matching a SKU-less item by name alone — the file's Tööpind spacer row (price 0.00) is named like a real item and would zero its price.

Summary

Functions

Collapses a name to its match key: case-folded, whitespace-collapsed, trimmed.

Resolves one row against the index.

Types

t()

@type t() :: %{
  digits: %{required(String.t()) => [PhoenixKitCatalogue.Schemas.Item.t()]},
  digits_name: %{
    required({String.t(), String.t()}) => [PhoenixKitCatalogue.Schemas.Item.t()]
  }
}

Functions

index(items)

@spec index([PhoenixKitCatalogue.Schemas.Item.t()]) :: t()

normalize_name(name)

@spec normalize_name(String.t() | nil) :: String.t()

Collapses a name to its match key: case-folded, whitespace-collapsed, trimmed.

Applied to item.name when the index is built and to the row name when a row is resolved. It must stay a single function: two copies that drift by one character make the name stage silently stop matching, and the symptom looks like a data problem rather than a code one.

iex> PhoenixKitCatalogue.Import.Matcher.normalize_name("  MP  U741   ST9 ")
"mp u741 st9"

iex> PhoenixKitCatalogue.Import.Matcher.normalize_name(nil)
""

resolve(index, id, name)

@spec resolve(t(), String.t(), String.t() | nil) ::
  {:matched, PhoenixKitCatalogue.Schemas.Item.t()}
  | {:ambiguous, [PhoenixKitCatalogue.Schemas.Item.t()]}
  | :unmatched

Resolves one row against the index.

Stages, in order: a blank id never matches; {id, name} wins when unique; the id alone wins when unique; an id held by several items is refused rather than guessed.