From beb94d2b0d70e57b7b30f49454ed6a498d4d203d Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 30 Mar 2026 20:35:59 +0300 Subject: [PATCH] fix(db): Added db to actual price --- db/DBDataUtils.py | 122 +++++++++++++++++----- db/InitializeDBData.py | 178 +++++++++++++++++++++++++------- db/handlers/catigory_handler.py | 71 +++++++++++-- db/handlers/product_handler.py | 127 ++++++++++++----------- 4 files changed, 364 insertions(+), 134 deletions(-) diff --git a/db/DBDataUtils.py b/db/DBDataUtils.py index f36a27b..ea2ec19 100644 --- a/db/DBDataUtils.py +++ b/db/DBDataUtils.py @@ -23,21 +23,29 @@ def add_category(conn, name, description=None, parent_id=None, image_path=None): def add_filter(conn, name, filter_key, filter_type='single'): cursor = conn.cursor() - cursor.execute(''' - INSERT OR IGNORE INTO filters (name, filter_key, filter_type) - VALUES (?, ?, ?) - ''', (name, filter_key, filter_type)) + try: + cursor.execute(''' + INSERT OR IGNORE INTO filters (name, filter_key, filter_type) + VALUES (?, ?, ?) + ''', (name, filter_key, filter_type)) + except sqlite3.Error as e: + log.error(f"Ошибка при добавлении фильтра: {e}") def parse_product_data(product_text): + """Парсинг данных продукта из текста""" + # Определяем тип применения application_match = re.search(r'(ВНУТРЕННЕЙ|НАРУЖНОЙ)', product_text) application_type = "внутренняя" if application_match and application_match.group(1) == "ВНУТРЕННЕЙ" else "наружная" + # Определяем цвет color_match = re.search(r'цвет\s+([^)]+)', product_text) color = color_match.group(1).strip() if color_match else None + # Определяем класс жесткости stiffness_match = re.search(r'SN(\d+)', product_text) stiffness_class = f"SN{stiffness_match.group(1)}" if stiffness_match else None + # Определяем размеры size_match = re.search(r'(\d+)х(\d+[,.]?\d*)х(\d+)', product_text.replace(',', '.')) if size_match: diameter = int(size_match.group(1)) @@ -46,7 +54,16 @@ def parse_product_data(product_text): else: diameter = wall_thickness = length = None - short_name = f"Труба ПВХ {diameter}мм {application_type} {length}мм" + # Для фитингов может не быть длины + if not length and diameter: + # Проверяем на отводы + angle_match = re.search(r'(\d+)°', product_text) + if angle_match: + length = None + else: + length = 0 + + short_name = f"Труба ПВХ {diameter}мм {application_type} {length}мм" if diameter else product_text[:50] return { 'short_name': short_name, @@ -59,11 +76,53 @@ def parse_product_data(product_text): 'stiffness_class': stiffness_class } -def add_product(conn, product_text, category_id, image_path=None): - """Добавление товара с парсингом параметров и изображением""" +def add_product(conn, product_text, category_id, image_path=None, + diameter=None, wall_thickness=None, length=None, + color=None, application_type=None, stiffness_class=None, + fitting_type=None, angle=None): + """ + Добавление товара с возможностью явного указания параметров + Если параметры не указаны, они парсятся из product_text + """ cursor = conn.cursor() - product_data = parse_product_data(product_text) + # Если параметры не указаны явно, парсим из текста + if any(p is None for p in [diameter, wall_thickness, length, color, application_type, stiffness_class]): + product_data = parse_product_data(product_text) + diameter = diameter or product_data['diameter'] + wall_thickness = wall_thickness or product_data['wall_thickness'] + length = length or product_data['length'] + color = color or product_data['color'] + application_type = application_type or product_data['application_type'] + stiffness_class = stiffness_class or product_data['stiffness_class'] + + # Формируем короткое имя + if diameter and length: + name = f"Труба ПВХ {diameter}мм {application_type} {length}мм" + elif fitting_type and diameter: + name = f"{fitting_type.capitalize()} ПВХ {diameter}мм" + else: + name = product_text[:100] + + # Формируем описание + description_parts = [] + if fitting_type: + description_parts.append(f"{fitting_type.capitalize()} для канализационных систем") + else: + description_parts.append(f"Труба ПВХ для {application_type} канализации") + + if diameter: + description_parts.append(f"Диаметр: {diameter}мм") + if wall_thickness: + description_parts.append(f"Толщина стенки: {wall_thickness}мм") + if length and length > 0: + description_parts.append(f"Длина: {length}мм") + if stiffness_class: + description_parts.append(f"Класс жесткости: {stiffness_class}") + if angle: + description_parts.append(f"Угол: {angle}") + + description = ", ".join(description_parts) try: cursor.execute(''' @@ -73,33 +132,40 @@ def add_product(conn, product_text, category_id, image_path=None): application_type, stiffness_class, image_path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( - product_data['short_name'], - product_data['full_name'], - f"Труба ПВХ для {product_data['application_type']} канализации", + name, + product_text, + description, category_id, - product_data['diameter'], - product_data['wall_thickness'], - product_data['length'], - product_data['color'], - product_data['application_type'], - product_data['stiffness_class'], + diameter, + wall_thickness, + length if length and length > 0 else None, + color, + application_type, + stiffness_class, image_path )) product_id = cursor.lastrowid - filters_to_add = [ - ('diameter', str(product_data['diameter'])), - ('length', str(product_data['length'])), - ('application_type', product_data['application_type']), - ('color', product_data['color']), - ] + # Добавляем фильтры для товара + filters_to_add = [] - if product_data['wall_thickness']: - filters_to_add.append(('wall_thickness', str(product_data['wall_thickness']))) - - if product_data['stiffness_class']: - filters_to_add.append(('stiffness_class', product_data['stiffness_class'])) + if diameter: + filters_to_add.append(('diameter', str(diameter))) + if length and length > 0: + filters_to_add.append(('length', str(length))) + if application_type: + filters_to_add.append(('application_type', application_type)) + if color: + filters_to_add.append(('color', color)) + if wall_thickness: + filters_to_add.append(('wall_thickness', str(wall_thickness))) + if stiffness_class: + filters_to_add.append(('stiffness_class', stiffness_class)) + if fitting_type: + filters_to_add.append(('fitting_type', fitting_type)) + if angle: + filters_to_add.append(('angle', angle)) for filter_key, value in filters_to_add: if value: diff --git a/db/InitializeDBData.py b/db/InitializeDBData.py index fe93abe..ed6c2ad 100644 --- a/db/InitializeDBData.py +++ b/db/InitializeDBData.py @@ -19,6 +19,7 @@ def init_tables(db_name='pipe_store.db'): log.info("Начинаем инициализацию базы категорий...") + # Основная категория main_category_id = add_category( conn, "Трубы ПВХ", @@ -26,6 +27,7 @@ def init_tables(db_name='pipe_store.db'): image_path="/images/categories/pvc_pipes_main.jpg" ) + # Подкатегории для труб internal_category_id = add_category( conn, "Для внутренней канализации", @@ -42,7 +44,8 @@ def init_tables(db_name='pipe_store.db'): image_path="/images/categories/external_pipes.jpg" ) - add_category( + # Категория для фитингов + fittings_category_id = add_category( conn, "Фитинги для ПВХ труб", "Соединительные элементы для ПВХ труб", @@ -50,63 +53,168 @@ def init_tables(db_name='pipe_store.db'): image_path="/images/categories/fittings.jpg" ) - add_category( + # Подкатегории для фитингов + elbows_category_id = add_category( conn, "Колена и отводы", "Угловые соединения для ПВХ труб", - main_category_id, + fittings_category_id, image_path="/images/categories/elbows.jpg" ) + tee_category_id = add_category( + conn, + "Тройники", + "Тройники для разветвления труб", + fittings_category_id, + image_path="/images/categories/tees.jpg" + ) + + couplings_category_id = add_category( + conn, + "Муфты и переходы", + "Соединительные муфты и переходники", + fittings_category_id, + image_path="/images/categories/couplings.jpg" + ) + + accessories_category_id = add_category( + conn, + "Заглушки и ревизии", + "Заглушки и ревизионные элементы", + fittings_category_id, + image_path="/images/categories/accessories.jpg" + ) + log.info("Категории успешно созданы") + # Добавляем фильтры add_filter(conn, "Диаметр", "diameter", "multiple") add_filter(conn, "Длина", "length", "multiple") add_filter(conn, "Тип применения", "application_type", "single") add_filter(conn, "Цвет", "color", "single") add_filter(conn, "Класс жесткости", "stiffness_class", "single") add_filter(conn, "Толщина стенки", "wall_thickness", "multiple") + add_filter(conn, "Угол", "angle", "multiple") # Для отводов и колен + add_filter(conn, "Тип фитинга", "fitting_type", "single") # Для фитингов log.info("Фильтры успешно добавлены") - # Данные продуктов - products_data = [ - # Внутренние трубы - {"text": "Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет серый), с внутренней структурной стенкой толщиной 2,2 мм 110х2,2х500", "image": "/images/products/internal_110_500.jpg"}, - {"text": "Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет серый), с внутренней структурной стенкой толщиной 2,2 мм 110х2,2х1000", "image": "/images/products/internal_110_1000.jpg"}, - {"text": "Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет серый), с внутренней структурной стенкой толщиной 2,2 мм 110х2,2х1500", "image": "/images/products/internal_110_1500.jpg"}, - {"text": "Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет серый), с внутренней структурной стенкой толщиной 2,2 мм 110х2,2х2000", "image": "/images/products/internal_110_2000.jpg"}, - {"text": "Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет серый), с внутренней структурной стенкой толщиной 2,2 мм 110х2,2х3000", "image": "/images/products/internal_110_3000.jpg"}, - - # Наружные трубы - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN4 110х3,2х500", "image": "/images/products/external_110_sn4_500.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN4 110х3,2х1000", "image": "/images/products/external_110_sn4_1000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN4 110х3,2х2000", "image": "/images/products/external_110_sn4_2000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN4 110х3,2х3000", "image": "/images/products/external_110_sn4_3000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN4 110х3,2х4000", "image": "/images/products/external_110_sn4_4000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN2 160х3,6х1000", "image": "/images/products/external_160_sn2_1000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN2 160х3,6х2000", "image": "/images/products/external_160_sn2_2000.jpg"}, - {"text": "Труба ПВХ для НАРУЖНОЙ канализации (цвет оранжево-коричневый), с внутренней структурной стенкой, класс жесткости SN2 160х3,6х3000", "image": "/images/products/external_160_sn2_3000.jpg"}, + # ==================== ТОВАРЫ ==================== + + # 1. Внутренние трубы (серые) + internal_pipes = [ + ("110х2,2х500", 110, 2.2, 500, "серый", "внутренняя", None), + ("110х2,2х1000", 110, 2.2, 1000, "серый", "внутренняя", None), + ("110х2,2х1500", 110, 2.2, 1500, "серый", "внутренняя", None), + ("110х2,2х2000", 110, 2.2, 2000, "серый", "внутренняя", None), + ("110х2,2х3000", 110, 2.2, 3000, "серый", "внутренняя", None), ] - + added_products = 0 - for product_info in products_data: - product_text = product_info["text"] - image_path = product_info["image"] + + for size, diameter, thickness, length, color, app_type, stiffness in internal_pipes: + full_name = f"Труба ПВХ для ВНУТРЕННЕЙ канализации (цвет {color}), со сплошной стенкой толщиной {thickness} мм {diameter}x{thickness}x{length}" + image_path = f"/images/products/internal_{diameter}_{length}.jpg" - if "ВНУТРЕННЕЙ" in product_text: - category_id = internal_category_id - else: - category_id = external_category_id - - product_id = add_product(conn, product_text, category_id, image_path) + product_id = add_product( + conn, full_name, internal_category_id, image_path, + diameter, thickness, length, color, app_type, stiffness + ) if product_id: added_products += 1 - log.info(f"Добавлен товар: {product_text[:50]}...") - else: - log.error(f"Ошибка при добавлении товара: {product_text}") + log.info(f"Добавлен товар: {full_name[:50]}...") + + # 2. Наружные трубы (оранжево-коричневые) - все типы + external_pipes = [ + # Без маркировки (обычные) + ("110х2,3х500", 110, 2.3, 500, "оранжево-коричневый", "наружная", None), + ("110х2,3х1000", 110, 2.3, 1000, "оранжево-коричневый", "наружная", None), + ("110х2,3х2000", 110, 2.3, 2000, "оранжево-коричневый", "наружная", None), + ("110х2,3х3000", 110, 2.3, 3000, "оранжево-коричневый", "наружная", None), + ("110х2,3х4000", 110, 2.3, 4000, "оранжево-коричневый", "наружная", None), + # SN2 + ("110х2,7х500 SN2", 110, 2.7, 500, "оранжево-коричневый", "наружная", "SN2"), + ("110х2,7х1000 SN2", 110, 2.7, 1000, "оранжево-коричневый", "наружная", "SN2"), + ("110х2,7х2000 SN2", 110, 2.7, 2000, "оранжево-коричневый", "наружная", "SN2"), + ("110х2,7х3000 SN2", 110, 2.7, 3000, "оранжево-коричневый", "наружная", "SN2"), + ("110х2,7х4000 SN2", 110, 2.7, 4000, "оранжево-коричневый", "наружная", "SN2"), + # SN4 + ("110х3,2х500 SN4", 110, 3.2, 500, "оранжево-коричневый", "наружная", "SN4"), + ("110х3,2х1000 SN4", 110, 3.2, 1000, "оранжево-коричневый", "наружная", "SN4"), + ("110х3,2х2000 SN4", 110, 3.2, 2000, "оранжево-коричневый", "наружная", "SN4"), + ("110х3,2х3000 SN4", 110, 3.2, 3000, "оранжево-коричневый", "наружная", "SN4"), + ("110х3,2х4000 SN4", 110, 3.2, 4000, "оранжево-коричневый", "наружная", "SN4"), + # 160 мм + ("160х3,6х1000 SN2", 160, 3.6, 1000, "оранжево-коричневый", "наружная", "SN2"), + ("160х3,6х2000 SN2", 160, 3.6, 2000, "оранжево-коричневый", "наружная", "SN2"), + ("160х3,6х3000 SN2", 160, 3.6, 3000, "оранжево-коричневый", "наружная", "SN2"), + ("160х4,0х1000 SN4", 160, 4.0, 1000, "оранжево-коричневый", "наружная", "SN4"), + ("160х4,0х2000 SN4", 160, 4.0, 2000, "оранжево-коричневый", "наружная", "SN4"), + ("160х4,0х3000 SN4", 160, 4.0, 3000, "оранжево-коричневый", "наружная", "SN4"), + ] + + for size, diameter, thickness, length, color, app_type, stiffness in external_pipes: + stiffness_text = f", класс жесткости {stiffness}" if stiffness else "" + full_name = f"Труба ПВХ для НАРУЖНОЙ канализации (цвет {color}), со сплошной стенкой{stiffness_text} {diameter}x{thickness}x{length}" + image_path = f"/images/products/external_{diameter}_{stiffness or 'std'}_{length}.jpg" + + product_id = add_product( + conn, full_name, external_category_id, image_path, + diameter, thickness, length, color, app_type, stiffness + ) + if product_id: + added_products += 1 + log.info(f"Добавлен товар: {full_name[:50]}...") + + # 3. Фитинги + fittings = [ + # Отводы (колена) + ("Отвод 110х15°", elbows_category_id, "отвод", 110, None, None, None, None, "15°"), + ("Отвод 110х30°", elbows_category_id, "отвод", 110, None, None, None, None, "30°"), + ("Отвод 110х45°", elbows_category_id, "отвод", 110, None, None, None, None, "45°"), + ("Отвод 110х87°", elbows_category_id, "отвод", 110, None, None, None, None, "87°"), + ("Отвод 160х15°", elbows_category_id, "отвод", 160, None, None, None, None, "15°"), + ("Отвод 160х30°", elbows_category_id, "отвод", 160, None, None, None, None, "30°"), + ("Отвод 160х45°", elbows_category_id, "отвод", 160, None, None, None, None, "45°"), + ("Отвод 160х87°", elbows_category_id, "отвод", 160, None, None, None, None, "87°"), + + # Тройники + ("Тройник 45° 110х110", tee_category_id, "тройник", 110, None, None, None, None, "45°"), + ("Тройник 45° 160х110", tee_category_id, "тройник", 160, None, None, None, None, "45°"), + ("Тройник 45° 160х160", tee_category_id, "тройник", 160, None, None, None, None, "45°"), + ("Тройник 87° 110х110", tee_category_id, "тройник", 110, None, None, None, None, "87°"), + ("Тройник 87° 160х110", tee_category_id, "тройник", 160, None, None, None, None, "87°"), + ("Тройник 87° 160х160", tee_category_id, "тройник", 160, None, None, None, None, "87°"), + + # Муфты + ("Муфта надвижная (ремонтная) 110", couplings_category_id, "муфта", 110, None, None, None, None, None), + ("Муфта надвижная (ремонтная) 160", couplings_category_id, "муфта", 160, None, None, None, None, None), + ("Муфта соединительная 110", couplings_category_id, "муфта", 110, None, None, None, None, None), + ("Муфта соединительная 160", couplings_category_id, "муфта", 160, None, None, None, None, None), + ("Редуктор 160", couplings_category_id, "редуктор", 160, None, None, None, None, None), + + # Заглушки и ревизии + ("Заглушка для раструба 110", accessories_category_id, "заглушка", 110, None, None, None, None, None), + ("Заглушка для раструба 160", accessories_category_id, "заглушка", 160, None, None, None, None, None), + ("Ревизия 110", accessories_category_id, "ревизия", 110, None, None, None, None, None), + ("Ревизия 160", accessories_category_id, "ревизия", 160, None, None, None, None, None), + ] + + for name, cat_id, fitting_type, diameter, thickness, length, color, app_type, angle in fittings: + full_name = f"{name} для наружной канализации" + image_path = f"/images/products/{name.lower().replace(' ', '_').replace('°', 'deg')}.jpg" + + product_id = add_product( + conn, full_name, cat_id, image_path, + diameter, thickness, length, color, app_type, None, + fitting_type=fitting_type, angle=angle + ) + if product_id: + added_products += 1 + log.info(f"Добавлен товар: {full_name[:50]}...") conn.commit() conn.close() - log.success(f"Успешно добавлено {added_products} товаров в базу категорий!") + log.success(f"Успешно добавлено {added_products} товаров в базу данных!") diff --git a/db/handlers/catigory_handler.py b/db/handlers/catigory_handler.py index 28c81f5..18f320b 100644 --- a/db/handlers/catigory_handler.py +++ b/db/handlers/catigory_handler.py @@ -12,7 +12,7 @@ def get_all_categories_with_attributes(db_name: str = 'pipe_store.db') -> List[D cursor.execute(""" SELECT id, name, image_path FROM categories - WHERE parent_id IS NULL OR parent_id = 1 + WHERE parent_id IS NULL ORDER BY id """) @@ -21,7 +21,7 @@ def get_all_categories_with_attributes(db_name: str = 'pipe_store.db') -> List[D for cat_row in cursor.fetchall(): category_id = cat_row['id'] - # Получаем все фильтры для товаров в этой категории + # Получаем все фильтры для товаров в этой категории и подкатегориях cursor.execute(""" SELECT DISTINCT f.id, f.name, f.filter_key FROM filters f @@ -29,10 +29,13 @@ def get_all_categories_with_attributes(db_name: str = 'pipe_store.db') -> List[D SELECT DISTINCT pf.filter_key FROM product_filters pf JOIN products p ON pf.product_id = p.id - WHERE p.category_id = ? + WHERE p.category_id IN ( + SELECT id FROM categories + WHERE id = ? OR parent_id = ? + ) ) ORDER BY f.id - """, (category_id,)) + """, (category_id, category_id)) attributes = [] @@ -46,21 +49,24 @@ def get_all_categories_with_attributes(db_name: str = 'pipe_store.db') -> List[D SELECT DISTINCT pf.value, COUNT(*) as count FROM product_filters pf JOIN products p ON pf.product_id = p.id - WHERE p.category_id = ? AND pf.filter_key = ? + WHERE p.category_id IN ( + SELECT id FROM categories + WHERE id = ? OR parent_id = ? + ) + AND pf.filter_key = ? GROUP BY pf.value ORDER BY pf.value - """, (category_id, filter_key)) + """, (category_id, category_id, filter_key)) vals = [] for val_row in cursor.fetchall(): - # Генерируем уникальный ID для значения val_id = hash(f"{category_id}_{filter_key}_{val_row['value']}") % 1000000 vals.append({ "id": val_id, "val": val_row['value'] }) - if vals: # Добавляем только если есть значения + if vals: attributes.append({ "id": filter_id, "name": filter_name, @@ -97,12 +103,28 @@ def get_category_by_id(category_id: int, db_name: str = 'pipe_store.db') -> Opti row = cursor.fetchone() if row: + # Получаем подкатегории + cursor.execute(""" + SELECT id, name, image_path + FROM categories + WHERE parent_id = ? + """, (category_id,)) + + subcategories = [] + for sub_row in cursor.fetchall(): + subcategories.append({ + "id": sub_row['id'], + "name": sub_row['name'], + "image": sub_row['image_path'] + }) + return { "id": row['id'], "name": row['name'], "description": row['description'], "image": row['image_path'], - "parent_id": row['parent_id'] + "parent_id": row['parent_id'], + "subcategories": subcategories } return None @@ -111,3 +133,34 @@ def get_category_by_id(category_id: int, db_name: str = 'pipe_store.db') -> Opti return None finally: conn.close() + +def get_subcategories(parent_id: int, db_name: str = 'pipe_store.db') -> List[Dict[str, Any]]: + """Получить подкатегории для родительской категории""" + conn = sqlite3.connect(db_name) + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + + try: + cursor.execute(""" + SELECT id, name, description, image_path + FROM categories + WHERE parent_id = ? + ORDER BY id + """, (parent_id,)) + + subcategories = [] + for row in cursor.fetchall(): + subcategories.append({ + "id": row['id'], + "name": row['name'], + "description": row['description'], + "image": row['image_path'] + }) + + return subcategories + + except sqlite3.Error as e: + log.error(f"Ошибка при получении подкатегорий для {parent_id}: {e}") + return [] + finally: + conn.close() diff --git a/db/handlers/product_handler.py b/db/handlers/product_handler.py index 8c24bfe..06bb4df 100644 --- a/db/handlers/product_handler.py +++ b/db/handlers/product_handler.py @@ -77,11 +77,13 @@ def get_products_with_filters( # Формируем атрибуты товара attributes = {} - # Добавляем все возможные атрибуты if row['color']: attributes['color'] = row['color'] - if row['length']: - attributes['size'] = f"{row['diameter']}x{row['wall_thickness']}x{row['length']}" if row['diameter'] else str(row['length']) + if row['length'] and row['length'] > 0: + if row['diameter'] and row['wall_thickness']: + attributes['size'] = f"{row['diameter']}x{row['wall_thickness']}x{row['length']}" + else: + attributes['size'] = str(row['length']) if row['diameter']: attributes['diameter'] = str(row['diameter']) if row['wall_thickness']: @@ -91,18 +93,30 @@ def get_products_with_filters( if row['application_type']: attributes['application_type'] = row['application_type'] + # Получаем дополнительные атрибуты из product_filters + cursor.execute(""" + SELECT filter_key, value + FROM product_filters + WHERE product_id = ? + """, (row['id'],)) + + for filter_row in cursor.fetchall(): + if filter_row['filter_key'] not in attributes: + attributes[filter_row['filter_key']] = filter_row['value'] + # Определяем количество в упаковке (можно вынести в отдельную таблицу) - attributes['amount'] = get_pack_amount(row['id'], conn) + attributes['amount'] = get_pack_amount(row['id'], row['diameter'], conn) items.append({ "id": row['id'], "name": row['name'], - "description": row['description'] or f"Труба ПВХ {row['diameter']}мм", - "price": calculate_price(row), # Функция для расчета цены + "description": row['description'] or f"Труба ПВХ {row['diameter']}мм" if row['diameter'] else "Товар", + # Цена не хранится в БД - возвращаем 0 или None + "price": None, "categoryId": category_id, "images": get_product_images(row['id'], row['image_path'], conn), "attributes": attributes, - "inStock": check_stock(row['id'], conn) # Проверка наличия + "inStock": check_stock(row['id'], conn) }) return { @@ -122,13 +136,6 @@ def get_products_with_filters( def get_product_by_id(product_id: int, db_name: str = 'pipe_store.db') -> Optional[Dict[str, Any]]: """ Получить товар по ID с полной информацией - - Args: - product_id: ID товара - db_name: Имя базы данных - - Returns: - Dict с полной информацией о товаре или None """ conn = sqlite3.connect(db_name) conn.row_factory = sqlite3.Row @@ -148,29 +155,46 @@ def get_product_by_id(product_id: int, db_name: str = 'pipe_store.db') -> Option if not row: return None - # Получаем все изображения товара (если есть несколько) images = get_product_images(product_id, row['image_path'], conn) - # Формируем полное описание + # Получаем дополнительные фильтры + cursor.execute(""" + SELECT filter_key, value + FROM product_filters + WHERE product_id = ? + """, (product_id,)) + + extra_attributes = {} + for filter_row in cursor.fetchall(): + extra_attributes[filter_row['filter_key']] = filter_row['value'] + full_description = generate_full_description(row) + # Формируем атрибуты + attributes = { + "color": row['color'], + "diameter": str(row['diameter']) if row['diameter'] else None, + "wall_thickness": str(row['wall_thickness']) if row['wall_thickness'] else None, + "length": str(row['length']) if row['length'] and row['length'] > 0 else None, + "stiffness_class": row['stiffness_class'], + "application_type": row['application_type'], + } + + if all([row['diameter'], row['wall_thickness'], row['length'] and row['length'] > 0]): + attributes["size"] = f"{row['diameter']}x{row['wall_thickness']}x{row['length']}" + + # Добавляем дополнительные атрибуты + attributes.update(extra_attributes) + return { "id": row['id'], "name": row['name'], "full_name": row['full_name'], "description": full_description, - "price": calculate_price(row), + "price": None, # Цена не хранится в БД "categoryId": row['category_id'], "images": images, - "attributes": { - "color": row['color'], - "diameter": str(row['diameter']) if row['diameter'] else None, - "wall_thickness": str(row['wall_thickness']) if row['wall_thickness'] else None, - "length": str(row['length']) if row['length'] else None, - "stiffness_class": row['stiffness_class'], - "application_type": row['application_type'], - "size": f"{row['diameter']}x{row['wall_thickness']}x{row['length']}" if all([row['diameter'], row['wall_thickness'], row['length']]) else None - }, + "attributes": attributes, "inStock": check_stock(product_id, conn), "created_at": row['created_at'] } @@ -182,57 +206,34 @@ def get_product_by_id(product_id: int, db_name: str = 'pipe_store.db') -> Option conn.close() def get_product_images(product_id: int, main_image: Optional[str], conn: sqlite3.Connection) -> List[str]: - """ - Получить список изображений товара - (В текущей структуре только одно изображение, но можно расширить) - """ + """Получить список изображений товара""" images = [] if main_image: images.append(main_image) - # Здесь можно добавить логику для получения дополнительных изображений - # Например, из отдельной таблицы product_images - - # Если нет изображения, возвращаем заглушку if not images: images.append("/images/products/default.jpg") return images -def calculate_price(row: sqlite3.Row) -> float: - """ - Рассчитать цену товара на основе параметров - (В реальном проекте цена должна быть в базе данных) - """ - # Временная логика расчета цены - base_price = 500 - - if row['diameter']: - base_price += (row['diameter'] - 50) * 5 - - if row['length']: - base_price += row['length'] * 0.1 - - if row['stiffness_class'] == 'SN4': - base_price *= 1.2 - - return round(base_price, 2) - def check_stock(product_id: int, conn: sqlite3.Connection) -> bool: - """ - Проверить наличие товара на складе - (В реальном проекте должна быть таблица stock) - """ + """Проверить наличие товара на складе""" # Временная логика - все товары в наличии + # В будущем можно добавить таблицу stock return True -def get_pack_amount(product_id: int, conn: sqlite3.Connection) -> str: +def get_pack_amount(product_id: int, diameter: int = None, conn: sqlite3.Connection = None) -> str: """ Получить количество в упаковке - (В реальном проекте должно быть в базе данных) + В реальном проекте должно быть в базе данных """ - # Временная логика - return "4" + # Временная логика на основе диаметра + if diameter: + if diameter == 110: + return "6-10" + elif diameter == 160: + return "2" + return "1" def generate_full_description(row: sqlite3.Row) -> str: """Сгенерировать полное описание товара""" @@ -247,8 +248,10 @@ def generate_full_description(row: sqlite3.Row) -> str: if row['application_type']: parts.append(f"Тип применения: {row['application_type']} канализация") - if row['diameter'] and row['wall_thickness'] and row['length']: + if row['diameter'] and row['wall_thickness'] and row['length'] and row['length'] > 0: parts.append(f"Размеры: {row['diameter']}x{row['wall_thickness']}x{row['length']} мм") + elif row['diameter']: + parts.append(f"Диаметр: {row['diameter']} мм") if row['stiffness_class']: parts.append(f"Класс жесткости: {row['stiffness_class']}")