Files
orion/app/api/v1/shop/orders.py
Samir Boulahtit 238c1ec9b8 refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter)
- Add comprehensive pyproject.toml configuration
- Simplify Makefile code quality targets
- Configure exclusions for venv/.venv in pyproject.toml
- Auto-fix 1,359 linting issues across codebase

Benefits:
- Much faster builds (Ruff is written in Rust)
- Single tool replaces multiple tools
- More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q)
- All configuration centralized in pyproject.toml
- Better import sorting and formatting consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 19:37:38 +01:00

232 lines
6.5 KiB
Python

# app/api/v1/shop/orders.py
"""
Shop Orders API (Public)
Public endpoints for managing customer orders in shop frontend.
Uses vendor from request.state (injected by VendorContextMiddleware).
Requires customer authentication for most operations.
"""
import logging
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
from sqlalchemy.orm import Session
from app.api.deps import get_current_customer_api
from app.core.database import get_db
from app.services.customer_service import customer_service
from app.services.order_service import order_service
from models.database.customer import Customer
from models.database.user import User
from models.schema.order import (
OrderCreate,
OrderDetailResponse,
OrderListResponse,
OrderResponse,
)
router = APIRouter()
logger = logging.getLogger(__name__)
def get_customer_from_user(request: Request, user: User, db: Session) -> Customer:
"""
Helper to get Customer record from authenticated User.
Args:
request: FastAPI request (to get vendor)
user: Authenticated user
db: Database session
Returns:
Customer record
Raises:
HTTPException: If customer not found or vendor mismatch
"""
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Find customer record for this user and vendor
customer = customer_service.get_customer_by_user_id(
db=db, vendor_id=vendor.id, user_id=user.id
)
if not customer:
raise HTTPException(
status_code=404, detail="Customer account not found for current vendor"
)
return customer
@router.post("/orders", response_model=OrderResponse)
def place_order(
request: Request,
order_data: OrderCreate,
current_user: User = Depends(get_current_customer_api),
db: Session = Depends(get_db),
):
"""
Place a new order for current vendor.
Vendor is automatically determined from request context.
Customer must be authenticated to place an order.
Creates an order from the customer's cart.
Request Body:
- Order data including shipping address, payment method, etc.
"""
# Get vendor from middleware
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
customer = get_customer_from_user(request, current_user, db)
logger.debug(
f"[SHOP_API] place_order for customer {customer.id}",
extra={
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"customer_id": customer.id,
"user_id": current_user.id,
},
)
# Create order
order = order_service.create_order(
db=db, vendor_id=vendor.id, order_data=order_data
)
logger.info(
f"Order {order.order_number} placed for vendor {vendor.subdomain}, "
f"total: €{order.total_amount:.2f}",
extra={
"order_id": order.id,
"order_number": order.order_number,
"customer_id": customer.id,
"total_amount": float(order.total_amount),
},
)
# TODO: Update customer stats
# TODO: Clear cart
# TODO: Send order confirmation email
return OrderResponse.model_validate(order)
@router.get("/orders", response_model=OrderListResponse)
def get_my_orders(
request: Request,
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=100),
current_user: User = Depends(get_current_customer_api),
db: Session = Depends(get_db),
):
"""
Get order history for authenticated customer.
Vendor is automatically determined from request context.
Returns all orders placed by the authenticated customer.
Query Parameters:
- skip: Number of orders to skip (pagination)
- limit: Maximum number of orders to return
"""
# Get vendor from middleware
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
customer = get_customer_from_user(request, current_user, db)
logger.debug(
f"[SHOP_API] get_my_orders for customer {customer.id}",
extra={
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"customer_id": customer.id,
"skip": skip,
"limit": limit,
},
)
# Get orders
orders, total = order_service.get_customer_orders(
db=db, vendor_id=vendor.id, customer_id=customer.id, skip=skip, limit=limit
)
return OrderListResponse(
orders=[OrderResponse.model_validate(o) for o in orders],
total=total,
skip=skip,
limit=limit,
)
@router.get("/orders/{order_id}", response_model=OrderDetailResponse)
def get_order_details(
request: Request,
order_id: int = Path(..., description="Order ID", gt=0),
current_user: User = Depends(get_current_customer_api),
db: Session = Depends(get_db),
):
"""
Get detailed order information for authenticated customer.
Vendor is automatically determined from request context.
Customer can only view their own orders.
Path Parameters:
- order_id: ID of the order to retrieve
"""
# Get vendor from middleware
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
customer = get_customer_from_user(request, current_user, db)
logger.debug(
f"[SHOP_API] get_order_details: order {order_id}",
extra={
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"customer_id": customer.id,
"order_id": order_id,
},
)
# Get order
order = order_service.get_order(db=db, vendor_id=vendor.id, order_id=order_id)
# Verify order belongs to customer
if order.customer_id != customer.id:
from app.exceptions import OrderNotFoundException
raise OrderNotFoundException(str(order_id))
return OrderDetailResponse.model_validate(order)