Разные ID платежей YooKassa (Telegram Bot)

не понимаю, почему разные идентификаторы платежей

что не так в моем коде?

в логах такая ошибка:

2025-04-14 02:48:54,533 - main - ERROR - Ошибка проверки платежа extend: {'type': 'error', 'id': '0196318e-4ba1-77c8-85fb-913eb5708ec4', 'code': 'not_found', 'description': "Incorrect payment_id. Payment doesn't exist or access denied. Specify the payment ID created in your store.", 'parameter': 'payment_id'}

в БД тот самый payment_id, который нужен для проверки, в логах ЮКассы тот же payment_id, что и в БД. Не понимаю, где ошибка

@router.message(Command(commands=['extend']))
async def extend_key_handler(message: types.Message):
    user_id = message.from_user.id
    try:
        # 1. Получаем текущий список клиентов из X-UI
        inbound_info = await asyncio.to_thread(
            xui_api.get_inbound_info,
            INBOUND_ID
        )

        if not inbound_info.get('success'):
            await message.answer("⚠️ Не удалось проверить ключи. Попробуйте позже.")
            return

        settings = json.loads(inbound_info['obj']['settings'])
        xui_clients = {client['id']: client for client in settings.get('clients', [])}

        # 2. Получаем ключи пользователя из базы
        db_keys = await db.get_user_keys(user_id)

        # 3. Фильтруем активные ключи (есть в X-UI и не истек срок)
        current_time = int(datetime.now().timestamp() * 1000)
        active_keys = []

        for key in db_keys:
            client = xui_clients.get(key['uuid'])
            if client and client['expiryTime'] > current_time:
                active_keys.append({
                    **key,
                    'expiry_time': client['expiryTime']  # Используем актуальное время из X-UI
                })

        if not active_keys:
            await message.answer(
                "У вас нет активных ключей для продления.\n"
                "Для покупки нового ключа нажмите /buy"
            )
            return

        # 4. Создаем клавиатуру с выбором ключей
        keyboard = []
        for key in active_keys:
            expiry_date = datetime.fromtimestamp(key['expiry_time'] / 1000).strftime('%d.%m.%Y')
            days_left = (datetime.fromtimestamp(key['expiry_time'] / 1000) - datetime.now()).days
            keyboard.append([
                InlineKeyboardButton(
                    text=f"Ключ до {expiry_date} ({days_left} дней осталось)",
                    callback_data=f"extend_{key['key_id']}"
                )
            ])

        reply_markup = InlineKeyboardMarkup(inline_keyboard=keyboard)
        await message.answer("Выберите ключ для продления:", reply_markup=reply_markup)

    except Exception as e:
        logger.error(f"Ошибка в extend_key_handler: {str(e)}")
        await message.answer("⚠️ Произошла ошибка. Попробуйте позже.")


@router.callback_query(lambda c: c.data.startswith('extend_'))
async def process_extend_callback(callback: types.CallbackQuery):
    try:
        key_id = int(callback.data.split('_')[1])
        user_id = callback.from_user.id

        # Проверяем ключ в X-UI
        inbound_info = await asyncio.to_thread(xui_api.get_inbound_info, INBOUND_ID)
        if not inbound_info.get('success'):
            await callback.answer("Ошибка проверки ключа", show_alert=True)
            return

        settings = json.loads(inbound_info['obj']['settings'])
        clients = {c['id']: c for c in settings.get('clients', [])}

        async with db.pool.acquire() as conn:
            # Получаем ключ из базы
            key = await conn.fetchrow(
                "SELECT * FROM user_keys WHERE key_id = $1 AND user_id = $2",
                key_id, user_id
            )

            if not key:
                await callback.answer("Ключ не найден", show_alert=True)
                return

            # Проверяем активность ключа
            client = clients.get(key['uuid'])
            if not client or client['expiryTime'] <= int(datetime.now().timestamp() * 1000):
                await callback.answer("Ключ неактивен или истёк", show_alert=True)
                return

            # Создаем платеж с уникальным idempotence_key
            idempotence_key = str(uuid.uuid4())
            try:
                payment = Payment.create({
                    "amount": {
                        "value": PRICE,
                        "currency": "RUB"
                    },
                    "confirmation": {
                        "type": "redirect",
                        "return_url": "https://t.me/your_bot"
                    },
                    "capture": True,
                    "metadata": {
                        "user_id": user_id,
                        "key_id": key_id,
                        "action": "extend"
                    },
                    "description": f"Продление VPN на {SUBSCRIPTION_DAYS} дней"
                }, idempotence_key)

                payment_url = payment.confirmation.confirmation_url
                payment_id = payment.id

                # Сохраняем платеж в базу
                await conn.execute(
                    "INSERT INTO key_extensions (user_id, key_id, payment_id, status) VALUES ($1, $2, $3, 'pending')", user_id,
                    key_id, payment_id
                )

                # Отправляем пользователю кнопки
                markup = InlineKeyboardMarkup(inline_keyboard=[
                    [InlineKeyboardButton(text="? Оплатить", url=payment_url)],
                    [InlineKeyboardButton(text="? Проверить", callback_data=f"check_extend_{payment_id}")]
                ])

                await callback.message.edit_text(
                    f"? Оплата продления на {SUBSCRIPTION_DAYS} дней\n"
                    f"Сумма: {PRICE} руб\n\n"
                    "Нажмите кнопку ниже для оплаты:",
                    reply_markup=markup
                )
                await callback.answer()

            except Exception as e:
                logger.error(f"Ошибка создания платежа: {str(e)}")
                await callback.answer("Ошибка при создании платежа", show_alert=True)

    except Exception as e:
        logger.error(f"Ошибка в process_extend_callback: {str(e)}")
        await callback.answer("Ошибка обработки запроса", show_alert=True)


