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

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 import select, desc
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
@ -16,7 +16,7 @@ class AppointmentsRepository:
select(Appointment) select(Appointment)
.options(joinedload(Appointment.type)) .options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient)) .options(joinedload(Appointment.patient))
.order_by(desc(Appointment.)) .order_by(desc(Appointment.appointment_datetime))
) )
result = await self.db.execute(stmt) result = await self.db.execute(stmt)
return result.scalars().all() return result.scalars().all()
@ -26,5 +26,45 @@ class AppointmentsRepository:
select(Appointment) select(Appointment)
.options(joinedload(Appointment.type)) .options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient)) .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 sqlalchemy.orm import relationship
from app.domain.models.base import BaseModel 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.orm import relationship
from sqlalchemy.sql import func from sqlalchemy.sql import func
@ -10,7 +10,7 @@ class Appointment(BaseModel):
results = Column(String) results = Column(String)
days_until_the_next_appointment = Column(Integer) 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) patient_id = Column(Integer, ForeignKey('patients.id'), nullable=False)
doctor_id = Column(Integer, ForeignKey('users.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 fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status from starlette import status
@ -28,7 +30,7 @@ class LensIssuesService:
for lens_issue in lens_issues 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) patient = await self.patient_repository.get_by_id(lens_issue.patient_id)
if not patient: if not patient:

View File

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

View File

@ -32,7 +32,7 @@ class LensesService:
for lens in lenses 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) lens_type = await self.lens_types_repository.get_by_id(lens.type_id)
if not lens_type: if not lens_type:
@ -47,7 +47,7 @@ class LensesService:
return self.model_to_entity(lens_model) 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) lens_model = await self.lenses_repository.get_by_id(lens_id)
if not lens_model: if not lens_model:

View File

@ -42,7 +42,8 @@ class SetContentService:
for content in set_content 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) _set = await self.set_repository.get_by_id(set_id)
if not _set: if not _set:
@ -73,7 +74,7 @@ class SetContentService:
for content in sets_content_models 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) _set = await self.set_repository.get_by_id(set_id)
if not _set: if not _set:
@ -104,8 +105,8 @@ class SetContentService:
return self.model_to_entity(set_content_model) 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[ async def update_set_content_by_set_id(self, set_id: int, sets_content: list[SetContentEntity]) -> Optional[
SetContentEntity list[SetContentEntity]
]: ]:
_set = await self.set_repository.get_by_id(set_id) _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.lens import LensEntity
from app.domain.entities.set import SetEntity from app.domain.entities.set import SetEntity
from app.domain.models import Set, Lens from app.domain.models import Set, Lens
from app.infrastructure.lenses_service import LensesService
class SetsService: class SetsService:
@ -20,25 +21,20 @@ class SetsService:
async def get_all_sets(self) -> list[SetEntity]: async def get_all_sets(self) -> list[SetEntity]:
sets = await self.sets_repository.get_all() sets = await self.sets_repository.get_all()
return [ return [
SetEntity( self.model_to_entity(_set)
id=_set.id,
title=_set.title,
)
for _set in sets for _set in sets
] ]
async def create_set(self, _set: SetEntity) -> SetEntity: async def create_set(self, _set: SetEntity) -> SetEntity:
set_model = Set( set_model = self.entity_to_model(_set)
title=_set.title,
)
await self.sets_repository.create(set_model)
return SetEntity(
id=set_model.id,
title=set_model.title,
)
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) set_model = await self.sets_repository.get_by_id(set_id)
if not set_model: if not set_model:
@ -48,10 +44,7 @@ class SetsService:
await self.sets_repository.update(set_model) await self.sets_repository.update(set_model)
return SetEntity( return self.model_to_entity(set_model)
id=set_model.id,
title=set_model.title,
)
async def delete_set(self, set_id: int) -> Optional[SetEntity]: async def delete_set(self, set_id: int) -> Optional[SetEntity]:
_set = await self.sets_repository.get_by_id(set_id) _set = await self.sets_repository.get_by_id(set_id)
@ -66,10 +59,7 @@ class SetsService:
result = await self.sets_repository.delete(_set) result = await self.sets_repository.delete(_set)
return SetEntity( return self.model_to_entity(result)
id=result.id,
title=result.title,
)
async def append_set_content_to_lenses(self, set_id: int) -> Optional[list[LensEntity]]: async def append_set_content_to_lenses(self, set_id: int) -> Optional[list[LensEntity]]:
_set = await self.sets_repository.get_by_id(set_id) _set = await self.sets_repository.get_by_id(set_id)
@ -81,31 +71,12 @@ class SetsService:
lenses = [] lenses = []
for content in set_content: for content in set_content:
lens = Lens( lens = LensesService.entity_to_model(content)
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,
)
await self.lenses_repository.create(lens) await self.lenses_repository.create(lens)
lenses.append( lenses.append(
LensEntity( LensesService.model_to_entity(lens)
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,
)
) )
return lenses return lenses
@ -122,3 +93,8 @@ class SetsService:
set_model = Set( set_model = Set(
title=_set.title, 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 fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware 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.auth_router import router as auth_router
from app.controllers.lens_issues_router import router as lens_issues_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 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(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(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(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 return api_app
@ -40,4 +44,4 @@ app = start_app()
@app.get("/", tags=['root']) @app.get("/", tags=['root'])
async def root(): async def root():
return {"message": "OK"} return {"message": "Hello :з"}