def festive_comment(update: Update, context, user: BaseUser):
    comment = update.message.text
    deal_message = user.festive_data.deal_message
    deal_id = user.festive_data.deal_id

    # send message to unapproved chat firstly
    BH.decline_deal(deal_id, comment, user.bitrix_user_id)

    unapproved_chat_id = user.festive_data.subdiv_chat_id

    if unapproved_chat_id:
        unapproved_chat = Chat(bot=context.bot, id=unapproved_chat_id, type=Chat.SUPERGROUP)
        keyboard = [
            [InlineKeyboardButton(text=Txt.REAPPROVE_BUTTON_TEXT, callback_data=Txt.REAPPROVE_BUTTON_KEY_PREFIX +
                                                                                Cmd.CMD_DELIMETER + deal_id)]]

        reserve_desc = HttpTxt.DEAL_RESERVE_DESC_ELT.format(user.festive_data.deal_reserve_desc) \
            if user.festive_data.deal_reserve_desc != GlobalTxt.FIELD_IS_EMPTY_PLACEHOLDER else ''
        prepaid = HttpTxt.DEAL_PREPAID_ELT.format(user.festive_data.deal_prepaid) \
            if user.festive_data.deal_pay_type == BFM.DEAL_PAY_PREPAID_FRIENDLY else ''
        terminal = HttpTxt.DEAL_TERMINAL_ELT.format(user.festive_data.deal_terminal) \
            if user.festive_data.deal_pay_type == BFM.DEAL_PAY_PERSONAL_FRIENDLY else ''
        change = HttpTxt.DEAL_CHANGE_ELT.format(user.festive_data.deal_change) \
            if user.festive_data.deal_terminal != BFM.DEAL_PAY_TERMINAL_FRIENDLY else ''

        if user.festive_data.photo_urls:
            media_list = [InputMediaPhoto(media=el) for el in user.festive_data.photo_urls]
            context.bot.send_media_group(chat_id=unapproved_chat_id, media=media_list)

        TgCommons.send_mdv2_chat(unapproved_chat, Txt.DECLINED_HEADER.format(deal_id) +
                                 Txt.DEAL_DECLINED.format(user.festive_data.deal_accepted,
                                                          user.festive_data.deal_subdivision,
                                                          Utils.prepare_str(comment), user.festive_data.deal_link,
                                                          user.festive_data.deal_order,
                                                          user.festive_data.deal_user_declined,
                                                          user.festive_data.deal_date, user.festive_data.deal_time,
                                                          user.festive_data.deal_sum,
                                                          user.festive_data.deal_source,
                                                          user.festive_data.deal_contact,
                                                          reserve_desc, user.festive_data.deal_delivery_type,
                                                          user.festive_data.deal_district,
                                                          user.festive_data.deal_address,
                                                          user.festive_data.deal_delivery_comment,
                                                          user.festive_data.deal_pay_method,
                                                          user.festive_data.deal_pay_type, prepaid, terminal, change,
                                                          user.festive_data.deal_to_pay,
                                                          user.festive_data.deal_pay_status
                                                          ),
                                 keyboard)

        TgCommons.send_mdv2_chat(update.effective_chat, Txt.DECLINED_HEADER.format(deal_id))

        TgCommons.edit_mdv2(deal_message, msg_text=Txt.DECLINED_HEADER.format('')
                                                   + deal_message.text_markdown_v2, need_cancel=False)

    return ConversationHandler.END
