feat(oa): auto-pass approval when assignee is initiator

Extract approve core and hook after creating approval tasks when the advanced setting is enabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-07-27 17:42:41 +08:00
1 parent d69388573a
commit 8bd45561b7
1 file changed
+130 -54
+130 -54
View File
@@ -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)