Python-telegram-bot inlineKeyboardButton вовзращает ошибку при нажатии

Использую Python Telegram Bot последней версии, логика такая, что есть рандомный пользователь который может написать в бота и сформировать определенную заявку, где в зависимости от "Проекта" она может перенаправляться различным Approver. Интересно, что если тот кто пишет в бота и является Approver1 то в рамках его чата с ботом все работает исправно ( не срабатывает условие правда elif decision == "approve4":, но с этим я смогу разобраться), а если же пишет рандомный пользователь и формирует заявку, то Approver 1 получает её и при нажатии на Approve я получаю ошибку:

Traceback (most recent call last):
  File "/home/bot/.local/lib/python3.10/site-packages/telegram/ext/_application.py", line 1197, in __create_task_callback
    return await coroutine  # type: ignore[misc]
  File "/home/bot/.local/lib/python3.10/site-packages/telegram/ext/_handlers/basehandler.py", line 157, in handle_update
    return await self.callback(update, context)
  File "/home/bot/qubot/newbot.py", line 223, in keyboard_callback
    await proceed_with_decision(update, context, state)
  File "/home/bot/qubot/newbot.py", line 259, in proceed_with_decision
    approval_message = f"Согласующий {next_stage - APPROVAL1 + 1}\n\n" + context.user_data['final_response']
KeyError: 'final_response'

Вот мой код, возможно неправильно обрабатываю в handler-ах нажатие на кнопки, но не могу понять в чём же проблема:

import logging
import sqlite3
from datetime import datetime
import pytz
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, ConversationHandler, MessageHandler, filters
from telegram.constants import ParseMode
from telegram.request import HTTPXRequest

# Enable logging
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO)
logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)

