eafc1c33fc
- FastAPI backend with SQLite database - React + TailwindCSS frontend - JWT authentication - Excel upload/download for attendance and accident records - Shift roster management with S7a/S7b split - Lateness/OT calculation based on shift times - Roster info API endpoints - Export API with token query parameter support - Docker compose deployment
188 lines
4.2 KiB
Python
188 lines
4.2 KiB
Python
from pydantic import BaseModel, EmailStr, Field
|
|
from typing import Optional, List, Dict, Any
|
|
from datetime import date, time, datetime
|
|
|
|
|
|
# ============ Auth ============
|
|
class LoginRequest(BaseModel):
|
|
email: str
|
|
password: str
|
|
|
|
|
|
class TokenResponse(BaseModel):
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
id: int
|
|
email: str
|
|
name: str
|
|
role: str
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============ Attendance ============
|
|
class AttendanceBase(BaseModel):
|
|
employee_id: str
|
|
employee_name: str
|
|
department: Optional[str] = None
|
|
date: date
|
|
check_in: Optional[time] = None
|
|
check_out: Optional[time] = None
|
|
overtime_hours: float = 0
|
|
leave_type: Optional[str] = None
|
|
leave_hours: float = 0
|
|
status: str
|
|
remarks: Optional[str] = None
|
|
custom_fields: Dict[str, Any] = {}
|
|
|
|
|
|
class AttendanceCreate(AttendanceBase):
|
|
pass
|
|
|
|
|
|
class AttendanceUpdate(BaseModel):
|
|
employee_id: Optional[str] = None
|
|
employee_name: Optional[str] = None
|
|
department: Optional[str] = None
|
|
date: Optional[date] = None
|
|
check_in: Optional[time] = None
|
|
check_out: Optional[time] = None
|
|
overtime_hours: Optional[float] = None
|
|
leave_type: Optional[str] = None
|
|
leave_hours: Optional[float] = None
|
|
status: Optional[str] = None
|
|
remarks: Optional[str] = None
|
|
custom_fields: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class AttendanceResponse(AttendanceBase):
|
|
id: int
|
|
created_by: Optional[int] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============ Accident ============
|
|
class AccidentBase(BaseModel):
|
|
date: date
|
|
time: Optional[time] = None
|
|
location: str
|
|
employee_name: str
|
|
employee_id: Optional[str] = None
|
|
department: Optional[str] = None
|
|
description: str
|
|
severity: str
|
|
medical_report: Optional[str] = None
|
|
action_taken: Optional[str] = None
|
|
responsible_person: Optional[str] = None
|
|
custom_fields: Dict[str, Any] = {}
|
|
|
|
|
|
class AccidentCreate(AccidentBase):
|
|
pass
|
|
|
|
|
|
class AccidentUpdate(BaseModel):
|
|
date: Optional[date] = None
|
|
time: Optional[time] = None
|
|
location: Optional[str] = None
|
|
employee_name: Optional[str] = None
|
|
employee_id: Optional[str] = None
|
|
department: Optional[str] = None
|
|
description: Optional[str] = None
|
|
severity: Optional[str] = None
|
|
medical_report: Optional[str] = None
|
|
action_taken: Optional[str] = None
|
|
responsible_person: Optional[str] = None
|
|
custom_fields: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class AccidentResponse(AccidentBase):
|
|
id: int
|
|
created_by: Optional[int] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============ Custom Fields ============
|
|
class CustomFieldBase(BaseModel):
|
|
field_name: str
|
|
field_type: str
|
|
field_key: str
|
|
required: bool = False
|
|
options: List[str] = []
|
|
order: int = 0
|
|
|
|
|
|
class CustomFieldCreate(CustomFieldBase):
|
|
pass
|
|
|
|
|
|
class CustomFieldResponse(CustomFieldBase):
|
|
id: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============ Dashboard ============
|
|
class AttendanceStats(BaseModel):
|
|
total: int
|
|
today: int
|
|
this_month: int
|
|
by_status: Dict[str, int]
|
|
by_department: Dict[str, int]
|
|
trend: List[Dict[str, Any]]
|
|
|
|
|
|
class AccidentStats(BaseModel):
|
|
total: int
|
|
this_month: int
|
|
unresolved: int
|
|
by_severity: Dict[str, int]
|
|
recent: List[AccidentResponse]
|
|
|
|
|
|
# ============ Import ============
|
|
class ImportRequest(BaseModel):
|
|
section: str # "attendance" or "accident"
|
|
update_existing: bool = True
|
|
|
|
|
|
class ImportResult(BaseModel):
|
|
created: int
|
|
updated: int
|
|
skipped: int
|
|
errors: List[str]
|
|
|
|
|
|
# ============ Pagination / Filter ============
|
|
class FilterParams(BaseModel):
|
|
page: int = 1
|
|
per_page: int = 20
|
|
sort_by: Optional[str] = None
|
|
sort_order: Optional[str] = "asc" # asc or desc
|
|
search: Optional[str] = None
|
|
date_from: Optional[date] = None
|
|
date_to: Optional[date] = None
|
|
department: Optional[str] = None
|
|
status: Optional[str] = None
|
|
|
|
|
|
class PaginatedResponse(BaseModel):
|
|
items: List[Any]
|
|
total: int
|
|
page: int
|
|
per_page: int
|
|
total_pages: int
|