diff --git a/pyproject.toml b/pyproject.toml index e019bce..e600cc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ build-backend = "uv_build" [dependency-groups] dev = [ "black>=25.9.0", + "faker>=38.2.0", "httpx>=0.28.1", "isort>=7.0.0", "pytest>=8.4.2", diff --git a/src/allmende_payment_system/api/__init__.py b/src/allmende_payment_system/api/__init__.py index 3f0a390..9ae8d3c 100644 --- a/src/allmende_payment_system/api/__init__.py +++ b/src/allmende_payment_system/api/__init__.py @@ -11,7 +11,6 @@ templates = get_jinja_renderer() @root_router.get("/") async def landing_page(request: Request, user: UserDep, session: SessionDep): - print(f"User {user.username} ({user.display_name}) accessed landing page") transactions = [] for account in user.accounts: transactions += account.transactions diff --git a/src/allmende_payment_system/api/dependencies.py b/src/allmende_payment_system/api/dependencies.py index 67cf694..1295243 100644 --- a/src/allmende_payment_system/api/dependencies.py +++ b/src/allmende_payment_system/api/dependencies.py @@ -13,6 +13,7 @@ def get_session() -> Session: try: yield db finally: + db.commit() db.close() diff --git a/src/allmende_payment_system/api/shop.py b/src/allmende_payment_system/api/shop.py index 9a7d868..a6b9eee 100644 --- a/src/allmende_payment_system/api/shop.py +++ b/src/allmende_payment_system/api/shop.py @@ -1,8 +1,12 @@ +from decimal import Decimal + from fastapi import APIRouter, Request from sqlalchemy import select +from starlette import status +from starlette.responses import RedirectResponse -from allmende_payment_system.api import SessionDep -from allmende_payment_system.models import Area +from allmende_payment_system.api.dependencies import SessionDep, UserDep +from allmende_payment_system.models import Area, OrderItem, Product from allmende_payment_system.tools import get_jinja_renderer shop_router = APIRouter() @@ -20,6 +24,26 @@ async def get_shop(request: Request, session: SessionDep): ) +@shop_router.get("/shop/cart") +async def get_cart(request: Request, session: SessionDep, user: UserDep): + + return templates.TemplateResponse( + "cart.html.jinja", + context={"request": request, "user": user}, + ) + + +@shop_router.get("/shop/finalize_order") +async def get_cart(request: Request, session: SessionDep, user: UserDep): + + cart = user.shopping_cart + + # TODO: Implement + cart.finalize_order() + + return RedirectResponse(url=f"/", status_code=status.HTTP_302_FOUND) + + @shop_router.get("/shop/area/{area_id}") async def get_shop(request: Request, session: SessionDep, area_id: int): query = select(Area).where(Area.id == area_id) @@ -28,3 +52,27 @@ async def get_shop(request: Request, session: SessionDep, area_id: int): "area.html.jinja", context={"request": request, "area": area}, ) + + +@shop_router.post("/shop/cart/add") +async def add_to_cart(request: Request, session: SessionDep, user: UserDep): + form_data = await request.form() + + query = select(Product).where(Product.id == form_data["product_id"]) + product = session.scalars(query).one() + + quantity = Decimal(form_data["quantity"]) + total_amount = product.price * quantity + + order_item = OrderItem( + product=product, quantity=quantity, total_amount=total_amount + ) + session.add(order_item) + cart = user.shopping_cart + cart.items.append(order_item) + + session.flush() + + return RedirectResponse( + url=f"/shop/area/{form_data['area_id']}", status_code=status.HTTP_302_FOUND + ) diff --git a/src/allmende_payment_system/database.py b/src/allmende_payment_system/database.py index 2ed4cec..1b6c6b8 100644 --- a/src/allmende_payment_system/database.py +++ b/src/allmende_payment_system/database.py @@ -24,6 +24,6 @@ def ensure_user(user_info: dict, session: Session) -> User: username=user_info["username"], display_name=user_info.get("display_name") ) session.add(user) - session.commit() + session.flush() return user diff --git a/src/allmende_payment_system/models.py b/src/allmende_payment_system/models.py index 3d19a8b..b82beb9 100644 --- a/src/allmende_payment_system/models.py +++ b/src/allmende_payment_system/models.py @@ -82,6 +82,7 @@ class Area(Base): UnitsOfMeasure = typing.Literal[ "g", "kg", + "l", "piece", ] @@ -121,6 +122,10 @@ class Order(Base): def is_in_shopping_cart(self): return self.account is None + @property + def total_amount(self): + return sum(item.total_amount for item in self.items) + class OrderItem(Base): __tablename__ = TABLE_PREFIX + "order_item" @@ -130,7 +135,7 @@ class OrderItem(Base): product_id: Mapped[int] = mapped_column(ForeignKey(TABLE_PREFIX + "product.id")) product: Mapped[Product] = relationship("Product") - quantity: Mapped[int] = mapped_column(nullable=False) + quantity: Mapped[decimal.Decimal] = mapped_column(nullable=False) total_amount: Mapped[decimal.Decimal] = mapped_column( Numeric(10, 2), nullable=False ) diff --git a/src/allmende_payment_system/templates/area.html.jinja b/src/allmende_payment_system/templates/area.html.jinja index b7ec129..94b2938 100644 --- a/src/allmende_payment_system/templates/area.html.jinja +++ b/src/allmende_payment_system/templates/area.html.jinja @@ -25,12 +25,85 @@
{{ product.description }}
Überprüfe deine Artikel und fahre zur Kasse fort.
+| Artikel | +Menge | +Einzelpreis | +Summe | ++ |
|---|---|---|---|---|
|
+ {{ item.product.name }}
+ {{ item.description or '' }}
+ |
+ + + | +{{ item.product.price | format_number }} € | +{{ item.total_amount | format_number }} € | ++ Entfernen + | +
| Gesamtsumme | +{{ user.shopping_cart.total_amount | format_number }} € | ++ | ||