Implement multi-card payment method management and enhance user notifications

- Added support for saving multiple payment methods, allowing users to bind and manage their cards effectively.
- Introduced a new paginated list view for displaying saved payment methods, improving user experience.
- Enhanced user notifications for successful binding of payment methods, including localized messages.
- Updated the database models and data access layer to accommodate multi-card functionality.
- Refactored existing payment method handlers to integrate with the new multi-card system.
This commit is contained in:
machka-pasla
2025-09-04 17:11:18 +03:00
parent 257597ccb7
commit 6b5828ea51
8 changed files with 310 additions and 31 deletions
+59 -12
View File
@@ -1,6 +1,6 @@
from aiogram.utils.keyboard import InlineKeyboardBuilder, InlineKeyboardButton
from aiogram.types import InlineKeyboardMarkup, WebAppInfo
from typing import Dict, Optional, List
from typing import Dict, Optional, List, Tuple
from config.settings import Settings
@@ -232,13 +232,13 @@ def get_connect_and_main_keyboard(
def get_payment_methods_manage_keyboard(lang: str, i18n_instance, has_card: bool) -> InlineKeyboardMarkup:
"""Deprecated in favor of get_payment_methods_list_keyboard. Kept for backward compatibility."""
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
builder = InlineKeyboardBuilder()
if has_card:
builder.row(
InlineKeyboardButton(text=_(key="payment_method_view_button"), callback_data="pm:view"),
InlineKeyboardButton(text=_(key="payment_method_delete_button"), callback_data="pm:delete_confirm"),
)
# Route to the new list view
builder.row(
InlineKeyboardButton(text=_(key="payment_methods_title"), callback_data="pm:list:0")
)
builder.row(
InlineKeyboardButton(text=_(key="payment_method_bind_button"), callback_data="pm:bind")
)
@@ -248,24 +248,64 @@ def get_payment_methods_manage_keyboard(lang: str, i18n_instance, has_card: bool
return builder.as_markup()
def get_payment_method_delete_confirm_keyboard(lang: str, i18n_instance) -> InlineKeyboardMarkup:
def get_payment_methods_list_keyboard(
cards: List[Tuple[str, str]],
page: int,
lang: str,
i18n_instance,
) -> InlineKeyboardMarkup:
"""
Build a paginated list of saved payment methods.
cards: list of tuples (payment_method_id, display_title)
page: 0-based page index
"""
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
builder = InlineKeyboardBuilder()
per_page = 5
total = len(cards)
start = page * per_page
end = start + per_page
for pm_id, title in cards[start:end]:
builder.row(
InlineKeyboardButton(text=title, callback_data=f"pm:view:{pm_id}")
)
# Pagination controls if needed
nav_buttons: List[InlineKeyboardButton] = []
if start > 0:
nav_buttons.append(InlineKeyboardButton(text="⬅️", callback_data=f"pm:list:{page-1}"))
if end < total:
nav_buttons.append(InlineKeyboardButton(text="➡️", callback_data=f"pm:list:{page+1}"))
if nav_buttons:
builder.row(*nav_buttons)
# Bind new card and back
builder.row(InlineKeyboardButton(text=_(key="payment_method_bind_button"), callback_data="pm:bind"))
builder.row(InlineKeyboardButton(text=_(key="back_to_main_menu_button"), callback_data="main_action:back_to_main"))
return builder.as_markup()
def get_payment_method_delete_confirm_keyboard(pm_id: str, lang: str, i18n_instance) -> InlineKeyboardMarkup:
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text=_(key="yes_button"), callback_data="pm:delete"),
InlineKeyboardButton(text=_(key="cancel_button"), callback_data="pm:manage"),
InlineKeyboardButton(text=_(key="yes_button"), callback_data=f"pm:delete:{pm_id}"),
InlineKeyboardButton(text=_(key="cancel_button"), callback_data=f"pm:view:{pm_id}"),
)
return builder.as_markup()
def get_payment_method_details_keyboard(lang: str, i18n_instance) -> InlineKeyboardMarkup:
def get_payment_method_details_keyboard(pm_id: str, lang: str, i18n_instance) -> InlineKeyboardMarkup:
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text=_(key="payment_method_tx_history_title"), callback_data="pm:history")
InlineKeyboardButton(text=_(key="payment_method_tx_history_title"), callback_data=f"pm:history:{pm_id}")
)
builder.row(
InlineKeyboardButton(text=_(key="back_to_main_menu_button"), callback_data="pm:manage")
InlineKeyboardButton(text=_(key="payment_method_delete_button"), callback_data=f"pm:delete_confirm:{pm_id}")
)
builder.row(
InlineKeyboardButton(text=_(key="payment_methods_title"), callback_data="pm:list:0")
)
return builder.as_markup()
@@ -277,3 +317,10 @@ def get_bind_url_keyboard(bind_url: str, lang: str, i18n_instance) -> InlineKeyb
builder.button(text=_(key="back_to_main_menu_button"), callback_data="pm:manage")
builder.adjust(1)
return builder.as_markup()
def get_back_to_payment_methods_keyboard(lang: str, i18n_instance) -> InlineKeyboardMarkup:
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text=_(key="payment_methods_title"), callback_data="pm:list:0"))
return builder.as_markup()