Packages

phoenix_kit

1.7.28
1.7.211 1.7.210 1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules shop schemas import_config.ex
Raw

lib/modules/shop/schemas/import_config.ex

defmodule PhoenixKit.Modules.Shop.ImportConfig do
@moduledoc """
ImportConfig schema for configurable CSV import filtering.
Allows defining custom filtering rules per import type instead of
using hardcoded keywords.
## Fields
- `name` - Config name (e.g., "decor_3d", "general")
- `include_keywords` - Keywords that must be present for inclusion
- `exclude_keywords` - Keywords that cause exclusion
- `exclude_phrases` - Phrases that cause exclusion
- `skip_filter` - If true, skip all filtering (import everything)
- `category_rules` - List of maps: `[%{keywords: [...], slug: "category-slug"}]`
- `default_category_slug` - Fallback category when no rules match
- `required_columns` - CSV columns that must be present
- `is_default` - Use this config when none specified
- `active` - Config is available for use
## Example Category Rules
[
%{"keywords" => ["shelf"], "slug" => "shelves"},
%{"keywords" => ["mask"], "slug" => "masks"},
%{"keywords" => ["vase", "planter"], "slug" => "vases-planters"}
]
"""
use Ecto.Schema
import Ecto.Changeset
@default_required_columns ["Handle", "Title", "Variant Price"]
schema "phoenix_kit_shop_import_configs" do
field :uuid, Ecto.UUID
field :name, :string
# Filtering keywords (PostgreSQL TEXT[] arrays)
field :include_keywords, {:array, :string}, default: []
field :exclude_keywords, {:array, :string}, default: []
field :exclude_phrases, {:array, :string}, default: []
field :skip_filter, :boolean, default: false
# Category assignment rules (JSONB)
field :category_rules, {:array, :map}, default: []
field :default_category_slug, :string
# CSV validation
field :required_columns, {:array, :string}, default: @default_required_columns
# Status flags
field :is_default, :boolean, default: false
field :active, :boolean, default: true
timestamps()
end
@doc """
Changeset for creating/updating an import config.
"""
def changeset(config \\ %__MODULE__{}, attrs) do
config
|> cast(attrs, [
:name,
:include_keywords,
:exclude_keywords,
:exclude_phrases,
:skip_filter,
:category_rules,
:default_category_slug,
:required_columns,
:is_default,
:active
])
|> validate_required([:name])
|> unique_constraint(:name)
|> unique_constraint(:uuid)
|> validate_category_rules()
|> generate_uuid()
end
defp validate_category_rules(changeset) do
case get_field(changeset, :category_rules) do
nil ->
changeset
rules when is_list(rules) ->
if Enum.all?(rules, &valid_category_rule?/1) do
changeset
else
add_error(
changeset,
:category_rules,
"each rule must have 'keywords' (list) and 'slug' (string)"
)
end
_ ->
add_error(changeset, :category_rules, "must be a list of rule objects")
end
end
defp valid_category_rule?(rule) when is_map(rule) do
keywords = rule["keywords"] || rule[:keywords]
slug = rule["slug"] || rule[:slug]
is_list(keywords) and is_binary(slug) and slug != ""
end
defp valid_category_rule?(_), do: false
defp generate_uuid(changeset) do
if get_field(changeset, :uuid) do
changeset
else
put_change(changeset, :uuid, Ecto.UUID.generate())
end
end
@doc """
Returns default required columns for CSV validation.
"""
def default_required_columns, do: @default_required_columns
@doc """
Builds a config struct from legacy hardcoded values (for backward compatibility).
"""
def from_legacy_defaults do
%__MODULE__{
name: "legacy_default",
include_keywords:
~w(3d printed shelf mask vase planter holder stand lamp light figurine sculpture statue),
exclude_keywords: ~w(decal sticker mural wallpaper poster tapestry canvas),
exclude_phrases: ["wall art"],
skip_filter: false,
category_rules: [
%{"keywords" => ["shelf"], "slug" => "shelves"},
%{"keywords" => ["mask"], "slug" => "masks"},
%{"keywords" => ["vase", "planter"], "slug" => "vases-planters"},
%{"keywords" => ["holder", "stand"], "slug" => "holders-stands"},
%{"keywords" => ["lamp", "light"], "slug" => "lamps"},
%{"keywords" => ["figurine", "sculpture", "statue"], "slug" => "figurines"}
],
default_category_slug: "other-3d",
required_columns: @default_required_columns,
is_default: true,
active: true
}
end
@doc """
Builds a "no filter" config that imports everything.
"""
def no_filter_config do
%__MODULE__{
name: "no_filter",
skip_filter: true,
category_rules: [],
required_columns: @default_required_columns,
is_default: false,
active: true
}
end
end