fix(bidding): 模版确认门加固(E2E实测)——confirm_tech_template权限改复用引擎_check_confirm_operator(同机构+超管/创建者,与flow_plan_confirm语义一致,原自写'仅同机构'丢了超管语义实测误拒admin);确认重落守卫:已有非pending章节拒绝重新确认(防毁已写内容)

This commit is contained in:
yumoqing 2026-09-15 15:27:42 +08:00
parent cc87340398
commit 87ecf3ee72

View File

@ -445,15 +445,25 @@ async def confirm_tech_template(human_task_id, decision, comment="",
if ht.get("status") != "pending":
return False, "待办已处理(当前 %s" % ht.get("status")
project_id = ht.get("project_id") or ""
# 同机构校验
prec = await sor.sqlExe("SELECT org_id FROM sd_projects WHERE id=${p}$",
{"p": project_id})
await sor.sqlExe("COMMIT", {})
proj_org = getattr(prec[0], "org_id", "") if prec else ""
from pipeline_service.human_task_capability import _get_user_org
user_org = await _get_user_org(sor, operator_id)
if proj_org and user_org != proj_org:
return False, "仅同机构用户可确认该项目模版"
# 确认权限:复用引擎 _check_confirm_operator同机构 + owner.superuser/项目创建者)——
# 与 flow_plan_confirm 确认门语义完全一致不自己另写一套校验2026-09-15 E2E 实测
# 发现自写「仅同机构」把超管/创建者语义丢了)。
try:
from pipeline_service.flow_plan_capability import _check_confirm_operator
ok_op, err_op = await _check_confirm_operator(
sor, {"project_id": project_id}, operator_id)
if not ok_op:
return False, err_op or "无权确认该项目模版"
except ImportError:
# 引擎不可用(理论不发生):兜底同机构校验
prec = await sor.sqlExe("SELECT org_id FROM sd_projects WHERE id=${p}$",
{"p": project_id})
await sor.sqlExe("COMMIT", {})
proj_org = getattr(prec[0], "org_id", "") if prec else ""
from pipeline_service.human_task_capability import _get_user_org
user_org = await _get_user_org(sor, operator_id)
if proj_org and user_org != proj_org:
return False, "仅同机构用户可确认该项目模版"
if decision == "confirm":
schema = json_loads(ht.get("form_schema"), {}) or {}
@ -462,7 +472,17 @@ async def confirm_tech_template(human_task_id, decision, comment="",
chapters = schema.get("chapters") or []
if not chapters:
return False, "待办里没有骨架数据form_schema.chapters 空),无法落库"
# 幂等:已有骨架先清(驳回重提后再确认的场景)
# 幂等重落守卫仅当既有章节全部未开写pending时清旧骨架——
# 已有 writing/written/approved 章节说明流程已推进,重新确认会毁掉
# 已写内容,拒绝并提示走驳回/人工处置2026-09-15 加固)。
busy = await sor.sqlExe(
"SELECT COUNT(*) AS c FROM bid_chapters WHERE project_id=${p}$ "
"AND status<>${s}$", {"p": project_id, "s": CH_PENDING})
await sor.sqlExe("COMMIT", {})
if to_int(getattr(busy[0], "c", 0) if busy else 0) > 0:
return False, ("项目已有开写/已完成的章节,不能重新确认骨架(会毁掉已写内容)。"
"如需换骨架请先驳回或在章节管理页人工处置既有章节。")
# 幂等:清掉此前确认落库但尚未开写的旧骨架(驳回重提后再确认的场景)
await sor.sqlExe(
"DELETE FROM bid_chapters WHERE project_id=${p}$", {"p": project_id})
n = 0