From aac49542e4b262f7bce1c617da21f43997ba5ee5 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Mon, 23 Feb 2026 09:18:59 +0000 Subject: [PATCH] fix(telegram): edit messages in-place during server switch flow Server switch flow now edits the original message at each step (progress, error, company list) instead of sending separate messages. "Server schimbat" notice is folded into the company selection header. Also adds budget debt breakdown to dashboard formatter. Co-Authored-By: Claude Sonnet 4.6 --- backend/modules/telegram/bot/formatters.py | 15 ++++ backend/modules/telegram/bot/handlers.py | 86 +++++++++++++++++++--- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/backend/modules/telegram/bot/formatters.py b/backend/modules/telegram/bot/formatters.py index 44d77f3..0333e03 100644 --- a/backend/modules/telegram/bot/formatters.py +++ b/backend/modules/telegram/bot/formatters.py @@ -63,6 +63,21 @@ def format_dashboard_response(data: Dict[str, Any], company_name: str = None) -> if tva_recup_cur > 0: text += f" - TVA de recuperat curent: {tva_recup_cur:,} RON\n" + # Datorii la Buget - breakdown pe grupe (TVA / BASS / CAM), valori luna precedentă + budget_breakdown = data.get('budget_debt_breakdown', []) + if budget_breakdown: + grupe_cu_datorie = [ + g for g in budget_breakdown + if round(float(g.get('precedent', 0))) > 0 + ] + if grupe_cu_datorie: + total_buget = sum(round(float(g.get('precedent', 0))) for g in grupe_cu_datorie) + text += "\n\n**Datorii la Buget:**\n" + for grupa in grupe_cu_datorie: + val = round(float(grupa.get('precedent', 0))) + text += f" - {grupa.get('label', '')}: {val:,} RON\n" + text += f" Total: {total_buget:,} RON\n" + return text diff --git a/backend/modules/telegram/bot/handlers.py b/backend/modules/telegram/bot/handlers.py index bcd279f..65171dc 100644 --- a/backend/modules/telegram/bot/handlers.py +++ b/backend/modules/telegram/bot/handlers.py @@ -1292,16 +1292,37 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE except Exception as e: logger.warning(f"Could not delete password message: {e}") + # Șterge și mesajul prompt "Parolă:" (ForceReply) + prompt_msg_id = context.user_data.pop('pending_switch_prompt_message_id', None) + if prompt_msg_id: + try: + await context.bot.delete_message( + chat_id=update.effective_chat.id, + message_id=prompt_msg_id + ) + except Exception: + pass + oracle_password = text jwt_token = context.user_data.pop('pending_switch_jwt_token', None) username = context.user_data.pop('pending_switch_username', None) context.user_data.pop('pending_switch_server_id', None) + # Recuperează message_id-ul și chat_id-ul pentru editare in-place + switch_msg_id = context.user_data.get('pending_switch_message_id') + switch_chat_id = context.user_data.get('pending_switch_chat_id') if not jwt_token or not username: await update.effective_chat.send_message("Sesiune expirată. Încearcă din nou.") return - await update.effective_chat.send_message("Se verifică parola și se schimbă serverul...") + if switch_msg_id and switch_chat_id: + await context.bot.edit_message_text( + chat_id=switch_chat_id, + message_id=switch_msg_id, + text="Se verifică parola și se schimbă serverul..." + ) + else: + await update.effective_chat.send_message("Se verifică parola și se schimbă serverul...") client = get_backend_client() async with client: @@ -1314,10 +1335,19 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE if not result.get('success'): from telegram import InlineKeyboardButton, InlineKeyboardMarkup - await update.effective_chat.send_message( - f"❌ {result.get('message', 'Eroare la schimbarea serverului')}\n\nReîncearcă cu /menu → Schimbă server.", - reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("« Meniu", callback_data="action:menu")]]) - ) + error_text = f"❌ {result.get('message', 'Eroare la schimbarea serverului')}\n\nReîncearcă cu /menu → Schimbă server." + error_markup = InlineKeyboardMarkup([[InlineKeyboardButton("« Meniu", callback_data="action:menu")]]) + if switch_msg_id and switch_chat_id: + context.user_data.pop('pending_switch_message_id', None) + context.user_data.pop('pending_switch_chat_id', None) + await context.bot.edit_message_text( + chat_id=switch_chat_id, + message_id=switch_msg_id, + text=error_text, + reply_markup=error_markup + ) + else: + await update.effective_chat.send_message(error_text, reply_markup=error_markup) return # Salvează noul JWT în SQLite @@ -1344,7 +1374,11 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE except Exception: srv_display = pending_server_id - await update.effective_chat.send_message(f"✅ Server schimbat: **{srv_display}**\nSelectează firma...", parse_mode=ParseMode.MARKDOWN) + edit_chat_id = switch_chat_id if (switch_msg_id and switch_chat_id) else None + edit_message_id = switch_msg_id if (switch_msg_id and switch_chat_id) else None + if switch_msg_id and switch_chat_id: + context.user_data.pop('pending_switch_message_id', None) + context.user_data.pop('pending_switch_chat_id', None) await _handle_selectcompany_view( query_or_update=update, @@ -1352,7 +1386,11 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE jwt_token=result['access_token'], is_callback=False, page=0, - search_term="" + search_term="", + header=f"Server schimbat: **{srv_display}**\n\n", + bot=context.bot, + edit_chat_id=edit_chat_id, + edit_message_id=edit_message_id ) return @@ -2528,12 +2566,18 @@ async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): f"_(Mesajul cu parola va fi șters automat)_", parse_mode=ParseMode.MARKDOWN ) + # Salvează message_id-ul mesajului "🔐 Schimbare server" pentru editare ulterioară + context.user_data['pending_switch_message_id'] = query.message.message_id + context.user_data['pending_switch_chat_id'] = query.message.chat_id + # Trimite un mesaj separat cu ForceReply pentru a forța input-ul - await context.bot.send_message( + force_reply_msg = await context.bot.send_message( chat_id=update.effective_chat.id, text="Parolă:", reply_markup=ForceReply(selective=True, input_field_placeholder="Parola Oracle...") ) + # Salvează message_id-ul prompt-ului "Parolă:" pentru ștergere ulterioară + context.user_data['pending_switch_prompt_message_id'] = force_reply_msg.message_id return # ========== LOGOUT CALLBACKS ========== @@ -3075,7 +3119,11 @@ async def _handle_selectcompany_view( jwt_token: str, is_callback: bool = False, page: int = 0, - search_term: str = "" + search_term: str = "", + header: str = "", + bot=None, + edit_chat_id: int = None, + edit_message_id: int = None ): """ Common handler pentru company selection cu paginare. @@ -3144,7 +3192,7 @@ async def _handle_selectcompany_view( from backend.modules.telegram.bot.menus import create_main_menu, get_menu_message keyboard = create_main_menu(company_name=company_name, company_cui=company_cui) - menu_text = f"✅ Firmă selectată automat: **{company_name}**\n\n" + get_menu_message(company_name, company_cui) + menu_text = header + f"Firma selectata automat: **{company_name}**\n\n" + get_menu_message(company_name, company_cui) if is_callback: await query_or_update.edit_message_text( @@ -3152,6 +3200,14 @@ async def _handle_selectcompany_view( reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN ) + elif bot and edit_chat_id and edit_message_id: + await bot.edit_message_text( + chat_id=edit_chat_id, + message_id=edit_message_id, + text=menu_text, + reply_markup=keyboard, + parse_mode=ParseMode.MARKDOWN + ) else: await query_or_update.message.reply_text( menu_text, @@ -3163,7 +3219,7 @@ async def _handle_selectcompany_view( from backend.modules.telegram.bot.helpers import create_company_selection_keyboard_paginated keyboard = create_company_selection_keyboard_paginated(companies, page=page) - message = f"**Selecteaza Compania**\n\n" + message = header + f"**Selecteaza Compania**\n\n" if search_term: message += f"Rezultate '{search_term}' ({len(companies)}):" else: @@ -3175,6 +3231,14 @@ async def _handle_selectcompany_view( reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN ) + elif bot and edit_chat_id and edit_message_id: + await bot.edit_message_text( + chat_id=edit_chat_id, + message_id=edit_message_id, + text=message, + reply_markup=keyboard, + parse_mode=ParseMode.MARKDOWN + ) else: await query_or_update.message.reply_text( message,