kancelyary_project/app.py

722 lines
29 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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/<int:order_id>', 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/<int:partner_id>', 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/<int:product_id>', 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/<int:product_id>', 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)