sample_cert_insurance.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. """样本级储存证 / 保险办理 API"""
  2. from typing import Optional
  3. from fastapi import APIRouter, Depends
  4. from pydantic import BaseModel, ConfigDict, Field
  5. from sqlalchemy.orm import Session
  6. from app.core.database import get_db
  7. from app.core.menu_guard import require_any_menu_code, require_strict_menu_code
  8. from app.core.response import error_response, success_response
  9. from app.core.utils import parse_datetime
  10. from app.crud import sample_insurance as insurance_crud
  11. from app.crud import sample_storage_cert as cert_crud
  12. from app.models.models import BizProtocolSample, SysUser
  13. router = APIRouter(prefix="/web/admin", tags=["样本储存证保险"])
  14. _MENU = require_any_menu_code("cell-storage:sample-info:list")
  15. _WRITE_MENU = require_strict_menu_code("cell-storage:storage-cert:list")
  16. def _get_tenant_no(db: Session, user: dict) -> str:
  17. user_id = user.get("user_id")
  18. if not user_id:
  19. raise PermissionError("用户身份信息缺失,无法确定租户")
  20. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  21. if not sys_user or not sys_user.tenant_no:
  22. raise PermissionError("用户租户信息缺失")
  23. return sys_user.tenant_no
  24. def _get_current_user_id(user: dict) -> str:
  25. user_id = user.get("user_id")
  26. if not user_id:
  27. raise PermissionError("用户身份信息缺失")
  28. return str(user_id)
  29. def _resolve_protocol_id(db: Session, tenant_no: str, sample_code: str) -> Optional[str]:
  30. row = (
  31. db.query(BizProtocolSample)
  32. .filter(
  33. BizProtocolSample.tenant_no == tenant_no,
  34. BizProtocolSample.sample_code == sample_code,
  35. BizProtocolSample.del_flag == 0,
  36. )
  37. .first()
  38. )
  39. return (row.collection_protocol_id or "").strip() or None if row else None
  40. class SampleHandleBody(BaseModel):
  41. model_config = ConfigDict(populate_by_name=True)
  42. handle_time: Optional[str] = Field(None, alias="handleTime")
  43. handler_user_id: Optional[str] = Field(None, alias="handlerUserId")
  44. cert_image_urls: Optional[str] = Field(None, alias="certImageUrls")
  45. insurance_attachments: Optional[str] = Field(None, alias="insuranceAttachments")
  46. remark: Optional[str] = None
  47. handle_remark: Optional[str] = Field(None, alias="handleRemark")
  48. mail_cert_time: Optional[str] = Field(None, alias="mailCertTime")
  49. policy_send_time: Optional[str] = Field(None, alias="policySendTime")
  50. collection_protocol_id: Optional[str] = Field(None, alias="collectionProtocolId")
  51. @router.get("/sample-storage-certs/{sample_code}")
  52. async def get_sample_storage_cert(
  53. sample_code: str,
  54. db: Session = Depends(get_db),
  55. user: dict = Depends(_MENU),
  56. ):
  57. try:
  58. tenant_no = _get_tenant_no(db, user)
  59. code = (sample_code or "").strip()
  60. row = cert_crud.get_by_sample_code(db, tenant_no, code)
  61. if row is None:
  62. return success_response(
  63. {
  64. "sampleCode": code,
  65. "storageCertHandled": False,
  66. "handleTime": "",
  67. "handlerUserId": "",
  68. "certImageUrls": "",
  69. "mailCertTime": "",
  70. "remark": "",
  71. }
  72. )
  73. return success_response(cert_crud.row_to_dict(row))
  74. except PermissionError as e:
  75. return error_response(403, str(e))
  76. except Exception as e:
  77. return error_response(400, str(e))
  78. @router.put("/sample-storage-certs/{sample_code}")
  79. async def put_sample_storage_cert(
  80. sample_code: str,
  81. body: SampleHandleBody,
  82. db: Session = Depends(get_db),
  83. user: dict = Depends(_WRITE_MENU),
  84. ):
  85. try:
  86. tenant_no = _get_tenant_no(db, user)
  87. user_id = _get_current_user_id(user)
  88. code = (sample_code or "").strip()
  89. pid = (body.collection_protocol_id or "").strip() or _resolve_protocol_id(
  90. db, tenant_no, code
  91. )
  92. ht = parse_datetime(body.handle_time) if body.handle_time else None
  93. mail_raw = body.mail_cert_time
  94. update_mail = mail_raw is not None
  95. mail_t = parse_datetime(mail_raw) if mail_raw and str(mail_raw).strip() else None
  96. row = cert_crud.upsert_handle(
  97. db,
  98. tenant_no=tenant_no,
  99. sample_code=code,
  100. collection_protocol_id=pid,
  101. user_id=user_id,
  102. handle_time=ht,
  103. handler_user_id=body.handler_user_id,
  104. cert_image_urls=body.cert_image_urls or "",
  105. remark=body.remark or "",
  106. mail_cert_time=mail_t,
  107. update_mail_cert_time=update_mail,
  108. )
  109. db.commit()
  110. return success_response(cert_crud.row_to_dict(row), message="保存成功")
  111. except PermissionError as e:
  112. db.rollback()
  113. return error_response(403, str(e))
  114. except ValueError as e:
  115. db.rollback()
  116. return error_response(400, str(e))
  117. except Exception as e:
  118. db.rollback()
  119. return error_response(400, str(e))
  120. @router.get("/sample-insurances/{sample_code}")
  121. async def get_sample_insurance(
  122. sample_code: str,
  123. db: Session = Depends(get_db),
  124. user: dict = Depends(_MENU),
  125. ):
  126. try:
  127. tenant_no = _get_tenant_no(db, user)
  128. code = (sample_code or "").strip()
  129. row = insurance_crud.get_by_sample_code(db, tenant_no, code)
  130. if row is None:
  131. return success_response(
  132. {
  133. "sampleCode": code,
  134. "insuranceHandled": False,
  135. "handleTime": "",
  136. "handlerUserId": "",
  137. "insuranceAttachments": "",
  138. "policySendTime": "",
  139. "handleRemark": "",
  140. }
  141. )
  142. return success_response(insurance_crud.row_to_dict(row))
  143. except PermissionError as e:
  144. return error_response(403, str(e))
  145. except Exception as e:
  146. return error_response(400, str(e))
  147. @router.put("/sample-insurances/{sample_code}")
  148. async def put_sample_insurance(
  149. sample_code: str,
  150. body: SampleHandleBody,
  151. db: Session = Depends(get_db),
  152. user: dict = Depends(_WRITE_MENU),
  153. ):
  154. try:
  155. tenant_no = _get_tenant_no(db, user)
  156. user_id = _get_current_user_id(user)
  157. code = (sample_code or "").strip()
  158. pid = (body.collection_protocol_id or "").strip() or _resolve_protocol_id(
  159. db, tenant_no, code
  160. )
  161. ht = parse_datetime(body.handle_time) if body.handle_time else None
  162. policy_raw = body.policy_send_time
  163. update_policy = policy_raw is not None
  164. policy_t = (
  165. parse_datetime(policy_raw) if policy_raw and str(policy_raw).strip() else None
  166. )
  167. row = insurance_crud.upsert_handle(
  168. db,
  169. tenant_no=tenant_no,
  170. sample_code=code,
  171. collection_protocol_id=pid,
  172. user_id=user_id,
  173. handle_time=ht,
  174. handler_user_id=body.handler_user_id,
  175. insurance_attachments=body.insurance_attachments or "",
  176. handle_remark=body.handle_remark or body.remark or "",
  177. policy_send_time=policy_t,
  178. update_policy_send_time=update_policy,
  179. )
  180. db.commit()
  181. return success_response(insurance_crud.row_to_dict(row), message="保存成功")
  182. except PermissionError as e:
  183. db.rollback()
  184. return error_response(403, str(e))
  185. except ValueError as e:
  186. db.rollback()
  187. return error_response(400, str(e))
  188. except Exception as e:
  189. db.rollback()
  190. return error_response(400, str(e))