workflow.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. from __future__ import annotations
  2. from typing import List, Optional, Sequence, Tuple
  3. from sqlalchemy.orm import Session
  4. from app.core.bx_auth import BxUserContext
  5. from app.core.tenant_context import get_tenant_no
  6. from app.core.utils import generate_uuid
  7. from app.models.bx_models import BxWorkflowDef, BxWorkflowNode
  8. from app.services.bx.base import BxCrudService
  9. _DEFAULT_WORKFLOWS = {
  10. "advance": {
  11. "wf_name": "备用金审批流程",
  12. "remark": "备用金申请默认审批流程",
  13. },
  14. "reimburse": {
  15. "wf_name": "报销单审批流程",
  16. "remark": "报销申请默认审批流程",
  17. },
  18. }
  19. class WorkflowService:
  20. @staticmethod
  21. def _tenant_no(db: Session, user: BxUserContext) -> str:
  22. return get_tenant_no(db, user.to_tenant_user_dict())
  23. @staticmethod
  24. def get_by_id(
  25. db: Session,
  26. workflow_id: str,
  27. tenant_no: str,
  28. *,
  29. user: Optional[BxUserContext] = None,
  30. skip_scope: bool = False,
  31. ) -> Optional[BxWorkflowDef]:
  32. return BxCrudService.get_by_id(
  33. BxWorkflowDef, db, workflow_id, tenant_no, user=user, skip_scope=skip_scope
  34. )
  35. @staticmethod
  36. def get_paged(
  37. db: Session,
  38. tenant_no: str,
  39. page: int,
  40. page_size: int,
  41. *,
  42. user: Optional[BxUserContext] = None,
  43. ) -> Tuple[Sequence[BxWorkflowDef], int]:
  44. return BxCrudService.get_paged(
  45. BxWorkflowDef, db, tenant_no, page, page_size, user=user
  46. )
  47. @staticmethod
  48. def create(
  49. db: Session,
  50. obj_in: dict,
  51. *,
  52. user: BxUserContext,
  53. ) -> BxWorkflowDef:
  54. tenant_no = WorkflowService._tenant_no(db, user)
  55. return BxCrudService.create(
  56. BxWorkflowDef,
  57. db,
  58. obj_in,
  59. tenant_no=tenant_no,
  60. user_id=user.id,
  61. dept_id=user.dept_id,
  62. )
  63. @staticmethod
  64. def update(
  65. db: Session,
  66. workflow_id: str,
  67. obj_in: dict,
  68. *,
  69. user: BxUserContext,
  70. ) -> Optional[BxWorkflowDef]:
  71. tenant_no = WorkflowService._tenant_no(db, user)
  72. return BxCrudService.update(
  73. BxWorkflowDef,
  74. db,
  75. workflow_id,
  76. tenant_no,
  77. obj_in,
  78. user_id=user.id,
  79. user=user,
  80. )
  81. @staticmethod
  82. def soft_delete(db: Session, workflow_id: str, *, user: BxUserContext) -> bool:
  83. tenant_no = WorkflowService._tenant_no(db, user)
  84. deleted = BxCrudService.soft_delete(
  85. BxWorkflowDef, db, workflow_id, tenant_no, user_id=user.id, user=user
  86. )
  87. if deleted:
  88. db.query(BxWorkflowNode).filter(
  89. BxWorkflowNode.wf_id == workflow_id,
  90. BxWorkflowNode.tenant_no == tenant_no,
  91. ).update({"del_flag": 1}, synchronize_session=False)
  92. db.flush()
  93. return deleted
  94. @staticmethod
  95. def get_by_biz_type(db: Session, biz_type: str, tenant_no: str) -> Optional[BxWorkflowDef]:
  96. return (
  97. db.query(BxWorkflowDef)
  98. .filter(
  99. BxWorkflowDef.biz_type == biz_type,
  100. BxWorkflowDef.tenant_no == tenant_no,
  101. BxWorkflowDef.del_flag == 0,
  102. )
  103. .first()
  104. )
  105. @staticmethod
  106. def ensure_by_biz_type(
  107. db: Session,
  108. biz_type: str,
  109. *,
  110. user: BxUserContext,
  111. ) -> Optional[BxWorkflowDef]:
  112. """按业务类型获取工作流;已知类型不存在时自动创建空定义(无节点)。"""
  113. tenant_no = WorkflowService._tenant_no(db, user)
  114. workflow = WorkflowService.get_by_biz_type(db, biz_type, tenant_no)
  115. if workflow:
  116. return workflow
  117. meta = _DEFAULT_WORKFLOWS.get(biz_type)
  118. if not meta:
  119. return None
  120. workflow = WorkflowService.create(
  121. db,
  122. {
  123. "biz_type": biz_type,
  124. "wf_name": meta["wf_name"],
  125. "remark": meta["remark"],
  126. "status": 1,
  127. },
  128. user=user,
  129. )
  130. db.commit()
  131. db.refresh(workflow)
  132. return workflow
  133. @staticmethod
  134. def save_nodes(
  135. db: Session,
  136. wf_id: str,
  137. nodes: List[dict],
  138. *,
  139. user: BxUserContext,
  140. ) -> List[BxWorkflowNode]:
  141. tenant_no = WorkflowService._tenant_no(db, user)
  142. workflow = WorkflowService.get_by_id(db, wf_id, tenant_no, user=user)
  143. if not workflow:
  144. raise ValueError("工作流不存在")
  145. db.query(BxWorkflowNode).filter(
  146. BxWorkflowNode.wf_id == wf_id,
  147. BxWorkflowNode.tenant_no == tenant_no,
  148. ).delete(synchronize_session=False)
  149. created: List[BxWorkflowNode] = []
  150. for node_data in nodes:
  151. data = dict(node_data)
  152. data["id"] = generate_uuid()
  153. data["wf_id"] = wf_id
  154. data["tenant_no"] = tenant_no
  155. data["create_by"] = user.id
  156. data["create_dept_id"] = user.dept_id or ""
  157. if data.get("approver_id") is not None:
  158. data["approver_id"] = str(data["approver_id"]).strip() or None
  159. node = BxWorkflowNode(**data)
  160. db.add(node)
  161. created.append(node)
  162. db.flush()
  163. db.expire(workflow, ["nodes"])
  164. return created