protocol_refund_record.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. """协议级退费登记 API"""
  2. from __future__ import annotations
  3. from typing import Optional
  4. from fastapi import APIRouter, Depends
  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 protocol_refund_record as rr_svc
  11. from app.models.models import (
  12. BizCollectionProtocol,
  13. BizProtocolRefundRecord,
  14. SysUser,
  15. )
  16. router = APIRouter(prefix="/web/admin", tags=["细胞存储-退费登记"])
  17. REFUND_CONFIRM_MENU = "biz:cellStorageRefundConfirm:list"
  18. def _get_tenant_no(db: Session, user: dict) -> str:
  19. user_id = user.get("user_id")
  20. if not user_id:
  21. raise PermissionError("用户身份信息缺失,无法确定租户")
  22. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  23. if not sys_user or not sys_user.tenant_no:
  24. raise PermissionError("用户租户信息缺失")
  25. return sys_user.tenant_no
  26. def _get_current_user_id(user: dict) -> str:
  27. user_id = user.get("user_id")
  28. if not user_id:
  29. raise PermissionError("用户身份信息缺失")
  30. return str(user_id)
  31. def _protocol_accessible(db: Session, protocol_id: str, tenant_no: str, user: dict) -> bool:
  32. from app.core.data_scope import apply_data_scope
  33. q = db.query(BizCollectionProtocol).filter(
  34. BizCollectionProtocol.id == protocol_id,
  35. BizCollectionProtocol.del_flag == 0,
  36. BizCollectionProtocol.tenant_no == tenant_no,
  37. )
  38. q = apply_data_scope(q, BizCollectionProtocol, user, db, tenant_no)
  39. return q.first() is not None
  40. class RefundRecordBody(BaseModel):
  41. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  42. refund_amount: float = Field(..., alias="refundAmount")
  43. refund_time: Optional[str] = Field(None, alias="refundTime")
  44. refund_remark: Optional[str] = Field(None, alias="refundRemark")
  45. refund_attachments: Optional[str] = Field(None, alias="refundAttachments")
  46. workflow_instance_id: Optional[str] = Field(None, alias="workflowInstanceId")
  47. remark: Optional[str] = None
  48. class RefundRecordUpdateBody(BaseModel):
  49. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  50. refund_amount: Optional[float] = Field(None, alias="refundAmount")
  51. refund_time: Optional[str] = Field(None, alias="refundTime")
  52. refund_remark: Optional[str] = Field(None, alias="refundRemark")
  53. refund_attachments: Optional[str] = Field(None, alias="refundAttachments")
  54. workflow_instance_id: Optional[str] = Field(None, alias="workflowInstanceId")
  55. remark: Optional[str] = None
  56. @router.get("/collection-protocols/{protocol_id}/refund-records")
  57. async def list_protocol_refund_records(
  58. protocol_id: str,
  59. user: dict = Depends(require_admin_or_super_admin),
  60. db: Session = Depends(get_db),
  61. ):
  62. try:
  63. tenant_no = _get_tenant_no(db, user)
  64. if not _protocol_accessible(db, protocol_id, tenant_no, user):
  65. return error_response(404, "协议单不存在或无权查看")
  66. data = rr_svc.list_refund_records(
  67. db, collection_protocol_id=protocol_id, tenant_no=tenant_no
  68. )
  69. return success_response(data)
  70. except PermissionError as e:
  71. return error_response(403, str(e))
  72. @router.post("/collection-protocols/{protocol_id}/refund-records")
  73. async def create_protocol_refund_record(
  74. protocol_id: str,
  75. body: RefundRecordBody,
  76. user: dict = Depends(require_strict_menu_code(REFUND_CONFIRM_MENU)),
  77. db: Session = Depends(get_db),
  78. ):
  79. try:
  80. tenant_no = _get_tenant_no(db, user)
  81. user_id = _get_current_user_id(user)
  82. if not _protocol_accessible(db, protocol_id, tenant_no, user):
  83. return error_response(404, "协议单不存在或无权操作")
  84. obj = rr_svc.create_refund_record(
  85. db,
  86. collection_protocol_id=protocol_id,
  87. tenant_no=tenant_no,
  88. user_id=user_id,
  89. refund_amount=body.refund_amount,
  90. refund_time=body.refund_time,
  91. refund_remark=body.refund_remark,
  92. refund_attachments=body.refund_attachments,
  93. workflow_instance_id=body.workflow_instance_id,
  94. remark=body.remark,
  95. )
  96. return success_response(
  97. rr_svc._record_to_dict(db, obj, tenant_no), message="登记成功"
  98. )
  99. except PermissionError as e:
  100. return error_response(403, str(e))
  101. except ValueError as e:
  102. return error_response(400, str(e))
  103. @router.put("/protocol-refund-records/{record_id}")
  104. async def update_protocol_refund_record(
  105. record_id: str,
  106. body: RefundRecordUpdateBody,
  107. user: dict = Depends(require_strict_menu_code(REFUND_CONFIRM_MENU)),
  108. db: Session = Depends(get_db),
  109. ):
  110. try:
  111. tenant_no = _get_tenant_no(db, user)
  112. user_id = _get_current_user_id(user)
  113. existing = (
  114. db.query(BizProtocolRefundRecord)
  115. .filter(
  116. BizProtocolRefundRecord.id == record_id,
  117. BizProtocolRefundRecord.tenant_no == tenant_no,
  118. BizProtocolRefundRecord.del_flag == 0,
  119. )
  120. .first()
  121. )
  122. if not existing:
  123. return error_response(404, "退费登记不存在")
  124. if not _protocol_accessible(
  125. db, existing.collection_protocol_id, tenant_no, user
  126. ):
  127. return error_response(403, "无权操作该协议")
  128. dumped = body.model_dump(by_alias=False, exclude_unset=True)
  129. obj = rr_svc.update_refund_record(
  130. db,
  131. record_id=record_id,
  132. tenant_no=tenant_no,
  133. user_id=user_id,
  134. refund_amount=dumped.get("refund_amount"),
  135. refund_time=dumped.get("refund_time"),
  136. refund_remark=dumped.get("refund_remark"),
  137. refund_attachments=dumped.get("refund_attachments"),
  138. workflow_instance_id=dumped.get("workflow_instance_id"),
  139. remark=dumped.get("remark"),
  140. fields_set=set(dumped.keys()),
  141. )
  142. return success_response(
  143. rr_svc._record_to_dict(db, obj, tenant_no), message="保存成功"
  144. )
  145. except PermissionError as e:
  146. return error_response(403, str(e))
  147. except ValueError as e:
  148. return error_response(400, str(e))
  149. @router.delete("/protocol-refund-records/{record_id}")
  150. async def delete_protocol_refund_record(
  151. record_id: str,
  152. user: dict = Depends(require_strict_menu_code(REFUND_CONFIRM_MENU)),
  153. db: Session = Depends(get_db),
  154. ):
  155. try:
  156. tenant_no = _get_tenant_no(db, user)
  157. user_id = _get_current_user_id(user)
  158. existing = (
  159. db.query(BizProtocolRefundRecord)
  160. .filter(
  161. BizProtocolRefundRecord.id == record_id,
  162. BizProtocolRefundRecord.tenant_no == tenant_no,
  163. BizProtocolRefundRecord.del_flag == 0,
  164. )
  165. .first()
  166. )
  167. if not existing:
  168. return error_response(404, "退费登记不存在")
  169. if not _protocol_accessible(
  170. db, existing.collection_protocol_id, tenant_no, user
  171. ):
  172. return error_response(403, "无权操作该协议")
  173. rr_svc.soft_delete_refund_record(
  174. db, record_id=record_id, tenant_no=tenant_no, user_id=user_id
  175. )
  176. return success_response(None, message="删除成功")
  177. except PermissionError as e:
  178. return error_response(403, str(e))
  179. except ValueError as e:
  180. return error_response(400, str(e))