bbbbbbbbbbb/app.py

246 lines
10 KiB
Python
Raw 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.

import os
import sqlite3
from datetime import datetime, timedelta
from flask import Flask, render_template, request, redirect, url_for, flash, session
app = Flask(__name__)
app.secret_key = 'super_secret_key_for_exam'
DB_PATH = 'shoe_shop.db'
# --- РАБОТА С БД ---
def get_db_connection():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def init_db():
# Если базы нет, создаем её из файла database.sql
if not os.path.exists(DB_PATH):
conn = get_db_connection()
with open('database.sql', 'r', encoding='utf-8') as f:
conn.executescript(f.read())
# Наполняем базу тестовыми данными (Импорт данных)
# Роли
conn.execute("INSERT INTO roles (name) VALUES ('admin'), ('manager'), ('user')")
# Пользователи (Логины без пароля)
conn.execute("INSERT INTO users (login, last_name, first_name, middle_name, role_id) VALUES ('admin', 'Админов', 'Админ', 'Админович', 1)")
conn.execute("INSERT INTO users (login, last_name, first_name, middle_name, role_id) VALUES ('manager', 'Менеджеров', 'Менеджер', 'Менеджерович', 2)")
conn.execute("INSERT INTO users (login, last_name, first_name, middle_name, role_id) VALUES ('user', 'Петров', 'Петр', 'Петрович', 3)")
# Категории и подкатегории
conn.execute("INSERT INTO categories (name) VALUES ('Мужская'), ('Женская')")
conn.execute("INSERT INTO subcategories (category_id, name) VALUES (1, 'Кроссовки'), (1, 'Ботинки'), (2, 'Кроссовки')")
conn.execute("INSERT INTO manufacturers (name) VALUES ('Nike'), ('Adidas')")
# Товары
conn.execute("""INSERT INTO products (article, name, subcategory_id, manufacturer_id, description, composition, price, image_path)
VALUES ('A001', 'Air Max', 1, 1, 'Спортивные', 'Кожа', 10000, '')""")
conn.execute("""INSERT INTO products (article, name, subcategory_id, manufacturer_id, description, composition, price, image_path)
VALUES ('A002', 'Superstar', 3, 2, 'Классика', 'Текстиль', 8000, '')""")
# Размеры и остатки (для проверки "мало/много")
conn.execute("INSERT INTO sizes (size_value) VALUES (40), (41), (42)")
conn.execute("INSERT INTO product_stock (product_id, size_id, quantity) VALUES (1, 1, 1), (1, 2, 2), (2, 1, 10), (2, 2, 15)")
conn.commit()
conn.close()
# --- БИЗНЕС-ЛОГИКА ---
def calculate_discount(product_id, base_price):
"""Скидка 25%, если на товар не было заказов за последний месяц (30 дней)"""
conn = get_db_connection()
one_month_ago = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
has_recent_orders = conn.execute(
"SELECT COUNT(*) FROM order_items oi JOIN orders o ON oi.order_id = o.id WHERE oi.product_id = ? AND o.order_date >= ?",
(product_id, one_month_ago)
).fetchone()[0]
conn.close()
return base_price * 0.75 if has_recent_orders == 0 else base_price
def get_user_role():
"""Получение роли текущего пользователя"""
if 'user_id' not in session:
return 'guest'
conn = get_db_connection()
role = conn.execute("SELECT r.name FROM roles r JOIN users u ON u.role_id = r.id WHERE u.id = ?", (session['user_id'],)).fetchone()
conn.close()
return role['name'] if role else 'guest'
# Передаем роль и имя во все шаблоны автоматически
@app.context_processor
def inject_globals():
return dict(current_role=get_user_role(), current_user=session.get('user_name'))
# --- МАРШРУТЫ (АВТОРИЗАЦИЯ) ---
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
login_val = request.form.get('login')
conn = get_db_connection()
user = conn.execute("SELECT * FROM users WHERE login = ?", (login_val,)).fetchone()
conn.close()
if user:
session['user_id'] = user['id']
session['user_name'] = f"{user['last_name']} {user['first_name']}"
flash(f'Вы вошли как {user["last_name"]}', 'message')
return redirect(url_for('index'))
else:
flash('Пользователь с таким логином не найден', 'error')
return render_template('login.html')
@app.route('/logout')
def logout():
session.clear()
flash('Вы вышли из системы', 'message')
return redirect(url_for('index'))
# --- КАТАЛОГ ---
@app.route('/')
def index():
conn = get_db_connection()
# Фильтрация и поиск (доступна только не гостям)
search = request.args.get('search', '')
category_filter = request.args.get('category', '')
query = """
SELECT p.*, sc.name as subcategory_name, c.name as category_name, m.name as manufacturer_name,
(SELECT SUM(quantity) FROM product_stock WHERE product_id = p.id) as total_qty
FROM products p
JOIN subcategories sc ON p.subcategory_id = sc.id
JOIN categories c ON sc.category_id = c.id
JOIN manufacturers m ON p.manufacturer_id = m.id
WHERE 1=1
"""
params = []
# Гостю фильтры не применяем (по ТЗ)
if get_user_role() != 'guest':
if search:
query += " AND (p.name LIKE ? OR p.description LIKE ?)"
params.extend([f'%{search}%', f'%{search}%'])
if category_filter:
query += " AND c.id = ?"
params.append(category_filter)
products_raw = conn.execute(query, params).fetchall()
categories = conn.execute("SELECT * FROM categories").fetchall()
conn.close()
products = []
for p in products_raw:
p_dict = dict(p)
# Расчет цены со скидкой
p_dict['final_price'] = round(calculate_discount(p['id'], p['price']), 2)
# Проверка количества (мало/много)
if p_dict['total_qty'] is None or p_dict['total_qty'] <= 5:
p_dict['qty_text'] = 'мало'
p_dict['highlight'] = False
else:
p_dict['qty_text'] = 'много'
p_dict['highlight'] = True
# Заглушка для картинки
if not p_dict['image_path']:
p_dict['image_path'] = 'picture.png'
products.append(p_dict)
return render_template('index.html', products=products, categories=categories, search=search, cat_filter=category_filter)
# --- КОРЗИНА И ЗАКАЗЫ ---
@app.route('/add_to_cart/<int:product_id>', methods=['POST'])
def add_to_cart(product_id):
if get_user_role() == 'guest':
flash('Войдите, чтобы оформлять заказы', 'error')
return redirect(url_for('index'))
size_id = request.form.get('size_id')
qty = int(request.form.get('quantity', 1))
if 'cart' not in session:
session['cart'] = []
cart = session['cart']
found = False
for item in cart:
if item['product_id'] == product_id and item['size_id'] == int(size_id):
item['quantity'] += qty
found = True
break
if not found:
cart.append({'product_id': product_id, 'size_id': int(size_id), 'quantity': qty})
session['cart'] = cart
flash('Товар добавлен в корзину', 'message')
return redirect(url_for('index'))
@app.route('/cart')
def cart():
if get_user_role() == 'guest':
return redirect(url_for('login'))
return render_template('cart.html', cart=session.get('cart', []))
@app.route('/checkout', methods=['POST'])
def checkout():
if get_user_role() == 'guest' or not session.get('cart'):
return redirect(url_for('index'))
client_name = request.form.get('client_name')
conn = get_db_connection()
cursor = conn.cursor()
# Создаем заказ
cursor.execute("INSERT INTO orders (user_id, client_full_name, order_date) VALUES (?, ?, ?)",
(session['user_id'], client_name, datetime.now().strftime('%Y-%m-%d')))
order_id = cursor.lastrowid
# Добавляем позиции
for item in session['cart']:
price = conn.execute("SELECT price FROM products WHERE id = ?", (item['product_id'],)).fetchone()['price']
final_price = calculate_discount(item['product_id'], price)
cursor.execute("INSERT INTO order_items (order_id, product_id, size_id, quantity, price_at_moment) VALUES (?, ?, ?, ?, ?)",
(order_id, item['product_id'], item['size_id'], item['quantity'], final_price))
conn.commit()
conn.close()
session.pop('cart', None)
flash('Заказ успешно оформлен!', 'message')
return redirect(url_for('orders'))
@app.route('/orders')
def orders():
# Просмотр заказов только для менеджера и админа
if get_user_role() in ['guest', 'user']:
flash('Доступ запрещен', 'error')
return redirect(url_for('index'))
conn = get_db_connection()
orders_list = conn.execute("""
SELECT o.id, o.order_date, o.client_full_name, u.last_name as manager_name
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
ORDER BY o.order_date DESC
""").fetchall()
conn.close()
return render_template('orders.html', orders=orders_list)
@app.route('/delete_order/<int:order_id>')
def delete_order(order_id):
if get_user_role() not in ['admin', 'manager']:
return redirect(url_for('index'))
conn = get_db_connection()
conn.execute("DELETE FROM orders WHERE id = ?", (order_id,))
conn.commit()
conn.close()
flash('Заказ удален', 'message')
return redirect(url_for('orders'))
# --- ЗАПУСК ---
if __name__ == '__main__':
init_db() # Проверяем/создаем базу при запуске
app.run(debug=True)