Coverage for apps/core_los/contacts_api.py: 94%
27 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-04 14:06 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-04 14:06 +0000
1"""Contacts router: business-contact directory + borrower directory (mounted at "")."""
3from ninja import Router
5from apps.accounts.auth import requires, staff_loan_queryset
6from apps.application_1003.models import Borrower
7from apps.core_los.models import BusinessContact
8from apps.core_los.schemas import (
9 BusinessContactCreate,
10 BusinessContactOut,
11 DirectoryBorrowerOut,
12)
13from domain.result import AppError, DomainError
15router = Router(tags=["contacts"])
18@router.get(
19 "/business-contacts", response=list[BusinessContactOut], auth=requires("CONTACT_VIEW")
20)
21def list_business_contacts(request):
22 return list(BusinessContact.objects.all().order_by("name"))
25@router.post(
26 "/business-contacts", response={201: BusinessContactOut}, auth=requires("CONTACT_EDIT")
27)
28def create_business_contact(request, payload: BusinessContactCreate):
29 if not payload.name.strip(): 29 ↛ 30line 29 didn't jump to line 30 because the condition on line 29 was never true
30 raise DomainError([AppError("VALIDATION", "Name is required", "name")])
31 contact = BusinessContact.objects.create(**payload.model_dump())
32 return 201, contact
35@router.delete(
36 "/business-contacts/{contact_id}", response={204: None}, auth=requires("CONTACT_EDIT")
37)
38def delete_business_contact(request, contact_id: int):
39 deleted, _ = BusinessContact.objects.filter(pk=contact_id).delete()
40 if deleted == 0:
41 raise DomainError([AppError("NOT_FOUND", "Contact not found")])
42 return 204, None
45@router.get(
46 "/borrower-directory", response=list[DirectoryBorrowerOut], auth=requires("LOAN_VIEW")
47)
48def borrower_directory(request):
49 qs = staff_loan_queryset(request.principal, "all")
50 borrowers = Borrower.objects.filter(loan__in=qs, is_primary=True).select_related("loan")
51 return [
52 {
53 "name": f"{b.first_name} {b.last_name}",
54 "email": b.email,
55 "phone": None, # Borrower has no phone field today (design.md note).
56 "loan_guid": str(b.loan.guid),
57 "loan_number": b.loan.arive_loan_no,
58 "stage": b.loan.stage,
59 }
60 for b in borrowers
61 ]