Coverage for modules\team\schemas.py: 99%

94 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-06 17:03 +0800

1from typing import Optional, List 

2from pydantic import BaseModel, ConfigDict, EmailStr, field_validator 

3from uuid import UUID 

4from datetime import datetime 

5 

6class AttendanceLogOut(BaseModel): 

7 id: UUID 

8 user_id: UUID 

9 user_name: Optional[str] = None 

10 user_email: Optional[str] = None 

11 department_name: Optional[str] = None 

12 check_in: datetime 

13 check_out: Optional[datetime] = None 

14 status: str 

15 notes: Optional[str] = None 

16 created_at: datetime 

17 updated_at: datetime 

18 

19 model_config = ConfigDict(from_attributes=True) 

20 

21 

22class AttendanceActionIn(BaseModel): 

23 notes: Optional[str] = None 

24 

25 

26class DepartmentIn(BaseModel): 

27 name: str 

28 code: str 

29 description: Optional[str] = None 

30 parent_id: Optional[UUID] = None 

31 manager_id: Optional[UUID] = None 

32 

33class DepartmentOut(BaseModel): 

34 id: UUID 

35 name: str 

36 code: str 

37 description: Optional[str] = None 

38 parent_id: Optional[UUID] = None 

39 parent_name: Optional[str] = None 

40 manager_id: Optional[UUID] = None 

41 manager_name: Optional[str] = None 

42 members_count: int = 0 

43 created_at: datetime 

44 

45 model_config = ConfigDict(from_attributes=True) 

46 

47class TeamMemberIn(BaseModel): 

48 user_id: UUID 

49 department_id: Optional[UUID] = None 

50 job_title: Optional[str] = None 

51 role: str = 'MEMBER' 

52 

53class LocalUserIn(BaseModel): 

54 local_email: str 

55 external_email: Optional[EmailStr] = None 

56 password: Optional[str] = None 

57 first_name: str = '' 

58 last_name: str = '' 

59 department_id: Optional[UUID] = None 

60 job_title: Optional[str] = None 

61 role: str = 'MEMBER' 

62 

63 @field_validator('local_email') 

64 @classmethod 

65 def validate_local_email(cls, value: str) -> str: 

66 value = value.strip().lower() 

67 if '@' not in value or '.' not in value.rsplit('@', 1)[-1]: 

68 raise ValueError('Enter a valid local email address.') 

69 return value 

70 

71class TeamMemberUpdateIn(BaseModel): 

72 department_id: Optional[UUID] = None 

73 job_title: Optional[str] = None 

74 role: Optional[str] = None 

75 status: Optional[str] = None 

76 

77class TeamMemberOut(BaseModel): 

78 id: UUID 

79 user_id: UUID 

80 email: str 

81 first_name: str 

82 last_name: str 

83 full_name: str 

84 avatar_url: Optional[str] = None 

85 phone_number: Optional[str] = None 

86 external_email: Optional[str] = None 

87 department_id: Optional[UUID] = None 

88 department_name: Optional[str] = None 

89 job_title: Optional[str] = None 

90 role: str 

91 status: str 

92 joined_at: datetime 

93 

94 model_config = ConfigDict(from_attributes=True) 

95 

96class InviteIn(BaseModel): 

97 email: EmailStr 

98 role: str = 'MEMBER' 

99 department_id: Optional[UUID] = None 

100 

101class InvitationOut(BaseModel): 

102 id: UUID 

103 email: str 

104 role: str 

105 department_id: Optional[UUID] = None 

106 invited_by_name: str 

107 status: str 

108 expires_at: datetime 

109 created_at: datetime 

110 

111 model_config = ConfigDict(from_attributes=True)