- EmailNotifier primește lista de conturi (nu doar count) - _create_email_body afișează solduri per cont + total RON - Format tabel HTML frumos cu styling - send_notifications.py citește date din JSON - Sincronizare cu TelegramNotifier (deja avea solduri) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
179 lines
5.8 KiB
Python
179 lines
5.8 KiB
Python
"""
|
|
Script pentru trimiterea notificărilor cu fișiere existente
|
|
Trimite ultimele fișiere CSV generate pe Email și Telegram
|
|
"""
|
|
import logging
|
|
import sys
|
|
import json
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from config import Config
|
|
from notifications import NotificationService
|
|
|
|
# Setup logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.StreamHandler(sys.stdout)
|
|
]
|
|
)
|
|
|
|
|
|
def find_latest_files(data_dir='./data', time_window_seconds=300):
|
|
"""
|
|
Găsește ultimele fișiere CSV generate și date despre conturi
|
|
|
|
Args:
|
|
data_dir: Directorul cu fișiere
|
|
time_window_seconds: Intervalul de timp (în secunde) pentru a considera fișierele din aceeași sesiune
|
|
|
|
Returns:
|
|
tuple: (solduri_csv_path, list_of_transaction_csvs, accounts_data)
|
|
"""
|
|
data_path = Path(data_dir)
|
|
|
|
if not data_path.exists():
|
|
logging.error(f"Directorul {data_dir} nu există!")
|
|
return None, [], []
|
|
|
|
# Găsește ultimul fișier solduri_*.csv
|
|
solduri_files = sorted(data_path.glob('solduri_*.csv'), key=lambda x: x.stat().st_mtime, reverse=True)
|
|
|
|
if not solduri_files:
|
|
logging.error("Nu s-a găsit niciun fișier solduri_*.csv!")
|
|
return None, [], []
|
|
|
|
latest_solduri = solduri_files[0]
|
|
solduri_time = latest_solduri.stat().st_mtime
|
|
|
|
logging.info(f"✓ Găsit fișier solduri: {latest_solduri.name}")
|
|
logging.info(f" Timestamp: {datetime.fromtimestamp(solduri_time).strftime('%Y-%m-%d %H:%M:%S')}")
|
|
|
|
# Găsește fișierul JSON corespunzător
|
|
json_filename = latest_solduri.stem + '.json'
|
|
json_path = data_path / json_filename
|
|
accounts_data = []
|
|
|
|
if json_path.exists():
|
|
try:
|
|
with open(json_path, 'r', encoding='utf-8') as f:
|
|
json_data = json.load(f)
|
|
accounts_data = json_data.get('conturi', [])
|
|
logging.info(f"✓ Găsit fișier JSON: {json_filename} ({len(accounts_data)} conturi)")
|
|
except Exception as e:
|
|
logging.warning(f"Nu s-a putut citi fișierul JSON: {e}")
|
|
else:
|
|
logging.warning(f"Nu s-a găsit fișierul JSON: {json_filename}")
|
|
|
|
# Găsește toate fișierele tranzactii_*.csv modificate în ultimele X secunde față de solduri
|
|
all_transaction_files = list(data_path.glob('tranzactii_*.csv'))
|
|
transaction_files = []
|
|
|
|
for tf in all_transaction_files:
|
|
tf_time = tf.stat().st_mtime
|
|
time_diff = abs(tf_time - solduri_time)
|
|
|
|
# Dacă fișierul tranzacții este din aceeași sesiune (în intervalul de timp)
|
|
if time_diff <= time_window_seconds:
|
|
transaction_files.append(tf)
|
|
logging.info(f" ✓ {tf.name} (diferență: {int(time_diff)}s)")
|
|
|
|
# Sortează după timp
|
|
transaction_files = sorted(transaction_files, key=lambda x: x.stat().st_mtime)
|
|
|
|
logging.info(f"✓ Găsite {len(transaction_files)} fișiere tranzacții din aceeași sesiune")
|
|
|
|
return latest_solduri, transaction_files, accounts_data
|
|
|
|
|
|
def send_existing_files():
|
|
"""Trimite fișierele existente pe Email și Telegram"""
|
|
try:
|
|
logging.info("=" * 60)
|
|
logging.info("TRIMITERE NOTIFICĂRI CU FIȘIERE EXISTENTE")
|
|
logging.info("=" * 60)
|
|
|
|
# Validează configurația
|
|
Config.validate()
|
|
|
|
if not Config.ENABLE_NOTIFICATIONS:
|
|
logging.error("ENABLE_NOTIFICATIONS=false în .env!")
|
|
logging.error("Setează ENABLE_NOTIFICATIONS=true pentru a trimite notificări")
|
|
return False
|
|
|
|
# Găsește ultimele fișiere
|
|
solduri_csv, transaction_csvs, accounts_data = find_latest_files(Config.OUTPUT_DIR)
|
|
|
|
if not solduri_csv:
|
|
logging.error("Nu există fișiere de trimis!")
|
|
return False
|
|
|
|
# Pregătește lista de fișiere
|
|
files_to_send = [str(solduri_csv)]
|
|
for tf in transaction_csvs:
|
|
files_to_send.append(str(tf))
|
|
|
|
logging.info("=" * 60)
|
|
logging.info(f"Total fișiere de trimis: {len(files_to_send)}")
|
|
logging.info("=" * 60)
|
|
|
|
# Dacă nu avem date despre conturi, creăm o listă goală
|
|
if not accounts_data:
|
|
logging.warning("Nu s-au găsit date despre conturi din JSON")
|
|
accounts_data = []
|
|
|
|
# Trimite notificările
|
|
service = NotificationService(Config)
|
|
results = service.send_all(files_to_send, accounts_data)
|
|
|
|
# Afișează rezumat
|
|
logging.info("=" * 60)
|
|
logging.info("REZUMAT NOTIFICĂRI")
|
|
logging.info("=" * 60)
|
|
|
|
if Config.EMAIL_ENABLED:
|
|
status = "✓ Succes" if results['email'] else "✗ Eșuat"
|
|
logging.info(f"Email: {status}")
|
|
else:
|
|
logging.info("Email: Dezactivat")
|
|
|
|
if Config.TELEGRAM_ENABLED:
|
|
status = "✓ Succes" if results['telegram'] else "✗ Eșuat"
|
|
logging.info(f"Telegram: {status}")
|
|
else:
|
|
logging.info("Telegram: Dezactivat")
|
|
|
|
logging.info("=" * 60)
|
|
|
|
# Verifică dacă cel puțin un canal a avut succes
|
|
success = any(results.values())
|
|
|
|
if success:
|
|
logging.info("✓ Notificări trimise cu succes!")
|
|
else:
|
|
logging.warning("Notificările au eșuat. Verifică configurația în .env")
|
|
|
|
return success
|
|
|
|
except ValueError as e:
|
|
logging.error(f"Eroare configurație: {e}")
|
|
logging.error("Verifică setările din .env")
|
|
return False
|
|
except Exception as e:
|
|
logging.error(f"Eroare neașteptată: {e}", exc_info=True)
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
logging.info("")
|
|
logging.info("🔔 BTGO Scraper - Trimitere Notificări")
|
|
logging.info("")
|
|
|
|
success = send_existing_files()
|
|
|
|
if success:
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|