from decimal import Decimal from unittest import mock import pytest from conftest import APSTestClient from fake_data import fake from sqlalchemy import select from allmende_payment_system.database import ensure_user from allmende_payment_system.models import ( Account, Area, Order, OrderItem, Product, Transaction, ) def create_user_with_account(test_db, username: str, balance: float | None = None): user_info = {"username": username, "display_name": f"Display {username}"} user = ensure_user(user_info, test_db) account = Account(name=f"Account for {username}") test_db.add(account) user.accounts.append(account) if balance is not None: user.accounts[0].transactions.append( Transaction(total_amount=Decimal(balance), type="deposit") ) test_db.flush() return user def add_finalized_order_to_user(test_db, user, product) -> Order: order = Order(user=user) total_amount = product.price order.items.append( OrderItem(product=product, quantity=1, total_amount=total_amount) ) order.transaction = Transaction(total_amount=total_amount, type="order") order.transaction.account = user.accounts[0] test_db.add(order) test_db.flush() return order @pytest.fixture def product(test_db): area = Area(**fake.area()) test_db.add(area) product = Product(**fake.product()) product.area = area test_db.add(product) test_db.flush() return product def test_add_item_to_cart(client: APSTestClient, test_db, product): form_data = {"product_id": product.id, "quantity": 2, "area_id": product.area.id} response = client.post( "/shop/cart/add", data=form_data, headers={"Content-Type": "application/x-www-form-urlencoded"}, follow_redirects=False, ) assert response.status_code == 302 cart = test_db.scalar(select(Order)) assert len(cart.items) == 1 def test_edit_item_in_cart(client: APSTestClient, test_db, product): form_data = {"product_id": product.id, "quantity": 2, "area_id": product.area.id} response = client.post( "/shop/cart/add", data=form_data, headers={"Content-Type": "application/x-www-form-urlencoded"}, follow_redirects=False, ) assert response.status_code == 302 form_data = {"quantity": 3} response = client.post( f"/shop/cart/update/{test_db.scalar(select(OrderItem)).id}", data=form_data, headers={"Content-Type": "application/x-www-form-urlencoded"}, follow_redirects=False, ) assert response.status_code == 302 cart = test_db.scalar(select(Order)) assert len(cart.items) == 1 assert cart.items[0].quantity == 3 assert cart.items[0].total_amount == product.price * 3 def test_remove_item_from_cart(client: APSTestClient, test_db, product): user = create_user_with_account(test_db, "test") user.shopping_cart.items.append( OrderItem(product=product, quantity=2, total_amount=product.price * 2) ) test_db.flush() cart = test_db.scalar(select(Order)) assert len(cart.items) == 1 response = client.get( f"/shop/cart/remove/{user.shopping_cart.items[0].id}", follow_redirects=False ) assert response.status_code == 302 cart = test_db.scalar(select(Order)) assert len(cart.items) == 0 assert len(test_db.scalars(select(OrderItem)).all()) == 0 def test_remove_item_from_cart_wrong_user(client: APSTestClient, test_db, product): user = create_user_with_account(test_db, "test") user.shopping_cart.items.append( OrderItem(product=product, quantity=2, total_amount=product.price * 2) ) test_db.flush() cart = test_db.scalar(select(Order)) assert len(cart.items) == 1 id_ = user.shopping_cart.items[0].id response = client.get( f"/shop/cart/remove/{id_}", follow_redirects=False, user="other_user" ) assert response.status_code == 404 cart = test_db.scalar(select(Order)) assert len(cart.items) == 1 def test_finalize_order(client: APSTestClient, test_db, product): user = create_user_with_account(test_db, "test", balance=100.0) user.shopping_cart.items.append( OrderItem(product=product, quantity=2, total_amount=product.price * 2) ) test_db.flush() response = client.get("/shop/finalize_order", follow_redirects=False) assert response.status_code == 302 assert len(user.shopping_cart.items) == 0 assert len(user.orders) == 2 # shopping cart + finalized order assert user.accounts[0].balance == Decimal(100.0) - (product.price * 2) def test_view_order(client: APSTestClient, test_db, product): user = create_user_with_account(test_db, "test") order = add_finalized_order_to_user(test_db, user, product) response = client.get(f"/shop/order/{order.id}") assert response.status_code == 200 assert f"Einkauf #{order.id}" in response.text assert product.name in response.text def test_view_order_wrong_user(client: APSTestClient, test_db, product): user = create_user_with_account(test_db, "test") order = add_finalized_order_to_user(test_db, user, product) response = client.get( f"/shop/order/{order.id}", follow_redirects=False, user="other_user" ) assert response.status_code == 403