mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-11 22:30:59 +04:30
Add public user-products storefront API and website docs.
Expose published customer listings under /tenants/:host/user-products (list, search, details, technical-info) and document them in the website API pack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
158523df7b
commit
953b87b616
@@ -0,0 +1,188 @@
|
||||
-- Customer / user products (stock listings)
|
||||
-- Like products, but: no variations/options; location (country/city/district);
|
||||
-- categories come from main product categories via category_assignments;
|
||||
-- technical data reuses category technical forms.
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- entity type for assignments / media attachments
|
||||
-- ---------------------------------------------------------------------------
|
||||
ALTER TYPE media_entity_type ADD VALUE IF NOT EXISTS 'user_product';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- cities: add district under city (country → province → city → district)
|
||||
-- ---------------------------------------------------------------------------
|
||||
ALTER TYPE city_level ADD VALUE IF NOT EXISTS 'district';
|
||||
|
||||
CREATE OR REPLACE FUNCTION cities_validate_parent_level()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
parent_level city_level;
|
||||
BEGIN
|
||||
IF NEW.level = 'country' THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT level INTO parent_level FROM cities WHERE id = NEW.parent_id;
|
||||
|
||||
IF NOT FOUND THEN
|
||||
RAISE EXCEPTION 'parent city not found';
|
||||
END IF;
|
||||
|
||||
IF NEW.level = 'province' AND parent_level <> 'country' THEN
|
||||
RAISE EXCEPTION 'province parent must be a country';
|
||||
END IF;
|
||||
|
||||
IF NEW.level = 'city' AND parent_level <> 'province' THEN
|
||||
RAISE EXCEPTION 'city parent must be a province';
|
||||
END IF;
|
||||
|
||||
IF NEW.level = 'district' AND parent_level <> 'city' THEN
|
||||
RAISE EXCEPTION 'district parent must be a city';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- user_products
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE user_products (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
business_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
content JSONB NOT NULL DEFAULT '{}',
|
||||
price NUMERIC(12, 2),
|
||||
compare_at_price NUMERIC(12, 2),
|
||||
sku VARCHAR(100),
|
||||
stock_quantity INTEGER,
|
||||
status content_status NOT NULL DEFAULT 'draft',
|
||||
featured_media_id BIGINT,
|
||||
brand_id BIGINT,
|
||||
country_id BIGINT NOT NULL,
|
||||
city_id BIGINT NOT NULL,
|
||||
district_id BIGINT,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
published_at TIMESTAMPTZ,
|
||||
metadata JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT user_products_business_slug_unique UNIQUE (business_id, slug),
|
||||
CONSTRAINT user_products_business_id_fkey
|
||||
FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_products_user_id_fkey
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_products_featured_media_id_fkey
|
||||
FOREIGN KEY (featured_media_id) REFERENCES media (id) ON DELETE SET NULL,
|
||||
CONSTRAINT user_products_brand_id_fkey
|
||||
FOREIGN KEY (brand_id) REFERENCES brands (id) ON DELETE SET NULL,
|
||||
CONSTRAINT user_products_country_id_fkey
|
||||
FOREIGN KEY (country_id) REFERENCES cities (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT user_products_city_id_fkey
|
||||
FOREIGN KEY (city_id) REFERENCES cities (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT user_products_district_id_fkey
|
||||
FOREIGN KEY (district_id) REFERENCES cities (id) ON DELETE SET NULL,
|
||||
CONSTRAINT user_products_price_non_negative CHECK (price IS NULL OR price >= 0),
|
||||
CONSTRAINT user_products_compare_price_non_negative CHECK (compare_at_price IS NULL OR compare_at_price >= 0),
|
||||
CONSTRAINT user_products_stock_non_negative CHECK (stock_quantity IS NULL OR stock_quantity >= 0)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_products_business_id ON user_products (business_id);
|
||||
CREATE INDEX idx_user_products_user_id ON user_products (user_id);
|
||||
CREATE INDEX idx_user_products_business_user ON user_products (business_id, user_id);
|
||||
CREATE INDEX idx_user_products_business_status ON user_products (business_id, status);
|
||||
CREATE INDEX idx_user_products_business_published ON user_products (business_id, published_at DESC);
|
||||
CREATE INDEX idx_user_products_brand_id ON user_products (brand_id);
|
||||
CREATE INDEX idx_user_products_country_id ON user_products (country_id);
|
||||
CREATE INDEX idx_user_products_city_id ON user_products (city_id);
|
||||
CREATE INDEX idx_user_products_district_id ON user_products (district_id);
|
||||
|
||||
CREATE TRIGGER user_products_set_updated_at
|
||||
BEFORE UPDATE ON user_products
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- technical data (same shape as product technical field values)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE user_product_technical_field_values (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
business_id BIGINT NOT NULL,
|
||||
user_product_id BIGINT NOT NULL,
|
||||
field_id BIGINT NOT NULL,
|
||||
text_value TEXT,
|
||||
option_id BIGINT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT user_product_technical_field_values_business_id_fkey
|
||||
FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_product_technical_field_values_user_product_id_fkey
|
||||
FOREIGN KEY (user_product_id) REFERENCES user_products (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_product_technical_field_values_field_id_fkey
|
||||
FOREIGN KEY (field_id) REFERENCES category_technical_form_fields (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_product_technical_field_values_option_id_fkey
|
||||
FOREIGN KEY (option_id) REFERENCES category_technical_form_field_options (id) ON DELETE SET NULL,
|
||||
CONSTRAINT user_product_technical_field_values_unique
|
||||
UNIQUE (user_product_id, field_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_product_technical_field_values_user_product_id
|
||||
ON user_product_technical_field_values (user_product_id);
|
||||
CREATE INDEX idx_user_product_technical_field_values_business_id
|
||||
ON user_product_technical_field_values (business_id);
|
||||
|
||||
CREATE TRIGGER user_product_technical_field_values_set_updated_at
|
||||
BEFORE UPDATE ON user_product_technical_field_values
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE user_product_technical_field_value_options (
|
||||
field_value_id BIGINT NOT NULL,
|
||||
option_id BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT user_product_technical_field_value_options_pkey
|
||||
PRIMARY KEY (field_value_id, option_id),
|
||||
CONSTRAINT user_product_technical_field_value_options_field_value_id_fkey
|
||||
FOREIGN KEY (field_value_id) REFERENCES user_product_technical_field_values (id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_product_technical_field_value_options_option_id_fkey
|
||||
FOREIGN KEY (option_id) REFERENCES category_technical_form_field_options (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_product_technical_field_value_options_option_id
|
||||
ON user_product_technical_field_value_options (option_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- permissions (business dashboard moderation)
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO permissions (name, slug, group_name, description) VALUES
|
||||
('View user products', 'user_products.read', 'user_products', 'View customer product listings'),
|
||||
('Create user products', 'user_products.create', 'user_products', 'Create customer product listings'),
|
||||
('Update user products', 'user_products.update', 'user_products', 'Edit customer product listings'),
|
||||
('Delete user products', 'user_products.delete', 'user_products', 'Delete customer product listings')
|
||||
ON CONFLICT (slug) DO NOTHING;
|
||||
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r
|
||||
JOIN permissions p ON p.slug LIKE 'user_products.%'
|
||||
WHERE r.slug IN ('business_owner', 'owner', 'admin')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r
|
||||
JOIN permissions p ON p.slug IN ('user_products.read', 'user_products.create', 'user_products.update')
|
||||
WHERE r.slug = 'editor'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r
|
||||
JOIN permissions p ON p.slug = 'user_products.read'
|
||||
WHERE r.slug = 'viewer'
|
||||
ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,86 @@
|
||||
-- Allow cities directly under a country (province optional).
|
||||
-- Seed Iraq, Turkey, UAE + major cities (Iran already seeded in 004_iran_cities).
|
||||
|
||||
CREATE OR REPLACE FUNCTION cities_validate_parent_level()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
parent_level city_level;
|
||||
BEGIN
|
||||
IF NEW.level = 'country' THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT level INTO parent_level FROM cities WHERE id = NEW.parent_id;
|
||||
|
||||
IF NOT FOUND THEN
|
||||
RAISE EXCEPTION 'parent city not found';
|
||||
END IF;
|
||||
|
||||
IF NEW.level = 'province' AND parent_level <> 'country' THEN
|
||||
RAISE EXCEPTION 'province parent must be a country';
|
||||
END IF;
|
||||
|
||||
-- Province is optional: city may hang under a province or directly under a country.
|
||||
IF NEW.level = 'city' AND parent_level NOT IN ('province', 'country') THEN
|
||||
RAISE EXCEPTION 'city parent must be a province or country';
|
||||
END IF;
|
||||
|
||||
IF NEW.level = 'district' AND parent_level <> 'city' THEN
|
||||
RAISE EXCEPTION 'district parent must be a city';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Countries (skip if slug already exists)
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO cities (parent_id, level, name_fa, name_en, landline_code, slug, sort_order)
|
||||
SELECT NULL, 'country', v.name_fa, v.name_en, v.landline_code, v.slug, v.sort_order
|
||||
FROM (
|
||||
VALUES
|
||||
('ایران', 'Iran', '98', 'iran', 1),
|
||||
('عراق', 'Iraq', '964', 'iraq', 2),
|
||||
('ترکیه', 'Turkey', '90', 'turkey', 3),
|
||||
('امارات', 'UAE', '971', 'uae', 4)
|
||||
) AS v(name_fa, name_en, landline_code, slug, sort_order)
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM cities c WHERE c.slug = v.slug
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Major cities under country (direct children; province not required)
|
||||
-- Iran cities already exist under provinces — API lists them via country parent.
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO cities (parent_id, level, name_fa, name_en, landline_code, slug, sort_order)
|
||||
SELECT c.id, 'city', v.name_fa, v.name_en, v.landline_code, v.slug, v.sort_order
|
||||
FROM cities c
|
||||
JOIN (
|
||||
VALUES
|
||||
-- Iraq
|
||||
('iraq', 'بغداد', 'Baghdad', '1', 'baghdad', 1),
|
||||
('iraq', 'بصره', 'Basra', '40', 'basra', 2),
|
||||
('iraq', 'اربیل', 'Erbil', '66', 'erbil', 3),
|
||||
('iraq', 'موصل', 'Mosul', '60', 'mosul', 4),
|
||||
('iraq', 'نجف', 'Najaf', '33', 'najaf', 5),
|
||||
('iraq', 'سلیمانیه', 'Sulaymaniyah', '53', 'sulaymaniyah', 6),
|
||||
('iraq', 'کرکوک', 'Kirkuk', '50', 'kirkuk', 7),
|
||||
-- Turkey
|
||||
('turkey', 'استانبول', 'Istanbul', '212', 'istanbul', 1),
|
||||
('turkey', 'آنکارا', 'Ankara', '312', 'ankara', 2),
|
||||
('turkey', 'ازمیر', 'Izmir', '232', 'izmir', 3),
|
||||
('turkey', 'آنتالیا', 'Antalya', '242', 'antalya', 4),
|
||||
('turkey', 'بورسا', 'Bursa', '224', 'bursa', 5),
|
||||
('turkey', 'غازی عینتاب', 'Gaziantep', '342', 'gaziantep', 6),
|
||||
-- UAE
|
||||
('uae', 'دبی', 'Dubai', '4', 'dubai', 1),
|
||||
('uae', 'ابوظبی', 'Abu Dhabi', '2', 'abu-dhabi', 2),
|
||||
('uae', 'شارجه', 'Sharjah', '6', 'sharjah', 3),
|
||||
('uae', 'عجمان', 'Ajman', '6', 'ajman', 4),
|
||||
('uae', 'رأس الخیمه', 'Ras Al Khaimah', '7', 'ras-al-khaimah', 5)
|
||||
) AS v(country_slug, name_fa, name_en, landline_code, slug, sort_order)
|
||||
ON c.slug = v.country_slug AND c.level = 'country'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM cities x WHERE x.slug = v.slug
|
||||
);
|
||||
@@ -0,0 +1,113 @@
|
||||
-- Seed Iran provinces + cities if missing (004_iran_cities may never have been applied).
|
||||
-- Iran country row is expected from 053 (or earlier).
|
||||
|
||||
-- Provinces under Iran
|
||||
INSERT INTO cities (parent_id, level, name_fa, name_en, landline_code, slug, sort_order)
|
||||
SELECT c.id, 'province', v.name_fa, v.name_en, v.landline_code, v.slug, v.sort_order
|
||||
FROM cities c
|
||||
CROSS JOIN (
|
||||
VALUES
|
||||
('آذربایجان شرقی', 'East Azerbaijan', '041', 'east-azerbaijan', 1),
|
||||
('آذربایجان غربی', 'West Azerbaijan', '044', 'west-azerbaijan', 2),
|
||||
('اردبیل', 'Ardabil', '045', 'ardabil', 3),
|
||||
('اصفهان', 'Isfahan', '031', 'isfahan', 4),
|
||||
('البرز', 'Alborz', '026', 'alborz', 5),
|
||||
('ایلام', 'Ilam', '084', 'ilam', 6),
|
||||
('بوشهر', 'Bushehr', '077', 'bushehr', 7),
|
||||
('تهران', 'Tehran', '021', 'tehran-province', 8),
|
||||
('چهارمحال و بختیاری', 'Chaharmahal and Bakhtiari', '038', 'chaharmahal-bakhtiari', 9),
|
||||
('خراسان جنوبی', 'South Khorasan', '056', 'south-khorasan', 10),
|
||||
('خراسان رضوی', 'Razavi Khorasan', '051', 'razavi-khorasan', 11),
|
||||
('خراسان شمالی', 'North Khorasan', '058', 'north-khorasan', 12),
|
||||
('خوزستان', 'Khuzestan', '061', 'khuzestan', 13),
|
||||
('زنجان', 'Zanjan', '024', 'zanjan', 14),
|
||||
('سمنان', 'Semnan', '023', 'semnan', 15),
|
||||
('سیستان و بلوچستان', 'Sistan and Baluchestan', '054', 'sistan-baluchestan', 16),
|
||||
('فارس', 'Fars', '071', 'fars', 17),
|
||||
('قزوین', 'Qazvin', '028', 'qazvin', 18),
|
||||
('قم', 'Qom', '025', 'qom', 19),
|
||||
('کردستان', 'Kurdistan', '087', 'kurdistan', 20),
|
||||
('کرمان', 'Kerman', '034', 'kerman', 21),
|
||||
('کرمانشاه', 'Kermanshah', '083', 'kermanshah', 22),
|
||||
('کهگیلویه و بویراحمد', 'Kohgiluyeh and Boyer-Ahmad', '074', 'kohgiluyeh-boyer-ahmad', 23),
|
||||
('گلستان', 'Golestan', '017', 'golestan', 24),
|
||||
('گیلان', 'Gilan', '013', 'gilan', 25),
|
||||
('لرستان', 'Lorestan', '066', 'lorestan', 26),
|
||||
('مازندران', 'Mazandaran', '011', 'mazandaran', 27),
|
||||
('مرکزی', 'Markazi', '086', 'markazi', 28),
|
||||
('هرمزگان', 'Hormozgan', '076', 'hormozgan', 29),
|
||||
('همدان', 'Hamadan', '081', 'hamadan', 30),
|
||||
('یزد', 'Yazd', '035', 'yazd', 31)
|
||||
) AS v(name_fa, name_en, landline_code, slug, sort_order)
|
||||
WHERE c.slug = 'iran' AND c.level = 'country'
|
||||
AND NOT EXISTS (SELECT 1 FROM cities x WHERE x.slug = v.slug);
|
||||
|
||||
-- Provincial capitals
|
||||
INSERT INTO cities (parent_id, level, name_fa, name_en, landline_code, slug, sort_order)
|
||||
SELECT p.id, 'city', v.name_fa, v.name_en, v.landline_code, v.slug, v.sort_order
|
||||
FROM cities p
|
||||
JOIN (
|
||||
VALUES
|
||||
('east-azerbaijan', 'تبریز', 'Tabriz', '041', 'tabriz', 1),
|
||||
('west-azerbaijan', 'ارومیه', 'Urmia', '044', 'urmia', 1),
|
||||
('ardabil', 'اردبیل', 'Ardabil', '045', 'ardabil-city', 1),
|
||||
('isfahan', 'اصفهان', 'Isfahan', '031', 'isfahan-city', 1),
|
||||
('alborz', 'کرج', 'Karaj', '026', 'karaj', 1),
|
||||
('ilam', 'ایلام', 'Ilam', '084', 'ilam-city', 1),
|
||||
('bushehr', 'بوشهر', 'Bushehr', '077', 'bushehr-city', 1),
|
||||
('tehran-province', 'تهران', 'Tehran', '021', 'tehran', 1),
|
||||
('chaharmahal-bakhtiari', 'شهرکرد', 'Shahrekord', '038', 'shahrekord', 1),
|
||||
('south-khorasan', 'بیرجند', 'Birjand', '056', 'birjand', 1),
|
||||
('razavi-khorasan', 'مشهد', 'Mashhad', '051', 'mashhad', 1),
|
||||
('north-khorasan', 'بجنورد', 'Bojnord', '058', 'bojnord', 1),
|
||||
('khuzestan', 'اهواز', 'Ahvaz', '061', 'ahvaz', 1),
|
||||
('zanjan', 'زنجان', 'Zanjan', '024', 'zanjan-city', 1),
|
||||
('semnan', 'سمنان', 'Semnan', '023', 'semnan-city', 1),
|
||||
('sistan-baluchestan', 'زاهدان', 'Zahedan', '054', 'zahedan', 1),
|
||||
('fars', 'شیراز', 'Shiraz', '071', 'shiraz', 1),
|
||||
('qazvin', 'قزوین', 'Qazvin', '028', 'qazvin-city', 1),
|
||||
('qom', 'قم', 'Qom', '025', 'qom-city', 1),
|
||||
('kurdistan', 'سنندج', 'Sanandaj', '087', 'sanandaj', 1),
|
||||
('kerman', 'کرمان', 'Kerman', '034', 'kerman-city', 1),
|
||||
('kermanshah', 'کرمانشاه', 'Kermanshah', '083', 'kermanshah-city', 1),
|
||||
('kohgiluyeh-boyer-ahmad', 'یاسوج', 'Yasuj', '074', 'yasuj', 1),
|
||||
('golestan', 'گرگان', 'Gorgan', '017', 'gorgan', 1),
|
||||
('gilan', 'رشت', 'Rasht', '013', 'rasht', 1),
|
||||
('lorestan', 'خرمآباد', 'Khorramabad', '066', 'khorramabad', 1),
|
||||
('mazandaran', 'ساری', 'Sari', '011', 'sari', 1),
|
||||
('markazi', 'اراک', 'Arak', '086', 'arak', 1),
|
||||
('hormozgan', 'بندرعباس', 'Bandar Abbas', '076', 'bandar-abbas', 1),
|
||||
('hamadan', 'همدان', 'Hamadan', '081', 'hamadan-city', 1),
|
||||
('yazd', 'یزد', 'Yazd', '035', 'yazd-city', 1)
|
||||
) AS v(province_slug, name_fa, name_en, landline_code, slug, sort_order)
|
||||
ON p.slug = v.province_slug AND p.level = 'province'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM cities x WHERE x.slug = v.slug);
|
||||
|
||||
-- Additional major cities
|
||||
INSERT INTO cities (parent_id, level, name_fa, name_en, landline_code, slug, sort_order)
|
||||
SELECT p.id, 'city', v.name_fa, v.name_en, v.landline_code, v.slug, v.sort_order
|
||||
FROM cities p
|
||||
JOIN (
|
||||
VALUES
|
||||
('tehran-province', 'ری', 'Rey', '021', 'rey', 2),
|
||||
('tehran-province', 'شهریار', 'Shahriar', '021', 'shahriar', 3),
|
||||
('tehran-province', 'ورامین', 'Varamin', '021', 'varamin', 4),
|
||||
('isfahan', 'کاشان', 'Kashan', '031', 'kashan', 2),
|
||||
('isfahan', 'نجفآباد', 'Najafabad', '031', 'najafabad', 3),
|
||||
('fars', 'مرودشت', 'Marvdasht', '071', 'marvdasht', 2),
|
||||
('fars', 'جهرم', 'Jahrom', '071', 'jahrom', 3),
|
||||
('khuzestan', 'آبادان', 'Abadan', '061', 'abadan', 2),
|
||||
('khuzestan', 'دزفول', 'Dezful', '061', 'dezful', 3),
|
||||
('razavi-khorasan', 'نیشابور', 'Neyshabur', '051', 'neyshabur', 2),
|
||||
('razavi-khorasan', 'سبزوار', 'Sabzevar', '051', 'sabzevar', 3),
|
||||
('mazandaran', 'آمل', 'Amol', '011', 'amol', 2),
|
||||
('mazandaran', 'بابل', 'Babol', '011', 'babol', 3),
|
||||
('gilan', 'انزلی', 'Bandar Anzali', '013', 'bandar-anzali', 2),
|
||||
('east-azerbaijan', 'مراغه', 'Maragheh', '041', 'maragheh', 2),
|
||||
('kerman', 'رفسنجان', 'Rafsanjan', '034', 'rafsanjan', 2),
|
||||
('alborz', 'فردیس', 'Fardis', '026', 'fardis', 2)
|
||||
) AS v(province_slug, name_fa, name_en, landline_code, slug, sort_order)
|
||||
ON p.slug = v.province_slug AND p.level = 'province'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM cities x WHERE x.slug = v.slug);
|
||||
|
||||
SELECT setval(pg_get_serial_sequence('cities', 'id'), COALESCE((SELECT MAX(id) FROM cities), 1));
|
||||
@@ -0,0 +1,18 @@
|
||||
-- User product listing extras: currency, delivery note, condition, technical notes
|
||||
|
||||
CREATE TYPE user_product_condition AS ENUM (
|
||||
'new',
|
||||
'stock',
|
||||
'needs_repair',
|
||||
'scrap'
|
||||
);
|
||||
|
||||
ALTER TABLE user_products
|
||||
ADD COLUMN IF NOT EXISTS price_currency VARCHAR(8) NOT NULL DEFAULT 'IRT',
|
||||
ADD COLUMN IF NOT EXISTS delivery_note TEXT,
|
||||
ADD COLUMN IF NOT EXISTS condition user_product_condition NOT NULL DEFAULT 'new',
|
||||
ADD COLUMN IF NOT EXISTS technical_notes TEXT;
|
||||
|
||||
ALTER TABLE user_products
|
||||
ADD CONSTRAINT user_products_price_currency_format
|
||||
CHECK (price_currency ~ '^[A-Z]{3,8}$');
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE content_status ADD VALUE IF NOT EXISTS 'rejected';
|
||||
Reference in New Issue
Block a user