# app/api/v1/vendor/customers.py """ Vendor customer management endpoints. Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern). The get_current_vendor_api dependency guarantees token_vendor_id is present. """ import logging from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.api.deps import get_current_vendor_api from app.core.database import get_db from app.services.customer_service import customer_service from models.database.user import User from models.schema.customer import ( CustomerDetailResponse, CustomerMessageResponse, CustomerOrdersResponse, CustomerResponse, CustomerStatisticsResponse, CustomerUpdate, VendorCustomerListResponse, ) router = APIRouter(prefix="/customers") logger = logging.getLogger(__name__) @router.get("", response_model=VendorCustomerListResponse) def get_vendor_customers( skip: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=1000), search: str | None = Query(None), is_active: bool | None = Query(None), current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get all customers for this vendor. - Query customers filtered by vendor_id - Support search by name/email - Support filtering by active status - Return paginated results """ customers, total = customer_service.get_vendor_customers( db=db, vendor_id=current_user.token_vendor_id, skip=skip, limit=limit, search=search, is_active=is_active, ) return VendorCustomerListResponse( customers=[CustomerResponse.model_validate(c) for c in customers], total=total, skip=skip, limit=limit, ) @router.get("/{customer_id}", response_model=CustomerDetailResponse) def get_customer_details( customer_id: int, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get detailed customer information. - Get customer by ID - Verify customer belongs to vendor - Include order statistics """ # Service will raise CustomerNotFoundException if not found customer = customer_service.get_customer( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, ) # Get statistics stats = customer_service.get_customer_statistics( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, ) return CustomerDetailResponse( id=customer.id, email=customer.email, first_name=customer.first_name, last_name=customer.last_name, phone=customer.phone, customer_number=customer.customer_number, is_active=customer.is_active, marketing_consent=customer.marketing_consent, total_orders=stats["total_orders"], total_spent=stats["total_spent"], average_order_value=stats["average_order_value"], last_order_date=stats["last_order_date"], created_at=customer.created_at, ) @router.get("/{customer_id}/orders", response_model=CustomerOrdersResponse) def get_customer_orders( customer_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get order history for a specific customer. - Get all orders for customer - Filter by vendor_id - Return order details """ # Service will raise CustomerNotFoundException if not found orders, total = customer_service.get_customer_orders( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, skip=skip, limit=limit, ) return CustomerOrdersResponse( orders=[ { "id": o.id, "order_number": o.order_number, "status": o.status, "total": o.total_cents / 100 if o.total_cents else 0, "created_at": o.created_at, } for o in orders ], total=total, skip=skip, limit=limit, ) @router.put("/{customer_id}", response_model=CustomerMessageResponse) def update_customer( customer_id: int, customer_data: CustomerUpdate, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Update customer information. - Update customer details - Verify customer belongs to vendor """ # Service will raise CustomerNotFoundException if not found customer_service.update_customer( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, customer_data=customer_data, ) db.commit() return CustomerMessageResponse(message="Customer updated successfully") @router.put("/{customer_id}/status", response_model=CustomerMessageResponse) def toggle_customer_status( customer_id: int, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Activate/deactivate customer account. - Toggle customer is_active status - Verify customer belongs to vendor """ # Service will raise CustomerNotFoundException if not found customer = customer_service.toggle_customer_status( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, ) db.commit() status = "activated" if customer.is_active else "deactivated" return CustomerMessageResponse(message=f"Customer {status} successfully") @router.get("/{customer_id}/stats", response_model=CustomerStatisticsResponse) def get_customer_statistics( customer_id: int, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get customer statistics and metrics. - Total orders - Total spent - Average order value - Last order date """ # Service will raise CustomerNotFoundException if not found stats = customer_service.get_customer_statistics( db=db, vendor_id=current_user.token_vendor_id, customer_id=customer_id, ) return CustomerStatisticsResponse(**stats)