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
« 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
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
19 model_config = ConfigDict(from_attributes=True)
22class AttendanceActionIn(BaseModel):
23 notes: Optional[str] = None
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
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
45 model_config = ConfigDict(from_attributes=True)
47class TeamMemberIn(BaseModel):
48 user_id: UUID
49 department_id: Optional[UUID] = None
50 job_title: Optional[str] = None
51 role: str = 'MEMBER'
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'
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
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
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
94 model_config = ConfigDict(from_attributes=True)
96class InviteIn(BaseModel):
97 email: EmailStr
98 role: str = 'MEMBER'
99 department_id: Optional[UUID] = None
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
111 model_config = ConfigDict(from_attributes=True)