presign_order.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. """预签约订单 / 意向金转账 / 转正式 API"""
  2. from __future__ import annotations
  3. from typing import Any, Dict, List, Optional
  4. from fastapi import APIRouter, Depends, Query
  5. from pydantic import BaseModel, ConfigDict, Field
  6. from sqlalchemy.orm import Session
  7. from app.core.database import get_db
  8. from app.core.menu_guard import require_admin_or_super_admin, require_strict_menu_code
  9. from app.core.response import error_response, success_response
  10. from app.crud import presign_order as po_svc
  11. from app.models.models import SysUser
  12. router = APIRouter(prefix="/web/admin", tags=["细胞存储-预签约订单"])
  13. PAYMENT_CONFIRM_MENU = "biz:cellStoragePaymentConfirm:list"
  14. def _get_tenant_no(db: Session, user: dict) -> str:
  15. user_id = user.get("user_id")
  16. if not user_id:
  17. raise PermissionError("用户身份信息缺失,无法确定租户")
  18. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  19. if not sys_user or not sys_user.tenant_no:
  20. raise PermissionError("用户租户信息缺失")
  21. return sys_user.tenant_no
  22. def _get_current_user_id(user: dict) -> str:
  23. user_id = user.get("user_id")
  24. if not user_id:
  25. raise PermissionError("用户身份信息缺失")
  26. return str(user_id)
  27. class PresignOrderBody(BaseModel):
  28. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  29. order_date: Optional[str] = Field(None, alias="orderDate")
  30. protocol_no: Optional[str] = Field(None, alias="protocolNo")
  31. mother_name: Optional[str] = Field(None, alias="motherName")
  32. expected_delivery_date: Optional[str] = Field(None, alias="expectedDeliveryDate")
  33. region_id: Optional[str] = Field(None, alias="regionId")
  34. hospital_id: Optional[str] = Field(None, alias="hospitalId")
  35. sample_collect_time: Optional[str] = Field(None, alias="sampleCollectTime")
  36. pay_mode: Optional[str] = Field(None, alias="payMode")
  37. contract_amount: Optional[float] = Field(None, alias="contractAmount")
  38. collector_user_id: Optional[str] = Field(None, alias="collectorUserId")
  39. sales_user_id: Optional[str] = Field(None, alias="salesUserId")
  40. region_manager_user_id: Optional[str] = Field(None, alias="regionManagerUserId")
  41. order_status: Optional[str] = Field(None, alias="orderStatus")
  42. remark: Optional[str] = None
  43. sample_type_ids: Optional[List[str]] = Field(None, alias="sampleTypeIds")
  44. transfers: Optional[List[Dict[str, Any]]] = None
  45. class PresignTransferBody(BaseModel):
  46. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  47. transfer_amount: Optional[float] = Field(None, alias="transferAmount")
  48. transfer_time: Optional[str] = Field(None, alias="transferTime")
  49. transfer_type: Optional[str] = Field(None, alias="transferType")
  50. transfer_attachments: Optional[str] = Field(None, alias="transferAttachments")
  51. remark: Optional[str] = None
  52. class FinanceConfirmBody(BaseModel):
  53. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  54. finance_confirm_attachments: Optional[str] = Field(
  55. None, alias="financeConfirmAttachments"
  56. )
  57. finance_remark: Optional[str] = Field(None, alias="financeRemark")
  58. @router.get("/presign-orders")
  59. async def list_presign_orders(
  60. page: int = Query(1, ge=1),
  61. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  62. keyword: Optional[str] = None,
  63. orderStatus: Optional[str] = Query(None, alias="orderStatus"),
  64. user: dict = Depends(require_admin_or_super_admin),
  65. db: Session = Depends(get_db),
  66. ):
  67. try:
  68. tenant_no = _get_tenant_no(db, user)
  69. items, total = po_svc.list_presign_orders(
  70. db,
  71. tenant_no=tenant_no,
  72. page=page,
  73. page_size=pageSize,
  74. keyword=keyword,
  75. order_status=orderStatus,
  76. user_info=user,
  77. )
  78. return success_response(
  79. {"list": items, "total": total, "page": page, "pageSize": pageSize}
  80. )
  81. except PermissionError as e:
  82. return error_response(403, str(e))
  83. @router.get("/presign-orders/{order_id}")
  84. async def get_presign_order(
  85. order_id: str,
  86. user: dict = Depends(require_admin_or_super_admin),
  87. db: Session = Depends(get_db),
  88. ):
  89. try:
  90. tenant_no = _get_tenant_no(db, user)
  91. data = po_svc.get_presign_order(db, order_id=order_id, tenant_no=tenant_no)
  92. if not data:
  93. return error_response(404, "预签约订单不存在")
  94. return success_response(data)
  95. except PermissionError as e:
  96. return error_response(403, str(e))
  97. @router.post("/presign-orders")
  98. async def create_presign_order(
  99. body: PresignOrderBody,
  100. user: dict = Depends(require_admin_or_super_admin),
  101. db: Session = Depends(get_db),
  102. ):
  103. try:
  104. tenant_no = _get_tenant_no(db, user)
  105. user_id = _get_current_user_id(user)
  106. dumped = body.model_dump(by_alias=False)
  107. obj = po_svc.create_presign_order(
  108. db,
  109. tenant_no=tenant_no,
  110. user_id=user_id,
  111. fields=dumped,
  112. sample_type_ids=body.sample_type_ids,
  113. transfers=body.transfers,
  114. )
  115. return success_response(
  116. po_svc.order_to_dict(db, obj, tenant_no, with_children=True),
  117. message="创建成功",
  118. )
  119. except PermissionError as e:
  120. return error_response(403, str(e))
  121. except ValueError as e:
  122. return error_response(400, str(e))
  123. @router.put("/presign-orders/{order_id}")
  124. async def update_presign_order(
  125. order_id: str,
  126. body: PresignOrderBody,
  127. user: dict = Depends(require_admin_or_super_admin),
  128. db: Session = Depends(get_db),
  129. ):
  130. try:
  131. tenant_no = _get_tenant_no(db, user)
  132. user_id = _get_current_user_id(user)
  133. dumped = body.model_dump(by_alias=False, exclude_unset=True)
  134. sample_type_ids = dumped.pop("sample_type_ids", None)
  135. dumped.pop("transfers", None)
  136. obj = po_svc.update_presign_order(
  137. db,
  138. order_id=order_id,
  139. tenant_no=tenant_no,
  140. user_id=user_id,
  141. fields=dumped,
  142. sample_type_ids=sample_type_ids,
  143. )
  144. return success_response(
  145. po_svc.order_to_dict(db, obj, tenant_no, with_children=True),
  146. message="保存成功",
  147. )
  148. except PermissionError as e:
  149. return error_response(403, str(e))
  150. except ValueError as e:
  151. return error_response(400, str(e))
  152. @router.delete("/presign-orders/{order_id}")
  153. async def delete_presign_order(
  154. order_id: str,
  155. user: dict = Depends(require_admin_or_super_admin),
  156. db: Session = Depends(get_db),
  157. ):
  158. try:
  159. tenant_no = _get_tenant_no(db, user)
  160. user_id = _get_current_user_id(user)
  161. po_svc.soft_delete_presign_order(
  162. db, order_id=order_id, tenant_no=tenant_no, user_id=user_id
  163. )
  164. return success_response(None, message="删除成功")
  165. except PermissionError as e:
  166. return error_response(403, str(e))
  167. except ValueError as e:
  168. return error_response(400, str(e))
  169. @router.post("/presign-orders/{order_id}/convert")
  170. async def convert_presign_order(
  171. order_id: str,
  172. user: dict = Depends(require_admin_or_super_admin),
  173. db: Session = Depends(get_db),
  174. ):
  175. try:
  176. tenant_no = _get_tenant_no(db, user)
  177. user_id = _get_current_user_id(user)
  178. data = po_svc.convert_to_protocol(
  179. db, order_id=order_id, tenant_no=tenant_no, user_id=user_id
  180. )
  181. return success_response(data, message="已转正式协议")
  182. except PermissionError as e:
  183. return error_response(403, str(e))
  184. except ValueError as e:
  185. return error_response(400, str(e))
  186. @router.post("/presign-orders/{order_id}/transfers")
  187. async def create_presign_transfer(
  188. order_id: str,
  189. body: PresignTransferBody,
  190. user: dict = Depends(require_admin_or_super_admin),
  191. db: Session = Depends(get_db),
  192. ):
  193. try:
  194. tenant_no = _get_tenant_no(db, user)
  195. user_id = _get_current_user_id(user)
  196. obj = po_svc.add_transfer(
  197. db,
  198. presign_order_id=order_id,
  199. tenant_no=tenant_no,
  200. user_id=user_id,
  201. fields=body.model_dump(by_alias=False),
  202. )
  203. return success_response(
  204. po_svc._transfer_to_dict(db, obj, tenant_no), message="添加成功"
  205. )
  206. except PermissionError as e:
  207. return error_response(403, str(e))
  208. except ValueError as e:
  209. return error_response(400, str(e))
  210. @router.put("/presign-transfers/{transfer_id}")
  211. async def update_presign_transfer(
  212. transfer_id: str,
  213. body: PresignTransferBody,
  214. user: dict = Depends(require_admin_or_super_admin),
  215. db: Session = Depends(get_db),
  216. ):
  217. try:
  218. tenant_no = _get_tenant_no(db, user)
  219. user_id = _get_current_user_id(user)
  220. obj = po_svc.update_transfer_draft(
  221. db,
  222. transfer_id=transfer_id,
  223. tenant_no=tenant_no,
  224. user_id=user_id,
  225. fields=body.model_dump(by_alias=False, exclude_unset=True),
  226. )
  227. return success_response(
  228. po_svc._transfer_to_dict(db, obj, tenant_no), message="保存成功"
  229. )
  230. except PermissionError as e:
  231. return error_response(403, str(e))
  232. except ValueError as e:
  233. return error_response(400, str(e))
  234. @router.post("/presign-transfers/{transfer_id}/submit-receipt-finance")
  235. async def submit_presign_transfer_finance(
  236. transfer_id: str,
  237. user: dict = Depends(require_admin_or_super_admin),
  238. db: Session = Depends(get_db),
  239. ):
  240. try:
  241. tenant_no = _get_tenant_no(db, user)
  242. user_id = _get_current_user_id(user)
  243. obj = po_svc.submit_receipt_finance(
  244. db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
  245. )
  246. return success_response(
  247. po_svc._transfer_to_dict(db, obj, tenant_no), message="已提交财务确认"
  248. )
  249. except PermissionError as e:
  250. return error_response(403, str(e))
  251. except ValueError as e:
  252. return error_response(400, str(e))
  253. @router.post("/presign-transfers/{transfer_id}/withdraw")
  254. async def withdraw_presign_transfer(
  255. transfer_id: str,
  256. user: dict = Depends(require_admin_or_super_admin),
  257. db: Session = Depends(get_db),
  258. ):
  259. try:
  260. tenant_no = _get_tenant_no(db, user)
  261. user_id = _get_current_user_id(user)
  262. obj = po_svc.withdraw_receipt(
  263. db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
  264. )
  265. return success_response(
  266. po_svc._transfer_to_dict(db, obj, tenant_no), message="已撤回"
  267. )
  268. except PermissionError as e:
  269. return error_response(403, str(e))
  270. except ValueError as e:
  271. return error_response(400, str(e))
  272. @router.get("/presign-transfers/receipt-confirm")
  273. async def list_presign_receipt_confirm(
  274. page: int = Query(1, ge=1),
  275. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  276. keyword: Optional[str] = None,
  277. user: dict = Depends(require_admin_or_super_admin),
  278. db: Session = Depends(get_db),
  279. ):
  280. try:
  281. tenant_no = _get_tenant_no(db, user)
  282. items, total = po_svc.list_presign_transfers_for_finance(
  283. db,
  284. pay_status="jfqrz",
  285. tenant_no=tenant_no,
  286. keyword=keyword,
  287. page=page,
  288. page_size=pageSize,
  289. user_info=user,
  290. )
  291. return success_response(
  292. {"list": items, "total": total, "page": page, "pageSize": pageSize}
  293. )
  294. except PermissionError as e:
  295. return error_response(403, str(e))
  296. @router.get("/presign-transfers/receipt-confirmed")
  297. async def list_presign_receipt_confirmed(
  298. page: int = Query(1, ge=1),
  299. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  300. keyword: Optional[str] = None,
  301. user: dict = Depends(require_admin_or_super_admin),
  302. db: Session = Depends(get_db),
  303. ):
  304. try:
  305. tenant_no = _get_tenant_no(db, user)
  306. items, total = po_svc.list_presign_transfers_for_finance(
  307. db,
  308. pay_status="yjf",
  309. tenant_no=tenant_no,
  310. keyword=keyword,
  311. page=page,
  312. page_size=pageSize,
  313. user_info=user,
  314. )
  315. return success_response(
  316. {"list": items, "total": total, "page": page, "pageSize": pageSize}
  317. )
  318. except PermissionError as e:
  319. return error_response(403, str(e))
  320. @router.post("/presign-transfers/{transfer_id}/receipt-confirm")
  321. async def confirm_presign_transfer(
  322. transfer_id: str,
  323. body: Optional[FinanceConfirmBody] = None,
  324. user: dict = Depends(require_strict_menu_code(PAYMENT_CONFIRM_MENU)),
  325. db: Session = Depends(get_db),
  326. ):
  327. try:
  328. tenant_no = _get_tenant_no(db, user)
  329. user_id = _get_current_user_id(user)
  330. obj = po_svc.confirm_receipt(
  331. db,
  332. transfer_id=transfer_id,
  333. tenant_no=tenant_no,
  334. user_id=user_id,
  335. finance_confirm_attachments=body.finance_confirm_attachments if body else None,
  336. finance_remark=body.finance_remark if body else None,
  337. )
  338. return success_response(
  339. po_svc._transfer_to_dict(db, obj, tenant_no), message="确认收款成功"
  340. )
  341. except PermissionError as e:
  342. return error_response(403, str(e))
  343. except ValueError as e:
  344. return error_response(400, str(e))
  345. @router.post("/presign-transfers/{transfer_id}/receipt-reject")
  346. async def reject_presign_transfer(
  347. transfer_id: str,
  348. user: dict = Depends(require_strict_menu_code(PAYMENT_CONFIRM_MENU)),
  349. db: Session = Depends(get_db),
  350. ):
  351. try:
  352. tenant_no = _get_tenant_no(db, user)
  353. user_id = _get_current_user_id(user)
  354. obj = po_svc.reject_receipt(
  355. db, transfer_id=transfer_id, tenant_no=tenant_no, user_id=user_id
  356. )
  357. return success_response(
  358. po_svc._transfer_to_dict(db, obj, tenant_no), message="已退回"
  359. )
  360. except PermissionError as e:
  361. return error_response(403, str(e))
  362. except ValueError as e:
  363. return error_response(400, str(e))