сделал слои для приемов и типов приемов

This commit is contained in:
Андрей Дувакин 2025-03-11 18:36:52 +05:00
parent b4de82a6e9
commit faaf087d08
16 changed files with 464 additions and 58 deletions

View File

@ -1,4 +1,4 @@
from typing import Optional, Sequence
from typing import Sequence
from sqlalchemy import select, desc
from sqlalchemy.ext.asyncio import AsyncSession
@ -16,7 +16,7 @@ class AppointmentsRepository:
select(Appointment)
.options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient))
.order_by(desc(Appointment.))
.order_by(desc(Appointment.appointment_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
@ -26,5 +26,45 @@ class AppointmentsRepository:
select(Appointment)
.options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient))
.filter()
.filter(Appointment.doctor_id == doctor_id)
.order_by(desc(Appointment.appointment_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_patient_id(self, patient_id: int):
stmt = (
select(Appointment)
.options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient))
.filter(Appointment.patient_id == patient_id)
.order_by(desc(Appointment.appointment_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_id(self, appointment_id: int):
stmt = (
select(Appointment)
.options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient))
.filter(Appointment.id == appointment_id)
)
result = await self.db.execute(stmt)
return result.scalars().first()
async def create(self, appointment: Appointment) -> Appointment:
self.db.add(appointment)
await self.db.commit()
await self.db.refresh(appointment)
return appointment
async def update(self, appointment: Appointment) -> Appointment:
await self.db.merge(appointment)
await self.db.commit()
return appointment
async def delete(self, appointment) -> Appointment:
await self.db.delete(appointment)
await self.db.commit()
return appointment

View File

@ -0,0 +1,23 @@
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.session import get_db
from app.domain.entities.appointment_type import AppointmentTypeEntity
from app.infrastructure.appointment_types_service import AppointmentTypesService
from app.infrastructure.dependencies import get_current_user
router = APIRouter()
@router.get(
"/appointment_types/",
response_model=list[AppointmentTypeEntity],
summary="Get all appointment types",
description="Returns a list of all appointment types",
)
async def get_all_appointment_types(
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointment_types_service = AppointmentTypesService(db)
return await appointment_types_service.get_all_appointment_types()

View File

@ -0,0 +1,84 @@
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.session import get_db
from app.domain.entities.appointment import AppointmentEntity
from app.infrastructure.appointments_service import AppointmentsService
from app.infrastructure.dependencies import get_current_user
router = APIRouter()
@router.get(
"/appointments/",
response_model=list[AppointmentEntity],
summary="Get all appointments",
description="Returns a list of all appointments",
)
async def get_all_appointments(
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointments_service = AppointmentsService(db)
return await appointments_service.get_all_appointments()
@router.get(
"/appointments/doctor/{doctor_id}/",
response_model=AppointmentEntity,
summary="Get all appointments for doctor",
description="Returns a list of appointments for doctor",
)
async def get_all_appointments_by_doctor_id(
doctor_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointments_service = AppointmentsService(db)
return await appointments_service.get_appointments_by_doctor_id(doctor_id)
@router.get(
"/appointments/patient/{patient_id}/",
response_model=AppointmentEntity,
summary="Get all appointments for patient",
description="Returns a list of appointments for patient",
)
async def get_all_appointments_by_patient_id(
patient_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointments_service = AppointmentsService(db)
return await appointments_service.get_appointments_by_patient_id(patient_id)
@router.post(
"/appointments/",
response_model=AppointmentEntity,
summary="Create appointment",
description="Creates a new appointment",
)
async def create_appointment(
appointment: AppointmentEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointment_service = AppointmentsService(db)
return await appointment_service.create_appointment(appointment)
@router.put(
"/appointments/{appointment_id}/",
response_model=AppointmentEntity,
summary="Update appointment",
description="Updates an existing appointment",
)
async def update_appointment(
appointment_id: int,
appointment: AppointmentEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointment_service = AppointmentsService(db)
return await appointment_service.update_appointment(appointment_id, appointment)

View File

@ -0,0 +1,32 @@
"""0002_изменил_полеаты_приемааатувремя
Revision ID: f28580d2d60f
Revises: b10579618fb5
Create Date: 2025-03-11 14:44:43.322192
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'f28580d2d60f'
down_revision: Union[str, None] = 'b10579618fb5'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('appointments', sa.Column('appointment_datetime', sa.DateTime(), server_default=sa.text('now()'), nullable=False))
op.drop_column('appointments', 'date')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('appointments', sa.Column('date', sa.DATE(), server_default=sa.text('now()'), autoincrement=False, nullable=False))
op.drop_column('appointments', 'appointment_datetime')
# ### end Alembic commands ###

View File

@ -0,0 +1,23 @@
import datetime
from typing import Optional
from pydantic import BaseModel
from app.domain.entities.appointment_type import AppointmentTypeEntity
from app.domain.entities.patient import PatientEntity
from app.domain.entities.user import UserEntity
class AppointmentEntity(BaseModel):
id: Optional[int] = None
results: Optional[str] = None
days_until_the_next_appointment: Optional[int] = None
appointment_datetime: datetime.datetime
patient_id: int
doctor_id: int
type_id: int
patient: Optional[PatientEntity] = None
doctor: Optional[UserEntity] = None
type: Optional[AppointmentTypeEntity] = None

View File

@ -0,0 +1,8 @@
from typing import Optional
from pydantic import BaseModel
class AppointmentTypeEntity(BaseModel):
id: Optional[int] = None
title: str

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, VARCHAR
from sqlalchemy import Column, VARCHAR
from sqlalchemy.orm import relationship
from app.domain.models.base import BaseModel

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Date
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
@ -10,7 +10,7 @@ class Appointment(BaseModel):
results = Column(String)
days_until_the_next_appointment = Column(Integer)
date = Column(Date, nullable=False, server_default=func.now())
appointment_datetime = Column(DateTime, nullable=False, server_default=func.now())
patient_id = Column(Integer, ForeignKey('patients.id'), nullable=False)
doctor_id = Column(Integer, ForeignKey('users.id'), nullable=False)

View File

@ -0,0 +1,36 @@
from sqlalchemy.ext.asyncio import AsyncSession
from app.application.appointment_types_repository import AppointmentTypesRepository
from app.domain.entities.appointment_type import AppointmentTypeEntity
from app.domain.models import AppointmentType
class AppointmentTypesService:
def __init__(self, db: AsyncSession):
self.appointment_types_repository = AppointmentTypesRepository(db)
async def get_all_appointment_types(self) -> list[AppointmentTypeEntity]:
appointment_types = await self.appointment_types_repository.get_all()
return [
self.model_to_entity(appointment_type)
for appointment_type in appointment_types
]
@staticmethod
def entity_to_model(appointment_type: AppointmentTypeEntity) -> AppointmentType:
appointment_type_model = AppointmentType(
title=appointment_type.title,
)
if appointment_type.id is not None:
appointment_type_model.id = appointment_type.id
return appointment_type_model
@staticmethod
def model_to_entity(appointment_type_model: AppointmentType) -> AppointmentTypeEntity:
return AppointmentTypeEntity(
id=appointment_type_model.id,
title=appointment_type_model.title,
)

View File

@ -0,0 +1,176 @@
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status
from app.application.appointment_types_repository import AppointmentTypesRepository
from app.application.appointments_repository import AppointmentsRepository
from app.application.patients_repository import PatientsRepository
from app.application.users_repository import UsersRepository
from app.domain.entities.appointment import AppointmentEntity
from app.domain.models import Appointment
from app.infrastructure.appointment_types_service import AppointmentTypesService
from app.infrastructure.patients_service import PatientsService
from app.infrastructure.users_service import UsersService
class AppointmentsService:
def __init__(self, db: AsyncSession):
self.appointments_repository = AppointmentsRepository(db)
self.appointment_types_repository = AppointmentTypesRepository(db)
self.users_repository = UsersRepository(db)
self.patients_repository = PatientsRepository(db)
async def get_all_appointments(self) -> list[AppointmentEntity]:
appointments = await self.appointments_repository.get_all()
return [
self.model_to_entity(appointment)
for appointment in appointments
]
async def get_appointments_by_doctor_id(self, doctor_id: int) -> Optional[list[AppointmentEntity]]:
doctor = await self.users_repository.get_by_id(doctor_id)
if not doctor:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The doctor with this ID was not found',
)
appointments = await self.appointments_repository.get_by_doctor_id(doctor_id)
return [
self.model_to_entity(appointment)
for appointment in appointments
]
async def get_appointments_by_patient_id(self, patient_id: int) -> Optional[list[AppointmentEntity]]:
patient = await self.patients_repository.get_by_id(patient_id)
if not patient:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The patient with this ID was not found',
)
appointments = await self.appointments_repository.get_by_patient_id(patient_id)
return [
self.model_to_entity(appointment)
for appointment in appointments
]
async def create_appointment(self, appointment: AppointmentEntity) -> Optional[AppointmentEntity]:
patient = await self.patients_repository.get_by_id(appointment.patient_id)
if not patient:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The patient with this ID was not found',
)
doctor = await self.users_repository.get_by_id(appointment.doctor_id)
if not doctor:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The doctor/user with this ID was not found',
)
appointment_type = await self.appointment_types_repository.get_by_id(appointment.type_id)
if not appointment_type:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The appointment type with this ID was not found',
)
appointment_model = self.entity_to_model(appointment)
await self.appointments_repository.create(appointment_model)
return self.model_to_entity(appointment_model)
async def update_appointment(self, appointment_id: int, appointment: AppointmentEntity) -> Optional[
AppointmentEntity
]:
appointment_model = await self.appointments_repository.get_by_id(appointment_id)
if not appointment_model:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Appointment not found")
patient = await self.patients_repository.get_by_id(appointment.patient_id)
if not patient:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The patient with this ID was not found',
)
doctor = await self.users_repository.get_by_id(appointment.doctor_id)
if not doctor:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The doctor/user with this ID was not found',
)
appointment_type = await self.appointment_types_repository.get_by_id(appointment.type_id)
if not appointment_type:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The appointment type with this ID was not found',
)
appointment_model.results = appointment.results
appointment_model.days_until_the_next_appointment = appointment.days_until_the_next_appointment
appointment_model.appointment_datetime = appointment.appointment_datetime
appointment_model.patient_id = appointment.patient_id
appointment_model.doctor_id = appointment.doctor_id
appointment_model.type_id = appointment.type_id
await self.appointments_repository.update(appointment_model)
return self.model_to_entity(appointment_model)
@staticmethod
def entity_to_model(appointment: AppointmentEntity) -> Appointment:
appointment_model = Appointment(
results=appointment.results,
days_until_the_next_appointment=appointment.days_until_the_next_appointment,
appointment_datetime=appointment.appointment_datetime,
patient_id=appointment.patient_id,
doctor_id=appointment.doctor_id,
type_id=appointment.type_id,
)
if appointment.id is not None:
appointment_model.id = appointment.id
return appointment_model
@staticmethod
def model_to_entity(appointment: Appointment) -> AppointmentEntity:
appointment_entity = AppointmentEntity(
id=appointment.id,
results=appointment.results,
days_until_the_next_appointment=appointment.days_until_the_next_appointment,
appointment_datetime=appointment.appointment_datetime,
patient_id=appointment.patient_id,
doctor_id=appointment.doctor_id,
type_id=appointment.type_id,
)
if appointment.patient is not None:
appointment_entity.patient = PatientsService.model_to_entity(appointment.patient)
if appointment.doctor is not None:
appointment_entity.doctor = UsersService.model_to_entity(appointment.doctor)
if appointment.type is not None:
appointment_entity.type = AppointmentTypesService.model_to_entity(appointment.type)
return appointment_entity

View File

@ -1,3 +1,5 @@
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status
@ -28,7 +30,7 @@ class LensIssuesService:
for lens_issue in lens_issues
]
async def create_lens_issue(self, lens_issue: LensIssueEntity, user_id: int) -> LensIssueEntity:
async def create_lens_issue(self, lens_issue: LensIssueEntity, user_id: int) -> Optional[LensIssueEntity]:
patient = await self.patient_repository.get_by_id(lens_issue.patient_id)
if not patient:

View File

@ -10,6 +10,7 @@ class LensTypesService:
async def get_all_lens_types(self) -> list[LensTypeEntity]:
lens_types = await self.lens_types_repository.get_all()
return [
LensTypeEntity(
id=lens_type.id,

View File

@ -32,7 +32,7 @@ class LensesService:
for lens in lenses
]
async def create_lens(self, lens: LensEntity) -> LensEntity:
async def create_lens(self, lens: LensEntity) -> Optional[LensEntity]:
lens_type = await self.lens_types_repository.get_by_id(lens.type_id)
if not lens_type:
@ -47,7 +47,7 @@ class LensesService:
return self.model_to_entity(lens_model)
async def update_lens(self, lens_id: int, lens: LensEntity) -> LensEntity:
async def update_lens(self, lens_id: int, lens: LensEntity) -> Optional[LensEntity]:
lens_model = await self.lenses_repository.get_by_id(lens_id)
if not lens_model:

View File

@ -42,7 +42,8 @@ class SetContentService:
for content in set_content
]
async def create_list_sets(self, set_id: int, sets_content: list[SetContentEntity]) -> list[SetContentEntity]:
async def create_list_sets(self, set_id: int, sets_content: list[SetContentEntity]) -> Optional[
list[SetContentEntity]]:
_set = await self.set_repository.get_by_id(set_id)
if not _set:
@ -73,7 +74,7 @@ class SetContentService:
for content in sets_content_models
]
async def create_set_content(self, set_id: int, set_content: SetContentEntity) -> SetContentEntity:
async def create_set_content(self, set_id: int, set_content: SetContentEntity) -> Optional[SetContentEntity]:
_set = await self.set_repository.get_by_id(set_id)
if not _set:
@ -104,8 +105,8 @@ class SetContentService:
return self.model_to_entity(set_content_model)
async def update_set_content_by_set_id(self, set_id: int, sets_content: list[SetContentEntity]) -> list[
SetContentEntity
async def update_set_content_by_set_id(self, set_id: int, sets_content: list[SetContentEntity]) -> Optional[
list[SetContentEntity]
]:
_set = await self.set_repository.get_by_id(set_id)

View File

@ -10,6 +10,7 @@ from app.application.sets_repository import SetsRepository
from app.domain.entities.lens import LensEntity
from app.domain.entities.set import SetEntity
from app.domain.models import Set, Lens
from app.infrastructure.lenses_service import LensesService
class SetsService:
@ -20,25 +21,20 @@ class SetsService:
async def get_all_sets(self) -> list[SetEntity]:
sets = await self.sets_repository.get_all()
return [
SetEntity(
id=_set.id,
title=_set.title,
)
self.model_to_entity(_set)
for _set in sets
]
async def create_set(self, _set: SetEntity) -> SetEntity:
set_model = Set(
title=_set.title,
)
await self.sets_repository.create(set_model)
return SetEntity(
id=set_model.id,
title=set_model.title,
)
set_model = self.entity_to_model(_set)
async def update_set(self, set_id: int, _set: SetEntity) -> SetEntity:
await self.sets_repository.create(set_model)
return self.model_to_entity(set_model)
async def update_set(self, set_id: int, _set: SetEntity) -> Optional[SetEntity]:
set_model = await self.sets_repository.get_by_id(set_id)
if not set_model:
@ -48,10 +44,7 @@ class SetsService:
await self.sets_repository.update(set_model)
return SetEntity(
id=set_model.id,
title=set_model.title,
)
return self.model_to_entity(set_model)
async def delete_set(self, set_id: int) -> Optional[SetEntity]:
_set = await self.sets_repository.get_by_id(set_id)
@ -66,10 +59,7 @@ class SetsService:
result = await self.sets_repository.delete(_set)
return SetEntity(
id=result.id,
title=result.title,
)
return self.model_to_entity(result)
async def append_set_content_to_lenses(self, set_id: int) -> Optional[list[LensEntity]]:
_set = await self.sets_repository.get_by_id(set_id)
@ -81,31 +71,12 @@ class SetsService:
lenses = []
for content in set_content:
lens = Lens(
tor=content.tor,
trial=content.trial,
esa=content.esa,
fvc=content.fvc,
preset_refraction=content.preset_refraction,
diameter=content.diameter,
periphery_toricity=content.periphery_toricity,
side=content.side,
type_id=content.type_id,
)
lens = LensesService.entity_to_model(content)
await self.lenses_repository.create(lens)
lenses.append(
LensEntity(
id=lens.id,
tor=lens.tor,
trial=lens.trial,
esa=lens.esa,
fvc=lens.fvc,
preset_refraction=lens.preset_refraction,
diameter=lens.diameter,
periphery_toricity=lens.periphery_toricity,
side=lens.side.value,
type_id=lens.type_id,
)
LensesService.model_to_entity(lens)
)
return lenses
@ -122,3 +93,8 @@ class SetsService:
set_model = Set(
title=_set.title,
)
if _set.id is not None:
set_model.id = _set.id
return set_model

View File

@ -1,6 +1,8 @@
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from app.controllers.appointment_types_router import router as appointment_types_router
from app.controllers.appointments_router import router as appointment_router
from app.controllers.auth_router import router as auth_router
from app.controllers.lens_issues_router import router as lens_issues_router
from app.controllers.lens_types_router import router as lens_types_router
@ -31,6 +33,8 @@ def start_app():
api_app.include_router(sets_router, prefix=settings.APP_PREFIX, tags=['sets'])
api_app.include_router(set_content_router, prefix=settings.APP_PREFIX, tags=['set_content'])
api_app.include_router(lens_issues_router, prefix=settings.APP_PREFIX, tags=['lens_issue'])
api_app.include_router(appointment_types_router, prefix=settings.APP_PREFIX, tags=['appointment_types'])
api_app.include_router(appointment_router, prefix=settings.APP_PREFIX, tags=['appointments'])
return api_app
@ -40,4 +44,4 @@ app = start_app()
@app.get("/", tags=['root'])
async def root():
return {"message": "OK"}
return {"message": "Hello :з"}