First implementation API for PIP (Proyecto: Pharmacy Integration Platform)
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
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 NotFoundException
|
||||
from src.domain.entities import InventoryRecordEntity, UserRole
|
||||
from src.infrastructure.database.repositories import InventoryRepository, ReservationRepository
|
||||
from src.infrastructure.database.session import get_db_session
|
||||
from src.services.auth.security import TokenData
|
||||
from src.services.inventory.inventory_service import InventoryService
|
||||
|
||||
router = APIRouter(prefix="/pharmacies/{pharmacy_id}/inventory", tags=["Inventory"])
|
||||
|
||||
|
||||
class InventoryUpsertRequest(BaseModel):
|
||||
medication_id: UUID
|
||||
stock: int = Field(..., ge=0)
|
||||
reserved_stock: int = Field(0, ge=0)
|
||||
available_stock: int = Field(0, ge=0)
|
||||
min_stock: int | None = Field(None, ge=0)
|
||||
max_stock: int | None = Field(None, ge=0)
|
||||
last_updated_at: datetime | None = None
|
||||
source: str | None = Field(None, max_length=100)
|
||||
batch_id: str | None = Field(None, max_length=100)
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class InventoryRecordResponse(BaseModel):
|
||||
id: UUID
|
||||
pharmacy_id: UUID
|
||||
medication_id: UUID
|
||||
stock: int
|
||||
reserved_stock: int
|
||||
available_stock: int
|
||||
min_stock: int | None
|
||||
max_stock: int | None
|
||||
last_updated_at: datetime | None
|
||||
source: str | None
|
||||
batch_id: str | None
|
||||
metadata: dict[str, Any] | None
|
||||
created_at: datetime | None
|
||||
updated_at: datetime | None
|
||||
|
||||
|
||||
class InventoryListResponse(BaseModel):
|
||||
items: list[InventoryRecordResponse]
|
||||
total: int
|
||||
offset: int
|
||||
limit: int
|
||||
|
||||
|
||||
class InventoryHistoryResponse(BaseModel):
|
||||
id: UUID
|
||||
pharmacy_id: UUID
|
||||
medication_id: UUID
|
||||
previous_stock: int
|
||||
new_stock: int
|
||||
delta: int
|
||||
reason: str | None
|
||||
source: str | None
|
||||
created_at: datetime | None
|
||||
|
||||
|
||||
def _record_entity_to_response(e: InventoryRecordEntity) -> InventoryRecordResponse:
|
||||
return InventoryRecordResponse(
|
||||
id=e.id, pharmacy_id=e.pharmacy_id, medication_id=e.medication_id,
|
||||
stock=e.stock, reserved_stock=e.reserved_stock, available_stock=e.available_stock,
|
||||
min_stock=e.min_stock, max_stock=e.max_stock,
|
||||
last_updated_at=e.last_updated_at, source=e.source, batch_id=e.batch_id,
|
||||
metadata=e.metadata_, created_at=e.created_at, updated_at=e.updated_at,
|
||||
)
|
||||
|
||||
|
||||
def _get_service(session: AsyncSession) -> InventoryService:
|
||||
return InventoryService(
|
||||
inventory_repo=InventoryRepository(session),
|
||||
reservation_repo=ReservationRepository(session),
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=InventoryListResponse)
|
||||
async def list_inventory(
|
||||
pharmacy_id: UUID,
|
||||
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.list_inventory(pharmacy_id, offset=offset, limit=limit)
|
||||
return InventoryListResponse(items=[_record_entity_to_response(e) for e in entities], total=total, offset=offset, limit=limit)
|
||||
|
||||
|
||||
@router.get("/{medication_id}", response_model=InventoryRecordResponse)
|
||||
async def get_inventory_record(
|
||||
pharmacy_id: UUID,
|
||||
medication_id: UUID,
|
||||
session: AsyncSession = Depends(get_db_session),
|
||||
current_user: TokenData = Depends(get_current_user),
|
||||
):
|
||||
service = _get_service(session)
|
||||
entity = await service.get_inventory_record(pharmacy_id, medication_id)
|
||||
if not entity:
|
||||
raise NotFoundException("InventoryRecord", f"{pharmacy_id}/{medication_id}")
|
||||
return _record_entity_to_response(entity)
|
||||
|
||||
|
||||
@router.put("", response_model=InventoryRecordResponse)
|
||||
async def upsert_inventory_record(
|
||||
pharmacy_id: UUID,
|
||||
body: InventoryUpsertRequest,
|
||||
session: AsyncSession = Depends(get_db_session),
|
||||
current_user: TokenData = Depends(require_role(UserRole.OPERATOR)),
|
||||
):
|
||||
service = _get_service(session)
|
||||
entity = InventoryRecordEntity(
|
||||
pharmacy_id=pharmacy_id, medication_id=body.medication_id,
|
||||
stock=body.stock, reserved_stock=body.reserved_stock,
|
||||
available_stock=body.available_stock, min_stock=body.min_stock,
|
||||
max_stock=body.max_stock, last_updated_at=body.last_updated_at,
|
||||
source=body.source, batch_id=body.batch_id, metadata_=body.metadata,
|
||||
)
|
||||
upserted = await service.upsert_inventory_record(entity)
|
||||
return _record_entity_to_response(upserted)
|
||||
|
||||
|
||||
@router.get("/{medication_id}/history", response_model=list[InventoryHistoryResponse])
|
||||
async def get_inventory_history(
|
||||
pharmacy_id: UUID,
|
||||
medication_id: UUID,
|
||||
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)
|
||||
history = await service.get_inventory_history(pharmacy_id, medication_id, offset=offset, limit=limit)
|
||||
return [
|
||||
InventoryHistoryResponse(
|
||||
id=h.id, pharmacy_id=h.pharmacy_id, medication_id=h.medication_id,
|
||||
previous_stock=h.previous_stock, new_stock=h.new_stock, delta=h.delta,
|
||||
reason=h.reason, source=h.source, created_at=h.created_at,
|
||||
)
|
||||
for h in history
|
||||
]
|
||||
Reference in New Issue
Block a user