feat: Add A-Z filter for clients/suppliers in Telegram bot

- Add A-Z alphabetical filter keyboard for clients and suppliers lists
  (same pattern as company selection, without emoji)
- Increase clients/suppliers list pagination from 10 to 20 items per page
- Remove emoji from company A-Z filter button for consistency
- Add 6 new callback handlers: clients_alpha_menu, clients_alpha:LETTER,
  clients_alpha_page:PAGE:LETTER, and supplier equivalents
- Dashboard service and models updates
- Telegram bot: email handlers, auth, DB operations, internal API improvements
- Frontend: dashboard cards updates (CashFlow, Clienti, Furnizori, Treasury)
- Frontend: SolduriCompactCard and CollapsibleCard improvements
- DashboardView enhancements
- start.sh and run-with-restart.sh script updates
- IIS web.config and service worker updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-21 14:34:15 +00:00
parent 1366dbc11c
commit 30f55cf18b
28 changed files with 1671 additions and 520 deletions

View File

@@ -260,7 +260,13 @@ def create_main_menu(
InlineKeyboardButton("Clear Cache", callback_data="menu:clearcache")
])
# Row 6: Help/Logout buttons (authenticated) or Login button (non-authenticated)
# Row 6: Switch Server button (authenticated only)
if is_authenticated:
keyboard.append([
InlineKeyboardButton("Schimba Server", callback_data="menu:switch_server"),
])
# Row 7: Help/Logout buttons (authenticated) or Login button (non-authenticated)
if is_authenticated:
keyboard.append([
InlineKeyboardButton("Help", callback_data="action:help"),
@@ -334,7 +340,7 @@ def create_action_buttons(current_view: str, show_export: bool = True, show_back
return InlineKeyboardMarkup(keyboard)
def create_client_list_keyboard(clients: List[Dict], max_items: int = 10, page: int = 0) -> InlineKeyboardMarkup:
def create_client_list_keyboard(clients: List[Dict], max_items: int = 20, page: int = 0, letter: str = None) -> InlineKeyboardMarkup:
"""
Create client list keyboard (Level 2) with client buttons and pagination.
@@ -344,6 +350,7 @@ def create_client_list_keyboard(clients: List[Dict], max_items: int = 10, page:
clients: List of client dicts with keys: id, name, balance
max_items: Maximum number of clients per page (default: 10)
page: Current page number (0-indexed)
letter: Optional letter filter (e.g. "A", "ALL") - when set, uses alpha pagination
Returns:
InlineKeyboardMarkup with client list buttons and pagination
@@ -387,10 +394,18 @@ def create_client_list_keyboard(clients: List[Dict], max_items: int = 10, page:
if total_pages > 1:
nav_buttons = []
# Choose pagination callback based on whether letter filter is active
if letter:
prev_cb = f"clients_alpha_page:{page-1}:{letter}"
next_cb = f"clients_alpha_page:{page+1}:{letter}"
else:
prev_cb = f"clients_page:{page-1}"
next_cb = f"clients_page:{page+1}"
# Previous button
if page > 0:
nav_buttons.append(
InlineKeyboardButton("< Anterior", callback_data=f"clients_page:{page-1}")
InlineKeyboardButton("< Anterior", callback_data=prev_cb)
)
# Page indicator (non-clickable)
@@ -401,20 +416,26 @@ def create_client_list_keyboard(clients: List[Dict], max_items: int = 10, page:
# Next button
if page < total_pages - 1:
nav_buttons.append(
InlineKeyboardButton("Următor >", callback_data=f"clients_page:{page+1}")
InlineKeyboardButton("Urmator >", callback_data=next_cb)
)
keyboard.append(nav_buttons)
# Navigation row: Back button only
# Filtrare A-Z button
keyboard.append([
InlineKeyboardButton("< Înapoi", callback_data="action:menu")
InlineKeyboardButton("Filtrare A-Z", callback_data="clients_alpha_menu")
])
# Back button: to A-Z menu if filtering, otherwise to main menu
back_callback = "clients_alpha_menu" if letter else "action:menu"
keyboard.append([
InlineKeyboardButton("< Inapoi", callback_data=back_callback)
])
return InlineKeyboardMarkup(keyboard)
def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10, page: int = 0) -> InlineKeyboardMarkup:
def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 20, page: int = 0, letter: str = None) -> InlineKeyboardMarkup:
"""
Create supplier list keyboard (Level 2) with supplier buttons and pagination.
@@ -424,6 +445,7 @@ def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10, pa
suppliers: List of supplier dicts with keys: id, name, balance
max_items: Maximum number of suppliers per page (default: 10)
page: Current page number (0-indexed)
letter: Optional letter filter (e.g. "A", "ALL") - when set, uses alpha pagination
Returns:
InlineKeyboardMarkup with supplier list buttons and pagination
@@ -467,10 +489,18 @@ def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10, pa
if total_pages > 1:
nav_buttons = []
# Choose pagination callback based on whether letter filter is active
if letter:
prev_cb = f"suppliers_alpha_page:{page-1}:{letter}"
next_cb = f"suppliers_alpha_page:{page+1}:{letter}"
else:
prev_cb = f"suppliers_page:{page-1}"
next_cb = f"suppliers_page:{page+1}"
# Previous button
if page > 0:
nav_buttons.append(
InlineKeyboardButton("< Anterior", callback_data=f"suppliers_page:{page-1}")
InlineKeyboardButton("< Anterior", callback_data=prev_cb)
)
# Page indicator (non-clickable)
@@ -481,14 +511,20 @@ def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10, pa
# Next button
if page < total_pages - 1:
nav_buttons.append(
InlineKeyboardButton("Următor >", callback_data=f"suppliers_page:{page+1}")
InlineKeyboardButton("Urmator >", callback_data=next_cb)
)
keyboard.append(nav_buttons)
# Navigation row: Back button only
# Filtrare A-Z button
keyboard.append([
InlineKeyboardButton("< Înapoi", callback_data="action:menu")
InlineKeyboardButton("Filtrare A-Z", callback_data="suppliers_alpha_menu")
])
# Back button: to A-Z menu if filtering, otherwise to main menu
back_callback = "suppliers_alpha_menu" if letter else "action:menu"
keyboard.append([
InlineKeyboardButton("< Inapoi", callback_data=back_callback)
])
return InlineKeyboardMarkup(keyboard)