feat(payments): implement server-side price resolution for subscription payments
Add a new function `resolve_fiat_offer_price_for_user` to determine the correct offer price for users based on their subscription choices and any applicable discounts. Update payment handlers for CryptoPay, FreeKassa, Platega, SeverPay, and YooKassa to utilize this function, ensuring callback price validation and improving error handling for price mismatches. This enhances security by preventing callback payload tampering and ensures accurate pricing for users.
This commit is contained in:
@@ -12,6 +12,8 @@ from config.settings import Settings
|
||||
router = Router(name="user_subscription_payments_crypto_router")
|
||||
|
||||
|
||||
from bot.handlers.user.subscription.payments_subscription import resolve_fiat_offer_price_for_user
|
||||
|
||||
@router.callback_query(F.data.startswith("pay_crypto:"))
|
||||
async def pay_crypto_callback_handler(
|
||||
callback: types.CallbackQuery,
|
||||
@@ -43,7 +45,7 @@ async def pay_crypto_callback_handler(
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
price_amount = float(parts[1])
|
||||
callback_price_amount = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
try:
|
||||
@@ -53,6 +55,43 @@ async def pay_crypto_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
resolved_price_amount = await resolve_fiat_offer_price_for_user(
|
||||
session=session,
|
||||
settings=settings,
|
||||
user_id=user_id,
|
||||
months=months,
|
||||
sale_mode=sale_mode,
|
||||
promo_code_service=promo_code_service,
|
||||
)
|
||||
if resolved_price_amount is None:
|
||||
logging.warning(
|
||||
"CryptoPay: no server-side price for user %s, value=%s, mode=%s",
|
||||
user_id,
|
||||
months,
|
||||
sale_mode,
|
||||
)
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception as exc:
|
||||
logging.debug("Suppressed exception in bot/handlers/user/subscription/payments_crypto.py: %s", exc)
|
||||
return
|
||||
|
||||
if abs(resolved_price_amount - callback_price_amount) > 0.01:
|
||||
logging.warning(
|
||||
"CryptoPay: callback price mismatch for user %s, value=%s, mode=%s, callback=%.2f, resolved=%.2f",
|
||||
user_id,
|
||||
months,
|
||||
sale_mode,
|
||||
callback_price_amount,
|
||||
resolved_price_amount,
|
||||
)
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception as exc:
|
||||
logging.debug("Suppressed exception in bot/handlers/user/subscription/payments_crypto.py: %s", exc)
|
||||
return
|
||||
|
||||
price_amount = resolved_price_amount
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
|
||||
Reference in New Issue
Block a user