def send_festive_deal_message(
        bot, deal_id, deal_stage, deal_order, deal_date, deal_time, deal_sum,
        deal_accepted, deal_source, deal_contact, deal_subdivision,
        deal_reserve_desc, deal_delivery_type, deal_district, deal_address,
        deal_delivery_comment, deal_pay_method, deal_pay_type, deal_prepaid,
        deal_terminal, deal_change, deal_to_pay, deal_pay_status, photo_urls):

    reserve_desc = Txt.DEAL_RESERVE_DESC_ELT.format(deal_reserve_desc) \
        if deal_reserve_desc != GlobalTxt.FIELD_IS_EMPTY_PLACEHOLDER else ''
    prepaid = Txt.DEAL_PREPAID_ELT.format(
        deal_prepaid) if deal_pay_type == BFM.DEAL_PAY_PREPAID_FRIENDLY else ''
    terminal = Txt.DEAL_TERMINAL_ELT.format(
        deal_terminal
    ) if deal_pay_type == BFM.DEAL_PAY_PERSONAL_FRIENDLY else ''
    change = Txt.DEAL_CHANGE_ELT.format(
        deal_change) if deal_terminal != BFM.DEAL_PAY_TERMINAL_FRIENDLY else ''

    deal_message = Txt.DEAL_FESTIVE_PROCESSED_TEMPLATE.format(
        deal_id, deal_stage, deal_order, deal_date, deal_time, deal_sum,
        deal_accepted, deal_source, deal_contact, deal_subdivision,
        reserve_desc, deal_delivery_type, deal_district, deal_address,
        deal_delivery_comment, deal_pay_method, deal_pay_type, prepaid,
        terminal, change, deal_to_pay, deal_pay_status)

    keyboard = [[
        InlineKeyboardButton(text=Txt.FESTIVE_APPROVE_BUTTON_TEXT,
                             callback_data=Txt.FESTIVE_APPROVE_BUTTON_KEY +
                             Cmd.CMD_DELIMETER + deal_id)
    ],
                [
                    InlineKeyboardButton(
                        text=Txt.FESTIVE_DECLINE_BUTTON_TEXT,
                        callback_data=Txt.FESTIVE_DECLINE_BUTTON_KEY +
                        Cmd.CMD_DELIMETER + deal_id)
                ]]

    chat = Chat(bot=bot,
                id=creds.FESTIVE_APPROVAL_CHAT_ID,
                type=Chat.SUPERGROUP)

    # 1024 symbols of caption only, if more -> need a message
    if photo_urls:
        media_list = [InputMediaPhoto(media=el) for el in photo_urls]
        bot.send_media_group(chat_id=creds.FESTIVE_APPROVAL_CHAT_ID,
                             media=media_list)

    TgCommons.send_mdv2_chat(chat, deal_message, keyboard)
def error_handler(update, context: CallbackContext):
    try:
        logger.error(msg="Exception while handling Telegram update:",
                     exc_info=context.error)

        # don't confuse user with particular error data
        if update:
            if update.effective_chat.type == Chat.PRIVATE:
                # don't confuse user with particular errors data
                TgCommons.send_mdv2(update.effective_user,
                                    GlobalTxt.UNKNOWN_ERROR)
            elif update.effective_chat.type in (Chat.GROUP, Chat.SUPERGROUP):
                TgCommons.send_mdv2_chat(update.effective_chat,
                                         GlobalTxt.UNKNOWN_ERROR)
    except Exception as e:
        logger.error(msg="Exception while handling lower-level exception:",
                     exc_info=e)
def stat_unprocessed(context: CallbackContext):
    unprocessed, subdivs = BH.stat_unprocessed()
    msg = ''

    if unprocessed:
        msg += Txt.UNPROCESSED_STAT_TEMPLATE.format(unprocessed)

    for s_name, s_count in subdivs.items():
        msg += Txt.DECLINED_SUBDIV_STAT_TEMPLATE.format(s_name, s_count)
        subdiv_chat_id = creds.FESTIVE_UNAPPROVED_SUBDIVS.get(s_name)
        subdiv_chat = Chat(bot=context.bot,
                           id=subdiv_chat_id,
                           type=Chat.SUPERGROUP)
        subdiv_msg = Txt.SPECIFIC_SUBDIV_STAT_TEMPLATE.format(s_count)
        TgCommons.send_mdv2_chat(subdiv_chat, subdiv_msg)

    chat = Chat(bot=context.bot,
                id=creds.FESTIVE_APPROVAL_CHAT_ID,
                type=Chat.SUPERGROUP)
    TgCommons.send_mdv2_chat(chat, msg)
def festive_decision(update: Update, context, user):
    if not user:
        TgCommons.send_mdv2_chat(update.effective_chat,
                                 Txt.USER_NOT_FOUND.format(Utils.prepare_str(update.effective_user.full_name)))
        return None

    user.festive_data.clear()

    action = context.match.group(1)
    deal_id = context.match.group(2)

    if action == HttpTxt.FESTIVE_APPROVE_BUTTON_KEY:
        BH.approve_deal(deal_id)
        TgCommons.send_mdv2_chat(update.effective_chat, Txt.APPROVED_HEADER.format(deal_id))
        TgCommons.edit_mdv2(update.effective_message, msg_text=Txt.APPROVED_HEADER.format('')
                                                               + update.effective_message.text_markdown_v2,
                            need_cancel=False)
        return ConversationHandler.END
    elif action == HttpTxt.FESTIVE_DECLINE_BUTTON_KEY:
        user.festive_data.deal_id = deal_id
        user.festive_data.deal_message = update.effective_message

        BH.get_info(context, deal_id, user)

        msg = Txt.REQUEST_DECLINE_COMMENT.format(deal_id)
        TgCommons.send_mdv2_chat(chat=update.effective_chat, msg_text=msg,
                                 reply_id=update.callback_query.message.message_id)
        return State.WRITING_DECLINE_COMMENT