skip to Main Content

We have 3 operators and I want them to be busy if they entered to chat with someone. When chat is ended with client, operator will be free for other clients and can chat. I accidentally removed the part of code where operator after entering to chat will become busy (is_available=False) and after ending chat becomes available (is_available=True).

Stack: Django, python-telegram-bot

models.py:

from django.db import models

class CustomUser(models.Model):
    tg_id = models.IntegerField()
    tg_first_name = models.CharField(max_length=500, blank=True, null=True)
    tg_username = models.CharField(max_length=500, blank=True, null=True)
    name = models.CharField(max_length=500, blank=True, null=True)
    choosen_lang = models.CharField(max_length=50, blank=True, null=True)
    phone_number = models.CharField(max_length=50, blank=True, null=True)
    status = models.CharField(max_length=500, blank=True, null=True)
    is_operator = models.BooleanField(default=False, blank=True, null=True)
    is_supervisor = models.BooleanField(default=False, blank=True, null=True)
    is_available = models.BooleanField(default=True, blank=True, null=True)

    def __str__(self):
        return self.tg_first_name
    
class Chat(models.Model):
    is_closed = models.BooleanField(default=False)
    client = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='client_of_chat', blank=True, null=True) 
    operator = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='operator_of_chat', blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True)

class Appeal(models.Model):
    custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
    body = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.body

buttons.py

from main.models import *

lang_btn = [
    ["O'zbek"],
    ["Русский"],
]

main_page_btn_uz = [
    ["Savol"],
    ["Shikoyat"],
]

main_page_btn_ru = [
    ["Вопрос"],
    ["Жалоба"],
]

chat_btn_uz = [
    ['Onlayn opertor'],
]

chat_btn_ru = [
    ['Онлайн-оператор'],
]

main_btn_operator = [
    ["Открытие чаты"],
    ["Закрытие чаты"],
]

close_chat_btn_ru = [
    ['✅Завершить чат'],
]

close_chat_btn_uz = [
    ['✅Chatni yopish'],
]

bot.py

# internal libs
import os, sys

# django setup
sys.dont_write_bytecode = True
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

import django
django.setup()

from django.db.models import Q
from test_app.models import *

# logging libs
import logging

# telegram api libs
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
    Application,
    CommandHandler,
    ContextTypes,
    ConversationHandler,
    MessageHandler,
    filters,
    CallbackQueryHandler,
)

import buttons

# 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__)

# phases
PHASE_LANG_CHOOSING, PHASE_SHARE_CONTACT, PHASE_MAIN_PAGE_UZ, PHASE_MAIN_PAGE_RU, PHASE_MAIN_OPERATOR, PHASE_CLIENT_CHAT, PHASE_OPERATOR_CHAT, PHASE_APPEAL = range(8)

# markups
markup_main_operator = ReplyKeyboardMarkup(buttons.main_btn_operator, one_time_keyboard=True, resize_keyboard=True)
markup_main_uz = ReplyKeyboardMarkup(buttons.main_page_btn_uz, one_time_keyboard=True, resize_keyboard=True)
markup_main_ru = ReplyKeyboardMarkup(buttons.main_page_btn_ru, one_time_keyboard=True, resize_keyboard=True)
markup_lang = ReplyKeyboardMarkup(buttons.lang_btn, one_time_keyboard=True, resize_keyboard=True)
markup_close_chat_uz = ReplyKeyboardMarkup(buttons.close_chat_btn_uz, one_time_keyboard=True, resize_keyboard=True)
markup_close_chat_ru = ReplyKeyboardMarkup(buttons.close_chat_btn_ru, one_time_keyboard=True, resize_keyboard=True)
markup_сhat_uz = ReplyKeyboardMarkup(buttons.chat_btn_uz, one_time_keyboard=True, resize_keyboard=True)
markup_сhat_ru = ReplyKeyboardMarkup(buttons.chat_btn_ru, one_time_keyboard=True, resize_keyboard=True)
# markup_done = ReplyKeyboardMarkup([[KeyboardButton("✅Завершить чат")]], one_time_keyboard=True, resize_keyboard=True)
markup_phone_ru = ReplyKeyboardMarkup([[KeyboardButton("Отправить", request_contact=True)]], one_time_keyboard=True, resize_keyboard=True)
markup_phone_uz = ReplyKeyboardMarkup([[KeyboardButton("Jo'natish", request_contact=True)]], one_time_keyboard=True, resize_keyboard=True)

