6a2e43f829
1、将药物发货新建和编辑从独立页面迁移到抽屉,详情页支持权限控制和停用中心只读状态。 2、补充药物发货状态字段校验,统一 PENDING、IN_TRANSIT、SIGNED、EXCEPTION 状态及演示数据。 3、为物资设备增加详情页和编辑抽屉,复用通用附件上传并按项目权限控制操作入口。 4、将启动会和培训授权编辑迁移到抽屉,详情页按中心过滤培训记录并移除旧独立编辑路由。
279 lines
8.2 KiB
Python
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()
|