-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
346 lines (294 loc) · 12.6 KB
/
Copy pathmain.py
File metadata and controls
346 lines (294 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Vergi Hatırlatıcı Bot - Ana Uygulama
GİB vergi güncellemelerini Telegram üzerinden kullanıcılara ileten bot
"""
import os
import sys
import asyncio
import logging
from datetime import datetime
import schedule
import time
from threading import Thread
from dotenv import load_dotenv
# Local imports
from bot import VergiBot
from database import DatabaseConnection
from scraper import GIBScraper
# .env dosyasını yükle
load_dotenv()
class VergiHatirlaticiApp:
"""Ana uygulama sınıfı"""
def __init__(self):
self.bot_token = os.getenv('BOT_TOKEN')
self.db = None
self.bot = None
self.logger = self.setup_logging()
# Uygulama başlangıç kontrolü
self.check_requirements()
def setup_logging(self):
"""Logging yapılandırması"""
# logs klasörünü oluştur
if not os.path.exists('logs'):
os.makedirs('logs')
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/main.log', encoding='utf-8'),
logging.StreamHandler()
]
)
return logging.getLogger(__name__)
def check_requirements(self):
"""Gereksinimler kontrolü"""
try:
# Bot token kontrolü
if not self.bot_token:
raise ValueError("BOT_TOKEN bulunamadı! .env dosyasını kontrol edin.")
# Veritabanı bağlantı kontrolü
self.db = DatabaseConnection()
self.db.connect()
self.logger.info("✅ Veritabanı bağlantısı başarılı")
# Gerekli tabloları oluştur
self.create_tables()
self.logger.info("✅ Tüm gereksinimler karşılandı")
except Exception as e:
self.logger.error(f"❌ Gereksinim kontrolü başarısız: {str(e)}")
sys.exit(1)
def create_tables(self):
"""Veritabanı tablolarını oluştur"""
try:
# Users tablosu - reminder_days sütunu eklendi
self.db.execute_query("""
CREATE TABLE IF NOT EXISTS users (
user_id BIGINT PRIMARY KEY,
username VARCHAR(255),
chat_id BIGINT UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT TRUE,
reminder_days INT DEFAULT NULL
)
""")
# Tax calendar tablosu
self.db.execute_query("""
CREATE TABLE IF NOT EXISTS tax_calendar (
id INT AUTO_INCREMENT PRIMARY KEY,
tax_type VARCHAR(255) NOT NULL,
deadline_date DATE NOT NULL,
description TEXT,
source VARCHAR(255) DEFAULT 'GİB',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_deadline_date (deadline_date)
)
""")
# Announcements tablosu
self.db.execute_query("""
CREATE TABLE IF NOT EXISTS announcements (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(500) NOT NULL,
content TEXT,
url VARCHAR(500),
source VARCHAR(255) DEFAULT 'GİB',
category VARCHAR(100),
published_date DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_published_date (published_date),
INDEX idx_source (source)
)
""")
# Reminders tablosu
self.db.execute_query("""
CREATE TABLE IF NOT EXISTS reminders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT,
tax_calendar_id INT,
reminder_date DATETIME,
is_sent BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (tax_calendar_id) REFERENCES tax_calendar(id) ON DELETE CASCADE,
INDEX idx_reminder_date (reminder_date),
INDEX idx_is_sent (is_sent)
)
""")
self.logger.info("✅ Veritabanı tabloları hazır")
except Exception as e:
self.logger.error(f"❌ Tablo oluşturma hatası: {str(e)}")
raise
def initialize_bot(self):
"""Bot'u başlat"""
try:
self.bot = VergiBot(self.bot_token)
self.logger.info("✅ Bot başarıyla oluşturuldu")
return True
except Exception as e:
self.logger.error(f"❌ Bot başlatma hatası: {str(e)}")
return False
def schedule_tasks(self):
"""Zamanlanmış görevleri ayarla"""
try:
# Her gün saat 09:00'da veri güncelleme
schedule.every().day.at("09:00").do(self.daily_data_update)
# Her gün saat 08:00'de hatırlatma kontrolü
schedule.every().day.at("08:00").do(self.send_reminders)
# Her 6 saatte bir sistem sağlık kontrolü
schedule.every(6).hours.do(self.health_check)
self.logger.info("✅ Zamanlanmış görevler ayarlandı")
except Exception as e:
self.logger.error(f"❌ Görev zamanlama hatası: {str(e)}")
def daily_data_update(self):
"""Günlük veri güncelleme"""
try:
self.logger.info("🔄 Günlük veri güncelleme başlatılıyor...")
scraper = GIBScraper()
updates = scraper.get_all_updates()
# Duyuruları veritabanına kaydet
if updates['announcements']:
for announcement in updates['announcements']:
try:
self.db.execute_query("""
INSERT IGNORE INTO announcements (title, content, url, source, category, published_date)
VALUES (%s, %s, %s, %s, %s, %s)
""", (
announcement['title'],
announcement.get('content', ''),
announcement.get('url', ''),
announcement.get('source', 'GİB'),
announcement.get('category', 'Duyuru'),
announcement.get('date', datetime.now())
))
except Exception as e:
self.logger.error(f"Duyuru kaydetme hatası: {str(e)}")
continue
# Vergi takvimini güncelle
if updates['calendar']:
for tax_event in updates['calendar']:
try:
self.db.execute_query("""
INSERT INTO tax_calendar (tax_type, deadline_date, description, source)
VALUES (%s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
description = VALUES(description),
updated_at = CURRENT_TIMESTAMP
""", (
tax_event['tax_type'],
tax_event['deadline_date'],
tax_event.get('description', ''),
tax_event.get('source', 'GİB')
))
except Exception as e:
self.logger.error(f"Takvim kaydetme hatası: {str(e)}")
continue
scraper.close()
self.logger.info("✅ Günlük veri güncelleme tamamlandı")
except Exception as e:
self.logger.error(f"❌ Günlük veri güncelleme hatası: {str(e)}")
def send_reminders(self):
"""Zamanlanmış hatırlatmaları gönder"""
try:
if self.bot:
asyncio.create_task(self.bot.send_scheduled_reminders())
self.logger.info("✅ Hatırlatmalar gönderildi")
except Exception as e:
self.logger.error(f"❌ Hatırlatma gönderme hatası: {str(e)}")
def health_check(self):
"""Sistem sağlık kontrolü"""
try:
# Veritabanı kontrolü
self.db.execute_query("SELECT 1")
# Bot durumu kontrolü
if not self.bot:
self.logger.warning("⚠️ Bot bağlantısı kopuk")
self.logger.info("✅ Sistem sağlık kontrolü başarılı")
except Exception as e:
self.logger.error(f"❌ Sistem sağlık kontrolü hatası: {str(e)}")
def run_scheduler(self):
"""Zamanlanmış görevleri çalıştır"""
while True:
try:
schedule.run_pending()
time.sleep(60) # Her dakika kontrol et
except KeyboardInterrupt:
self.logger.info("🛑 Zamanlayıcı durduruldu")
break
except Exception as e:
self.logger.error(f"❌ Zamanlayıcı hatası: {str(e)}")
time.sleep(60)
def run(self):
"""Ana uygulama çalıştır"""
try:
self.logger.info("🚀 Vergi Hatırlatıcı Bot başlatılıyor...")
# Bot'u başlat
if not self.initialize_bot():
self.logger.error("❌ Bot başlatılamadı!")
return
# Zamanlanmış görevleri ayarla
self.schedule_tasks()
# İlk veri güncellemeyi yap
self.daily_data_update()
# Zamanlayıcıyı ayrı thread'de çalıştır
scheduler_thread = Thread(target=self.run_scheduler, daemon=True)
scheduler_thread.start()
self.logger.info("✅ Zamanlayıcı thread'i başlatıldı")
# Bot'u çalıştır
self.logger.info("🤖 Telegram Bot çalıştırılıyor...")
self.logger.info(f"Bot kullanıma hazır: @VergiHatirlaticiBot")
# Bot'u başlat
self.bot.app.run_polling(
drop_pending_updates=True,
allowed_updates=['message', 'callback_query']
)
except KeyboardInterrupt:
self.logger.info("🛑 Uygulama kullanıcı tarafından durduruldu")
except Exception as e:
self.logger.error(f"❌ Ana uygulama hatası: {str(e)}")
finally:
self.cleanup()
def cleanup(self):
"""Kaynakları temizle"""
try:
if self.bot:
self.bot.scraper.close()
if self.db:
self.db.close_connection()
self.logger.info("✅ Kaynaklar temizlendi")
except Exception as e:
self.logger.error(f"❌ Cleanup hatası: {str(e)}")
def print_startup_info():
"""Başlangıç bilgilerini göster"""
print("=" * 60)
print("🏛️ VERGİ HATIRLATICI BOT")
print("=" * 60)
print("📋 Özellikler:")
print(" • GİB vergi güncellemeleri")
print(" • Otomatik vergi takvimi")
print(" • Hatırlatma sistemi")
print(" • 7/24 çalışma")
print()
print("🔧 Sistem Gereksinimleri:")
print(" • Python 3.8+")
print(" • MySQL 8.0+")
print(" • Internet bağlantısı")
print()
print("📞 Bot Bilgileri:")
print(" • Ad: VergiHatirlaticiBot")
print(" • Link: t.me/VergiHatirlaticiBot")
print("=" * 60)
print()
def main():
"""Ana fonksiyon"""
try:
# Başlangıç bilgilerini göster
print_startup_info()
# Uygulamayı başlat
app = VergiHatirlaticiApp()
app.run()
except Exception as e:
logging.error(f"❌ Program başlatma hatası: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()