|
|
@@ -30,6 +30,9 @@ class OaEngineError(ValueError):
|
|
|
"""引擎业务错误"""
|
|
|
|
|
|
|
|
|
+_AUTO_PASS_COMMENT = "系统自动通过"
|
|
|
+
|
|
|
+
|
|
|
def _loads(text: Optional[str], default: Any = None) -> Any:
|
|
|
if text is None or text == "":
|
|
|
return default
|
|
|
@@ -1501,6 +1504,13 @@ def advance_from(
|
|
|
continue
|
|
|
if not tasks:
|
|
|
raise OaEngineError("审批节点未生成任务")
|
|
|
+ _maybe_auto_pass_initiator(
|
|
|
+ db,
|
|
|
+ inst=inst,
|
|
|
+ ver=ver,
|
|
|
+ tasks=tasks,
|
|
|
+ user_id=user_id,
|
|
|
+ )
|
|
|
return
|
|
|
# 未知类型跳过子节点
|
|
|
cur = next_node(cur)
|
|
|
@@ -1773,6 +1783,116 @@ def list_tasks(
|
|
|
return _enrich_list_rows(db, tenant_no=tenant_no, rows=rows, instances=insts)
|
|
|
|
|
|
|
|
|
+def _approve_task_core(
|
|
|
+ db: Session,
|
|
|
+ *,
|
|
|
+ task: OaTask,
|
|
|
+ inst: OaInstance,
|
|
|
+ ver: OaAppVersion,
|
|
|
+ user_id: str,
|
|
|
+ comment: Optional[str],
|
|
|
+) -> bool:
|
|
|
+ """将 pending 审批任务置为 approved 并按或签/会签决定是否推进。
|
|
|
+
|
|
|
+ 返回 True 表示已调用 advance_from 推进;False 表示会签未齐、未推进。
|
|
|
+ 调用方负责 commit(若需要)。
|
|
|
+ """
|
|
|
+ now = datetime.now()
|
|
|
+ task.comment_text = (comment or "").strip() or None
|
|
|
+ task.status = "approved"
|
|
|
+ task.update_by = user_id
|
|
|
+ task.update_time = now
|
|
|
+ db.add(task)
|
|
|
+ # Session 默认 autoflush=False:不先 flush 时,后续按 status=pending 的查询仍会命中本任务,
|
|
|
+ # 或签「取消同节点其余待办」会把本人已同意覆盖成 done。
|
|
|
+ db.flush()
|
|
|
+
|
|
|
+ sign_mode = (task.sign_mode or "or").strip() or "or"
|
|
|
+ pending_same = (
|
|
|
+ db.query(OaTask)
|
|
|
+ .filter(
|
|
|
+ OaTask.instance_id == inst.id,
|
|
|
+ OaTask.node_key == task.node_key,
|
|
|
+ OaTask.task_type == "approval",
|
|
|
+ OaTask.id != task.id,
|
|
|
+ OaTask.status == "pending",
|
|
|
+ OaTask.del_flag == 0,
|
|
|
+ )
|
|
|
+ .count()
|
|
|
+ )
|
|
|
+ if sign_mode == "and" and pending_same > 0:
|
|
|
+ return False
|
|
|
+
|
|
|
+ if sign_mode != "and":
|
|
|
+ for s in (
|
|
|
+ db.query(OaTask)
|
|
|
+ .filter(
|
|
|
+ OaTask.instance_id == inst.id,
|
|
|
+ OaTask.node_key == task.node_key,
|
|
|
+ OaTask.id != task.id,
|
|
|
+ OaTask.status == "pending",
|
|
|
+ OaTask.del_flag == 0,
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ ):
|
|
|
+ s.status = "done"
|
|
|
+ s.update_by = user_id
|
|
|
+ s.update_time = now
|
|
|
+ db.add(s)
|
|
|
+
|
|
|
+ root = _flow_root(_loads(ver.flow_tree_json, {}))
|
|
|
+ node = _find_node(root, task.node_key or "")
|
|
|
+ if not node:
|
|
|
+ raise OaEngineError("找不到对应流程节点")
|
|
|
+ advance_from(
|
|
|
+ db,
|
|
|
+ inst=inst,
|
|
|
+ ver=ver,
|
|
|
+ from_node=node,
|
|
|
+ user_id=user_id,
|
|
|
+ initiator_select_by_node=_load_initiator_select_by_node(inst),
|
|
|
+ )
|
|
|
+ return True
|
|
|
+
|
|
|
+
|
|
|
+def _maybe_auto_pass_initiator(
|
|
|
+ db: Session,
|
|
|
+ *,
|
|
|
+ inst: OaInstance,
|
|
|
+ ver: OaAppVersion,
|
|
|
+ tasks: List[OaTask],
|
|
|
+ user_id: Optional[str],
|
|
|
+) -> None:
|
|
|
+ _ = user_id
|
|
|
+ advanced = _advanced(ver)
|
|
|
+ if not advanced.get("autoPassWhenApproverIsInitiator"):
|
|
|
+ return
|
|
|
+ if inst.status != "running":
|
|
|
+ return
|
|
|
+ initiator = (inst.initiator_user_id or "").strip()
|
|
|
+ if not initiator:
|
|
|
+ return
|
|
|
+ self_task = None
|
|
|
+ for t in tasks:
|
|
|
+ if (
|
|
|
+ t.task_type == "approval"
|
|
|
+ and t.status == "pending"
|
|
|
+ and (t.assignee_user_id or "") == initiator
|
|
|
+ ):
|
|
|
+ self_task = t
|
|
|
+ break
|
|
|
+ if not self_task:
|
|
|
+ return
|
|
|
+ _approve_task_core(
|
|
|
+ db,
|
|
|
+ task=self_task,
|
|
|
+ inst=inst,
|
|
|
+ ver=ver,
|
|
|
+ user_id=initiator,
|
|
|
+ comment=_AUTO_PASS_COMMENT,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
def complete_task(
|
|
|
db: Session,
|
|
|
task_id: str,
|
|
|
@@ -1814,18 +1934,14 @@ def complete_task(
|
|
|
if advanced.get("commentRequired") and not (comment or "").strip():
|
|
|
raise OaEngineError("请填写审批意见")
|
|
|
|
|
|
- now = datetime.now()
|
|
|
- task.comment_text = (comment or "").strip() or None
|
|
|
- task.status = "approved" if action == "approve" else "rejected"
|
|
|
- task.update_by = user_id
|
|
|
- task.update_time = now
|
|
|
- db.add(task)
|
|
|
- # Session 默认 autoflush=False:不先 flush 时,后续按 status=pending 的查询仍会命中本任务,
|
|
|
- # 或签「取消同节点其余待办」会把本人已同意/已拒绝覆盖成 done,导致「已处理」列表查不到。
|
|
|
- db.flush()
|
|
|
-
|
|
|
if action == "reject":
|
|
|
- # 同节点其他待办作废(排除当前任务)
|
|
|
+ now = datetime.now()
|
|
|
+ task.comment_text = (comment or "").strip() or None
|
|
|
+ task.status = "rejected"
|
|
|
+ task.update_by = user_id
|
|
|
+ task.update_time = now
|
|
|
+ db.add(task)
|
|
|
+ db.flush()
|
|
|
siblings = (
|
|
|
db.query(OaTask)
|
|
|
.filter(
|
|
|
@@ -1849,53 +1965,13 @@ def complete_task(
|
|
|
db.commit()
|
|
|
return get_instance_detail(db, inst.id, tenant_no=tenant_no)
|
|
|
|
|
|
- # 或签:一人通过即可;会签:全部通过
|
|
|
- sign_mode = (task.sign_mode or "or").strip() or "or"
|
|
|
- pending_same = (
|
|
|
- db.query(OaTask)
|
|
|
- .filter(
|
|
|
- OaTask.instance_id == inst.id,
|
|
|
- OaTask.node_key == task.node_key,
|
|
|
- OaTask.task_type == "approval",
|
|
|
- OaTask.id != task.id,
|
|
|
- OaTask.status == "pending",
|
|
|
- OaTask.del_flag == 0,
|
|
|
- )
|
|
|
- .count()
|
|
|
- )
|
|
|
- if sign_mode == "and" and pending_same > 0:
|
|
|
- db.commit()
|
|
|
- return get_instance_detail(db, inst.id, tenant_no=tenant_no)
|
|
|
-
|
|
|
- # 或签:取消同节点其余待办(排除当前任务)
|
|
|
- if sign_mode != "and":
|
|
|
- for s in (
|
|
|
- db.query(OaTask)
|
|
|
- .filter(
|
|
|
- OaTask.instance_id == inst.id,
|
|
|
- OaTask.node_key == task.node_key,
|
|
|
- OaTask.id != task.id,
|
|
|
- OaTask.status == "pending",
|
|
|
- OaTask.del_flag == 0,
|
|
|
- )
|
|
|
- .all()
|
|
|
- ):
|
|
|
- s.status = "done"
|
|
|
- s.update_by = user_id
|
|
|
- s.update_time = now
|
|
|
- db.add(s)
|
|
|
-
|
|
|
- root = _flow_root(_loads(ver.flow_tree_json, {}))
|
|
|
- node = _find_node(root, task.node_key or "")
|
|
|
- if not node:
|
|
|
- raise OaEngineError("找不到对应流程节点")
|
|
|
- advance_from(
|
|
|
+ _approve_task_core(
|
|
|
db,
|
|
|
+ task=task,
|
|
|
inst=inst,
|
|
|
ver=ver,
|
|
|
- from_node=node,
|
|
|
user_id=user_id,
|
|
|
- initiator_select_by_node=_load_initiator_select_by_node(inst),
|
|
|
+ comment=comment,
|
|
|
)
|
|
|
db.commit()
|
|
|
return get_instance_detail(db, inst.id, tenant_no=tenant_no)
|