""" HR Management Module Handles employees, contractors, payroll, and time tracking """ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import List, Optional from datetime import datetime from app.database import get_db from app.models import Employee, Contractor, EmployeeStatus, User from app.core.security import get_current_user router = APIRouter(prefix="/hr", tags=["hr"]) # ─── EMPLOYEES ──────────────────────────────────────────────────────────────── @router.get("/employees") async def list_employees( status: Optional[EmployeeStatus] = None, department: Optional[str] = None, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """List all employees with optional filtering.""" query = db.query(Employee) if status: query = query.filter(Employee.status == status) if department: query = query.filter(Employee.department.ilike(f"%{department}%")) employees = query.offset(skip).limit(limit).all() return { "employees": [ { "id": e.id, "employee_id": e.employee_id, "full_name": f"{e.first_name} {e.last_name}", "email": e.email, "department": e.department, "position": e.position, "status": e.status.value, "start_date": e.start_date.isoformat() if e.start_date else None, "salary": float(e.salary) if e.salary else None, "salary_currency": e.salary_currency, } for e in employees ], "total": query.count(), } @router.post("/employees") async def create_employee( employee_id: str, first_name: str, last_name: str, email: str, department: str, position: str, salary: float, start_date: datetime, phone: Optional[str] = None, manager_id: Optional[int] = None, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Create a new employee record.""" employee = Employee( employee_id=employee_id, first_name=first_name, last_name=last_name, email=email, phone=phone, department=department, position=position, salary=salary, start_date=start_date, manager_id=manager_id, ) db.add(employee) db.commit() db.refresh(employee) return {"status": "created", "employee_id": employee.id} @router.get("/employees/{employee_id}") async def get_employee( employee_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Get employee details.""" employee = db.query(Employee).filter(Employee.id == employee_id).first() if not employee: raise HTTPException(status_code=404, detail="Employee not found") return { "id": employee.id, "employee_id": employee.employee_id, "first_name": employee.first_name, "last_name": employee.last_name, "email": employee.email, "phone": employee.phone, "department": employee.department, "position": employee.position, "status": employee.status.value, "start_date": employee.start_date.isoformat() if employee.start_date else None, "end_date": employee.end_date.isoformat() if employee.end_date else None, "salary": float(employee.salary) if employee.salary else None, "salary_currency": employee.salary_currency, "manager_id": employee.manager_id, } @router.put("/employees/{employee_id}") async def update_employee( employee_id: int, department: Optional[str] = None, position: Optional[str] = None, salary: Optional[float] = None, status: Optional[EmployeeStatus] = None, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Update employee information.""" employee = db.query(Employee).filter(Employee.id == employee_id).first() if not employee: raise HTTPException(status_code=404, detail="Employee not found") if department: employee.department = department if position: employee.position = position if salary: employee.salary = salary if status: employee.status = status if status == EmployeeStatus.TERMINATED: employee.end_date = datetime.utcnow() db.commit() db.refresh(employee) return {"status": "updated", "employee_id": employee.id} # ─── CONTRACTORS ────────────────────────────────────────────────────────────── @router.get("/contractors") async def list_contractors( status: Optional[str] = None, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """List all contractors.""" query = db.query(Contractor) if status: query = query.filter(Contractor.status == status) contractors = query.all() return { "contractors": [ { "id": c.id, "contractor_id": c.contractor_id, "company_name": c.company_name, "contact_name": c.contact_name, "email": c.email, "services": c.services, "hourly_rate": float(c.hourly_rate) if c.hourly_rate else None, "currency": c.currency, "contract_start": c.contract_start.isoformat() if c.contract_start else None, "contract_end": c.contract_end.isoformat() if c.contract_end else None, "status": c.status, } for c in contractors ], "total": query.count(), } @router.post("/contractors") async def create_contractor( contractor_id: str, company_name: str, contact_name: str, email: str, services: List[str], hourly_rate: float, contract_start: datetime, contract_end: Optional[datetime] = None, phone: Optional[str] = None, currency: str = "SEK", db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Create a new contractor record.""" contractor = Contractor( contractor_id=contractor_id, company_name=company_name, contact_name=contact_name, email=email, phone=phone, services=services, hourly_rate=hourly_rate, currency=currency, contract_start=contract_start, contract_end=contract_end, ) db.add(contractor) db.commit() db.refresh(contractor) return {"status": "created", "contractor_id": contractor.id} @router.get("/contractors/{contractor_id}") async def get_contractor( contractor_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Get contractor details.""" contractor = db.query(Contractor).filter(Contractor.id == contractor_id).first() if not contractor: raise HTTPException(status_code=404, detail="Contractor not found") return { "id": contractor.id, "contractor_id": contractor.contractor_id, "company_name": contractor.company_name, "contact_name": contractor.contact_name, "email": contractor.email, "phone": contractor.phone, "services": contractor.services, "hourly_rate": float(contractor.hourly_rate) if contractor.hourly_rate else None, "currency": contractor.currency, "contract_start": contractor.contract_start.isoformat() if contractor.contract_start else None, "contract_end": contractor.contract_end.isoformat() if contractor.contract_end else None, "status": contractor.status, } # ─── PAYROLL ────────────────────────────────────────────────────────────────── @router.get("/payroll/summary") async def get_payroll_summary( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Get payroll summary.""" employees = db.query(Employee).filter(Employee.status == EmployeeStatus.ACTIVE).all() contractors = db.query(Contractor).filter(Contractor.status == "active").all() total_salary = sum(float(e.salary) for e in employees if e.salary) total_contractor_cost = sum(float(c.hourly_rate) * 160 for c in contractors if c.hourly_rate) # Assume 160h/month return { "period": datetime.utcnow().strftime("%Y-%m"), "employees": { "count": len(employees), "total_monthly_salary": total_salary, "currency": "SEK", }, "contractors": { "count": len(contractors), "estimated_monthly_cost": total_contractor_cost, "currency": "SEK", }, "total_monthly_cost": total_salary + total_contractor_cost, }