bober-bbq-bot/tests/test_tech_cards.py
byrsapty 5501fe3094 Tech cards: remove photo without replacement, header spacing, order link
- New "Видалити фото (без заміни)" checkbox on the tech card form —
  previously the only way to clear a plating photo was uploading a
  replacement.
- Fixed missing top margin between the "← До тех карт" back-link and the
  product header on the tech card form.
- Order detail page now links each item to its tech card (when the viewer
  has tech-card access) so kitchen staff can jump straight to prep
  instructions while working an order.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 00:19:32 +03:00

151 lines
5.4 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.

"""Тех карти (bober_bbq/admin/tech_cards.py) — kitchen-only instructions +
plating photo per product. Access follows the same admin/manager-toggle
pattern as suppliers (see admin/authz.py's tech_cards_access_required).
"""
from bober_bbq.config import config
from bober_bbq.extensions import db
from bober_bbq.models import AdminUser, Category, Order, OrderItem, Product, Setting, TechCard
def _make_category(app):
with app.app_context():
cat = Category(name="Тестова категорія", slug="test-tech-cards-cat", sort_order=999)
db.session.add(cat)
db.session.commit()
return cat.id
def _make_product(app):
with app.app_context():
cat_id = _make_category(app)
product = Product(category_id=cat_id, name="Шашлик класичний", price=150, is_active=True)
db.session.add(product)
db.session.commit()
return product.id
def _admin_login(client, app):
with app.app_context():
username, password = config.FLASK_ADMIN_USERNAME, config.FLASK_ADMIN_PASSWORD
return client.post("/admin/login", data={"username": username, "password": password}, follow_redirects=True)
def _manager_login(client, app):
with app.app_context():
manager = AdminUser(username="test-manager", role="manager")
manager.set_password("manager-pass-123")
db.session.add(manager)
db.session.commit()
return client.post(
"/admin/login", data={"username": "test-manager", "password": "manager-pass-123"}, follow_redirects=True
)
def test_manager_blocked_from_tech_cards_by_default(app):
client = app.test_client()
_manager_login(client, app)
resp = client.get("/admin/tech-cards", follow_redirects=True)
assert resp.status_code == 200
assert "Доступ до тех карт вимкнено" in resp.get_data(as_text=True)
def test_manager_allowed_when_admin_enables_access(app):
with app.app_context():
Setting.set("tech_cards_manager_access", "1")
db.session.commit()
client = app.test_client()
_manager_login(client, app)
resp = client.get("/admin/tech-cards", follow_redirects=True)
assert resp.status_code == 200
assert "Доступ до тех карт вимкнено" not in resp.get_data(as_text=True)
def test_admin_always_has_tech_cards_access(app):
client = app.test_client()
_admin_login(client, app)
resp = client.get("/admin/tech-cards", follow_redirects=True)
assert resp.status_code == 200
assert "Тех карти" in resp.get_data(as_text=True)
def test_tech_card_create_then_edit_roundtrip(app):
product_id = _make_product(app)
client = app.test_client()
_admin_login(client, app)
resp = client.post(
f"/admin/tech-cards/{product_id}",
data={"instructions": "1. Замаринувати\n2. Обсмажити", "cook_time_min": "25"},
follow_redirects=True,
)
assert resp.status_code == 200
assert "Тех карту збережено" in resp.get_data(as_text=True)
with app.app_context():
card = TechCard.query.filter_by(product_id=product_id).one()
assert card.instructions == "1. Замаринувати\n2. Обсмажити"
assert card.cook_time_min == 25
resp = client.get(f"/admin/tech-cards/{product_id}")
body = resp.get_data(as_text=True)
assert "Замаринувати" in body
assert "Видалити тех карту" in body
def test_tech_card_remove_photo_without_replacement(app):
product_id = _make_product(app)
with app.app_context():
db.session.add(TechCard(product_id=product_id, photo_url="/static/uploads/old.jpg"))
db.session.commit()
client = app.test_client()
_admin_login(client, app)
resp = client.post(
f"/admin/tech-cards/{product_id}",
data={"instructions": "", "remove_photo": "1"},
follow_redirects=True,
)
assert resp.status_code == 200
with app.app_context():
card = TechCard.query.filter_by(product_id=product_id).one()
assert card.photo_url == ""
def test_order_detail_links_to_tech_card(app):
product_id = _make_product(app)
with app.app_context():
product = Product.query.get(product_id)
order = Order(user_id=-1, order_type="pickup", customer_name="Гість", payment_method="cash", pickup_time="19:00")
db.session.add(order)
db.session.commit()
db.session.add(OrderItem(order_id=order.id, product_id=product_id, product_name=product.name, product_price=150, quantity=1))
db.session.commit()
order_id = order.id
client = app.test_client()
_admin_login(client, app)
resp = client.get(f"/admin/orders/{order_id}")
assert resp.status_code == 200
assert f"/admin/tech-cards/{product_id}" in resp.get_data(as_text=True)
def test_tech_card_delete_removes_row(app):
product_id = _make_product(app)
with app.app_context():
db.session.add(TechCard(product_id=product_id, instructions="старий текст"))
db.session.commit()
client = app.test_client()
_admin_login(client, app)
resp = client.post(f"/admin/tech-cards/{product_id}/delete", follow_redirects=True)
assert resp.status_code == 200
assert "Тех карту видалено" in resp.get_data(as_text=True)
with app.app_context():
assert TechCard.query.filter_by(product_id=product_id).first() is None