fix: use requester name (CN) instead of email for SD API - fallback to AI when name fails
This commit is contained in:
+43
-17
@@ -106,35 +106,46 @@ def get_ad_user_info(user_id: str) -> dict | None:
|
||||
return None
|
||||
|
||||
|
||||
async def _send_sd_api_request(requester_email: str, subject: str, description: str, city: str) -> str | None:
|
||||
async def _send_sd_api_request(
|
||||
requester_cn: str,
|
||||
requester_email: str,
|
||||
subject: str,
|
||||
description: str,
|
||||
city: str
|
||||
) -> str | None:
|
||||
"""
|
||||
Автономная прямая отправка HTTP-запроса в Service Desk API v3.
|
||||
Автоматически ищет ID группы и техника по именам из config.
|
||||
Умеет привязывать пользователя по ФИО, Email или Fallback.
|
||||
"""
|
||||
# Если запрашивает системный ИИ — ищем по ИМЕНИ
|
||||
if requester_email == DEFAULT_REQUESTER or requester_email == "ai@sibcem.ru":
|
||||
requester_payload = {"name": "Искусственный Интеллект"}
|
||||
else:
|
||||
# 1. Формируем структуру заявителя (приоритет: ФИО -> Email -> ИИ)
|
||||
if requester_cn and requester_cn != "N/A":
|
||||
requester_payload = {"name": requester_cn}
|
||||
elif requester_email and requester_email not in (DEFAULT_REQUESTER, "ai@sibcem.ru"):
|
||||
requester_payload = {"email_id": requester_email}
|
||||
else:
|
||||
requester_payload = {"name": "Искусственный Интеллект"}
|
||||
|
||||
# Ищем ID группы
|
||||
# 2. Поиск ID группы (пробуем /groups и /group)
|
||||
group_id = None
|
||||
try:
|
||||
url_groups = f"{SD_URL.rstrip('/')}/api/v3/groups"
|
||||
headers = {"TECHNICIAN_KEY": SD_TOKEN}
|
||||
async with httpx.AsyncClient(verify=False) as client:
|
||||
for endpoint in ["/api/v3/groups", "/api/v3/group"]:
|
||||
url_groups = f"{SD_URL.rstrip('/')}{endpoint}"
|
||||
resp = await client.get(url_groups, headers=headers, timeout=10.0)
|
||||
if resp.status_code == 200:
|
||||
groups = resp.json().get("groups", [])
|
||||
groups = resp.json().get("groups", []) or resp.json().get("group", [])
|
||||
for g in groups:
|
||||
if g.get("name") == SD_INSTRUCT_GROUP_NAME:
|
||||
group_id = g.get("id")
|
||||
logger.info(f"SD group found: name={SD_INSTRUCT_GROUP_NAME}, id={group_id}")
|
||||
break
|
||||
if group_id:
|
||||
break
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to fetch SD groups: {e}")
|
||||
|
||||
# Ищем ID техника
|
||||
# 3. Поиск ID техника
|
||||
tech_id = None
|
||||
try:
|
||||
url_techs = f"{SD_URL.rstrip('/')}/api/v3/technicians"
|
||||
@@ -151,6 +162,7 @@ async def _send_sd_api_request(requester_email: str, subject: str, description:
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to fetch SD technicians: {e}")
|
||||
|
||||
# 4. Формируем тело запроса
|
||||
payload = {
|
||||
"request": {
|
||||
"subject": subject,
|
||||
@@ -161,7 +173,6 @@ async def _send_sd_api_request(requester_email: str, subject: str, description:
|
||||
}
|
||||
}
|
||||
}
|
||||
# Добавляем группу и исполнителя если найдены
|
||||
if group_id:
|
||||
payload["request"]["group"] = {"id": group_id}
|
||||
if tech_id:
|
||||
@@ -178,7 +189,22 @@ async def _send_sd_api_request(requester_email: str, subject: str, description:
|
||||
res_json = response.json()
|
||||
ticket_id = res_json.get("request", {}).get("id")
|
||||
return str(ticket_id) if ticket_id else None
|
||||
else:
|
||||
|
||||
# Fallback: Если по ФИО не нашло, пробуем через DEFAULT_REQUESTER
|
||||
elif response.status_code == 400 and requester_payload != {"name": "Искусственный Интеллект"}:
|
||||
logger.warning(
|
||||
f"ServiceDesk не смог привязать requester={requester_payload}. "
|
||||
f"Повторяем запрос от имени системного заявителя..."
|
||||
)
|
||||
payload["request"]["requester"] = {"name": "Искусственный Интеллект"}
|
||||
payload["request"]["description"] = f"[Пользователь: {requester_cn}]\n\n{description}"
|
||||
data_fb = {"input_data": json.dumps(payload)}
|
||||
|
||||
resp_fb = await client.post(url, headers=headers, data=data_fb, timeout=15.0)
|
||||
if resp_fb.status_code in (200, 201):
|
||||
ticket_id = resp_fb.json().get("request", {}).get("id")
|
||||
return str(ticket_id) if ticket_id else None
|
||||
|
||||
logger.error(f"Service Desk API Error ({response.status_code}): {response.text}")
|
||||
return None
|
||||
|
||||
@@ -214,9 +240,9 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
|
||||
"""
|
||||
subject = "Запрос доступа к Trueconf"
|
||||
|
||||
# Получаем email из AD
|
||||
# Получаем данные пользователя из AD
|
||||
ad_info = get_ad_user_info(user_id)
|
||||
requester_email = ad_info.get("mail") or DEFAULT_REQUESTER
|
||||
requester_email = (ad_info.get("mail") if ad_info else None) or DEFAULT_REQUESTER
|
||||
city = ad_info.get("city", "Кемерово") if ad_info else "Кемерово"
|
||||
|
||||
description = (
|
||||
@@ -225,10 +251,10 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
|
||||
)
|
||||
|
||||
try:
|
||||
logger.info(f"Calling SD API directly: requester={requester_email}, city={city}")
|
||||
ticket_id = await _send_sd_api_request(requester_email, subject, description, city)
|
||||
logger.info(f"Calling SD API directly: cn='{cn}', email='{requester_email}', city='{city}'")
|
||||
ticket_id = await _send_sd_api_request(cn, requester_email, subject, description, city)
|
||||
if ticket_id:
|
||||
logger.info(f"SD ticket created for {cn}: #{ticket_id} (requester={requester_email})")
|
||||
logger.info(f"SD ticket created for {cn}: #{ticket_id}")
|
||||
else:
|
||||
logger.error(f"Failed to create SD ticket for {cn}")
|
||||
return ticket_id
|
||||
|
||||
Reference in New Issue
Block a user