Files
vpn-control-panel/app/scheduler/tasks/send_reminders.py
smolkik-code 7c7c88621d Initial commit: VPN Control Panel
- FastAPI REST API with JWT auth
- aiogram 3 Telegram bot with admin middleware
- APScheduler daily tasks (expiry, reminders, revoke, sync)
- SQLAlchemy 2 async ORM with Alembic migrations
- Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs)
- VPN provider abstraction with MockProvider
- Stats service with revenue/subscription analytics
- Docker Compose (PostgreSQL + Redis + app)
- Healthcheck endpoint
2026-07-05 17:50:11 +07:00

49 lines
1.7 KiB
Python

from datetime import datetime, timedelta, timezone
from loguru import logger
from app.database import async_session_factory
from app.models.payment import PaymentStatus
from app.repositories.notification import NotificationRepository
from app.repositories.payment import PaymentRepository
from app.repositories.tariff import TariffRepository
from app.repositories.user import UserRepository
from app.services.notification import NotificationService
async def send_reminders() -> None:
logger.info("[Scheduler] Sending subscription expiry reminders")
async with async_session_factory() as session:
payment_repo = PaymentRepository(session)
tariff_repo = TariffRepository(session)
user_repo = UserRepository(session)
notification_service = NotificationService(
NotificationRepository(session), user_repo
)
confirmed = await payment_repo.get_by_status(PaymentStatus.CONFIRMED)
now = datetime.now(timezone.utc)
reminders_sent = 0
for payment in confirmed:
tariff = await tariff_repo.get(payment.tariff_id)
if tariff is None:
continue
start = payment.paid_at or payment.created_at
end = start + timedelta(days=tariff.duration_days)
remaining = (end - now).days
result = await notification_service.send_expiry_reminder(
user_id=payment.user_id,
remaining_days=remaining,
tariff_name=tariff.name,
)
if result is not None:
reminders_sent += 1
logger.info(
"[Scheduler] Sent {} expiry reminders", reminders_sent
)