feat: add trusted ticket intake backend
This commit is contained in:
@@ -1,13 +1,98 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.audit.models import OperationAuditLog
|
||||
from apps.tickets.models import Ticket, TicketEvent
|
||||
from apps.tickets.models import Ticket, TicketCategory, TicketEvent, TicketPriority
|
||||
|
||||
|
||||
class TicketStatusError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class TicketDataError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
REQUIRED_TICKET_FIELDS = (
|
||||
"title",
|
||||
"description",
|
||||
"category_code",
|
||||
"priority",
|
||||
"problem_performance",
|
||||
"problem_object",
|
||||
"submitter_name",
|
||||
"submitter_org",
|
||||
"environment",
|
||||
)
|
||||
|
||||
|
||||
def validate_ticket_fields(fields: dict) -> tuple[dict, TicketCategory]:
|
||||
normalized = {
|
||||
"title": str(fields.get("title") or "").strip(),
|
||||
"description": str(fields.get("description") or "").strip(),
|
||||
"category_code": str(fields.get("category_code") or "").strip(),
|
||||
"priority": str(fields.get("priority") or "medium").strip(),
|
||||
"problem_performance": str(fields.get("problem_performance") or "").strip(),
|
||||
"problem_object": str(fields.get("problem_object") or "").strip(),
|
||||
"submitter_name": str(fields.get("submitter_name") or "").strip(),
|
||||
"submitter_org": str(fields.get("submitter_org") or "").strip(),
|
||||
"impact_scope": str(fields.get("impact_scope") or "").strip(),
|
||||
"environment": str(fields.get("environment") or "").strip(),
|
||||
"related_system": str(fields.get("related_system") or "").strip(),
|
||||
"assignee_id": fields.get("assignee_id"),
|
||||
}
|
||||
missing = [code for code in REQUIRED_TICKET_FIELDS if not normalized.get(code)]
|
||||
if missing:
|
||||
raise TicketDataError(f"缺少必填字段: {', '.join(missing)}")
|
||||
if normalized["priority"] not in TicketPriority.values:
|
||||
raise TicketDataError("工单优先级无效")
|
||||
category = TicketCategory.objects.filter(code=normalized["category_code"], enabled=True).first()
|
||||
if category is None:
|
||||
raise TicketDataError("工单分类无效或已停用")
|
||||
if normalized["assignee_id"]:
|
||||
assignee = get_user_model().objects.filter(id=normalized["assignee_id"]).first()
|
||||
if assignee is None:
|
||||
raise TicketDataError("处理人不存在")
|
||||
else:
|
||||
assignee = None
|
||||
normalized["assignee"] = assignee
|
||||
return normalized, category
|
||||
|
||||
|
||||
def next_ticket_no() -> str:
|
||||
prefix = timezone.localdate().strftime("TK%Y%m%d")
|
||||
count = Ticket.objects.filter(ticket_no__startswith=prefix).count() + 1
|
||||
return f"{prefix}{count:04d}"
|
||||
|
||||
|
||||
def create_ticket_from_fields(fields: dict, user) -> Ticket:
|
||||
normalized, category = validate_ticket_fields(fields)
|
||||
ticket = Ticket.objects.create(
|
||||
ticket_no=next_ticket_no(),
|
||||
title=normalized["title"],
|
||||
description=normalized["description"],
|
||||
category=category,
|
||||
priority=normalized["priority"],
|
||||
problem_performance=normalized["problem_performance"],
|
||||
problem_object=normalized["problem_object"],
|
||||
submitter_name=normalized["submitter_name"],
|
||||
submitter_org=normalized["submitter_org"],
|
||||
impact_scope=normalized["impact_scope"],
|
||||
environment=normalized["environment"],
|
||||
related_system=normalized["related_system"],
|
||||
assignee=normalized["assignee"],
|
||||
requester=user,
|
||||
created_by=user,
|
||||
)
|
||||
TicketEvent.objects.create(
|
||||
ticket=ticket,
|
||||
event_type="created",
|
||||
to_value={"status": ticket.status, "category_code": normalized["category_code"]},
|
||||
operator=user,
|
||||
)
|
||||
return ticket
|
||||
|
||||
|
||||
STANDARD_TRANSITIONS: dict[str, set[str]] = {
|
||||
"pending_info": {"pending", "closed"},
|
||||
"pending": {"in_progress", "closed"},
|
||||
|
||||
Reference in New Issue
Block a user