药品流向管理内容优化-初步

This commit is contained in:
Cheng Zhou
2026-01-13 19:42:28 +08:00
parent 1db36f40b0
commit ef1e67218c
21 changed files with 344 additions and 480 deletions
+21 -1
View File
@@ -6,6 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_current_user, get_db_session, require_study_member, require_study_roles
from app.crud import audit as audit_crud
from app.crud import drug_shipment as shipment_crud
from app.crud import site as site_crud
from app.crud import study as study_crud
from app.schemas.drug_shipment import DrugShipmentCreate, DrugShipmentRead, DrugShipmentUpdate
@@ -32,6 +33,10 @@ async def create_shipment(
current_user=Depends(get_current_user),
) -> DrugShipmentRead:
await _ensure_study_exists(db, study_id)
site = await site_crud.get_site(db, shipment_in.center_id)
if not site or site.study_id != study_id:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="分中心不存在")
shipment_in = shipment_in.model_copy(update={"site_name": site.name})
shipment = await shipment_crud.create_shipment(db, study_id, shipment_in, created_by=current_user.id)
await audit_crud.log_action(
db,
@@ -53,8 +58,10 @@ async def create_shipment(
)
async def list_shipments(
study_id: uuid.UUID,
center_id: uuid.UUID | None = None,
site_name: str | None = None,
tracking_no: str | None = None,
direction: str | None = None,
status: str | None = None,
skip: int = 0,
limit: int = 100,
@@ -62,7 +69,15 @@ async def list_shipments(
) -> list[DrugShipmentRead]:
await _ensure_study_exists(db, study_id)
items = await shipment_crud.list_shipments(
db, study_id, site_name=site_name, tracking_no=tracking_no, status=status, skip=skip, limit=limit
db,
study_id,
center_id=center_id,
site_name=site_name,
tracking_no=tracking_no,
direction=direction,
status=status,
skip=skip,
limit=limit,
)
return [DrugShipmentRead.model_validate(item) for item in items]
@@ -100,6 +115,11 @@ async def update_shipment(
shipment = await shipment_crud.get_shipment(db, shipment_id)
if not shipment or shipment.study_id != study_id:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="运输记录不存在")
if shipment_in.center_id:
site = await site_crud.get_site(db, shipment_in.center_id)
if not site or site.study_id != study_id:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="分中心不存在")
shipment_in = shipment_in.model_copy(update={"site_name": site.name})
shipment = await shipment_crud.update_shipment(db, shipment, shipment_in)
await audit_crud.log_action(
db,
+11 -4
View File
@@ -17,13 +17,14 @@ async def create_shipment(
shipment = DrugShipment(
study_id=study_id,
direction=shipment_in.direction,
site_name=shipment_in.site_name,
drug_desc=shipment_in.drug_desc,
center_id=shipment_in.center_id,
site_name=shipment_in.site_name or "",
ship_date=shipment_in.ship_date,
receive_date=shipment_in.receive_date,
quantity=shipment_in.quantity,
batch_no=shipment_in.batch_no,
carrier=shipment_in.carrier,
tracking_no=shipment_in.tracking_no,
from_party=shipment_in.from_party,
to_party=shipment_in.to_party,
status=shipment_in.status,
remark=shipment_in.remark,
created_by=created_by,
@@ -42,17 +43,23 @@ async def get_shipment(db: AsyncSession, shipment_id: uuid.UUID) -> DrugShipment
async def list_shipments(
db: AsyncSession,
study_id: uuid.UUID,
center_id: uuid.UUID | None = None,
site_name: str | None = None,
tracking_no: str | None = None,
direction: str | None = None,
status: str | None = None,
skip: int = 0,
limit: int = 100,
) -> Sequence[DrugShipment]:
stmt = select(DrugShipment).where(DrugShipment.study_id == study_id)
if center_id:
stmt = stmt.where(DrugShipment.center_id == center_id)
if site_name:
stmt = stmt.where(DrugShipment.site_name.ilike(f"%{site_name}%"))
if tracking_no:
stmt = stmt.where(DrugShipment.tracking_no.ilike(f"%{tracking_no}%"))
if direction:
stmt = stmt.where(DrugShipment.direction == direction)
if status:
stmt = stmt.where(DrugShipment.status == status)
stmt = stmt.order_by(DrugShipment.created_at.desc()).offset(skip).limit(limit)
+5 -4
View File
@@ -1,7 +1,7 @@
import uuid
from datetime import date, datetime
from sqlalchemy import Date, DateTime, ForeignKey, String, Text, func
from sqlalchemy import Date, DateTime, ForeignKey, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
@@ -14,13 +14,14 @@ class DrugShipment(Base):
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
study_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("studies.id"), index=True, nullable=False)
direction: Mapped[str] = mapped_column(String(20), nullable=False)
center_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("sites.id"), index=True, nullable=True)
site_name: Mapped[str] = mapped_column(String(255), nullable=False)
drug_desc: Mapped[str] = mapped_column(Text, nullable=False)
ship_date: Mapped[date | None] = mapped_column(Date, nullable=True)
receive_date: Mapped[date | None] = mapped_column(Date, nullable=True)
quantity: Mapped[int | None] = mapped_column(Integer, nullable=True)
batch_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
carrier: Mapped[str | None] = mapped_column(String(100), nullable=True)
tracking_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
from_party: Mapped[str | None] = mapped_column(String(255), nullable=True)
to_party: Mapped[str | None] = mapped_column(String(255), nullable=True)
status: Mapped[str] = mapped_column(String(30), nullable=False)
remark: Mapped[str | None] = mapped_column(Text, nullable=True)
created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
+17 -14
View File
@@ -7,26 +7,28 @@ from pydantic import BaseModel, ConfigDict
class DrugShipmentCreate(BaseModel):
direction: str
site_name: str
drug_desc: str
ship_date: Optional[date] = None
carrier: Optional[str] = None
tracking_no: Optional[str] = None
from_party: Optional[str] = None
to_party: Optional[str] = None
center_id: uuid.UUID
site_name: Optional[str] = None
ship_date: date
receive_date: date
quantity: int
batch_no: str
carrier: str
tracking_no: str
status: str
remark: Optional[str] = None
remark: str
class DrugShipmentUpdate(BaseModel):
direction: Optional[str] = None
center_id: Optional[uuid.UUID] = None
site_name: Optional[str] = None
drug_desc: Optional[str] = None
ship_date: Optional[date] = None
receive_date: Optional[date] = None
quantity: Optional[int] = None
batch_no: Optional[str] = None
carrier: Optional[str] = None
tracking_no: Optional[str] = None
from_party: Optional[str] = None
to_party: Optional[str] = None
status: Optional[str] = None
remark: Optional[str] = None
@@ -35,13 +37,14 @@ class DrugShipmentRead(BaseModel):
id: uuid.UUID
study_id: uuid.UUID
direction: str
center_id: Optional[uuid.UUID]
site_name: str
drug_desc: str
ship_date: Optional[date]
receive_date: Optional[date]
quantity: Optional[int]
batch_no: Optional[str]
carrier: Optional[str]
tracking_no: Optional[str]
from_party: Optional[str]
to_party: Optional[str]
status: str
remark: Optional[str]
created_by: Optional[uuid.UUID]