From 3f62af27b704b4454ec4ae66ecf30f6d7e4c6e34 Mon Sep 17 00:00:00 2001 From: Vladless Date: Sat, 14 Feb 2026 22:11:45 +0300 Subject: [PATCH] indempotence of cash registers/ fixed regime of countries --- handlers/keys/key_mode/key_country_mode.py | 2 +- handlers/payments/freekassa/freekassa_pay.py | 26 +++++++------------- handlers/payments/kassai/webhook.py | 4 ++- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/handlers/keys/key_mode/key_country_mode.py b/handlers/keys/key_mode/key_country_mode.py index ac2b76db..dca7a80b 100644 --- a/handlers/keys/key_mode/key_country_mode.py +++ b/handlers/keys/key_mode/key_country_mode.py @@ -673,7 +673,7 @@ async def finalize_key_creation( session=session, plan=tariff_id, is_trial=is_trial, - total_gb_value=traffic_limit_gb, + total_traffic_limit_bytes=traffic_limit_bytes, device_limit_value=device_limit, ) diff --git a/handlers/payments/freekassa/freekassa_pay.py b/handlers/payments/freekassa/freekassa_pay.py index 4055b735..a1dd823e 100644 --- a/handlers/payments/freekassa/freekassa_pay.py +++ b/handlers/payments/freekassa/freekassa_pay.py @@ -9,7 +9,6 @@ from aiogram.fsm.state import State, StatesGroup from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup from aiogram.utils.keyboard import InlineKeyboardBuilder from aiohttp import web -from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession from config import ( @@ -22,11 +21,12 @@ from database import ( add_user, async_session_maker, check_user_exists, + clear_temporary_data, get_key_count, + get_payment_by_payment_id, get_temporary_data, update_balance, ) -from database.models import Payment from handlers.buttons import BACK, PAY_2 from handlers.payments.utils import send_payment_success_notification from handlers.texts import DEFAULT_PAYMENT_MESSAGE, ENTER_SUM, PAYMENT_OPTIONS @@ -234,28 +234,20 @@ async def freekassa_webhook(request: web.Request): return web.Response(status=400, text="Invalid parameter format") async with async_session_maker() as session: - recent_time = datetime.utcnow() - timedelta(minutes=1) - result = await session.execute( - select(Payment).where( - and_( - Payment.tg_id == tg_id_int, - Payment.amount == amount_float, - Payment.status == "success", - Payment.created_at >= recent_time, - ) - ) - ) - duplicate = result.scalar_one_or_none() - if duplicate: + existing = await get_payment_by_payment_id(session, merchant_order_id) + if existing and existing.get("status") == "success": logger.warning( - f"[Freekassa] Повторный webhook. Платёж уже обработан: tg_id={tg_id_int}, amount={amount_float}" + f"[Freekassa] Повторный webhook. Платёж уже обработан: order_id={merchant_order_id}" ) return web.Response(text="YES") await update_balance(session, tg_id_int, amount_float) await send_payment_success_notification(tg_id_int, amount_float, session) - await add_payment(session, tg_id_int, amount_float, "freekassa") + await add_payment( + session, tg_id_int, amount_float, "freekassa", payment_id=merchant_order_id + ) + await clear_temporary_data(session, tg_id_int) logger.info(f"Payment processed successfully. User: {tg_id_int}, Amount: {amount_float}") return web.Response(text="YES") diff --git a/handlers/payments/kassai/webhook.py b/handlers/payments/kassai/webhook.py index 6c1f6dcb..2cb182dc 100644 --- a/handlers/payments/kassai/webhook.py +++ b/handlers/payments/kassai/webhook.py @@ -77,7 +77,9 @@ async def kassai_webhook(request: web.Request): if payment.get("status") == "success": logger.info(f"KassaAI: платёж {order_id} уже обработан") return web.Response(text=KASSAI_WEBHOOK_RESPONSE) - ok = await update_payment_status(session=session, internal_id=int(payment["id"]), new_status="success") + ok = await update_payment_status( + session=session, internal_id=int(payment["id"]), new_status="success" + ) if not ok: logger.error(f"KassaAI: не удалось обновить статус платежа {order_id}") return web.Response(status=500)