Enhance payment method display logic and localization updates

- Improved the logic for displaying payment method details, including card type and last four digits, to provide a clearer user experience.
- Updated localization strings to reflect changes in payment method terminology, ensuring consistency across user-facing messages.
- Refactored payment method handlers to utilize the new display logic, enhancing the overall management of payment methods.
This commit is contained in:
machka-pasla
2025-09-04 18:14:32 +03:00
parent cf7f0eae51
commit a5aecb0f86
4 changed files with 74 additions and 22 deletions
+29 -6
View File
@@ -140,13 +140,26 @@ async def process_successful_payment(session: AsyncSession, bot: Bot,
payment_method = payment_info_from_webhook.get("payment_method") payment_method = payment_info_from_webhook.get("payment_method")
if isinstance(payment_method, dict) and payment_method.get("saved", False): if isinstance(payment_method, dict) and payment_method.get("saved", False):
pm_id = payment_method.get("id") pm_id = payment_method.get("id")
pm_type = payment_method.get("type")
title = payment_method.get("title")
card = payment_method.get("card") or {} card = payment_method.get("card") or {}
display_network = None
display_last4 = None
# Build generic display for various instrument types
if (pm_type or "").lower() in {"bank_card", "bank-card", "card"}:
display_network = card.get("card_type") or title or "Card"
display_last4 = card.get("last4")
else:
# Wallets, SBP, etc. — use provided title/type; no last4
display_network = title or (pm_type.upper() if pm_type else "Payment method")
display_last4 = None
await user_billing_dal.upsert_yk_payment_method( await user_billing_dal.upsert_yk_payment_method(
session, session,
user_id=user_id, user_id=user_id,
payment_method_id=pm_id, payment_method_id=pm_id,
card_last4=card.get("last4"), card_last4=display_last4,
card_network=card.get("card_type"), card_network=display_network,
) )
except Exception: except Exception:
logging.exception("Failed to persist YooKassa payment method from webhook") logging.exception("Failed to persist YooKassa payment method from webhook")
@@ -463,13 +476,23 @@ async def yookassa_webhook_route(request: web.Request):
user_id = int(user_id_str) user_id = int(user_id_str)
payment_method = payment_dict_for_processing.get("payment_method") payment_method = payment_dict_for_processing.get("payment_method")
if isinstance(payment_method, dict) and payment_method.get("id"): if isinstance(payment_method, dict) and payment_method.get("id"):
pm_type = payment_method.get("type")
title = payment_method.get("title")
card = payment_method.get("card") or {} card = payment_method.get("card") or {}
display_network = None
display_last4 = None
if (pm_type or "").lower() in {"bank_card", "bank-card", "card"}:
display_network = card.get("card_type") or title or "Card"
display_last4 = card.get("last4")
else:
display_network = title or (pm_type.upper() if pm_type else "Payment method")
display_last4 = None
await user_billing_dal.upsert_yk_payment_method( await user_billing_dal.upsert_yk_payment_method(
session, session,
user_id=user_id, user_id=user_id,
payment_method_id=payment_method.get("id"), payment_method_id=payment_method.get("id"),
card_last4=card.get("last4"), card_last4=display_last4,
card_network=card.get("card_type"), card_network=display_network,
) )
await session.commit() await session.commit()
# Save multi-card entry and mark default if first # Save multi-card entry and mark default if first
@@ -480,8 +503,8 @@ async def yookassa_webhook_route(request: web.Request):
user_id=user_id, user_id=user_id,
provider_payment_method_id=payment_method.get("id"), provider_payment_method_id=payment_method.get("id"),
provider="yookassa", provider="yookassa",
card_last4=card.get("last4"), card_last4=display_last4,
card_network=card.get("card_type"), card_network=display_network,
set_default=True, set_default=True,
) )
await session.commit() await session.commit()
+35 -8
View File
@@ -313,12 +313,21 @@ async def pay_yk_callback_handler(
pm = payment_response_yk.get("payment_method") pm = payment_response_yk.get("payment_method")
try: try:
if pm and pm.get('id'): if pm and pm.get('id'):
pm_type = pm.get('type')
title = pm.get('title')
card = pm.get('card') or {}
if isinstance(card, dict) and (pm_type or '').lower() in {"bank_card", "bank-card", "card"}:
display_network = card.get('card_type') or title or 'Card'
display_last4 = card.get('last4')
else:
display_network = title or (pm_type.upper() if pm_type else 'Payment method')
display_last4 = None
await user_billing_dal.upsert_yk_payment_method( await user_billing_dal.upsert_yk_payment_method(
session, session,
user_id=user_id, user_id=user_id,
payment_method_id=pm['id'], payment_method_id=pm['id'],
card_last4=pm.get('last4'), card_last4=display_last4,
card_network=pm.get('card', {}).get('card_type') if isinstance(pm.get('card'), dict) else None, card_network=display_network,
) )
await session.commit() await session.commit()
except Exception: except Exception:
@@ -604,7 +613,10 @@ async def payment_methods_manage(callback: types.CallbackQuery, settings: Settin
methods = await list_user_payment_methods(session, callback.from_user.id) methods = await list_user_payment_methods(session, callback.from_user.id)
cards: List[tuple] = [] cards: List[tuple] = []
for m in methods: for m in methods:
title = get_text("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4 or "????") if m.card_last4:
title = get_text("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4)
else:
title = get_text("payment_method_generic_title", network=m.card_network or "Payment method")
cards.append((str(m.method_id), title if not m.is_default else f"{title}")) cards.append((str(m.method_id), title if not m.is_default else f"{title}"))
text = get_text("payment_methods_title") text = get_text("payment_methods_title")
@@ -683,7 +695,10 @@ async def payment_method_delete(callback: types.CallbackQuery, settings: Setting
text = _("payment_methods_title") text = _("payment_methods_title")
cards = [] cards = []
for m in methods: for m in methods:
title = _("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4 or "????") if m.card_last4:
title = _("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4)
else:
title = _("payment_method_generic_title", network=m.card_network or "Payment method")
cards.append((str(m.method_id), title if not m.is_default else f"{title}")) cards.append((str(m.method_id), title if not m.is_default else f"{title}"))
if not cards: if not cards:
text += "\n\n" + _("payment_method_none") text += "\n\n" + _("payment_method_none")
@@ -713,7 +728,10 @@ async def payment_method_delete(callback: types.CallbackQuery, settings: Setting
methods = await list_user_payment_methods(session, callback.from_user.id) methods = await list_user_payment_methods(session, callback.from_user.id)
cards = [] cards = []
for m in methods: for m in methods:
title = _("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4 or "????") if m.card_last4:
title = _("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4)
else:
title = _("payment_method_generic_title", network=m.card_network or "Payment method")
cards.append((str(m.method_id), title if not m.is_default else f"{title}")) cards.append((str(m.method_id), title if not m.is_default else f"{title}"))
text = _("payment_methods_title") text = _("payment_methods_title")
if not cards: if not cards:
@@ -743,7 +761,10 @@ async def payment_method_view(callback: types.CallbackQuery, settings: Settings,
pm_id = parts[2] if len(parts) >= 3 else str(methods[0].method_id) pm_id = parts[2] if len(parts) >= 3 else str(methods[0].method_id)
# Map: # Map:
sel = next((m for m in methods if str(m.method_id) == pm_id or m.provider_payment_method_id == pm_id), methods[0]) sel = next((m for m in methods if str(m.method_id) == pm_id or m.provider_payment_method_id == pm_id), methods[0])
title = _("payment_method_card_title", network=sel.card_network or "Card", last4=sel.card_last4 or "????") if sel.card_last4:
title = _("payment_method_card_title", network=sel.card_network or "Card", last4=sel.card_last4)
else:
title = _("payment_method_generic_title", network=sel.card_network or "Payment method")
added_at = sel.created_at.strftime('%Y-%m-%d') if getattr(sel, 'created_at', None) else "" added_at = sel.created_at.strftime('%Y-%m-%d') if getattr(sel, 'created_at', None) else ""
# Last tx # Last tx
last_tx = "" last_tx = ""
@@ -791,7 +812,10 @@ async def payment_method_view(callback: types.CallbackQuery, settings: Settings,
last_tx = last_payment.created_at.strftime('%Y-%m-%d') last_tx = last_payment.created_at.strftime('%Y-%m-%d')
except Exception: except Exception:
pass pass
title = _("payment_method_card_title", network=billing.card_network or "Card", last4=billing.card_last4 or "????") if billing.card_last4:
title = _("payment_method_card_title", network=billing.card_network or "Card", last4=billing.card_last4)
else:
title = _("payment_method_generic_title", network=billing.card_network or "Payment method")
details = f"{title}\n{_('payment_method_added_at', date=added_at)}\n{_('payment_method_last_tx', date=last_tx)}" details = f"{title}\n{_('payment_method_added_at', date=added_at)}\n{_('payment_method_last_tx', date=last_tx)}"
await callback.message.edit_text(details, reply_markup=get_payment_method_details_keyboard(billing.yookassa_payment_method_id, current_lang, i18n)) await callback.message.edit_text(details, reply_markup=get_payment_method_details_keyboard(billing.yookassa_payment_method_id, current_lang, i18n))
try: try:
@@ -847,7 +871,10 @@ async def payment_methods_list(callback: types.CallbackQuery, settings: Settings
cards: List[tuple] = [] cards: List[tuple] = []
methods = await list_user_payment_methods(session, callback.from_user.id) methods = await list_user_payment_methods(session, callback.from_user.id)
for m in methods: for m in methods:
title = get_text("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4 or "????") if m.card_last4:
title = get_text("payment_method_card_title", network=m.card_network or "Card", last4=m.card_last4)
else:
title = get_text("payment_method_generic_title", network=m.card_network or "Payment method")
cards.append((str(m.method_id), title if not m.is_default else f"{title}")) cards.append((str(m.method_id), title if not m.is_default else f"{title}"))
# Parse page # Parse page
+5 -4
View File
@@ -377,14 +377,15 @@
"subscription_autorenew_updated": "Auto-renew settings updated.", "subscription_autorenew_updated": "Auto-renew settings updated.",
"payment_methods_manage_button": "💳 Payment Methods", "payment_methods_manage_button": "💳 Payment Methods",
"payment_methods_title": "💳 <b>Payment Methods</b>", "payment_methods_title": "💳 <b>Payment Methods</b>",
"payment_method_bind_button": " Add card", "payment_method_bind_button": " Add method",
"payment_method_delete_button": "🗑 Remove", "payment_method_delete_button": "🗑 Remove",
"payment_method_view_button": "️ Details", "payment_method_view_button": "️ Details",
"payment_method_none": "You don't have a saved card yet.", "payment_method_none": "You don't have a saved payment method yet.",
"payment_method_bound_success": "✅ Card successfully added.", "payment_method_bound_success": "✅ Payment method added.",
"payment_method_deleted_success": "✅ Payment method removed.", "payment_method_deleted_success": "✅ Payment method removed.",
"payment_method_delete_confirm": "Remove saved payment method?", "payment_method_delete_confirm": "Remove saved payment method?",
"payment_method_card_title": "💳 Card {network} ••••{last4}", "payment_method_card_title": "💳 {network} ••••{last4}",
"payment_method_generic_title": "💳 {network}",
"payment_method_added_at": "Added: {date}", "payment_method_added_at": "Added: {date}",
"payment_method_last_tx": "Last transaction: {date}", "payment_method_last_tx": "Last transaction: {date}",
"payment_method_tx_history_title": "📜 Transactions history", "payment_method_tx_history_title": "📜 Transactions history",
+5 -4
View File
@@ -376,14 +376,15 @@
"subscription_autorenew_updated": "Настройки автопродления обновлены.", "subscription_autorenew_updated": "Настройки автопродления обновлены.",
"payment_methods_manage_button": "💳 Способы оплаты", "payment_methods_manage_button": "💳 Способы оплаты",
"payment_methods_title": "💳 <b>Способы оплаты</b>", "payment_methods_title": "💳 <b>Способы оплаты</b>",
"payment_method_bind_button": " Привязать карту", "payment_method_bind_button": " Добавить способ",
"payment_method_delete_button": "🗑 Удалить", "payment_method_delete_button": "🗑 Удалить",
"payment_method_view_button": "️ Детали", "payment_method_view_button": "️ Детали",
"payment_method_none": "У вас пока нет сохранённой карты.", "payment_method_none": "У вас пока нет сохранённого способа оплаты.",
"payment_method_bound_success": "✅ Карта успешно привязана.", "payment_method_bound_success": "✅ Способ оплаты добавлен.",
"payment_method_deleted_success": "✅ Способ оплаты удалён.", "payment_method_deleted_success": "✅ Способ оплаты удалён.",
"payment_method_delete_confirm": "Удалить сохранённый способ оплаты?", "payment_method_delete_confirm": "Удалить сохранённый способ оплаты?",
"payment_method_card_title": "💳 Карта {network} ••••{last4}", "payment_method_card_title": "💳 {network} ••••{last4}",
"payment_method_generic_title": "💳 {network}",
"payment_method_added_at": "Добавлена: {date}", "payment_method_added_at": "Добавлена: {date}",
"payment_method_last_tx": "Последняя операция: {date}", "payment_method_last_tx": "Последняя операция: {date}",
"payment_method_tx_history_title": "📜 История операций", "payment_method_tx_history_title": "📜 История операций",