150 lines
6.3 KiB
Python
Executable File
150 lines
6.3 KiB
Python
Executable File
# /opt/docker/dev/service_finder/backend/app/services/notification_service.py
|
|
import logging
|
|
import uuid
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import joinedload
|
|
|
|
from app.models.identity import User
|
|
from app.models import Asset
|
|
from app.models.marketplace.organization import Organization
|
|
from app.models.system import InternalNotification
|
|
from app.services.email_manager import email_manager
|
|
from app.services.config_service import config
|
|
|
|
logger = logging.getLogger("Notification-Service-2.2")
|
|
|
|
class NotificationService:
|
|
"""
|
|
Sentinel Master Notification Service 2.2 - Fully Admin-Configurable.
|
|
Nincs fix kód: minden típus (biztosítás, műszaki, okmány) a DB-ből vezérelt.
|
|
"""
|
|
|
|
@staticmethod
|
|
async def send_notification(
|
|
db: AsyncSession,
|
|
user_id: int,
|
|
title: str,
|
|
message: str,
|
|
category: str = "info",
|
|
priority: str = "medium",
|
|
data: dict = None,
|
|
send_email: bool = True,
|
|
email_template: str = None,
|
|
email_vars: dict = None
|
|
):
|
|
""" Univerzális küldő: Belső Dashboard + Email. """
|
|
new_notif = InternalNotification(
|
|
user_id=user_id,
|
|
title=title,
|
|
message=message,
|
|
category=category,
|
|
priority=priority,
|
|
data=data or {}
|
|
)
|
|
db.add(new_notif)
|
|
|
|
if send_email and email_template and email_vars:
|
|
await email_manager.send_email(
|
|
db=db,
|
|
recipient=email_vars.get("recipient"),
|
|
template_key=email_template,
|
|
variables=email_vars,
|
|
lang=email_vars.get("lang", "hu")
|
|
)
|
|
await db.commit()
|
|
|
|
@staticmethod
|
|
async def check_expiring_documents(db: AsyncSession):
|
|
"""
|
|
Dinamikus lejárat-figyelő: Típusonkénti naptárak az adminból.
|
|
"""
|
|
try:
|
|
today = datetime.now(timezone.utc).date()
|
|
|
|
# 1. Lekérjük az összes aktív járművet és a tulajdonosaikat
|
|
stmt = (
|
|
select(Asset, User)
|
|
.join(Organization, Asset.current_organization_id == Organization.id)
|
|
.join(User, Organization.owner_id == User.id)
|
|
.where(Asset.status == "active")
|
|
.options(joinedload(Asset.catalog))
|
|
)
|
|
result = await db.execute(stmt)
|
|
notifications_sent = 0
|
|
|
|
for asset, user in result.all():
|
|
# 2. DINAMIKUS MÁTRIX LEKÉRÉSE (Hierarchikus: User > Region > Global)
|
|
# Az adminban így van tárolva: {"insurance": [45, 30, 7, 0], "mot": [30, 7, 0], ...}
|
|
alert_matrix = await config.get_setting(
|
|
db,
|
|
"NOTIFICATION_TYPE_MATRIX",
|
|
scope_level="user",
|
|
scope_id=str(user.id),
|
|
default={
|
|
"insurance": [45, 30, 15, 7, 1, 0],
|
|
"mot": [30, 7, 1, 0],
|
|
"personal_id": [30, 15, 0],
|
|
"default": [30, 7, 1]
|
|
}
|
|
)
|
|
|
|
# 3. Ellenőrizendő dátumok (factory_data a Robotoktól)
|
|
# Kulcsok: insurance_expiry_date, mot_expiry_date, id_card_expiry stb.
|
|
check_map = {
|
|
"insurance": asset.factory_data.get("insurance_expiry_date"),
|
|
"mot": asset.factory_data.get("mot_expiry_date"),
|
|
"personal_id": user.person.identity_docs.get("expiry_date") if user.person else None
|
|
}
|
|
|
|
for doc_type, expiry_str in check_map.items():
|
|
if not expiry_str: continue
|
|
|
|
try:
|
|
expiry_dt = datetime.strptime(expiry_str, "%Y-%m-%d").date()
|
|
days_until = (expiry_dt - today).days
|
|
|
|
# Megnézzük a típushoz tartozó admin-beállítást (pl. a 45 napot)
|
|
alert_steps = alert_matrix.get(doc_type, alert_matrix["default"])
|
|
|
|
if days_until in alert_steps:
|
|
# Prioritás meghatározása (Adminból is jöhetne, de itt kategória alapú)
|
|
priority = "critical" if days_until <= 1 or (doc_type == "insurance" and days_until == 45) else "high"
|
|
|
|
title = f"Riasztás: {asset.license_plate} - {doc_type.upper()}"
|
|
msg = f"A(z) {doc_type} dokumentum {days_until} nap múlva lejár ({expiry_str})."
|
|
|
|
if days_until == 45 and doc_type == "insurance":
|
|
msg = f"🚨 BIZTOSÍTÁSI FORDULÓ! (45 nap). Most van időd felmondani a régit!"
|
|
|
|
await NotificationService.send_notification(
|
|
db=db,
|
|
user_id=user.id,
|
|
title=title,
|
|
message=msg,
|
|
category=doc_type,
|
|
priority=priority,
|
|
data={"asset_id": str(asset.id), "vin": asset.vin, "days": days_until},
|
|
email_template="expiry_alert",
|
|
email_vars={
|
|
"recipient": user.email,
|
|
"first_name": user.person.first_name if user.person else "Partnerünk",
|
|
"license_plate": asset.license_plate,
|
|
"expiry_date": expiry_str,
|
|
"days_left": days_until,
|
|
"lang": user.preferred_language
|
|
}
|
|
)
|
|
notifications_sent += 1
|
|
|
|
except (ValueError, TypeError):
|
|
continue
|
|
|
|
return {"status": "success", "count": notifications_sent}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Notification System Error: {e}")
|
|
raise e |