diff --git a/fetch_tickets.py b/fetch_tickets.py index 8d0fa03..b707cee 100644 --- a/fetch_tickets.py +++ b/fetch_tickets.py @@ -1,18 +1,28 @@ #!/usr/bin/env python3 -"""Получение списка заявок из ServiceDesk Plus с 20 июля 2026. Экспорт: Группа, Описание, Назначено, Категория в JSONL.""" +"""Получение списка заявок из ServiceDesk Plus. Экспорт: Группа, Описание, Назначено, Категория в JSONL.""" -import asyncio -import httpx +import requests import json import urllib3 -from datetime import datetime, timezone +from datetime import datetime from html import unescape import re import sys import os -# Добавляем путь к конфигу -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +# Отключаем ворнинги для чистой работы консоли +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +# --- ИМПОРТ КОНФИГУРАЦИИ --- +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config')) + +# Пытаемся импортировать конфиг, но не падаем если Passwork недоступен +try: + from config import * + config_loaded = True +except Exception as e: + config_loaded = False + print(f"⚠️ Конфиг не загружен: {e}") # Локальный Service Desk (для выгрузки данных) LOCAL_SD_URL = "https://192.168.1.237:8080" @@ -43,67 +53,66 @@ def get_name(obj): return obj.get("name", "") or obj.get("display_value", "") return str(obj) -async def fetch_ticket_detail(client, req_id): +def get_ticket_detail(ticket_id): + """Получить детальную информацию по заявке.""" try: - resp = await client.get( - f"{LOCAL_SD_URL}/api/v3/requests/{req_id}", - headers={"authtoken": LOCAL_SD_API_KEY, "Accept": "application/vnd.manageengine.sdp.v3+json"}, - timeout=15.0 - ) + url = f"{LOCAL_SD_URL}/api/v3/requests/{ticket_id}" + headers = {"authtoken": LOCAL_SD_API_KEY, "Accept": "application/vnd.manageengine.sdp.v3+json"} + resp = requests.get(url, headers=headers, verify=False, timeout=15.0) + resp.raise_for_status() data = resp.json() return data.get("request", data) except Exception as e: return {} -async def list_tickets(from_date=DEFAULT_FROM_DATE): +def list_tickets(from_date=DEFAULT_FROM_DATE): url = f"{LOCAL_SD_URL}/api/v3/requests" headers = {"authtoken": LOCAL_SD_API_KEY, "Accept": "application/vnd.manageengine.sdp.v3+json"} # Вычисляем timestamp с указанной даты date_obj = datetime.strptime(from_date, "%Y-%m-%d") - from_date_ms = int(date_obj.replace(tzinfo=timezone.utc).timestamp() * 1000) + from_date_ms = int(date_obj.replace(tzinfo=__import__('datetime').timezone.utc).timestamp() * 1000) - async with httpx.AsyncClient(verify=False, timeout=30.0) as client: - resp = await client.get(url, headers=headers) - data = resp.json() - all_reqs = data.get("requests", []) + resp = requests.get(url, headers=headers, verify=False, timeout=30.0) + resp.raise_for_status() + data = resp.json() + all_reqs = data.get("requests", []) + + from_date_reqs = [r for r in all_reqs if get_ts(r) >= from_date_ms] + + # Получаем детали для каждой заявки + rows = [] + for req in from_date_reqs: + req_id = req.get("request_id", req.get("id", "?")) + detail = get_ticket_detail(req_id) - from_date_reqs = [r for r in all_reqs if get_ts(r) >= from_date_ms] + # Группа — из списка + group = req.get("group", {}) + group_name = get_name(group) - # Получаем детали для каждой заявки - tasks = [fetch_ticket_detail(client, r.get("request_id", r.get("id", "?"))) for r in from_date_reqs] - details = await asyncio.gather(*tasks) + # Описание — из детального запроса + desc = detail.get("description", "") + desc_clean = clean_html(desc) - rows = [] - for req, detail in zip(from_date_reqs, details): - # Группа — из списка - group = req.get("group", {}) - group_name = get_name(group) - - # Описание — из детального запроса - desc = detail.get("description", "") - desc_clean = clean_html(desc) - - # Назначено (специалист) — из детального запроса - tech = detail.get("technician", {}) - assignee = get_name(tech) - - # Категория — из детального запроса - cat = detail.get("category", {}) - category = get_name(cat) - - rows.append({ - "group": group_name, - "description": desc_clean, - "assignee": assignee, - "category": category - }) + # Назначено (специалист) — из детального запроса + tech = detail.get("technician", {}) + assignee = get_name(tech) - # Выводим JSONL - for row in rows: - print(json.dumps(row, ensure_ascii=False)) + # Категория — из детального запроса + cat = detail.get("category", {}) + category = get_name(cat) + + rows.append({ + "group": group_name, + "description": desc_clean, + "assignee": assignee, + "category": category + }) + + # Выводим JSONL + for row in rows: + print(json.dumps(row, ensure_ascii=False)) if __name__ == "__main__": - urllib3.disable_warnings() from_date = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_FROM_DATE - asyncio.run(list_tickets(from_date)) + list_tickets(from_date)