# global attrs
ch_id = None
operator = None
client = None
supervisor = None

# starting function
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('start()')
    global operator, client, supervisor

    tg_id = update.message.from_user.id
    check_user = CustomUser.objects.filter(tg_id=tg_id).exists()

    if check_user:
        u = CustomUser.objects.get(tg_id=tg_id)
        if u.is_operator:
            operator = u.tg_id
            await update.message.reply_text(
                "Главнaя страница",
                reply_markup=markup_main_operator,
            )
            return PHASE_MAIN_OPERATOR
        else:
            client = u
            if u.choosen_lang:
                if u.phone_number:
                    if u.choosen_lang == "O'zbek":
                        await update.message.reply_text(
                            "Asosiy sahifa",
                            reply_markup=markup_main_uz,
                        )
                        return PHASE_MAIN_PAGE_UZ
                    await update.message.reply_text(
                        "Главная страница",
                        reply_markup=markup_main_ru,
                    )
                    return PHASE_MAIN_PAGE_RU
                else:
                    if u.choosen_lang == "O'zbek":
                        await update.message.reply_text(
                                "Telefon raqamingizni jo'nating",
                                reply_markup=markup_phone_uz
                            )
                        return PHASE_SHARE_CONTACT
                    else:
                        await update.message.reply_text(
                                "Отправьте номер телефона",
                                reply_markup=markup_phone_ru
                            )
                        return PHASE_SHARE_CONTACT
            else:
                await update.message.reply_text(
                    f"Assalomu alaykum {update.message.from_user.first_name}, xush kelibsiz!n"
                    "Tilni tanlang:nn"
                    f"Здравствуйте {update.message.from_user.first_name}, добро пожаловать!n"
                    "Выберите язык:",
                    reply_markup=markup_lang,
                )
                return PHASE_LANG_CHOOSING
    else:
        u = CustomUser.objects.create(
            tg_id=update.message.from_user.id,
            tg_first_name=update.message.from_user.first_name,
            tg_username=update.message.from_user.username,
        )
        client = u
        await update.message.reply_text(
            f"Assalomu alaykum {update.message.from_user.first_name}, xush kelibsiz!n"
            "Tilni tanlang:nn"
            f"Здравствуйте {update.message.from_user.first_name}, добро пожаловать!n"
            "Выберите язык:",
            reply_markup=markup_lang,
        )
        return PHASE_LANG_CHOOSING

# language choosing and telephone number submission
async def lang_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('lang_choice()')
    u = CustomUser.objects.get(tg_id=update.message.from_user.id)
    u.choosen_lang = update.message.text
    u.save()

    if update.message.text == "O'zbek":
        await update.message.reply_text("Telefon raqamingizni jo'nating", reply_markup=markup_phone_uz)
        return PHASE_SHARE_CONTACT
    elif update.message.text == "Русский":
        await update.message.reply_text("Отправьте номер телефона", reply_markup=markup_phone_ru)
        return PHASE_SHARE_CONTACT

