Coverage for apps/client_needs/services.py: 94%

23 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-04 17:24 +0000

1"""Client-need helpers shared by the staff API and the borrower portal.""" 

2 

3from __future__ import annotations 

4 

5from apps.client_needs.models import ClientNeed 

6from domain.enums import ClientNeedStatus, ClientNeedType 

7 

8 

9def generate_standard_needs(loan) -> tuple[list[ClientNeed], int]: 

10 """Add the standard document requests for ``loan`` (by purpose), skipping any it already 

11 has by name. Returns ``(created, skipped_count)``. Used by ``POST /loans/{guid}/ 

12 generate-needs`` and by borrower-portal submit (add-borrower-portal-api design.md D9).""" 

13 existing = set(loan.needs.values_list("name", flat=True)) 

14 existing_lower = {n.lower() for n in existing} 

15 

16 primary_borrower = loan.borrowers.filter(is_primary=True).first() or loan.borrowers.first() 

17 borrower_ids = [primary_borrower.id] if primary_borrower else [] 

18 

19 standard = [ 

20 { 

21 "name": "Government-Issued Photo ID", 

22 "type": ClientNeedType.DOC_REQUEST.value, 

23 "description": "Driver's license, passport or state ID for all borrowers.", 

24 }, 

25 { 

26 "name": "Recent 30-Day Pay Stubs", 

27 "type": ClientNeedType.DOC_REQUEST.value, 

28 "description": "Most recent 30 consecutive days of paystubs showing YTD earnings.", 

29 }, 

30 { 

31 "name": "Last 2 Years W-2 Statements", 

32 "type": ClientNeedType.DOC_REQUEST.value, 

33 "description": "Official W-2 or 1099 statements for the prior 2 tax years.", 

34 }, 

35 { 

36 "name": "Last 2 Months Bank Statements", 

37 "type": ClientNeedType.DOC_REQUEST.value, 

38 "description": ( 

39 "All pages of checking and savings accounts used for assets or reserves." 

40 ), 

41 }, 

42 ] 

43 if loan.purpose == "Purchase": 43 ↛ 52line 43 didn't jump to line 52 because the condition on line 43 was always true

44 standard.append( 

45 { 

46 "name": "Executed Purchase Agreement", 

47 "type": ClientNeedType.DOC_REQUEST.value, 

48 "description": "Signed purchase and sales contract including all addenda.", 

49 } 

50 ) 

51 else: 

52 standard.append( 

53 { 

54 "name": "Current Mortgage Statement", 

55 "type": ClientNeedType.DOC_REQUEST.value, 

56 "description": ( 

57 "Latest mortgage statement for the subject property showing balance " 

58 "and escrow." 

59 ), 

60 } 

61 ) 

62 

63 created = [] 

64 skipped = 0 

65 for item in standard: 

66 if item["name"].lower() in existing_lower: 

67 skipped += 1 

68 continue 

69 need = ClientNeed.objects.create( 

70 loan=loan, 

71 name=item["name"], 

72 type=item["type"], 

73 description=item["description"], 

74 required=True, 

75 status=ClientNeedStatus.REQUESTED.value, 

76 ) 

77 if borrower_ids: 

78 need.borrowers.set(borrower_ids) 

79 created.append(need) 

80 

81 return created, skipped