Packages

phoenix_kit

1.7.88
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 phoenix_kit migrations postgres v46.ex
Raw

lib/phoenix_kit/migrations/postgres/v46.ex

defmodule PhoenixKit.Migrations.Postgres.V46 do
@moduledoc """
V46: Product Options with Dynamic Pricing + Import Logs + Translations
This migration adds:
- phoenix_kit_shop_config table for global Shop configuration
- option_schema JSONB column to categories for category-specific options
- image_id BIGINT column to categories for Storage media integration
- featured_image_id and image_ids columns to products for Storage integration
- selected_specs JSONB column to cart_items for specification storage
- phoenix_kit_shop_import_logs table for CSV import history tracking
- translations JSONB column to products and categories for multi-language support
## Option Schema Format
Options support dynamic pricing with two modifier types:
%{
"key" => "material",
"label" => "Material",
"type" => "select",
"options" => ["PLA", "ABS", "PETG"],
"affects_price" => true,
"modifier_type" => "fixed", # "fixed" or "percent"
"price_modifiers" => %{
"PLA" => "0",
"ABS" => "5.00",
"PETG" => "10.00"
}
}
## Price Calculation Order
1. Sum all fixed modifiers
2. Add to base price (intermediate price)
3. Sum all percent modifiers
4. Apply percent to intermediate price
Example: Base $20 + PETG ($10 fixed) + Premium (20% percent)
Result: ($20 + $10) * 1.20 = $36
"""
use Ecto.Migration
def up(%{prefix: prefix} = _opts) do
prefix_str = if prefix && prefix != "public", do: "#{prefix}.", else: ""
# 1. Create shop_config table for global settings (key-value JSONB)
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_shop_config (
id BIGSERIAL PRIMARY KEY,
uuid UUID DEFAULT gen_random_uuid(),
key VARCHAR(255) NOT NULL,
value JSONB DEFAULT '{}',
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
"""
execute """
CREATE UNIQUE INDEX IF NOT EXISTS idx_shop_config_key
ON #{prefix_str}phoenix_kit_shop_config(key);
"""
execute """
CREATE UNIQUE INDEX IF NOT EXISTS idx_shop_config_uuid
ON #{prefix_str}phoenix_kit_shop_config(uuid);
"""
# 2. Add option_schema, image_id, status, and translations to categories
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_categories
ADD COLUMN IF NOT EXISTS option_schema JSONB DEFAULT '[]',
ADD COLUMN IF NOT EXISTS image_id UUID,
ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'active',
ADD COLUMN IF NOT EXISTS translations JSONB DEFAULT '{}';
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_categories_status
ON #{prefix_str}phoenix_kit_shop_categories(status);
"""
# 3. Add new columns to products (including translations for multi-language)
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_products
ADD COLUMN IF NOT EXISTS made_to_order BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS featured_image_id UUID,
ADD COLUMN IF NOT EXISTS image_ids UUID[] DEFAULT '{}',
ADD COLUMN IF NOT EXISTS translations JSONB DEFAULT '{}';
"""
# 3b. Create GIN indexes for translations JSONB fields
execute """
CREATE INDEX IF NOT EXISTS idx_shop_products_translations
ON #{prefix_str}phoenix_kit_shop_products USING GIN(translations);
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_categories_translations
ON #{prefix_str}phoenix_kit_shop_categories USING GIN(translations);
"""
# 4. Add selected_specs to cart_items for storing user selections
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_cart_items
ADD COLUMN IF NOT EXISTS selected_specs JSONB DEFAULT '{}';
"""
# 5. Create GIN index for selected_specs JSONB for efficient querying
execute """
CREATE INDEX IF NOT EXISTS idx_shop_cart_items_selected_specs
ON #{prefix_str}phoenix_kit_shop_cart_items USING GIN(selected_specs);
"""
# 6. Create import_logs table for CSV import history
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_shop_import_logs (
id BIGSERIAL PRIMARY KEY,
uuid UUID DEFAULT gen_random_uuid(),
filename VARCHAR(255) NOT NULL,
file_path VARCHAR(1024),
status VARCHAR(50) DEFAULT 'pending',
total_rows INTEGER DEFAULT 0,
processed_rows INTEGER DEFAULT 0,
imported_count INTEGER DEFAULT 0,
updated_count INTEGER DEFAULT 0,
skipped_count INTEGER DEFAULT 0,
error_count INTEGER DEFAULT 0,
options JSONB DEFAULT '{}',
error_details JSONB DEFAULT '[]',
started_at TIMESTAMP,
completed_at TIMESTAMP,
user_id BIGINT REFERENCES #{prefix_str}phoenix_kit_users(id) ON DELETE SET NULL,
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
"""
execute """
CREATE UNIQUE INDEX IF NOT EXISTS idx_shop_import_logs_uuid
ON #{prefix_str}phoenix_kit_shop_import_logs(uuid);
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_import_logs_status
ON #{prefix_str}phoenix_kit_shop_import_logs(status);
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_import_logs_inserted_at
ON #{prefix_str}phoenix_kit_shop_import_logs(inserted_at DESC);
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_import_logs_user_id
ON #{prefix_str}phoenix_kit_shop_import_logs(user_id);
"""
# 7. Create import_configs table for configurable CSV import filtering
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_shop_import_configs (
id BIGSERIAL PRIMARY KEY,
uuid UUID DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
include_keywords TEXT[] DEFAULT '{}',
exclude_keywords TEXT[] DEFAULT '{}',
exclude_phrases TEXT[] DEFAULT '{}',
skip_filter BOOLEAN DEFAULT false,
category_rules JSONB DEFAULT '[]',
default_category_slug VARCHAR(255),
required_columns TEXT[] DEFAULT ARRAY['Handle', 'Title', 'Variant Price'],
is_default BOOLEAN DEFAULT false,
active BOOLEAN DEFAULT true,
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
"""
execute """
CREATE UNIQUE INDEX IF NOT EXISTS idx_shop_import_configs_uuid
ON #{prefix_str}phoenix_kit_shop_import_configs(uuid);
"""
execute """
CREATE UNIQUE INDEX IF NOT EXISTS idx_shop_import_configs_name
ON #{prefix_str}phoenix_kit_shop_import_configs(name);
"""
execute """
CREATE INDEX IF NOT EXISTS idx_shop_import_configs_is_default
ON #{prefix_str}phoenix_kit_shop_import_configs(is_default) WHERE is_default = true;
"""
# 8. Update version
execute "COMMENT ON TABLE #{prefix_str}phoenix_kit IS '46'"
end
def down(%{prefix: prefix} = _opts) do
prefix_str = if prefix && prefix != "public", do: "#{prefix}.", else: ""
# Drop import_configs table and indexes
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_configs_is_default;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_configs_name;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_configs_uuid;"
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_shop_import_configs CASCADE;"
# Drop import_logs table and indexes
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_logs_user_id;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_logs_inserted_at;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_logs_status;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_import_logs_uuid;"
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_shop_import_logs CASCADE;"
# Drop GIN index for selected_specs
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_cart_items_selected_specs;"
# Remove selected_specs from cart_items
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_cart_items
DROP COLUMN IF EXISTS selected_specs;
"""
# Drop translations GIN indexes
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_products_translations;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_categories_translations;"
# Remove new columns from products
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_products
DROP COLUMN IF EXISTS made_to_order,
DROP COLUMN IF EXISTS featured_image_id,
DROP COLUMN IF EXISTS image_ids,
DROP COLUMN IF EXISTS translations;
"""
# Remove option_schema, image_id, status, and translations from categories
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_categories_status;"
execute """
ALTER TABLE #{prefix_str}phoenix_kit_shop_categories
DROP COLUMN IF EXISTS option_schema,
DROP COLUMN IF EXISTS image_id,
DROP COLUMN IF EXISTS status,
DROP COLUMN IF EXISTS translations;
"""
# Drop shop_config table
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_config_uuid;"
execute "DROP INDEX IF EXISTS #{prefix_str}idx_shop_config_key;"
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_shop_config CASCADE;"
# Update version
execute "COMMENT ON TABLE #{prefix_str}phoenix_kit IS '45'"
end
end