| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- """预签约订单 / 意向金转账 / 转正式 API"""
- from __future__ import annotations
- from datetime import datetime
- from typing import Any, Dict, List, Optional
- from fastapi import APIRouter, Depends, Query
- from pydantic import BaseModel, ConfigDict, Field, field_validator
- from sqlalchemy.orm import Session
- from app.core.database import get_db
- from app.core.data_scope import get_user_dept_id
- from app.core.menu_guard import require_admin_or_super_admin, require_strict_menu_code
- from app.core.response import error_response, success_response
- from app.crud import presign_order as po_svc
- from app.models.models import SysUser
- router = APIRouter(prefix="/web/admin", tags=["细胞存储-预签约订单"])
- PAYMENT_CONFIRM_MENU = "biz:cellStoragePaymentConfirm:list"
- 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 PresignOrderBody(BaseModel):
- model_config = ConfigDict(extra="ignore", populate_by_name=True)
- order_date: Optional[str] = Field(None, alias="orderDate")
- protocol_no: Optional[str] = Field(None, alias="protocolNo")
- mother_name: Optional[str] = Field(None, alias="motherName")
- expected_delivery_date: Optional[str] = Field(None, alias="expectedDeliveryDate")
- region_id: Optional[str] = Field(None, alias="regionId")
- hospital_id: Optional[str] = Field(None, alias="hospitalId")
- sample_collect_time: Optional[str] = Field(None, alias="sampleCollectTime")
- pay_mode: Optional[str] = Field(None, alias="payMode")
- contract_amount: Optional[float] = Field(None, alias="contractAmount")
- collector_user_id: Optional[str] = Field(None, alias="collectorUserId")
- sales_user_id: Optional[str] = Field(None, alias="salesUserId")
- region_manager_user_id: Optional[str] = Field(None, alias="regionManagerUserId")
- order_status: Optional[str] = Field(None, alias="orderStatus")
- remark: Optional[str] = None
- sample_type_ids: Optional[List[str]] = Field(None, alias="sampleTypeIds")
- transfers: Optional[List[Dict[str, Any]]] = None
- @field_validator("order_date", "expected_delivery_date")
- @classmethod
- def validate_ymd(cls, value: Optional[str]) -> Optional[str]:
- if value in (None, ""):
- return value
- text = value.strip()
- if len(text) != 8 or not text.isdigit():
- raise ValueError("日期必须使用 YYYYMMDD 格式")
- try:
- datetime.strptime(text, "%Y%m%d")
- except ValueError as exc:
- raise ValueError("日期必须是有效的 YYYYMMDD") from exc
- return text
- class PresignTransferBody(BaseModel):
- model_config = ConfigDict(extra="ignore", populate_by_name=True)
- transfer_amount: Optional[float] = Field(None, alias="transferAmount")
- transfer_time: Optional[str] = Field(None, alias="transferTime")
- transfer_type: Optional[str] = Field(None, alias="transferType")
- transfer_attachments: Optional[str] = Field(None, alias="transferAttachments")
- remark: Optional[str] = None
- class FinanceConfirmBody(BaseModel):
- model_config = ConfigDict(extra="ignore", populate_by_name=True)
- finance_confirm_attachments: Optional[str] = Field(
- None, alias="financeConfirmAttachments"
- )
- finance_remark: Optional[str] = Field(None, alias="financeRemark")
- @router.get("/presign-orders")
- async def list_presign_orders(
- page: int = Query(1, ge=1),
- pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
- keyword: Optional[str] = None,
- orderStatus: Optional[str] = Query(None, alias="orderStatus"),
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- items, total = po_svc.list_presign_orders(
- db,
- tenant_no=tenant_no,
- page=page,
- page_size=pageSize,
- keyword=keyword,
- order_status=orderStatus,
- user_info=user,
- )
- return success_response(
- {"list": items, "total": total, "page": page, "pageSize": pageSize}
- )
- except PermissionError as e:
- return error_response(403, str(e))
- @router.get("/presign-orders/{order_id}")
- async def get_presign_order(
- order_id: str,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(db, order_id, tenant_no, user)
- data = po_svc.get_presign_order(db, order_id=order_id, tenant_no=tenant_no)
- if not data:
- return error_response(404, "预签约订单不存在")
- return success_response(data)
- except PermissionError as e:
- return error_response(403, str(e))
- @router.post("/presign-orders")
- async def create_presign_order(
- body: PresignOrderBody,
- 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)
- dumped = body.model_dump(by_alias=False)
- obj = po_svc.create_presign_order(
- db,
- create_dept_id=get_user_dept_id(db, user_id) or "",
- tenant_no=tenant_no,
- user_id=user_id,
- fields=dumped,
- sample_type_ids=body.sample_type_ids,
- transfers=body.transfers,
- )
- return success_response(
- po_svc.order_to_dict(db, obj, tenant_no, with_children=True),
- message="创建成功",
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.put("/presign-orders/{order_id}")
- async def update_presign_order(
- order_id: str,
- body: PresignOrderBody,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(db, order_id, tenant_no, user)
- user_id = _get_current_user_id(user)
- dumped = body.model_dump(by_alias=False, exclude_unset=True)
- sample_type_ids = dumped.pop("sample_type_ids", None)
- dumped.pop("transfers", None)
- obj = po_svc.update_presign_order(
- db,
- create_dept_id=get_user_dept_id(db, user_id) or "",
- order_id=order_id,
- tenant_no=tenant_no,
- user_id=user_id,
- fields=dumped,
- sample_type_ids=sample_type_ids,
- )
- return success_response(
- po_svc.order_to_dict(db, obj, tenant_no, with_children=True),
- message="保存成功",
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.delete("/presign-orders/{order_id}")
- async def delete_presign_order(
- order_id: str,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(db, order_id, tenant_no, user)
- user_id = _get_current_user_id(user)
- po_svc.soft_delete_presign_order(
- db, order_id=order_id, tenant_no=tenant_no, user_id=user_id
- )
- return success_response(None, message="删除成功")
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.post("/presign-orders/{order_id}/convert")
- async def convert_presign_order(
- order_id: str,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(db, order_id, tenant_no, user)
- user_id = _get_current_user_id(user)
- data = po_svc.convert_to_protocol(
- db, order_id=order_id, tenant_no=tenant_no, user_id=user_id,
- create_dept_id=get_user_dept_id(db, user_id) or "",
- )
- 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.post("/presign-orders/{order_id}/transfers")
- async def create_presign_transfer(
- order_id: str,
- body: PresignTransferBody,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(db, order_id, tenant_no, user)
- user_id = _get_current_user_id(user)
- obj = po_svc.add_transfer(
- db,
- create_dept_id=get_user_dept_id(db, user_id) or "",
- presign_order_id=order_id,
- tenant_no=tenant_no,
- user_id=user_id,
- fields=body.model_dump(by_alias=False),
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="添加成功"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.put("/presign-transfers/{transfer_id}")
- async def update_presign_transfer(
- transfer_id: str,
- body: PresignTransferBody,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(
- db, transfer_id, tenant_no, user, transfer=True
- )
- user_id = _get_current_user_id(user)
- obj = po_svc.update_transfer_draft(
- db,
- transfer_id=transfer_id,
- tenant_no=tenant_no,
- user_id=user_id,
- fields=body.model_dump(by_alias=False, exclude_unset=True),
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="保存成功"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.post("/presign-transfers/{transfer_id}/submit-receipt-finance")
- async def submit_presign_transfer_finance(
- transfer_id: str,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(
- db, transfer_id, tenant_no, user, transfer=True
- )
- user_id = _get_current_user_id(user)
- obj = po_svc.submit_receipt_finance(
- db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="已提交财务确认"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.post("/presign-transfers/{transfer_id}/withdraw")
- async def withdraw_presign_transfer(
- transfer_id: str,
- user: dict = Depends(require_admin_or_super_admin),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(
- db, transfer_id, tenant_no, user, transfer=True
- )
- user_id = _get_current_user_id(user)
- obj = po_svc.withdraw_receipt(
- db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="已撤回"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.get("/presign-transfers/receipt-confirm")
- async def list_presign_receipt_confirm(
- page: int = Query(1, ge=1),
- pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
- keyword: 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 = po_svc.list_presign_transfers_for_finance(
- db,
- pay_status="jfqrz",
- tenant_no=tenant_no,
- keyword=keyword,
- page=page,
- page_size=pageSize,
- user_info=user,
- )
- return success_response(
- {"list": items, "total": total, "page": page, "pageSize": pageSize}
- )
- except PermissionError as e:
- return error_response(403, str(e))
- @router.get("/presign-transfers/receipt-confirmed")
- async def list_presign_receipt_confirmed(
- page: int = Query(1, ge=1),
- pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
- keyword: 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 = po_svc.list_presign_transfers_for_finance(
- db,
- pay_status="yjf",
- tenant_no=tenant_no,
- keyword=keyword,
- page=page,
- page_size=pageSize,
- user_info=user,
- )
- return success_response(
- {"list": items, "total": total, "page": page, "pageSize": pageSize}
- )
- except PermissionError as e:
- return error_response(403, str(e))
- @router.post("/presign-transfers/{transfer_id}/receipt-confirm")
- async def confirm_presign_transfer(
- transfer_id: str,
- body: Optional[FinanceConfirmBody] = None,
- user: dict = Depends(require_strict_menu_code(PAYMENT_CONFIRM_MENU)),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(
- db, transfer_id, tenant_no, user, transfer=True
- )
- user_id = _get_current_user_id(user)
- obj = po_svc.confirm_receipt(
- db,
- transfer_id=transfer_id,
- tenant_no=tenant_no,
- user_id=user_id,
- finance_confirm_attachments=body.finance_confirm_attachments if body else None,
- finance_remark=body.finance_remark if body else None,
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="确认收款成功"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
- @router.post("/presign-transfers/{transfer_id}/receipt-reject")
- async def reject_presign_transfer(
- transfer_id: str,
- user: dict = Depends(require_strict_menu_code(PAYMENT_CONFIRM_MENU)),
- db: Session = Depends(get_db),
- ):
- try:
- tenant_no = _get_tenant_no(db, user)
- po_svc.assert_presign_data_access(
- db, transfer_id, tenant_no, user, transfer=True
- )
- user_id = _get_current_user_id(user)
- obj = po_svc.reject_receipt(
- db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
- )
- return success_response(
- po_svc._transfer_to_dict(db, obj, tenant_no), message="已退回"
- )
- except PermissionError as e:
- return error_response(403, str(e))
- except ValueError as e:
- return error_response(400, str(e))
|