# Define states for the conversation
CHOOSING, CONFIRMATION, AMOUNT, DESCRIPTION, SUMM, APPROVAL1, APPROVAL2, APPROVAL3, APPROVAL4, FINAL_APPROVAL, REJECTION_COMMENT = range(11)


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    if update.message.chat.type != "private":
        return ConversationHandler.END
    keyboard = [
        [
            InlineKeyboardButton("Проект ?️", callback_data="project"),
            InlineKeyboardButton("Цех ?", callback_data="workshop"),
            InlineKeyboardButton("Офис ?", callback_data="office"),
        ]
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    welcome_message = (
        "Вас приветствует telegram бот MDA distribution! ?\n"
        "Заполните, пожалуйста, вашу заявку. Для начала выберите направление:\n"
    )
    await update.message.reply_text(welcome_message, reply_markup=reply_markup)
    return CHOOSING

async def project_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    query = update.callback_query
    await query.answer()
    context.user_data['project'] = query.data
    keyboard = [
        [InlineKeyboardButton("1️⃣ ? Внутрискладская транспортировка", callback_data="warehouse_transport")],
        [InlineKeyboardButton("2️⃣ ? Доставка материалов", callback_data="materials")],
        [InlineKeyboardButton("3️⃣ ? Доставка материалов по межгороду", callback_data="materials_intercity")],
        [InlineKeyboardButton("4️⃣ ? Курьерские услуги", callback_data="courier_services")],
        [InlineKeyboardButton("5️⃣ ? Транспортные услуги", callback_data="transport_services")],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    await query.message.edit_text("Выберите статью:", reply_markup=reply_markup)
    return CONFIRMATION

async def confirmation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    query = update.callback_query
    await query.answer()
    context.user_data['category'] = query.data
    await query.message.edit_text("Введите название сделки:")
    return AMOUNT

async def amount_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    context.user_data['deal_text'] = update.message.text
    await update.message.reply_text("Введите сумму сделки:")
    return DESCRIPTION

async def description_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    amount_text = update.message.text
    try:
        context.user_data['amount'] = format_amount(amount_text)
    except ValueError:
        await update.message.reply_text("Вы не ввели сумму ( принимаются только числа), напишите ОК и попробуйте снова")
        return AMOUNT
    await update.message.reply_text("Введите описание сделки:")
    return SUMM

async def summarize_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    context.user_data['description'] = update.message.text
    project = CALLBACK_TRANSLATIONS.get(context.user_data.get('project'), 'Not provided')
    category = CALLBACK_TRANSLATIONS.get(context.user_data.get('category'), 'Not provided')
    deal_text = context.user_data.get('deal_text', 'Not provided')
    amount = context.user_data.get('amount', 'Not provided')
    description = context.user_data.get('description', 'Not provided')
    dt = format_datetime(update.message.date)

    final_response = (
        f"<b>Заявка от:</b> <i>{update.message.from_user.first_name}</i>\n"
        f"<b>Дата:</b> <i>{dt}</i>\n"
        f"<b>Направление:</b> <i>{project}</i>\n"
        f"<b>Статья:</b> <i>{category}</i>\n"
        f"<b>Наименование сделки:</b> <i>{deal_text}</i>\n"
        f"<b>Сумма:</b> <i>{amount}</i>\n"
        f"<b>Описание:</b> <i>{description}</i>"
    )
    context.user_data['final_response'] = final_response

    approval_message = "Согласующий 1\n\n" + final_response
    approval_keyboard = [
        [InlineKeyboardButton("✅ Принять", callback_data="approve1")],
        [InlineKeyboardButton("? Отклонить", callback_data="reject1")],
    ]
    approval_markup = InlineKeyboardMarkup(approval_keyboard)

    logger.info("Context user data before sending approval message: %s", context.user_data)
    logger.info("Sending approval message to approver %s", APPROVER1_ID)

    await context.bot.send_message(chat_id=APPROVER1_ID, text=approval_message, reply_markup=approval_markup, parse_mode=ParseMode.HTML)
    return APPROVAL1

async def keyboard_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    decision = query.data

    await query.answer()
    await query.edit_message_reply_markup(reply_markup=None)  # Hide buttons after approval

    # Logging context.user_data for debugging
    logger.info("Context user data in keyboard_callback: %s", context.user_data)

    state = None
    if decision.startswith("approve"):
        state = int(decision.replace("approve", "")) + APPROVAL1
    elif decision.startswith("reject"):
        context.user_data['approver'] = query.from_user.id
        await query.message.reply_text("Введите комментарий для отказа:")
        state = REJECTION_COMMENT

    if state is not None:
        context.user_data['decision'] = decision
        await proceed_with_decision(update, context, state)



async def proceed_with_decision(update: Update, context: ContextTypes.DEFAULT_TYPE, state: int) -> int:
    decision = context.user_data.get('decision', None)
    project = context.user_data.get('project', None)
    next_approver = None
    next_stage = None

    if state == REJECTION_COMMENT:
        await update.message.reply_text("Введите комментарий для отказа:")
        return REJECTION_COMMENT

    if decision == "approve1":
        if project == "workshop":
            next_approver = APPROVER2_ID
            next_stage = APPROVAL2
        elif project == "project":
            next_approver = APPROVER3_ID
            next_stage = APPROVAL3
        else:
            next_approver = APPROVER4_ID
            next_stage = APPROVAL4

    elif decision == "approve4":
        amount = int(context.user_data.get('amount', '0').replace(" ", "").replace("₸", "").strip())
        if amount >= 100000:
            next_approver = APPROVER5_ID
            next_stage = FINAL_APPROVAL
        else:
            final_response = context.user_data['final_response'] + "\n\n✅ ЗАЯВКА ПРИНЯТА"
            await context.bot.send_message(chat_id=GROUP_CHAT_ID, text=final_response, parse_mode=ParseMode.HTML)
            return ConversationHandler.END

    if next_approver and next_stage:
        approval_message = f"Согласующий {next_stage - APPROVAL1 + 1}\n\n" + context.user_data['final_response']
        approval_keyboard = [
            [InlineKeyboardButton("✅ Принять", callback_data=f"approve{next_stage - APPROVAL1 + 1}")],
            [InlineKeyboardButton("? Отклонить", callback_data=f"reject{next_stage - APPROVAL1 + 1}")],
        ]
        approval_markup = InlineKeyboardMarkup(approval_keyboard)

        logger.info("Sending approval message to approver %s", next_approver)
        await context.bot.send_message(chat_id=next_approver, text=approval_message, reply_markup=approval_markup, parse_mode=ParseMode.HTML)
        return next_stage

async def rejection_comment(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    comment_text = update.message.text
    context.user_data['rejection_comment'] = comment_text
    approver = context.user_data['approver']

    final_response = context.user_data['final_response'] + f"\n\n? ЗАЯВКА ОТКЛОНЕНА\n\n<b>Комментарий:</b> <i>{comment_text}</i>"
    await context.bot.send_message(chat_id=GROUP_CHAT_ID, text=final_response, parse_mode=ParseMode.HTML)
    await context.bot.send_message(chat_id=approver, text="Комментарий для отказа принят и заявка отправлена в группу.", parse_mode=ParseMode.HTML)

    # Save the rejected request to the database with the comment
    context.user_data['comment'] = comment_text
    logger.info("Saving request to database with context user data: %s", context.user_data)
    save_request(context.user_data)

    return ConversationHandler.END

def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    logger.error(msg="Exception while handling an update:", exc_info=context.error)


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("Используйте /start для начала работы с ботом.")

def main() -> None:
    init_db()

    request = HTTPXRequest(connect_timeout=60.0, read_timeout=60.0)
    application = Application.builder().token("token").request(request).concurrent_updates(True).build()

    conv_handler = ConversationHandler(
        entry_points=[CommandHandler("start", start)],
        states={
            CHOOSING: [CallbackQueryHandler(project_choice, block=False)],
            CONFIRMATION: [CallbackQueryHandler(confirmation, block=False)],
            AMOUNT: [MessageHandler(filters.TEXT & ~filters.COMMAND, amount_input)],
            DESCRIPTION: [MessageHandler(filters.TEXT & ~filters.COMMAND, description_input)],
            SUMM: [MessageHandler(filters.TEXT & ~filters.COMMAND, summarize_input, block=False)],
            REJECTION_COMMENT: [MessageHandler(filters.TEXT & ~filters.COMMAND, rejection_comment, block=False)],
        },
        fallbacks=[],
    )
    
    application.add_error_handler(error_handler)
    application.add_handler(conv_handler)
    application.add_handler(CommandHandler("help", help_command, block=False))
    application.add_handler(CallbackQueryHandler(keyboard_callback, block=False))
    application.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == "__main__":
    main()

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