From a5aecb0f866e0bafcb86f7cac9b566c6ba14ec7f Mon Sep 17 00:00:00 2001 From: machka-pasla Date: Thu, 4 Sep 2025 18:14:32 +0300 Subject: [PATCH] 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. --- bot/handlers/user/payment.py | 35 ++++++++++++++++++++----- bot/handlers/user/subscription.py | 43 +++++++++++++++++++++++++------ locales/en.json | 9 ++++--- locales/ru.json | 9 ++++--- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/bot/handlers/user/payment.py b/bot/handlers/user/payment.py index 2f7f473..361df09 100644 --- a/bot/handlers/user/payment.py +++ b/bot/handlers/user/payment.py @@ -140,13 +140,26 @@ async def process_successful_payment(session: AsyncSession, bot: Bot, payment_method = payment_info_from_webhook.get("payment_method") if isinstance(payment_method, dict) and payment_method.get("saved", False): pm_id = payment_method.get("id") + pm_type = payment_method.get("type") + title = payment_method.get("title") 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( session, user_id=user_id, payment_method_id=pm_id, - card_last4=card.get("last4"), - card_network=card.get("card_type"), + card_last4=display_last4, + card_network=display_network, ) except Exception: 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) payment_method = payment_dict_for_processing.get("payment_method") 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 {} + 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( session, user_id=user_id, payment_method_id=payment_method.get("id"), - card_last4=card.get("last4"), - card_network=card.get("card_type"), + card_last4=display_last4, + card_network=display_network, ) await session.commit() # 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, provider_payment_method_id=payment_method.get("id"), provider="yookassa", - card_last4=card.get("last4"), - card_network=card.get("card_type"), + card_last4=display_last4, + card_network=display_network, set_default=True, ) await session.commit() diff --git a/bot/handlers/user/subscription.py b/bot/handlers/user/subscription.py index 0d2ca3a..fe005ae 100644 --- a/bot/handlers/user/subscription.py +++ b/bot/handlers/user/subscription.py @@ -313,12 +313,21 @@ async def pay_yk_callback_handler( pm = payment_response_yk.get("payment_method") try: 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( session, user_id=user_id, payment_method_id=pm['id'], - card_last4=pm.get('last4'), - card_network=pm.get('card', {}).get('card_type') if isinstance(pm.get('card'), dict) else None, + card_last4=display_last4, + card_network=display_network, ) await session.commit() 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) cards: List[tuple] = [] 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}")) text = get_text("payment_methods_title") @@ -683,7 +695,10 @@ async def payment_method_delete(callback: types.CallbackQuery, settings: Setting text = _("payment_methods_title") cards = [] 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}")) if not cards: 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) cards = [] 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}")) text = _("payment_methods_title") 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) # 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]) - 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 "—" # 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') except Exception: 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)}" await callback.message.edit_text(details, reply_markup=get_payment_method_details_keyboard(billing.yookassa_payment_method_id, current_lang, i18n)) try: @@ -847,7 +871,10 @@ async def payment_methods_list(callback: types.CallbackQuery, settings: Settings cards: List[tuple] = [] methods = await list_user_payment_methods(session, callback.from_user.id) 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}")) # Parse page diff --git a/locales/en.json b/locales/en.json index a171d61..b66d666 100644 --- a/locales/en.json +++ b/locales/en.json @@ -377,14 +377,15 @@ "subscription_autorenew_updated": "Auto-renew settings updated.", "payment_methods_manage_button": "💳 Payment Methods", "payment_methods_title": "💳 Payment Methods", - "payment_method_bind_button": "➕ Add card", + "payment_method_bind_button": "➕ Add method", "payment_method_delete_button": "🗑 Remove", "payment_method_view_button": "ℹ️ Details", - "payment_method_none": "You don't have a saved card yet.", - "payment_method_bound_success": "✅ Card successfully added.", + "payment_method_none": "You don't have a saved payment method yet.", + "payment_method_bound_success": "✅ Payment method added.", "payment_method_deleted_success": "✅ Payment method removed.", "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_last_tx": "Last transaction: {date}", "payment_method_tx_history_title": "📜 Transactions history", diff --git a/locales/ru.json b/locales/ru.json index d6af159..199436d 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -376,14 +376,15 @@ "subscription_autorenew_updated": "Настройки автопродления обновлены.", "payment_methods_manage_button": "💳 Способы оплаты", "payment_methods_title": "💳 Способы оплаты", - "payment_method_bind_button": "➕ Привязать карту", + "payment_method_bind_button": "➕ Добавить способ", "payment_method_delete_button": "🗑 Удалить", "payment_method_view_button": "ℹ️ Детали", - "payment_method_none": "У вас пока нет сохранённой карты.", - "payment_method_bound_success": "✅ Карта успешно привязана.", + "payment_method_none": "У вас пока нет сохранённого способа оплаты.", + "payment_method_bound_success": "✅ Способ оплаты добавлен.", "payment_method_deleted_success": "✅ Способ оплаты удалён.", "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_last_tx": "Последняя операция: {date}", "payment_method_tx_history_title": "📜 История операций",