mirror of
https://github.com/olegvodyanov/docbot.git
synced 2025-12-20 08:07:04 +03:00
map payments
This commit is contained in:
parent
6a69c0d4d2
commit
852c924383
@ -1,15 +1,38 @@
|
|||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
from core.config import settings
|
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():
|
def setup_logging():
|
||||||
"""
|
"""
|
||||||
Инициализирует логирование для всего приложения.
|
Инициализирует логирование для всего приложения.
|
||||||
Конфигурирует консольный и файловый логгеры с ротацией.
|
Конфигурирует консольный и файловый логгеры с ротацией.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Используем наш кастомный класс логгера
|
||||||
|
logging.setLoggerClass(ExtendedLogger)
|
||||||
|
|
||||||
# Получаем уровень логирования из настроек, по умолчанию INFO
|
# Получаем уровень логирования из настроек, по умолчанию INFO
|
||||||
level_name = settings.LOGGING_LEVEL if hasattr(settings, 'LOGGING_LEVEL') else 'INFO'
|
level_name = settings.LOGGING_LEVEL if hasattr(settings, 'LOGGING_LEVEL') else 'INFO'
|
||||||
log_level = getattr(logging, level_name, logging.INFO)
|
log_level = getattr(logging, level_name, logging.INFO)
|
||||||
|
|||||||
@ -30,3 +30,36 @@ async def get_not_mapped_payments() -> Sequence[Row[Tuple[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 AsyncSessionLocal() as session:
|
||||||
async with session.begin():
|
async with session.begin():
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
from telegram.ext import (
|
from telegram.ext import (
|
||||||
ContextTypes
|
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 docbot.services.session_service import get_sessions_awaiting_payments
|
||||||
from core.logging import logger
|
from core.logging import logger
|
||||||
|
from sqlalchemy import Row
|
||||||
|
from db.models import PaymentsRegistered, Sessions
|
||||||
|
|
||||||
# Сопоставляем оплаты, которые пришли от продамуса с сессиями, по которым ещё не было оплаты
|
# Сопоставляем оплаты, которые пришли от продамуса с сессиями, по которым ещё не было оплаты
|
||||||
async def map_payments(context: ContextTypes.DEFAULT_TYPE) -> None:
|
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:
|
for session in sessions_awaiting_payments:
|
||||||
logger.info(f"Неоплаченная сессия: {session.Sessions.code}")
|
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