206 lines
8.3 KiB
Python
206 lines
8.3 KiB
Python
"""
|
||
Справочники Intradesk.
|
||
|
||
Содержит:
|
||
1. Статические константы (известные ID → имена)
|
||
2. Загрузку справочников из API Intradesk в локальную БД
|
||
"""
|
||
|
||
import logging
|
||
|
||
import requests
|
||
|
||
import config
|
||
import database
|
||
|
||
log = logging.getLogger(__name__)
|
||
|
||
# ── Статические справочники ────────────────────────────────────────────────────
|
||
# Используются как fallback если данные ещё не загружены из API,
|
||
# а также сидируются в БД при старте.
|
||
|
||
STATUSES: dict[int, str] = {
|
||
68046: "Открыта",
|
||
68048: "Требует уточнения",
|
||
68051: "В работе",
|
||
68045: "Выполнена",
|
||
}
|
||
|
||
PRIORITIES: dict[int, str] = {
|
||
29749: "Наивысший",
|
||
29598: "Критический",
|
||
29597: "Высокий",
|
||
29596: "Низкий",
|
||
}
|
||
|
||
USER_TYPES: dict[int, str] = {
|
||
10: "Клиент",
|
||
20: "Сотрудник",
|
||
}
|
||
|
||
# Все типы событий из lifecycle заявки
|
||
EVENT_TYPES: dict[int, str] = {
|
||
10: "Смена статуса",
|
||
20: "Смена приоритета",
|
||
25: "Смена оценки",
|
||
30: "Смена исполнителя",
|
||
40: "Смена группы исполнителей",
|
||
45: "Изменение доп. данных",
|
||
50: "Комментарий",
|
||
55: "Приватный комментарий",
|
||
60: "Добавлен наблюдатель",
|
||
61: "Добавлен координатор",
|
||
65: "Добавлена группа наблюдателей",
|
||
70: "Удалён наблюдатель",
|
||
75: "Удалена группа наблюдателей",
|
||
80: "Добавлен файл",
|
||
85: "Добавлен скрытый файл",
|
||
90: "Удалён файл",
|
||
95: "Удалён скрытый файл",
|
||
100: "Добавлен тег",
|
||
105: "Добавлен актив",
|
||
110: "Удалён тег",
|
||
115: "Удалён актив",
|
||
120: "Изменён плановый срок решения",
|
||
125: "Изменён фактический срок решения",
|
||
126: "Изменено оставшееся время",
|
||
130: "Изменён плановый срок реакции",
|
||
135: "Изменён фактический срок реакции",
|
||
136: "Истёк срок решения",
|
||
137: "Истёк срок реакции",
|
||
138: "Изменена дата закрытия",
|
||
140: "Изменён сервис",
|
||
150: "Изменён тип заявки",
|
||
160: "Изменён инициатор",
|
||
161: "Изменён клиент",
|
||
165: "Изменена группа инициатора",
|
||
170: "Изменено доп. поле",
|
||
180: "Изменена дата создания",
|
||
185: "Изменена дата обновления",
|
||
190: "Изменён создатель",
|
||
195: "Изменён последний редактор",
|
||
200: "Изменено название",
|
||
205: "Изменено описание",
|
||
210: "Изменён бизнес-процесс",
|
||
220: "Добавлен не ответственный исполнитель",
|
||
225: "Добавлена не ответственная группа исполнителей",
|
||
230: "Удалён не ответственный исполнитель",
|
||
235: "Удалена не ответственная группа исполнителей",
|
||
240: "Изменён SLA",
|
||
250: "Изменена история",
|
||
260: "Изменён канал создания",
|
||
270: "Изменён канал обновления",
|
||
280: "Архивировано",
|
||
290: "Добавлены координаты",
|
||
300: "Выполнен макрос",
|
||
310: "Изменён признак массового инцидента",
|
||
320: "Изменён массовый инцидент",
|
||
330: "Изменена координация",
|
||
340: "Изменена критичность приоритета",
|
||
350: "Изменено влияние приоритета",
|
||
400: "Эскалация заявки",
|
||
}
|
||
|
||
|
||
# ── API-справочники (загружаются из Intradesk) ─────────────────────────────────
|
||
|
||
_TASKS_URL = "https://apigw.intradesk.ru/tasklist/odata/v3/tasks"
|
||
|
||
# Маппинг поля "type" из dictionaries → ключ entity в БД
|
||
_DICT_TYPE_TO_ENTITY: dict[str, str] = {
|
||
"user": "employees",
|
||
"usergroup": "groups",
|
||
"status": "statuses",
|
||
"priority": "priorities",
|
||
"tasktype": "tasktypes",
|
||
"tags": "tags",
|
||
"workflow": "workflows",
|
||
"asset": "assets",
|
||
}
|
||
|
||
|
||
# ── вспомогательные ────────────────────────────────────────────────────────────
|
||
|
||
def resolve(entity: str, item_id: int | None) -> str | None:
|
||
"""
|
||
Резолвит ID в имя.
|
||
Сначала смотрит в БД (актуальные данные из API),
|
||
затем в статические словари-fallback.
|
||
"""
|
||
if item_id is None:
|
||
return None
|
||
|
||
name = database.resolve(entity, item_id)
|
||
if name:
|
||
return name
|
||
|
||
_fallbacks = {
|
||
"statuses": STATUSES,
|
||
"priorities": PRIORITIES,
|
||
}
|
||
fb = _fallbacks.get(entity, {})
|
||
return fb.get(item_id)
|
||
|
||
|
||
def event_name(event_type: int) -> str:
|
||
"""Возвращает человекочитаемое имя события по его числовому коду."""
|
||
return EVENT_TYPES.get(event_type, f"Событие {event_type}")
|
||
|
||
|
||
def user_type_name(user_type: int) -> str:
|
||
"""Возвращает тип пользователя (Клиент / Сотрудник)."""
|
||
return USER_TYPES.get(user_type, str(user_type))
|
||
|
||
|
||
# ── загрузка из API ────────────────────────────────────────────────────────────
|
||
|
||
def seed_static():
|
||
"""Сидирует в БД известные статические данные (статусы, приоритеты)."""
|
||
database.save_ref_data("statuses", list(STATUSES.items()))
|
||
database.save_ref_data("priorities", list(PRIORITIES.items()))
|
||
log.info("Static reference data seeded (statuses, priorities)")
|
||
|
||
|
||
def load_all():
|
||
"""
|
||
Загружает справочники из поля dictionaries ответа tasklist API.
|
||
Один запрос заменяет 7+ отдельных запросов к settings/odata.
|
||
Обновление накопительное: новые/обновлённые записи добавляются,
|
||
старые не удаляются (они могут встретиться в старых заявках).
|
||
"""
|
||
log.info("Loading reference data from tasklist dictionaries...")
|
||
|
||
try:
|
||
resp = requests.get(
|
||
_TASKS_URL,
|
||
params={"ApiKey": config.API_KEY, "$top": 1},
|
||
timeout=30,
|
||
)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
except requests.exceptions.RequestException as e:
|
||
log.error(f"Failed to fetch tasklist for dictionaries: {e}")
|
||
return
|
||
|
||
dictionaries = data.get("dictionaries", [])
|
||
if not dictionaries:
|
||
log.warning("dictionaries field is empty or missing in tasklist response")
|
||
return
|
||
|
||
# Группируем по entity
|
||
buckets: dict[str, list[tuple[int, str]]] = {}
|
||
for item in dictionaries:
|
||
dtype = item.get("type", "")
|
||
entity = _DICT_TYPE_TO_ENTITY.get(dtype)
|
||
if not entity:
|
||
continue
|
||
item_id = item.get("id")
|
||
name = str(item.get("name") or "").strip()
|
||
if item_id and name:
|
||
buckets.setdefault(entity, []).append((item_id, name))
|
||
|
||
for entity, pairs in buckets.items():
|
||
database.save_ref_data(entity, pairs)
|
||
log.info(f"[{entity}] updated {len(pairs)} records from dictionaries")
|
||
|
||
log.info("Reference data loading complete.")
|