Files
ctms/backend/app/crud/startup.py
T
Cheng Zhou 6a2e43f829 抽屉化物资与启动授权流程
1、将药物发货新建和编辑从独立页面迁移到抽屉,详情页支持权限控制和停用中心只读状态。

2、补充药物发货状态字段校验,统一 PENDING、IN_TRANSIT、SIGNED、EXCEPTION 状态及演示数据。

3、为物资设备增加详情页和编辑抽屉,复用通用附件上传并按项目权限控制操作入口。

4、将启动会和培训授权编辑迁移到抽屉,详情页按中心过滤培训记录并移除旧独立编辑路由。
2026-06-04 11:08:43 +08:00

279 lines
8.2 KiB
Python

import uuid
from typing import Sequence
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.startup_feasibility import StartupFeasibility
from app.models.startup_ethics import StartupEthics
from app.models.kickoff_meeting import KickoffMeeting
from app.models.training_authorization import TrainingAuthorization
from app.schemas.startup import (
KickoffMeetingCreate,
KickoffMeetingUpdate,
StartupEthicsCreate,
StartupEthicsUpdate,
StartupFeasibilityCreate,
StartupFeasibilityUpdate,
TrainingAuthorizationCreate,
TrainingAuthorizationUpdate,
)
async def create_feasibility(
db: AsyncSession,
study_id: uuid.UUID,
record_in: StartupFeasibilityCreate,
created_by: uuid.UUID | None,
) -> StartupFeasibility:
record = StartupFeasibility(
study_id=study_id,
site_id=record_in.site_id,
submit_date=record_in.submit_date,
accept_date=record_in.accept_date,
approved_date=record_in.approved_date,
project_no=record_in.project_no,
created_by=created_by,
)
db.add(record)
await db.commit()
await db.refresh(record)
return record
async def get_feasibility(db: AsyncSession, record_id: uuid.UUID) -> StartupFeasibility | None:
result = await db.execute(select(StartupFeasibility).where(StartupFeasibility.id == record_id))
return result.scalar_one_or_none()
async def list_feasibilities(
db: AsyncSession,
study_id: uuid.UUID,
skip: int = 0,
limit: int = 100,
site_ids: set[uuid.UUID] | None = None,
) -> Sequence[StartupFeasibility]:
if site_ids is not None and not site_ids:
return []
stmt = (
select(StartupFeasibility)
.where(StartupFeasibility.study_id == study_id)
.order_by(StartupFeasibility.created_at.desc())
.offset(skip)
.limit(limit)
)
if site_ids is not None:
stmt = stmt.where(StartupFeasibility.site_id.in_(site_ids))
result = await db.execute(stmt)
return result.scalars().all()
async def update_feasibility(
db: AsyncSession, record: StartupFeasibility, record_in: StartupFeasibilityUpdate
) -> StartupFeasibility:
update_data = record_in.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(record, key, value)
await db.commit()
await db.refresh(record)
return record
async def delete_feasibility(db: AsyncSession, record: StartupFeasibility) -> None:
await db.delete(record)
await db.commit()
async def create_ethics(
db: AsyncSession,
study_id: uuid.UUID,
record_in: StartupEthicsCreate,
created_by: uuid.UUID | None,
) -> StartupEthics:
record = StartupEthics(
study_id=study_id,
site_id=record_in.site_id,
submit_date=record_in.submit_date,
accept_date=record_in.accept_date,
meeting_date=record_in.meeting_date,
approved_date=record_in.approved_date,
approval_no=record_in.approval_no,
created_by=created_by,
)
db.add(record)
await db.commit()
await db.refresh(record)
return record
async def get_ethics(db: AsyncSession, record_id: uuid.UUID) -> StartupEthics | None:
result = await db.execute(select(StartupEthics).where(StartupEthics.id == record_id))
return result.scalar_one_or_none()
async def list_ethics(
db: AsyncSession,
study_id: uuid.UUID,
skip: int = 0,
limit: int = 100,
site_ids: set[uuid.UUID] | None = None,
) -> Sequence[StartupEthics]:
if site_ids is not None and not site_ids:
return []
stmt = (
select(StartupEthics)
.where(StartupEthics.study_id == study_id)
.order_by(StartupEthics.created_at.desc())
.offset(skip)
.limit(limit)
)
if site_ids is not None:
stmt = stmt.where(StartupEthics.site_id.in_(site_ids))
result = await db.execute(stmt)
return result.scalars().all()
async def update_ethics(
db: AsyncSession, record: StartupEthics, record_in: StartupEthicsUpdate
) -> StartupEthics:
update_data = record_in.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(record, key, value)
await db.commit()
await db.refresh(record)
return record
async def delete_ethics(db: AsyncSession, record: StartupEthics) -> None:
await db.delete(record)
await db.commit()
async def create_kickoff(
db: AsyncSession,
study_id: uuid.UUID,
meeting_in: KickoffMeetingCreate,
created_by: uuid.UUID | None,
) -> KickoffMeeting:
meeting = KickoffMeeting(
study_id=study_id,
site_id=meeting_in.site_id,
kickoff_date=meeting_in.kickoff_date,
attendees=meeting_in.attendees,
created_by=created_by,
)
db.add(meeting)
await db.commit()
await db.refresh(meeting)
return meeting
async def get_kickoff(db: AsyncSession, meeting_id: uuid.UUID) -> KickoffMeeting | None:
result = await db.execute(select(KickoffMeeting).where(KickoffMeeting.id == meeting_id))
return result.scalar_one_or_none()
async def list_kickoffs(
db: AsyncSession,
study_id: uuid.UUID,
skip: int = 0,
limit: int = 100,
site_ids: set[uuid.UUID] | None = None,
) -> Sequence[KickoffMeeting]:
if site_ids is not None and not site_ids:
return []
stmt = (
select(KickoffMeeting)
.where(KickoffMeeting.study_id == study_id)
.order_by(KickoffMeeting.created_at.desc())
.offset(skip)
.limit(limit)
)
if site_ids is not None:
stmt = stmt.where(KickoffMeeting.site_id.in_(site_ids))
result = await db.execute(stmt)
return result.scalars().all()
async def update_kickoff(
db: AsyncSession, meeting: KickoffMeeting, meeting_in: KickoffMeetingUpdate
) -> KickoffMeeting:
update_data = meeting_in.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(meeting, key, value)
await db.commit()
await db.refresh(meeting)
return meeting
async def create_training_authorization(
db: AsyncSession,
study_id: uuid.UUID,
record_in: TrainingAuthorizationCreate,
created_by: uuid.UUID | None,
) -> TrainingAuthorization:
record = TrainingAuthorization(
study_id=study_id,
name=record_in.name,
role=record_in.role,
site_name=record_in.site_name,
trained=record_in.trained,
authorized=record_in.authorized,
trained_date=record_in.trained_date,
authorized_date=record_in.authorized_date,
remark=record_in.remark,
created_by=created_by,
)
db.add(record)
await db.commit()
await db.refresh(record)
return record
async def get_training_authorization(
db: AsyncSession, record_id: uuid.UUID
) -> TrainingAuthorization | None:
result = await db.execute(select(TrainingAuthorization).where(TrainingAuthorization.id == record_id))
return result.scalar_one_or_none()
async def list_training_authorizations(
db: AsyncSession,
study_id: uuid.UUID,
skip: int = 0,
limit: int = 200,
site_names: set[str] | None = None,
site_name: str | None = None,
) -> Sequence[TrainingAuthorization]:
if site_names is not None and not site_names:
return []
stmt = (
select(TrainingAuthorization)
.where(TrainingAuthorization.study_id == study_id)
.order_by(TrainingAuthorization.created_at.desc())
.offset(skip)
.limit(limit)
)
if site_names is not None:
stmt = stmt.where(TrainingAuthorization.site_name.in_(site_names))
if site_name:
stmt = stmt.where(TrainingAuthorization.site_name == site_name)
result = await db.execute(stmt)
return result.scalars().all()
async def update_training_authorization(
db: AsyncSession, record: TrainingAuthorization, record_in: TrainingAuthorizationUpdate
) -> TrainingAuthorization:
update_data = record_in.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(record, key, value)
await db.commit()
await db.refresh(record)
return record
async def delete_training_authorization(db: AsyncSession, record: TrainingAuthorization) -> None:
await db.delete(record)
await db.commit()