Packages
phoenix_kit
1.7.76
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
Current section
Files
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
- `option_mappings` - Mappings from CSV option columns to global options
## Example Category Rules
[
%{"keywords" => ["shelf"], "slug" => "shelves"},
%{"keywords" => ["mask"], "slug" => "masks"},
%{"keywords" => ["vase", "planter"], "slug" => "vases-planters"}
]
## Example Option Mappings
[
%{
"csv_name" => "Cup Color",
"slot_key" => "cup_color",
"source_key" => "color",
"auto_add" => true,
"label" => %{"en" => "Cup Color", "ru" => "Цвет чашки"}
},
%{
"csv_name" => "Liquid Color",
"slot_key" => "liquid_color",
"source_key" => "color",
"auto_add" => true
}
]
"""
use Ecto.Schema
import Ecto.Changeset
@type t :: %__MODULE__{}
@default_required_columns ["Handle", "Title", "Variant Price"]
@primary_key {:uuid, UUIDv7, autogenerate: true}
schema "phoenix_kit_shop_import_configs" do
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
# Image migration options
field :download_images, :boolean, default: false
# Option mappings for CSV import (JSONB)
field :option_mappings, {:array, :map}, default: []
timestamps(type: :utc_datetime)
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,
:download_images,
:option_mappings
])
|> validate_required([:name])
|> unique_constraint(:name)
|> unique_constraint(:uuid)
|> validate_category_rules()
|> validate_option_mappings()
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 validate_option_mappings(changeset) do
case get_field(changeset, :option_mappings) do
nil ->
changeset
mappings when is_list(mappings) ->
if Enum.all?(mappings, &valid_option_mapping?/1) do
changeset
else
add_error(
changeset,
:option_mappings,
"each mapping must have 'csv_name' (string) and 'slot_key' (string)"
)
end
_ ->
add_error(changeset, :option_mappings, "must be a list of mapping objects")
end
end
defp valid_option_mapping?(mapping) when is_map(mapping) do
csv_name = mapping["csv_name"] || mapping[:csv_name]
slot_key = mapping["slot_key"] || mapping[:slot_key]
is_binary(csv_name) and csv_name != "" and
is_binary(slot_key) and slot_key != ""
end
defp valid_option_mapping?(_), do: false
@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 default config for Prom.ua imports (no filtering, import everything).
"""
def from_prom_ua_defaults do
%__MODULE__{
name: "prom_ua_default",
skip_filter: true,
category_rules: [],
required_columns: ["Назва_позиції", "Ціна"],
is_default: false,
active: true,
download_images: true,
include_keywords: [],
exclude_keywords: [],
exclude_phrases: []
}
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