adding endpoints
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
__version__ = "1.0.0"
|
||||
|
||||
__all__ = ["__version__"]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
|
||||
import uvicorn
|
||||
|
||||
|
||||
def main():
|
||||
host = os.environ.get("APP_HOST", "127.0.0.1")
|
||||
port = int(os.environ.get("APP_PORT", "5006"))
|
||||
uvicorn.run("scheduler.main:app", host=host, port=port)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from . import company_routes, employee_routes, health_routes, schedule_routes
|
||||
|
||||
__all__ = [
|
||||
"company_routes",
|
||||
"employee_routes",
|
||||
"health_routes",
|
||||
"schedule_routes",
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from scheduler.api.dependencies import get_company_service
|
||||
from scheduler.core.schemas.company import Company, CreateCompanyRequest
|
||||
from scheduler.core.services.company_service import CompanyService
|
||||
|
||||
router = APIRouter(prefix="/companies", tags=["companies"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[Company])
|
||||
def list_companies(service: Annotated[CompanyService, Depends(get_company_service)]):
|
||||
return service.list_companies()
|
||||
|
||||
|
||||
@router.post("", response_model=Company)
|
||||
def create_company(payload: CreateCompanyRequest, service: Annotated[CompanyService, Depends(get_company_service)]):
|
||||
return service.create_company(payload.name)
|
||||
|
||||
|
||||
@router.get("/{id}", response_model=Company)
|
||||
def get_company(id: int, service: Annotated[CompanyService, Depends(get_company_service)]):
|
||||
company = service.get_company(id)
|
||||
if company is None:
|
||||
raise HTTPException(status_code=404, detail="Company not found")
|
||||
return company
|
||||
|
||||
|
||||
@router.delete("/{id}", response_model=Company)
|
||||
def delete_company(id: int, service: Annotated[CompanyService, Depends(get_company_service)]):
|
||||
company = service.delete_company(id)
|
||||
if company is None:
|
||||
raise HTTPException(status_code=404, detail="Company not found")
|
||||
return company
|
||||
@@ -0,0 +1,50 @@
|
||||
from collections.abc import Generator
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from scheduler.core.services.company_service import CompanyService
|
||||
from scheduler.core.services.employee_service import EmployeeService
|
||||
from scheduler.core.services.schedule_service import ScheduleService
|
||||
from scheduler.database import CompanyRepository, Database, EmployeeRepository, ScheduleRepository
|
||||
|
||||
|
||||
|
||||
def get_database() -> Database:
|
||||
load_dotenv()
|
||||
return Database()
|
||||
|
||||
|
||||
def get_db() -> Generator:
|
||||
connection = get_database().get_connection()
|
||||
try:
|
||||
yield connection
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def get_company_service() -> Generator:
|
||||
connection = get_database().get_connection()
|
||||
try:
|
||||
yield CompanyService(CompanyRepository(connection))
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def get_employee_service() -> Generator:
|
||||
connection = get_database().get_connection()
|
||||
try:
|
||||
yield EmployeeService(EmployeeRepository(connection), CompanyRepository(connection))
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def get_schedule_service() -> Generator:
|
||||
connection = get_database().get_connection()
|
||||
try:
|
||||
yield ScheduleService(
|
||||
ScheduleRepository(connection),
|
||||
EmployeeRepository(connection),
|
||||
CompanyRepository(connection),
|
||||
)
|
||||
finally:
|
||||
connection.close()
|
||||
@@ -0,0 +1,109 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from scheduler.api.dependencies import get_employee_service
|
||||
from scheduler.core.schemas.company import CompanyUser
|
||||
from scheduler.core.schemas.employee import (
|
||||
CreateEmployeeRequest,
|
||||
EmployeeNamesResponse,
|
||||
EmployeeResponse,
|
||||
RegisterPreferenceRequest,
|
||||
UpdateEmployeeRequest,
|
||||
WeeklyPreferenceRequest,
|
||||
)
|
||||
from scheduler.core.services.employee_service import EmployeeService
|
||||
|
||||
router = APIRouter(tags=["employees"])
|
||||
|
||||
|
||||
@router.get("/employees", response_model=list[EmployeeResponse])
|
||||
def list_employees(service: Annotated[EmployeeService, Depends(get_employee_service)]):
|
||||
return service.list_employees()
|
||||
|
||||
|
||||
@router.post("/employees", response_model=EmployeeResponse)
|
||||
def create_employee(payload: CreateEmployeeRequest, service: Annotated[EmployeeService, Depends(get_employee_service)]):
|
||||
employee = service.create_employee(payload.company_id, payload.name, payload.last_name, payload.preference)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Company not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.put("/employees/{id}", response_model=EmployeeResponse)
|
||||
def update_employee(
|
||||
id: int,
|
||||
payload: UpdateEmployeeRequest,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
employee = service.update_employee(id, payload.name, payload.last_name, payload.preference, payload.company_id)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Employee or company not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.patch("/employees/{id}", response_model=EmployeeResponse)
|
||||
def patch_employee(
|
||||
id: int,
|
||||
payload: UpdateEmployeeRequest,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
employee = service.update_employee(id, payload.name, payload.last_name, payload.preference, payload.company_id)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Employee or company not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.delete("/employees/{id}", response_model=EmployeeResponse)
|
||||
def delete_employee(id: int, service: Annotated[EmployeeService, Depends(get_employee_service)]):
|
||||
employee = service.delete_employee(id)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Employee not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.put("/employees/{id}/preference", response_model=EmployeeResponse)
|
||||
def register_employee_preference(
|
||||
id: int,
|
||||
payload: RegisterPreferenceRequest,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
employee = service.update_preference(id, payload.preference)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Employee not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.put("/employees/{id}/weekly-preferences", response_model=EmployeeResponse)
|
||||
def register_weekly_employee_preferences(
|
||||
id: int,
|
||||
payload: WeeklyPreferenceRequest,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
employee = service.save_weekly_preferences(id, payload.preferences)
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=404, detail="Employee not found")
|
||||
return employee
|
||||
|
||||
|
||||
@router.post("/companies/{company_id}/employees/{employee_id}", response_model=CompanyUser)
|
||||
def assign_employee_to_company(
|
||||
company_id: int,
|
||||
employee_id: int,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
company_user = service.assign_to_company(company_id, employee_id)
|
||||
if company_user is None:
|
||||
raise HTTPException(status_code=404, detail="Company or employee not found")
|
||||
return company_user
|
||||
|
||||
|
||||
@router.get("/companies/{company_name}/employees/names", response_model=EmployeeNamesResponse)
|
||||
def get_employee_names_by_company(
|
||||
company_name: str,
|
||||
service: Annotated[EmployeeService, Depends(get_employee_service)],
|
||||
):
|
||||
employees = service.get_names_by_company_name(company_name)
|
||||
if employees is None:
|
||||
raise HTTPException(status_code=404, detail="Company not found")
|
||||
return {"employees": employees}
|
||||
@@ -0,0 +1,10 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from scheduler.core.schemas.health import HealthResponse
|
||||
|
||||
router = APIRouter(tags=["health"])
|
||||
|
||||
|
||||
@router.get("/health", response_model=HealthResponse)
|
||||
def health_check():
|
||||
return {"status": "ok"}
|
||||
@@ -0,0 +1,68 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from scheduler.api.dependencies import get_schedule_service
|
||||
from scheduler.core.schemas.schedule import (
|
||||
ClockInRequest,
|
||||
ClockOutRequest,
|
||||
CreateScheduleRequest,
|
||||
GenerateWeeklyScheduleRequest,
|
||||
ScheduleResponse,
|
||||
WeeklyScheduleResponse,
|
||||
)
|
||||
from scheduler.core.services.schedule_service import ScheduleService
|
||||
|
||||
router = APIRouter(tags=["schedules"])
|
||||
|
||||
|
||||
@router.post("/schedules", response_model=ScheduleResponse)
|
||||
def create_schedule(payload: CreateScheduleRequest, service: Annotated[ScheduleService, Depends(get_schedule_service)]):
|
||||
schedule = service.create_schedule(payload.user_id, payload.enter_time, payload.day_of_week, payload.out_time)
|
||||
if schedule is None:
|
||||
raise HTTPException(status_code=404, detail="Employee not found")
|
||||
return schedule
|
||||
|
||||
|
||||
@router.post("/employees/{id}/clock-in", response_model=ScheduleResponse)
|
||||
def clock_in(
|
||||
id: int,
|
||||
payload: ClockInRequest,
|
||||
service: Annotated[ScheduleService, Depends(get_schedule_service)],
|
||||
):
|
||||
schedule = service.clock_in(
|
||||
id,
|
||||
day_of_week=payload.day_of_week,
|
||||
enter_time=payload.enter_time,
|
||||
)
|
||||
if schedule is None:
|
||||
raise HTTPException(status_code=404, detail="Employee not found")
|
||||
return schedule
|
||||
|
||||
|
||||
@router.put("/employees/{id}/clock-out", response_model=ScheduleResponse)
|
||||
def clock_out(
|
||||
id: int,
|
||||
payload: ClockOutRequest,
|
||||
service: Annotated[ScheduleService, Depends(get_schedule_service)],
|
||||
):
|
||||
schedule = service.clock_out(id, payload.day_of_week, payload.out_time)
|
||||
if schedule is None:
|
||||
raise HTTPException(status_code=404, detail="Schedule not found")
|
||||
return schedule
|
||||
|
||||
|
||||
@router.get("/schedules/weekly", response_model=WeeklyScheduleResponse)
|
||||
def get_weekly_schedule(service: Annotated[ScheduleService, Depends(get_schedule_service)]):
|
||||
return service.get_weekly_schedule()
|
||||
|
||||
|
||||
@router.post("/schedules/weekly/generate", response_model=WeeklyScheduleResponse)
|
||||
def generate_weekly_schedule(
|
||||
payload: GenerateWeeklyScheduleRequest,
|
||||
service: Annotated[ScheduleService, Depends(get_schedule_service)],
|
||||
):
|
||||
schedule = service.generate_weekly_schedule(payload.company_id)
|
||||
if schedule is None:
|
||||
raise HTTPException(status_code=404, detail="Company not found")
|
||||
return schedule
|
||||
@@ -0,0 +1,46 @@
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from scheduler.api import company_routes, employee_routes, health_routes, schedule_routes
|
||||
from scheduler.database import Database
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
Database().initialize_schema()
|
||||
yield
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI(
|
||||
title="manager_employees_python",
|
||||
lifespan=lifespan,
|
||||
openapi_url="/api-docs/openapi.json",
|
||||
docs_url="/swagger-ui/",
|
||||
)
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(health_routes.router)
|
||||
app.include_router(company_routes.router)
|
||||
app.include_router(employee_routes.router)
|
||||
app.include_router(schedule_routes.router)
|
||||
|
||||
@app.get("/api-docs/openai.json", include_in_schema=False)
|
||||
def openai_json_alias():
|
||||
return app.openapi()
|
||||
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
||||
@@ -0,0 +1,4 @@
|
||||
from scheduler.core.enums.day_of_week import DayOfWeek
|
||||
from scheduler.core.enums.work_time import WorkTime
|
||||
|
||||
__all__ = ["DayOfWeek", "WorkTime"]
|
||||
@@ -0,0 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class DayOfWeek(str, Enum):
|
||||
SUNDAY = "sunday"
|
||||
MONDAY = "monday"
|
||||
TUESDAY = "tuesday"
|
||||
WEDNESDAY = "wednesday"
|
||||
THURSDAY = "thursday"
|
||||
FRIDAY = "friday"
|
||||
SATURDAY = "saturday"
|
||||
@@ -0,0 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class WorkTime(str, Enum):
|
||||
MORNING = "morning"
|
||||
AFTERNOON = "afternoon"
|
||||
EVENING = "evening"
|
||||
@@ -0,0 +1,22 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class CreateCompanyRequest(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
class Company(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
date_created: datetime
|
||||
date_updated: datetime
|
||||
|
||||
|
||||
class CompanyUser(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
company_id: int
|
||||
date_created: datetime
|
||||
date_updated: datetime
|
||||
@@ -0,0 +1,44 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from scheduler.core.enums import DayOfWeek, WorkTime
|
||||
|
||||
|
||||
class CreateEmployeeRequest(BaseModel):
|
||||
company_id: int
|
||||
name: str
|
||||
last_name: str
|
||||
preference: WorkTime
|
||||
|
||||
|
||||
class RegisterPreferenceRequest(BaseModel):
|
||||
preference: WorkTime
|
||||
|
||||
|
||||
class DayPreferenceRequest(BaseModel):
|
||||
day_of_week: DayOfWeek
|
||||
first: WorkTime
|
||||
second: WorkTime
|
||||
third: WorkTime
|
||||
|
||||
|
||||
class WeeklyPreferenceRequest(BaseModel):
|
||||
preferences: list[DayPreferenceRequest]
|
||||
|
||||
|
||||
class EmployeeNamesResponse(BaseModel):
|
||||
employees: list[str]
|
||||
|
||||
|
||||
class UpdateEmployeeRequest(BaseModel):
|
||||
company_id: int | None = None
|
||||
name: str
|
||||
last_name: str
|
||||
preference: WorkTime
|
||||
|
||||
|
||||
class EmployeeResponse(BaseModel):
|
||||
id: int
|
||||
company_id: int
|
||||
name: str
|
||||
last_name: str
|
||||
preference: WorkTime
|
||||
@@ -0,0 +1,5 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class HealthResponse(BaseModel):
|
||||
status: str
|
||||
@@ -0,0 +1,38 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from scheduler.core.enums import DayOfWeek
|
||||
|
||||
|
||||
class CreateScheduleRequest(BaseModel):
|
||||
user_id: int
|
||||
enter_time: datetime
|
||||
day_of_week: DayOfWeek
|
||||
out_time: datetime
|
||||
|
||||
|
||||
class ClockInRequest(BaseModel):
|
||||
day_of_week: DayOfWeek
|
||||
enter_time: datetime
|
||||
|
||||
|
||||
class ClockOutRequest(BaseModel):
|
||||
day_of_week: DayOfWeek
|
||||
out_time: datetime
|
||||
|
||||
|
||||
class GenerateWeeklyScheduleRequest(BaseModel):
|
||||
company_id: int
|
||||
|
||||
|
||||
class ScheduleResponse(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
enter_time: datetime
|
||||
day_of_week: DayOfWeek
|
||||
out_time: datetime | None = None
|
||||
|
||||
|
||||
class WeeklyScheduleResponse(BaseModel):
|
||||
schedules: list[ScheduleResponse]
|
||||
@@ -0,0 +1,18 @@
|
||||
from scheduler.database.company_repository import CompanyRepository
|
||||
|
||||
|
||||
class CompanyService:
|
||||
def __init__(self, repository: CompanyRepository):
|
||||
self.repository = repository
|
||||
|
||||
def list_companies(self):
|
||||
return self.repository.list()
|
||||
|
||||
def create_company(self, name: str):
|
||||
return self.repository.create(name)
|
||||
|
||||
def get_company(self, company_id: int):
|
||||
return self.repository.get(company_id)
|
||||
|
||||
def delete_company(self, company_id: int):
|
||||
return self.repository.delete(company_id)
|
||||
@@ -0,0 +1,57 @@
|
||||
from scheduler.database.company_repository import CompanyRepository
|
||||
from scheduler.database.employee_repository import EmployeeRepository
|
||||
|
||||
|
||||
class EmployeeService:
|
||||
def __init__(self, employee_repository: EmployeeRepository, company_repository: CompanyRepository):
|
||||
self.employee_repository = employee_repository
|
||||
self.company_repository = company_repository
|
||||
|
||||
def list_employees(self):
|
||||
return self.employee_repository.list()
|
||||
|
||||
def create_employee(self, company_id: int, name: str, last_name: str, preference: str):
|
||||
if self.company_repository.get(company_id) is None:
|
||||
return None
|
||||
return self.employee_repository.create(company_id, name, last_name, preference)
|
||||
|
||||
def delete_employee(self, employee_id: int):
|
||||
return self.employee_repository.delete(employee_id)
|
||||
|
||||
def update_preference(self, employee_id: int, preference: str):
|
||||
return self.employee_repository.update_preference(employee_id, preference)
|
||||
|
||||
def update_employee(
|
||||
self,
|
||||
employee_id: int,
|
||||
name: str,
|
||||
last_name: str,
|
||||
preference: str,
|
||||
company_id: int | None,
|
||||
):
|
||||
if self.employee_repository.get(employee_id) is None:
|
||||
return None
|
||||
if company_id is not None and self.company_repository.get(company_id) is None:
|
||||
return None
|
||||
updated = self.employee_repository.update(employee_id, name, last_name, preference)
|
||||
if company_id is not None:
|
||||
updated = self.employee_repository.update_company(employee_id, company_id)
|
||||
return updated
|
||||
|
||||
def assign_to_company(self, company_id: int, employee_id: int):
|
||||
if self.company_repository.get(company_id) is None:
|
||||
return None
|
||||
if self.employee_repository.get(employee_id) is None:
|
||||
return None
|
||||
return self.employee_repository.assign_to_company(company_id, employee_id)
|
||||
|
||||
def get_names_by_company_name(self, company_name: str):
|
||||
company = self.company_repository.get_by_name(company_name)
|
||||
if company is None:
|
||||
return None
|
||||
return self.employee_repository.get_names_by_company(company["id"])
|
||||
|
||||
def save_weekly_preferences(self, employee_id: int, preferences: list):
|
||||
if self.employee_repository.get(employee_id) is None:
|
||||
return None
|
||||
return self.employee_repository.save_weekly_preferences(employee_id, preferences)
|
||||
@@ -0,0 +1,46 @@
|
||||
from datetime import datetime
|
||||
|
||||
from scheduler.database.company_repository import CompanyRepository
|
||||
from scheduler.database.employee_repository import EmployeeRepository
|
||||
from scheduler.database.schedule_repository import ScheduleRepository
|
||||
|
||||
|
||||
class ScheduleService:
|
||||
def __init__(
|
||||
self,
|
||||
schedule_repository: ScheduleRepository,
|
||||
employee_repository: EmployeeRepository,
|
||||
company_repository: CompanyRepository,
|
||||
):
|
||||
self.schedule_repository = schedule_repository
|
||||
self.employee_repository = employee_repository
|
||||
self.company_repository = company_repository
|
||||
|
||||
def create_schedule(self, user_id: int, enter_time: datetime, day_of_week: str, out_time: datetime):
|
||||
if self.employee_repository.get(user_id) is None:
|
||||
return None
|
||||
return self.schedule_repository.create(user_id, enter_time, day_of_week, out_time)
|
||||
|
||||
def clock_in(
|
||||
self,
|
||||
user_id: int,
|
||||
day_of_week: str,
|
||||
enter_time: datetime,
|
||||
):
|
||||
employee = self.employee_repository.get(user_id)
|
||||
if employee is None:
|
||||
return None
|
||||
return self.schedule_repository.create(user_id, enter_time, day_of_week, None)
|
||||
|
||||
def clock_out(self, user_id: int, day_of_week: str, out_time: datetime):
|
||||
if self.employee_repository.get(user_id) is None:
|
||||
return None
|
||||
return self.schedule_repository.update_clock_out(user_id, day_of_week, out_time)
|
||||
|
||||
def get_weekly_schedule(self, company_id: int | None = None):
|
||||
return {"schedules": self.schedule_repository.list_weekly(company_id)}
|
||||
|
||||
def generate_weekly_schedule(self, company_id: int):
|
||||
if self.company_repository.get(company_id) is None:
|
||||
return None
|
||||
return self.get_weekly_schedule(company_id)
|
||||
@@ -0,0 +1,6 @@
|
||||
from scheduler.database.company_repository import CompanyRepository
|
||||
from scheduler.database.database import Database
|
||||
from scheduler.database.employee_repository import EmployeeRepository
|
||||
from scheduler.database.schedule_repository import ScheduleRepository
|
||||
|
||||
__all__ = ["CompanyRepository", "Database", "EmployeeRepository", "ScheduleRepository"]
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
class CompanyRepository:
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def list(self):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, name, date_created, date_updated
|
||||
FROM companies
|
||||
ORDER BY id
|
||||
"""
|
||||
)
|
||||
return cursor.fetchall()
|
||||
|
||||
def create(self, name: str):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO companies (name)
|
||||
VALUES (%s)
|
||||
RETURNING id, name, date_created, date_updated
|
||||
""",
|
||||
(name,),
|
||||
)
|
||||
company = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return company
|
||||
|
||||
def get(self, company_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, name, date_created, date_updated
|
||||
FROM companies
|
||||
WHERE id = %s
|
||||
""",
|
||||
(company_id,),
|
||||
)
|
||||
return cursor.fetchone()
|
||||
|
||||
def get_by_name(self, name: str):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, name, date_created, date_updated
|
||||
FROM companies
|
||||
WHERE name = %s
|
||||
""",
|
||||
(name,),
|
||||
)
|
||||
return cursor.fetchone()
|
||||
|
||||
def delete(self, company_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
DELETE FROM companies
|
||||
WHERE id = %s
|
||||
RETURNING id, name, date_created, date_updated
|
||||
""",
|
||||
(company_id,),
|
||||
)
|
||||
company = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return company
|
||||
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
|
||||
import psycopg
|
||||
from psycopg.rows import dict_row
|
||||
|
||||
|
||||
DEFAULT_DATABASE_URL = "postgres://carlos:password@localhost/rust_manager_employees"
|
||||
|
||||
|
||||
class Database:
|
||||
def __init__(self, database_url: str | None = None):
|
||||
self.database_url = database_url or os.environ.get("DATABASE_URL", DEFAULT_DATABASE_URL)
|
||||
|
||||
def get_connection(self):
|
||||
return psycopg.connect(self.database_url, row_factory=dict_row)
|
||||
|
||||
def initialize_schema(self):
|
||||
with self.get_connection() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
DO $$
|
||||
BEGIN
|
||||
CREATE TYPE work_time AS ENUM ('morning', 'afternoon', 'evening');
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
"""
|
||||
)
|
||||
cursor.execute("ALTER TYPE work_time ADD VALUE IF NOT EXISTS 'afternoon';")
|
||||
cursor.execute(
|
||||
"""
|
||||
DO $$
|
||||
BEGIN
|
||||
CREATE TYPE day_of_week AS ENUM (
|
||||
'sunday', 'monday', 'tuesday', 'wednesday',
|
||||
'thursday', 'friday', 'saturday'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS companies (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
date_created TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
date_updated TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
last_name TEXT NOT NULL,
|
||||
preference work_time NOT NULL,
|
||||
date_created TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
date_updated TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS company_users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||||
date_created TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
date_updated TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (user_id, company_id)
|
||||
);
|
||||
"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS schedules (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
enter_time TIMESTAMP NOT NULL,
|
||||
day_of_week day_of_week NOT NULL,
|
||||
out_time TIMESTAMP,
|
||||
date_created TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
date_updated TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
"""
|
||||
)
|
||||
cursor.execute("ALTER TABLE schedules ALTER COLUMN out_time DROP NOT NULL;")
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS weekly_preferences (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
day_of_week day_of_week NOT NULL,
|
||||
first work_time NOT NULL,
|
||||
second work_time NOT NULL,
|
||||
third work_time NOT NULL,
|
||||
date_created TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
date_updated TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (user_id, day_of_week)
|
||||
);
|
||||
"""
|
||||
)
|
||||
connection.commit()
|
||||
@@ -0,0 +1,167 @@
|
||||
class EmployeeRepository:
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def list(self):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT users.id, company_users.company_id, users.name, users.last_name, users.preference
|
||||
FROM users
|
||||
INNER JOIN company_users ON company_users.user_id = users.id
|
||||
ORDER BY users.id
|
||||
"""
|
||||
)
|
||||
return cursor.fetchall()
|
||||
|
||||
def create(self, company_id: int, name: str, last_name: str, preference: str):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO users (name, last_name, preference)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id, name, last_name, preference
|
||||
""",
|
||||
(name, last_name, preference),
|
||||
)
|
||||
user = cursor.fetchone()
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO company_users (user_id, company_id)
|
||||
VALUES (%s, %s)
|
||||
RETURNING company_id
|
||||
""",
|
||||
(user["id"], company_id),
|
||||
)
|
||||
company_user = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return {**user, "company_id": company_user["company_id"]}
|
||||
|
||||
def get(self, employee_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT users.id, company_users.company_id, users.name, users.last_name, users.preference
|
||||
FROM users
|
||||
INNER JOIN company_users ON company_users.user_id = users.id
|
||||
WHERE users.id = %s
|
||||
""",
|
||||
(employee_id,),
|
||||
)
|
||||
return cursor.fetchone()
|
||||
|
||||
def delete(self, employee_id: int):
|
||||
employee = self.get(employee_id)
|
||||
if employee is None:
|
||||
return None
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute("DELETE FROM users WHERE id = %s", (employee_id,))
|
||||
self.connection.commit()
|
||||
return employee
|
||||
|
||||
def update_preference(self, employee_id: int, preference: str):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE users
|
||||
SET preference = %s, date_updated = NOW()
|
||||
WHERE id = %s
|
||||
""",
|
||||
(preference, employee_id),
|
||||
)
|
||||
self.connection.commit()
|
||||
return self.get(employee_id)
|
||||
|
||||
def update(self, employee_id: int, name: str | None, last_name: str | None, preference: str | None):
|
||||
updates: list[str] = []
|
||||
params: list[object] = []
|
||||
if name is not None:
|
||||
updates.append("name = %s")
|
||||
params.append(name)
|
||||
if last_name is not None:
|
||||
updates.append("last_name = %s")
|
||||
params.append(last_name)
|
||||
if preference is not None:
|
||||
updates.append("preference = %s")
|
||||
params.append(preference)
|
||||
if updates:
|
||||
updates.append("date_updated = NOW()")
|
||||
params.append(employee_id)
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE users
|
||||
SET {", ".join(updates)}
|
||||
WHERE id = %s
|
||||
""",
|
||||
tuple(params),
|
||||
)
|
||||
self.connection.commit()
|
||||
return self.get(employee_id)
|
||||
|
||||
def update_company(self, employee_id: int, company_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute("DELETE FROM company_users WHERE user_id = %s", (employee_id,))
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO company_users (user_id, company_id)
|
||||
VALUES (%s, %s)
|
||||
ON CONFLICT (user_id, company_id) DO UPDATE SET date_updated = NOW()
|
||||
""",
|
||||
(employee_id, company_id),
|
||||
)
|
||||
self.connection.commit()
|
||||
return self.get(employee_id)
|
||||
|
||||
def assign_to_company(self, company_id: int, employee_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO company_users (user_id, company_id)
|
||||
VALUES (%s, %s)
|
||||
ON CONFLICT (user_id, company_id) DO UPDATE SET date_updated = NOW()
|
||||
RETURNING id, user_id, company_id, date_created, date_updated
|
||||
""",
|
||||
(employee_id, company_id),
|
||||
)
|
||||
company_user = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return company_user
|
||||
|
||||
def get_names_by_company(self, company_id: int):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT users.name, users.last_name
|
||||
FROM users
|
||||
INNER JOIN company_users ON company_users.user_id = users.id
|
||||
WHERE company_users.company_id = %s
|
||||
ORDER BY users.name, users.last_name
|
||||
""",
|
||||
(company_id,),
|
||||
)
|
||||
return [f"{row['name']} {row['last_name']}" for row in cursor.fetchall()]
|
||||
|
||||
def save_weekly_preferences(self, employee_id: int, preferences: list):
|
||||
with self.connection.cursor() as cursor:
|
||||
for preference in preferences:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO weekly_preferences (user_id, day_of_week, first, second, third)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
ON CONFLICT (user_id, day_of_week) DO UPDATE SET
|
||||
first = EXCLUDED.first,
|
||||
second = EXCLUDED.second,
|
||||
third = EXCLUDED.third,
|
||||
date_updated = NOW()
|
||||
""",
|
||||
(
|
||||
employee_id,
|
||||
preference.day_of_week,
|
||||
preference.first,
|
||||
preference.second,
|
||||
preference.third,
|
||||
),
|
||||
)
|
||||
self.connection.commit()
|
||||
return self.get(employee_id)
|
||||
@@ -0,0 +1,61 @@
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ScheduleRepository:
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def create(self, user_id: int, enter_time: datetime, day_of_week: str, out_time: datetime | None):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO schedules (user_id, enter_time, day_of_week, out_time)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
RETURNING id, user_id, enter_time, day_of_week, out_time
|
||||
""",
|
||||
(user_id, enter_time, day_of_week, out_time),
|
||||
)
|
||||
schedule = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return schedule
|
||||
|
||||
def list_weekly(self, company_id: int | None = None):
|
||||
params = ()
|
||||
where = ""
|
||||
if company_id is not None:
|
||||
where = "WHERE company_users.company_id = %s"
|
||||
params = (company_id,)
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
SELECT schedules.id, schedules.user_id, schedules.enter_time,
|
||||
schedules.day_of_week, schedules.out_time
|
||||
FROM schedules
|
||||
INNER JOIN company_users ON company_users.user_id = schedules.user_id
|
||||
{where}
|
||||
ORDER BY schedules.day_of_week, schedules.enter_time, schedules.id
|
||||
""",
|
||||
params,
|
||||
)
|
||||
return cursor.fetchall()
|
||||
|
||||
def update_clock_out(self, user_id: int, day_of_week: str, out_time: datetime):
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE schedules
|
||||
SET out_time = %s, date_updated = NOW()
|
||||
WHERE id = (
|
||||
SELECT id
|
||||
FROM schedules
|
||||
WHERE user_id = %s AND day_of_week = %s
|
||||
ORDER BY date_created DESC
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING id, user_id, enter_time, day_of_week, out_time
|
||||
""",
|
||||
(out_time, user_id, day_of_week),
|
||||
)
|
||||
schedule = cursor.fetchone()
|
||||
self.connection.commit()
|
||||
return schedule
|
||||
@@ -0,0 +1,93 @@
|
||||
from scheduler.database.company_repository import CompanyRepository
|
||||
from scheduler.database.database import Database
|
||||
from scheduler.database.employee_repository import EmployeeRepository
|
||||
from scheduler.database.schedule_repository import ScheduleRepository
|
||||
|
||||
|
||||
def get_connection():
|
||||
return Database().get_connection()
|
||||
|
||||
|
||||
def initialize_schema(connection=None):
|
||||
Database().initialize_schema()
|
||||
|
||||
|
||||
def add_company(connection, name):
|
||||
return CompanyRepository(connection).create(name)
|
||||
|
||||
|
||||
def get_company_by_name(connection, name):
|
||||
return CompanyRepository(connection).get_by_name(name)
|
||||
|
||||
|
||||
def remove_company(connection, company_id):
|
||||
return CompanyRepository(connection).delete(company_id)
|
||||
|
||||
|
||||
def get_employee_names_by_company(connection, company_id):
|
||||
return EmployeeRepository(connection).get_names_by_company(company_id)
|
||||
|
||||
|
||||
def add_user(connection, name, last_name, preference):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO users (name, last_name, preference)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id, name, last_name, preference, date_created, date_updated
|
||||
""",
|
||||
(name, last_name, preference),
|
||||
)
|
||||
user = cursor.fetchone()
|
||||
connection.commit()
|
||||
return user
|
||||
|
||||
|
||||
def update_user_preference(connection, user_id, preference):
|
||||
return EmployeeRepository(connection).update_preference(user_id, preference)
|
||||
|
||||
|
||||
def add_company_user(connection, company_id, user_id):
|
||||
return EmployeeRepository(connection).assign_to_company(company_id, user_id)
|
||||
|
||||
|
||||
def remove_user(connection, user_id):
|
||||
return EmployeeRepository(connection).delete(user_id)
|
||||
|
||||
|
||||
def add_schedule(connection, user_id, enter_time, day_of_week, out_time):
|
||||
return ScheduleRepository(connection).create(user_id, enter_time, day_of_week, out_time)
|
||||
|
||||
|
||||
def get_days_worked_by_user(connection, user_id):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT DISTINCT day_of_week
|
||||
FROM schedules
|
||||
WHERE user_id = %s
|
||||
ORDER BY day_of_week
|
||||
""",
|
||||
(user_id,),
|
||||
)
|
||||
return [row["day_of_week"] for row in cursor.fetchall()]
|
||||
|
||||
|
||||
def get_user_enter_time_by_day(connection, user_id, day_of_week):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT enter_time
|
||||
FROM schedules
|
||||
WHERE user_id = %s AND day_of_week = %s
|
||||
ORDER BY date_created DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(user_id, day_of_week),
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
return None if row is None else row["enter_time"]
|
||||
|
||||
|
||||
def update_day_end_by_user_and_day(connection, user_id, day_of_week, out_time):
|
||||
return ScheduleRepository(connection).update_clock_out(user_id, day_of_week, out_time)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from scheduler.app import app, create_app
|
||||
|
||||
__all__ = ["app", "create_app"]
|
||||
@@ -0,0 +1,3 @@
|
||||
from . import conflict, scheduler, validator
|
||||
|
||||
__all__ = ["conflict", "scheduler", "validator"]
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Conflict resolution guide.
|
||||
# Import validator functions before moving employees between shifts or days.
|
||||
|
||||
|
||||
def detect_preferred_shift_conflict(connection, user_id, day_of_week, preferred_shift):
|
||||
# check if preferred shift is already full for selected day
|
||||
# check if user already works that day
|
||||
# check if user already worked five days this week
|
||||
pass
|
||||
|
||||
|
||||
def resolve_conflict_same_day(connection, user_id, day_of_week):
|
||||
# loop over other shifts on the same day
|
||||
# choose the first shift where user can legally work
|
||||
# assign only after validator confirms the schedule is valid
|
||||
pass
|
||||
|
||||
|
||||
def resolve_conflict_next_day(connection, user_id, current_day):
|
||||
# if same-day alternatives fail, move to next day
|
||||
# loop through next-day shifts by preference priority
|
||||
# assign only after validator confirms the schedule is valid
|
||||
pass
|
||||
|
||||
|
||||
def resolve_missing_second_employee(connection, company_id, day_of_week, shift):
|
||||
# find shifts with only one employee assigned
|
||||
# loop over available employees in company
|
||||
# skip employees who already work that day
|
||||
# skip employees who already worked five days this week
|
||||
# assign a valid extra employee to satisfy minimum coverage
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Schedule generation guide.
|
||||
# Import database.storage for queries and manager.validator/conflict for rules.
|
||||
|
||||
|
||||
def generate_weekly_schedule(connection, company_id):
|
||||
# load all employees for selected company
|
||||
# load employee preferences for all seven days
|
||||
# loop through each day of the week
|
||||
# loop through morning, afternoon, and evening shifts
|
||||
# assign employees based on preferences first
|
||||
# validate one-shift-per-day before each assignment
|
||||
# validate five-days-per-week before each assignment
|
||||
# ensure at least two employees per shift after assignments
|
||||
# resolve conflicts by assigning another shift on same day or next day
|
||||
# save final schedule rows to the schedules table
|
||||
pass
|
||||
|
||||
|
||||
def assign_preferred_shift(connection, user_id, day_of_week, preferred_shift):
|
||||
# validate employee can join selected shift
|
||||
# call storage.add_schedule when assignment is valid
|
||||
# return validation error if assignment is not valid
|
||||
pass
|
||||
|
||||
|
||||
def fill_missing_shift_coverage(connection, company_id, day_of_week, shift):
|
||||
# find company shift with fewer than two employees
|
||||
# if only one employee is assigned, search for another valid employee
|
||||
# randomly choose or rotate through employees who have not worked five days
|
||||
# add the selected employee to the schedule
|
||||
pass
|
||||
|
||||
|
||||
def register_clock_in(connection, user_id, day_of_week, enter_time):
|
||||
# reject if user already worked the same day
|
||||
# reject if user already worked five days this week
|
||||
# save enter_time through storage.add_schedule or update an open schedule row
|
||||
pass
|
||||
|
||||
|
||||
def register_clock_out(connection, user_id, day_of_week, out_time):
|
||||
# call storage.update_day_end_by_user_and_day
|
||||
# keep the existing schedule row and update out_time only
|
||||
pass
|
||||
|
||||
|
||||
def print_final_schedule(connection, company_id):
|
||||
# query final schedule with employee names
|
||||
# group output by day and shift
|
||||
# print employees assigned to each shift
|
||||
# print warnings for shifts with fewer than two employees
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Validation guide for schedule rules.
|
||||
# Import scheduler.database.storage query functions before implementing these checks.
|
||||
|
||||
|
||||
def validate_user_has_not_worked_same_day(connection, user_id, day_of_week):
|
||||
# query schedules for user_id and day_of_week
|
||||
# if a schedule exists, reject the new assignment
|
||||
# otherwise allow scheduler to continue
|
||||
pass
|
||||
|
||||
|
||||
def validate_user_has_not_worked_more_than_five_days(connection, user_id):
|
||||
# call storage.get_days_worked_by_user(connection, user_id)
|
||||
# count distinct worked days with a loop
|
||||
# reject if count is five or more
|
||||
# otherwise allow assignment
|
||||
pass
|
||||
|
||||
|
||||
def validate_shift_has_minimum_two_employees(connection, company_id, day_of_week, shift):
|
||||
# query schedules for company_id, day_of_week, and shift
|
||||
# count assigned employees
|
||||
# if fewer than two, scheduler must add another available employee
|
||||
pass
|
||||
|
||||
|
||||
def validate_employee_can_join_shift(connection, user_id, day_of_week, shift):
|
||||
# check one-shift-per-day rule first
|
||||
# check five-days-per-week rule second
|
||||
# check shift coverage and capacity rules last
|
||||
pass
|
||||
|
||||
|
||||
def validate_company_has_enough_employees(connection, company_id):
|
||||
# get employee names by company
|
||||
# reject schedule generation if company has fewer than two employees
|
||||
# otherwise continue schedule generation
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from . import employee, schedule, shift
|
||||
|
||||
__all__ = ["employee", "schedule", "shift"]
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
from scheduler.database import storage
|
||||
|
||||
|
||||
def define_employee_fields():
|
||||
# include id from users table
|
||||
# include company_id from company_users table
|
||||
# include name and last_name from users table
|
||||
# include preferred shift for each day of the week
|
||||
# include optional priority ranking for bonus preference support
|
||||
pass
|
||||
|
||||
|
||||
def register_employee_preference(connection, user_id, preference):
|
||||
return storage.update_user_preference(connection, user_id, preference)
|
||||
|
||||
|
||||
def get_employee_names_by_company(connection, company_name):
|
||||
company = storage.get_company_by_name(connection, company_name)
|
||||
if company is None:
|
||||
return None
|
||||
return storage.get_employee_names_by_company(connection, company["id"])
|
||||
|
||||
|
||||
def register_user_into_company(connection, company_id, name, last_name, preference):
|
||||
user = storage.add_user(connection, name, last_name, preference)
|
||||
storage.add_company_user(connection, company_id, user["id"])
|
||||
return user
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from scheduler.database import storage
|
||||
|
||||
|
||||
def define_schedule_fields():
|
||||
# include user_id to identify the employee
|
||||
# include company_id if schedules need to be filtered by company
|
||||
# include day_of_week for the assigned day
|
||||
# include shift value for morning, afternoon, or evening
|
||||
# include enter_time and out_time for clock-in and clock-out
|
||||
pass
|
||||
|
||||
|
||||
def register_user_enter_and_out(connection, user_id, enter_time, day_of_week, out_time):
|
||||
# Add manager validation before saving once scheduling rules are complete.
|
||||
return storage.add_schedule(connection, user_id, enter_time, day_of_week, out_time)
|
||||
|
||||
|
||||
def output_weekly_schedule():
|
||||
# group saved schedules by day of week
|
||||
# inside each day, group schedules by shift
|
||||
# list employee names for each shift
|
||||
# show missing coverage when a shift has fewer than two employees
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Shift model guide.
|
||||
# Keep shift names consistent with the PostgreSQL work_time enum.
|
||||
|
||||
|
||||
def define_shift_values():
|
||||
# morning maps to work_time value "morning"
|
||||
# afternoon can map to "evening" if you keep the Rust enum name
|
||||
# evening maps to work_time value "evening"
|
||||
pass
|
||||
|
||||
|
||||
def define_day_values():
|
||||
# use sunday through saturday to match the day_of_week enum
|
||||
# loop over all seven days when generating the weekly schedule
|
||||
pass
|
||||
|
||||
|
||||
def compare_shift_capacity():
|
||||
# count employees assigned to one shift on one day
|
||||
# if the count is fewer than two, scheduler must add another employee
|
||||
# if the preferred shift is full, conflict manager must choose another shift
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user