from flask import Flask, render_template, request, redirect, url_for, flash, jsonify import sqlite3 import os import pandas as pd from datetime import datetime from database import get_db_connection, calculate_order_total, calculate_discount, get_discount_description, \ calculate_discount_for_new_order, get_db, create_tables from import_data import import_data_from_files app = Flask(__name__) app.secret_key = 'kancelyary_secret_key_2026' app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DATABASE'] = 'partners.db' # Функция для сохранения данных в Excel (опционально) def save_to_excel(): """Сохраняет все данные из БД в Excel файлы""" try: if not os.path.exists('data'): os.makedirs('data') with get_db() as conn: product_types = conn.execute('SELECT * FROM product_types').fetchall() if product_types: df_types = pd.DataFrame([dict(pt) for pt in product_types]) df_types.to_excel('data/Product_types_import.xlsx', index=False) partners = conn.execute('SELECT * FROM partners').fetchall() if partners: df_partners = pd.DataFrame([dict(p) for p in partners]) df_partners.to_excel('data/Partners_import.xlsx', index=False) products = conn.execute('SELECT * FROM products').fetchall() if products: df_products = pd.DataFrame([dict(p) for p in products]) df_products.to_excel('data/Products_import.xlsx', index=False) orders = conn.execute('SELECT * FROM orders').fetchall() if orders: df_orders = pd.DataFrame([dict(o) for o in orders]) df_orders.to_excel('data/Orders_import.xlsx', index=False) order_items = conn.execute('SELECT * FROM order_items').fetchall() if order_items: df_items = pd.DataFrame([dict(oi) for oi in order_items]) df_items.to_excel('data/Order_items_import.xlsx', index=False) print("✅ Данные сохранены в Excel файлы") return True except Exception as e: print(f"❌ Ошибка при сохранении в Excel: {e}") return False # Главная страница - список заказов с сортировкой @app.route('/') def index(): sort_by = request.args.get('sort', 'date_desc') partner_filter = request.args.get('partner', None) try: with get_db() as conn: if partner_filter: query = f''' SELECT o.*, p.name as partner_name, p.id as partner_id FROM orders o JOIN partners p ON o.partner_id = p.id WHERE o.partner_id = {partner_filter} ''' else: query = ''' SELECT o.*, p.name as partner_name, p.id as partner_id FROM orders o JOIN partners p ON o.partner_id = p.id ''' if sort_by == 'amount_desc': query += ''' LEFT JOIN order_items oi ON o.id = oi.order_id GROUP BY o.id ORDER BY COALESCE(SUM(oi.quantity * oi.price_at_order), 0) * 1.1 DESC ''' elif sort_by == 'date_desc': query += ' ORDER BY o.order_date DESC' elif sort_by == 'partner': query += ' ORDER BY p.name, o.order_date DESC' else: query += ' ORDER BY o.order_date DESC' orders = conn.execute(query).fetchall() orders_with_discount = [] for order in orders: try: items_count = conn.execute(''' SELECT COUNT(*) as count FROM order_items WHERE order_id = ? ''', (order['id'],)).fetchone()['count'] subtotal_without_markup = conn.execute(''' SELECT COALESCE(SUM(quantity * price_at_order), 0) as total FROM order_items WHERE order_id = ? ''', (order['id'],)).fetchone()['total'] subtotal_with_markup = subtotal_without_markup * 1.1 discount_percent = order['discount_percent'] if order['discount_percent'] else 0 discount_amount = subtotal_with_markup * discount_percent / 100 total = subtotal_with_markup - discount_amount order_dict = { 'order_id': order['id'], 'partner_id': order['partner_id'], 'partner_name': order['partner_name'], 'order_date': order['order_date'], 'notes': order['notes'] if order['notes'] else '', 'items_count': items_count, 'subtotal_without_markup': round(subtotal_without_markup, 2), 'subtotal_with_markup': round(subtotal_with_markup, 2), 'discount_percent': discount_percent, 'discount_desc': get_discount_description(discount_percent), 'discount_amount': round(discount_amount, 2), 'total': round(total, 2) } orders_with_discount.append(order_dict) except Exception as e: print(f"Ошибка при обработке заказа {order['id']}: {e}") orders_with_discount.append({ 'order_id': order['id'], 'partner_id': order['partner_id'], 'partner_name': order['partner_name'], 'order_date': order['order_date'], 'notes': '', 'items_count': 0, 'subtotal_without_markup': 0, 'subtotal_with_markup': 0, 'discount_percent': 0, 'discount_desc': '0%', 'discount_amount': 0, 'total': 0 }) return render_template('index.html', orders=orders_with_discount, current_sort=sort_by) except Exception as e: print(f"Критическая ошибка в index: {e}") return render_template('index.html', orders=[], current_sort='date_desc') # Страница товаров @app.route('/products') def products(): try: with get_db() as conn: products_rows = conn.execute(''' SELECT p.*, pt.type_name as product_type_name FROM products p JOIN product_types pt ON p.product_type_id = pt.id ORDER BY p.product_name ''').fetchall() products_list = [] for row in products_rows: products_list.append({ 'id': row['id'], 'product_type_id': row['product_type_id'], 'product_name': row['product_name'], 'article': row['article'], 'min_partner_price': row['min_partner_price'], 'product_type_name': row['product_type_name'] }) product_types_rows = conn.execute('SELECT * FROM product_types ORDER BY type_name').fetchall() product_types = [] for row in product_types_rows: product_types.append({ 'id': row['id'], 'type_name': row['type_name'], 'description': row['description'] }) partners_rows = conn.execute('SELECT id, name FROM partners ORDER BY name').fetchall() partners = [] for row in partners_rows: partners.append({ 'id': row['id'], 'name': row['name'] }) today = datetime.now().strftime('%Y-%m-%d') return render_template('products.html', products=products_list, product_types=product_types, partners=partners, today=today) except Exception as e: print(f"Ошибка на странице товаров: {e}") flash('Ошибка при загрузке страницы', 'error') return redirect(url_for('index')) # Страница партнеров @app.route('/partners') def partners(): try: with get_db() as conn: partners_rows = conn.execute(''' SELECT p.*, COUNT(DISTINCT o.id) as orders_count, COALESCE(SUM(oi.quantity * oi.price_at_order), 0) as total_purchases FROM partners p LEFT JOIN orders o ON p.id = o.partner_id LEFT JOIN order_items oi ON o.id = oi.order_id GROUP BY p.id ORDER BY p.name ''').fetchall() partners_with_stats = [] for partner in partners_rows: partner_dict = { 'id': partner['id'], 'name': partner['name'], 'director': partner['director'], 'email': partner['email'], 'phone': partner['phone'], 'legal_address': partner['legal_address'], 'inn': partner['inn'], 'orders_count': partner['orders_count'], 'total_purchases': partner['total_purchases'] } discount_percent = calculate_discount(partner['total_purchases'] or 0) discount_desc = get_discount_description(discount_percent) partner_dict['discount_percent'] = discount_percent partner_dict['discount_desc'] = discount_desc partners_with_stats.append(partner_dict) return render_template('partners.html', partners=partners_with_stats) except Exception as e: print(f"Ошибка на странице партнеров: {e}") import traceback traceback.print_exc() flash('Ошибка при загрузке страницы', 'error') return redirect(url_for('index')) # Добавление заказа @app.route('/add_order', methods=['GET', 'POST']) def add_order(): if request.method == 'POST': try: partner_id = request.form['partner_id'] order_date = request.form['order_date'] notes = request.form.get('notes', '') products = request.form.getlist('product_id[]') quantities = request.form.getlist('quantity[]') prices = request.form.getlist('price[]') with get_db() as conn: # Проверка (товары всегда есть в наличии, но проверяем что они существуют) for i in range(len(products)): if products[i] and quantities[i]: product_id = int(products[i]) quantity = int(quantities[i]) if quantity <= 0: flash(f'Количество должно быть положительным для позиции {i + 1}', 'warning') return redirect(url_for('add_order')) product = conn.execute('SELECT * FROM products WHERE id = ?', (product_id,)).fetchone() if not product: flash(f'Товар с ID {product_id} не найден', 'error') return redirect(url_for('add_order')) # Рассчитываем сумму текущего заказа (без добавочной стоимости) current_order_amount_without_markup = 0 for i in range(len(products)): if products[i] and quantities[i] and prices[i]: quantity = int(quantities[i]) price = float(prices[i]) current_order_amount_without_markup += quantity * price # Рассчитываем скидку на основе предыдущих заказов discount_percent = calculate_discount_for_new_order(partner_id, order_date, current_order_amount_without_markup) # Создаем заказ cursor = conn.cursor() cursor.execute(''' INSERT INTO orders (partner_id, order_date, notes, discount_percent) VALUES (?, ?, ?, ?) ''', (partner_id, order_date, notes, discount_percent)) order_id = cursor.lastrowid # Добавляем позиции items_added = 0 for i in range(len(products)): if products[i] and quantities[i] and prices[i]: product_id = int(products[i]) quantity = int(quantities[i]) price = float(prices[i]) cursor.execute(''' INSERT INTO order_items (order_id, product_id, quantity, price_at_order) VALUES (?, ?, ?, ?) ''', (order_id, product_id, quantity, price)) items_added += 1 save_to_excel() if items_added > 0: flash(f'Заказ успешно создан! Добавлено {items_added} позиций', 'success') return redirect(url_for('index')) except Exception as e: print(f"Ошибка при создании заказа: {e}") flash(f'Ошибка при создании заказа: {str(e)}', 'error') return redirect(url_for('add_order')) # GET запрос try: with get_db() as conn: partners_rows = conn.execute('SELECT * FROM partners ORDER BY name').fetchall() partners = [] for row in partners_rows: partners.append({ 'id': row['id'], 'name': row['name'], 'director': row['director'], 'email': row['email'], 'phone': row['phone'], 'legal_address': row['legal_address'], 'inn': row['inn'] }) products_rows = conn.execute(''' SELECT p.*, pt.type_name FROM products p JOIN product_types pt ON p.product_type_id = pt.id ORDER BY p.product_name ''').fetchall() products = [] for row in products_rows: products.append({ 'id': row['id'], 'product_type_id': row['product_type_id'], 'product_name': row['product_name'], 'article': row['article'], 'min_partner_price': row['min_partner_price'], 'type_name': row['type_name'] }) today = datetime.now().strftime('%Y-%m-%d') return render_template('add_order.html', partners=partners, products=products, today=today) except Exception as e: print(f"Ошибка при загрузке формы: {e}") flash('Ошибка при загрузке формы', 'error') return redirect(url_for('index')) # Редактирование заказа (УБРАН МАРШРУТ УДАЛЕНИЯ) @app.route('/edit_order/', methods=['GET', 'POST']) def edit_order(order_id): if request.method == 'POST': try: order_date = request.form['order_date'] notes = request.form.get('notes', '') with get_db() as conn: old_items = conn.execute('SELECT product_id, quantity FROM order_items WHERE order_id = ?', (order_id,)).fetchall() products = request.form.getlist('product_id[]') quantities = request.form.getlist('quantity[]') prices = request.form.getlist('price[]') has_new_items = any(p and p.strip() for p in products) if has_new_items: conn.execute('DELETE FROM order_items WHERE order_id = ?', (order_id,)) items_added = 0 new_order_amount_without_markup = 0 for i in range(len(products)): if products[i] and products[i].strip(): product_id = int(products[i]) quantity = int(quantities[i]) if quantities[i] and quantities[i].strip() else 1 price = float(prices[i]) if prices[i] and prices[i].strip() else 0 conn.execute(''' INSERT INTO order_items (order_id, product_id, quantity, price_at_order) VALUES (?, ?, ?, ?) ''', (order_id, product_id, quantity, price)) new_order_amount_without_markup += quantity * price items_added += 1 order_info = conn.execute('SELECT partner_id FROM orders WHERE id = ?', (order_id,)).fetchone() partner_id = order_info['partner_id'] discount_percent = calculate_discount_for_new_order(partner_id, order_date, new_order_amount_without_markup, order_id) conn.execute(''' UPDATE orders SET order_date = ?, notes = ?, discount_percent = ? WHERE id = ? ''', (order_date, notes, discount_percent, order_id)) else: items_added = len(old_items) conn.execute(''' UPDATE orders SET order_date = ?, notes = ? WHERE id = ? ''', (order_date, notes, order_id)) save_to_excel() flash(f'Заказ обновлен! {items_added} позиций', 'success') return redirect(url_for('index')) except Exception as e: print(f"Ошибка при редактировании заказа: {e}") import traceback traceback.print_exc() flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('edit_order', order_id=order_id)) try: with get_db() as conn: order_row = conn.execute('SELECT * FROM orders WHERE id = ?', (order_id,)).fetchone() if not order_row: return redirect(url_for('index')) order = { 'id': order_row['id'], 'partner_id': order_row['partner_id'], 'order_date': order_row['order_date'], 'notes': order_row['notes'] } items_rows = conn.execute(''' SELECT oi.*, p.product_name, p.article FROM order_items oi JOIN products p ON oi.product_id = p.id WHERE oi.order_id = ? ''', (order_id,)).fetchall() items = [] for row in items_rows: items.append({ 'id': row['id'], 'order_id': row['order_id'], 'product_id': row['product_id'], 'quantity': row['quantity'], 'price_at_order': row['price_at_order'], 'product_name': row['product_name'], 'article': row['article'] }) products_rows = conn.execute(''' SELECT p.*, pt.type_name FROM products p JOIN product_types pt ON p.product_type_id = pt.id ORDER BY p.product_name ''').fetchall() products = [] for row in products_rows: products.append({ 'id': row['id'], 'product_type_id': row['product_type_id'], 'product_name': row['product_name'], 'article': row['article'], 'min_partner_price': row['min_partner_price'], 'type_name': row['type_name'] }) return render_template('edit_order.html', order=order, items=items, products=products) except Exception as e: print(f"Ошибка при загрузке заказа: {e}") flash('Ошибка при загрузке заказа', 'error') return redirect(url_for('index')) # Добавление партнера @app.route('/add_partner', methods=['GET', 'POST']) def add_partner(): if request.method == 'POST': try: name = request.form['name'] director = request.form.get('director', '') email = request.form['email'] phone = request.form.get('phone', '') legal_address = request.form.get('legal_address', '') inn = request.form.get('inn', '') with get_db() as conn: conn.execute(''' INSERT INTO partners (name, director, email, phone, legal_address, inn) VALUES (?, ?, ?, ?, ?, ?) ''', (name, director, email, phone, legal_address, inn)) save_to_excel() flash('Партнер успешно добавлен!', 'success') return redirect(url_for('partners')) except sqlite3.IntegrityError: flash('Партнер с таким ИНН уже существует', 'error') return redirect(url_for('add_partner')) except Exception as e: print(f"Ошибка при добавлении партнера: {e}") flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('add_partner')) return render_template('add_partner.html') # Редактирование партнера (УБРАН МАРШРУТ УДАЛЕНИЯ) @app.route('/edit_partner/', methods=['GET', 'POST']) def edit_partner(partner_id): if request.method == 'POST': try: name = request.form['name'] director = request.form.get('director', '') email = request.form['email'] phone = request.form.get('phone', '') legal_address = request.form.get('legal_address', '') inn = request.form.get('inn', '') with get_db() as conn: existing = conn.execute( 'SELECT id FROM partners WHERE inn = ? AND id != ?', (inn, partner_id) ).fetchone() if existing: flash('Партнер с таким ИНН уже существует', 'error') return redirect(url_for('edit_partner', partner_id=partner_id)) conn.execute(''' UPDATE partners SET name = ?, director = ?, email = ?, phone = ?, legal_address = ?, inn = ? WHERE id = ? ''', (name, director, email, phone, legal_address, inn, partner_id)) save_to_excel() flash('Данные партнера обновлены!', 'success') return redirect(url_for('partners')) except Exception as e: print(f"Ошибка при редактировании партнера: {e}") flash(f'Ошибка: {str(e)}', 'error') return redirect(url_for('edit_partner', partner_id=partner_id)) try: with get_db() as conn: partner_row = conn.execute('SELECT * FROM partners WHERE id = ?', (partner_id,)).fetchone() if not partner_row: flash('Партнер не найден', 'error') return redirect(url_for('partners')) partner = { 'id': partner_row['id'], 'name': partner_row['name'], 'director': partner_row['director'], 'email': partner_row['email'], 'phone': partner_row['phone'], 'legal_address': partner_row['legal_address'], 'inn': partner_row['inn'] } return render_template('edit_partner.html', partner=partner) except Exception as e: print(f"Ошибка при загрузке партнера: {e}") flash('Ошибка при загрузке данных', 'error') return redirect(url_for('partners')) # API для работы с товарами (УБРАН МАРШРУТ УДАЛЕНИЯ ТОВАРА) @app.route('/api/product/', methods=['GET']) def api_get_product(product_id): try: with get_db() as conn: product = conn.execute('SELECT * FROM products WHERE id = ?', (product_id,)).fetchone() if product: return jsonify(dict(product)) return jsonify({'error': 'Product not found'}), 404 except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/product', methods=['POST']) def api_add_product(): data = request.json try: with get_db() as conn: cursor = conn.cursor() cursor.execute(''' INSERT INTO products (product_type_id, product_name, article, min_partner_price) VALUES (?, ?, ?, ?) ''', ( data['product_type_id'], data['product_name'], data['article'], data['min_partner_price'] )) product_id = cursor.lastrowid save_to_excel() return jsonify({'success': True, 'product_id': product_id}) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 400 @app.route('/api/product/', methods=['PUT']) def api_update_product(product_id): data = request.json try: with get_db() as conn: conn.execute(''' UPDATE products SET product_type_id = ?, product_name = ?, article = ?, min_partner_price = ? WHERE id = ? ''', ( data['product_type_id'], data['product_name'], data['article'], data['min_partner_price'], product_id )) save_to_excel() return jsonify({'success': True}) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 400 @app.route('/api/product_type', methods=['POST']) def api_add_product_type(): data = request.json try: with get_db() as conn: cursor = conn.cursor() cursor.execute(''' INSERT INTO product_types (type_name, description) VALUES (?, ?) ''', ( data['type_name'], data.get('description', '') )) type_id = cursor.lastrowid save_to_excel() return jsonify({'success': True, 'type_id': type_id}) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 400 @app.route('/api/order', methods=['POST']) def api_create_order(): data = request.json try: with get_db() as conn: for item in data['items']: product = conn.execute('SELECT * FROM products WHERE id = ?', (item['product_id'],)).fetchone() if not product: return jsonify({'success': False, 'error': 'Товар не найден'}), 400 order_amount_without_markup = sum(item['quantity'] * item['price'] for item in data['items']) discount_percent = calculate_discount_for_new_order(data['partner_id'], data['order_date'], order_amount_without_markup) cursor = conn.cursor() cursor.execute(''' INSERT INTO orders (partner_id, order_date, notes, discount_percent) VALUES (?, ?, ?, ?) ''', (data['partner_id'], data['order_date'], data.get('notes', ''), discount_percent)) order_id = cursor.lastrowid for item in data['items']: cursor.execute(''' INSERT INTO order_items (order_id, product_id, quantity, price_at_order) VALUES (?, ?, ?, ?) ''', (order_id, item['product_id'], item['quantity'], item['price'])) save_to_excel() return jsonify({'success': True, 'order_id': order_id}) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 400 @app.route('/test_partner') def test_partner(): """Страница для ручного тестирования добавления партнера""" return render_template('manual_partner_test.html') if __name__ == '__main__': if not os.path.exists('data'): os.makedirs('data') app.run(debug=True)