PMFlow/backend/app/api/sstc_api/releases_status_generate.py

108 lines
3.9 KiB
Python

from __future__ import annotations
from .shared import *
from ...services.sstc.entity_lookup import _ensure_charter, _ensure_project, _ensure_release
from ...services.sstc.governance import _assert_release_transition_allowed, _require_manager
from ...services.sstc.signal_core import _as_dict, _parse_node_id, _parse_project_id
router = APIRouter(tags=["sstc"])
@router.patch("/projects/{project_id}/releases/{release_node_id}/status")
async def patch_release_status(
project_id: str,
release_node_id: str,
body: ReleaseStatusPatchRequest,
permission_user: User = Depends(require_project_member_or_manager),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
_ = permission_user
_require_manager(current_user)
pid = _parse_project_id(project_id)
rid = _parse_node_id(release_node_id, "release_node_id")
tenant_id = int(current_user.tenant_id)
await _ensure_project(SSTCService(db, tenant_id=tenant_id), pid)
release_node = await _ensure_release(
db, tenant_id=tenant_id, project_id=pid, release_node_id=rid
)
await _assert_release_transition_allowed(
db,
tenant_id=tenant_id,
project_id=pid,
release_node=release_node,
target_status=body.status,
)
before = {"status": release_node.status}
release_node.status = body.status
content = _as_dict(release_node.content)
content["status_note"] = body.note
content["last_status_changed_at"] = now_cn_aware().isoformat()
release_node.content = content
await log_operation(
db,
tenant_id=tenant_id,
user_id=int(current_user.id),
project_id=pid,
entity_type="release",
entity_id=str(rid),
action="status_change",
before_data=before,
after_data={"status": body.status, "note": body.note},
)
await db.commit()
return success_response({"id": str(release_node.id), "status": release_node.status})
@router.post("/projects/{project_id}/releases/{release_node_id}/verification/generate")
async def generate_release_verification(
project_id: str,
release_node_id: str,
permission_user: User = Depends(require_project_member_or_manager),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
_ = permission_user
_require_manager(current_user)
pid = _parse_project_id(project_id)
rid = _parse_node_id(release_node_id, "release_node_id")
tenant_id = int(current_user.tenant_id)
await _ensure_project(SSTCService(db, tenant_id=tenant_id), pid)
release_node = await _ensure_release(
db, tenant_id=tenant_id, project_id=pid, release_node_id=rid
)
content = _as_dict(release_node.content)
charter_id = int(content.get("charter_id") or 0)
charter = await _ensure_charter(
db,
tenant_id=tenant_id,
project_id=pid,
charter_id=charter_id,
)
charter_content = _as_dict(charter.content)
success_metrics = charter_content.get("success_metrics") or charter_content.get("core_metrics") or []
if not success_metrics:
success_metrics = ["功能验收通过", "核心流程无阻塞", "关键性能指标达标"]
items = [
{
"id": f"check-{i+1}",
"title": str(metric),
"expected": "达到预期",
"status": "pending",
"required": True,
"source": "charter_success_metric",
"verified_by": None,
"verified_at": None,
"note": None,
}
for i, metric in enumerate(success_metrics)
]
content["verification_items"] = items
content["verification_progress"] = {"done": 0, "total": len(items)}
content["verification_done"] = False
release_node.content = content
await db.commit()
return success_response({"release_id": str(release_node.id), "verification_items": items})