from flask import Flask, render_template, send_from_directory, request, redirect, url_for, flash, session import sqlite3 import os from datetime import datetime, timedelta app = Flask(__name__) app.secret_key = 'my_secret_key_12345' # ========== ФИЛЬТР ДЛЯ ФОРМАТИРОВАНИЯ ДАТ ========== @app.template_filter('date_format') def date_format(value): """Преобразует дату из формата YYYY-MM-DD в ДД.ММ.ГГГГ""" if not value: return '-' try: # Если value уже строка, пробуем распарсить if isinstance(value, str) and len(value) >= 10: # Проверяем, что это похоже на дату в формате YYYY-MM-DD if value[4] == '-' and value[7] == '-': year, month, day = value[:10].split('-') return f"{day}.{month}.{year}" return value except: return value def get_db_connection(): conn = sqlite3.connect('partners.db') conn.row_factory = sqlite3.Row return conn def dict_from_row(row): """Преобразует sqlite3.Row в словарь""" if row is None: return None return {key: row[key] for key in row.keys()} def list_from_rows(rows): """Преобразует список sqlite3.Row в список словарей""" return [dict_from_row(row) for row in rows] def calculate_discount(total_amount): """Рассчитывает скидку на основе общей суммы заказов в рублях""" return 0, '0%' def calculate_order_discount(order_amount): """Рассчитывает скидку на текущий заказ в зависимости от его суммы""" return 0 # ========== ГЛАВНАЯ СТРАНИЦА ========== @app.route('/') def index(): # Получаем параметры фильтрации из URL search_query = request.args.get('search', '') client_type = request.args.get('type', 'all') min_rating = request.args.get('rating', '0') sort_by = request.args.get('sort', 'name_asc') conn = get_db_connection() try: # Получаем общее количество всех клиентов (без фильтров) total_count = conn.execute('SELECT COUNT(*) as count FROM Clients').fetchone()['count'] # Базовый SQL запрос для клиентов sql = ''' SELECT c.*, ct.type_name as contractor_type_name, COALESCE(SUM(o.total_amount), 0) as total_amount, COALESCE(SUM(oi.quantity), 0) as total_quantity, COUNT(DISTINCT o.id) as orders_count FROM Clients c LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id LEFT JOIN Orders o ON c.id = o.client_id LEFT JOIN OrderItems oi ON o.id = oi.order_id WHERE 1=1 ''' params = [] # Поиск по названию или ИНН if search_query: sql += " AND (c.name LIKE ? OR c.inn LIKE ?)" params.extend([f'%{search_query}%', f'%{search_query}%']) # Фильтр по типу клиента if client_type != 'all': sql += " AND ct.type_name = ?" params.append(client_type) # Фильтр по минимальному рейтингу if min_rating != '0': sql += " AND c.rating >= ?" params.append(float(min_rating)) # Группировка (обязательно после WHERE) sql += " GROUP BY c.id" # Сортировка if sort_by == 'name_asc': sql += " ORDER BY c.name ASC" elif sort_by == 'name_desc': sql += " ORDER BY c.name DESC" elif sort_by == 'rating_desc': sql += " ORDER BY c.rating DESC" elif sort_by == 'rating_asc': sql += " ORDER BY c.rating ASC" elif sort_by == 'discount_desc': sql += " ORDER BY total_amount DESC" elif sort_by == 'discount_asc': sql += " ORDER BY total_amount ASC" else: sql += " ORDER BY c.name ASC" # Выполняем запрос и преобразуем в словари rows = conn.execute(sql, params).fetchall() clients = list_from_rows(rows) # Добавляем информацию о скидке на основе суммы clients_with_discount = [] for client in clients: total_amount = client['total_amount'] or 0 discount_percent, discount_text = calculate_discount(total_amount) client['total_sales'] = total_amount client['discount_percent'] = discount_percent client['discount'] = discount_percent client['discount_text'] = discount_text clients_with_discount.append(client) conn.close() return render_template('index.html', partners=clients_with_discount, total_count=total_count) except Exception as e: conn.close() print(f"❌ ОШИБКА: {e}") return render_template('index.html', partners=[], total_count=0, error_message=f"Ошибка базы данных: {str(e)}") # ========== МАРШРУТЫ ДЛЯ КЛИЕНТОВ ========== @app.route('/add_client', methods=['GET', 'POST']) def add_client(): if request.method == 'POST': try: name = request.form['name'] director = request.form.get('director', '') email = request.form['email'] phone = request.form.get('phone', '') address = request.form.get('address', '') inn = request.form.get('inn', '') contractor_type_id = request.form['contractor_type_id'] rating = request.form.get('rating', 0.0) conn = get_db_connection() # Проверяем уникальность ИНН if inn: existing = conn.execute('SELECT id FROM Clients WHERE inn = ?', (inn,)).fetchone() if existing: flash('Клиент с таким ИНН уже существует', 'error') conn.close() return redirect(url_for('add_client')) conn.execute(''' INSERT INTO Clients (name, director, email, phone, address, inn, contractor_type_id, rating) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', (name, director, email, phone, address, inn, contractor_type_id, rating)) conn.commit() conn.close() flash('Клиент успешно добавлен!', 'success') return redirect(url_for('index')) except Exception as e: flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('add_client')) # GET запрос conn = get_db_connection() contractor_types = conn.execute('SELECT * FROM ContractorType ORDER BY type_name').fetchall() conn.close() return render_template('add_client.html', contractor_types=contractor_types) @app.route('/edit_client/', methods=['GET', 'POST']) def edit_client(client_id): conn = get_db_connection() if request.method == 'POST': try: name = request.form['name'] director = request.form.get('director', '') email = request.form['email'] phone = request.form.get('phone', '') address = request.form.get('address', '') inn = request.form.get('inn', '') contractor_type_id = request.form['contractor_type_id'] rating = request.form.get('rating', 0.0) # Проверяем уникальность ИНН if inn: existing = conn.execute( 'SELECT id FROM Clients WHERE inn = ? AND id != ?', (inn, client_id) ).fetchone() if existing: flash('Клиент с таким ИНН уже существует', 'error') conn.close() return redirect(url_for('edit_client', client_id=client_id)) conn.execute(''' UPDATE Clients SET name = ?, director = ?, email = ?, phone = ?, address = ?, inn = ?, contractor_type_id = ?, rating = ? WHERE id = ? ''', (name, director, email, phone, address, inn, contractor_type_id, rating, client_id)) conn.commit() conn.close() flash('Данные обновлены!', 'success') return redirect(url_for('index')) except Exception as e: flash(f'Ошибка: {str(e)}', 'error') conn.close() return redirect(url_for('edit_client', client_id=client_id)) # GET запрос client_row = conn.execute(''' SELECT c.*, ct.type_name as contractor_type_name FROM Clients c LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id WHERE c.id = ? ''', (client_id,)).fetchone() client_dict = dict_from_row(client_row) contractor_types = conn.execute('SELECT * FROM ContractorType ORDER BY type_name').fetchall() conn.close() if not client_dict: flash('Клиент не найден', 'error') return redirect(url_for('index')) return render_template('edit_client.html', client=client_dict, contractor_types=contractor_types) # ========== МАРШРУТЫ ДЛЯ ЗАКАЗОВ ========== @app.route('/order_history/') def order_history(client_id): conn = get_db_connection() client_row = conn.execute(''' SELECT c.*, ct.type_name as contractor_type_name FROM Clients c LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id WHERE c.id = ? ''', (client_id,)).fetchone() client_dict = dict_from_row(client_row) # Получаем заказы клиента orders_rows = conn.execute(''' SELECT o.* FROM Orders o WHERE o.client_id = ? ORDER BY o.order_date DESC, o.id DESC ''', (client_id,)).fetchall() # Получаем детальную информацию о товарах в каждом заказе orders_with_items = [] total_quantity_all = 0 total_amount_all = 0 completed_count = 0 for order_row in orders_rows: order_dict = dict_from_row(order_row) # Получаем товары для этого заказа items_rows = conn.execute(''' SELECT oi.*, cat.product_name, cat.article, cat.min_price, cat2.category_name FROM OrderItems oi JOIN Catalog cat ON oi.product_id = cat.id LEFT JOIN Categories cat2 ON cat.category_id = cat2.id WHERE oi.order_id = ? ''', (order_dict['id'],)).fetchall() items_list = list_from_rows(items_rows) order_dict['items'] = items_list # Считаем общее количество для этого заказа order_total_qty = sum(item['quantity'] for item in items_list) if items_list else 0 order_dict['total_items'] = order_total_qty total_quantity_all += order_total_qty total_amount_all += order_dict['total_amount'] if order_dict['status'] == 'Выполнен': completed_count += 1 orders_with_items.append(order_dict) # Статистика total_stats = { 'total_orders': len(orders_with_items), 'total_quantity': total_quantity_all, 'total_amount': total_amount_all, 'completed_orders': completed_count } conn.close() if not client_dict: flash('Клиент не найден', 'error') return redirect(url_for('index')) return render_template('order_history.html', client=client_dict, orders=orders_with_items, total_stats=total_stats) # ========== МАРШРУТ ДЛЯ ОБНОВЛЕНИЯ СТАТУСА ЗАКАЗА ========== @app.route('/update_order_status/', methods=['POST']) def update_order_status(order_id): """Обновление статуса заказа""" try: new_status = request.form['status'] conn = get_db_connection() conn.execute('UPDATE Orders SET status = ? WHERE id = ?', (new_status, order_id)) conn.commit() conn.close() flash(f'Статус заказа обновлен на "{new_status}"', 'success') except Exception as e: flash(f'Ошибка при обновлении статуса: {str(e)}', 'error') return redirect(request.referrer or url_for('orders_list')) # ========== МАРШРУТ ДЛЯ ОБНОВЛЕНИЯ СТАТУСА ПРОИЗВОДСТВА ========== @app.route('/update_production_status/', methods=['POST']) def update_production_status(order_id): """Обновление статуса производства""" try: new_status = request.form['production_status'] conn = get_db_connection() conn.execute('UPDATE Orders SET production_status = ? WHERE id = ?', (new_status, order_id)) conn.commit() conn.close() flash(f'Статус производства обновлен на "{new_status}"', 'success') except Exception as e: flash(f'Ошибка при обновлении статуса производства: {str(e)}', 'error') return redirect(request.referrer) # ========== МАРШРУТЫ ДЛЯ ТОВАРОВ ========== @app.route('/add_product', methods=['GET', 'POST']) def add_product(): if request.method == 'POST': try: product_name = request.form['product_name'] article = request.form['article'] category_id = request.form['category_id'] material_id = request.form.get('material_id') or None description = request.form.get('description', '') min_price = float(request.form['min_price']) quantity_in_stock = int(request.form.get('quantity_in_stock', 0)) production_time_days = int(request.form.get('production_time_days', 1)) conn = get_db_connection() existing = conn.execute('SELECT id FROM Catalog WHERE article = ?', (article,)).fetchone() if existing: flash('Товар с таким артикулом уже существует', 'error') conn.close() return redirect(url_for('add_product')) conn.execute(''' INSERT INTO Catalog (product_name, article, category_id, material_id, description, min_price, quantity_in_stock, production_time_days) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', (product_name, article, category_id, material_id, description, min_price, quantity_in_stock, production_time_days)) conn.commit() conn.close() flash('Товар успешно добавлен!', 'success') return redirect(url_for('catalog')) except Exception as e: flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('add_product')) conn = get_db_connection() categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() materials = conn.execute('SELECT * FROM Materials ORDER BY material_name').fetchall() conn.close() return render_template('add_product.html', categories=categories, materials=materials) @app.route('/edit_product/', methods=['GET', 'POST']) def edit_product(product_id): conn = get_db_connection() if request.method == 'POST': try: product_name = request.form['product_name'] article = request.form['article'] category_id = request.form['category_id'] material_id = request.form.get('material_id') or None description = request.form.get('description', '') min_price = float(request.form['min_price']) quantity_in_stock = int(request.form.get('quantity_in_stock', 0)) production_time_days = int(request.form.get('production_time_days', 1)) existing = conn.execute( 'SELECT id FROM Catalog WHERE article = ? AND id != ?', (article, product_id) ).fetchone() if existing: flash('Товар с таким артикулом уже существует', 'error') conn.close() return redirect(url_for('edit_product', product_id=product_id)) conn.execute(''' UPDATE Catalog SET product_name = ?, article = ?, category_id = ?, material_id = ?, description = ?, min_price = ?, quantity_in_stock = ?, production_time_days = ? WHERE id = ? ''', (product_name, article, category_id, material_id, description, min_price, quantity_in_stock, production_time_days, product_id)) conn.commit() conn.close() flash('Товар успешно обновлен!', 'success') return redirect(url_for('catalog')) except Exception as e: flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('edit_product', product_id=product_id)) product_row = conn.execute(''' SELECT cat.*, c.category_name, m.material_name FROM Catalog cat LEFT JOIN Categories c ON cat.category_id = c.id LEFT JOIN Materials m ON cat.material_id = m.id WHERE cat.id = ? ''', (product_id,)).fetchone() product_dict = dict_from_row(product_row) categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() materials = conn.execute('SELECT * FROM Materials ORDER BY material_name').fetchall() conn.close() if not product_dict: flash('Товар не найден', 'error') return redirect(url_for('catalog')) return render_template('edit_product.html', product=product_dict, categories=categories, materials=materials) @app.route('/delete_product/', methods=['POST']) def delete_product(product_id): try: conn = get_db_connection() order_items = conn.execute('SELECT COUNT(*) as count FROM OrderItems WHERE product_id = ?', (product_id,)).fetchone() if order_items['count'] > 0: flash('Нельзя удалить товар, по которому есть заказы', 'error') conn.close() return redirect(url_for('catalog')) conn.execute('DELETE FROM Catalog WHERE id = ?', (product_id,)) conn.commit() conn.close() flash('Товар успешно удален', 'success') except Exception as e: flash(f'Ошибка при удалении: {str(e)}', 'error') return redirect(url_for('catalog')) @app.route('/catalog') def catalog(): conn = get_db_connection() categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() # Получаем список всех клиентов для выпадающего списка clients_rows = conn.execute('SELECT id, name FROM Clients ORDER BY name').fetchall() clients = list_from_rows(clients_rows) search_query = request.args.get('search', '') category_id = request.args.get('category', 'all') sort_by = request.args.get('sort', 'name_asc') sql = ''' SELECT cat.*, c.category_name, m.material_name, m.color, m.production_time_days, m.daily_capacity FROM Catalog cat LEFT JOIN Categories c ON cat.category_id = c.id LEFT JOIN Materials m ON cat.material_id = m.id WHERE 1=1 ''' params = [] if search_query: sql += " AND (cat.product_name LIKE ? OR cat.article LIKE ?)" params.extend([f'%{search_query}%', f'%{search_query}%']) if category_id != 'all': sql += " AND cat.category_id = ?" params.append(category_id) if sort_by == 'name_asc': sql += " ORDER BY cat.product_name ASC" elif sort_by == 'name_desc': sql += " ORDER BY cat.product_name DESC" elif sort_by == 'price_asc': sql += " ORDER BY cat.min_price ASC" elif sort_by == 'price_desc': sql += " ORDER BY cat.min_price DESC" elif sort_by == 'stock_desc': sql += " ORDER BY cat.quantity_in_stock DESC" else: sql += " ORDER BY cat.product_name ASC" products_rows = conn.execute(sql, params).fetchall() products = list_from_rows(products_rows) cart = session.get('cart', {}) cart_count = sum(item['quantity'] for item in cart.values()) if cart else 0 conn.close() return render_template('catalog.html', products=products, categories=categories, clients=clients, cart_count=cart_count) @app.route('/product/') def product_detail(product_id): conn = get_db_connection() product_row = conn.execute(''' SELECT cat.*, c.category_name, m.material_name, m.price_per_unit, m.unit, m.in_stock as material_stock, m.daily_capacity as material_capacity, m.production_time_days as material_production_time, m.cost_price as material_cost_price FROM Catalog cat LEFT JOIN Categories c ON cat.category_id = c.id LEFT JOIN Materials m ON cat.material_id = m.id WHERE cat.id = ? ''', (product_id,)).fetchone() product_dict = dict_from_row(product_row) material = None if product_dict and product_dict.get('material_id'): material_row = conn.execute('SELECT * FROM Materials WHERE id = ?', (product_dict['material_id'],)).fetchone() material = dict_from_row(material_row) orders_stats_row = conn.execute(''' SELECT COUNT(DISTINCT oi.order_id) as total_orders, SUM(oi.quantity) as total_sold, AVG(oi.quantity) as avg_order_size FROM OrderItems oi WHERE oi.product_id = ? ''', (product_id,)).fetchone() orders_stats_dict = dict_from_row(orders_stats_row) conn.close() if not product_dict: flash('Товар не найден', 'error') return redirect(url_for('catalog')) return render_template('product_detail.html', product=product_dict, material=material, orders_stats=orders_stats_dict) # ========== МАРШРУТЫ ДЛЯ КОРЗИНЫ ========== @app.route('/cart') def view_cart(): cart = session.get('cart', {}) cart_items = [] total_amount = 0 conn = get_db_connection() for key, item_data in cart.items(): product_id = item_data['product_id'] quantity = item_data['quantity'] client_id = item_data['client_id'] # Получаем информацию о товаре product_row = conn.execute(''' SELECT cat.*, c.category_name, m.material_name, cat.quantity_in_stock FROM Catalog cat LEFT JOIN Categories c ON cat.category_id = c.id LEFT JOIN Materials m ON cat.material_id = m.id WHERE cat.id = ? ''', (product_id,)).fetchone() # Получаем информацию о партнере client_row = conn.execute('SELECT name FROM Clients WHERE id = ?', (client_id,)).fetchone() client_name = client_row['name'] if client_row else 'Неизвестный' if product_row: product = dict_from_row(product_row) cart_items.append({ 'id': key, 'product_id': product_id, 'product_name': product['product_name'], 'article': product['article'], 'category_name': product['category_name'], 'material_name': product['material_name'], 'client_id': client_id, 'client_name': client_name, 'price': product['min_price'], 'quantity': quantity, 'in_stock': product['quantity_in_stock'] or 0 }) total_amount += product['min_price'] * quantity conn.close() return render_template('cart_new.html', cart_items=cart_items, total_amount=total_amount) @app.route('/add_to_cart/', methods=['POST']) def add_to_cart(product_id): quantity = int(request.form.get('quantity', 1)) client_id = request.form.get('client_id') if not client_id: flash('Выберите партнера', 'error') return redirect(url_for('catalog')) cart = session.get('cart', {}) # Проверяем, что все товары в корзине от одного партнера if cart: existing_client = next(iter(cart.values()))['client_id'] if existing_client != int(client_id): flash('Нельзя добавлять товары разных партнеров в одну корзину', 'error') return redirect(url_for('catalog')) # Создаем уникальный ключ для комбинации товар + партнер key = f"{product_id}_{client_id}" if key in cart: cart[key]['quantity'] += quantity else: cart[key] = { 'product_id': product_id, 'client_id': int(client_id), 'quantity': quantity } session['cart'] = cart flash('Товар добавлен в корзину', 'success') return redirect(url_for('catalog')) @app.route('/update_cart/', methods=['POST']) def update_cart(item_id): quantity = int(request.form.get('quantity', 1)) cart = session.get('cart', {}) if quantity > 0 and item_id in cart: cart[item_id]['quantity'] = quantity elif quantity <= 0 and item_id in cart: cart.pop(item_id, None) session['cart'] = cart return ('', 204) @app.route('/remove_from_cart/', methods=['POST']) def remove_from_cart(item_id): cart = session.get('cart', {}) cart.pop(item_id, None) session['cart'] = cart return redirect(url_for('view_cart')) # ========== МАРШРУТ ДЛЯ ОФОРМЛЕНИЯ ЗАКАЗА ========== @app.route('/checkout', methods=['POST']) def checkout(): cart = session.get('cart', {}) if not cart: flash('Корзина пуста', 'error') return redirect(url_for('catalog')) conn = get_db_connection() # Проверяем, что все товары от одного партнера client_ids = set(item_data['client_id'] for item_data in cart.values()) if len(client_ids) > 1: flash('Ошибка: в корзине товары от разных партнеров', 'error') conn.close() return redirect(url_for('view_cart')) client_id = list(client_ids)[0] if client_ids else None # Собираем все товары items = [] subtotal = 0 for key, item_data in cart.items(): product_id = item_data['product_id'] quantity = item_data['quantity'] product_row = conn.execute('SELECT * FROM Catalog WHERE id = ?', (product_id,)).fetchone() if not product_row: flash(f'Товар с ID {product_id} не найден', 'error') conn.close() return redirect(url_for('view_cart')) product = dict_from_row(product_row) if product['quantity_in_stock'] < quantity: flash(f'Недостаточно товара "{product["product_name"]}" на складе', 'error') conn.close() return redirect(url_for('view_cart')) items.append({ 'product': product, 'quantity': quantity }) subtotal += product['min_price'] * quantity try: # Рассчитываем наценку 15% + 10% = 25% assembly_percent = 15 delivery_percent = 10 assembly_cost = subtotal * assembly_percent / 100 delivery_cost = subtotal * delivery_percent / 100 total_amount = subtotal + assembly_cost + delivery_cost # Срок изготовления (максимальный из всех товаров) production_days = max(item['product']['production_time_days'] or 1 for item in items) today = datetime.now().strftime('%Y-%m-%d') end_date = (datetime.now() + timedelta(days=production_days)).strftime('%Y-%m-%d') # Создаем ОДИН заказ cursor = conn.execute(''' INSERT INTO Orders ( client_id, order_date, total_amount, status, production_days, production_start_date, production_end_date, production_status, assembly_percent, delivery_percent, assembly_cost, delivery_cost, base_amount ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( client_id, today, total_amount, 'Новый', production_days, today, end_date, 'Ожидает', assembly_percent, delivery_percent, assembly_cost, delivery_cost, subtotal )) order_id = cursor.lastrowid # Добавляем все товары в OrderItems for item in items: product = item['product'] quantity = item['quantity'] conn.execute(''' INSERT INTO OrderItems (order_id, product_id, quantity, price_at_moment) VALUES (?, ?, ?, ?) ''', (order_id, product['id'], quantity, product['min_price'])) conn.execute(''' UPDATE Catalog SET quantity_in_stock = quantity_in_stock - ? WHERE id = ? ''', (quantity, product['id'])) conn.commit() session.pop('cart', None) flash(f'✅ Заказ успешно оформлен! Сумма: {total_amount:.2f} руб.', 'success') except Exception as e: conn.rollback() flash(f'Ошибка при создании заказа: {str(e)}', 'error') conn.close() return redirect(url_for('orders_list')) # ========== МАРШРУТ ДЛЯ СПИСКА ВСЕХ ЗАКАЗОВ ========== @app.route('/orders_list') def orders_list(): """Список всех заказов""" conn = get_db_connection() clients_rows = conn.execute('SELECT id, name FROM Clients ORDER BY name').fetchall() clients_list = list_from_rows(clients_rows) # Получаем заказы с основной информацией orders_rows = conn.execute(''' SELECT o.*, c.name as client_name, c.inn as client_inn, COUNT(oi.id) as items_count, COALESCE(SUM(oi.quantity), 0) as total_items FROM Orders o LEFT JOIN Clients c ON o.client_id = c.id LEFT JOIN OrderItems oi ON o.id = oi.order_id GROUP BY o.id ORDER BY o.order_date DESC, o.id DESC LIMIT 100 ''').fetchall() # Для каждого заказа получаем список товаров orders_with_items = [] for order_row in orders_rows: order_dict = dict_from_row(order_row) # Получаем товары для этого заказа items_rows = conn.execute(''' SELECT oi.*, cat.product_name, cat.article, cat.min_price, cat.category_id, cat2.category_name FROM OrderItems oi JOIN Catalog cat ON oi.product_id = cat.id LEFT JOIN Categories cat2 ON cat.category_id = cat2.id WHERE oi.order_id = ? ''', (order_dict['id'],)).fetchall() order_dict['items'] = list_from_rows(items_rows) orders_with_items.append(order_dict) # Считаем общую статистику total_stats_row = conn.execute(''' SELECT COUNT(DISTINCT o.id) as total_orders, COALESCE(SUM(oi.quantity), 0) as total_quantity, COALESCE(SUM(o.total_amount), 0) as total_amount FROM Orders o LEFT JOIN OrderItems oi ON o.id = oi.order_id ''').fetchone() total_stats = dict_from_row(total_stats_row) conn.close() return render_template('orders_list.html', orders=orders_with_items, total_stats=total_stats, clients=clients_list) # ========== МАРШРУТ ДЛЯ МАТЕРИАЛОВ ========== @app.route('/materials') def materials(): conn = get_db_connection() materials_rows = conn.execute(''' SELECT * FROM Materials ORDER BY material_name ''').fetchall() materials_list = list_from_rows(materials_rows) conn.close() return render_template('materials.html', materials=materials_list) # ========== СЛУЖЕБНЫЕ МАРШРУТЫ ========== @app.route('/favicon.ico') def favicon(): return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico', mimetype='image/vnd.microsoft.icon') @app.route('/static/') def static_files(filename): return send_from_directory(app.root_path + '/static', filename) if __name__ == '__main__': app.run(debug=True)