async def get_phone(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('get_phone()')
    u = CustomUser.objects.get(tg_id=update.message.from_user.id)
    u.phone_number = update.message.contact.phone_number
    u.save()

    if u.choosen_lang == "O'zbek":
        await update.message.reply_text(
            "Asosiy sahifa",
            reply_markup=markup_main_uz,
        )
        return PHASE_MAIN_PAGE_UZ
    await update.message.reply_text(
        "Главная страница",
        reply_markup=markup_main_ru,
    )
    return PHASE_MAIN_PAGE_RU

async def get_phone_wrong(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('get_phone_wrong()')
    global client

    if client.choosen_lang == "O'zbek":
        await update.message.reply_text(
            "Iltimos raqamingizni "jo'natish" tugmasi orqali yuboring!",
            reply_markup=markup_phone_uz,
        )
        return PHASE_SHARE_CONTACT
    await update.message.reply_text(
        "Пожалуйста отправьте номер телефона вместо текста!",
        reply_markup=markup_phone_ru,
    )
    return PHASE_SHARE_CONTACT

# main menu for operators
async def open_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('open_chats()')
    return PHASE_MAIN_OPERATOR

async def closed_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('closed_chats()')
    return PHASE_MAIN_OPERATOR

# chat
async def move_to_get_reply(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('move_to_get_reply()')
    global ch_id
    global operator
    query = update.callback_query
    await query.answer()

    # ch_id = query.data
    
    if ch_id is not None:
        created_chat = Chat.objects.get(id=ch_id)
        created_chat.operator = CustomUser.objects.get(tg_id=operator)
        created_chat.save()

        await context.bot.send_message(created_chat.operator.tg_id, 'Чат открыт, напишите ...', reply_markup=markup_close_chat_ru)

        if created_chat.client.choosen_lang == "O'zbek":
            await context.bot.send_message(created_chat.client.tg_id, 'Assalomu alaykum, nima yordam bera olaman?', reply_markup=markup_close_chat_uz)
        else:
            await context.bot.send_message(created_chat.client.tg_id, 'Здравствуйте, чем могу помочь?', reply_markup=markup_close_chat_ru)

        return PHASE_OPERATOR_CHAT
    else:
        await context.bot.send_message(created_chat.operator.tg_id, 'Клиент уже завершил чат.', reply_markup=markup_main_operator)
        return PHASE_MAIN_OPERATOR


async def operator_chat(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('operator_chat()')
    global ch_id
    ch = Chat.objects.get(id=ch_id)
    client_tg = ch.client.tg_id

    await context.bot.send_message(client_tg, update.message.text)
    
    return PHASE_OPERATOR_CHAT

async def lets_chat(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('lets_chat()')
    global ch_id

    created_chat = Chat.objects.create(
        is_closed=False,
        client=CustomUser.objects.get(tg_id=update.message.from_user.id),
    )
    
    ch_id = created_chat.id
    keyboard = [
        [
            InlineKeyboardButton("Присоединиться к чату", callback_data=ch_id),
        ],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    available_operator = CustomUser.objects.filter(is_operator=True, is_available=True).first()

    notification_message = (
        f"<u>Появился новый чат!</u>n"
        f'n'
        f'<b>Имя пользователя:</b> <i>{update.message.from_user.first_name}</i>'
        f'n'
        f'<b>Обрашения:</b> <i>{update.message.text}</i>' 
    )
    if available_operator:
        await context.bot.send_message(available_operator.tg_id, notification_message, reply_markup=reply_markup, parse_mode='HTML')

    if created_chat.client.choosen_lang == "O'zbek":
        await update.message.reply_text("Iltimos, kutib turing! Biz sizni mavjud operator bilan bog'layabmiz.", reply_markup=markup_close_chat_uz,)
    else:
        await update.message.reply_text("Пожалуйста, ожидайте! Мы соединяем Вас со свободным оператором.", reply_markup=markup_close_chat_ru,)
    
    return PHASE_CLIENT_CHAT

async def chat(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('chat()')
    global ch_id

    if ch_id is None:
        await update.message.reply_text("Чат не найден.", reply_markup=markup_main_ru)
        return PHASE_MAIN_PAGE_RU

    try:
        ch = Chat.objects.get(id=ch_id)
    except Chat.DoesNotExist:
        await update.message.reply_text("Чат не найден.", reply_markup=markup_main_ru)
        return PHASE_MAIN_PAGE_RU

    if ch.operator is None:
        await context.bot.send_message(ch.client.tg_id, "Пожалуйста подождите, оператор скоро подключится!")
    else:
        await context.bot.send_message(ch.operator.tg_id, update.message.text)

    return PHASE_CLIENT_CHAT

# question and chat 
async def question(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('question()')
    global client

    if client.choosen_lang == "O'zbek":
        await update.message.reply_text(
            'Bu yerda barcha "Ko'p berildagan savollar" bo'ladi...',
            # reply_markup=markup_сhat_ru,
        )
        await update.message.reply_text(
            'Savollaringiz qoldimi? "Onlayn operator" tugmasini bosing va operator siz bilan bog'lanadi!',
            reply_markup=markup_сhat_ru,
        )
        return PHASE_MAIN_PAGE_UZ
    
    # await update.message.reply_text(
    #         'Здесь будет все "Часто задаваемые вопросы"...',
    #         # reply_markup=markup_сhat_ru,
    #     )

    await update.message.reply_html(
"""
Some text
"""
    )
    await update.message.reply_text(
            'Выше указаны все вопросы и ответы раздела FAQ. Если не нашли ответ, нажмите на кнопку "Онлайн-оператор" и оператор вам ответит!',
            reply_markup=markup_сhat_ru,
        )
    return PHASE_MAIN_PAGE_RU

# appeal
async def appeal(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('appeal()')
    global client

    if client.choosen_lang == "O'zbek":
        update.message.reply_text("Shikoyat mazmunini yozib jo'nating", reply_markup=ReplyKeyboardRemove(),)
        return PHASE_APPEAL

    await update.message.reply_text("Отправьте вашy жалобу", reply_markup=ReplyKeyboardRemove(),)
    return PHASE_APPEAL

async def get_appeal(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('get_appeal()')
    global client

    Appeal.objects.create(
        custom_user = client,
        body = update.message.text
    )

    if client.choosen_lang == "O'zbek":
        update.message.reply_text("Shikoyat yuborildi!", reply_markup=markup_main_uz,)
        return PHASE_MAIN_PAGE_UZ

    await update.message.reply_text("Жалоба принята, спасибо!", reply_markup=markup_main_ru,)
    return PHASE_MAIN_PAGE_RU

# wrong selection
async def wrong(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('wrong()')
    await update.message.reply_text("Выберите из списка.", reply_markup=markup_main_ru,)

    return PHASE_MAIN_PAGE_RU

# end conversationhandler function
async def done(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('done()')
    global ch_id, operator, client, supervisor

    ch_id = None
    operator = None
    client = None
    supervisor = None

    await update.message.reply_text('Rahmat!', reply_markup=ReplyKeyboardRemove(),)
    return ConversationHandler.END

# end chat functions
async def done_operator(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('done_operator()')
    global ch_id
    await update.message.reply_text("Вы завершили чат.", reply_markup=markup_main_operator)

    try:
        chat = Chat.objects.get(id=ch_id)
    except Chat.DoesNotExist:
        # await update.message.reply_text("Chat not found.")
        print('Chat not found')

    chat.is_closed = True
    chat.save()

    client_tg_id = chat.client.tg_id
    await context.bot.send_message(client_tg_id, 'Оператор завершил чат', reply_markup=markup_main_ru,)

    # Reset the ch_id after chat is done
    ch_id = None

    return PHASE_MAIN_OPERATOR

async def done_client(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    print('done_client()')
    global ch_id
    await update.message.reply_text("Вы завершили чат.", reply_markup=markup_main_ru)

    try:
        chat = Chat.objects.get(id=ch_id)
    except Chat.DoesNotExist:
        await update.message.reply_text("Chat not found.")
        print('Chat not found')

    chat.is_closed = True
    chat.save()

    if chat.operator is None:
        pass
    else:
        await context.bot.send_message(chat.operator.tg_id, 'Клиент завершил чат', reply_markup=markup_main_operator)

    # Reset the ch_id after chat is done
    ch_id = None

    return PHASE_MAIN_PAGE_RU

# main function
def main() -> None:
    application = Application.builder().token("token").build()

    conv_handler = ConversationHandler(
        entry_points=[CommandHandler("start", start)],
        states={
            PHASE_LANG_CHOOSING: [
                MessageHandler(filters.Regex("^(O'zbek|Русский)$"), lang_choice),
            ],
            PHASE_SHARE_CONTACT: [
                MessageHandler(filters.CONTACT, get_phone,),
                MessageHandler(filters.TEXT, get_phone_wrong,),
                # MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_APPEAL: [
                MessageHandler(filters.TEXT, get_appeal,),
                MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_MAIN_PAGE_UZ: [
                MessageHandler(filters.Regex("^Savol$"), question,),
                MessageHandler(filters.Regex("^Shikoyat$"), appeal,),
                MessageHandler(filters.Regex("^Onlayn opertor$"), lets_chat,),
                # MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_MAIN_PAGE_RU: [
                MessageHandler(filters.Regex("^Вопрос$"), question,),
                MessageHandler(filters.Regex("^Жалоба$"), appeal,),
                MessageHandler(filters.Regex("^Онлайн-оператор$"), lets_chat,),
                # MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_MAIN_OPERATOR: [
                MessageHandler(filters.Regex("^✅Завершить чат$"), done_operator,),
                MessageHandler(filters.Regex("^Открытие чаты$"), open_chats,),
                MessageHandler(filters.Regex("^Закрытие чаты$"), closed_chats,),
                CallbackQueryHandler(move_to_get_reply),
                # MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_OPERATOR_CHAT: [
                MessageHandler(filters.Regex("^✅Завершить чат$"), done_operator,),
                MessageHandler(filters.Regex("^Открытие чаты$"), open_chats,),
                MessageHandler(filters.Regex("^Закрытие чаты$"), closed_chats,),
                MessageHandler(filters.TEXT, operator_chat,),
                CallbackQueryHandler(move_to_get_reply),
                # MessageHandler(filters.ALL, wrong,),
            ],
            PHASE_CLIENT_CHAT: [
                MessageHandler(filters.Regex("^✅Завершить чат$"), done_client,),
                MessageHandler(filters.Regex("^✅Chatni yopish$"), done_client,),
                MessageHandler(filters.Regex("^Вопрос$"), question,),
                MessageHandler(filters.Regex("^Жалоба$"), appeal,),
                MessageHandler(filters.Regex("^Savol$"), question,),
                MessageHandler(filters.Regex("^Shikoyat$"), appeal,),
                MessageHandler(filters.TEXT, chat,),
                # MessageHandler(filters.ALL, wrong,),
            ],
        },
        fallbacks=[CommandHandler("cancel", done)],
    )

    application.add_handler(conv_handler)
    application.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == "__main__":
    main()

I have tested with one operator and one client everything is working fine, but when I add another operator and more clients messages are messing between them… What I am doing wrong, please help me?!)

2

Answers


  1. It really does come down to global variables and a complete lack of concurrency safety.
    PTB has a built-in solution for storing variables like that. I’d probably use bot_data for storage in this case, but you should go through the entire article and consider the best option yourself.

    Login or Signup to reply.
  2. To manage operator availability and ensure that the messages are routed correctly between clients and operators, you need to handle the is_available flag properly. You also need to ensure that each chat is correctly mapped to the respective operator and client.
    I have made a few modifications to ur code 2manage the is_available status of operators:

    1. Update the move_to_get_reply function to mark the operator as busy when they start a chat
    async def move_to_get_reply(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
        print('move_to_get_reply()')
        global ch_id
        query = update.callback_query
        await query.answer()
    
        if ch_id is not None:
            created_chat = Chat.objects.get(id=ch_id)
            operator = CustomUser.objects.get(tg_id=query.from_user.id)
            created_chat.operator = operator
            created_chat.save()
    
            # Mark operator as busy
            operator.is_available = False
            operator.save()
    
            await context.bot.send_message(created_chat.operator.tg_id, 'Чат открыт, напишите ...', reply_markup=markup_close_chat_ru)
    
            if created_chat.client.choosen_lang == "O'zbek":
                await context.bot.send_message(created_chat.client.tg_id, 'Assalomu alaykum, nima yordam bera olaman?', reply_markup=markup_close_chat_uz)
            else:
                await context.bot.send_message(created_chat.client.tg_id, 'Здравствуйте, чем могу помочь?', reply_markup=markup_close_chat_ru)
    
            return PHASE_OPERATOR_CHAT
        else:
            await context.bot.send_message(created_chat.operator.tg_id, 'Клиент уже завершил чат.', reply_markup=markup_main_operator)
            return PHASE_MAIN_OPERATOR
    
    1. Update the done_operator function 2mark operator as available when the chat ends
    async def done_operator(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
        print('done_operator()')
        global ch_id
        await update.message.reply_text("Вы завершили чат.", reply_markup=markup_main_operator)
    
        try:
            chat = Chat.objects.get(id=ch_id)
        except Chat.DoesNotExist:
            print('Chat not found')
            return PHASE_MAIN_OPERATOR
    
        chat.is_closed = True
        chat.save()
    
        client_tg_id = chat.client.tg_id
        await context.bot.send_message(client_tg_id, 'Оператор завершил чат', reply_markup=markup_main_ru)
    
        # Mark operator as available
        operator = chat.operator
        operator.is_available = True
        operator.save()
    
        # Reset the ch_id after chat is done
        ch_id = None
    
        return PHASE_MAIN_OPERATOR
    
    1. Update the done_client function similarly to handle when a client ends the chat
    async def done_client(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
        print('done_client()')
        global ch_id
        await update.message.reply_text("Вы завершили чат.", reply_markup=markup_main_ru)
    
        try:
            chat = Chat.objects.get(id=ch_id)
        except Chat.DoesNotExist:
            await update.message.reply_text("Chat not found.")
            print('Chat not found')
            return PHASE_MAIN_PAGE_RU
    
        chat.is_closed = True
        chat.save()
    
        if chat.operator:
            await context.bot.send_message(chat.operator.tg_id, 'Клиент завершил чат', reply_markup=markup_main_operator)
            # Mark operator as available
            operator = chat.operator
            operator.is_available = True
            operator.save()
    
        # Reset the ch_id after chat is done
        ch_id = None
    
        return PHASE_MAIN_PAGE_RU
    
    1. Ensure that the lets_chat function assigns an available operator to the chat and handles multiple operators correctly
    async def lets_chat(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
        print('lets_chat()')
        global ch_id
    
        created_chat = Chat.objects.create(
            is_closed=False,
            client=CustomUser.objects.get(tg_id=update.message.from_user.id),
        )
        
        ch_id = created_chat.id
        keyboard = [
            [
                InlineKeyboardButton("Присоединиться к чату", callback_data=ch_id),
            ],
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        available_operator = CustomUser.objects.filter(is_operator=True, is_available=True).first()
    
        notification_message = (
            f"<u>Появился новый чат!</u>n"
            f'n'
            f'<b>Имя пользователя:</b> <i>{update.message.from_user.first_name}</i>'
            f'n'
            f'<b>Обрашения:</b> <i>{update.message.text}</i>' 
        )
        if available_operator:
            await context.bot.send_message(available_operator.tg_id, notification_message, reply_markup=reply_markup, parse_mode='HTML')
    
        if created_chat.client.choosen_lang == "O'zbek":
            await update.message.reply_text("Iltimos, kutib turing! Biz sizni mavjud operator bilan bog'layabmiz.", reply_markup=markup_close_chat_uz)
        else:
            await update.message.reply_text("Пожалуйста, ожидайте! Мы соединяем Вас со свободным оператором.", reply_markup=markup_close_chat_ru)
        
        return PHASE_CLIENT_CHAT
    

    I hope this changes will ensure that an operator is marked as busy (is_available=False) when they start a chat and available (is_available=True) once the chat ends. This should resolve the issue of messages getting mixed up between different clients and operators.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search