mirror of
https://github.com/olegvodyanov/docbot.git
synced 2025-12-19 23:57:05 +03:00
map payments
This commit is contained in:
parent
6a69c0d4d2
commit
852c924383
@ -1,15 +1,38 @@
|
||||
import logging
|
||||
import sys
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import Sequence
|
||||
|
||||
from core.config import settings
|
||||
|
||||
class ExtendedLogger(logging.Logger):
|
||||
"""Расширенный логгер с дополнительными методами для форматирования."""
|
||||
|
||||
def list(self, message: str, items: Sequence, limit: int | None = 20) -> None:
|
||||
"""
|
||||
Логирует сообщение и список элементов в читаемом виде.
|
||||
Пример:
|
||||
logger.list("Common codes", ["A1", "B2", "C3"])
|
||||
"""
|
||||
if not items:
|
||||
formatted = "(empty)"
|
||||
else:
|
||||
items = [str(i) for i in items]
|
||||
if limit and len(items) > limit:
|
||||
formatted = ", ".join(items[:limit]) + f" ... (+{len(items) - limit} more)"
|
||||
else:
|
||||
formatted = ", ".join(items)
|
||||
self.info(f"{message}: {formatted}")
|
||||
|
||||
def setup_logging():
|
||||
"""
|
||||
Инициализирует логирование для всего приложения.
|
||||
Конфигурирует консольный и файловый логгеры с ротацией.
|
||||
"""
|
||||
|
||||
# Используем наш кастомный класс логгера
|
||||
logging.setLoggerClass(ExtendedLogger)
|
||||
|
||||
# Получаем уровень логирования из настроек, по умолчанию INFO
|
||||
level_name = settings.LOGGING_LEVEL if hasattr(settings, 'LOGGING_LEVEL') else 'INFO'
|
||||
log_level = getattr(logging, level_name, logging.INFO)
|
||||
|
||||
@ -29,4 +29,37 @@ async def get_not_mapped_payments() -> Sequence[Row[Tuple[PaymentsRegistered]]]
|
||||
select(PaymentsRegistered)
|
||||
)
|
||||
|
||||
return result.all()
|
||||
return result.all()
|
||||
|
||||
|
||||
async def update_payment_and_session(code: str) -> bool:
|
||||
"""
|
||||
Updates both PaymentsRegistered and Sessions in a single transaction.
|
||||
Returns True if both updates succeed, False if any update fails.
|
||||
Automatically rolls back if any error occurs.
|
||||
"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
async with session.begin():
|
||||
try:
|
||||
# Update PaymentsRegistered
|
||||
payment_result = await session.execute(
|
||||
select(PaymentsRegistered).where(PaymentsRegistered.code == code)
|
||||
)
|
||||
payment = payment_result.scalar_one_or_none()
|
||||
if not payment or payment.mapped is not None:
|
||||
return False
|
||||
payment.mapped = True
|
||||
|
||||
# Update Sessions
|
||||
session_result = await session.execute(
|
||||
select(Sessions).where(Sessions.code == code)
|
||||
)
|
||||
session_rec = session_result.scalar_one_or_none()
|
||||
if not session_rec or session_rec.paid_at is not None:
|
||||
return False
|
||||
session_rec.paid_at = datetime.utcnow()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Transaction failed: {str(e)}")
|
||||
raise # This will trigger rollback
|
||||
|
||||
@ -101,7 +101,7 @@ async def get_session_info(code: str) -> dict | None:
|
||||
}
|
||||
|
||||
|
||||
async def get_sessions_awaiting_payments() -> Sequence[Row[Sessions]]:
|
||||
async def get_sessions_awaiting_payments() -> Sequence[Row[Sessions]] | bool:
|
||||
async with AsyncSessionLocal() as session:
|
||||
async with session.begin():
|
||||
result = await session.execute(
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
from telegram.ext import (
|
||||
ContextTypes
|
||||
)
|
||||
from docbot.services.payments_service import get_not_mapped_payments
|
||||
from typing import Sequence, List
|
||||
from docbot.services.payments_service import get_not_mapped_payments, update_payment_and_session
|
||||
from docbot.services.session_service import get_sessions_awaiting_payments
|
||||
from core.logging import logger
|
||||
from sqlalchemy import Row
|
||||
from db.models import PaymentsRegistered, Sessions
|
||||
|
||||
# Сопоставляем оплаты, которые пришли от продамуса с сессиями, по которым ещё не было оплаты
|
||||
async def map_payments(context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
@ -15,3 +18,20 @@ async def map_payments(context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
|
||||
for session in sessions_awaiting_payments:
|
||||
logger.info(f"Неоплаченная сессия: {session.Sessions.code}")
|
||||
|
||||
np_codes = [payment.PaymentsRegistered.code for payment in not_mapped_payments]
|
||||
sa_codes = [session.Sessions.code for session in sessions_awaiting_payments]
|
||||
|
||||
common_codes: List[str] = list(set(np_codes).intersection(sa_codes))
|
||||
|
||||
if common_codes:
|
||||
logger.list("Common codes", common_codes, None)
|
||||
|
||||
# Update the database for matching codes (example using raw SQL)
|
||||
for code in common_codes:
|
||||
logger.info(f"Updating payment and session for {code}")
|
||||
success = await update_payment_and_session(code)
|
||||
if not success:
|
||||
logger.error(f"Failed to update payment and session for {code}")
|
||||
else:
|
||||
logger.info("Совпадения не найдены!")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user