feat: add multiple platega buttons

This commit is contained in:
3252a8
2026-04-27 14:34:41 +03:00
parent 587b39de1d
commit 0610156f80
8 changed files with 117 additions and 15 deletions
+5 -1
View File
@@ -107,7 +107,11 @@ CRYPTOPAY_ASSET=RUB #
PLATEGA_BASE_URL=https://app.platega.io # Base API URL
PLATEGA_MERCHANT_ID= # Your MerchantId from Platega
PLATEGA_SECRET= # API secret from Platega
PLATEGA_PAYMENT_METHOD=2 # Payment method ID (2=SBP QR, 10=RU cards, 12=International, 13=Crypto)
PLATEGA_PAYMENT_METHOD=2 # Legacy method ID; fallback for the SBP button when PLATEGA_SBP_METHOD stays default
PLATEGA_SBP_ENABLED=False # Show a separate "Pay via SBP" Platega button
PLATEGA_CRYPTO_ENABLED=False # Show a separate "Pay with crypto" Platega button
PLATEGA_SBP_METHOD=2 # Platega method ID for SBP QR (default 2)
PLATEGA_CRYPTO_METHOD=13 # Platega method ID for crypto (default 13)
PLATEGA_RETURN_URL= # Optional: redirect after successful payment (defaults to bot link)
PLATEGA_FAILED_URL= # Optional: redirect after failed/cancelled payment (defaults to return URL)
+18 -4
View File
@@ -2066,7 +2066,8 @@ def _serialize_payment_methods(
labels = {
"severpay": "SeverPay",
"freekassa": "FreeKassa / СБП",
"platega": "Platega",
"platega_sbp": "Platega · СБП",
"platega_crypto": "Platega · Crypto",
"yookassa": "Банковская карта",
"stars": "Telegram Stars",
"cryptopay": "CryptoPay",
@@ -2078,7 +2079,9 @@ def _serialize_payment_methods(
methods.append({"id": method, "name": labels[method]})
elif method == "freekassa" and _service_configured(app, "freekassa_service"):
methods.append({"id": method, "name": labels[method]})
elif method == "platega" and _service_configured(app, "platega_service"):
elif method == "platega_sbp" and settings.PLATEGA_SBP_ENABLED and _service_configured(app, "platega_service"):
methods.append({"id": method, "name": labels[method]})
elif method == "platega_crypto" and settings.PLATEGA_CRYPTO_ENABLED and _service_configured(app, "platega_service"):
methods.append({"id": method, "name": labels[method]})
elif method == "yookassa" and _service_configured(app, "yookassa_service"):
methods.append({"id": method, "name": labels[method]})
@@ -2116,9 +2119,9 @@ async def _create_subscription_payment(
return await _create_freekassa_payment(
request, session, user_id, months, price, description
)
if method == "platega":
if method in ("platega", "platega_sbp", "platega_crypto"):
return await _create_platega_payment(
request, session, user_id, months, price, description
request, session, user_id, months, price, description, variant=method
)
if method == "severpay":
return await _create_severpay_payment(
@@ -2316,11 +2319,20 @@ async def _create_platega_payment(
months: int,
price: float,
description: str,
variant: str = "platega_sbp",
) -> web.Response:
settings: Settings = request.app["settings"]
service: PlategaService = request.app["platega_service"]
if not service or not service.configured:
return _json_error(400, "payment_unavailable", "Payment method unavailable")
if variant == "platega_crypto":
if not settings.PLATEGA_CRYPTO_ENABLED:
return _json_error(400, "payment_unavailable", "Payment method unavailable")
platega_method_id = settings.PLATEGA_CRYPTO_METHOD
else:
if variant == "platega_sbp" and not settings.PLATEGA_SBP_ENABLED:
return _json_error(400, "payment_unavailable", "Payment method unavailable")
platega_method_id = settings.platega_sbp_method_resolved
try:
payment = await _create_base_payment_record(
@@ -2340,6 +2352,7 @@ async def _create_platega_payment(
"months": months,
"sale_mode": "subscription",
"source": "webapp",
"platega_variant": "crypto" if variant == "platega_crypto" else "sbp",
}
)
success, response_data = await service.create_transaction(
@@ -2350,6 +2363,7 @@ async def _create_platega_payment(
currency=settings.DEFAULT_CURRENCY_SYMBOL or "RUB",
description=description,
payload=payload,
payment_method=platega_method_id,
)
payment_url = (
response_data.get("redirect")
@@ -14,7 +14,11 @@ from db.dal import payment_dal
router = Router(name="user_subscription_payments_platega_router")
@router.callback_query(F.data.startswith("pay_platega:"))
@router.callback_query(
F.data.startswith("pay_platega_sbp:")
| F.data.startswith("pay_platega_crypto:")
| F.data.startswith("pay_platega:")
)
async def pay_platega_callback_handler(
callback: types.CallbackQuery,
settings: Settings,
@@ -22,6 +26,29 @@ async def pay_platega_callback_handler(
platega_service: PlategaService,
session: AsyncSession,
):
callback_prefix, _, _ = (callback.data or "").partition(":")
if callback_prefix == "pay_platega_crypto":
platega_method_id = settings.PLATEGA_CRYPTO_METHOD
platega_variant = "crypto"
if not settings.PLATEGA_CRYPTO_ENABLED:
try:
await callback.answer()
except Exception:
pass
return
elif callback_prefix == "pay_platega_sbp":
platega_method_id = settings.platega_sbp_method_resolved
platega_variant = "sbp"
if not settings.PLATEGA_SBP_ENABLED:
try:
await callback.answer()
except Exception:
pass
return
else:
# Legacy callback (pre-split): keep working as SBP
platega_method_id = settings.platega_sbp_method_resolved
platega_variant = "sbp"
current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE)
i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance")
get_text = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key
@@ -103,6 +130,7 @@ async def pay_platega_callback_handler(
"user_id": user_id,
"months": months,
"sale_mode": sale_mode,
"platega_variant": platega_variant,
}
)
@@ -114,6 +142,7 @@ async def pay_platega_callback_handler(
currency=currency_code,
description=payment_description,
payload=payload_meta,
payment_method=platega_method_id,
)
if success:
+8 -3
View File
@@ -206,10 +206,15 @@ def get_payment_method_keyboard(months: int, price: float,
text=_("pay_with_sbp_button"),
callback_data=f"pay_fk:{value_str}:{price}{mode_suffix}",
)
elif method == "platega" and settings.PLATEGA_ENABLED:
elif method == "platega_sbp" and settings.PLATEGA_ENABLED and settings.PLATEGA_SBP_ENABLED:
builder.button(
text=_("pay_with_platega_button"),
callback_data=f"pay_platega:{value_str}:{price}{mode_suffix}",
text=_("pay_with_platega_sbp_button"),
callback_data=f"pay_platega_sbp:{value_str}:{price}{mode_suffix}",
)
elif method == "platega_crypto" and settings.PLATEGA_ENABLED and settings.PLATEGA_CRYPTO_ENABLED:
builder.button(
text=_("pay_with_platega_crypto_button"),
callback_data=f"pay_platega_crypto:{value_str}:{price}{mode_suffix}",
)
elif method == "yookassa" and settings.YOOKASSA_ENABLED:
builder.button(
+5 -1
View File
@@ -42,6 +42,8 @@ class PlategaService:
self.merchant_id = settings.PLATEGA_MERCHANT_ID
self.secret = settings.PLATEGA_SECRET
self.payment_method = settings.PLATEGA_PAYMENT_METHOD
self.sbp_method = settings.platega_sbp_method_resolved
self.crypto_method = settings.PLATEGA_CRYPTO_METHOD
self.return_url = settings.PLATEGA_RETURN_URL or f"https://t.me/{default_return_url}"
self.failed_url = settings.PLATEGA_FAILED_URL or self.return_url
@@ -77,6 +79,7 @@ class PlategaService:
currency: Optional[str],
description: str,
payload: Optional[str] = None,
payment_method: Optional[int] = None,
) -> Tuple[bool, Dict[str, Any]]:
if not self.configured:
logging.error("PlategaService is not configured. Cannot create transaction.")
@@ -85,9 +88,10 @@ class PlategaService:
session = await self._get_session()
url = f"{self.base_url}/transaction/process"
currency_code = (currency or self.settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
method_id = int(payment_method if payment_method is not None else self.payment_method)
body: Dict[str, Any] = {
"paymentMethod": int(self.payment_method),
"paymentMethod": method_id,
"paymentDetails": {"amount": float(amount), "currency": currency_code},
"description": description,
"return": self.return_url,
+47 -5
View File
@@ -44,6 +44,10 @@ class PaymentSettings(BaseModel):
platega_merchant_id: Optional[str]
platega_secret: Optional[str]
platega_payment_method: int
platega_sbp_enabled: bool
platega_crypto_enabled: bool
platega_sbp_method: int
platega_crypto_method: int
platega_return_url: Optional[str]
platega_failed_url: Optional[str]
severpay_enabled: bool
@@ -179,7 +183,24 @@ class Settings(BaseSettings):
PLATEGA_MERCHANT_ID: Optional[str] = None
PLATEGA_SECRET: Optional[str] = None
PLATEGA_PAYMENT_METHOD: int = Field(
default=2, description="Platega payment method ID (e.g., 2 for SBP QR)"
default=2,
description="Legacy Platega payment method ID. Used as fallback for PLATEGA_SBP_METHOD when the new field is unset.",
)
PLATEGA_SBP_ENABLED: bool = Field(
default=False,
description="Show a separate Platega SBP payment button.",
)
PLATEGA_CRYPTO_ENABLED: bool = Field(
default=False,
description="Show a separate Platega crypto payment button.",
)
PLATEGA_SBP_METHOD: int = Field(
default=2,
description="Platega method ID for SBP QR (default 2).",
)
PLATEGA_CRYPTO_METHOD: int = Field(
default=13,
description="Platega method ID for crypto (default 13).",
)
PLATEGA_RETURN_URL: Optional[str] = Field(default=None)
PLATEGA_FAILED_URL: Optional[str] = Field(default=None)
@@ -404,6 +425,10 @@ class Settings(BaseSettings):
platega_merchant_id=self.PLATEGA_MERCHANT_ID,
platega_secret=self.PLATEGA_SECRET,
platega_payment_method=self.PLATEGA_PAYMENT_METHOD,
platega_sbp_enabled=self.PLATEGA_SBP_ENABLED,
platega_crypto_enabled=self.PLATEGA_CRYPTO_ENABLED,
platega_sbp_method=self.platega_sbp_method_resolved,
platega_crypto_method=self.PLATEGA_CRYPTO_METHOD,
platega_return_url=self.PLATEGA_RETURN_URL,
platega_failed_url=self.PLATEGA_FAILED_URL,
severpay_enabled=self.SEVERPAY_ENABLED,
@@ -750,7 +775,8 @@ class Settings(BaseSettings):
"""
default_order = [
"freekassa",
"platega",
"platega_sbp",
"platega_crypto",
"severpay",
"yookassa",
"stars",
@@ -758,13 +784,29 @@ class Settings(BaseSettings):
]
if not self.PAYMENT_METHODS_ORDER:
return default_order
methods = []
methods: List[str] = []
for item in self.PAYMENT_METHODS_ORDER.split(","):
slug = item.strip().lower()
if slug:
methods.append(slug)
if not slug:
continue
if slug == "platega":
# Legacy slug — expand to the new sub-methods preserving order
if "platega_sbp" not in methods:
methods.append("platega_sbp")
if "platega_crypto" not in methods:
methods.append("platega_crypto")
continue
methods.append(slug)
return methods or default_order
@computed_field
@property
def platega_sbp_method_resolved(self) -> int:
"""SBP method ID, falling back to legacy PLATEGA_PAYMENT_METHOD when SBP-specific value is the default."""
if self.PLATEGA_SBP_METHOD != 2:
return self.PLATEGA_SBP_METHOD
return self.PLATEGA_PAYMENT_METHOD or 2
@computed_field
@property
def email_auth_configured(self) -> bool:
+2
View File
@@ -49,6 +49,8 @@
"yookassa_autopay_charge_initiated": "Charge request sent to the selected card. We'll notify you once the payment completes.",
"pay_with_sbp_button": "📱 SBP",
"pay_with_platega_button": "💳 Platega (SBP/Cards)",
"pay_with_platega_sbp_button": "🏦 Pay via SBP",
"pay_with_platega_crypto_button": "🪙 Pay with crypto",
"pay_with_severpay_button": "💳 SeverPay",
"back_to_payment_methods_button": "⬅️ Back",
"pay_with_cryptopay_button": "💎 CryptoBot",
+2
View File
@@ -49,6 +49,8 @@
"yookassa_autopay_charge_initiated": "Запрос на списание с выбранной карты отправлен. Сообщим, как только платёж завершится.",
"pay_with_sbp_button": "📱 СБП",
"pay_with_platega_button": "💳 Platega (СБП/карты)",
"pay_with_platega_sbp_button": "🏦 Оплата через СБП",
"pay_with_platega_crypto_button": "🪙 Оплата криптой",
"pay_with_severpay_button": "💳 SeverPay",
"back_to_payment_methods_button": "⬅️ Назад",
"pay_with_cryptopay_button": "💎 CryptoBot",