@router.callback_query(lambda c: c.data.startswith('check_extend_'))
async def check_extend_payment(callback: types.CallbackQuery):
    payment_id = callback.data.split('_')[2]
    user_id = callback.from_user.id

    try:
        # Добавляем задержку перед проверкой
        await asyncio.sleep(3)

        # Получаем информацию о платеже
        try:
            payment = Payment.find_one(payment_id)
            if not payment:
                raise ValueError("Платеж не найден")
        except Exception as e:
            logger.error(f"Ошибка получения платежа {payment_id}: {str(e)}")
            await callback.answer("Платеж не найден. Попробуйте позже.", show_alert=True)
            return

        # Обрабатываем разные статусы платежа
        if payment.status == 'succeeded':
            async with db.pool.acquire() as conn:
                # Проверяем, не обработан ли уже платеж
                extension = await conn.fetchrow(
                    "SELECT * FROM key_extensions WHERE payment_id = $1 AND status = 'pending' FOR UPDATE",
                    payment_id
                )
                if not extension:
                    await callback.answer("Этот платеж уже был обработан", show_alert=True)
                    return

                # Получаем ключ
                key = await conn.fetchrow(
                    "SELECT * FROM user_keys WHERE key_id = $1 AND user_id = $2",
                    extension['key_id'], user_id
                )
                if not key:
                    await callback.answer("Ключ не найден", show_alert=True)
                    return

                # Обновляем срок действия
                new_expiry = int((datetime.now() + timedelta(days=SUBSCRIPTION_DAYS)).timestamp() * 1000)

                # Обновляем X-UI
                inbound_info = await asyncio.to_thread(xui_api.get_inbound_info, INBOUND_ID)
                settings = json.loads(inbound_info['obj']['settings'])

                for client in settings['clients']:
                    if client['id'] == key['uuid']:
                        client['expiryTime'] = new_expiry
                        break

                await asyncio.to_thread(
                    xui_api.update_inbound,
                    INBOUND_ID,
                    {
                        "settings": json.dumps(settings),
                        "streamSettings": inbound_info['obj']['streamSettings']
                    }
                )

                # Обновляем базу данных
                await conn.execute(
                    "UPDATE user_keys SET expiry_time = $1 WHERE key_id = $2",
                    new_expiry, key['key_id']
                )
                await conn.execute(
                    "UPDATE key_extensions SET status = 'completed' WHERE payment_id = $1",
                    payment_id
                )

                # Уведомляем пользователя
                expiry_date = datetime.fromtimestamp(new_expiry / 1000).strftime('%d.%m.%Y')
                await callback.message.edit_text(
                    f"✅ Ключ продлен до {expiry_date}",
                    reply_markup=None
                )
                await callback.answer()

        elif payment.status == 'pending':
            await callback.answer("Платеж в обработке. Попробуйте позже.", show_alert=True)
        else:
            await callback.answer("Платеж не был завершен", show_alert=True)

    except Exception as e:
        logger.error(f"Ошибка проверки платежа: {str(e)}")
        await callback.answer("Ошибка при проверке платежа", show_alert=True)

Ответы (0 шт):