190 lines
6.9 KiB
Python
190 lines
6.9 KiB
Python
from datetime import datetime
|
|
from typing import Any
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from pydantic import BaseModel, Field
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src.api.v1.dependencies.auth import get_current_user, require_role
|
|
from src.core.exceptions import ConflictException, NotFoundException
|
|
from src.domain.entities import MedicationEntity, UserRole
|
|
from src.infrastructure.database.repositories import MedicationCatalogRepository, MedicationRepository
|
|
from src.infrastructure.database.session import get_db_session
|
|
from src.services.auth.security import TokenData
|
|
from src.services.medication.medication_service import MedicationService
|
|
|
|
router = APIRouter(prefix="/medications", tags=["Medications"])
|
|
|
|
|
|
class MedicationCreateRequest(BaseModel):
|
|
nregistro: str = Field(..., min_length=1, max_length=50)
|
|
name: str = Field(..., min_length=1, max_length=500)
|
|
active_ingredient: str | None = Field(None, max_length=500)
|
|
dosage: str | None = Field(None, max_length=100)
|
|
form: str | None = Field(None, max_length=100)
|
|
atc_code: str | None = Field(None, max_length=20)
|
|
prescription_required: bool = False
|
|
manufacturer: str | None = Field(None, max_length=255)
|
|
metadata: dict[str, Any] | None = None
|
|
|
|
|
|
class MedicationUpdateRequest(BaseModel):
|
|
name: str | None = Field(None, min_length=1, max_length=500)
|
|
active_ingredient: str | None = Field(None, max_length=500)
|
|
dosage: str | None = Field(None, max_length=100)
|
|
form: str | None = Field(None, max_length=100)
|
|
atc_code: str | None = Field(None, max_length=20)
|
|
prescription_required: bool | None = None
|
|
manufacturer: str | None = Field(None, max_length=255)
|
|
metadata: dict[str, Any] | None = None
|
|
|
|
|
|
class MedicationResponse(BaseModel):
|
|
id: UUID
|
|
nregistro: str
|
|
name: str
|
|
active_ingredient: str | None
|
|
dosage: str | None
|
|
form: str | None
|
|
atc_code: str | None
|
|
prescription_required: bool
|
|
manufacturer: str | None
|
|
metadata: dict[str, Any] | None
|
|
created_at: datetime | None
|
|
updated_at: datetime | None
|
|
|
|
|
|
class MedicationListResponse(BaseModel):
|
|
items: list[MedicationResponse]
|
|
total: int
|
|
offset: int
|
|
limit: int
|
|
|
|
|
|
def _entity_to_response(e: MedicationEntity) -> MedicationResponse:
|
|
return MedicationResponse(
|
|
id=e.id, nregistro=e.nregistro, name=e.name,
|
|
active_ingredient=e.active_ingredient, dosage=e.dosage,
|
|
form=e.form, atc_code=e.atc_code,
|
|
prescription_required=e.prescription_required,
|
|
manufacturer=e.manufacturer, metadata=e.metadata_,
|
|
created_at=e.created_at, updated_at=e.updated_at,
|
|
)
|
|
|
|
|
|
def _get_service(session: AsyncSession) -> MedicationService:
|
|
return MedicationService(
|
|
medication_repo=MedicationRepository(session),
|
|
catalog_repo=MedicationCatalogRepository(session),
|
|
)
|
|
|
|
|
|
@router.get("", response_model=MedicationListResponse)
|
|
async def list_medications(
|
|
q: str | None = None,
|
|
offset: int = Query(0, ge=0),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(get_current_user),
|
|
):
|
|
service = _get_service(session)
|
|
if q:
|
|
entities, total = await service.search_medications(q, offset=offset, limit=limit)
|
|
else:
|
|
from src.domain.entities import MedicationEntity
|
|
all_entities, total = await service.search_medications("", offset=offset, limit=limit)
|
|
entities = all_entities
|
|
return MedicationListResponse(items=[_entity_to_response(e) for e in entities], total=total, offset=offset, limit=limit)
|
|
|
|
|
|
@router.get("/search", response_model=MedicationListResponse)
|
|
async def search_medications(
|
|
q: str = Query(..., min_length=1),
|
|
offset: int = Query(0, ge=0),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(get_current_user),
|
|
):
|
|
service = _get_service(session)
|
|
entities, total = await service.search_medications(q, offset=offset, limit=limit)
|
|
return MedicationListResponse(items=[_entity_to_response(e) for e in entities], total=total, offset=offset, limit=limit)
|
|
|
|
|
|
@router.get("/nregistro/{nregistro}", response_model=MedicationResponse)
|
|
async def get_medication_by_nregistro(
|
|
nregistro: str,
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(get_current_user),
|
|
):
|
|
service = _get_service(session)
|
|
entity = await service.get_by_nregistro(nregistro)
|
|
if not entity:
|
|
raise NotFoundException("Medication", nregistro)
|
|
return _entity_to_response(entity)
|
|
|
|
|
|
@router.get("/{medication_id}", response_model=MedicationResponse)
|
|
async def get_medication(
|
|
medication_id: UUID,
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(get_current_user),
|
|
):
|
|
service = _get_service(session)
|
|
entity = await service.get_medication(medication_id)
|
|
if not entity:
|
|
raise NotFoundException("Medication", str(medication_id))
|
|
return _entity_to_response(entity)
|
|
|
|
|
|
@router.post("", response_model=MedicationResponse, status_code=201)
|
|
async def create_medication(
|
|
body: MedicationCreateRequest,
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
|
|
):
|
|
service = _get_service(session)
|
|
entity = MedicationEntity(
|
|
nregistro=body.nregistro, name=body.name,
|
|
active_ingredient=body.active_ingredient, dosage=body.dosage,
|
|
form=body.form, atc_code=body.atc_code,
|
|
prescription_required=body.prescription_required,
|
|
manufacturer=body.manufacturer, metadata_=body.metadata,
|
|
)
|
|
created = await service.create_medication(entity)
|
|
return _entity_to_response(created)
|
|
|
|
|
|
@router.put("/{medication_id}", response_model=MedicationResponse)
|
|
async def update_medication(
|
|
medication_id: UUID,
|
|
body: MedicationUpdateRequest,
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
|
|
):
|
|
service = _get_service(session)
|
|
entity = await service.get_medication(medication_id)
|
|
if not entity:
|
|
raise NotFoundException("Medication", str(medication_id))
|
|
|
|
update_data = body.model_dump(exclude_unset=True)
|
|
if "metadata" in update_data:
|
|
entity.metadata_ = update_data.pop("metadata")
|
|
for key, value in update_data.items():
|
|
setattr(entity, key, value)
|
|
|
|
updated = await service.update_medication(entity)
|
|
return _entity_to_response(updated)
|
|
|
|
|
|
@router.delete("/{medication_id}", status_code=204)
|
|
async def delete_medication(
|
|
medication_id: UUID,
|
|
session: AsyncSession = Depends(get_db_session),
|
|
current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
|
|
):
|
|
service = _get_service(session)
|
|
deleted = await service.delete_medication(medication_id)
|
|
if not deleted:
|
|
raise NotFoundException("Medication", str(medication_id))
|