project/app.py

294 lines
12 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.

from flask import Flask, render_template, request, redirect, url_for, flash
from database import db
import os
import re
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-2026'
# Функция валидации телефона
def validate_phone(phone):
phone_clean = re.sub(r'[^\d+]', '', phone)
if phone_clean.startswith('+7') and len(phone_clean) == 12:
return True
elif phone_clean.startswith('8') and len(phone_clean) == 11:
return True
elif len(phone_clean) == 10 and phone_clean.isdigit():
return True
elif len(phone_clean) == 11 and phone_clean.isdigit():
return True
return False
def format_phone(phone):
phone_clean = re.sub(r'[^\d+]', '', phone)
if phone_clean.startswith('+7') and len(phone_clean) == 12:
return f"+7 ({phone_clean[2:5]}) {phone_clean[5:8]}-{phone_clean[8:10]}-{phone_clean[10:12]}"
elif phone_clean.startswith('8') and len(phone_clean) == 11:
return f"+7 ({phone_clean[1:4]}) {phone_clean[4:7]}-{phone_clean[7:9]}-{phone_clean[9:11]}"
elif len(phone_clean) == 10:
return f"+7 ({phone_clean[0:3]}) {phone_clean[3:6]}-{phone_clean[6:8]}-{phone_clean[8:10]}"
elif len(phone_clean) == 11:
return f"+7 ({phone_clean[1:4]}) {phone_clean[4:7]}-{phone_clean[7:9]}-{phone_clean[9:11]}"
return phone
# Функция расчета коэффициента срока годности
def get_expiry_coefficient(expiry_date):
"""
Расчет коэффициента скидки в зависимости от срока годности
< 30 дней -> 50% скидка
30-90 дней -> 30% скидка
90-180 дней -> 15% скидка
> 180 дней -> 0% скидка
"""
if not expiry_date:
return 0
try:
# Преобразуем строку в дату (формат дд.мм.гггг)
expiry = datetime.strptime(expiry_date, '%d.%m.%Y')
today = datetime.now()
days_until_expiry = (expiry - today).days
if days_until_expiry < 0:
return 100 # Просрочен - 100% скидка (не продаем)
elif days_until_expiry < 30:
return 50 # 50% скидка
elif days_until_expiry < 90:
return 30 # 30% скидка
elif days_until_expiry < 180:
return 15 # 15% скидка
else:
return 0
except:
return 0
# Функция расчета итоговой цены с учетом скидки и срока годности
def calculate_final_price(price, quantity, expiry_date, quantity_discount_percent=0):
"""
Расчет итоговой цены:
1. Базовая сумма = цена * количество
2. Скидка по сроку годности
3. Скидка по количеству
"""
total = price * quantity
# Скидка по сроку годности
expiry_discount_percent = get_expiry_coefficient(expiry_date)
expiry_discount_amount = total * expiry_discount_percent / 100
# Скидка по количеству
quantity_discount_amount = total * quantity_discount_percent / 100
# Общая скидка
total_discount = expiry_discount_amount + quantity_discount_amount
final_total = total - total_discount
return {
'total': total,
'expiry_discount_percent': expiry_discount_percent,
'expiry_discount_amount': expiry_discount_amount,
'quantity_discount_percent': quantity_discount_percent,
'quantity_discount_amount': quantity_discount_amount,
'total_discount': total_discount,
'final_total': final_total
}
# ============ ГЛАВНАЯ ============
@app.route('/')
def index():
products = db.get_products()
total_items = sum(p.get('stock_quantity', 0) for p in products)
total_value = sum(p.get('stock_quantity', 0) * p.get('selling_price', 0) for p in products)
return render_template('index.html', total_items=total_items, total_value=total_value)
# ============ ТОВАРЫ ============
@app.route('/products', methods=['GET', 'POST'])
def products():
if request.method == 'POST':
product = {
'name': request.form.get('name'),
'manufacturer': request.form.get('manufacturer'),
'product_type': request.form.get('product_type'),
'purchase_price': float(request.form.get('purchase_price', 0)),
'selling_price': float(request.form.get('selling_price', 0)),
'expiry_date': request.form.get('expiry_date', ''),
'stock_quantity': int(request.form.get('stock_quantity', 0))
}
db.save_product(product)
flash('Товар добавлен', 'success')
return redirect(url_for('products'))
products = db.get_products()
categories = db.get_categories()
return render_template('products.html', products=products, categories=categories)
@app.route('/products/delete/<int:product_id>')
def delete_product(product_id):
db.delete_product(product_id)
flash('Товар удален', 'warning')
return redirect(url_for('products'))
@app.route('/products/edit/<int:product_id>', methods=['GET', 'POST'])
def edit_product(product_id):
product = db.get_product_by_id(product_id)
if not product:
flash('Товар не найден', 'danger')
return redirect(url_for('products'))
if request.method == 'POST':
updated_data = {
'name': request.form.get('name'),
'manufacturer': request.form.get('manufacturer'),
'product_type': request.form.get('product_type'),
'purchase_price': float(request.form.get('purchase_price', 0)),
'selling_price': float(request.form.get('selling_price', 0)),
'expiry_date': request.form.get('expiry_date', ''),
'stock_quantity': int(request.form.get('stock_quantity', 0))
}
db.update_product(product_id, updated_data)
flash('Товар обновлен', 'success')
return redirect(url_for('products'))
return render_template('edit_product.html', product=product)
# ============ ПОСТАВЩИКИ ============
@app.route('/suppliers', methods=['GET', 'POST'])
def suppliers():
if request.method == 'POST':
name = request.form.get('name')
contact = request.form.get('contact')
phone = request.form.get('phone')
if phone and not validate_phone(phone):
flash('Неверный формат телефона', 'danger')
suppliers = db.get_suppliers()
return render_template('suppliers.html', suppliers=suppliers)
supplier = {
'name': name,
'contact': contact,
'phone': format_phone(phone) if phone else ''
}
db.save_supplier(supplier)
flash('Поставщик добавлен', 'success')
return redirect(url_for('suppliers'))
suppliers = db.get_suppliers()
return render_template('suppliers.html', suppliers=suppliers)
@app.route('/suppliers/edit/<int:supplier_id>', methods=['GET', 'POST'])
def edit_supplier(supplier_id):
supplier = db.get_supplier_by_id(supplier_id)
if not supplier:
flash('Поставщик не найден', 'danger')
return redirect(url_for('suppliers'))
if request.method == 'POST':
name = request.form.get('name')
contact = request.form.get('contact')
phone = request.form.get('phone')
if phone and not validate_phone(phone):
flash('Неверный формат телефона', 'danger')
return render_template('edit_supplier.html', supplier=supplier)
updated_data = {
'name': name,
'contact': contact,
'phone': format_phone(phone) if phone else ''
}
db.update_supplier(supplier_id, updated_data)
flash('Поставщик обновлен', 'success')
return redirect(url_for('suppliers'))
return render_template('edit_supplier.html', supplier=supplier)
@app.route('/supplier/orders/<int:supplier_id>')
def supplier_orders(supplier_id):
supplier = db.get_supplier_by_id(supplier_id)
if not supplier:
flash('Поставщик не найден', 'danger')
return redirect(url_for('suppliers'))
all_orders = db.get_incoming_orders()
supplier_orders = [o for o in all_orders if o.get('supplier_id') == supplier_id]
total_sum = sum(o.get('total', 0) for o in supplier_orders)
total_items = sum(o.get('quantity', 0) for o in supplier_orders)
return render_template('supplier_orders.html',
supplier=supplier,
orders=supplier_orders,
total_sum=total_sum,
total_items=total_items)
# ============ ПОСТУПЛЕНИЕ ТОВАРА (С УЧЕТОМ СРОКА ГОДНОСТИ) ============
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
if request.method == 'POST':
product_id = int(request.form.get('product_id'))
supplier_id = int(request.form.get('supplier_id'))
quantity = int(request.form.get('quantity'))
purchase_price = float(request.form.get('purchase_price'))
product = db.get_product_by_id(product_id)
supplier = db.get_supplier_by_id(supplier_id)
if product and supplier:
# Получаем срок годности товара
expiry_date = product.get('expiry_date', '')
# Рассчитываем коэффициенты
expiry_discount_percent = get_expiry_coefficient(expiry_date)
# Базовая сумма
total = quantity * purchase_price
# Скидка по сроку годности
discount_amount = total * expiry_discount_percent / 100
final_total = total - discount_amount
incoming_order = {
'supplier_id': supplier_id,
'supplier_name': supplier['name'],
'product_id': product_id,
'product_name': product['name'],
'expiry_date': expiry_date,
'quantity': quantity,
'purchase_price': purchase_price,
'total': total,
'expiry_discount_percent': expiry_discount_percent,
'discount_amount': discount_amount,
'final_total': final_total
}
db.save_incoming_order(incoming_order)
db.update_stock(product_id, quantity)
if expiry_discount_percent > 0:
flash(f'Товар "{product["name"]}" поступил на склад. Применена скидка {expiry_discount_percent}% по сроку годности!', 'success')
else:
flash(f'Товар "{product["name"]}" поступил на склад в количестве {quantity} шт.', 'success')
else:
flash('Ошибка при оформлении поступления', 'danger')
return redirect(url_for('incoming'))
products = db.get_products()
suppliers = db.get_suppliers()
return render_template('incoming.html', products=products, suppliers=suppliers)
# ============ ПРИХОДНЫЕ НАКЛАДНЫЕ ============
@app.route('/incoming-orders')
def incoming_orders():
sort_by = request.args.get('sort', 'date')
order = request.args.get('order', 'desc')
orders = db.get_incoming_orders(sort_by=sort_by, order=order)
return render_template('incoming_orders.html', orders=orders, sort_by=sort_by, order=order)
# ============ ЗАПУСК ============
if __name__ == '__main__':
app.run(debug=True)