@@ -0,0 +1,85 @@
|
||||
"""Уведомления в центр зоотехника по алертам feed_quality."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Iterable
|
||||
|
||||
from app.models.feed_alert import FeedAlert
|
||||
from app.services.feed_quality.rules import (
|
||||
EVENT_LEFT_IN_MIXER,
|
||||
EVENT_LOADING_FAST,
|
||||
EVENT_LOADING_TIME,
|
||||
EVENT_MIX_TIME,
|
||||
EVENT_OVERLOAD,
|
||||
EVENT_UNDERLOAD,
|
||||
SEVERITY_ERROR,
|
||||
SEVERITY_WARNING,
|
||||
settings_section_for_alert,
|
||||
)
|
||||
from app.services.feed_quality.settings_store import get_feed_quality_settings
|
||||
from app.services.notification_center_service import create_notification, format_detail_timestamp
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_EVENT_TITLES = {
|
||||
EVENT_OVERLOAD: "Перегруз при загрузке",
|
||||
EVENT_UNDERLOAD: "Недогруз при загрузке",
|
||||
EVENT_LOADING_TIME: "Долгая загрузка компонента",
|
||||
EVENT_LOADING_FAST: "Быстрая загрузка компонента",
|
||||
EVENT_MIX_TIME: "Отклонение смешивания",
|
||||
EVENT_LEFT_IN_MIXER: "Остаток в миксере",
|
||||
}
|
||||
|
||||
|
||||
def _alert_title(alert: FeedAlert) -> str:
|
||||
if alert.group_name and alert.event_type in (EVENT_OVERLOAD, EVENT_UNDERLOAD):
|
||||
return "Отклонение при выгрузке"
|
||||
return _EVENT_TITLES.get(alert.event_type, "Отклонение кормления")
|
||||
|
||||
|
||||
def _alert_detail(alert: FeedAlert) -> str:
|
||||
when = format_detail_timestamp(alert.created_at)
|
||||
recipe = alert.recipe_name or "рейс"
|
||||
return f"Рейс «{recipe}»: {alert.detail} — {when}"
|
||||
|
||||
|
||||
def _should_notify(alert: FeedAlert) -> bool:
|
||||
if alert.severity not in (SEVERITY_WARNING, SEVERITY_ERROR):
|
||||
return False
|
||||
section_key = settings_section_for_alert(
|
||||
alert.event_type,
|
||||
component_name=alert.component_name,
|
||||
group_name=alert.group_name,
|
||||
)
|
||||
cfg = get_feed_quality_settings().get(section_key) or {}
|
||||
if alert.severity == SEVERITY_ERROR:
|
||||
return bool(cfg.get("notify_critical", True))
|
||||
return bool(cfg.get("notify_warning", True))
|
||||
|
||||
|
||||
def notify_feed_quality_alerts(alerts: Iterable[FeedAlert]) -> int:
|
||||
"""Создаёт записи в «К» по флагам notify_* в настройках."""
|
||||
count = 0
|
||||
for alert in alerts:
|
||||
if not _should_notify(alert):
|
||||
continue
|
||||
kind = "error" if alert.severity == SEVERITY_ERROR else "warning"
|
||||
try:
|
||||
create_notification(
|
||||
title=_alert_title(alert),
|
||||
detail=_alert_detail(alert),
|
||||
kind=kind,
|
||||
category="feed_quality",
|
||||
page="reports",
|
||||
link_kind="report_loading",
|
||||
link_id=alert.loading_report_id,
|
||||
)
|
||||
count += 1
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"[FEED-QUALITY-NOTIFY] alert=%s report=%s",
|
||||
alert.id,
|
||||
alert.loading_report_id,
|
||||
)
|
||||
return count
|
||||
Reference in New Issue
Block a user