|
|
@@ -22,7 +22,12 @@ from app.models.models import (
|
|
|
SysDept,
|
|
|
SysUser,
|
|
|
)
|
|
|
-from app.services.oa_assignee import AssigneeResolveError, resolve_assignees
|
|
|
+from app.services.oa_assignee import (
|
|
|
+ AssigneeResolveError,
|
|
|
+ normalize_cc_assignee_types,
|
|
|
+ resolve_assignees,
|
|
|
+ resolve_cc_assignees,
|
|
|
+)
|
|
|
from app.services.oa_formula import FormulaError, apply_formulas_and_linkages, eval_formula
|
|
|
|
|
|
|
|
|
@@ -309,7 +314,33 @@ def _pending_people_for_node(
|
|
|
node_select_ids = _ids_for_initiator_select_node(
|
|
|
initiator_select_by_node, node.get("id") or ""
|
|
|
)
|
|
|
- if assignee_type == "initiator_select":
|
|
|
+ resolve_source = assignee_type
|
|
|
+ if ntype == "cc":
|
|
|
+ types = normalize_cc_assignee_types(cfg)
|
|
|
+ assignees, meta = resolve_cc_assignees(
|
|
|
+ db,
|
|
|
+ tenant_no=tenant_no,
|
|
|
+ assignee_config=cfg,
|
|
|
+ initiator_user_id=initiator_user_id,
|
|
|
+ initiator_dept_id=initiator_dept_id,
|
|
|
+ advanced=advanced,
|
|
|
+ initiator_select_user_ids=node_select_ids,
|
|
|
+ )
|
|
|
+ resolve_source = str(meta.get("resolve_source") or "")
|
|
|
+ if not resolve_source:
|
|
|
+ resolve_source = "multi" if len(types) > 1 else (types[0] if types else "")
|
|
|
+ for uid in assignees:
|
|
|
+ people.append(
|
|
|
+ {
|
|
|
+ "id": uid,
|
|
|
+ "nickName": "",
|
|
|
+ "status": "not_reached",
|
|
|
+ "timestamp": "",
|
|
|
+ "commentText": "",
|
|
|
+ "taskId": "",
|
|
|
+ }
|
|
|
+ )
|
|
|
+ elif assignee_type == "initiator_select":
|
|
|
for uid in node_select_ids:
|
|
|
people.append(
|
|
|
{
|
|
|
@@ -349,7 +380,7 @@ def _pending_people_for_node(
|
|
|
name_map = _user_name_map(db, [p["id"] for p in people if p.get("id")])
|
|
|
for p in people:
|
|
|
p["nickName"] = name_map.get(p["id"], "") or p["id"]
|
|
|
- return people, sign_mode, assignee_type
|
|
|
+ return people, sign_mode, resolve_source
|
|
|
|
|
|
|
|
|
def _iter_resolved_path_nodes(
|
|
|
@@ -1046,6 +1077,17 @@ def _assignee_meta(db: Session, tenant_no: str, cfg: Dict[str, Any]) -> str:
|
|
|
return base
|
|
|
|
|
|
|
|
|
+def _assignee_meta_for_cc(
|
|
|
+ db: Session, tenant_no: str, cfg: Dict[str, Any], types: List[str]
|
|
|
+) -> str:
|
|
|
+ if not types:
|
|
|
+ return "未配置抄送人"
|
|
|
+ if len(types) == 1:
|
|
|
+ return _assignee_meta(db, tenant_no, {**cfg, "assigneeType": types[0]})
|
|
|
+ labels = [_ASSIGNEE_TYPE_LABEL.get(t, t) for t in types]
|
|
|
+ return " + ".join(labels)
|
|
|
+
|
|
|
+
|
|
|
def _preview_people(db: Session, user_ids: List[str]) -> List[Dict[str, str]]:
|
|
|
name_map = _user_name_map(db, user_ids)
|
|
|
out: List[Dict[str, str]] = []
|
|
|
@@ -1216,48 +1258,86 @@ def _walk_preview_nodes(
|
|
|
|
|
|
if ntype in ("approval", "cc"):
|
|
|
cfg = cur.get("approverConfig") or {}
|
|
|
- assignee_type = (cfg.get("assigneeType") or cfg.get("assignee_type") or "").strip()
|
|
|
sign_mode = (cfg.get("signMode") or cfg.get("sign_mode") or "").strip()
|
|
|
- if ntype == "cc":
|
|
|
- sign_mode = "cc"
|
|
|
- elif not sign_mode and assignee_type != "initiator_select":
|
|
|
- sign_mode = "or"
|
|
|
- meta = _assignee_meta(db, tenant_no, cfg)
|
|
|
people: List[Dict[str, str]] = []
|
|
|
resolve_error = ""
|
|
|
node_select_ids = _ids_for_initiator_select_node(
|
|
|
initiator_select_by_node, cur.get("id") or ""
|
|
|
)
|
|
|
- if assignee_type == "initiator_select":
|
|
|
- people = _preview_people(db, [str(x) for x in node_select_ids if str(x).strip()])
|
|
|
- if not people:
|
|
|
- meta = meta or "发起人自选"
|
|
|
+ if ntype == "cc":
|
|
|
+ types = normalize_cc_assignee_types(cfg)
|
|
|
+ if "initiator_select" in types:
|
|
|
+ display_type = "initiator_select"
|
|
|
+ elif len(types) == 1:
|
|
|
+ display_type = types[0]
|
|
|
+ elif types:
|
|
|
+ display_type = "multi"
|
|
|
+ else:
|
|
|
+ display_type = ""
|
|
|
+ sign_mode = "cc"
|
|
|
+ meta = _assignee_meta_for_cc(db, tenant_no, cfg, types)
|
|
|
+ assignees, _meta = resolve_cc_assignees(
|
|
|
+ db,
|
|
|
+ tenant_no=tenant_no,
|
|
|
+ assignee_config=cfg,
|
|
|
+ initiator_user_id=initiator_user_id,
|
|
|
+ initiator_dept_id=initiator_dept_id,
|
|
|
+ advanced=advanced,
|
|
|
+ initiator_select_user_ids=node_select_ids,
|
|
|
+ )
|
|
|
+ people = _preview_people(db, assignees)
|
|
|
+ steps.append(
|
|
|
+ {
|
|
|
+ "id": cur.get("id") or "",
|
|
|
+ "type": ntype,
|
|
|
+ "name": cur.get("name") or "抄送人",
|
|
|
+ "signMode": sign_mode,
|
|
|
+ "assigneeType": display_type,
|
|
|
+ "assigneeTypes": types,
|
|
|
+ "meta": meta,
|
|
|
+ "people": people,
|
|
|
+ "resolveError": resolve_error,
|
|
|
+ }
|
|
|
+ )
|
|
|
else:
|
|
|
- try:
|
|
|
- assignees, _meta = resolve_assignees(
|
|
|
- db,
|
|
|
- tenant_no=tenant_no,
|
|
|
- assignee_config=cfg,
|
|
|
- initiator_user_id=initiator_user_id,
|
|
|
- initiator_dept_id=initiator_dept_id,
|
|
|
- advanced=advanced,
|
|
|
- initiator_select_user_ids=node_select_ids,
|
|
|
+ assignee_type = (
|
|
|
+ cfg.get("assigneeType") or cfg.get("assignee_type") or ""
|
|
|
+ ).strip()
|
|
|
+ if not sign_mode and assignee_type != "initiator_select":
|
|
|
+ sign_mode = "or"
|
|
|
+ meta = _assignee_meta(db, tenant_no, cfg)
|
|
|
+ if assignee_type == "initiator_select":
|
|
|
+ people = _preview_people(
|
|
|
+ db, [str(x) for x in node_select_ids if str(x).strip()]
|
|
|
)
|
|
|
- people = _preview_people(db, assignees)
|
|
|
- except AssigneeResolveError as e:
|
|
|
- resolve_error = str(e)
|
|
|
- steps.append(
|
|
|
- {
|
|
|
- "id": cur.get("id") or "",
|
|
|
- "type": ntype,
|
|
|
- "name": cur.get("name") or ("抄送人" if ntype == "cc" else "审批人"),
|
|
|
- "signMode": sign_mode,
|
|
|
- "assigneeType": assignee_type,
|
|
|
- "meta": meta,
|
|
|
- "people": people,
|
|
|
- "resolveError": resolve_error,
|
|
|
- }
|
|
|
- )
|
|
|
+ if not people:
|
|
|
+ meta = meta or "发起人自选"
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ assignees, _meta = resolve_assignees(
|
|
|
+ db,
|
|
|
+ tenant_no=tenant_no,
|
|
|
+ assignee_config=cfg,
|
|
|
+ initiator_user_id=initiator_user_id,
|
|
|
+ initiator_dept_id=initiator_dept_id,
|
|
|
+ advanced=advanced,
|
|
|
+ initiator_select_user_ids=node_select_ids,
|
|
|
+ )
|
|
|
+ people = _preview_people(db, assignees)
|
|
|
+ except AssigneeResolveError as e:
|
|
|
+ resolve_error = str(e)
|
|
|
+ steps.append(
|
|
|
+ {
|
|
|
+ "id": cur.get("id") or "",
|
|
|
+ "type": ntype,
|
|
|
+ "name": cur.get("name") or "审批人",
|
|
|
+ "signMode": sign_mode,
|
|
|
+ "assigneeType": assignee_type,
|
|
|
+ "meta": meta,
|
|
|
+ "people": people,
|
|
|
+ "resolveError": resolve_error,
|
|
|
+ }
|
|
|
+ )
|
|
|
cur = cur.get("child")
|
|
|
continue
|
|
|
|
|
|
@@ -1353,19 +1433,13 @@ def _create_tasks_for_node(
|
|
|
return created
|
|
|
|
|
|
cfg = node.get("approverConfig") or {}
|
|
|
- assignee_type = (cfg.get("assigneeType") or cfg.get("assignee_type") or "").strip()
|
|
|
node_select_ids = _ids_for_initiator_select_node(
|
|
|
initiator_select_by_node, node.get("id") or ""
|
|
|
)
|
|
|
- if assignee_type == "initiator_select":
|
|
|
- if ntype == "cc" and not node_select_ids:
|
|
|
- return created
|
|
|
- if ntype == "approval" and not node_select_ids:
|
|
|
- raise OaEngineError("发起人未选择审批人")
|
|
|
-
|
|
|
advanced = _advanced(ver)
|
|
|
- try:
|
|
|
- assignees, meta = resolve_assignees(
|
|
|
+
|
|
|
+ if ntype == "cc":
|
|
|
+ assignees, meta = resolve_cc_assignees(
|
|
|
db,
|
|
|
tenant_no=inst.tenant_no,
|
|
|
assignee_config=cfg,
|
|
|
@@ -1374,8 +1448,24 @@ def _create_tasks_for_node(
|
|
|
advanced=advanced,
|
|
|
initiator_select_user_ids=node_select_ids,
|
|
|
)
|
|
|
- except AssigneeResolveError as e:
|
|
|
- raise OaEngineError(str(e)) from e
|
|
|
+ if not assignees:
|
|
|
+ return created
|
|
|
+ else:
|
|
|
+ assignee_type = (cfg.get("assigneeType") or cfg.get("assignee_type") or "").strip()
|
|
|
+ if assignee_type == "initiator_select" and not node_select_ids:
|
|
|
+ raise OaEngineError("发起人未选择审批人")
|
|
|
+ try:
|
|
|
+ assignees, meta = resolve_assignees(
|
|
|
+ db,
|
|
|
+ tenant_no=inst.tenant_no,
|
|
|
+ assignee_config=cfg,
|
|
|
+ initiator_user_id=inst.initiator_user_id,
|
|
|
+ initiator_dept_id=inst.initiator_dept_id,
|
|
|
+ advanced=advanced,
|
|
|
+ initiator_select_user_ids=node_select_ids,
|
|
|
+ )
|
|
|
+ except AssigneeResolveError as e:
|
|
|
+ raise OaEngineError(str(e)) from e
|
|
|
|
|
|
sign_mode = (cfg.get("signMode") or cfg.get("sign_mode") or "or").strip() or "or"
|
|
|
resolve_source = meta.get("resolve_source")
|