First implementation API for PIP (Proyecto: Pharmacy Integration Platform)
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
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))
|
||||
Reference in New Issue
Block a user