229 lines
5.6 KiB
Python
229 lines
5.6 KiB
Python
from datetime import datetime
|
|
|
|
from flask import Blueprint, redirect, render_template, request, url_for
|
|
from sqlalchemy import distinct, select
|
|
from werkzeug.wrappers.response import Response
|
|
|
|
from app.db import SessionLocal
|
|
from app.models import Drink, Transaction
|
|
|
|
bp = Blueprint("main", __name__)
|
|
|
|
|
|
@bp.get("/")
|
|
def index() -> str:
|
|
return render_template("index.html")
|
|
|
|
|
|
@bp.get("/add")
|
|
def create_drink_get() -> str:
|
|
return render_template("add.html")
|
|
|
|
|
|
@bp.post("/add")
|
|
def create_drink_post() -> Response | tuple[str, int]:
|
|
name = request.form.get("name")
|
|
stock_raw = request.form.get("stock")
|
|
price_raw = request.form.get("price")
|
|
contact = request.form.get("phone_number")
|
|
|
|
if name is None or stock_raw is None or price_raw is None or contact is None:
|
|
return "Missing required fields", 400
|
|
|
|
name = name.strip()
|
|
contact = contact.strip()
|
|
|
|
try:
|
|
stock = int(stock_raw)
|
|
price = float(price_raw)
|
|
except ValueError:
|
|
return "Invalid numeric input", 400
|
|
|
|
if stock <= 0 or price <= 0:
|
|
return "Invalid stock or price", 400
|
|
|
|
session = SessionLocal()
|
|
|
|
drink = Drink(name=name, stock=stock, price=price, stocked_by=contact)
|
|
|
|
session.add(drink)
|
|
session.commit()
|
|
|
|
return redirect(url_for("main.list_drinks_get", id=drink.id))
|
|
|
|
|
|
@bp.get("/drink/<id>/manage")
|
|
def manage_drink_get(id: int) -> str | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
return render_template("drink_manage.html", drink=drink)
|
|
|
|
|
|
@bp.post("/drink/<id>/restock")
|
|
def restock_drink_post(id: int) -> Response | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
amount_raw = request.form.get("amount")
|
|
|
|
if amount_raw is None:
|
|
return "Missing fields", 400
|
|
|
|
try:
|
|
amount = int(amount_raw)
|
|
except ValueError:
|
|
return "Non numeric amount", 400
|
|
|
|
if amount <= 0:
|
|
return "Invalid amount", 400
|
|
|
|
drink.stock += amount
|
|
session.commit()
|
|
|
|
return redirect(url_for("main.manage_drink_get", id=id))
|
|
|
|
|
|
@bp.post("/drink/<id>/price")
|
|
def change_price_post(id: int) -> Response | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
price_raw = request.form.get("price")
|
|
|
|
if price_raw is None:
|
|
return "Missing fields", 400
|
|
|
|
try:
|
|
price = float(price_raw)
|
|
except ValueError:
|
|
return "Non numeric amount", 400
|
|
|
|
if price <= 0:
|
|
return "Invalid price", 400
|
|
|
|
drink.price = price
|
|
session.commit()
|
|
|
|
return redirect(url_for("main.manage_drink_get", id=id))
|
|
|
|
|
|
@bp.post("/drink/<id>/delete")
|
|
def delete_drink_post(id: int) -> Response | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
session.delete(drink)
|
|
session.commit()
|
|
|
|
return redirect(url_for("main.list_drinks_get"))
|
|
|
|
|
|
@bp.get("/drinks")
|
|
def list_drinks_get() -> str:
|
|
session = SessionLocal()
|
|
|
|
stmt = select(Drink)
|
|
result = session.execute(stmt)
|
|
drinks = [row[0] for row in result if row[0]]
|
|
|
|
return render_template("drink_list.html", drinks=drinks)
|
|
|
|
|
|
@bp.get("/drink/<id>")
|
|
def buy_drink_get(id: int) -> str | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
# Find user names
|
|
stmt = select(distinct(Transaction.user_name)).order_by(Transaction.user_name)
|
|
result = session.execute(stmt).all()
|
|
names = [row[0] for row in result if row[0]]
|
|
|
|
return render_template("drink_buy.html", drink=drink, names=names)
|
|
|
|
|
|
@bp.post("/drink/<id>/buy")
|
|
def buy_drink_post(id: int) -> Response | tuple[str, int]: # noqa: A002
|
|
session = SessionLocal()
|
|
|
|
drink = session.get(Drink, id)
|
|
if drink is None:
|
|
return "Drink not found", 404
|
|
|
|
name = request.form.get("name")
|
|
qty_raw = request.form.get("quantity")
|
|
|
|
if name is None or qty_raw is None:
|
|
return "Missing fields", 400
|
|
|
|
name = name.strip()
|
|
|
|
try:
|
|
quantity = int(qty_raw)
|
|
except ValueError:
|
|
return "Invalid quantity", 400
|
|
|
|
if quantity <= 0:
|
|
return "Quantity must be positive", 400
|
|
|
|
if drink.stock < quantity:
|
|
return "Not enough stock", 400
|
|
|
|
# Update stock
|
|
drink.stock -= quantity
|
|
|
|
# Calculate cost
|
|
cost = drink.price * quantity
|
|
|
|
# Create transaction
|
|
transaction = Transaction(
|
|
drink=drink.id, user_name=name, quantity=quantity, cost=cost, timestamp=datetime.now().astimezone()
|
|
)
|
|
|
|
session.add(transaction)
|
|
session.commit()
|
|
|
|
return redirect(url_for("main.list_drinks_get", id=id))
|
|
|
|
|
|
@bp.get("/transactions")
|
|
def list_transactions_get() -> str:
|
|
session = SessionLocal()
|
|
|
|
stmt = select(Transaction).order_by(Transaction.timestamp)
|
|
result = session.execute(stmt).all()
|
|
txs: list[Transaction] = [row[0] for row in result if row[0]]
|
|
|
|
stmt = select(Drink)
|
|
result = session.execute(stmt).all()
|
|
drinks: dict[int, Drink] = {row[0].id: row[0] for row in result if row[0]}
|
|
|
|
patched = [
|
|
{
|
|
"drink_name": drinks[t.drink].name if t.drink in drinks else "<removed drink>",
|
|
"user_name": t.user_name,
|
|
"quantity": t.quantity,
|
|
"cost": t.cost,
|
|
"timestamp": t.timestamp,
|
|
}
|
|
for t in txs
|
|
]
|
|
|
|
return render_template("transactions.html", transactions=patched)
|