290 lines
9.4 KiB
Python
290 lines
9.4 KiB
Python
"""样本运费批次 API"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.database import get_db
|
|
from app.core.menu_guard import require_admin_or_super_admin
|
|
from app.core.response import error_response, success_response
|
|
from app.crud import sample_freight as freight_svc
|
|
from app.models.models import SysUser
|
|
|
|
router = APIRouter(prefix="/web/admin", tags=["样本运费批次"])
|
|
|
|
|
|
def _get_tenant_no(db: Session, user: dict) -> str:
|
|
user_id = user.get("user_id")
|
|
if not user_id:
|
|
raise PermissionError("用户身份信息缺失,无法确定租户")
|
|
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
|
|
if not sys_user or not sys_user.tenant_no:
|
|
raise PermissionError("用户租户信息缺失")
|
|
return sys_user.tenant_no
|
|
|
|
|
|
def _get_current_user_id(user: dict) -> str:
|
|
user_id = user.get("user_id")
|
|
if not user_id:
|
|
raise PermissionError("用户身份信息缺失")
|
|
return str(user_id)
|
|
|
|
|
|
class SampleFreightItemBody(BaseModel):
|
|
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
|
|
sample_source: str = Field(..., alias="sampleSource")
|
|
sample_id: str = Field(..., alias="sampleId")
|
|
protocol_id: Optional[str] = Field(None, alias="protocolId")
|
|
sample_code: Optional[str] = Field(None, alias="sampleCode")
|
|
|
|
|
|
class SampleFreightCreateBody(BaseModel):
|
|
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
|
|
transport_mode: str = Field(..., alias="transportMode")
|
|
freight_amount: Optional[float] = Field(None, alias="freightAmount")
|
|
waybill_no: Optional[str] = Field(None, alias="waybillNo")
|
|
items: Optional[List[SampleFreightItemBody]] = None
|
|
|
|
|
|
class SampleFreightUpdateBody(BaseModel):
|
|
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
|
|
transport_mode: Optional[str] = Field(None, alias="transportMode")
|
|
freight_amount: Optional[float] = Field(None, alias="freightAmount")
|
|
waybill_no: Optional[str] = Field(None, alias="waybillNo")
|
|
|
|
|
|
class SampleFreightItemsBody(BaseModel):
|
|
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
|
|
items: List[SampleFreightItemBody] = Field(default_factory=list)
|
|
|
|
|
|
@router.get("/sample-freights")
|
|
async def list_sample_freights(
|
|
page: int = Query(1, ge=1),
|
|
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
|
|
keyword: Optional[str] = None,
|
|
transportMode: Optional[str] = None,
|
|
sampleSource: Optional[str] = None,
|
|
createTimeFrom: Optional[str] = None,
|
|
createTimeTo: Optional[str] = None,
|
|
includeItems: bool = Query(False),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
items, total = freight_svc.list_freights(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
page=page,
|
|
page_size=pageSize,
|
|
keyword=keyword,
|
|
transport_mode=transportMode,
|
|
sample_source=sampleSource,
|
|
create_time_from=createTimeFrom,
|
|
create_time_to=createTimeTo,
|
|
include_items=includeItems,
|
|
)
|
|
return success_response(
|
|
{"list": items, "total": total, "page": page, "pageSize": pageSize}
|
|
)
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.get("/sample-freights/sample-options")
|
|
async def list_sample_freight_options(
|
|
page: int = Query(1, ge=1),
|
|
pageSize: int = Query(20, ge=1, le=100, alias="pageSize"),
|
|
keyword: Optional[str] = None,
|
|
sampleSource: Optional[str] = None,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
items, total = freight_svc.list_sample_options(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
page=page,
|
|
page_size=pageSize,
|
|
keyword=keyword,
|
|
sample_source=sampleSource,
|
|
)
|
|
return success_response(
|
|
{"list": items, "total": total, "page": page, "pageSize": pageSize}
|
|
)
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.get("/sample-freights/{freight_id}")
|
|
async def get_sample_freight(
|
|
freight_id: str,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = freight_svc.get_freight_detail(db, freight_id, tenant_no, user_info=user)
|
|
return success_response(data)
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
return error_response(404, str(e))
|
|
|
|
|
|
@router.post("/sample-freights")
|
|
async def create_sample_freight(
|
|
body: SampleFreightCreateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = _get_current_user_id(user)
|
|
items = [it.model_dump(by_alias=True) for it in (body.items or [])]
|
|
data = freight_svc.create_freight(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
user_id=user_id,
|
|
transport_mode_raw=body.transport_mode,
|
|
freight_amount=body.freight_amount,
|
|
waybill_no=body.waybill_no,
|
|
waybill_supplied=True,
|
|
amount_supplied=True,
|
|
items=items,
|
|
)
|
|
return success_response(data, message="创建成功")
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.put("/sample-freights/{freight_id}")
|
|
async def update_sample_freight(
|
|
freight_id: str,
|
|
body: SampleFreightUpdateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = _get_current_user_id(user)
|
|
data = freight_svc.update_freight(
|
|
db,
|
|
freight_id,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
user_id=user_id,
|
|
transport_mode_raw=body.transport_mode,
|
|
freight_amount=body.freight_amount,
|
|
waybill_no=body.waybill_no,
|
|
waybill_supplied="waybill_no" in body.model_fields_set,
|
|
amount_supplied="freight_amount" in body.model_fields_set,
|
|
)
|
|
return success_response(data, message="更新成功")
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
msg = str(e)
|
|
code = 404 if "不存在" in msg else 400
|
|
return error_response(code, msg)
|
|
|
|
|
|
@router.post("/sample-freights/{freight_id}/link")
|
|
async def link_sample_freight(
|
|
freight_id: str,
|
|
body: SampleFreightItemsBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = _get_current_user_id(user)
|
|
items = [it.model_dump(by_alias=True) for it in (body.items or [])]
|
|
data = freight_svc.link_samples(
|
|
db,
|
|
freight_id,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
user_id=user_id,
|
|
items=items,
|
|
)
|
|
return success_response(data, message="关联成功")
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
msg = str(e)
|
|
code = 404 if "不存在" in msg else 400
|
|
return error_response(code, msg)
|
|
|
|
|
|
@router.post("/sample-freights/{freight_id}/unlink")
|
|
async def unlink_sample_freight(
|
|
freight_id: str,
|
|
body: SampleFreightItemsBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = _get_current_user_id(user)
|
|
items = [it.model_dump(by_alias=True) for it in (body.items or [])]
|
|
data = freight_svc.unlink_samples(
|
|
db,
|
|
freight_id,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
user_id=user_id,
|
|
items=items,
|
|
)
|
|
return success_response(data, message="已取消关联")
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
msg = str(e)
|
|
code = 404 if "不存在" in msg else 400
|
|
return error_response(code, msg)
|
|
|
|
|
|
@router.delete("/sample-freights/{freight_id}")
|
|
async def delete_sample_freight(
|
|
freight_id: str,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = _get_current_user_id(user)
|
|
data = freight_svc.delete_freight(
|
|
db,
|
|
freight_id,
|
|
tenant_no=tenant_no,
|
|
user_info=user,
|
|
user_id=user_id,
|
|
)
|
|
return success_response(data, message="删除成功")
|
|
except PermissionError as e:
|
|
return error_response(403, str(e))
|
|
except ValueError as e:
|
|
msg = str(e)
|
|
code = 404 if "不存在" in msg else 400
|
|
return error_response(code, msg)
|