import logging from fastapi import APIRouter, Depends, HTTPException, Response, status from sqlalchemy.orm import Session from app.core.rbac import require_permission from app.db.database import get_db from app.models.customer import Customer, CustomerContact from app.models.user import User from app.repositories.customer_repository import CustomerRepository from app.schemas.customer import ( CustomerContactCreate, CustomerContactResponse, CustomerContactUpdate, CustomerCreate, CustomerResponse, CustomerUpdate, ) logger = logging.getLogger(__name__) router = APIRouter( prefix="/customers", tags=["Customers"], ) def get_customer_or_404(db: Session, customer_id: int) -> Customer: customer = CustomerRepository.get_by_id(db, customer_id) if customer is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Kunde nicht gefunden", ) return customer def get_contact_or_404(db: Session, customer_id: int, contact_id: int) -> CustomerContact: contact = CustomerRepository.get_contact_by_id(db, customer_id, contact_id) if contact is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Ansprechpartner nicht gefunden", ) return contact def ensure_unique_customer_number( db: Session, customer_number: str, customer_id: int | None = None, ) -> None: conflict = CustomerRepository.find_number_conflict( db, customer_number=customer_number, exclude_customer_id=customer_id, ) if conflict is not None: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Kundennummer ist bereits vergeben", ) @router.get("", response_model=list[CustomerResponse]) @router.get("/", response_model=list[CustomerResponse], include_in_schema=False) def get_customers( db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.read")), ): logger.info("customers.list", extra={"actor_user_id": current_user.id}) return CustomerRepository.get_all(db) @router.get("/{customer_id}", response_model=CustomerResponse) def get_customer( customer_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.read")), ): logger.info( "customers.detail", extra={"actor_user_id": current_user.id, "target_customer_id": customer_id}, ) return get_customer_or_404(db, customer_id) @router.post("", response_model=CustomerResponse, status_code=status.HTTP_201_CREATED) @router.post( "/", response_model=CustomerResponse, status_code=status.HTTP_201_CREATED, include_in_schema=False, ) def create_customer( customer: CustomerCreate, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.create")), ): ensure_unique_customer_number(db, customer.customer_number) logger.info("customers.create", extra={"actor_user_id": current_user.id}) return CustomerRepository.create(db, customer) @router.put("/{customer_id}", response_model=CustomerResponse) def update_customer( customer_id: int, customer: CustomerUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.update")), ): db_customer = get_customer_or_404(db, customer_id) ensure_unique_customer_number(db, customer.customer_number, customer_id) logger.info( "customers.update", extra={"actor_user_id": current_user.id, "target_customer_id": customer_id}, ) return CustomerRepository.update(db, db_customer, customer) @router.delete("/{customer_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_customer( customer_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.delete")), ): db_customer = get_customer_or_404(db, customer_id) logger.info( "customers.delete", extra={"actor_user_id": current_user.id, "target_customer_id": customer_id}, ) CustomerRepository.delete(db, db_customer) return Response(status_code=status.HTTP_204_NO_CONTENT) @router.get("/{customer_id}/contacts", response_model=list[CustomerContactResponse]) def get_customer_contacts( customer_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.read")), ): get_customer_or_404(db, customer_id) logger.info( "customers.contacts.list", extra={"actor_user_id": current_user.id, "target_customer_id": customer_id}, ) return CustomerRepository.get_contacts(db, customer_id) @router.post( "/{customer_id}/contacts", response_model=CustomerContactResponse, status_code=status.HTTP_201_CREATED, ) def create_customer_contact( customer_id: int, contact: CustomerContactCreate, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.update")), ): get_customer_or_404(db, customer_id) logger.info( "customers.contacts.create", extra={"actor_user_id": current_user.id, "target_customer_id": customer_id}, ) return CustomerRepository.create_contact(db, customer_id, contact) @router.put("/{customer_id}/contacts/{contact_id}", response_model=CustomerContactResponse) def update_customer_contact( customer_id: int, contact_id: int, contact: CustomerContactUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.update")), ): get_customer_or_404(db, customer_id) db_contact = get_contact_or_404(db, customer_id, contact_id) logger.info( "customers.contacts.update", extra={ "actor_user_id": current_user.id, "target_customer_id": customer_id, "target_contact_id": contact_id, }, ) return CustomerRepository.update_contact(db, db_contact, contact) @router.delete("/{customer_id}/contacts/{contact_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_customer_contact( customer_id: int, contact_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_permission("customers.update")), ): get_customer_or_404(db, customer_id) db_contact = get_contact_or_404(db, customer_id, contact_id) logger.info( "customers.contacts.delete", extra={ "actor_user_id": current_user.id, "target_customer_id": customer_id, "target_contact_id": contact_id, }, ) CustomerRepository.delete_contact(db, db_contact) return Response(status_code=status.HTTP_204_NO_CONTENT)