""" 従業員管理API (Employee Management API) """ from fastapi import APIRouter, HTTPException, status from typing import List from . import schemas from ...core.database import get_connection router = APIRouter(prefix="/payroll/employees", tags=["Payroll - Employees"]) @router.post("/", response_model=schemas.Employee, status_code=status.HTTP_201_CREATED) def create_employee(employee: schemas.EmployeeCreate): """従業員を作成""" with get_connection() as conn: with conn.cursor() as cur: cur.execute( """ INSERT INTO employees ( employee_code, name, name_kana, birth_date, gender, my_number, email, phone, postal_code, address, hire_date, termination_date, is_active, bank_name, bank_branch, bank_account_number, bank_account_type, notes, photo_url, my_number_card_image_url, residence_card_image_url, health_insurance_card_image_url, other_id_image_url ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING * """, ( employee.employee_code, employee.name, employee.name_kana, employee.birth_date, employee.gender, employee.my_number, employee.email, employee.phone, employee.postal_code, employee.address, employee.hire_date, employee.termination_date, employee.is_active, employee.bank_name, employee.bank_branch, employee.bank_account_number, employee.bank_account_type, employee.notes, employee.photo_url, employee.my_number_card_image_url, employee.residence_card_image_url, employee.health_insurance_card_image_url, employee.other_id_image_url ), ) result = cur.fetchone() conn.commit() return result @router.get("/", response_model=List[schemas.Employee]) def get_employees(is_active: bool = None): """従業員一覧を取得""" with get_connection() as conn: with conn.cursor() as cur: if is_active is not None: cur.execute( "SELECT * FROM employees WHERE is_active = %s ORDER BY employee_code", (is_active,) ) else: cur.execute("SELECT * FROM employees ORDER BY employee_code") return cur.fetchall() @router.get("/{employee_id}", response_model=schemas.EmployeeWithDependents) def get_employee(employee_id: int): """従業員の詳細を取得(扶養家族を含む)""" with get_connection() as conn: with conn.cursor() as cur: # 従業員情報取得 cur.execute("SELECT * FROM employees WHERE employee_id = %s", (employee_id,)) employee = cur.fetchone() if not employee: raise HTTPException(status_code=404, detail="従業員が見つかりません") # 扶養家族情報取得 cur.execute( """ SELECT * FROM dependents WHERE employee_id = %s AND (valid_to IS NULL OR valid_to >= CURRENT_DATE) ORDER BY valid_from """, (employee_id,) ) dependents = cur.fetchall() return {**employee, "dependents": dependents} @router.put("/{employee_id}", response_model=schemas.Employee) def update_employee(employee_id: int, employee: schemas.EmployeeUpdate): """従業員情報を更新""" update_data = employee.model_dump(exclude_unset=True) if not update_data: raise HTTPException(status_code=400, detail="更新するデータがありません") set_clause = ", ".join([f"{key} = %s" for key in update_data.keys()]) values = list(update_data.values()) + [employee_id] with get_connection() as conn: with conn.cursor() as cur: cur.execute( f"UPDATE employees SET {set_clause} WHERE employee_id = %s RETURNING *", values, ) result = cur.fetchone() if not result: raise HTTPException(status_code=404, detail="従業員が見つかりません") conn.commit() return result @router.delete("/{employee_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_employee(employee_id: int): """従業員を削除""" with get_connection() as conn: with conn.cursor() as cur: cur.execute("DELETE FROM employees WHERE employee_id = %s", (employee_id,)) if cur.rowcount == 0: raise HTTPException(status_code=404, detail="従業員が見つかりません") conn.commit() # ======================================== # 扶養家族管理 # ======================================== @router.post("/{employee_id}/dependents", response_model=schemas.Dependent, status_code=status.HTTP_201_CREATED) def create_dependent(employee_id: int, dependent: schemas.DependentCreate): """扶養家族を追加""" with get_connection() as conn: with conn.cursor() as cur: # 従業員の存在確認 cur.execute("SELECT employee_id FROM employees WHERE employee_id = %s", (employee_id,)) if not cur.fetchone(): raise HTTPException(status_code=404, detail="従業員が見つかりません") cur.execute( """ INSERT INTO dependents ( employee_id, name, relationship, birth_date, is_spouse, is_disabled, income_amount, valid_from, valid_to ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING * """, ( employee_id, dependent.name, dependent.relationship, dependent.birth_date, dependent.is_spouse, dependent.is_disabled, dependent.income_amount, dependent.valid_from, dependent.valid_to ), ) result = cur.fetchone() conn.commit() return result @router.get("/{employee_id}/dependents", response_model=List[schemas.Dependent]) def get_dependents(employee_id: int): """従業員の扶養家族一覧を取得""" with get_connection() as conn: with conn.cursor() as cur: cur.execute( """ SELECT * FROM dependents WHERE employee_id = %s ORDER BY valid_from DESC """, (employee_id,) ) return cur.fetchall() @router.put("/dependents/{dependent_id}", response_model=schemas.Dependent) def update_dependent(dependent_id: int, dependent: schemas.DependentUpdate): """扶養家族情報を更新""" update_data = dependent.model_dump(exclude_unset=True) if not update_data: raise HTTPException(status_code=400, detail="更新するデータがありません") set_clause = ", ".join([f"{key} = %s" for key in update_data.keys()]) values = list(update_data.values()) + [dependent_id] with get_connection() as conn: with conn.cursor() as cur: cur.execute( f"UPDATE dependents SET {set_clause} WHERE dependent_id = %s RETURNING *", values, ) result = cur.fetchone() if not result: raise HTTPException(status_code=404, detail="扶養家族が見つかりません") conn.commit() return result @router.delete("/dependents/{dependent_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_dependent(dependent_id: int): """扶養家族を削除""" with get_connection() as conn: with conn.cursor() as cur: cur.execute("DELETE FROM dependents WHERE dependent_id = %s", (dependent_id,)) if cur.rowcount == 0: raise HTTPException(status_code=404, detail="扶養家族が見つかりません") conn.commit()